Files
sqlite3/context.go

174 lines
4.3 KiB
Go
Raw Normal View History

2023-06-30 11:48:54 +01:00
package sqlite3
import (
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.
//
// https://www.sqlite.org/c3ref/context.html
type Context struct {
2023-07-03 17:21:35 +01:00
*sqlite
2023-06-30 11:48:54 +01:00
handle uint32
}
2023-07-04 02:18:03 +01:00
// SetAuxData saves metadata for argument n of the function.
//
// https://www.sqlite.org/c3ref/get_auxdata.html
func (c Context) SetAuxData(n int, data any) {
ptr := util.AddHandle(c.ctx, data)
c.call(c.api.setAuxData, uint64(c.handle), uint64(n), uint64(ptr))
}
// GetAuxData returns metadata for argument n of the function.
//
// https://www.sqlite.org/c3ref/get_auxdata.html
func (c Context) GetAuxData(n int) any {
ptr := uint32(c.call(c.api.getAuxData, uint64(c.handle), uint64(n)))
return util.GetHandle(c.ctx, ptr)
}
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).
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultBool(value bool) {
2023-06-30 11:48:54 +01:00
var i int64
if value {
i = 1
}
c.ResultInt64(i)
}
// ResultInt sets the result of the function to an int.
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultInt(value int) {
2023-06-30 11:48:54 +01:00
c.ResultInt64(int64(value))
}
// ResultInt64 sets the result of the function to an int64.
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultInt64(value int64) {
2023-07-01 00:15:28 +01:00
c.call(c.api.resultInteger,
2023-06-30 11:48:54 +01:00
uint64(c.handle), uint64(value))
}
// ResultFloat sets the result of the function to a float64.
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultFloat(value float64) {
2023-07-01 00:15:28 +01:00
c.call(c.api.resultFloat,
2023-06-30 11:48:54 +01:00
uint64(c.handle), math.Float64bits(value))
}
// ResultText sets the result of the function to a string.
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultText(value string) {
2023-07-01 00:15:28 +01:00
ptr := c.newString(value)
c.call(c.api.resultText,
2023-06-30 11:48:54 +01:00
uint64(c.handle), uint64(ptr), uint64(len(value)),
2023-07-01 00:15:28 +01:00
uint64(c.api.destructor), _UTF8)
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].
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultBlob(value []byte) {
2023-07-01 00:15:28 +01:00
ptr := c.newBytes(value)
c.call(c.api.resultBlob,
2023-06-30 11:48:54 +01:00
uint64(c.handle), uint64(ptr), uint64(len(value)),
2023-07-01 00:15:28 +01:00
uint64(c.api.destructor))
2023-06-30 11:48:54 +01:00
}
// BindZeroBlob sets the result of the function to a zero-filled, length n BLOB.
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultZeroBlob(n int64) {
2023-07-01 00:15:28 +01:00
c.call(c.api.resultZeroBlob,
2023-06-30 11:48:54 +01:00
uint64(c.handle), uint64(n))
}
// ResultNull sets the result of the function to NULL.
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultNull() {
2023-07-01 00:15:28 +01:00
c.call(c.api.resultNull,
2023-06-30 11:48:54 +01:00
uint64(c.handle))
}
// ResultTime sets the result of the function to a [time.Time].
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultTime(value time.Time, format TimeFormat) {
2023-06-30 11:48:54 +01:00
if format == TimeFormatDefault {
c.resultRFC3339Nano(value)
return
}
switch v := format.Encode(value).(type) {
case string:
c.ResultText(v)
case int64:
c.ResultInt64(v)
case float64:
c.ResultFloat(v)
default:
panic(util.AssertErr())
}
}
2023-07-03 17:08:16 +01:00
func (c Context) resultRFC3339Nano(value time.Time) {
2023-06-30 11:48:54 +01:00
const maxlen = uint64(len(time.RFC3339Nano))
2023-07-01 00:15:28 +01:00
ptr := c.new(maxlen)
buf := util.View(c.mod, ptr, maxlen)
2023-06-30 11:48:54 +01:00
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
2023-07-01 00:15:28 +01:00
c.call(c.api.resultText,
2023-06-30 11:48:54 +01:00
uint64(c.handle), uint64(ptr), uint64(len(buf)),
2023-07-01 00:15:28 +01:00
uint64(c.api.destructor), _UTF8)
2023-06-30 11:48:54 +01:00
}
2023-06-30 12:25:07 +01:00
// ResultError sets the result of the function an error.
//
// https://www.sqlite.org/c3ref/result_blob.html
2023-07-03 17:08:16 +01:00
func (c Context) ResultError(err error) {
2023-06-30 12:25:07 +01:00
if errors.Is(err, NOMEM) {
2023-07-01 00:15:28 +01:00
c.call(c.api.resultErrorMem, uint64(c.handle))
2023-06-30 12:25:07 +01:00
return
}
if errors.Is(err, TOOBIG) {
2023-07-01 00:15:28 +01:00
c.call(c.api.resultErrorBig, uint64(c.handle))
2023-06-30 12:25:07 +01:00
return
}
str := err.Error()
2023-07-01 00:15:28 +01:00
ptr := c.newString(str)
2023-07-03 17:08:16 +01:00
c.call(c.api.resultError,
2023-06-30 12:25:07 +01:00
uint64(c.handle), uint64(ptr), uint64(len(str)))
2023-07-01 00:15:28 +01:00
c.free(ptr)
2023-06-30 12:25:07 +01:00
var code uint64
var ecode ErrorCode
var xcode xErrorCode
switch {
case errors.As(err, &xcode):
code = uint64(xcode)
case errors.As(err, &ecode):
code = uint64(ecode)
}
if code != 0 {
2023-07-01 00:15:28 +01:00
c.call(c.api.resultErrorCode,
2023-07-03 18:20:54 +01:00
uint64(c.handle), code)
2023-06-30 12:25:07 +01:00
}
}