Commit dee9b21f authored by gwenn's avatar gwenn

Second draft of user's defined functions in Go.

parent 7b3d5a3e
...@@ -17,6 +17,35 @@ static void my_result_blob(sqlite3_context *ctx, void *p, int np) { ...@@ -17,6 +17,35 @@ static void my_result_blob(sqlite3_context *ctx, void *p, int np) {
sqlite3_result_blob(ctx, p, np, SQLITE_TRANSIENT); sqlite3_result_blob(ctx, p, np, SQLITE_TRANSIENT);
} }
static void my_result_value(sqlite3_context* ctx, sqlite3_value** argv, int i) {
sqlite3_result_value(ctx, argv[i]);
}
static const void *my_value_blob(sqlite3_value** argv, int i) {
return sqlite3_value_blob(argv[i]);
}
static int my_value_bytes(sqlite3_value** argv, int i) {
return sqlite3_value_bytes(argv[i]);
}
static double my_value_double(sqlite3_value** argv, int i) {
return sqlite3_value_double(argv[i]);
}
static int my_value_int(sqlite3_value** argv, int i) {
return sqlite3_value_int(argv[i]);
}
static sqlite3_int64 my_value_int64(sqlite3_value** argv, int i) {
return sqlite3_value_int64(argv[i]);
}
static const unsigned char *my_value_text(sqlite3_value** argv, int i) {
return sqlite3_value_text(argv[i]);
}
static int my_value_type(sqlite3_value** argv, int i) {
return sqlite3_value_type(argv[i]);
}
static int my_value_numeric_type(sqlite3_value** argv, int i) {
return sqlite3_value_numeric_type(argv[i]);
}
extern void goXFunc(sqlite3_context* ctx, int argc, sqlite3_value** argv); extern void goXFunc(sqlite3_context* ctx, int argc, sqlite3_value** argv);
extern void goXDestroy(void *pApp); extern void goXDestroy(void *pApp);
...@@ -39,7 +68,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ...@@ -39,7 +68,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
type Context struct { type Context struct {
context *C.sqlite3_context context *C.sqlite3_context
pApp interface{} argv **C.sqlite3_value
} }
// Set the result of an SQL function // Set the result of an SQL function
...@@ -111,9 +140,10 @@ func (c *Context) ResultText(s string) { ...@@ -111,9 +140,10 @@ func (c *Context) ResultText(s string) {
} }
// Set the result of an SQL function // Set the result of an SQL function
// The leftmost value is number 0.
// Calls sqlite3_result_value, http://sqlite.org/c3ref/result_blob.html // Calls sqlite3_result_value, http://sqlite.org/c3ref/result_blob.html
func (c *Context) ResultValue(v *Value) { func (c *Context) ResultValue(i int) {
C.sqlite3_result_value(c.context, v.value) C.my_result_value(c.context, c.argv, C.int(i))
} }
// Set the result of an SQL function // Set the result of an SQL function
...@@ -125,7 +155,8 @@ func (c *Context) ResultZeroblob(n ZeroBlobLength) { ...@@ -125,7 +155,8 @@ func (c *Context) ResultZeroblob(n ZeroBlobLength) {
// User data for functions // User data for functions
// Calls http://sqlite.org/c3ref/user_data.html // Calls http://sqlite.org/c3ref/user_data.html
func (c *Context) UserData() interface{} { func (c *Context) UserData() interface{} {
return c.pApp udp := (*sqliteScalarFunction)(C.sqlite3_user_data(c.context))
return udp.pApp
} }
// Function auxiliary data // Function auxiliary data
...@@ -142,59 +173,61 @@ func (c *Context) SetAuxData(n int, ad interface{}, f AuxDataDestructor) { ...@@ -142,59 +173,61 @@ func (c *Context) SetAuxData(n int, ad interface{}, f AuxDataDestructor) {
// FIXME C.sqlite3_set_auxdata(c.context, C.int(n), unsafe.Pointer(ad), nil /*void (*)(void*)*/ ) // FIXME C.sqlite3_set_auxdata(c.context, C.int(n), unsafe.Pointer(ad), nil /*void (*)(void*)*/ )
} }
// SQL function parameter value // The leftmost value is number 0.
type Value struct {
value *C.sqlite3_value
}
// Calls sqlite3_value_blob and sqlite3_value_bytes, http://sqlite.org/c3ref/value_blob.html // Calls sqlite3_value_blob and sqlite3_value_bytes, http://sqlite.org/c3ref/value_blob.html
func (v *Value) Blob() (value []byte) { func (c *Context) Blob(i int) (value []byte) {
p := C.sqlite3_value_blob(v.value) p := C.my_value_blob(c.argv, C.int(i))
if p != nil { if p != nil {
n := C.sqlite3_value_bytes(v.value) n := C.my_value_bytes(c.argv, C.int(i))
value = (*[1 << 30]byte)(unsafe.Pointer(p))[0:n] value = (*[1 << 30]byte)(unsafe.Pointer(p))[0:n]
} }
return return
} }
// The leftmost value is number 0.
// Calls sqlite3_value_double, http://sqlite.org/c3ref/value_blob.html // Calls sqlite3_value_double, http://sqlite.org/c3ref/value_blob.html
func (v *Value) Double() float64 { func (c *Context) Double(i int) float64 {
return float64(C.sqlite3_value_double(v.value)) return float64(C.my_value_double(c.argv, C.int(i)))
} }
// The leftmost value is number 0.
// Calls sqlite3_value_int, http://sqlite.org/c3ref/value_blob.html // Calls sqlite3_value_int, http://sqlite.org/c3ref/value_blob.html
func (v *Value) Int() int { func (c *Context) Int(i int) int {
return int(C.sqlite3_value_int(v.value)) return int(C.my_value_int(c.argv, C.int(i)))
} }
// The leftmost value is number 0.
// Calls sqlite3_value_int64, http://sqlite.org/c3ref/value_blob.html // Calls sqlite3_value_int64, http://sqlite.org/c3ref/value_blob.html
func (v *Value) Int64() int64 { func (c *Context) Int64(i int) int64 {
return int64(C.sqlite3_value_int64(v.value)) return int64(C.my_value_int64(c.argv, C.int(i)))
} }
// The leftmost value is number 0.
// Calls sqlite3_value_text, http://sqlite.org/c3ref/value_blob.html // Calls sqlite3_value_text, http://sqlite.org/c3ref/value_blob.html
func (v *Value) Text() string { func (c *Context) Text(i int) string {
p := C.sqlite3_value_text(v.value) p := C.my_value_text(c.argv, C.int(i))
if p == nil { if p == nil {
return "" return ""
} }
n := C.sqlite3_value_bytes(v.value) n := C.my_value_bytes(c.argv, C.int(i))
return C.GoStringN((*C.char)(unsafe.Pointer(p)), n) return C.GoStringN((*C.char)(unsafe.Pointer(p)), n)
} }
// The leftmost value is number 0.
// SQL function parameter value type // SQL function parameter value type
// Calls sqlite3_value_type, http://sqlite.org/c3ref/value_blob.html // Calls sqlite3_value_type, http://sqlite.org/c3ref/value_blob.html
func (v *Value) Type() Type { func (c *Context) Type(i int) Type {
return Type(C.sqlite3_value_type(v.value)) return Type(C.my_value_type(c.argv, C.int(i)))
} }
// The leftmost value is number 0.
// SQL function parameter value numeric type (with possible conversion) // SQL function parameter value numeric type (with possible conversion)
// Calls sqlite3_value_numeric_type, http://sqlite.org/c3ref/value_blob.html // Calls sqlite3_value_numeric_type, http://sqlite.org/c3ref/value_blob.html
func (v *Value) NumericType() Type { func (c *Context) NumericType(i int) Type {
return Type(C.sqlite3_value_numeric_type(v.value)) return Type(C.my_value_numeric_type(c.argv, C.int(i)))
} }
type ScalarFunction func(ctx *Context, values []Value) type ScalarFunction func(ctx *Context, nArg int)
type DestroyFunctionData func(pApp interface{}) type DestroyFunctionData func(pApp interface{})
type sqliteScalarFunction struct { type sqliteScalarFunction struct {
...@@ -204,13 +237,12 @@ type sqliteScalarFunction struct { ...@@ -204,13 +237,12 @@ type sqliteScalarFunction struct {
} }
//export goXFunc //export goXFunc
func goXFunc(ctxp unsafe.Pointer, argc C.int, argvp unsafe.Pointer) { func goXFunc(ctxp unsafe.Pointer, argc int, argv unsafe.Pointer) {
ctx := (*C.sqlite3_context)(ctxp) ctx := (*C.sqlite3_context)(ctxp)
argv := (**C.sqlite3_value)(argvp) udp := (*sqliteScalarFunction)(C.sqlite3_user_data(ctx))
pApp := (*sqliteScalarFunction)(C.sqlite3_user_data(ctx))
// TODO How to avoid to create a Context at each call? // TODO How to avoid to create a Context at each call?
// TODO How to avoid to create Values at each call? context := &Context{ctx, (**C.sqlite3_value)(argv)}
println(ctx, pApp, argc, argv) udp.f(context, argc)
} }
//export goXDestroy //export goXDestroy
...@@ -240,4 +272,4 @@ func (c *Conn) CreateScalarFunction(functionName string, nArg int, pApp interfac ...@@ -240,4 +272,4 @@ func (c *Conn) CreateScalarFunction(functionName string, nArg int, pApp interfac
} }
c.udfs[functionName] = xFunc // FIXME same function name with different args is not supported c.udfs[functionName] = xFunc // FIXME same function name with different args is not supported
return c.error(C.goSqlite3CreateFunctionV2(c.db, fname, C.int(nArg), C.SQLITE_UTF8, unsafe.Pointer(xFunc))) return c.error(C.goSqlite3CreateFunctionV2(c.db, fname, C.int(nArg), C.SQLITE_UTF8, unsafe.Pointer(xFunc)))
} }
\ No newline at end of file
...@@ -92,7 +92,7 @@ type sqliteUpdateHook struct { ...@@ -92,7 +92,7 @@ type sqliteUpdateHook struct {
} }
//export goXUpdateHook //export goXUpdateHook
func goXUpdateHook(udp unsafe.Pointer, action C.int, dbName, tableName *C.char, rowId C.sqlite3_int64) { func goXUpdateHook(udp unsafe.Pointer, action int, dbName, tableName *C.char, rowId C.sqlite3_int64) {
arg := (*sqliteUpdateHook)(udp) arg := (*sqliteUpdateHook)(udp)
arg.f(arg.udp, Action(action), C.GoString(dbName), C.GoString(tableName), int64(rowId)) arg.f(arg.udp, Action(action), C.GoString(dbName), C.GoString(tableName), int64(rowId))
} }
......
...@@ -167,7 +167,7 @@ type sqliteAuthorizer struct { ...@@ -167,7 +167,7 @@ type sqliteAuthorizer struct {
} }
//export goXAuth //export goXAuth
func goXAuth(udp unsafe.Pointer, action C.int, arg1, arg2, dbName, triggerName *C.char) C.int { func goXAuth(udp unsafe.Pointer, action int, arg1, arg2, dbName, triggerName *C.char) C.int {
arg := (*sqliteAuthorizer)(udp) arg := (*sqliteAuthorizer)(udp)
result := arg.f(arg.udp, Action(action), C.GoString(arg1), C.GoString(arg2), C.GoString(dbName), C.GoString(triggerName)) result := arg.f(arg.udp, Action(action), C.GoString(arg1), C.GoString(arg2), C.GoString(dbName), C.GoString(triggerName))
return C.int(result) return C.int(result)
...@@ -195,9 +195,9 @@ type sqliteBusyHandler struct { ...@@ -195,9 +195,9 @@ type sqliteBusyHandler struct {
} }
//export goXBusy //export goXBusy
func goXBusy(udp unsafe.Pointer, count C.int) C.int { func goXBusy(udp unsafe.Pointer, count int) C.int {
arg := (*sqliteBusyHandler)(udp) arg := (*sqliteBusyHandler)(udp)
result := arg.f(arg.udp, int(count)) result := arg.f(arg.udp, count)
return btocint(result) return btocint(result)
} }
...@@ -307,7 +307,7 @@ type sqliteLogger struct { ...@@ -307,7 +307,7 @@ type sqliteLogger struct {
} }
//export goXLog //export goXLog
func goXLog(udp unsafe.Pointer, err C.int, msg *C.char) { func goXLog(udp unsafe.Pointer, err int, msg *C.char) {
arg := (*sqliteLogger)(udp) arg := (*sqliteLogger)(udp)
arg.f(arg.udp, Errno(err), C.GoString(msg)) arg.f(arg.udp, Errno(err), C.GoString(msg))
return return
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment