Skip to content

Commit 122ddb1

Browse files
committedAug 21, 2015
Move argument converters to callback.go, and optimize return value handling.
A call now doesn't have to do any reflection, it just blindly invokes a bunch of argument and return value handlers to execute the translation, and the safety of the translation is determined at registration time.
1 parent cf8fa0a commit 122ddb1

File tree

4 files changed

+367
-154
lines changed

4 files changed

+367
-154
lines changed
 

‎callback.go

Lines changed: 199 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,214 @@
55

66
package sqlite3
77

8+
// You can't export a Go function to C and have definitions in the C
9+
// preamble in the same file, so we have to have callbackTrampoline in
10+
// its own file. Because we need a separate file anyway, the support
11+
// code for SQLite custom functions is in here.
12+
813
/*
914
#include <sqlite3-binding.h>
15+
16+
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
17+
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
1018
*/
1119
import "C"
1220

13-
import "unsafe"
21+
import (
22+
"errors"
23+
"fmt"
24+
"reflect"
25+
"unsafe"
26+
)
1427

1528
//export callbackTrampoline
1629
func callbackTrampoline(ctx *C.sqlite3_context, argc int, argv **C.sqlite3_value) {
1730
args := (*[1 << 30]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
1831
fi := (*functionInfo)(unsafe.Pointer(C.sqlite3_user_data(ctx)))
1932
fi.Call(ctx, args)
2033
}
34+
35+
// This is only here so that tests can refer to it.
36+
type callbackArgRaw C.sqlite3_value
37+
38+
type callbackArgConverter func(*C.sqlite3_value) (reflect.Value, error)
39+
40+
type callbackArgCast struct {
41+
f callbackArgConverter
42+
typ reflect.Type
43+
}
44+
45+
func (c callbackArgCast) Run(v *C.sqlite3_value) (reflect.Value, error) {
46+
val, err := c.f(v)
47+
if err != nil {
48+
return reflect.Value{}, err
49+
}
50+
if !val.Type().ConvertibleTo(c.typ) {
51+
return reflect.Value{}, fmt.Errorf("cannot convert %s to %s", val.Type(), c.typ)
52+
}
53+
return val.Convert(c.typ), nil
54+
}
55+
56+
func callbackArgInt64(v *C.sqlite3_value) (reflect.Value, error) {
57+
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
58+
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
59+
}
60+
return reflect.ValueOf(int64(C.sqlite3_value_int64(v))), nil
61+
}
62+
63+
func callbackArgBool(v *C.sqlite3_value) (reflect.Value, error) {
64+
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
65+
return reflect.Value{}, fmt.Errorf("argument must be an INTEGER")
66+
}
67+
i := int64(C.sqlite3_value_int64(v))
68+
val := false
69+
if i != 0 {
70+
val = true
71+
}
72+
return reflect.ValueOf(val), nil
73+
}
74+
75+
func callbackArgFloat64(v *C.sqlite3_value) (reflect.Value, error) {
76+
if C.sqlite3_value_type(v) != C.SQLITE_FLOAT {
77+
return reflect.Value{}, fmt.Errorf("argument must be a FLOAT")
78+
}
79+
return reflect.ValueOf(float64(C.sqlite3_value_double(v))), nil
80+
}
81+
82+
func callbackArgBytes(v *C.sqlite3_value) (reflect.Value, error) {
83+
switch C.sqlite3_value_type(v) {
84+
case C.SQLITE_BLOB:
85+
l := C.sqlite3_value_bytes(v)
86+
p := C.sqlite3_value_blob(v)
87+
return reflect.ValueOf(C.GoBytes(p, l)), nil
88+
case C.SQLITE_TEXT:
89+
l := C.sqlite3_value_bytes(v)
90+
c := unsafe.Pointer(C.sqlite3_value_text(v))
91+
return reflect.ValueOf(C.GoBytes(c, l)), nil
92+
default:
93+
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
94+
}
95+
}
96+
97+
func callbackArgString(v *C.sqlite3_value) (reflect.Value, error) {
98+
switch C.sqlite3_value_type(v) {
99+
case C.SQLITE_BLOB:
100+
l := C.sqlite3_value_bytes(v)
101+
p := (*C.char)(C.sqlite3_value_blob(v))
102+
return reflect.ValueOf(C.GoStringN(p, l)), nil
103+
case C.SQLITE_TEXT:
104+
c := (*C.char)(unsafe.Pointer(C.sqlite3_value_text(v)))
105+
return reflect.ValueOf(C.GoString(c)), nil
106+
default:
107+
return reflect.Value{}, fmt.Errorf("argument must be BLOB or TEXT")
108+
}
109+
}
110+
111+
func callbackArg(typ reflect.Type) (callbackArgConverter, error) {
112+
switch typ.Kind() {
113+
case reflect.Slice:
114+
if typ.Elem().Kind() != reflect.Uint8 {
115+
return nil, errors.New("the only supported slice type is []byte")
116+
}
117+
return callbackArgBytes, nil
118+
case reflect.String:
119+
return callbackArgString, nil
120+
case reflect.Bool:
121+
return callbackArgBool, nil
122+
case reflect.Int64:
123+
return callbackArgInt64, nil
124+
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
125+
c := callbackArgCast{callbackArgInt64, typ}
126+
return c.Run, nil
127+
case reflect.Float64:
128+
return callbackArgFloat64, nil
129+
case reflect.Float32:
130+
c := callbackArgCast{callbackArgFloat64, typ}
131+
return c.Run, nil
132+
default:
133+
return nil, fmt.Errorf("don't know how to convert to %s", typ)
134+
}
135+
}
136+
137+
type callbackRetConverter func(*C.sqlite3_context, reflect.Value) error
138+
139+
func callbackRetInteger(ctx *C.sqlite3_context, v reflect.Value) error {
140+
switch v.Type().Kind() {
141+
case reflect.Int64:
142+
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
143+
v = v.Convert(reflect.TypeOf(int64(0)))
144+
case reflect.Bool:
145+
b := v.Interface().(bool)
146+
if b {
147+
v = reflect.ValueOf(int64(1))
148+
} else {
149+
v = reflect.ValueOf(int64(0))
150+
}
151+
default:
152+
return fmt.Errorf("cannot convert %s to INTEGER", v.Type())
153+
}
154+
155+
C.sqlite3_result_int64(ctx, C.sqlite3_int64(v.Interface().(int64)))
156+
return nil
157+
}
158+
159+
func callbackRetFloat(ctx *C.sqlite3_context, v reflect.Value) error {
160+
switch v.Type().Kind() {
161+
case reflect.Float64:
162+
case reflect.Float32:
163+
v = v.Convert(reflect.TypeOf(float64(0)))
164+
default:
165+
return fmt.Errorf("cannot convert %s to FLOAT", v.Type())
166+
}
167+
168+
C.sqlite3_result_double(ctx, C.double(v.Interface().(float64)))
169+
return nil
170+
}
171+
172+
func callbackRetBlob(ctx *C.sqlite3_context, v reflect.Value) error {
173+
if v.Type().Kind() != reflect.Slice || v.Type().Elem().Kind() != reflect.Uint8 {
174+
return fmt.Errorf("cannot convert %s to BLOB", v.Type())
175+
}
176+
i := v.Interface()
177+
if i == nil || len(i.([]byte)) == 0 {
178+
C.sqlite3_result_null(ctx)
179+
} else {
180+
bs := i.([]byte)
181+
C._sqlite3_result_blob(ctx, unsafe.Pointer(&bs[0]), C.int(len(bs)))
182+
}
183+
return nil
184+
}
185+
186+
func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error {
187+
if v.Type().Kind() != reflect.String {
188+
return fmt.Errorf("cannot convert %s to TEXT", v.Type())
189+
}
190+
C._sqlite3_result_text(ctx, C.CString(v.Interface().(string)))
191+
return nil
192+
}
193+
194+
func callbackRet(typ reflect.Type) (callbackRetConverter, error) {
195+
switch typ.Kind() {
196+
case reflect.Slice:
197+
if typ.Elem().Kind() != reflect.Uint8 {
198+
return nil, errors.New("the only supported slice type is []byte")
199+
}
200+
return callbackRetBlob, nil
201+
case reflect.String:
202+
return callbackRetText, nil
203+
case reflect.Bool, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Uint:
204+
return callbackRetInteger, nil
205+
case reflect.Float32, reflect.Float64:
206+
return callbackRetFloat, nil
207+
default:
208+
return nil, fmt.Errorf("don't know how to convert to %s", typ)
209+
}
210+
}
211+
212+
// Test support code. Tests are not allowed to import "C", so we can't
213+
// declare any functions that use C.sqlite3_value.
214+
func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter {
215+
return func(*C.sqlite3_value) (reflect.Value, error) {
216+
return v, err
217+
}
218+
}

‎callback_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package sqlite3
2+
3+
import (
4+
"errors"
5+
"math"
6+
"reflect"
7+
"testing"
8+
)
9+
10+
func TestCallbackArgCast(t *testing.T) {
11+
intConv := callbackSyntheticForTests(reflect.ValueOf(int64(math.MaxInt64)), nil)
12+
floatConv := callbackSyntheticForTests(reflect.ValueOf(float64(math.MaxFloat64)), nil)
13+
errConv := callbackSyntheticForTests(reflect.Value{}, errors.New("test"))
14+
15+
tests := []struct {
16+
f callbackArgConverter
17+
o reflect.Value
18+
}{
19+
{intConv, reflect.ValueOf(int8(-1))},
20+
{intConv, reflect.ValueOf(int16(-1))},
21+
{intConv, reflect.ValueOf(int32(-1))},
22+
{intConv, reflect.ValueOf(uint8(math.MaxUint8))},
23+
{intConv, reflect.ValueOf(uint16(math.MaxUint16))},
24+
{intConv, reflect.ValueOf(uint32(math.MaxUint32))},
25+
// Special case, int64->uint64 is only 1<<63 - 1, not 1<<64 - 1
26+
{intConv, reflect.ValueOf(uint64(math.MaxInt64))},
27+
{floatConv, reflect.ValueOf(float32(math.Inf(1)))},
28+
}
29+
30+
for _, test := range tests {
31+
conv := callbackArgCast{test.f, test.o.Type()}
32+
val, err := conv.Run(nil)
33+
if err != nil {
34+
t.Errorf("Couldn't convert to %s: %s", test.o.Type(), err)
35+
} else if !reflect.DeepEqual(val.Interface(), test.o.Interface()) {
36+
t.Errorf("Unexpected result from converting to %s: got %v, want %v", test.o.Type(), val.Interface(), test.o.Interface())
37+
}
38+
}
39+
40+
conv := callbackArgCast{errConv, reflect.TypeOf(int8(0))}
41+
_, err := conv.Run(nil)
42+
if err == nil {
43+
t.Errorf("Expected error during callbackArgCast, but got none")
44+
}
45+
}
46+
47+
func TestCallbackConverters(t *testing.T) {
48+
tests := []struct {
49+
v interface{}
50+
err bool
51+
}{
52+
// Unfortunately, we can't tell which converter was returned,
53+
// but we can at least check which types can be converted.
54+
{[]byte{0}, false},
55+
{"text", false},
56+
{true, false},
57+
{int8(0), false},
58+
{int16(0), false},
59+
{int32(0), false},
60+
{int64(0), false},
61+
{uint8(0), false},
62+
{uint16(0), false},
63+
{uint32(0), false},
64+
{uint64(0), false},
65+
{int(0), false},
66+
{uint(0), false},
67+
{float64(0), false},
68+
{float32(0), false},
69+
70+
{func() {}, true},
71+
{complex64(complex(0, 0)), true},
72+
{complex128(complex(0, 0)), true},
73+
{struct{}{}, true},
74+
{map[string]string{}, true},
75+
{[]string{}, true},
76+
{(*int8)(nil), true},
77+
{make(chan int), true},
78+
}
79+
80+
for _, test := range tests {
81+
_, err := callbackArg(reflect.TypeOf(test.v))
82+
if test.err && err == nil {
83+
t.Errorf("Expected an error when converting %s, got no error", reflect.TypeOf(test.v))
84+
} else if !test.err && err != nil {
85+
t.Errorf("Expected converter when converting %s, got error: %s", reflect.TypeOf(test.v), err)
86+
}
87+
}
88+
89+
for _, test := range tests {
90+
_, err := callbackRet(reflect.TypeOf(test.v))
91+
if test.err && err == nil {
92+
t.Errorf("Expected an error when converting %s, got no error", reflect.TypeOf(test.v))
93+
} else if !test.err && err != nil {
94+
t.Errorf("Expected converter when converting %s, got error: %s", reflect.TypeOf(test.v), err)
95+
}
96+
}
97+
}

‎sqlite3.go

Lines changed: 18 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ type SQLiteRows struct {
166166

167167
type functionInfo struct {
168168
f reflect.Value
169-
argConverters []func(*C.sqlite3_value) (reflect.Value, error)
169+
argConverters []callbackArgConverter
170+
retConverter callbackRetConverter
170171
}
171172

172173
func (fi *functionInfo) error(ctx *C.sqlite3_context, err error) {
@@ -193,58 +194,11 @@ func (fi *functionInfo) Call(ctx *C.sqlite3_context, argv []*C.sqlite3_value) {
193194
return
194195
}
195196

196-
res := ret[0].Interface()
197-
// Normalize ret to one of the types sqlite knows.
198-
switch r := res.(type) {
199-
case int64, float64, []byte, string:
200-
// Already the right type
201-
case bool:
202-
if r {
203-
res = int64(1)
204-
} else {
205-
res = int64(0)
206-
}
207-
case int:
208-
res = int64(r)
209-
case uint:
210-
res = int64(r)
211-
case uint8:
212-
res = int64(r)
213-
case uint16:
214-
res = int64(r)
215-
case uint32:
216-
res = int64(r)
217-
case uint64:
218-
res = int64(r)
219-
case int8:
220-
res = int64(r)
221-
case int16:
222-
res = int64(r)
223-
case int32:
224-
res = int64(r)
225-
case float32:
226-
res = float64(r)
227-
default:
228-
fi.error(ctx, errors.New("cannot convert returned type to sqlite type"))
197+
err := fi.retConverter(ctx, ret[0])
198+
if err != nil {
199+
fi.error(ctx, err)
229200
return
230201
}
231-
232-
switch r := res.(type) {
233-
case int64:
234-
C.sqlite3_result_int64(ctx, C.sqlite3_int64(r))
235-
case float64:
236-
C.sqlite3_result_double(ctx, C.double(r))
237-
case []byte:
238-
if len(r) == 0 {
239-
C.sqlite3_result_null(ctx)
240-
} else {
241-
C._sqlite3_result_blob(ctx, unsafe.Pointer(&r[0]), C.int(len(r)))
242-
}
243-
case string:
244-
C._sqlite3_result_text(ctx, C.CString(r))
245-
default:
246-
panic("unreachable")
247-
}
248202
}
249203

250204
// Commit transaction.
@@ -261,10 +215,10 @@ func (tx *SQLiteTx) Rollback() error {
261215

262216
// RegisterFunc makes a Go function available as a SQLite function.
263217
//
264-
// The function must accept only arguments of type int64, float64,
265-
// []byte or string, and return one value of any numeric type except
266-
// complex, bool, []byte or string. Optionally, an error can be
267-
// provided as a second return value.
218+
// The function can accept arguments of any real numeric type
219+
// (i.e. not complex), as well as []byte and string. It must return a
220+
// value of one of those types, and optionally an error as a second
221+
// value.
268222
//
269223
// If pure is true. SQLite will assume that the function's return
270224
// value depends only on its inputs, and make more aggressive
@@ -287,59 +241,19 @@ func (c *SQLiteConn) RegisterFunc(name string, impl interface{}, pure bool) erro
287241
}
288242

289243
for i := 0; i < t.NumIn(); i++ {
290-
arg := t.In(i)
291-
var conv func(*C.sqlite3_value) (reflect.Value, error)
292-
switch arg.Kind() {
293-
case reflect.Int64:
294-
conv = func(v *C.sqlite3_value) (reflect.Value, error) {
295-
if C.sqlite3_value_type(v) != C.SQLITE_INTEGER {
296-
return reflect.Value{}, fmt.Errorf("Argument %d to %s must be an INTEGER", i+1, name)
297-
}
298-
return reflect.ValueOf(int64(C.sqlite3_value_int64(v))), nil
299-
}
300-
case reflect.Float64:
301-
conv = func(v *C.sqlite3_value) (reflect.Value, error) {
302-
if C.sqlite3_value_type(v) != C.SQLITE_FLOAT {
303-
return reflect.Value{}, fmt.Errorf("Argument %d to %s must be a FLOAT", i+1, name)
304-
}
305-
return reflect.ValueOf(float64(C.sqlite3_value_double(v))), nil
306-
}
307-
case reflect.Slice:
308-
if arg.Elem().Kind() != reflect.Uint8 {
309-
return errors.New("The only supported slice type is []byte")
310-
}
311-
conv = func(v *C.sqlite3_value) (reflect.Value, error) {
312-
switch C.sqlite3_value_type(v) {
313-
case C.SQLITE_BLOB:
314-
l := C.sqlite3_value_bytes(v)
315-
p := C.sqlite3_value_blob(v)
316-
return reflect.ValueOf(C.GoBytes(p, l)), nil
317-
case C.SQLITE_TEXT:
318-
l := C.sqlite3_value_bytes(v)
319-
c := unsafe.Pointer(C.sqlite3_value_text(v))
320-
return reflect.ValueOf(C.GoBytes(c, l)), nil
321-
default:
322-
return reflect.Value{}, fmt.Errorf("Argument %d to %s must be BLOB or TEXT", i+1, name)
323-
}
324-
}
325-
case reflect.String:
326-
conv = func(v *C.sqlite3_value) (reflect.Value, error) {
327-
switch C.sqlite3_value_type(v) {
328-
case C.SQLITE_BLOB:
329-
l := C.sqlite3_value_bytes(v)
330-
p := (*C.char)(C.sqlite3_value_blob(v))
331-
return reflect.ValueOf(C.GoStringN(p, l)), nil
332-
case C.SQLITE_TEXT:
333-
c := (*C.char)(unsafe.Pointer(C.sqlite3_value_text(v)))
334-
return reflect.ValueOf(C.GoString(c)), nil
335-
default:
336-
return reflect.Value{}, fmt.Errorf("Argument %d to %s must be BLOB or TEXT", i+1, name)
337-
}
338-
}
244+
conv, err := callbackArg(t.In(i))
245+
if err != nil {
246+
return err
339247
}
340248
fi.argConverters = append(fi.argConverters, conv)
341249
}
342250

251+
conv, err := callbackRet(t.Out(0))
252+
if err != nil {
253+
return err
254+
}
255+
fi.retConverter = conv
256+
343257
// fi must outlast the database connection, or we'll have dangling pointers.
344258
c.funcs = append(c.funcs, &fi)
345259

‎sqlite3_test.go

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"net/url"
1616
"os"
1717
"path/filepath"
18+
"reflect"
1819
"regexp"
1920
"strings"
2021
"sync"
@@ -1060,25 +1061,41 @@ func TestDateTimeNow(t *testing.T) {
10601061
}
10611062

10621063
func TestFunctionRegistration(t *testing.T) {
1063-
custom_add := func(a, b int64) (int64, error) {
1064-
return a + b, nil
1065-
}
1066-
custom_regex := func(s, re string) bool {
1067-
matched, err := regexp.MatchString(re, s)
1068-
if err != nil {
1069-
// We should really return the error here, but this
1070-
// function is also testing single return value functions.
1071-
panic("Bad regexp")
1072-
}
1073-
return matched
1064+
addi_8_16_32 := func(a int8, b int16) int32 { return int32(a) + int32(b) }
1065+
addi_64 := func(a, b int64) int64 { return a + b }
1066+
addu_8_16_32 := func(a uint8, b uint16) uint32 { return uint32(a) + uint32(b) }
1067+
addu_64 := func(a, b uint64) uint64 { return a + b }
1068+
addiu := func(a int, b uint) int64 { return int64(a) + int64(b) }
1069+
addf_32_64 := func(a float32, b float64) float64 { return float64(a) + b }
1070+
not := func(a bool) bool { return !a }
1071+
regex := func(re, s string) (bool, error) {
1072+
return regexp.MatchString(re, s)
10741073
}
10751074

10761075
sql.Register("sqlite3_FunctionRegistration", &SQLiteDriver{
10771076
ConnectHook: func(conn *SQLiteConn) error {
1078-
if err := conn.RegisterFunc("custom_add", custom_add, true); err != nil {
1077+
if err := conn.RegisterFunc("addi_8_16_32", addi_8_16_32, true); err != nil {
1078+
return err
1079+
}
1080+
if err := conn.RegisterFunc("addi_64", addi_64, true); err != nil {
1081+
return err
1082+
}
1083+
if err := conn.RegisterFunc("addu_8_16_32", addu_8_16_32, true); err != nil {
10791084
return err
10801085
}
1081-
if err := conn.RegisterFunc("regexp", custom_regex, true); err != nil {
1086+
if err := conn.RegisterFunc("addu_64", addu_64, true); err != nil {
1087+
return err
1088+
}
1089+
if err := conn.RegisterFunc("addiu", addiu, true); err != nil {
1090+
return err
1091+
}
1092+
if err := conn.RegisterFunc("addf_32_64", addf_32_64, true); err != nil {
1093+
return err
1094+
}
1095+
if err := conn.RegisterFunc("not", not, true); err != nil {
1096+
return err
1097+
}
1098+
if err := conn.RegisterFunc("regex", regex, true); err != nil {
10821099
return err
10831100
}
10841101
return nil
@@ -1090,42 +1107,29 @@ func TestFunctionRegistration(t *testing.T) {
10901107
}
10911108
defer db.Close()
10921109

1093-
additions := []struct {
1094-
a, b, c int64
1110+
ops := []struct {
1111+
query string
1112+
expected interface{}
10951113
}{
1096-
{1, 1, 2},
1097-
{1, 3, 4},
1098-
{1, -1, 0},
1099-
}
1100-
1101-
for _, add := range additions {
1102-
var i int64
1103-
err = db.QueryRow("SELECT custom_add($1, $2)", add.a, add.b).Scan(&i)
1114+
{"SELECT addi_8_16_32(1,2)", int32(3)},
1115+
{"SELECT addi_64(1,2)", int64(3)},
1116+
{"SELECT addu_8_16_32(1,2)", uint32(3)},
1117+
{"SELECT addu_64(1,2)", uint64(3)},
1118+
{"SELECT addiu(1,2)", int64(3)},
1119+
{"SELECT addf_32_64(1.5,1.5)", float64(3)},
1120+
{"SELECT not(1)", false},
1121+
{"SELECT not(0)", true},
1122+
{`SELECT regex("^foo.*", "foobar")`, true},
1123+
{`SELECT regex("^foo.*", "barfoobar")`, false},
1124+
}
1125+
1126+
for _, op := range ops {
1127+
ret := reflect.New(reflect.TypeOf(op.expected))
1128+
err = db.QueryRow(op.query).Scan(ret.Interface())
11041129
if err != nil {
1105-
t.Fatal("Failed to call custom_add:", err)
1106-
}
1107-
if i != add.c {
1108-
t.Fatalf("custom_add returned the wrong value, got %d, want %d", i, add.c)
1109-
}
1110-
}
1111-
1112-
regexes := []struct {
1113-
re, in string
1114-
out bool
1115-
}{
1116-
{".*", "foo", true},
1117-
{"^foo.*", "foobar", true},
1118-
{"^foo.*", "barfoo", false},
1119-
}
1120-
1121-
for _, re := range regexes {
1122-
var b bool
1123-
err = db.QueryRow("SELECT regexp($1, $2)", re.in, re.re).Scan(&b)
1124-
if err != nil {
1125-
t.Fatal("Failed to call regexp:", err)
1126-
}
1127-
if b != re.out {
1128-
t.Fatalf("regexp returned the wrong value, got %v, want %v", b, re.out)
1130+
t.Errorf("Query %q failed: %s", op.query, err)
1131+
} else if !reflect.DeepEqual(ret.Elem().Interface(), op.expected) {
1132+
t.Errorf("Query %q returned wrong value: got %v (%T), want %v (%T)", op.query, ret.Elem().Interface(), ret.Elem().Interface(), op.expected, op.expected)
11291133
}
11301134
}
11311135
}
@@ -1134,8 +1138,8 @@ var customFunctionOnce sync.Once
11341138

11351139
func BenchmarkCustomFunctions(b *testing.B) {
11361140
customFunctionOnce.Do(func() {
1137-
custom_add := func(a, b int64) (int64, error) {
1138-
return a + b, nil
1141+
custom_add := func(a, b int64) int64 {
1142+
return a + b
11391143
}
11401144

11411145
sql.Register("sqlite3_BenchmarkCustomFunctions", &SQLiteDriver{

0 commit comments

Comments
 (0)
Please sign in to comment.