mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Refactor.
This commit is contained in:
26
context.go
26
context.go
@@ -21,7 +21,7 @@ type Context struct {
|
||||
// Instead, boolean values are stored as integers 0 (false) and 1 (true).
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultBool(value bool) {
|
||||
func (c Context) ResultBool(value bool) {
|
||||
var i int64
|
||||
if value {
|
||||
i = 1
|
||||
@@ -32,14 +32,14 @@ func (c *Context) ResultBool(value bool) {
|
||||
// ResultInt sets the result of the function to an int.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultInt(value int) {
|
||||
func (c Context) ResultInt(value int) {
|
||||
c.ResultInt64(int64(value))
|
||||
}
|
||||
|
||||
// ResultInt64 sets the result of the function to an int64.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultInt64(value int64) {
|
||||
func (c Context) ResultInt64(value int64) {
|
||||
c.call(c.api.resultInteger,
|
||||
uint64(c.handle), uint64(value))
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (c *Context) ResultInt64(value int64) {
|
||||
// ResultFloat sets the result of the function to a float64.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultFloat(value float64) {
|
||||
func (c Context) ResultFloat(value float64) {
|
||||
c.call(c.api.resultFloat,
|
||||
uint64(c.handle), math.Float64bits(value))
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func (c *Context) ResultFloat(value float64) {
|
||||
// ResultText sets the result of the function to a string.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultText(value string) {
|
||||
func (c Context) ResultText(value string) {
|
||||
ptr := c.newString(value)
|
||||
c.call(c.api.resultText,
|
||||
uint64(c.handle), uint64(ptr), uint64(len(value)),
|
||||
@@ -66,7 +66,7 @@ func (c *Context) ResultText(value string) {
|
||||
// Returning a nil slice is the same as calling [Context.ResultNull].
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultBlob(value []byte) {
|
||||
func (c Context) ResultBlob(value []byte) {
|
||||
ptr := c.newBytes(value)
|
||||
c.call(c.api.resultBlob,
|
||||
uint64(c.handle), uint64(ptr), uint64(len(value)),
|
||||
@@ -76,7 +76,7 @@ func (c *Context) ResultBlob(value []byte) {
|
||||
// BindZeroBlob sets the result of the function to a zero-filled, length n BLOB.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultZeroBlob(n int64) {
|
||||
func (c Context) ResultZeroBlob(n int64) {
|
||||
c.call(c.api.resultZeroBlob,
|
||||
uint64(c.handle), uint64(n))
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func (c *Context) ResultZeroBlob(n int64) {
|
||||
// ResultNull sets the result of the function to NULL.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultNull() {
|
||||
func (c Context) ResultNull() {
|
||||
c.call(c.api.resultNull,
|
||||
uint64(c.handle))
|
||||
}
|
||||
@@ -92,7 +92,7 @@ func (c *Context) ResultNull() {
|
||||
// ResultTime sets the result of the function to a [time.Time].
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultTime(value time.Time, format TimeFormat) {
|
||||
func (c Context) ResultTime(value time.Time, format TimeFormat) {
|
||||
if format == TimeFormatDefault {
|
||||
c.resultRFC3339Nano(value)
|
||||
return
|
||||
@@ -109,7 +109,7 @@ func (c *Context) ResultTime(value time.Time, format TimeFormat) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) resultRFC3339Nano(value time.Time) {
|
||||
func (c Context) resultRFC3339Nano(value time.Time) {
|
||||
const maxlen = uint64(len(time.RFC3339Nano))
|
||||
|
||||
ptr := c.new(maxlen)
|
||||
@@ -124,7 +124,7 @@ func (c *Context) resultRFC3339Nano(value time.Time) {
|
||||
// ResultError sets the result of the function an error.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/result_blob.html
|
||||
func (c *Context) ResultError(err error) {
|
||||
func (c Context) ResultError(err error) {
|
||||
if errors.Is(err, NOMEM) {
|
||||
c.call(c.api.resultErrorMem, uint64(c.handle))
|
||||
return
|
||||
@@ -137,7 +137,7 @@ func (c *Context) ResultError(err error) {
|
||||
|
||||
str := err.Error()
|
||||
ptr := c.newString(str)
|
||||
c.call(c.api.resultBlob,
|
||||
c.call(c.api.resultError,
|
||||
uint64(c.handle), uint64(ptr), uint64(len(str)))
|
||||
c.free(ptr)
|
||||
|
||||
@@ -152,6 +152,6 @@ func (c *Context) ResultError(err error) {
|
||||
}
|
||||
if code != 0 {
|
||||
c.call(c.api.resultErrorCode,
|
||||
uint64(c.handle), uint64(xcode))
|
||||
uint64(c.handle), uint64(code))
|
||||
}
|
||||
}
|
||||
|
||||
55
func.go
55
func.go
@@ -56,8 +56,12 @@ func (c *Conn) CreateWindowFunction(name string, nArg int, flag FunctionFlag, fn
|
||||
//
|
||||
// https://www.sqlite.org/appfunc.html
|
||||
type AggregateFunction interface {
|
||||
// Step is invoked to add a row to the current window.
|
||||
// The function arguments, if any, corresponding to the row being added are passed to Step.
|
||||
Step(ctx Context, arg ...Value)
|
||||
Final(ctx Context)
|
||||
|
||||
// Value is invoked to return the current value of the aggregate.
|
||||
Value(ctx Context)
|
||||
}
|
||||
|
||||
// WindowFunction is the interface an aggregate window function should implement.
|
||||
@@ -65,7 +69,9 @@ type AggregateFunction interface {
|
||||
// https://www.sqlite.org/windowfunctions.html
|
||||
type WindowFunction interface {
|
||||
AggregateFunction
|
||||
Value(ctx Context)
|
||||
|
||||
// Inverse is invoked to remove the oldest presently aggregated result of Step from the current window.
|
||||
// The function arguments, if any, are those passed to Step for the row being removed.
|
||||
Inverse(ctx Context, arg ...Value)
|
||||
}
|
||||
|
||||
@@ -92,48 +98,35 @@ func callbackCompare(ctx context.Context, mod api.Module, pApp, nKey1, pKey1, nK
|
||||
func callbackFunc(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
|
||||
module := ctx.Value(moduleKey{}).(*module)
|
||||
fn := callbackHandle(module, pCtx).(func(ctx Context, arg ...Value))
|
||||
fn(Context{
|
||||
module: module,
|
||||
handle: pCtx,
|
||||
}, callbackArgs(module, nArg, pArg)...)
|
||||
fn(Context{module, pCtx}, callbackArgs(module, nArg, pArg)...)
|
||||
}
|
||||
|
||||
func callbackStep(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
|
||||
module := ctx.Value(moduleKey{}).(*module)
|
||||
fn := callbackAggregate(module, pCtx, nil).(AggregateFunction)
|
||||
fn.Step(Context{
|
||||
module: module,
|
||||
handle: pCtx,
|
||||
}, callbackArgs(module, nArg, pArg)...)
|
||||
fn.Step(Context{module, pCtx}, callbackArgs(module, nArg, pArg)...)
|
||||
}
|
||||
|
||||
func callbackFinal(ctx context.Context, mod api.Module, pCtx uint32) {
|
||||
var handle uint32
|
||||
module := ctx.Value(moduleKey{}).(*module)
|
||||
fn := callbackAggregate(module, pCtx, &handle).(AggregateFunction)
|
||||
fn.Final(Context{
|
||||
module: module,
|
||||
handle: pCtx,
|
||||
})
|
||||
util.DelHandle(ctx, handle)
|
||||
fn.Value(Context{module, pCtx})
|
||||
if err := util.DelHandle(ctx, handle); err != nil {
|
||||
Context{module, pCtx}.ResultError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func callbackValue(ctx context.Context, mod api.Module, pCtx uint32) {
|
||||
module := ctx.Value(moduleKey{}).(*module)
|
||||
fn := callbackAggregate(module, pCtx, nil).(WindowFunction)
|
||||
fn.Value(Context{
|
||||
module: module,
|
||||
handle: pCtx,
|
||||
})
|
||||
fn := callbackAggregate(module, pCtx, nil).(AggregateFunction)
|
||||
fn.Value(Context{module, pCtx})
|
||||
}
|
||||
|
||||
func callbackInverse(ctx context.Context, mod api.Module, pCtx, nArg, pArg uint32) {
|
||||
module := ctx.Value(moduleKey{}).(*module)
|
||||
fn := callbackAggregate(module, pCtx, nil).(WindowFunction)
|
||||
fn.Inverse(Context{
|
||||
module: module,
|
||||
handle: pCtx,
|
||||
}, callbackArgs(module, nArg, pArg)...)
|
||||
fn.Inverse(Context{module, pCtx}, callbackArgs(module, nArg, pArg)...)
|
||||
}
|
||||
|
||||
func callbackHandle(module *module, pCtx uint32) any {
|
||||
@@ -141,18 +134,21 @@ func callbackHandle(module *module, pCtx uint32) any {
|
||||
return util.GetHandle(module.ctx, pApp)
|
||||
}
|
||||
|
||||
func callbackAggregate(module *module, pCtx uint32, delete *uint32) any {
|
||||
func callbackAggregate(module *module, pCtx uint32, close *uint32) any {
|
||||
// On close, we're getting rid of the handle.
|
||||
// Don't allocate space to store it.
|
||||
var size uint64
|
||||
if delete == nil {
|
||||
if close == nil {
|
||||
size = ptrlen
|
||||
}
|
||||
ptr := uint32(module.call(module.api.aggregateCtx, uint64(pCtx), size))
|
||||
|
||||
if ptr != 0 {
|
||||
// Try loading the handle, if we already have one, or want a new one.
|
||||
if ptr != 0 || size != 0 {
|
||||
if handle := util.ReadUint32(module.mod, ptr); handle != 0 {
|
||||
fn := util.GetHandle(module.ctx, handle)
|
||||
if delete != nil {
|
||||
*delete = handle
|
||||
if close != nil {
|
||||
*close = handle
|
||||
}
|
||||
if fn != nil {
|
||||
return fn
|
||||
@@ -160,6 +156,7 @@ func callbackAggregate(module *module, pCtx uint32, delete *uint32) any {
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new aggregate and store the handle.
|
||||
fn := callbackHandle(module, pCtx).(func() AggregateFunction)()
|
||||
if ptr != 0 {
|
||||
util.WriteUint32(module.mod, ptr, util.AddHandle(module.ctx, fn))
|
||||
|
||||
@@ -61,18 +61,12 @@ func ExampleConn_CreateWindowFunction() {
|
||||
// 0
|
||||
}
|
||||
|
||||
type countASCII struct {
|
||||
result int
|
||||
}
|
||||
type countASCII struct{ result int }
|
||||
|
||||
func newASCIICounter() sqlite3.AggregateFunction {
|
||||
return &countASCII{}
|
||||
}
|
||||
|
||||
func (f *countASCII) Final(ctx sqlite3.Context) {
|
||||
f.Value(ctx)
|
||||
}
|
||||
|
||||
func (f *countASCII) Value(ctx sqlite3.Context) {
|
||||
ctx.ResultInt(f.result)
|
||||
}
|
||||
|
||||
22
value.go
22
value.go
@@ -18,7 +18,7 @@ type Value struct {
|
||||
// Type returns the initial [Datatype] of the value.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) Type() Datatype {
|
||||
func (v Value) Type() Datatype {
|
||||
r := v.call(v.api.valueType, uint64(v.handle))
|
||||
return Datatype(r)
|
||||
}
|
||||
@@ -29,7 +29,7 @@ func (v *Value) Type() Datatype {
|
||||
// with 0 converted to false and any other value to true.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) Bool() bool {
|
||||
func (v Value) Bool() bool {
|
||||
if i := v.Int64(); i != 0 {
|
||||
return true
|
||||
}
|
||||
@@ -39,14 +39,14 @@ func (v *Value) Bool() bool {
|
||||
// Int returns the value as an int.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) Int() int {
|
||||
func (v Value) Int() int {
|
||||
return int(v.Int64())
|
||||
}
|
||||
|
||||
// Int64 returns the value as an int64.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) Int64() int64 {
|
||||
func (v Value) Int64() int64 {
|
||||
r := v.call(v.api.valueInteger, uint64(v.handle))
|
||||
return int64(r)
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func (v *Value) Int64() int64 {
|
||||
// Float returns the value as a float64.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) Float() float64 {
|
||||
func (v Value) Float() float64 {
|
||||
r := v.call(v.api.valueFloat, uint64(v.handle))
|
||||
return math.Float64frombits(r)
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func (v *Value) Float() float64 {
|
||||
// Time returns the value as a [time.Time].
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) Time(format TimeFormat) time.Time {
|
||||
func (v Value) Time(format TimeFormat) time.Time {
|
||||
var a any
|
||||
switch v.Type() {
|
||||
case INTEGER:
|
||||
@@ -83,7 +83,7 @@ func (v *Value) Time(format TimeFormat) time.Time {
|
||||
// Text returns the value as a string.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) Text() string {
|
||||
func (v Value) Text() string {
|
||||
return string(v.RawText())
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ func (v *Value) Text() string {
|
||||
// the value as a []byte.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) Blob(buf []byte) []byte {
|
||||
func (v Value) Blob(buf []byte) []byte {
|
||||
return append(buf, v.RawBlob()...)
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func (v *Value) Blob(buf []byte) []byte {
|
||||
// subsequent calls to [Value] methods.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) RawText() []byte {
|
||||
func (v Value) RawText() []byte {
|
||||
r := v.call(v.api.valueText, uint64(v.handle))
|
||||
return v.rawBytes(uint32(r))
|
||||
}
|
||||
@@ -110,12 +110,12 @@ func (v *Value) RawText() []byte {
|
||||
// subsequent calls to [Value] methods.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/value_blob.html
|
||||
func (v *Value) RawBlob() []byte {
|
||||
func (v Value) RawBlob() []byte {
|
||||
r := v.call(v.api.valueBlob, uint64(v.handle))
|
||||
return v.rawBytes(uint32(r))
|
||||
}
|
||||
|
||||
func (v *Value) rawBytes(ptr uint32) []byte {
|
||||
func (v Value) rawBytes(ptr uint32) []byte {
|
||||
if ptr == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type VFS interface {
|
||||
FullPathname(name string) (string, error)
|
||||
}
|
||||
|
||||
// VFSParams extends VFS to with the ability to handle URI parameters
|
||||
// VFSParams extends VFS with the ability to handle URI parameters
|
||||
// through the OpenParams method.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/uri_boolean.html
|
||||
|
||||
Reference in New Issue
Block a user