| @@ -566,11 +566,11 @@ | |||
| version = "v1.46.1" | |||
| [[projects]] | |||
| digest = "1:3ef954101983406a71171c4dc816a73e01bb3de608b3dd063627aa67a459f3e3" | |||
| digest = "1:9996f2363985103284c59b3d0ca5be58deb1b0db22144bb2fcfa0b4e16f0e61b" | |||
| name = "github.com/mattn/go-sqlite3" | |||
| packages = ["."] | |||
| pruneopts = "NUT" | |||
| revision = "acfa60124032040b9f5a9406f5a772ee16fe845e" | |||
| revision = "f3aa5ce89995fab8c7777f7821f689d9ac81c80f" | |||
| [[projects]] | |||
| branch = "master" | |||
| @@ -39,6 +39,10 @@ ignored = ["google.golang.org/appengine*"] | |||
| name = "github.com/go-sql-driver/mysql" | |||
| revision = "d523deb1b23d913de5bdada721a6071e71283618" | |||
| [[override]] | |||
| name = "github.com/mattn/go-sqlite3" | |||
| revision = "f3aa5ce89995fab8c7777f7821f689d9ac81c80f" | |||
| [[override]] | |||
| name = "github.com/gorilla/mux" | |||
| revision = "757bef944d0f21880861c2dd9c871ca543023cba" | |||
| @@ -53,6 +53,36 @@ func doneTrampoline(ctx *C.sqlite3_context) { | |||
| ai.Done(ctx) | |||
| } | |||
| //export compareTrampoline | |||
| func compareTrampoline(handlePtr uintptr, la C.int, a *C.char, lb C.int, b *C.char) C.int { | |||
| cmp := lookupHandle(handlePtr).(func(string, string) int) | |||
| return C.int(cmp(C.GoStringN(a, la), C.GoStringN(b, lb))) | |||
| } | |||
| //export commitHookTrampoline | |||
| func commitHookTrampoline(handle uintptr) int { | |||
| callback := lookupHandle(handle).(func() int) | |||
| return callback() | |||
| } | |||
| //export rollbackHookTrampoline | |||
| func rollbackHookTrampoline(handle uintptr) { | |||
| callback := lookupHandle(handle).(func()) | |||
| callback() | |||
| } | |||
| //export updateHookTrampoline | |||
| func updateHookTrampoline(handle uintptr, op int, db *C.char, table *C.char, rowid int64) { | |||
| callback := lookupHandle(handle).(func(int, string, string, int64)) | |||
| callback(op, C.GoString(db), C.GoString(table), rowid) | |||
| } | |||
| //export authorizerTrampoline | |||
| func authorizerTrampoline(handle uintptr, op int, arg1 *C.char, arg2 *C.char, arg3 *C.char) int { | |||
| callback := lookupHandle(handle).(func(int, string, string, string) int) | |||
| return callback(op, C.GoString(arg1), C.GoString(arg2), C.GoString(arg3)) | |||
| } | |||
| // Use handles to avoid passing Go pointers to C. | |||
| type handleVal struct { | |||
| @@ -307,8 +337,18 @@ func callbackRetText(ctx *C.sqlite3_context, v reflect.Value) error { | |||
| return nil | |||
| } | |||
| func callbackRetNil(ctx *C.sqlite3_context, v reflect.Value) error { | |||
| return nil | |||
| } | |||
| func callbackRet(typ reflect.Type) (callbackRetConverter, error) { | |||
| switch typ.Kind() { | |||
| case reflect.Interface: | |||
| errorInterface := reflect.TypeOf((*error)(nil)).Elem() | |||
| if typ.Implements(errorInterface) { | |||
| return callbackRetNil, nil | |||
| } | |||
| fallthrough | |||
| case reflect.Slice: | |||
| if typ.Elem().Kind() != reflect.Uint8 { | |||
| return nil, errors.New("the only supported slice type is []byte") | |||
| @@ -0,0 +1,120 @@ | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| package sqlite3 | |||
| import ( | |||
| "crypto/sha1" | |||
| "crypto/sha256" | |||
| "crypto/sha512" | |||
| ) | |||
| // This file provides several different implementations for the | |||
| // default embedded sqlite_crypt function. | |||
| // This function is uses a ceasar-cypher by default | |||
| // and is used within the UserAuthentication module to encode | |||
| // the password. | |||
| // | |||
| // The provided functions can be used as an overload to the sqlite_crypt | |||
| // function through the use of the RegisterFunc on the connection. | |||
| // | |||
| // Because the functions can serv a purpose to an end-user | |||
| // without using the UserAuthentication module | |||
| // the functions are default compiled in. | |||
| // | |||
| // From SQLITE3 - user-auth.txt | |||
| // The sqlite_user.pw field is encoded by a built-in SQL function | |||
| // "sqlite_crypt(X,Y)". The two arguments are both BLOBs. The first argument | |||
| // is the plaintext password supplied to the sqlite3_user_authenticate() | |||
| // interface. The second argument is the sqlite_user.pw value and is supplied | |||
| // so that the function can extract the "salt" used by the password encoder. | |||
| // The result of sqlite_crypt(X,Y) is another blob which is the value that | |||
| // ends up being stored in sqlite_user.pw. To verify credentials X supplied | |||
| // by the sqlite3_user_authenticate() routine, SQLite runs: | |||
| // | |||
| // sqlite_user.pw == sqlite_crypt(X, sqlite_user.pw) | |||
| // | |||
| // To compute an appropriate sqlite_user.pw value from a new or modified | |||
| // password X, sqlite_crypt(X,NULL) is run. A new random salt is selected | |||
| // when the second argument is NULL. | |||
| // | |||
| // The built-in version of of sqlite_crypt() uses a simple Ceasar-cypher | |||
| // which prevents passwords from being revealed by searching the raw database | |||
| // for ASCII text, but is otherwise trivally broken. For better password | |||
| // security, the database should be encrypted using the SQLite Encryption | |||
| // Extension or similar technology. Or, the application can use the | |||
| // sqlite3_create_function() interface to provide an alternative | |||
| // implementation of sqlite_crypt() that computes a stronger password hash, | |||
| // perhaps using a cryptographic hash function like SHA1. | |||
| // CryptEncoderSHA1 encodes a password with SHA1 | |||
| func CryptEncoderSHA1(pass []byte, hash interface{}) []byte { | |||
| h := sha1.Sum(pass) | |||
| return h[:] | |||
| } | |||
| // CryptEncoderSSHA1 encodes a password with SHA1 with the | |||
| // configured salt. | |||
| func CryptEncoderSSHA1(salt string) func(pass []byte, hash interface{}) []byte { | |||
| return func(pass []byte, hash interface{}) []byte { | |||
| s := []byte(salt) | |||
| p := append(pass, s...) | |||
| h := sha1.Sum(p) | |||
| return h[:] | |||
| } | |||
| } | |||
| // CryptEncoderSHA256 encodes a password with SHA256 | |||
| func CryptEncoderSHA256(pass []byte, hash interface{}) []byte { | |||
| h := sha256.Sum256(pass) | |||
| return h[:] | |||
| } | |||
| // CryptEncoderSSHA256 encodes a password with SHA256 | |||
| // with the configured salt | |||
| func CryptEncoderSSHA256(salt string) func(pass []byte, hash interface{}) []byte { | |||
| return func(pass []byte, hash interface{}) []byte { | |||
| s := []byte(salt) | |||
| p := append(pass, s...) | |||
| h := sha256.Sum256(p) | |||
| return h[:] | |||
| } | |||
| } | |||
| // CryptEncoderSHA384 encodes a password with SHA384 | |||
| func CryptEncoderSHA384(pass []byte, hash interface{}) []byte { | |||
| h := sha512.Sum384(pass) | |||
| return h[:] | |||
| } | |||
| // CryptEncoderSSHA384 encodes a password with SHA384 | |||
| // with the configured salt | |||
| func CryptEncoderSSHA384(salt string) func(pass []byte, hash interface{}) []byte { | |||
| return func(pass []byte, hash interface{}) []byte { | |||
| s := []byte(salt) | |||
| p := append(pass, s...) | |||
| h := sha512.Sum384(p) | |||
| return h[:] | |||
| } | |||
| } | |||
| // CryptEncoderSHA512 encodes a password with SHA512 | |||
| func CryptEncoderSHA512(pass []byte, hash interface{}) []byte { | |||
| h := sha512.Sum512(pass) | |||
| return h[:] | |||
| } | |||
| // CryptEncoderSSHA512 encodes a password with SHA512 | |||
| // with the configured salt | |||
| func CryptEncoderSSHA512(salt string) func(pass []byte, hash interface{}) []byte { | |||
| return func(pass []byte, hash interface{}) []byte { | |||
| s := []byte(salt) | |||
| p := append(pass, s...) | |||
| h := sha512.Sum512(p) | |||
| return h[:] | |||
| } | |||
| } | |||
| // EOF | |||
| @@ -3,6 +3,7 @@ | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build cgo | |||
| // +build go1.8 | |||
| package sqlite3 | |||
| @@ -2,6 +2,7 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build libsqlite3 | |||
| package sqlite3 | |||
| @@ -10,5 +11,7 @@ package sqlite3 | |||
| #cgo CFLAGS: -DUSE_LIBSQLITE3 | |||
| #cgo linux LDFLAGS: -lsqlite3 | |||
| #cgo darwin LDFLAGS: -L/usr/local/opt/sqlite/lib -lsqlite3 | |||
| #cgo openbsd LDFLAGS: -lsqlite3 | |||
| #cgo solaris LDFLAGS: -lsqlite3 | |||
| */ | |||
| import "C" | |||
| @@ -2,6 +2,7 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !sqlite_omit_load_extension | |||
| package sqlite3 | |||
| @@ -2,6 +2,7 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_omit_load_extension | |||
| package sqlite3 | |||
| @@ -0,0 +1,15 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_allow_uri_authority | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_ALLOW_URI_AUTHORITY | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -0,0 +1,16 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !windows | |||
| // +build sqlite_app_armor | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_API_ARMOR | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -0,0 +1,15 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_foreign_keys | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_DEFAULT_FOREIGN_KEYS=1 | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -2,7 +2,8 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build fts5 | |||
| // +build sqlite_fts5 fts5 | |||
| package sqlite3 | |||
| @@ -2,12 +2,16 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build icu | |||
| // +build sqlite_icu icu | |||
| package sqlite3 | |||
| /* | |||
| #cgo LDFLAGS: -licuuc -licui18n | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_ICU | |||
| #cgo darwin CFLAGS: -I/usr/local/opt/icu4c/include | |||
| #cgo darwin LDFLAGS: -L/usr/local/opt/icu4c/lib | |||
| #cgo openbsd LDFLAGS: -lsqlite3 | |||
| */ | |||
| import "C" | |||
| @@ -0,0 +1,15 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_introspect | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_INTROSPECTION_PRAGMAS | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -2,7 +2,8 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build json1 | |||
| // +build sqlite_json sqlite_json1 json1 | |||
| package sqlite3 | |||
| @@ -0,0 +1,15 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_secure_delete | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_SECURE_DELETE=1 | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -0,0 +1,15 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_secure_delete_fast | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_SECURE_DELETE=FAST | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -0,0 +1,15 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_stat4 | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_STAT4 | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -0,0 +1,85 @@ | |||
| // Copyright (C) 2018 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY | |||
| #include <stdio.h> | |||
| #include <sqlite3-binding.h> | |||
| extern int unlock_notify_wait(sqlite3 *db); | |||
| int | |||
| _sqlite3_step_blocking(sqlite3_stmt *stmt) | |||
| { | |||
| int rv; | |||
| sqlite3* db; | |||
| db = sqlite3_db_handle(stmt); | |||
| for (;;) { | |||
| rv = sqlite3_step(stmt); | |||
| if (rv != SQLITE_LOCKED) { | |||
| break; | |||
| } | |||
| if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) { | |||
| break; | |||
| } | |||
| rv = unlock_notify_wait(db); | |||
| if (rv != SQLITE_OK) { | |||
| break; | |||
| } | |||
| sqlite3_reset(stmt); | |||
| } | |||
| return rv; | |||
| } | |||
| int | |||
| _sqlite3_step_row_blocking(sqlite3_stmt* stmt, long long* rowid, long long* changes) | |||
| { | |||
| int rv; | |||
| sqlite3* db; | |||
| db = sqlite3_db_handle(stmt); | |||
| for (;;) { | |||
| rv = sqlite3_step(stmt); | |||
| if (rv!=SQLITE_LOCKED) { | |||
| break; | |||
| } | |||
| if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) { | |||
| break; | |||
| } | |||
| rv = unlock_notify_wait(db); | |||
| if (rv != SQLITE_OK) { | |||
| break; | |||
| } | |||
| sqlite3_reset(stmt); | |||
| } | |||
| *rowid = (long long) sqlite3_last_insert_rowid(db); | |||
| *changes = (long long) sqlite3_changes(db); | |||
| return rv; | |||
| } | |||
| int | |||
| _sqlite3_prepare_v2_blocking(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail) | |||
| { | |||
| int rv; | |||
| for (;;) { | |||
| rv = sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail); | |||
| if (rv!=SQLITE_LOCKED) { | |||
| break; | |||
| } | |||
| if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) { | |||
| break; | |||
| } | |||
| rv = unlock_notify_wait(db); | |||
| if (rv != SQLITE_OK) { | |||
| break; | |||
| } | |||
| } | |||
| return rv; | |||
| } | |||
| #endif | |||
| @@ -0,0 +1,92 @@ | |||
| // Copyright (C) 2018 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build cgo | |||
| // +build sqlite_unlock_notify | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY | |||
| #include <stdlib.h> | |||
| #include <sqlite3-binding.h> | |||
| extern void unlock_notify_callback(void *arg, int argc); | |||
| */ | |||
| import "C" | |||
| import ( | |||
| "fmt" | |||
| "sync" | |||
| "unsafe" | |||
| ) | |||
| type unlock_notify_table struct { | |||
| sync.Mutex | |||
| seqnum uint | |||
| table map[uint]chan struct{} | |||
| } | |||
| var unt unlock_notify_table = unlock_notify_table{table: make(map[uint]chan struct{})} | |||
| func (t *unlock_notify_table) add(c chan struct{}) uint { | |||
| t.Lock() | |||
| defer t.Unlock() | |||
| h := t.seqnum | |||
| t.table[h] = c | |||
| t.seqnum++ | |||
| return h | |||
| } | |||
| func (t *unlock_notify_table) remove(h uint) { | |||
| t.Lock() | |||
| defer t.Unlock() | |||
| delete(t.table, h) | |||
| } | |||
| func (t *unlock_notify_table) get(h uint) chan struct{} { | |||
| t.Lock() | |||
| defer t.Unlock() | |||
| c, ok := t.table[h] | |||
| if !ok { | |||
| panic(fmt.Sprintf("Non-existent key for unlcok-notify channel: %d", h)) | |||
| } | |||
| return c | |||
| } | |||
| //export unlock_notify_callback | |||
| func unlock_notify_callback(argv unsafe.Pointer, argc C.int) { | |||
| for i := 0; i < int(argc); i++ { | |||
| parg := ((*(*[1 << 30]*[1]uint)(argv))[i]) | |||
| arg := *parg | |||
| h := arg[0] | |||
| c := unt.get(h) | |||
| c <- struct{}{} | |||
| } | |||
| } | |||
| //export unlock_notify_wait | |||
| func unlock_notify_wait(db *C.sqlite3) C.int { | |||
| // It has to be a bufferred channel to not block in sqlite_unlock_notify | |||
| // as sqlite_unlock_notify could invoke the callback before it returns. | |||
| c := make(chan struct{}, 1) | |||
| defer close(c) | |||
| h := unt.add(c) | |||
| defer unt.remove(h) | |||
| pargv := C.malloc(C.sizeof_uint) | |||
| defer C.free(pargv) | |||
| argv := (*[1]uint)(pargv) | |||
| argv[0] = h | |||
| if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C.unlock_notify_callback), unsafe.Pointer(pargv)); rv != C.SQLITE_OK { | |||
| return rv | |||
| } | |||
| <-c | |||
| return C.SQLITE_OK | |||
| } | |||
| @@ -0,0 +1,289 @@ | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_userauth | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_USER_AUTHENTICATION | |||
| #cgo LDFLAGS: -lm | |||
| #ifndef USE_LIBSQLITE3 | |||
| #include <sqlite3-binding.h> | |||
| #else | |||
| #include <sqlite3.h> | |||
| #endif | |||
| #include <stdlib.h> | |||
| static int | |||
| _sqlite3_user_authenticate(sqlite3* db, const char* zUsername, const char* aPW, int nPW) | |||
| { | |||
| return sqlite3_user_authenticate(db, zUsername, aPW, nPW); | |||
| } | |||
| static int | |||
| _sqlite3_user_add(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin) | |||
| { | |||
| return sqlite3_user_add(db, zUsername, aPW, nPW, isAdmin); | |||
| } | |||
| static int | |||
| _sqlite3_user_change(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin) | |||
| { | |||
| return sqlite3_user_change(db, zUsername, aPW, nPW, isAdmin); | |||
| } | |||
| static int | |||
| _sqlite3_user_delete(sqlite3* db, const char* zUsername) | |||
| { | |||
| return sqlite3_user_delete(db, zUsername); | |||
| } | |||
| static int | |||
| _sqlite3_auth_enabled(sqlite3* db) | |||
| { | |||
| int exists = -1; | |||
| sqlite3_stmt *stmt; | |||
| sqlite3_prepare_v2(db, "select count(type) from sqlite_master WHERE type='table' and name='sqlite_user';", -1, &stmt, NULL); | |||
| while ( sqlite3_step(stmt) == SQLITE_ROW) { | |||
| exists = sqlite3_column_int(stmt, 0); | |||
| } | |||
| sqlite3_finalize(stmt); | |||
| return exists; | |||
| } | |||
| */ | |||
| import "C" | |||
| import ( | |||
| "errors" | |||
| "unsafe" | |||
| ) | |||
| const ( | |||
| SQLITE_AUTH = C.SQLITE_AUTH | |||
| ) | |||
| var ( | |||
| ErrUnauthorized = errors.New("SQLITE_AUTH: Unauthorized") | |||
| ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required") | |||
| ) | |||
| // Authenticate will perform an authentication of the provided username | |||
| // and password against the database. | |||
| // | |||
| // If a database contains the SQLITE_USER table, then the | |||
| // call to Authenticate must be invoked with an | |||
| // appropriate username and password prior to enable read and write | |||
| //access to the database. | |||
| // | |||
| // Return SQLITE_OK on success or SQLITE_ERROR if the username/password | |||
| // combination is incorrect or unknown. | |||
| // | |||
| // If the SQLITE_USER table is not present in the database file, then | |||
| // this interface is a harmless no-op returnning SQLITE_OK. | |||
| func (c *SQLiteConn) Authenticate(username, password string) error { | |||
| rv := c.authenticate(username, password) | |||
| switch rv { | |||
| case C.SQLITE_ERROR, C.SQLITE_AUTH: | |||
| return ErrUnauthorized | |||
| case C.SQLITE_OK: | |||
| return nil | |||
| default: | |||
| return c.lastError() | |||
| } | |||
| } | |||
| // authenticate provides the actual authentication to SQLite. | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // C.SQLITE_OK (0) | |||
| // C.SQLITE_ERROR (1) | |||
| // C.SQLITE_AUTH (23) | |||
| func (c *SQLiteConn) authenticate(username, password string) int { | |||
| // Allocate C Variables | |||
| cuser := C.CString(username) | |||
| cpass := C.CString(password) | |||
| // Free C Variables | |||
| defer func() { | |||
| C.free(unsafe.Pointer(cuser)) | |||
| C.free(unsafe.Pointer(cpass)) | |||
| }() | |||
| return int(C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password)))) | |||
| } | |||
| // AuthUserAdd can be used (by an admin user only) | |||
| // to create a new user. When called on a no-authentication-required | |||
| // database, this routine converts the database into an authentication- | |||
| // required database, automatically makes the added user an | |||
| // administrator, and logs in the current connection as that user. | |||
| // The AuthUserAdd only works for the "main" database, not | |||
| // for any ATTACH-ed databases. Any call to AuthUserAdd by a | |||
| // non-admin user results in an error. | |||
| func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { | |||
| isAdmin := 0 | |||
| if admin { | |||
| isAdmin = 1 | |||
| } | |||
| rv := c.authUserAdd(username, password, isAdmin) | |||
| switch rv { | |||
| case C.SQLITE_ERROR, C.SQLITE_AUTH: | |||
| return ErrAdminRequired | |||
| case C.SQLITE_OK: | |||
| return nil | |||
| default: | |||
| return c.lastError() | |||
| } | |||
| } | |||
| // authUserAdd enables the User Authentication if not enabled. | |||
| // Otherwise it will add a user. | |||
| // | |||
| // When user authentication is already enabled then this function | |||
| // can only be called by an admin. | |||
| // | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // C.SQLITE_OK (0) | |||
| // C.SQLITE_ERROR (1) | |||
| // C.SQLITE_AUTH (23) | |||
| func (c *SQLiteConn) authUserAdd(username, password string, admin int) int { | |||
| // Allocate C Variables | |||
| cuser := C.CString(username) | |||
| cpass := C.CString(password) | |||
| // Free C Variables | |||
| defer func() { | |||
| C.free(unsafe.Pointer(cuser)) | |||
| C.free(unsafe.Pointer(cpass)) | |||
| }() | |||
| return int(C._sqlite3_user_add(c.db, cuser, cpass, C.int(len(password)), C.int(admin))) | |||
| } | |||
| // AuthUserChange can be used to change a users | |||
| // login credentials or admin privilege. Any user can change their own | |||
| // login credentials. Only an admin user can change another users login | |||
| // credentials or admin privilege setting. No user may change their own | |||
| // admin privilege setting. | |||
| func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error { | |||
| isAdmin := 0 | |||
| if admin { | |||
| isAdmin = 1 | |||
| } | |||
| rv := c.authUserChange(username, password, isAdmin) | |||
| switch rv { | |||
| case C.SQLITE_ERROR, C.SQLITE_AUTH: | |||
| return ErrAdminRequired | |||
| case C.SQLITE_OK: | |||
| return nil | |||
| default: | |||
| return c.lastError() | |||
| } | |||
| } | |||
| // authUserChange allows to modify a user. | |||
| // Users can change their own password. | |||
| // | |||
| // Only admins can change passwords for other users | |||
| // and modify the admin flag. | |||
| // | |||
| // The admin flag of the current logged in user cannot be changed. | |||
| // THis ensures that their is always an admin. | |||
| // | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // C.SQLITE_OK (0) | |||
| // C.SQLITE_ERROR (1) | |||
| // C.SQLITE_AUTH (23) | |||
| func (c *SQLiteConn) authUserChange(username, password string, admin int) int { | |||
| // Allocate C Variables | |||
| cuser := C.CString(username) | |||
| cpass := C.CString(password) | |||
| // Free C Variables | |||
| defer func() { | |||
| C.free(unsafe.Pointer(cuser)) | |||
| C.free(unsafe.Pointer(cpass)) | |||
| }() | |||
| return int(C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(admin))) | |||
| } | |||
| // AuthUserDelete can be used (by an admin user only) | |||
| // to delete a user. The currently logged-in user cannot be deleted, | |||
| // which guarantees that there is always an admin user and hence that | |||
| // the database cannot be converted into a no-authentication-required | |||
| // database. | |||
| func (c *SQLiteConn) AuthUserDelete(username string) error { | |||
| rv := c.authUserDelete(username) | |||
| switch rv { | |||
| case C.SQLITE_ERROR, C.SQLITE_AUTH: | |||
| return ErrAdminRequired | |||
| case C.SQLITE_OK: | |||
| return nil | |||
| default: | |||
| return c.lastError() | |||
| } | |||
| } | |||
| // authUserDelete can be used to delete a user. | |||
| // | |||
| // This function can only be executed by an admin. | |||
| // | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // C.SQLITE_OK (0) | |||
| // C.SQLITE_ERROR (1) | |||
| // C.SQLITE_AUTH (23) | |||
| func (c *SQLiteConn) authUserDelete(username string) int { | |||
| // Allocate C Variables | |||
| cuser := C.CString(username) | |||
| // Free C Variables | |||
| defer func() { | |||
| C.free(unsafe.Pointer(cuser)) | |||
| }() | |||
| return int(C._sqlite3_user_delete(c.db, cuser)) | |||
| } | |||
| // AuthEnabled checks if the database is protected by user authentication | |||
| func (c *SQLiteConn) AuthEnabled() (exists bool) { | |||
| rv := c.authEnabled() | |||
| if rv == 1 { | |||
| exists = true | |||
| } | |||
| return | |||
| } | |||
| // authEnabled perform the actual check for user authentication. | |||
| // | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // 0 - Disabled | |||
| // 1 - Enabled | |||
| func (c *SQLiteConn) authEnabled() int { | |||
| return int(C._sqlite3_auth_enabled(c.db)) | |||
| } | |||
| // EOF | |||
| @@ -0,0 +1,152 @@ | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !sqlite_userauth | |||
| package sqlite3 | |||
| import ( | |||
| "C" | |||
| ) | |||
| // Authenticate will perform an authentication of the provided username | |||
| // and password against the database. | |||
| // | |||
| // If a database contains the SQLITE_USER table, then the | |||
| // call to Authenticate must be invoked with an | |||
| // appropriate username and password prior to enable read and write | |||
| //access to the database. | |||
| // | |||
| // Return SQLITE_OK on success or SQLITE_ERROR if the username/password | |||
| // combination is incorrect or unknown. | |||
| // | |||
| // If the SQLITE_USER table is not present in the database file, then | |||
| // this interface is a harmless no-op returnning SQLITE_OK. | |||
| func (c *SQLiteConn) Authenticate(username, password string) error { | |||
| // NOOP | |||
| return nil | |||
| } | |||
| // authenticate provides the actual authentication to SQLite. | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // C.SQLITE_OK (0) | |||
| // C.SQLITE_ERROR (1) | |||
| // C.SQLITE_AUTH (23) | |||
| func (c *SQLiteConn) authenticate(username, password string) int { | |||
| // NOOP | |||
| return 0 | |||
| } | |||
| // AuthUserAdd can be used (by an admin user only) | |||
| // to create a new user. When called on a no-authentication-required | |||
| // database, this routine converts the database into an authentication- | |||
| // required database, automatically makes the added user an | |||
| // administrator, and logs in the current connection as that user. | |||
| // The AuthUserAdd only works for the "main" database, not | |||
| // for any ATTACH-ed databases. Any call to AuthUserAdd by a | |||
| // non-admin user results in an error. | |||
| func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { | |||
| // NOOP | |||
| return nil | |||
| } | |||
| // authUserAdd enables the User Authentication if not enabled. | |||
| // Otherwise it will add a user. | |||
| // | |||
| // When user authentication is already enabled then this function | |||
| // can only be called by an admin. | |||
| // | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // C.SQLITE_OK (0) | |||
| // C.SQLITE_ERROR (1) | |||
| // C.SQLITE_AUTH (23) | |||
| func (c *SQLiteConn) authUserAdd(username, password string, admin int) int { | |||
| // NOOP | |||
| return 0 | |||
| } | |||
| // AuthUserChange can be used to change a users | |||
| // login credentials or admin privilege. Any user can change their own | |||
| // login credentials. Only an admin user can change another users login | |||
| // credentials or admin privilege setting. No user may change their own | |||
| // admin privilege setting. | |||
| func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error { | |||
| // NOOP | |||
| return nil | |||
| } | |||
| // authUserChange allows to modify a user. | |||
| // Users can change their own password. | |||
| // | |||
| // Only admins can change passwords for other users | |||
| // and modify the admin flag. | |||
| // | |||
| // The admin flag of the current logged in user cannot be changed. | |||
| // THis ensures that their is always an admin. | |||
| // | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // C.SQLITE_OK (0) | |||
| // C.SQLITE_ERROR (1) | |||
| // C.SQLITE_AUTH (23) | |||
| func (c *SQLiteConn) authUserChange(username, password string, admin int) int { | |||
| // NOOP | |||
| return 0 | |||
| } | |||
| // AuthUserDelete can be used (by an admin user only) | |||
| // to delete a user. The currently logged-in user cannot be deleted, | |||
| // which guarantees that there is always an admin user and hence that | |||
| // the database cannot be converted into a no-authentication-required | |||
| // database. | |||
| func (c *SQLiteConn) AuthUserDelete(username string) error { | |||
| // NOOP | |||
| return nil | |||
| } | |||
| // authUserDelete can be used to delete a user. | |||
| // | |||
| // This function can only be executed by an admin. | |||
| // | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // C.SQLITE_OK (0) | |||
| // C.SQLITE_ERROR (1) | |||
| // C.SQLITE_AUTH (23) | |||
| func (c *SQLiteConn) authUserDelete(username string) int { | |||
| // NOOP | |||
| return 0 | |||
| } | |||
| // AuthEnabled checks if the database is protected by user authentication | |||
| func (c *SQLiteConn) AuthEnabled() (exists bool) { | |||
| // NOOP | |||
| return false | |||
| } | |||
| // authEnabled perform the actual check for user authentication. | |||
| // | |||
| // This is not exported for usage in Go. | |||
| // It is however exported for usage within SQL by the user. | |||
| // | |||
| // Returns: | |||
| // 0 - Disabled | |||
| // 1 - Enabled | |||
| func (c *SQLiteConn) authEnabled() int { | |||
| // NOOP | |||
| return 0 | |||
| } | |||
| // EOF | |||
| @@ -0,0 +1,15 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_vacuum_full | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_DEFAULT_AUTOVACUUM=1 | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -0,0 +1,15 @@ | |||
| // Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build sqlite_vacuum_incr | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -DSQLITE_DEFAULT_AUTOVACUUM=2 | |||
| #cgo LDFLAGS: -lm | |||
| */ | |||
| import "C" | |||
| @@ -2,14 +2,18 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build vtable | |||
| // +build sqlite_vtable vtable | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -std=gnu99 | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61 | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_RTREE | |||
| #cgo CFLAGS: -DSQLITE_THREADSAFE | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_FTS3 | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_FTS3_PARENTHESIS | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_FTS4_UNICODE61 | |||
| #cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15 | |||
| #cgo CFLAGS: -DSQLITE_ENABLE_COLUMN_METADATA=1 | |||
| #cgo CFLAGS: -Wno-deprecated-declarations | |||
| @@ -2,6 +2,7 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !windows | |||
| package sqlite3 | |||
| @@ -9,5 +10,8 @@ package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -I. | |||
| #cgo linux LDFLAGS: -ldl | |||
| #cgo linux,ppc LDFLAGS: -lpthread | |||
| #cgo linux,ppc64 LDFLAGS: -lpthread | |||
| #cgo linux,ppc64le LDFLAGS: -lpthread | |||
| */ | |||
| import "C" | |||
| @@ -0,0 +1,14 @@ | |||
| // Copyright (C) 2018 Yasuhiro Matsumoto <mattn.jp@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build solaris | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -D__EXTENSIONS__=1 | |||
| #cgo LDFLAGS: -lc | |||
| */ | |||
| import "C" | |||
| @@ -2,7 +2,8 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build trace | |||
| // +build sqlite_trace trace | |||
| package sqlite3 | |||
| @@ -14,16 +15,12 @@ package sqlite3 | |||
| #endif | |||
| #include <stdlib.h> | |||
| void stepTrampoline(sqlite3_context*, int, sqlite3_value**); | |||
| void doneTrampoline(sqlite3_context*); | |||
| int traceCallbackTrampoline(unsigned int traceEventCode, void *ctx, void *p, void *x); | |||
| */ | |||
| import "C" | |||
| import ( | |||
| "errors" | |||
| "fmt" | |||
| "reflect" | |||
| "strings" | |||
| "sync" | |||
| "unsafe" | |||
| @@ -32,10 +29,10 @@ import ( | |||
| // Trace... constants identify the possible events causing callback invocation. | |||
| // Values are same as the corresponding SQLite Trace Event Codes. | |||
| const ( | |||
| TraceStmt = C.SQLITE_TRACE_STMT | |||
| TraceProfile = C.SQLITE_TRACE_PROFILE | |||
| TraceRow = C.SQLITE_TRACE_ROW | |||
| TraceClose = C.SQLITE_TRACE_CLOSE | |||
| TraceStmt = uint32(C.SQLITE_TRACE_STMT) | |||
| TraceProfile = uint32(C.SQLITE_TRACE_PROFILE) | |||
| TraceRow = uint32(C.SQLITE_TRACE_ROW) | |||
| TraceClose = uint32(C.SQLITE_TRACE_CLOSE) | |||
| ) | |||
| type TraceInfo struct { | |||
| @@ -75,7 +72,7 @@ type TraceUserCallback func(TraceInfo) int | |||
| type TraceConfig struct { | |||
| Callback TraceUserCallback | |||
| EventMask C.uint | |||
| EventMask uint32 | |||
| WantExpandedSQL bool | |||
| } | |||
| @@ -109,6 +106,8 @@ func traceCallbackTrampoline( | |||
| // Parameter named 'X' in SQLite docs (eXtra event data?): | |||
| xValue unsafe.Pointer) C.int { | |||
| eventCode := uint32(traceEventCode) | |||
| if ctx == nil { | |||
| panic(fmt.Sprintf("No context (ev 0x%x)", traceEventCode)) | |||
| } | |||
| @@ -118,7 +117,7 @@ func traceCallbackTrampoline( | |||
| var traceConf TraceConfig | |||
| var found bool | |||
| if traceEventCode == TraceClose { | |||
| if eventCode == TraceClose { | |||
| // clean up traceMap: 'pop' means get and delete | |||
| traceConf, found = popTraceMapping(connHandle) | |||
| } else { | |||
| @@ -127,16 +126,16 @@ func traceCallbackTrampoline( | |||
| if !found { | |||
| panic(fmt.Sprintf("Mapping not found for handle 0x%x (ev 0x%x)", | |||
| connHandle, traceEventCode)) | |||
| connHandle, eventCode)) | |||
| } | |||
| var info TraceInfo | |||
| info.EventCode = uint32(traceEventCode) | |||
| info.EventCode = eventCode | |||
| info.AutoCommit = (int(C.sqlite3_get_autocommit(contextDB)) != 0) | |||
| info.ConnHandle = connHandle | |||
| switch traceEventCode { | |||
| switch eventCode { | |||
| case TraceStmt: | |||
| info.StmtHandle = uintptr(p) | |||
| @@ -187,7 +186,7 @@ func traceCallbackTrampoline( | |||
| // registering this callback trampoline with SQLite --- for cleanup. | |||
| // In the future there may be more events forced to "selected" in SQLite | |||
| // for the driver's needs. | |||
| if traceConf.EventMask&traceEventCode == 0 { | |||
| if traceConf.EventMask&eventCode == 0 { | |||
| return 0 | |||
| } | |||
| @@ -239,131 +238,6 @@ func popTraceMapping(connHandle uintptr) (TraceConfig, bool) { | |||
| return entryCopy.config, found | |||
| } | |||
| // RegisterAggregator makes a Go type available as a SQLite aggregation function. | |||
| // | |||
| // Because aggregation is incremental, it's implemented in Go with a | |||
| // type that has 2 methods: func Step(values) accumulates one row of | |||
| // data into the accumulator, and func Done() ret finalizes and | |||
| // returns the aggregate value. "values" and "ret" may be any type | |||
| // supported by RegisterFunc. | |||
| // | |||
| // RegisterAggregator takes as implementation a constructor function | |||
| // that constructs an instance of the aggregator type each time an | |||
| // aggregation begins. The constructor must return a pointer to a | |||
| // type, or an interface that implements Step() and Done(). | |||
| // | |||
| // The constructor function and the Step/Done methods may optionally | |||
| // return an error in addition to their other return values. | |||
| // | |||
| // See _example/go_custom_funcs for a detailed example. | |||
| func (c *SQLiteConn) RegisterAggregator(name string, impl interface{}, pure bool) error { | |||
| var ai aggInfo | |||
| ai.constructor = reflect.ValueOf(impl) | |||
| t := ai.constructor.Type() | |||
| if t.Kind() != reflect.Func { | |||
| return errors.New("non-function passed to RegisterAggregator") | |||
| } | |||
| if t.NumOut() != 1 && t.NumOut() != 2 { | |||
| return errors.New("SQLite aggregator constructors must return 1 or 2 values") | |||
| } | |||
| if t.NumOut() == 2 && !t.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | |||
| return errors.New("Second return value of SQLite function must be error") | |||
| } | |||
| if t.NumIn() != 0 { | |||
| return errors.New("SQLite aggregator constructors must not have arguments") | |||
| } | |||
| agg := t.Out(0) | |||
| switch agg.Kind() { | |||
| case reflect.Ptr, reflect.Interface: | |||
| default: | |||
| return errors.New("SQlite aggregator constructor must return a pointer object") | |||
| } | |||
| stepFn, found := agg.MethodByName("Step") | |||
| if !found { | |||
| return errors.New("SQlite aggregator doesn't have a Step() function") | |||
| } | |||
| step := stepFn.Type | |||
| if step.NumOut() != 0 && step.NumOut() != 1 { | |||
| return errors.New("SQlite aggregator Step() function must return 0 or 1 values") | |||
| } | |||
| if step.NumOut() == 1 && !step.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | |||
| return errors.New("type of SQlite aggregator Step() return value must be error") | |||
| } | |||
| stepNArgs := step.NumIn() | |||
| start := 0 | |||
| if agg.Kind() == reflect.Ptr { | |||
| // Skip over the method receiver | |||
| stepNArgs-- | |||
| start++ | |||
| } | |||
| if step.IsVariadic() { | |||
| stepNArgs-- | |||
| } | |||
| for i := start; i < start+stepNArgs; i++ { | |||
| conv, err := callbackArg(step.In(i)) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| ai.stepArgConverters = append(ai.stepArgConverters, conv) | |||
| } | |||
| if step.IsVariadic() { | |||
| conv, err := callbackArg(t.In(start + stepNArgs).Elem()) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| ai.stepVariadicConverter = conv | |||
| // Pass -1 to sqlite so that it allows any number of | |||
| // arguments. The call helper verifies that the minimum number | |||
| // of arguments is present for variadic functions. | |||
| stepNArgs = -1 | |||
| } | |||
| doneFn, found := agg.MethodByName("Done") | |||
| if !found { | |||
| return errors.New("SQlite aggregator doesn't have a Done() function") | |||
| } | |||
| done := doneFn.Type | |||
| doneNArgs := done.NumIn() | |||
| if agg.Kind() == reflect.Ptr { | |||
| // Skip over the method receiver | |||
| doneNArgs-- | |||
| } | |||
| if doneNArgs != 0 { | |||
| return errors.New("SQlite aggregator Done() function must have no arguments") | |||
| } | |||
| if done.NumOut() != 1 && done.NumOut() != 2 { | |||
| return errors.New("SQLite aggregator Done() function must return 1 or 2 values") | |||
| } | |||
| if done.NumOut() == 2 && !done.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { | |||
| return errors.New("second return value of SQLite aggregator Done() function must be error") | |||
| } | |||
| conv, err := callbackRet(done.Out(0)) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| ai.doneRetConverter = conv | |||
| ai.active = make(map[int64]reflect.Value) | |||
| ai.next = 1 | |||
| // ai must outlast the database connection, or we'll have dangling pointers. | |||
| c.aggregators = append(c.aggregators, &ai) | |||
| cname := C.CString(name) | |||
| defer C.free(unsafe.Pointer(cname)) | |||
| opts := C.SQLITE_UTF8 | |||
| if pure { | |||
| opts |= C.SQLITE_DETERMINISTIC | |||
| } | |||
| rv := sqlite3CreateFunction(c.db, cname, C.int(stepNArgs), C.int(opts), newHandle(c, &ai), nil, C.stepTrampoline, C.doneTrampoline) | |||
| if rv != C.SQLITE_OK { | |||
| return c.lastError() | |||
| } | |||
| return nil | |||
| } | |||
| // SetTrace installs or removes the trace callback for the given database connection. | |||
| // It's not named 'RegisterTrace' because only one callback can be kept and called. | |||
| // Calling SetTrace a second time on same database connection | |||
| @@ -0,0 +1,39 @@ | |||
| // Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>. | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build cgo | |||
| package sqlite3 | |||
| // usleep is a function available on *nix based systems. | |||
| // This function is not present in Windows. | |||
| // Windows has a sleep function but this works with seconds | |||
| // and not with microseconds as usleep. | |||
| // | |||
| // This code should improve performance on windows because | |||
| // without the presence of usleep SQLite waits 1 second. | |||
| // | |||
| // Source: https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa | |||
| /* | |||
| #include <windows.h> | |||
| void usleep(__int64 usec) | |||
| { | |||
| HANDLE timer; | |||
| LARGE_INTEGER ft; | |||
| // Convert to 100 nanosecond interval, negative value indicates relative time | |||
| ft.QuadPart = -(10*usec); | |||
| timer = CreateWaitableTimer(NULL, TRUE, NULL); | |||
| SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); | |||
| WaitForSingleObject(timer, INFINITE); | |||
| CloseHandle(timer); | |||
| } | |||
| */ | |||
| import "C" | |||
| // EOF | |||
| @@ -2,13 +2,17 @@ | |||
| // | |||
| // Use of this source code is governed by an MIT-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build windows | |||
| package sqlite3 | |||
| /* | |||
| #cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe | |||
| #cgo windows,386 CFLAGS: -D_USE_32BIT_TIME_T | |||
| #cgo CFLAGS: -I. | |||
| #cgo CFLAGS: -fno-stack-check | |||
| #cgo CFLAGS: -fno-stack-protector | |||
| #cgo CFLAGS: -mno-stack-arg-probe | |||
| #cgo LDFLAGS: -lmingwex -lmingw32 | |||
| #cgo windows,386 CFLAGS: -D_USE_32BIT_TIME_T | |||
| */ | |||
| import "C" | |||
| @@ -18,7 +18,7 @@ | |||
| */ | |||
| #ifndef SQLITE3EXT_H | |||
| #define SQLITE3EXT_H | |||
| #include "sqlite3.h" | |||
| #include "sqlite3-binding.h" | |||
| /* | |||
| ** The following structure holds pointers to all of the SQLite API | |||
| @@ -135,7 +135,7 @@ struct sqlite3_api_routines { | |||
| int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, | |||
| const char*,const char*),void*); | |||
| void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); | |||
| char * (*snprintf)(int,char*,const char*,...); | |||
| char * (*xsnprintf)(int,char*,const char*,...); | |||
| int (*step)(sqlite3_stmt*); | |||
| int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, | |||
| char const**,char const**,int*,int*,int*); | |||
| @@ -247,7 +247,7 @@ struct sqlite3_api_routines { | |||
| int (*uri_boolean)(const char*,const char*,int); | |||
| sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); | |||
| const char *(*uri_parameter)(const char*,const char*); | |||
| char *(*vsnprintf)(int,char*,const char*,va_list); | |||
| char *(*xvsnprintf)(int,char*,const char*,va_list); | |||
| int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); | |||
| /* Version 3.8.7 and later */ | |||
| int (*auto_extension)(void(*)(void)); | |||
| @@ -283,6 +283,40 @@ struct sqlite3_api_routines { | |||
| /* Version 3.14.0 and later */ | |||
| int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*); | |||
| char *(*expanded_sql)(sqlite3_stmt*); | |||
| /* Version 3.18.0 and later */ | |||
| void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64); | |||
| /* Version 3.20.0 and later */ | |||
| int (*prepare_v3)(sqlite3*,const char*,int,unsigned int, | |||
| sqlite3_stmt**,const char**); | |||
| int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int, | |||
| sqlite3_stmt**,const void**); | |||
| int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*)); | |||
| void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*)); | |||
| void *(*value_pointer)(sqlite3_value*,const char*); | |||
| int (*vtab_nochange)(sqlite3_context*); | |||
| int (*value_nochange)(sqlite3_value*); | |||
| const char *(*vtab_collation)(sqlite3_index_info*,int); | |||
| /* Version 3.24.0 and later */ | |||
| int (*keyword_count)(void); | |||
| int (*keyword_name)(int,const char**,int*); | |||
| int (*keyword_check)(const char*,int); | |||
| sqlite3_str *(*str_new)(sqlite3*); | |||
| char *(*str_finish)(sqlite3_str*); | |||
| void (*str_appendf)(sqlite3_str*, const char *zFormat, ...); | |||
| void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list); | |||
| void (*str_append)(sqlite3_str*, const char *zIn, int N); | |||
| void (*str_appendall)(sqlite3_str*, const char *zIn); | |||
| void (*str_appendchar)(sqlite3_str*, int N, char C); | |||
| void (*str_reset)(sqlite3_str*); | |||
| int (*str_errcode)(sqlite3_str*); | |||
| int (*str_length)(sqlite3_str*); | |||
| char *(*str_value)(sqlite3_str*); | |||
| int (*create_window_function)(sqlite3*,const char*,int,int,void*, | |||
| void (*xStep)(sqlite3_context*,int,sqlite3_value**), | |||
| void (*xFinal)(sqlite3_context*), | |||
| void (*xValue)(sqlite3_context*), | |||
| void (*xInv)(sqlite3_context*,int,sqlite3_value**), | |||
| void(*xDestroy)(void*)); | |||
| }; | |||
| /* | |||
| @@ -409,7 +443,7 @@ typedef int (*sqlite3_loadext_entry)( | |||
| #define sqlite3_rollback_hook sqlite3_api->rollback_hook | |||
| #define sqlite3_set_authorizer sqlite3_api->set_authorizer | |||
| #define sqlite3_set_auxdata sqlite3_api->set_auxdata | |||
| #define sqlite3_snprintf sqlite3_api->snprintf | |||
| #define sqlite3_snprintf sqlite3_api->xsnprintf | |||
| #define sqlite3_step sqlite3_api->step | |||
| #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata | |||
| #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup | |||
| @@ -433,7 +467,7 @@ typedef int (*sqlite3_loadext_entry)( | |||
| #define sqlite3_value_text16le sqlite3_api->value_text16le | |||
| #define sqlite3_value_type sqlite3_api->value_type | |||
| #define sqlite3_vmprintf sqlite3_api->vmprintf | |||
| #define sqlite3_vsnprintf sqlite3_api->vsnprintf | |||
| #define sqlite3_vsnprintf sqlite3_api->xvsnprintf | |||
| #define sqlite3_overload_function sqlite3_api->overload_function | |||
| #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 | |||
| #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 | |||
| @@ -509,7 +543,7 @@ typedef int (*sqlite3_loadext_entry)( | |||
| #define sqlite3_uri_boolean sqlite3_api->uri_boolean | |||
| #define sqlite3_uri_int64 sqlite3_api->uri_int64 | |||
| #define sqlite3_uri_parameter sqlite3_api->uri_parameter | |||
| #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf | |||
| #define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf | |||
| #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 | |||
| /* Version 3.8.7 and later */ | |||
| #define sqlite3_auto_extension sqlite3_api->auto_extension | |||
| @@ -541,6 +575,35 @@ typedef int (*sqlite3_loadext_entry)( | |||
| /* Version 3.14.0 and later */ | |||
| #define sqlite3_trace_v2 sqlite3_api->trace_v2 | |||
| #define sqlite3_expanded_sql sqlite3_api->expanded_sql | |||
| /* Version 3.18.0 and later */ | |||
| #define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid | |||
| /* Version 3.20.0 and later */ | |||
| #define sqlite3_prepare_v3 sqlite3_api->prepare_v3 | |||
| #define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3 | |||
| #define sqlite3_bind_pointer sqlite3_api->bind_pointer | |||
| #define sqlite3_result_pointer sqlite3_api->result_pointer | |||
| #define sqlite3_value_pointer sqlite3_api->value_pointer | |||
| /* Version 3.22.0 and later */ | |||
| #define sqlite3_vtab_nochange sqlite3_api->vtab_nochange | |||
| #define sqlite3_value_nochange sqlite3_api->value_nochange | |||
| #define sqlite3_vtab_collation sqlite3_api->vtab_collation | |||
| /* Version 3.24.0 and later */ | |||
| #define sqlite3_keyword_count sqlite3_api->keyword_count | |||
| #define sqlite3_keyword_name sqlite3_api->keyword_name | |||
| #define sqlite3_keyword_check sqlite3_api->keyword_check | |||
| #define sqlite3_str_new sqlite3_api->str_new | |||
| #define sqlite3_str_finish sqlite3_api->str_finish | |||
| #define sqlite3_str_appendf sqlite3_api->str_appendf | |||
| #define sqlite3_str_vappendf sqlite3_api->str_vappendf | |||
| #define sqlite3_str_append sqlite3_api->str_append | |||
| #define sqlite3_str_appendall sqlite3_api->str_appendall | |||
| #define sqlite3_str_appendchar sqlite3_api->str_appendchar | |||
| #define sqlite3_str_reset sqlite3_api->str_reset | |||
| #define sqlite3_str_errcode sqlite3_api->str_errcode | |||
| #define sqlite3_str_length sqlite3_api->str_length | |||
| #define sqlite3_str_value sqlite3_api->str_value | |||
| /* Version 3.25.0 and later */ | |||
| #define sqlite3_create_window_function sqlite3_api->create_window_function | |||
| #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ | |||
| #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) | |||
| @@ -0,0 +1,21 @@ | |||
| // +build !cgo | |||
| package sqlite3 | |||
| import ( | |||
| "database/sql" | |||
| "database/sql/driver" | |||
| "errors" | |||
| ) | |||
| func init() { | |||
| sql.Register("sqlite3", &SQLiteDriverMock{}) | |||
| } | |||
| type SQLiteDriverMock struct{} | |||
| var errorMsg = errors.New("Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub") | |||
| func (SQLiteDriverMock) Open(s string) (driver.Conn, error) { | |||
| return nil, errorMsg | |||
| } | |||