mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 17:12:26 -05:00
[chore] update latest deps, ensure readme up to date (#1873)
* [chore] update latest deps, ensure readme up to date * remove double entry
This commit is contained in:
parent
f1b70cc00f
commit
b401bd1ccb
156 changed files with 11730 additions and 2842 deletions
613
vendor/modernc.org/sqlite/sqlite.go
generated
vendored
613
vendor/modernc.org/sqlite/sqlite.go
generated
vendored
|
|
@ -10,11 +10,14 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/bits"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
@ -1319,7 +1322,12 @@ func (c *conn) errstr(rc int32) error {
|
|||
// Begin starts a transaction.
|
||||
//
|
||||
// Deprecated: Drivers should implement ConnBeginTx instead (or additionally).
|
||||
func (c *conn) Begin() (driver.Tx, error) {
|
||||
func (c *conn) Begin() (dt driver.Tx, err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("conn %p: (driver.Tx %p, err %v)", c, dt, err)
|
||||
}()
|
||||
}
|
||||
return c.begin(context.Background(), driver.TxOptions{})
|
||||
}
|
||||
|
||||
|
|
@ -1333,7 +1341,12 @@ func (c *conn) begin(ctx context.Context, opts driver.TxOptions) (t driver.Tx, e
|
|||
// Because the sql package maintains a free pool of connections and only calls
|
||||
// Close when there's a surplus of idle connections, it shouldn't be necessary
|
||||
// for drivers to do their own connection caching.
|
||||
func (c *conn) Close() error {
|
||||
func (c *conn) Close() (err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("conn %p: err %v", c, err)
|
||||
}()
|
||||
}
|
||||
c.Lock() // Defend against race with .interrupt invoked by context handling.
|
||||
|
||||
defer c.Unlock()
|
||||
|
|
@ -1362,27 +1375,106 @@ func (c *conn) closeV2(db uintptr) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// FunctionImpl describes an [application-defined SQL function]. If Scalar is
|
||||
// set, it is treated as a scalar function; otherwise, it is treated as an
|
||||
// aggregate function using MakeAggregate.
|
||||
//
|
||||
// [application-defined SQL function]: https://sqlite.org/appfunc.html
|
||||
type FunctionImpl struct {
|
||||
// NArgs is the required number of arguments that the function accepts.
|
||||
// If NArgs is negative, then the function is variadic.
|
||||
NArgs int32
|
||||
|
||||
// If Deterministic is true, the function must always give the same
|
||||
// output when the input parameters are the same. This enables functions
|
||||
// to be used in additional contexts like the WHERE clause of partial
|
||||
// indexes and enables additional optimizations.
|
||||
//
|
||||
// See https://sqlite.org/c3ref/c_deterministic.html#sqlitedeterministic
|
||||
// for more details.
|
||||
Deterministic bool
|
||||
|
||||
// Scalar is called when a scalar function is invoked in SQL. The
|
||||
// argument Values are not valid past the return of the function.
|
||||
Scalar func(ctx *FunctionContext, args []driver.Value) (driver.Value, error)
|
||||
|
||||
// MakeAggregate is called at the beginning of each evaluation of an
|
||||
// aggregate function.
|
||||
MakeAggregate func(ctx FunctionContext) (AggregateFunction, error)
|
||||
}
|
||||
|
||||
// An AggregateFunction is an invocation of an aggregate or window function. See
|
||||
// the documentation for [aggregate function callbacks] and [application-defined
|
||||
// window functions] for an overview.
|
||||
//
|
||||
// [aggregate function callbacks]: https://www.sqlite.org/appfunc.html#the_aggregate_function_callbacks
|
||||
// [application-defined window functions]: https://www.sqlite.org/windowfunctions.html#user_defined_aggregate_window_functions
|
||||
type AggregateFunction interface {
|
||||
// Step is called for each row of an aggregate function's SQL
|
||||
// invocation. The argument Values are not valid past the return of the
|
||||
// function.
|
||||
Step(ctx *FunctionContext, rowArgs []driver.Value) error
|
||||
|
||||
// WindowInverse is called to remove the oldest presently aggregated
|
||||
// result of Step from the current window. The arguments are those
|
||||
// passed to Step for the row being removed. The argument Values are not
|
||||
// valid past the return of the function.
|
||||
WindowInverse(ctx *FunctionContext, rowArgs []driver.Value) error
|
||||
|
||||
// WindowValue is called to get the current value of an aggregate
|
||||
// function. This is used to return the final value of the function,
|
||||
// whether it is used as a window function or not.
|
||||
WindowValue(ctx *FunctionContext) (driver.Value, error)
|
||||
|
||||
// Final is called after all of the aggregate function's input rows have
|
||||
// been stepped through. No other methods will be called on the
|
||||
// AggregateFunction after calling Final. WindowValue returns the value
|
||||
// from the function.
|
||||
Final(ctx *FunctionContext)
|
||||
}
|
||||
|
||||
type userDefinedFunction struct {
|
||||
zFuncName uintptr
|
||||
nArg int32
|
||||
eTextRep int32
|
||||
xFunc func(*libc.TLS, uintptr, int32, uintptr)
|
||||
pApp uintptr
|
||||
|
||||
scalar bool
|
||||
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 {
|
||||
var rc int32
|
||||
|
||||
if fun.scalar {
|
||||
rc = sqlite3.Xsqlite3_create_function(
|
||||
c.tls,
|
||||
c.db,
|
||||
fun.zFuncName,
|
||||
fun.nArg,
|
||||
fun.eTextRep,
|
||||
fun.pApp,
|
||||
cFuncPointer(funcTrampoline),
|
||||
0,
|
||||
0,
|
||||
)
|
||||
} else {
|
||||
rc = sqlite3.Xsqlite3_create_window_function(
|
||||
c.tls,
|
||||
c.db,
|
||||
fun.zFuncName,
|
||||
fun.nArg,
|
||||
fun.eTextRep,
|
||||
fun.pApp,
|
||||
cFuncPointer(stepTrampoline),
|
||||
cFuncPointer(finalTrampoline),
|
||||
cFuncPointer(valueTrampoline),
|
||||
cFuncPointer(inverseTrampoline),
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
if rc != sqlite3.SQLITE_OK {
|
||||
return c.errstr(rc)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -1396,7 +1488,12 @@ func (c *conn) createFunctionInternal(fun *userDefinedFunction) error {
|
|||
// Exec may return ErrSkip.
|
||||
//
|
||||
// Deprecated: Drivers should implement ExecerContext instead.
|
||||
func (c *conn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
||||
func (c *conn) Exec(query string, args []driver.Value) (dr driver.Result, err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("conn %p, query %q, args %v: (driver.Result %p, err %v)", c, query, args, dr, err)
|
||||
}()
|
||||
}
|
||||
return c.exec(context.Background(), query, toNamedValues(args))
|
||||
}
|
||||
|
||||
|
|
@ -1416,7 +1513,12 @@ func (c *conn) exec(ctx context.Context, query string, args []driver.NamedValue)
|
|||
}
|
||||
|
||||
// Prepare returns a prepared statement, bound to this connection.
|
||||
func (c *conn) Prepare(query string) (driver.Stmt, error) {
|
||||
func (c *conn) Prepare(query string) (ds driver.Stmt, err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("conn %p, query %q: (driver.Stmt %p, err %v)", c, query, ds, err)
|
||||
}()
|
||||
}
|
||||
return c.prepare(context.Background(), query)
|
||||
}
|
||||
|
||||
|
|
@ -1433,7 +1535,12 @@ func (c *conn) prepare(ctx context.Context, query string) (s driver.Stmt, err er
|
|||
// Query may return ErrSkip.
|
||||
//
|
||||
// Deprecated: Drivers should implement QueryerContext instead.
|
||||
func (c *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
||||
func (c *conn) Query(query string, args []driver.Value) (dr driver.Rows, err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("conn %p, query %q, args %v: (driver.Rows %p, err %v)", c, query, args, dr, err)
|
||||
}()
|
||||
}
|
||||
return c.query(context.Background(), query, toNamedValues(args))
|
||||
}
|
||||
|
||||
|
|
@ -1491,7 +1598,12 @@ func newDriver() *Driver { return d }
|
|||
// 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) {
|
||||
func (d *Driver) Open(name string) (conn driver.Conn, err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("name %q: (driver.Conn %p, err %v)", name, conn, err)
|
||||
}()
|
||||
}
|
||||
c, err := newConn(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -1508,10 +1620,38 @@ func (d *Driver) Open(name string) (driver.Conn, error) {
|
|||
|
||||
// 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{}
|
||||
type FunctionContext struct {
|
||||
tls *libc.TLS
|
||||
ctx uintptr
|
||||
}
|
||||
|
||||
const sqliteValPtrSize = unsafe.Sizeof(&sqlite3.Sqlite3_value{})
|
||||
|
||||
// RegisterFunction registers a function named zFuncName with nArg arguments.
|
||||
// Passing -1 for nArg indicates the function is variadic. The FunctionImpl
|
||||
// determines whether the function is deterministic or not, and whether it is a
|
||||
// scalar function (when Scalar is defined) or an aggregate function (when
|
||||
// Scalar is not defined and MakeAggregate is defined).
|
||||
//
|
||||
// The new function will be available to all new connections opened after
|
||||
// executing RegisterFunction.
|
||||
func RegisterFunction(
|
||||
zFuncName string,
|
||||
impl *FunctionImpl,
|
||||
) error {
|
||||
return registerFunction(zFuncName, impl)
|
||||
}
|
||||
|
||||
// MustRegisterFunction is like RegisterFunction but panics on error.
|
||||
func MustRegisterFunction(
|
||||
zFuncName string,
|
||||
impl *FunctionImpl,
|
||||
) {
|
||||
if err := RegisterFunction(zFuncName, impl); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterScalarFunction registers a scalar function named zFuncName with nArg
|
||||
// arguments. Passing -1 for nArg indicates the function is variadic.
|
||||
//
|
||||
|
|
@ -1521,8 +1661,13 @@ 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)
|
||||
) (err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("zFuncName %q, nArg %v, xFunc %p: err %v", zFuncName, nArg, xFunc, err)
|
||||
}()
|
||||
}
|
||||
return registerFunction(zFuncName, &FunctionImpl{NArgs: nArg, Scalar: xFunc, Deterministic: false})
|
||||
}
|
||||
|
||||
// MustRegisterScalarFunction is like RegisterScalarFunction but panics on
|
||||
|
|
@ -1532,6 +1677,9 @@ func MustRegisterScalarFunction(
|
|||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) {
|
||||
if dmesgs {
|
||||
dmesg("zFuncName %q, nArg %v, xFunc %p", zFuncName, nArg, xFunc)
|
||||
}
|
||||
if err := RegisterScalarFunction(zFuncName, nArg, xFunc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -1544,6 +1692,9 @@ func MustRegisterDeterministicScalarFunction(
|
|||
nArg int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
) {
|
||||
if dmesgs {
|
||||
dmesg("zFuncName %q, nArg %v, xFunc %p", zFuncName, nArg, xFunc)
|
||||
}
|
||||
if err := RegisterDeterministicScalarFunction(zFuncName, nArg, xFunc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -1560,15 +1711,18 @@ 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)
|
||||
) (err error) {
|
||||
if dmesgs {
|
||||
defer func() {
|
||||
dmesg("zFuncName %q, nArg %v, xFunc %p: err %v", zFuncName, nArg, xFunc, err)
|
||||
}()
|
||||
}
|
||||
return registerFunction(zFuncName, &FunctionImpl{NArgs: nArg, Scalar: xFunc, Deterministic: true})
|
||||
}
|
||||
|
||||
func registerScalarFunction(
|
||||
func registerFunction(
|
||||
zFuncName string,
|
||||
nArg int32,
|
||||
eTextRep int32,
|
||||
xFunc func(ctx *FunctionContext, args []driver.Value) (driver.Value, error),
|
||||
impl *FunctionImpl,
|
||||
) error {
|
||||
|
||||
if _, ok := d.udfs[zFuncName]; ok {
|
||||
|
|
@ -1581,91 +1735,334 @@ func registerScalarFunction(
|
|||
return err
|
||||
}
|
||||
|
||||
var textrep int32 = sqlite3.SQLITE_UTF8
|
||||
|
||||
if impl.Deterministic {
|
||||
textrep |= sqlite3.SQLITE_DETERMINISTIC
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
},
|
||||
nArg: impl.NArgs,
|
||||
eTextRep: textrep,
|
||||
}
|
||||
|
||||
if impl.Scalar != nil {
|
||||
xFuncs.mu.Lock()
|
||||
id := xFuncs.ids.next()
|
||||
xFuncs.m[id] = impl.Scalar
|
||||
xFuncs.mu.Unlock()
|
||||
|
||||
udf.scalar = true
|
||||
udf.pApp = id
|
||||
} else {
|
||||
xAggregateFactories.mu.Lock()
|
||||
id := xAggregateFactories.ids.next()
|
||||
xAggregateFactories.m[id] = impl.MakeAggregate
|
||||
xAggregateFactories.mu.Unlock()
|
||||
|
||||
udf.pApp = id
|
||||
}
|
||||
|
||||
d.udfs[zFuncName] = udf
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func origin(skip int) string {
|
||||
pc, fn, fl, _ := runtime.Caller(skip)
|
||||
f := runtime.FuncForPC(pc)
|
||||
var fns string
|
||||
if f != nil {
|
||||
fns = f.Name()
|
||||
if x := strings.LastIndex(fns, "."); x > 0 {
|
||||
fns = fns[x+1:]
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s:%d:%s", fn, fl, fns)
|
||||
}
|
||||
|
||||
func errorResultFunction(tls *libc.TLS, ctx uintptr) func(error) {
|
||||
return 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)
|
||||
}
|
||||
}
|
||||
|
||||
func functionArgs(tls *libc.TLS, argc int32, argv uintptr) []driver.Value {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func functionReturnValue(tls *libc.TLS, ctx uintptr, res driver.Value) error {
|
||||
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 nil
|
||||
}
|
||||
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:
|
||||
return fmt.Errorf("function did not return a valid driver.Value: %T", resTyped)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The below is all taken from zombiezen.com/go/sqlite. Aggregate functions need
|
||||
// to maintain state (for instance, the count of values seen so far). We give
|
||||
// each aggregate function an ID, generated by idGen, and put that in the pApp
|
||||
// argument to sqlite3_create_function. We track this on the Go side in
|
||||
// xAggregateFactories.
|
||||
//
|
||||
// When (if) the function is called is called by a query, we call the
|
||||
// MakeAggregate factory function to set it up, and track that in
|
||||
// xAggregateContext, retrieving it via sqlite3_aggregate_context.
|
||||
//
|
||||
// We also need to ensure that, for both aggregate and scalar functions, the
|
||||
// function pointer we pass to SQLite meets certain rules on the Go side, so
|
||||
// that the pointer remains valid.
|
||||
var (
|
||||
xFuncs = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]func(*FunctionContext, []driver.Value) (driver.Value, error)
|
||||
ids idGen
|
||||
}{
|
||||
m: make(map[uintptr]func(*FunctionContext, []driver.Value) (driver.Value, error)),
|
||||
}
|
||||
|
||||
xAggregateFactories = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]func(FunctionContext) (AggregateFunction, error)
|
||||
ids idGen
|
||||
}{
|
||||
m: make(map[uintptr]func(FunctionContext) (AggregateFunction, error)),
|
||||
}
|
||||
|
||||
xAggregateContext = struct {
|
||||
mu sync.RWMutex
|
||||
m map[uintptr]AggregateFunction
|
||||
ids idGen
|
||||
}{
|
||||
m: make(map[uintptr]AggregateFunction),
|
||||
}
|
||||
)
|
||||
|
||||
type idGen struct {
|
||||
bitset []uint64
|
||||
}
|
||||
|
||||
func (gen *idGen) next() uintptr {
|
||||
base := uintptr(1)
|
||||
for i := 0; i < len(gen.bitset); i, base = i+1, base+64 {
|
||||
b := gen.bitset[i]
|
||||
if b != 1<<64-1 {
|
||||
n := uintptr(bits.TrailingZeros64(^b))
|
||||
gen.bitset[i] |= 1 << n
|
||||
return base + n
|
||||
}
|
||||
}
|
||||
gen.bitset = append(gen.bitset, 1)
|
||||
return base
|
||||
}
|
||||
|
||||
func (gen *idGen) reclaim(id uintptr) {
|
||||
bit := id - 1
|
||||
gen.bitset[bit/64] &^= 1 << (bit % 64)
|
||||
}
|
||||
|
||||
func makeAggregate(tls *libc.TLS, ctx uintptr) (AggregateFunction, uintptr) {
|
||||
goCtx := FunctionContext{tls: tls, ctx: ctx}
|
||||
aggCtx := (*uintptr)(unsafe.Pointer(sqlite3.Xsqlite3_aggregate_context(tls, ctx, int32(ptrSize))))
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
if aggCtx == nil {
|
||||
setErrorResult(errors.New("insufficient memory for aggregate"))
|
||||
return nil, 0
|
||||
}
|
||||
if *aggCtx != 0 {
|
||||
// Already created.
|
||||
xAggregateContext.mu.RLock()
|
||||
f := xAggregateContext.m[*aggCtx]
|
||||
xAggregateContext.mu.RUnlock()
|
||||
return f, *aggCtx
|
||||
}
|
||||
|
||||
factoryID := sqlite3.Xsqlite3_user_data(tls, ctx)
|
||||
xAggregateFactories.mu.RLock()
|
||||
factory := xAggregateFactories.m[factoryID]
|
||||
xAggregateFactories.mu.RUnlock()
|
||||
|
||||
f, err := factory(goCtx)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
return nil, 0
|
||||
}
|
||||
if f == nil {
|
||||
setErrorResult(errors.New("MakeAggregate function returned nil"))
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
xAggregateContext.mu.Lock()
|
||||
*aggCtx = xAggregateContext.ids.next()
|
||||
xAggregateContext.m[*aggCtx] = f
|
||||
xAggregateContext.mu.Unlock()
|
||||
return f, *aggCtx
|
||||
}
|
||||
|
||||
// cFuncPointer converts a function defined by a function declaration to a C pointer.
|
||||
// The result of using cFuncPointer on closures is undefined.
|
||||
func cFuncPointer[T any](f T) uintptr {
|
||||
// This assumes the memory representation described in https://golang.org/s/go11func.
|
||||
//
|
||||
// cFuncPointer does its conversion by doing the following in order:
|
||||
// 1) Create a Go struct containing a pointer to a pointer to
|
||||
// the function. It is assumed that the pointer to the function will be
|
||||
// stored in the read-only data section and thus will not move.
|
||||
// 2) Convert the pointer to the Go struct to a pointer to uintptr through
|
||||
// unsafe.Pointer. This is permitted via Rule #1 of unsafe.Pointer.
|
||||
// 3) Dereference the pointer to uintptr to obtain the function value as a
|
||||
// uintptr. This is safe as long as function values are passed as pointers.
|
||||
return *(*uintptr)(unsafe.Pointer(&struct{ f T }{f}))
|
||||
}
|
||||
|
||||
func funcTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
||||
id := sqlite3.Xsqlite3_user_data(tls, ctx)
|
||||
xFuncs.mu.RLock()
|
||||
xFunc := xFuncs.m[id]
|
||||
xFuncs.mu.RUnlock()
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
res, err := xFunc(&FunctionContext{}, functionArgs(tls, argc, argv))
|
||||
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = functionReturnValue(tls, ctx, res)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
|
||||
func stepTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
||||
impl, _ := makeAggregate(tls, ctx)
|
||||
if impl == nil {
|
||||
return
|
||||
}
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
err := impl.Step(&FunctionContext{}, functionArgs(tls, argc, argv))
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
|
||||
func inverseTrampoline(tls *libc.TLS, ctx uintptr, argc int32, argv uintptr) {
|
||||
impl, _ := makeAggregate(tls, ctx)
|
||||
if impl == nil {
|
||||
return
|
||||
}
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
err := impl.WindowInverse(&FunctionContext{}, functionArgs(tls, argc, argv))
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
|
||||
func valueTrampoline(tls *libc.TLS, ctx uintptr) {
|
||||
impl, _ := makeAggregate(tls, ctx)
|
||||
if impl == nil {
|
||||
return
|
||||
}
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
res, err := impl.WindowValue(&FunctionContext{})
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
} else {
|
||||
err = functionReturnValue(tls, ctx, res)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func finalTrampoline(tls *libc.TLS, ctx uintptr) {
|
||||
impl, id := makeAggregate(tls, ctx)
|
||||
if impl == nil {
|
||||
return
|
||||
}
|
||||
|
||||
setErrorResult := errorResultFunction(tls, ctx)
|
||||
res, err := impl.WindowValue(&FunctionContext{})
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
} else {
|
||||
err = functionReturnValue(tls, ctx, res)
|
||||
if err != nil {
|
||||
setErrorResult(err)
|
||||
}
|
||||
}
|
||||
impl.Final(&FunctionContext{})
|
||||
|
||||
xAggregateContext.mu.Lock()
|
||||
defer xAggregateContext.mu.Unlock()
|
||||
delete(xAggregateContext.m, id)
|
||||
xAggregateContext.ids.reclaim(id)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue