Skip to content

Commit b037a61

Browse files
committed
Add support for interface{} arguments in Go SQLite functions.
This enabled support for functions like Foo(a interface{}) and Bar(a ...interface{}).
1 parent 566f63a commit b037a61

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

callback.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,32 @@ func callbackArgString(v *C.sqlite3_value) (reflect.Value, error) {
108108
}
109109
}
110110

111+
func callbackArgGeneric(v *C.sqlite3_value) (reflect.Value, error) {
112+
switch C.sqlite3_value_type(v) {
113+
case C.SQLITE_INTEGER:
114+
return callbackArgInt64(v)
115+
case C.SQLITE_FLOAT:
116+
return callbackArgFloat64(v)
117+
case C.SQLITE_TEXT:
118+
return callbackArgString(v)
119+
case C.SQLITE_BLOB:
120+
return callbackArgBytes(v)
121+
case C.SQLITE_NULL:
122+
// Interpret NULL as a nil byte slice.
123+
var ret []byte
124+
return reflect.ValueOf(ret), nil
125+
default:
126+
panic("unreachable")
127+
}
128+
}
129+
111130
func callbackArg(typ reflect.Type) (callbackArgConverter, error) {
112131
switch typ.Kind() {
132+
case reflect.Interface:
133+
if typ.NumMethod() != 0 {
134+
return nil, errors.New("the only supported interface type is interface{}")
135+
}
136+
return callbackArgGeneric, nil
113137
case reflect.Slice:
114138
if typ.Elem().Kind() != reflect.Uint8 {
115139
return nil, errors.New("the only supported slice type is []byte")

sqlite3.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,14 @@ func (tx *SQLiteTx) Rollback() error {
232232

233233
// RegisterFunc makes a Go function available as a SQLite function.
234234
//
235-
// The function can accept arguments of any real numeric type
236-
// (i.e. not complex), as well as []byte and string. It must return a
237-
// value of one of those types, and optionally an error as a second
238-
// value. Variadic functions are allowed, if the variadic argument is
239-
// one of the allowed types.
235+
// The Go function can have arguments of the following types: any
236+
// numeric type except complex, bool, []byte, string and
237+
// interface{}. interface{} arguments are given the direct translation
238+
// of the SQLite data type: int64 for INTEGER, float64 for FLOAT,
239+
// []byte for BLOB, string for TEXT.
240+
//
241+
// The function can additionally be variadic, as long as the type of
242+
// the variadic argument is one of the above.
240243
//
241244
// If pure is true. SQLite will assume that the function's return
242245
// value depends only on its inputs, and make more aggressive

sqlite3_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,13 +1071,30 @@ func TestFunctionRegistration(t *testing.T) {
10711071
regex := func(re, s string) (bool, error) {
10721072
return regexp.MatchString(re, s)
10731073
}
1074+
generic := func(a interface{}) int64 {
1075+
switch a.(type) {
1076+
case int64:
1077+
return 1
1078+
case float64:
1079+
return 2
1080+
case []byte:
1081+
return 3
1082+
case string:
1083+
return 4
1084+
default:
1085+
panic("unreachable")
1086+
}
1087+
}
10741088
variadic := func(a, b int64, c ...int64) int64 {
10751089
ret := a + b
10761090
for _, d := range c {
10771091
ret += d
10781092
}
10791093
return ret
10801094
}
1095+
variadicGeneric := func(a ...interface{}) int64 {
1096+
return int64(len(a))
1097+
}
10811098

10821099
sql.Register("sqlite3_FunctionRegistration", &SQLiteDriver{
10831100
ConnectHook: func(conn *SQLiteConn) error {
@@ -1105,9 +1122,15 @@ func TestFunctionRegistration(t *testing.T) {
11051122
if err := conn.RegisterFunc("regex", regex, true); err != nil {
11061123
return err
11071124
}
1125+
if err := conn.RegisterFunc("generic", generic, true); err != nil {
1126+
return err
1127+
}
11081128
if err := conn.RegisterFunc("variadic", variadic, true); err != nil {
11091129
return err
11101130
}
1131+
if err := conn.RegisterFunc("variadicGeneric", variadicGeneric, true); err != nil {
1132+
return err
1133+
}
11111134
return nil
11121135
},
11131136
})
@@ -1131,9 +1154,14 @@ func TestFunctionRegistration(t *testing.T) {
11311154
{"SELECT not(0)", true},
11321155
{`SELECT regex("^foo.*", "foobar")`, true},
11331156
{`SELECT regex("^foo.*", "barfoobar")`, false},
1157+
{"SELECT generic(1)", int64(1)},
1158+
{"SELECT generic(1.1)", int64(2)},
1159+
{`SELECT generic(NULL)`, int64(3)},
1160+
{`SELECT generic("foo")`, int64(4)},
11341161
{"SELECT variadic(1,2)", int64(3)},
11351162
{"SELECT variadic(1,2,3,4)", int64(10)},
11361163
{"SELECT variadic(1,1,1,1,1,1,1,1,1,1)", int64(10)},
1164+
{`SELECT variadicGeneric(1,"foo",2.3, NULL)`, int64(4)},
11371165
}
11381166

11391167
for _, op := range ops {

0 commit comments

Comments
 (0)