diff options
Diffstat (limited to 'vendor/github.com/ncruces/go-sqlite3/context.go')
-rw-r--r-- | vendor/github.com/ncruces/go-sqlite3/context.go | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/vendor/github.com/ncruces/go-sqlite3/context.go b/vendor/github.com/ncruces/go-sqlite3/context.go new file mode 100644 index 000000000..8d7604c66 --- /dev/null +++ b/vendor/github.com/ncruces/go-sqlite3/context.go @@ -0,0 +1,229 @@ +package sqlite3 + +import ( + "encoding/json" + "errors" + "math" + "time" + + "github.com/ncruces/go-sqlite3/internal/util" +) + +// Context is the context in which an SQL function executes. +// An SQLite [Context] is in no way related to a Go [context.Context]. +// +// https://sqlite.org/c3ref/context.html +type Context struct { + c *Conn + handle uint32 +} + +// Conn returns the database connection of the +// [Conn.CreateFunction] or [Conn.CreateWindowFunction] +// routines that originally registered the application defined function. +// +// https://sqlite.org/c3ref/context_db_handle.html +func (ctx Context) Conn() *Conn { + return ctx.c +} + +// SetAuxData saves metadata for argument n of the function. +// +// https://sqlite.org/c3ref/get_auxdata.html +func (ctx Context) SetAuxData(n int, data any) { + ptr := util.AddHandle(ctx.c.ctx, data) + ctx.c.call("sqlite3_set_auxdata_go", uint64(ctx.handle), uint64(n), uint64(ptr)) +} + +// GetAuxData returns metadata for argument n of the function. +// +// https://sqlite.org/c3ref/get_auxdata.html +func (ctx Context) GetAuxData(n int) any { + ptr := uint32(ctx.c.call("sqlite3_get_auxdata", uint64(ctx.handle), uint64(n))) + return util.GetHandle(ctx.c.ctx, ptr) +} + +// ResultBool sets the result of the function to a bool. +// SQLite does not have a separate boolean storage class. +// Instead, boolean values are stored as integers 0 (false) and 1 (true). +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultBool(value bool) { + var i int64 + if value { + i = 1 + } + ctx.ResultInt64(i) +} + +// ResultInt sets the result of the function to an int. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultInt(value int) { + ctx.ResultInt64(int64(value)) +} + +// ResultInt64 sets the result of the function to an int64. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultInt64(value int64) { + ctx.c.call("sqlite3_result_int64", + uint64(ctx.handle), uint64(value)) +} + +// ResultFloat sets the result of the function to a float64. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultFloat(value float64) { + ctx.c.call("sqlite3_result_double", + uint64(ctx.handle), math.Float64bits(value)) +} + +// ResultText sets the result of the function to a string. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultText(value string) { + ptr := ctx.c.newString(value) + ctx.c.call("sqlite3_result_text64", + uint64(ctx.handle), uint64(ptr), uint64(len(value)), + uint64(ctx.c.freer), _UTF8) +} + +// ResultRawText sets the text result of the function to a []byte. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultRawText(value []byte) { + ptr := ctx.c.newBytes(value) + ctx.c.call("sqlite3_result_text64", + uint64(ctx.handle), uint64(ptr), uint64(len(value)), + uint64(ctx.c.freer), _UTF8) +} + +// ResultBlob sets the result of the function to a []byte. +// Returning a nil slice is the same as calling [Context.ResultNull]. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultBlob(value []byte) { + ptr := ctx.c.newBytes(value) + ctx.c.call("sqlite3_result_blob64", + uint64(ctx.handle), uint64(ptr), uint64(len(value)), + uint64(ctx.c.freer)) +} + +// ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultZeroBlob(n int64) { + ctx.c.call("sqlite3_result_zeroblob64", + uint64(ctx.handle), uint64(n)) +} + +// ResultNull sets the result of the function to NULL. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultNull() { + ctx.c.call("sqlite3_result_null", + uint64(ctx.handle)) +} + +// ResultTime sets the result of the function to a [time.Time]. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultTime(value time.Time, format TimeFormat) { + if format == TimeFormatDefault { + ctx.resultRFC3339Nano(value) + return + } + switch v := format.Encode(value).(type) { + case string: + ctx.ResultText(v) + case int64: + ctx.ResultInt64(v) + case float64: + ctx.ResultFloat(v) + default: + panic(util.AssertErr()) + } +} + +func (ctx Context) resultRFC3339Nano(value time.Time) { + const maxlen = uint64(len(time.RFC3339Nano)) + 5 + + ptr := ctx.c.new(maxlen) + buf := util.View(ctx.c.mod, ptr, maxlen) + buf = value.AppendFormat(buf[:0], time.RFC3339Nano) + + ctx.c.call("sqlite3_result_text64", + uint64(ctx.handle), uint64(ptr), uint64(len(buf)), + uint64(ctx.c.freer), _UTF8) +} + +// ResultPointer sets the result of the function to NULL, just like [Context.ResultNull], +// except that it also associates ptr with that NULL value such that it can be retrieved +// within an application-defined SQL function using [Value.Pointer]. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultPointer(ptr any) { + valPtr := util.AddHandle(ctx.c.ctx, ptr) + ctx.c.call("sqlite3_result_pointer_go", uint64(valPtr)) +} + +// ResultJSON sets the result of the function to the JSON encoding of value. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultJSON(value any) { + data, err := json.Marshal(value) + if err != nil { + ctx.ResultError(err) + return + } + ctx.ResultRawText(data) +} + +// ResultValue sets the result of the function to a copy of [Value]. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultValue(value Value) { + if value.c != ctx.c { + ctx.ResultError(MISUSE) + return + } + ctx.c.call("sqlite3_result_value", + uint64(ctx.handle), uint64(value.handle)) +} + +// ResultError sets the result of the function an error. +// +// https://sqlite.org/c3ref/result_blob.html +func (ctx Context) ResultError(err error) { + if errors.Is(err, NOMEM) { + ctx.c.call("sqlite3_result_error_nomem", uint64(ctx.handle)) + return + } + + if errors.Is(err, TOOBIG) { + ctx.c.call("sqlite3_result_error_toobig", uint64(ctx.handle)) + return + } + + msg, code := errorCode(err, _OK) + if msg != "" { + defer ctx.c.arena.mark()() + ptr := ctx.c.arena.string(msg) + ctx.c.call("sqlite3_result_error", + uint64(ctx.handle), uint64(ptr), uint64(len(msg))) + } + if code != _OK { + ctx.c.call("sqlite3_result_error_code", + uint64(ctx.handle), uint64(code)) + } +} + +// VTabNoChange may return true if a column is being fetched as part +// of an update during which the column value will not change. +// +// https://sqlite.org/c3ref/vtab_nochange.html +func (ctx Context) VTabNoChange() bool { + r := ctx.c.call("sqlite3_vtab_nochange", uint64(ctx.handle)) + return r != 0 +} |