diff options
Diffstat (limited to 'vendor/modernc.org/sqlite')
| -rw-r--r-- | vendor/modernc.org/sqlite/CONTRIBUTORS | 1 | ||||
| -rw-r--r-- | vendor/modernc.org/sqlite/convert.go | 299 | ||||
| -rw-r--r-- | vendor/modernc.org/sqlite/pre_update_hook.go | 227 | ||||
| -rw-r--r-- | vendor/modernc.org/sqlite/sqlite.go | 6 |
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. // |
