value.go

  1package sqlite3
  2
  3import (
  4	"encoding/json"
  5	"math"
  6	"strconv"
  7	"time"
  8
  9	"github.com/ncruces/go-sqlite3/internal/util"
 10)
 11
 12// Value is any value that can be stored in a database table.
 13//
 14// https://sqlite.org/c3ref/value.html
 15type Value struct {
 16	c      *Conn
 17	handle ptr_t
 18	unprot bool
 19	copied bool
 20}
 21
 22func (v Value) protected() stk_t {
 23	if v.unprot {
 24		panic(util.ValueErr)
 25	}
 26	return stk_t(v.handle)
 27}
 28
 29// Dup makes a copy of the SQL value and returns a pointer to that copy.
 30//
 31// https://sqlite.org/c3ref/value_dup.html
 32func (v Value) Dup() *Value {
 33	ptr := ptr_t(v.c.call("sqlite3_value_dup", stk_t(v.handle)))
 34	return &Value{
 35		c:      v.c,
 36		copied: true,
 37		handle: ptr,
 38	}
 39}
 40
 41// Close frees an SQL value previously obtained by [Value.Dup].
 42//
 43// https://sqlite.org/c3ref/value_dup.html
 44func (dup *Value) Close() error {
 45	if !dup.copied {
 46		panic(util.ValueErr)
 47	}
 48	dup.c.call("sqlite3_value_free", stk_t(dup.handle))
 49	dup.handle = 0
 50	return nil
 51}
 52
 53// Type returns the initial datatype of the value.
 54//
 55// https://sqlite.org/c3ref/value_blob.html
 56func (v Value) Type() Datatype {
 57	return Datatype(v.c.call("sqlite3_value_type", v.protected()))
 58}
 59
 60// Type returns the numeric datatype of the value.
 61//
 62// https://sqlite.org/c3ref/value_blob.html
 63func (v Value) NumericType() Datatype {
 64	return Datatype(v.c.call("sqlite3_value_numeric_type", v.protected()))
 65}
 66
 67// Bool returns the value as a bool.
 68// SQLite does not have a separate boolean storage class.
 69// Instead, boolean values are retrieved as numbers,
 70// with 0 converted to false and any other value to true.
 71//
 72// https://sqlite.org/c3ref/value_blob.html
 73func (v Value) Bool() bool {
 74	return v.Float() != 0
 75}
 76
 77// Int returns the value as an int.
 78//
 79// https://sqlite.org/c3ref/value_blob.html
 80func (v Value) Int() int {
 81	return int(v.Int64())
 82}
 83
 84// Int64 returns the value as an int64.
 85//
 86// https://sqlite.org/c3ref/value_blob.html
 87func (v Value) Int64() int64 {
 88	return int64(v.c.call("sqlite3_value_int64", v.protected()))
 89}
 90
 91// Float returns the value as a float64.
 92//
 93// https://sqlite.org/c3ref/value_blob.html
 94func (v Value) Float() float64 {
 95	f := uint64(v.c.call("sqlite3_value_double", v.protected()))
 96	return math.Float64frombits(f)
 97}
 98
 99// Time returns the value as a [time.Time].
100//
101// https://sqlite.org/c3ref/value_blob.html
102func (v Value) Time(format TimeFormat) time.Time {
103	var a any
104	switch v.Type() {
105	case INTEGER:
106		a = v.Int64()
107	case FLOAT:
108		a = v.Float()
109	case TEXT, BLOB:
110		a = v.Text()
111	case NULL:
112		return time.Time{}
113	default:
114		panic(util.AssertErr())
115	}
116	t, _ := format.Decode(a)
117	return t
118}
119
120// Text returns the value as a string.
121//
122// https://sqlite.org/c3ref/value_blob.html
123func (v Value) Text() string {
124	return string(v.RawText())
125}
126
127// Blob appends to buf and returns
128// the value as a []byte.
129//
130// https://sqlite.org/c3ref/value_blob.html
131func (v Value) Blob(buf []byte) []byte {
132	return append(buf, v.RawBlob()...)
133}
134
135// RawText returns the value as a []byte.
136// The []byte is owned by SQLite and may be invalidated by
137// subsequent calls to [Value] methods.
138//
139// https://sqlite.org/c3ref/value_blob.html
140func (v Value) RawText() []byte {
141	ptr := ptr_t(v.c.call("sqlite3_value_text", v.protected()))
142	return v.rawBytes(ptr, 1)
143}
144
145// RawBlob returns the value as a []byte.
146// The []byte is owned by SQLite and may be invalidated by
147// subsequent calls to [Value] methods.
148//
149// https://sqlite.org/c3ref/value_blob.html
150func (v Value) RawBlob() []byte {
151	ptr := ptr_t(v.c.call("sqlite3_value_blob", v.protected()))
152	return v.rawBytes(ptr, 0)
153}
154
155func (v Value) rawBytes(ptr ptr_t, nul int32) []byte {
156	if ptr == 0 {
157		return nil
158	}
159
160	n := int32(v.c.call("sqlite3_value_bytes", v.protected()))
161	return util.View(v.c.mod, ptr, int64(n+nul))[:n]
162}
163
164// Pointer gets the pointer associated with this value,
165// or nil if it has no associated pointer.
166func (v Value) Pointer() any {
167	ptr := ptr_t(v.c.call("sqlite3_value_pointer_go", v.protected()))
168	return util.GetHandle(v.c.ctx, ptr)
169}
170
171// JSON parses a JSON-encoded value
172// and stores the result in the value pointed to by ptr.
173func (v Value) JSON(ptr any) error {
174	var data []byte
175	switch v.Type() {
176	case NULL:
177		data = []byte("null")
178	case TEXT:
179		data = v.RawText()
180	case BLOB:
181		data = v.RawBlob()
182	case INTEGER:
183		data = strconv.AppendInt(nil, v.Int64(), 10)
184	case FLOAT:
185		data = util.AppendNumber(nil, v.Float())
186	default:
187		panic(util.AssertErr())
188	}
189	return json.Unmarshal(data, ptr)
190}
191
192// NoChange returns true if and only if the value is unchanged
193// in a virtual table update operatiom.
194//
195// https://sqlite.org/c3ref/value_blob.html
196func (v Value) NoChange() bool {
197	b := int32(v.c.call("sqlite3_value_nochange", v.protected()))
198	return b != 0
199}
200
201// FromBind returns true if value originated from a bound parameter.
202//
203// https://sqlite.org/c3ref/value_blob.html
204func (v Value) FromBind() bool {
205	b := int32(v.c.call("sqlite3_value_frombind", v.protected()))
206	return b != 0
207}
208
209// InFirst returns the first element
210// on the right-hand side of an IN constraint.
211//
212// https://sqlite.org/c3ref/vtab_in_first.html
213func (v Value) InFirst() (Value, error) {
214	defer v.c.arena.mark()()
215	valPtr := v.c.arena.new(ptrlen)
216	rc := res_t(v.c.call("sqlite3_vtab_in_first", stk_t(v.handle), stk_t(valPtr)))
217	if err := v.c.error(rc); err != nil {
218		return Value{}, err
219	}
220	return Value{
221		c:      v.c,
222		handle: util.Read32[ptr_t](v.c.mod, valPtr),
223	}, nil
224}
225
226// InNext returns the next element
227// on the right-hand side of an IN constraint.
228//
229// https://sqlite.org/c3ref/vtab_in_first.html
230func (v Value) InNext() (Value, error) {
231	defer v.c.arena.mark()()
232	valPtr := v.c.arena.new(ptrlen)
233	rc := res_t(v.c.call("sqlite3_vtab_in_next", stk_t(v.handle), stk_t(valPtr)))
234	if err := v.c.error(rc); err != nil {
235		return Value{}, err
236	}
237	return Value{
238		c:      v.c,
239		handle: util.Read32[ptr_t](v.c.mod, valPtr),
240	}, nil
241}