Skip to content

Commit adec212

Browse files
committed
all: switch internal API's to use driver.NamedValue instead of driver.Value
database/sql defaults to using the QueryContext and ExecContext API's. Previously, we would need to allocate in order to convert the driver.NamedValue parameter that each of those accepts to a driver.Value. By using driver.NamedValue consistently internally, we can save allocations and improve performance. See #1067 for a full set of benchmarks.
1 parent 8446d16 commit adec212

File tree

2 files changed

+34
-39
lines changed

2 files changed

+34
-39
lines changed

conn.go

+23-22
Original file line numberDiff line numberDiff line change
@@ -867,12 +867,20 @@ func (cn *conn) Close() (err error) {
867867
return cn.sendSimpleMessage('X')
868868
}
869869

870+
func toNamedValue(v []driver.Value) []driver.NamedValue {
871+
v2 := make([]driver.NamedValue, len(v))
872+
for i := range v {
873+
v2[i] = driver.NamedValue{Value: v[i]}
874+
}
875+
return v2
876+
}
877+
870878
// Implement the "Queryer" interface
871879
func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
872-
return cn.query(query, args)
880+
return cn.query(query, toNamedValue(args))
873881
}
874882

875-
func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
883+
func (cn *conn) query(query string, args []driver.NamedValue) (_ *rows, err error) {
876884
if err := cn.err.get(); err != nil {
877885
return nil, err
878886
}
@@ -921,7 +929,7 @@ func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err
921929
}
922930

923931
if cn.binaryParameters {
924-
cn.sendBinaryModeQuery(query, args)
932+
cn.sendBinaryModeQuery(query, toNamedValue(args))
925933

926934
cn.readParseResponse()
927935
cn.readBindResponse()
@@ -1379,10 +1387,10 @@ func (st *stmt) Close() (err error) {
13791387
}
13801388

13811389
func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) {
1382-
return st.query(v)
1390+
return st.query(toNamedValue(v))
13831391
}
13841392

1385-
func (st *stmt) query(v []driver.Value) (r *rows, err error) {
1393+
func (st *stmt) query(v []driver.NamedValue) (r *rows, err error) {
13861394
if err := st.cn.err.get(); err != nil {
13871395
return nil, err
13881396
}
@@ -1395,18 +1403,11 @@ func (st *stmt) query(v []driver.Value) (r *rows, err error) {
13951403
}, nil
13961404
}
13971405

1398-
func (st *stmt) Exec(v []driver.Value) (res driver.Result, err error) {
1399-
if err := st.cn.err.get(); err != nil {
1400-
return nil, err
1401-
}
1402-
defer st.cn.errRecover(&err)
1403-
1404-
st.exec(v)
1405-
res, _, err = st.cn.readExecuteResponse("simple query")
1406-
return res, err
1406+
func (st *stmt) Exec(v []driver.Value) (driver.Result, error) {
1407+
return st.ExecContext(context.Background(), toNamedValue(v))
14071408
}
14081409

1409-
func (st *stmt) exec(v []driver.Value) {
1410+
func (st *stmt) exec(v []driver.NamedValue) {
14101411
if len(v) >= 65536 {
14111412
errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(v))
14121413
}
@@ -1425,10 +1426,10 @@ func (st *stmt) exec(v []driver.Value) {
14251426
w.int16(0)
14261427
w.int16(len(v))
14271428
for i, x := range v {
1428-
if x == nil {
1429+
if x.Value == nil {
14291430
w.int32(-1)
14301431
} else {
1431-
b := encode(&cn.parameterStatus, x, st.paramTyps[i])
1432+
b := encode(&cn.parameterStatus, x.Value, st.paramTyps[i])
14321433
w.int32(len(b))
14331434
w.bytes(b)
14341435
}
@@ -1684,13 +1685,13 @@ func md5s(s string) string {
16841685
return fmt.Sprintf("%x", h.Sum(nil))
16851686
}
16861687

1687-
func (cn *conn) sendBinaryParameters(b *writeBuf, args []driver.Value) {
1688+
func (cn *conn) sendBinaryParameters(b *writeBuf, args []driver.NamedValue) {
16881689
// Do one pass over the parameters to see if we're going to send any of
16891690
// them over in binary. If we are, create a paramFormats array at the
16901691
// same time.
16911692
var paramFormats []int
16921693
for i, x := range args {
1693-
_, ok := x.([]byte)
1694+
_, ok := x.Value.([]byte)
16941695
if ok {
16951696
if paramFormats == nil {
16961697
paramFormats = make([]int, len(args))
@@ -1709,17 +1710,17 @@ func (cn *conn) sendBinaryParameters(b *writeBuf, args []driver.Value) {
17091710

17101711
b.int16(len(args))
17111712
for _, x := range args {
1712-
if x == nil {
1713+
if x.Value == nil {
17131714
b.int32(-1)
17141715
} else {
1715-
datum := binaryEncode(&cn.parameterStatus, x)
1716+
datum := binaryEncode(&cn.parameterStatus, x.Value)
17161717
b.int32(len(datum))
17171718
b.bytes(datum)
17181719
}
17191720
}
17201721
}
17211722

1722-
func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) {
1723+
func (cn *conn) sendBinaryModeQuery(query string, args []driver.NamedValue) {
17231724
if len(args) >= 65536 {
17241725
errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(args))
17251726
}

conn_go18.go

+11-17
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,8 @@ const (
1616

1717
// Implement the "QueryerContext" interface
1818
func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
19-
list := make([]driver.Value, len(args))
20-
for i, nv := range args {
21-
list[i] = nv.Value
22-
}
2319
finish := cn.watchCancel(ctx)
24-
r, err := cn.query(query, list)
20+
r, err := cn.query(query, args)
2521
if err != nil {
2622
if finish != nil {
2723
finish()
@@ -183,12 +179,8 @@ func (cn *conn) cancel(ctx context.Context) error {
183179

184180
// Implement the "StmtQueryContext" interface
185181
func (st *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
186-
list := make([]driver.Value, len(args))
187-
for i, nv := range args {
188-
list[i] = nv.Value
189-
}
190182
finish := st.watchCancel(ctx)
191-
r, err := st.query(list)
183+
r, err := st.query(args)
192184
if err != nil {
193185
if finish != nil {
194186
finish()
@@ -200,17 +192,19 @@ func (st *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (dri
200192
}
201193

202194
// Implement the "StmtExecContext" interface
203-
func (st *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
204-
list := make([]driver.Value, len(args))
205-
for i, nv := range args {
206-
list[i] = nv.Value
207-
}
208-
195+
func (st *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (res driver.Result, err error) {
209196
if finish := st.watchCancel(ctx); finish != nil {
210197
defer finish()
211198
}
212199

213-
return st.Exec(list)
200+
if err := st.cn.err.get(); err != nil {
201+
return nil, err
202+
}
203+
defer st.cn.errRecover(&err)
204+
205+
st.exec(args)
206+
res, _, err = st.cn.readExecuteResponse("simple query")
207+
return res, err
214208
}
215209

216210
// watchCancel is implemented on stmt in order to not mark the parent conn as bad

0 commit comments

Comments
 (0)