Files
sqlite3/context.go

230 lines
6.3 KiB
Go
Raw Normal View History

2023-06-30 11:48:54 +01:00
package sqlite3
import (
2023-10-13 17:06:05 +01:00
"encoding/json"
2023-06-30 12:25:07 +01:00
"errors"
2023-06-30 11:48:54 +01:00
"math"
"time"
"github.com/ncruces/go-sqlite3/internal/util"
)
// Context is the context in which an SQL function executes.
2023-07-04 02:29:38 +01:00
// An SQLite [Context] is in no way related to a Go [context.Context].
2023-06-30 11:48:54 +01:00
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/context.html
2023-06-30 11:48:54 +01:00
type Context struct {
2023-11-06 18:11:47 +00:00
c *Conn
2023-06-30 11:48:54 +01:00
handle uint32
}
2023-11-06 18:11:47 +00:00
// 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
}
2023-07-04 02:18:03 +01:00
// SetAuxData saves metadata for argument n of the function.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/get_auxdata.html
2023-11-06 18:11:47 +00:00
func (ctx Context) SetAuxData(n int, data any) {
ptr := util.AddHandle(ctx.c.ctx, data)
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_set_auxdata_go", uint64(ctx.handle), uint64(n), uint64(ptr))
2023-07-04 02:18:03 +01:00
}
// GetAuxData returns metadata for argument n of the function.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/get_auxdata.html
2023-11-06 18:11:47 +00:00
func (ctx Context) GetAuxData(n int) any {
2023-11-30 17:52:35 +00:00
ptr := uint32(ctx.c.call("sqlite3_get_auxdata", uint64(ctx.handle), uint64(n)))
2023-11-06 18:11:47 +00:00
return util.GetHandle(ctx.c.ctx, ptr)
2023-07-04 02:18:03 +01:00
}
2023-06-30 11:48:54 +01:00
// 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).
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultBool(value bool) {
2023-06-30 11:48:54 +01:00
var i int64
if value {
i = 1
}
2023-11-06 18:11:47 +00:00
ctx.ResultInt64(i)
2023-06-30 11:48:54 +01:00
}
// ResultInt sets the result of the function to an int.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultInt(value int) {
ctx.ResultInt64(int64(value))
2023-06-30 11:48:54 +01:00
}
// ResultInt64 sets the result of the function to an int64.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultInt64(value int64) {
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_int64",
2023-11-06 18:11:47 +00:00
uint64(ctx.handle), uint64(value))
2023-06-30 11:48:54 +01:00
}
// ResultFloat sets the result of the function to a float64.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultFloat(value float64) {
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_double",
2023-11-06 18:11:47 +00:00
uint64(ctx.handle), math.Float64bits(value))
2023-06-30 11:48:54 +01:00
}
// ResultText sets the result of the function to a string.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultText(value string) {
ptr := ctx.c.newString(value)
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_text64",
2023-11-06 18:11:47 +00:00
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
2023-11-30 17:52:35 +00:00
uint64(ctx.c.freer), _UTF8)
2023-06-30 11:48:54 +01:00
}
2023-11-10 13:42:11 +00:00
// 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)
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_text64",
2023-11-10 13:42:11 +00:00
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
2023-11-30 17:52:35 +00:00
uint64(ctx.c.freer), _UTF8)
2023-11-10 13:42:11 +00:00
}
2023-06-30 11:48:54 +01:00
// ResultBlob sets the result of the function to a []byte.
// Returning a nil slice is the same as calling [Context.ResultNull].
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultBlob(value []byte) {
ptr := ctx.c.newBytes(value)
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_blob64",
2023-11-06 18:11:47 +00:00
uint64(ctx.handle), uint64(ptr), uint64(len(value)),
2023-11-30 17:52:35 +00:00
uint64(ctx.c.freer))
2023-06-30 11:48:54 +01:00
}
2023-11-10 13:42:11 +00:00
// ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB.
2023-06-30 11:48:54 +01:00
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultZeroBlob(n int64) {
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_zeroblob64",
2023-11-06 18:11:47 +00:00
uint64(ctx.handle), uint64(n))
2023-06-30 11:48:54 +01:00
}
// ResultNull sets the result of the function to NULL.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultNull() {
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_null",
2023-11-06 18:11:47 +00:00
uint64(ctx.handle))
2023-06-30 11:48:54 +01:00
}
// ResultTime sets the result of the function to a [time.Time].
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultTime(value time.Time, format TimeFormat) {
2023-06-30 11:48:54 +01:00
if format == TimeFormatDefault {
2023-11-06 18:11:47 +00:00
ctx.resultRFC3339Nano(value)
2023-06-30 11:48:54 +01:00
return
}
switch v := format.Encode(value).(type) {
case string:
2023-11-06 18:11:47 +00:00
ctx.ResultText(v)
2023-06-30 11:48:54 +01:00
case int64:
2023-11-06 18:11:47 +00:00
ctx.ResultInt64(v)
2023-06-30 11:48:54 +01:00
case float64:
2023-11-06 18:11:47 +00:00
ctx.ResultFloat(v)
2023-06-30 11:48:54 +01:00
default:
panic(util.AssertErr())
}
}
2023-11-06 18:11:47 +00:00
func (ctx Context) resultRFC3339Nano(value time.Time) {
2023-10-19 16:46:58 +01:00
const maxlen = uint64(len(time.RFC3339Nano)) + 5
2023-06-30 11:48:54 +01:00
2023-11-06 18:11:47 +00:00
ptr := ctx.c.new(maxlen)
buf := util.View(ctx.c.mod, ptr, maxlen)
2023-06-30 11:48:54 +01:00
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_text64",
2023-11-06 18:11:47 +00:00
uint64(ctx.handle), uint64(ptr), uint64(len(buf)),
2023-11-30 17:52:35 +00:00
uint64(ctx.c.freer), _UTF8)
2023-06-30 11:48:54 +01:00
}
2023-06-30 12:25:07 +01:00
2023-11-07 00:50:43 +00:00
// 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].
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-07 00:50:43 +00:00
func (ctx Context) ResultPointer(ptr any) {
valPtr := util.AddHandle(ctx.c.ctx, ptr)
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_pointer_go", uint64(valPtr))
2023-11-07 00:50:43 +00:00
}
2023-10-13 17:06:05 +01:00
// ResultJSON sets the result of the function to the JSON encoding of value.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultJSON(value any) {
2023-10-13 17:06:05 +01:00
data, err := json.Marshal(value)
if err != nil {
2023-11-06 18:11:47 +00:00
ctx.ResultError(err)
2023-11-27 14:57:04 +00:00
return
2023-10-13 17:06:05 +01:00
}
2023-11-10 13:42:11 +00:00
ctx.ResultRawText(data)
2023-10-13 17:06:05 +01:00
}
2023-11-17 19:06:10 +00:00
// ResultValue sets the result of the function to a copy of [Value].
2023-10-13 17:06:05 +01:00
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultValue(value Value) {
2024-01-08 19:23:32 +00:00
if value.c != ctx.c {
2023-11-06 18:11:47 +00:00
ctx.ResultError(MISUSE)
2023-11-27 14:57:04 +00:00
return
2023-10-13 17:06:05 +01:00
}
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_value",
2023-11-06 18:11:47 +00:00
uint64(ctx.handle), uint64(value.handle))
2023-10-13 17:06:05 +01:00
}
2023-06-30 12:25:07 +01:00
// ResultError sets the result of the function an error.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/result_blob.html
2023-11-06 18:11:47 +00:00
func (ctx Context) ResultError(err error) {
2023-06-30 12:25:07 +01:00
if errors.Is(err, NOMEM) {
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_error_nomem", uint64(ctx.handle))
2023-06-30 12:25:07 +01:00
return
}
if errors.Is(err, TOOBIG) {
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_error_toobig", uint64(ctx.handle))
2023-06-30 12:25:07 +01:00
return
}
2023-11-21 13:40:55 +00:00
msg, code := errorCode(err, _OK)
if msg != "" {
2023-11-29 10:38:03 +00:00
defer ctx.c.arena.mark()()
ptr := ctx.c.arena.string(msg)
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_error",
2023-11-21 13:40:55 +00:00
uint64(ctx.handle), uint64(ptr), uint64(len(msg)))
}
if code != _OK {
2023-11-30 17:52:35 +00:00
ctx.c.call("sqlite3_result_error_code",
2023-11-16 01:16:38 +00:00
uint64(ctx.handle), uint64(code))
2023-06-30 12:25:07 +01:00
}
}
2024-01-08 19:23:32 +00:00
// VTabNoChange may return true if a column is being fetched as part
// of an update during which the column value will not change.
//
2024-01-18 15:53:00 +00:00
// https://sqlite.org/c3ref/vtab_nochange.html
2024-01-08 19:23:32 +00:00
func (ctx Context) VTabNoChange() bool {
r := ctx.c.call("sqlite3_vtab_nochange", uint64(ctx.handle))
return r != 0
}