chore(deps): Update sqlite dependencies
This commit is contained in:
389
vendor/modernc.org/sqlite/sqlite.go
generated
vendored
389
vendor/modernc.org/sqlite/sqlite.go
generated
vendored
@ -2,8 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run generator.go
|
||||
//go:generate go fmt ./...
|
||||
//go:generate go run generator.go -full-path-comments
|
||||
|
||||
package sqlite // import "modernc.org/sqlite"
|
||||
|
||||
@ -11,7 +10,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@ -337,6 +335,22 @@ func (c *conn) parseTimeString(s0 string, x int) (interface{}, bool) {
|
||||
return s0, false
|
||||
}
|
||||
|
||||
// writeTimeFormats are the names and formats supported
|
||||
// by the `_time_format` DSN query param.
|
||||
var writeTimeFormats = map[string]string{
|
||||
"sqlite": parseTimeFormats[0],
|
||||
}
|
||||
|
||||
func (c *conn) formatTime(t time.Time) string {
|
||||
// Before configurable write time formats were supported,
|
||||
// time.Time.String was used. Maintain that default to
|
||||
// keep existing driver users formatting times the same.
|
||||
if c.writeTimeFormat == "" {
|
||||
return t.String()
|
||||
}
|
||||
return t.Format(c.writeTimeFormat)
|
||||
}
|
||||
|
||||
// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return
|
||||
// the database system type name without the length. Type names should be
|
||||
// uppercase. Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2",
|
||||
@ -477,20 +491,7 @@ func (s *stmt) exec(ctx context.Context, args []driver.NamedValue) (r driver.Res
|
||||
var pstmt uintptr
|
||||
var done int32
|
||||
if ctx != nil && ctx.Done() != nil {
|
||||
donech := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
atomic.AddInt32(&done, 1)
|
||||
s.c.interrupt(s.c.db)
|
||||
case <-donech:
|
||||
}
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
close(donech)
|
||||
}()
|
||||
defer interruptOnDone(ctx, s.c, &done)()
|
||||
}
|
||||
|
||||
for psql := s.psql; *(*byte)(unsafe.Pointer(psql)) != 0 && atomic.LoadInt32(&done) == 0; {
|
||||
@ -574,20 +575,7 @@ func (s *stmt) query(ctx context.Context, args []driver.NamedValue) (r driver.Ro
|
||||
var pstmt uintptr
|
||||
var done int32
|
||||
if ctx != nil && ctx.Done() != nil {
|
||||
donech := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
atomic.AddInt32(&done, 1)
|
||||
s.c.interrupt(s.c.db)
|
||||
case <-donech:
|
||||
}
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
close(donech)
|
||||
}()
|
||||
defer interruptOnDone(ctx, s.c, &done)()
|
||||
}
|
||||
|
||||
var allocs []uintptr
|
||||
@ -671,7 +659,13 @@ type tx struct {
|
||||
|
||||
func newTx(c *conn) (*tx, error) {
|
||||
r := &tx{c: c}
|
||||
if err := r.exec(context.Background(), "begin"); err != nil {
|
||||
var sql string
|
||||
if c.beginMode != "" {
|
||||
sql = "begin " + c.beginMode
|
||||
} else {
|
||||
sql = "begin"
|
||||
}
|
||||
if err := r.exec(context.Background(), sql); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -698,19 +692,7 @@ func (t *tx) exec(ctx context.Context, sql string) (err error) {
|
||||
//TODO use t.conn.ExecContext() instead
|
||||
|
||||
if ctx != nil && ctx.Done() != nil {
|
||||
donech := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.c.interrupt(t.c.db)
|
||||
case <-donech:
|
||||
}
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
close(donech)
|
||||
}()
|
||||
defer interruptOnDone(ctx, t.c, nil)()
|
||||
}
|
||||
|
||||
if rc := sqlite3.Xsqlite3_exec(t.c.tls, t.c.db, psql, 0, 0, 0); rc != sqlite3.SQLITE_OK {
|
||||
@ -720,6 +702,43 @@ func (t *tx) exec(ctx context.Context, sql string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// interruptOnDone sets up a goroutine to interrupt the provided db when the
|
||||
// context is canceled, and returns a function the caller must defer so it
|
||||
// doesn't interrupt after the caller finishes.
|
||||
func interruptOnDone(
|
||||
ctx context.Context,
|
||||
c *conn,
|
||||
done *int32,
|
||||
) func() {
|
||||
if done == nil {
|
||||
var d int32
|
||||
done = &d
|
||||
}
|
||||
|
||||
donech := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// don't call interrupt if we were already done: it indicates that this
|
||||
// call to exec is no longer running and we would be interrupting
|
||||
// nothing, or even possibly an unrelated later call to exec.
|
||||
if atomic.AddInt32(done, 1) == 1 {
|
||||
c.interrupt(c.db)
|
||||
}
|
||||
case <-donech:
|
||||
}
|
||||
}()
|
||||
|
||||
// the caller is expected to defer this function
|
||||
return func() {
|
||||
// set the done flag so that a context cancellation right after the caller
|
||||
// returns doesn't trigger a call to interrupt for some other statement.
|
||||
atomic.AddInt32(done, 1)
|
||||
close(donech)
|
||||
}
|
||||
}
|
||||
|
||||
type conn struct {
|
||||
db uintptr // *sqlite3.Xsqlite3
|
||||
tls *libc.TLS
|
||||
@ -727,6 +746,9 @@ type conn struct {
|
||||
// Context handling can cause conn.Close and conn.interrupt to be invoked
|
||||
// concurrently.
|
||||
sync.Mutex
|
||||
|
||||
writeTimeFormat string
|
||||
beginMode string
|
||||
}
|
||||
|
||||
func newConn(dsn string) (*conn, error) {
|
||||
@ -760,7 +782,7 @@ func newConn(dsn string) (*conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = applyPragmas(c, query); err != nil {
|
||||
if err = applyQueryParams(c, query); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
@ -768,11 +790,12 @@ func newConn(dsn string) (*conn, error) {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func applyPragmas(c *conn, query string) error {
|
||||
func applyQueryParams(c *conn, query string) error {
|
||||
q, err := url.ParseQuery(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, v := range q["_pragma"] {
|
||||
cmd := "pragma " + v
|
||||
_, err := c.exec(context.Background(), cmd, nil)
|
||||
@ -780,6 +803,24 @@ func applyPragmas(c *conn, query string) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v := q.Get("_time_format"); v != "" {
|
||||
f, ok := writeTimeFormats[v]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown _time_format %q", v)
|
||||
}
|
||||
c.writeTimeFormat = f
|
||||
return nil
|
||||
}
|
||||
|
||||
if v := q.Get("_txlock"); v != "" {
|
||||
lower := strings.ToLower(v)
|
||||
if lower != "deferred" && lower != "immediate" && lower != "exclusive" {
|
||||
return fmt.Errorf("unknown _txlock %q", v)
|
||||
}
|
||||
c.beginMode = v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -883,7 +924,7 @@ func (c *conn) step(pstmt uintptr) (int, error) {
|
||||
|
||||
return int(rc), nil
|
||||
default:
|
||||
return int(rc), errors.New(ErrorCodeString[int(rc)])
|
||||
return int(rc), c.errstr(rc)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1006,7 +1047,7 @@ func (c *conn) bind(pstmt uintptr, n int, args []driver.NamedValue) (allocs []ui
|
||||
return allocs, err
|
||||
}
|
||||
case time.Time:
|
||||
if p, err = c.bindText(pstmt, i, x.String()); err != nil {
|
||||
if p, err = c.bindText(pstmt, i, c.formatTime(x)); err != nil {
|
||||
return allocs, err
|
||||
}
|
||||
case nil:
|
||||
@ -1049,11 +1090,17 @@ func (c *conn) bindText(pstmt uintptr, idx1 int, value string) (uintptr, error)
|
||||
|
||||
// int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
|
||||
func (c *conn) bindBlob(pstmt uintptr, idx1 int, value []byte) (uintptr, error) {
|
||||
if value != nil && len(value) == 0 {
|
||||
if rc := sqlite3.Xsqlite3_bind_zeroblob(c.tls, pstmt, int32(idx1), 0); rc != sqlite3.SQLITE_OK {
|
||||
return 0, c.errstr(rc)
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
p, err := c.malloc(len(value))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if len(value) != 0 {
|
||||
copy((*libc.RawMem)(unsafe.Pointer(p))[:len(value):len(value)], value)
|
||||
}
|
||||
@ -1225,11 +1272,15 @@ func (c *conn) errstr(rc int32) error {
|
||||
p := sqlite3.Xsqlite3_errstr(c.tls, rc)
|
||||
str := libc.GoString(p)
|
||||
p = sqlite3.Xsqlite3_errmsg(c.tls, c.db)
|
||||
var s string
|
||||
if rc == sqlite3.SQLITE_BUSY {
|
||||
s = " (SQLITE_BUSY)"
|
||||
}
|
||||
switch msg := libc.GoString(p); {
|
||||
case msg == str:
|
||||
return &Error{msg: fmt.Sprintf("%s (%v)", str, rc), code: int(rc)}
|
||||
return &Error{msg: fmt.Sprintf("%s (%v)%s", str, rc, s), code: int(rc)}
|
||||
default:
|
||||
return &Error{msg: fmt.Sprintf("%s: %s (%v)", str, msg, rc), code: int(rc)}
|
||||
return &Error{msg: fmt.Sprintf("%s: %s (%v)%s", str, msg, rc, s), code: int(rc)}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1262,6 +1313,7 @@ func (c *conn) Close() error {
|
||||
|
||||
c.db = 0
|
||||
}
|
||||
|
||||
if c.tls != nil {
|
||||
c.tls.Close()
|
||||
c.tls = nil
|
||||
@ -1278,6 +1330,32 @@ func (c *conn) closeV2(db uintptr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type userDefinedFunction struct {
|
||||
zFuncName uintptr
|
||||
nArg int32
|
||||
eTextRep int32
|
||||
xFunc func(*libc.TLS, uintptr, int32, uintptr)
|
||||
|
||||
freeOnce sync.Once
|
||||
}
|
||||
|
||||
func (c *conn) createFunctionInternal(fun *userDefinedFunction) error {
|
||||
if rc := sqlite3.Xsqlite3_create_function(
|
||||
c.tls,
|
||||
c.db,
|
||||
fun.zFuncName,
|
||||
fun.nArg,
|
||||
fun.eTextRep,
|
||||
0,
|
||||
*(*uintptr)(unsafe.Pointer(&fun.xFunc)),
|
||||
0,
|
||||
0,
|
||||
); rc != sqlite3.SQLITE_OK {
|
||||
return c.errstr(rc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Execer is an optional interface that may be implemented by a Conn.
|
||||
//
|
||||
// If a Conn does not implement Execer, the sql package's DB.Exec will first
|
||||
@ -1343,9 +1421,14 @@ func (c *conn) query(ctx context.Context, query string, args []driver.NamedValue
|
||||
}
|
||||
|
||||
// Driver implements database/sql/driver.Driver.
|
||||
type Driver struct{}
|
||||
type Driver struct {
|
||||
// user defined functions that are added to every new connection on Open
|
||||
udfs map[string]*userDefinedFunction
|
||||
}
|
||||
|
||||
func newDriver() *Driver { return &Driver{} }
|
||||
var d = &Driver{udfs: make(map[string]*userDefinedFunction)}
|
||||
|
||||
func newDriver() *Driver { return d }
|
||||
|
||||
// Open returns a new connection to the database. The name is a string in a
|
||||
// driver-specific format.
|
||||
@ -1355,6 +1438,202 @@ func newDriver() *Driver { return &Driver{} }
|
||||
// efficient re-use.
|
||||
//
|
||||
// The returned connection is only used by one goroutine at a time.
|
||||
//
|
||||
// If name contains a '?', what follows is treated as a query string. This
|
||||
// driver supports the following query parameters:
|
||||
//
|
||||
// _pragma: Each value will be run as a "PRAGMA ..." statement (with the PRAGMA
|
||||
// keyword added for you). May be specified more than once. Example:
|
||||
// "_pragma=foreign_keys(1)" will enable foreign key enforcement. More
|
||||
// information on supported PRAGMAs is available from the SQLite documentation:
|
||||
// https://www.sqlite.org/pragma.html
|
||||
//
|
||||
// _time_format: The name of a format to use when writing time values to the
|
||||
// database. Currently the only supported value is "sqlite", which corresponds
|
||||
// to format 7 from https://www.sqlite.org/lang_datefunc.html#time_values,
|
||||
// including the timezone specifier. If this parameter is not specified, then
|
||||
// the default String() format will be used.
|
||||
//
|
||||
// _txlock: The locking behavior to use when beginning a transaction. May be
|
||||
// "deferred", "immediate", or "exclusive" (case insensitive). The default is to
|
||||
// not specify one, which SQLite maps to "deferred". More information is
|
||||
// available at
|
||||
// https://www.sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
|
||||
func (d *Driver) Open(name string) (driver.Conn, error) {
|
||||
return newConn(name)
|
||||
c, err := newConn(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, udf := range d.udfs {
|
||||
if err = c.createFunctionInternal(udf); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// FunctionContext represents the context user defined functions execute in.
|
||||
// Fields and/or methods of this type may get addedd in the future.
|
||||
type FunctionContext struct{}
|
||||
|
||||
const sqliteValPtrSize = unsafe.Sizeof(&sqlite3.Sqlite3_value{})
|
||||
|
||||
// RegisterScalarFunction registers a scalar function named zFuncName with nArg
|
||||
// arguments. Passing -1 for nArg indicates the function is variadic.
|
||||
//
|
||||
// The new function will be available to all new connections opened after
|
||||
// executing RegisterScalarFunction.
|
||||
func RegisterScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) error {
|
||||
return registerScalarFunction(zFuncName, nArg, sqlite3.SQLITE_UTF8, xFunc)
|
||||
}
|
||||
|
||||
// MustRegisterScalarFunction is like RegisterScalarFunction but panics on
|
||||
// error.
|
||||
func MustRegisterScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) {
|
||||
if err := RegisterScalarFunction(zFuncName, nArg, xFunc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustRegisterDeterministicScalarFunction is like
|
||||
// RegisterDeterministicScalarFunction but panics on error.
|
||||
func MustRegisterDeterministicScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) {
|
||||
if err := RegisterDeterministicScalarFunction(zFuncName, nArg, xFunc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterDeterministicScalarFunction registers a deterministic scalar
|
||||
// function named zFuncName with nArg arguments. Passing -1 for nArg indicates
|
||||
// the function is variadic. A deterministic function means that the function
|
||||
// always gives the same output when the input parameters are the same.
|
||||
//
|
||||
// The new function will be available to all new connections opened after
|
||||
// executing RegisterDeterministicScalarFunction.
|
||||
func RegisterDeterministicScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) error {
|
||||
return registerScalarFunction(zFuncName, nArg, sqlite3.SQLITE_UTF8|sqlite3.SQLITE_DETERMINISTIC, xFunc)
|
||||
}
|
||||
|
||||
func registerScalarFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
eTextRep int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) error {
|
||||
|
||||
if _, ok := d.udfs[zFuncName]; ok {
|
||||
return fmt.Errorf("a function named %q is already registered", zFuncName)
|
||||
}
|
||||
|
||||
// dont free, functions registered on the driver live as long as the program
|
||||
name, err := libc.CString(zFuncName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
udf := &userDefinedFunction{
|
||||
zFuncName: name,
|
||||
nArg: nArg,
|
||||
eTextRep: eTextRep,
|
||||
xFunc: func(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
||||
setErrorResult := func(res error) {
|
||||
errmsg, cerr := libc.CString(res.Error())
|
||||
if cerr != nil {
|
||||
panic(cerr)
|
||||
}
|
||||
defer libc.Xfree(tls, errmsg)
|
||||
sqlite3.Xsqlite3_result_error(tls, ctx, errmsg, -1)
|
||||
sqlite3.Xsqlite3_result_error_code(tls, ctx, sqlite3.SQLITE_ERROR)
|
||||
}
|
||||
|
||||
args := make([]driver.Value, argc)
|
||||
for i := int32(0); i < argc; i++ {
|
||||
valPtr := *(*uintptr)(unsafe.Pointer(argv + uintptr(i)*sqliteValPtrSize))
|
||||
|
||||
switch valType := sqlite3.Xsqlite3_value_type(tls, valPtr); valType {
|
||||
case sqlite3.SQLITE_TEXT:
|
||||
args[i] = libc.GoString(sqlite3.Xsqlite3_value_text(tls, valPtr))
|
||||
case sqlite3.SQLITE_INTEGER:
|
||||
args[i] = sqlite3.Xsqlite3_value_int64(tls, valPtr)
|
||||
case sqlite3.SQLITE_FLOAT:
|
||||
args[i] = sqlite3.Xsqlite3_value_double(tls, valPtr)
|
||||
case sqlite3.SQLITE_NULL:
|
||||
args[i] = nil
|
||||
case sqlite3.SQLITE_BLOB:
|
||||
size := sqlite3.Xsqlite3_value_bytes(tls, valPtr)
|
||||
blobPtr := sqlite3.Xsqlite3_value_blob(tls, valPtr)
|
||||
v := make([]byte, size)
|
||||
copy(v, (*libc.RawMem)(unsafe.Pointer(blobPtr))[:size:size])
|
||||
args[i] = v
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected argument type %q passed by sqlite", valType))
|
||||
}
|
||||
}
|
||||
|
||||
res, err := xFunc(&FunctionContext{}, args)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
return
|
||||
}
|
||||
|
||||
switch resTyped := res.(type) {
|
||||
case nil:
|
||||
sqlite3.Xsqlite3_result_null(tls, ctx)
|
||||
case int64:
|
||||
sqlite3.Xsqlite3_result_int64(tls, ctx, resTyped)
|
||||
case float64:
|
||||
sqlite3.Xsqlite3_result_double(tls, ctx, resTyped)
|
||||
case bool:
|
||||
sqlite3.Xsqlite3_result_int(tls, ctx, libc.Bool32(resTyped))
|
||||
case time.Time:
|
||||
sqlite3.Xsqlite3_result_int64(tls, ctx, resTyped.Unix())
|
||||
case string:
|
||||
size := int32(len(resTyped))
|
||||
cstr, err := libc.CString(resTyped)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer libc.Xfree(tls, cstr)
|
||||
sqlite3.Xsqlite3_result_text(tls, ctx, cstr, size, sqlite3.SQLITE_TRANSIENT)
|
||||
case []byte:
|
||||
size := int32(len(resTyped))
|
||||
if size == 0 {
|
||||
sqlite3.Xsqlite3_result_zeroblob(tls, ctx, 0)
|
||||
return
|
||||
}
|
||||
p := libc.Xmalloc(tls, types.Size_t(size))
|
||||
if p == 0 {
|
||||
panic(fmt.Sprintf("unable to allocate space for blob: %d", size))
|
||||
}
|
||||
defer libc.Xfree(tls, p)
|
||||
copy((*libc.RawMem)(unsafe.Pointer(p))[:size:size], resTyped)
|
||||
|
||||
sqlite3.Xsqlite3_result_blob(tls, ctx, p, size, sqlite3.SQLITE_TRANSIENT)
|
||||
default:
|
||||
setErrorResult(fmt.Errorf("function did not return a valid driver.Value: %T", resTyped))
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
d.udfs[zFuncName] = udf
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user