summaryrefslogtreecommitdiff
path: root/vendor/modernc.org/sqlite
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/modernc.org/sqlite')
-rw-r--r--vendor/modernc.org/sqlite/CONTRIBUTORS1
-rw-r--r--vendor/modernc.org/sqlite/convert.go299
-rw-r--r--vendor/modernc.org/sqlite/pre_update_hook.go227
-rw-r--r--vendor/modernc.org/sqlite/sqlite.go6
4 files changed, 533 insertions, 0 deletions
diff --git a/vendor/modernc.org/sqlite/CONTRIBUTORS b/vendor/modernc.org/sqlite/CONTRIBUTORS
index 625b7dcd2..8c09cfcea 100644
--- a/vendor/modernc.org/sqlite/CONTRIBUTORS
+++ b/vendor/modernc.org/sqlite/CONTRIBUTORS
@@ -38,5 +38,6 @@ Sean McGivern <sean@mcgivern.me.uk>
Steffen Butzer <steffen(dot)butzer@outlook.com>
Toni Spets <toni.spets@beeper.com>
W. Michael Petullo <mike@flyn.org>
+Walter Wanderley <walterwanderley@gmail.com>
Yaacov Akiba Slama <ya@slamail.org>
Prathyush PV <prathyush.pv@temporal.io>
diff --git a/vendor/modernc.org/sqlite/convert.go b/vendor/modernc.org/sqlite/convert.go
new file mode 100644
index 000000000..1b19dc60c
--- /dev/null
+++ b/vendor/modernc.org/sqlite/convert.go
@@ -0,0 +1,299 @@
+// Extracted from Go database/sql source code
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Type conversions for Scan.
+
+package sqlite
+
+import (
+ "database/sql"
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+ "time"
+)
+
+var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
+
+// convertAssign copies to dest the value in src, converting it if possible.
+// An error is returned if the copy would result in loss of information.
+// dest should be a pointer type.
+func convertAssign(dest, src interface{}) error {
+ // Common cases, without reflect.
+ switch s := src.(type) {
+ case string:
+ switch d := dest.(type) {
+ case *string:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = s
+ return nil
+ case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = []byte(s)
+ return nil
+ case *sql.RawBytes:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = append((*d)[:0], s...)
+ return nil
+ }
+ case []byte:
+ switch d := dest.(type) {
+ case *string:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = string(s)
+ return nil
+ case *interface{}:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = cloneBytes(s)
+ return nil
+ case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = cloneBytes(s)
+ return nil
+ case *sql.RawBytes:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = s
+ return nil
+ }
+ case time.Time:
+ switch d := dest.(type) {
+ case *time.Time:
+ *d = s
+ return nil
+ case *string:
+ *d = s.Format(time.RFC3339Nano)
+ return nil
+ case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = []byte(s.Format(time.RFC3339Nano))
+ return nil
+ case *sql.RawBytes:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
+ return nil
+ }
+ case nil:
+ switch d := dest.(type) {
+ case *interface{}:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = nil
+ return nil
+ case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = nil
+ return nil
+ case *sql.RawBytes:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = nil
+ return nil
+ }
+ }
+
+ var sv reflect.Value
+
+ switch d := dest.(type) {
+ case *string:
+ sv = reflect.ValueOf(src)
+ switch sv.Kind() {
+ case reflect.Bool,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Float32, reflect.Float64:
+ *d = asString(src)
+ return nil
+ }
+ case *[]byte:
+ sv = reflect.ValueOf(src)
+ if b, ok := asBytes(nil, sv); ok {
+ *d = b
+ return nil
+ }
+ case *sql.RawBytes:
+ sv = reflect.ValueOf(src)
+ if b, ok := asBytes([]byte(*d)[:0], sv); ok {
+ *d = sql.RawBytes(b)
+ return nil
+ }
+ case *bool:
+ bv, err := driver.Bool.ConvertValue(src)
+ if err == nil {
+ *d = bv.(bool)
+ }
+ return err
+ case *interface{}:
+ *d = src
+ return nil
+ }
+
+ if scanner, ok := dest.(sql.Scanner); ok {
+ return scanner.Scan(src)
+ }
+
+ dpv := reflect.ValueOf(dest)
+ if dpv.Kind() != reflect.Ptr {
+ return errors.New("destination not a pointer")
+ }
+ if dpv.IsNil() {
+ return errNilPtr
+ }
+
+ if !sv.IsValid() {
+ sv = reflect.ValueOf(src)
+ }
+
+ dv := reflect.Indirect(dpv)
+ if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
+ switch b := src.(type) {
+ case []byte:
+ dv.Set(reflect.ValueOf(cloneBytes(b)))
+ default:
+ dv.Set(sv)
+ }
+ return nil
+ }
+
+ if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
+ dv.Set(sv.Convert(dv.Type()))
+ return nil
+ }
+
+ // The following conversions use a string value as an intermediate representation
+ // to convert between various numeric types.
+ //
+ // This also allows scanning into user defined types such as "type Int int64".
+ // For symmetry, also check for string destination types.
+ switch dv.Kind() {
+ case reflect.Ptr:
+ if src == nil {
+ dv.Set(reflect.Zero(dv.Type()))
+ return nil
+ }
+ dv.Set(reflect.New(dv.Type().Elem()))
+ return convertAssign(dv.Interface(), src)
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ s := asString(src)
+ i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
+ if err != nil {
+ err = strconvErr(err)
+ return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+ }
+ dv.SetInt(i64)
+ return nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ s := asString(src)
+ u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
+ if err != nil {
+ err = strconvErr(err)
+ return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+ }
+ dv.SetUint(u64)
+ return nil
+ case reflect.Float32, reflect.Float64:
+ s := asString(src)
+ f64, err := strconv.ParseFloat(s, dv.Type().Bits())
+ if err != nil {
+ err = strconvErr(err)
+ return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
+ }
+ dv.SetFloat(f64)
+ return nil
+ case reflect.String:
+ switch v := src.(type) {
+ case string:
+ dv.SetString(v)
+ return nil
+ case []byte:
+ dv.SetString(string(v))
+ return nil
+ }
+ }
+
+ return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
+}
+
+func strconvErr(err error) error {
+ if ne, ok := err.(*strconv.NumError); ok {
+ return ne.Err
+ }
+ return err
+}
+
+func cloneBytes(b []byte) []byte {
+ if b == nil {
+ return nil
+ }
+ c := make([]byte, len(b))
+ copy(c, b)
+ return c
+}
+
+func asString(src interface{}) string {
+ switch v := src.(type) {
+ case string:
+ return v
+ case []byte:
+ return string(v)
+ }
+ rv := reflect.ValueOf(src)
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.FormatInt(rv.Int(), 10)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.FormatUint(rv.Uint(), 10)
+ case reflect.Float64:
+ return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
+ case reflect.Float32:
+ return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
+ case reflect.Bool:
+ return strconv.FormatBool(rv.Bool())
+ }
+ return fmt.Sprintf("%v", src)
+}
+
+func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
+ switch rv.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.AppendInt(buf, rv.Int(), 10), true
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.AppendUint(buf, rv.Uint(), 10), true
+ case reflect.Float32:
+ return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
+ case reflect.Float64:
+ return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
+ case reflect.Bool:
+ return strconv.AppendBool(buf, rv.Bool()), true
+ case reflect.String:
+ s := rv.String()
+ return append(buf, s...), true
+ }
+ return
+}
diff --git a/vendor/modernc.org/sqlite/pre_update_hook.go b/vendor/modernc.org/sqlite/pre_update_hook.go
new file mode 100644
index 000000000..9a00fe5ac
--- /dev/null
+++ b/vendor/modernc.org/sqlite/pre_update_hook.go
@@ -0,0 +1,227 @@
+package sqlite
+
+import (
+ "errors"
+ "fmt"
+ "sync"
+ "unsafe"
+
+ "modernc.org/libc"
+ "modernc.org/libc/sys/types"
+ sqlite3 "modernc.org/sqlite/lib"
+)
+
+var (
+ xPreUpdateHandlers = struct {
+ mu sync.RWMutex
+ m map[uintptr]func(SQLitePreUpdateData)
+ }{
+ m: make(map[uintptr]func(SQLitePreUpdateData)),
+ }
+ xCommitHandlers = struct {
+ mu sync.RWMutex
+ m map[uintptr]CommitHookFn
+ }{
+ m: make(map[uintptr]CommitHookFn),
+ }
+ xRollbackHandlers = struct {
+ mu sync.RWMutex
+ m map[uintptr]RollbackHookFn
+ }{
+ m: make(map[uintptr]RollbackHookFn),
+ }
+)
+
+type PreUpdateHookFn func(SQLitePreUpdateData)
+
+func (c *conn) RegisterPreUpdateHook(callback PreUpdateHookFn) {
+
+ if callback == nil {
+ xPreUpdateHandlers.mu.Lock()
+ delete(xPreUpdateHandlers.m, c.db)
+ xPreUpdateHandlers.mu.Unlock()
+ sqlite3.Xsqlite3_preupdate_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil)))
+ return
+ }
+ xPreUpdateHandlers.mu.Lock()
+ xPreUpdateHandlers.m[c.db] = callback
+ xPreUpdateHandlers.mu.Unlock()
+
+ sqlite3.Xsqlite3_preupdate_hook(c.tls, c.db, cFuncPointer(preUpdateHookTrampoline), c.db)
+}
+
+type CommitHookFn func() int32
+
+func (c *conn) RegisterCommitHook(callback CommitHookFn) {
+ if callback == nil {
+ xCommitHandlers.mu.Lock()
+ delete(xCommitHandlers.m, c.db)
+ xCommitHandlers.mu.Unlock()
+ sqlite3.Xsqlite3_commit_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil)))
+ return
+ }
+ xCommitHandlers.mu.Lock()
+ xCommitHandlers.m[c.db] = callback
+ xCommitHandlers.mu.Unlock()
+ sqlite3.Xsqlite3_commit_hook(c.tls, c.db, cFuncPointer(commitHookTrampoline), c.db)
+}
+
+type RollbackHookFn func()
+
+func (c *conn) RegisterRollbackHook(callback RollbackHookFn) {
+ if callback == nil {
+ xRollbackHandlers.mu.Lock()
+ delete(xRollbackHandlers.m, c.db)
+ xRollbackHandlers.mu.Unlock()
+ sqlite3.Xsqlite3_rollback_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil)))
+ return
+ }
+ xRollbackHandlers.mu.Lock()
+ xRollbackHandlers.m[c.db] = callback
+ xRollbackHandlers.mu.Unlock()
+ sqlite3.Xsqlite3_rollback_hook(c.tls, c.db, cFuncPointer(rollbackHookTrampoline), c.db)
+}
+
+type SQLitePreUpdateData struct {
+ tls *libc.TLS
+ pCsr uintptr
+ Op int32
+ DatabaseName string
+ TableName string
+ OldRowID int64
+ NewRowID int64
+}
+
+// Depth returns the source path of the write, see sqlite3_preupdate_depth()
+func (d *SQLitePreUpdateData) Depth() int {
+ return int(sqlite3.Xsqlite3_preupdate_depth(d.tls, d.pCsr))
+}
+
+// Count returns the number of columns in the row
+func (d *SQLitePreUpdateData) Count() int {
+ return int(sqlite3.Xsqlite3_preupdate_count(d.tls, d.pCsr))
+}
+
+func (d *SQLitePreUpdateData) row(dest []any, new bool) error {
+ count := d.Count()
+ ppValue, err := mallocValue(d.tls)
+ if err != nil {
+ return err
+ }
+ defer libc.Xfree(d.tls, ppValue)
+
+ for i := 0; i < count && i < len(dest); i++ {
+ val, err := d.value(ppValue, i, new)
+ if err != nil {
+ return err
+ }
+ err = convertAssign(&dest[i], val)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Old populates dest with the row data to be replaced. This works similar to
+// database/sql's Rows.Scan()
+func (d *SQLitePreUpdateData) Old(dest ...any) error {
+ if d.Op == sqlite3.SQLITE_INSERT {
+ return errors.New("there is no old row for INSERT operations")
+ }
+ return d.row(dest, false)
+}
+
+// New populates dest with the replacement row data. This works similar to
+// database/sql's Rows.Scan()
+func (d *SQLitePreUpdateData) New(dest ...any) error {
+ if d.Op == sqlite3.SQLITE_DELETE {
+ return errors.New("there is no new row for DELETE operations")
+ }
+ return d.row(dest, true)
+}
+
+const ptrValSize = types.Size_t(unsafe.Sizeof(&sqlite3.Sqlite3_value{}))
+
+func mallocValue(tls *libc.TLS) (uintptr, error) {
+ p := libc.Xmalloc(tls, ptrValSize)
+ if p == 0 {
+ return 0, fmt.Errorf("out of memory")
+ }
+ return p, nil
+}
+
+func (d *SQLitePreUpdateData) value(ppValue uintptr, i int, new bool) (any, error) {
+ var src any
+ if new {
+ sqlite3.Xsqlite3_preupdate_new(d.tls, d.pCsr, int32(i), ppValue)
+ } else {
+ sqlite3.Xsqlite3_preupdate_old(d.tls, d.pCsr, int32(i), ppValue)
+ }
+ ptrValue := *(*uintptr)(unsafe.Pointer(ppValue))
+ switch sqlite3.Xsqlite3_value_type(d.tls, ptrValue) {
+ case sqlite3.SQLITE_INTEGER:
+ src = int64(sqlite3.Xsqlite3_value_int64(d.tls, ptrValue))
+ case sqlite3.SQLITE_FLOAT:
+ src = float64(sqlite3.Xsqlite3_value_double(d.tls, ptrValue))
+ case sqlite3.SQLITE_BLOB:
+ size := sqlite3.Xsqlite3_value_bytes(d.tls, ptrValue)
+ blobPtr := sqlite3.Xsqlite3_value_blob(d.tls, ptrValue)
+
+ var v []byte
+ if size != 0 {
+ v = make([]byte, size)
+ copy(v, (*libc.RawMem)(unsafe.Pointer(blobPtr))[:size:size])
+ }
+ src = v
+ case sqlite3.SQLITE_TEXT:
+ src = libc.GoString(sqlite3.Xsqlite3_value_text(d.tls, ptrValue))
+ case sqlite3.SQLITE_NULL:
+ src = nil
+ }
+ return src, nil
+}
+
+func preUpdateHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr, op int32, zDb uintptr, pTab uintptr, iKey1 int64, iReg int32, iBlobWrite int32) {
+ xPreUpdateHandlers.mu.RLock()
+ xPreUpdateHandler := xPreUpdateHandlers.m[handle]
+ xPreUpdateHandlers.mu.RUnlock()
+
+ if xPreUpdateHandler == nil {
+ return
+ }
+ data := SQLitePreUpdateData{
+ tls: tls,
+ pCsr: pCsr,
+ Op: op,
+ DatabaseName: libc.GoString(zDb),
+ TableName: libc.GoString(pTab),
+ OldRowID: iKey1,
+ NewRowID: int64(iReg),
+ }
+ xPreUpdateHandler(data)
+}
+
+func commitHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr) int32 {
+ xCommitHandlers.mu.RLock()
+ xCommitHandler := xCommitHandlers.m[handle]
+ xCommitHandlers.mu.RUnlock()
+
+ if xCommitHandler == nil {
+ return 0
+ }
+
+ return xCommitHandler()
+}
+
+func rollbackHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr) {
+ xRollbackHandlers.mu.RLock()
+ xRollbackHandler := xRollbackHandlers.m[handle]
+ xRollbackHandlers.mu.RUnlock()
+
+ if xRollbackHandler == nil {
+ return
+ }
+
+ xRollbackHandler()
+}
diff --git a/vendor/modernc.org/sqlite/sqlite.go b/vendor/modernc.org/sqlite/sqlite.go
index a0b6ca4eb..c48b70292 100644
--- a/vendor/modernc.org/sqlite/sqlite.go
+++ b/vendor/modernc.org/sqlite/sqlite.go
@@ -1914,6 +1914,12 @@ type ExecQuerierContext interface {
driver.QueryerContext
}
+type HookRegisterer interface {
+ RegisterPreUpdateHook(PreUpdateHookFn)
+ RegisterCommitHook(CommitHookFn)
+ RegisterRollbackHook(RollbackHookFn)
+}
+
// Commit releases all resources associated with the Backup object but does not
// close the destination database connection.
//