Files
sqlite3/stmt.go

757 lines
20 KiB
Go
Raw Normal View History

2023-01-15 04:35:37 +00:00
package sqlite3
2023-01-17 13:43:16 +00:00
import (
2023-10-13 17:06:05 +01:00
"encoding/json"
2023-01-17 13:43:16 +00:00
"math"
2023-10-13 17:06:05 +01:00
"strconv"
2023-02-21 04:30:24 +00:00
"time"
2023-03-29 15:01:25 +01:00
"github.com/ncruces/go-sqlite3/internal/util"
2023-01-17 13:43:16 +00:00
)
2023-01-15 04:35:37 +00:00
2023-02-10 14:14:19 +00:00
// Stmt is a prepared statement object.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/stmt.html
2023-01-15 04:35:37 +00:00
type Stmt struct {
c *Conn
2023-01-21 00:33:46 +00:00
err error
sql string
2025-01-21 01:42:57 +00:00
handle ptr_t
2023-01-15 04:35:37 +00:00
}
2023-02-10 14:14:19 +00:00
// Close destroys the prepared statement object.
//
2023-03-01 10:34:08 +00:00
// It is safe to close a nil, zero or closed Stmt.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/finalize.html
2023-01-15 04:35:37 +00:00
func (s *Stmt) Close() error {
2023-02-16 13:52:05 +00:00
if s == nil || s.handle == 0 {
2023-02-10 14:14:19 +00:00
return nil
}
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_finalize", stk_t(s.handle)))
2024-09-30 11:03:50 +01:00
stmts := s.c.stmts
for i := range stmts {
if s == stmts[i] {
l := len(stmts) - 1
stmts[i] = stmts[l]
stmts[l] = nil
s.c.stmts = stmts[:l]
break
}
}
2023-01-15 04:35:37 +00:00
s.handle = 0
2025-01-21 01:42:57 +00:00
return s.c.error(rc)
2023-01-17 13:43:16 +00:00
}
2023-12-04 12:37:53 +00:00
// Conn returns the database connection to which the prepared statement belongs.
//
// https://sqlite.org/c3ref/db_handle.html
func (s *Stmt) Conn() *Conn {
return s.c
}
// SQL returns the SQL text used to create the prepared statement.
//
// https://sqlite.org/c3ref/expanded_sql.html
func (s *Stmt) SQL() string {
return s.sql
}
// ExpandedSQL returns the SQL text of the prepared statement
// with bound parameters expanded.
//
// https://sqlite.org/c3ref/expanded_sql.html
func (s *Stmt) ExpandedSQL() string {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_expanded_sql", stk_t(s.handle)))
sql := util.ReadString(s.c.mod, ptr, _MAX_SQL_LENGTH)
s.c.free(ptr)
return sql
}
2023-12-04 12:37:53 +00:00
// ReadOnly returns true if and only if the statement
// makes no direct changes to the content of the database file.
//
// https://sqlite.org/c3ref/stmt_readonly.html
func (s *Stmt) ReadOnly() bool {
2025-01-21 01:42:57 +00:00
b := int32(s.c.call("sqlite3_stmt_readonly", stk_t(s.handle)))
return b != 0
2023-12-04 12:37:53 +00:00
}
2023-02-10 14:14:19 +00:00
// Reset resets the prepared statement object.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/reset.html
2023-01-17 15:01:30 +00:00
func (s *Stmt) Reset() error {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_reset", stk_t(s.handle)))
2023-02-10 14:14:19 +00:00
s.err = nil
2025-01-21 01:42:57 +00:00
return s.c.error(rc)
2023-01-17 15:01:30 +00:00
}
2023-12-04 12:37:53 +00:00
// Busy determines if a prepared statement has been reset.
2023-02-10 14:14:19 +00:00
//
2023-12-04 12:37:53 +00:00
// https://sqlite.org/c3ref/stmt_busy.html
func (s *Stmt) Busy() bool {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_stmt_busy", stk_t(s.handle)))
return rc != 0
2023-02-10 14:14:19 +00:00
}
// Step evaluates the SQL statement.
// If the SQL statement being executed returns any data,
// then true is returned each time a new row of data is ready for processing by the caller.
// The values may be accessed using the Column access functions.
// Step is called again to retrieve the next row of data.
// If an error has occurred, Step returns false;
// call [Stmt.Err] or [Stmt.Reset] to get the error.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/step.html
2023-01-21 00:33:46 +00:00
func (s *Stmt) Step() bool {
2025-03-26 11:39:06 +00:00
if s.c.interrupt.Err() != nil {
s.err = INTERRUPT
return false
}
2025-03-26 19:02:14 +00:00
return s.step()
}
2025-03-26 11:39:06 +00:00
2025-03-26 19:02:14 +00:00
func (s *Stmt) step() bool {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_step", stk_t(s.handle)))
switch rc {
2023-08-10 13:18:13 +01:00
case _ROW:
2023-12-06 15:39:26 +00:00
s.err = nil
2023-01-21 00:33:46 +00:00
return true
2023-08-10 13:18:13 +01:00
case _DONE:
2023-01-21 00:33:46 +00:00
s.err = nil
2023-08-10 13:18:13 +01:00
default:
2025-01-21 01:42:57 +00:00
s.err = s.c.error(rc)
2023-01-17 15:01:30 +00:00
}
2023-01-21 00:33:46 +00:00
return false
}
2023-02-10 14:14:19 +00:00
// Err gets the last error occurred during [Stmt.Step].
// Err returns nil after [Stmt.Reset] is called.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/step.html
2023-01-21 00:33:46 +00:00
func (s *Stmt) Err() error {
return s.err
2023-01-17 15:01:30 +00:00
}
2023-02-10 14:14:19 +00:00
// Exec is a convenience function that repeatedly calls [Stmt.Step] until it returns false,
// then calls [Stmt.Reset] to reset the statement and get any error that occurred.
2023-02-08 00:00:53 +00:00
func (s *Stmt) Exec() error {
2025-03-26 19:02:14 +00:00
if s.c.interrupt.Err() != nil {
return INTERRUPT
}
// TODO: implement this in C.
for s.step() {
2023-02-08 00:00:53 +00:00
}
2023-02-10 14:14:19 +00:00
return s.Reset()
2023-02-08 00:00:53 +00:00
}
2023-12-04 12:37:53 +00:00
// Status monitors the performance characteristics of prepared statements.
2023-12-01 02:38:56 +00:00
//
2023-12-04 12:37:53 +00:00
// https://sqlite.org/c3ref/stmt_status.html
func (s *Stmt) Status(op StmtStatus, reset bool) int {
2024-01-18 15:53:00 +00:00
if op > STMTSTATUS_FILTER_HIT && op != STMTSTATUS_MEMUSED {
return 0
}
2025-01-21 01:42:57 +00:00
var i int32
2023-12-04 12:37:53 +00:00
if reset {
i = 1
}
2025-01-21 01:42:57 +00:00
n := int32(s.c.call("sqlite3_stmt_status", stk_t(s.handle),
stk_t(op), stk_t(i)))
return int(n)
2023-12-04 12:37:53 +00:00
}
// ClearBindings resets all bindings on the prepared statement.
//
// https://sqlite.org/c3ref/clear_bindings.html
func (s *Stmt) ClearBindings() error {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_clear_bindings", stk_t(s.handle)))
return s.c.error(rc)
2023-12-01 02:38:56 +00:00
}
2023-02-18 00:47:56 +00:00
// BindCount returns the number of SQL parameters in the prepared statement.
2023-02-14 18:21:18 +00:00
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_parameter_count.html
2023-02-14 18:21:18 +00:00
func (s *Stmt) BindCount() int {
2025-01-21 01:42:57 +00:00
n := int32(s.c.call("sqlite3_bind_parameter_count",
stk_t(s.handle)))
return int(n)
2023-02-14 18:21:18 +00:00
}
2023-02-18 00:47:56 +00:00
// BindIndex returns the index of a parameter in the prepared statement
// given its name.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_parameter_index.html
2023-02-18 00:47:56 +00:00
func (s *Stmt) BindIndex(name string) int {
2023-11-29 10:38:03 +00:00
defer s.c.arena.mark()()
2023-02-18 00:47:56 +00:00
namePtr := s.c.arena.string(name)
2025-01-21 01:42:57 +00:00
i := int32(s.c.call("sqlite3_bind_parameter_index",
stk_t(s.handle), stk_t(namePtr)))
return int(i)
2023-02-18 00:47:56 +00:00
}
// BindName returns the name of a parameter in the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_parameter_name.html
2023-02-18 00:47:56 +00:00
func (s *Stmt) BindName(param int) string {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_bind_parameter_name",
stk_t(s.handle), stk_t(param)))
2023-02-18 00:47:56 +00:00
if ptr == 0 {
return ""
}
2023-11-24 17:25:02 +00:00
return util.ReadString(s.c.mod, ptr, _MAX_NAME)
2023-02-18 00:47:56 +00:00
}
2023-02-10 14:14:19 +00:00
// BindBool binds a bool to the prepared statement.
// The leftmost SQL parameter has an index of 1.
// 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/bind_blob.html
2023-01-17 13:43:16 +00:00
func (s *Stmt) BindBool(param int, value bool) error {
2023-06-30 11:48:54 +01:00
var i int64
2023-01-17 13:43:16 +00:00
if value {
2023-06-30 11:48:54 +01:00
i = 1
2023-01-17 13:43:16 +00:00
}
2023-06-30 11:48:54 +01:00
return s.BindInt64(param, i)
2023-01-17 13:43:16 +00:00
}
2023-02-10 14:14:19 +00:00
// BindInt binds an int to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-01-17 13:43:16 +00:00
func (s *Stmt) BindInt(param int, value int) error {
return s.BindInt64(param, int64(value))
}
2023-02-10 14:14:19 +00:00
// BindInt64 binds an int64 to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-01-17 13:43:16 +00:00
func (s *Stmt) BindInt64(param int, value int64) error {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_int64",
stk_t(s.handle), stk_t(param), stk_t(value)))
return s.c.error(rc)
2023-01-17 13:43:16 +00:00
}
2023-02-10 14:14:19 +00:00
// BindFloat binds a float64 to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-01-17 13:43:16 +00:00
func (s *Stmt) BindFloat(param int, value float64) error {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_double",
stk_t(s.handle), stk_t(param),
stk_t(math.Float64bits(value))))
return s.c.error(rc)
2023-01-17 13:43:16 +00:00
}
2023-02-10 14:14:19 +00:00
// BindText binds a string to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-01-17 13:43:16 +00:00
func (s *Stmt) BindText(param int, value string) error {
2023-11-24 17:25:02 +00:00
if len(value) > _MAX_LENGTH {
return TOOBIG
}
2023-01-17 13:43:16 +00:00
ptr := s.c.newString(value)
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_text_go",
stk_t(s.handle), stk_t(param),
stk_t(ptr), stk_t(len(value))))
return s.c.error(rc)
2023-01-17 13:43:16 +00:00
}
2023-11-10 13:42:11 +00:00
// BindRawText binds a []byte to the prepared statement as text.
// The leftmost SQL parameter has an index of 1.
//
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindRawText(param int, value []byte) error {
2023-11-24 17:25:02 +00:00
if len(value) > _MAX_LENGTH {
return TOOBIG
}
2025-03-31 16:33:31 +01:00
if len(value) == 0 {
return s.BindText(param, "")
}
2023-11-10 13:42:11 +00:00
ptr := s.c.newBytes(value)
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_text_go",
stk_t(s.handle), stk_t(param),
stk_t(ptr), stk_t(len(value))))
return s.c.error(rc)
2023-11-10 13:42:11 +00:00
}
2023-02-10 14:14:19 +00:00
// BindBlob binds a []byte to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-01-17 13:43:16 +00:00
func (s *Stmt) BindBlob(param int, value []byte) error {
2023-11-24 17:25:02 +00:00
if len(value) > _MAX_LENGTH {
return TOOBIG
}
2025-03-31 16:33:31 +01:00
if len(value) == 0 {
return s.BindZeroBlob(param, 0)
}
2023-01-17 13:43:16 +00:00
ptr := s.c.newBytes(value)
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_blob_go",
stk_t(s.handle), stk_t(param),
stk_t(ptr), stk_t(len(value))))
return s.c.error(rc)
2023-01-17 13:43:16 +00:00
}
2023-02-22 14:19:56 +00:00
// BindZeroBlob binds a zero-filled, length n BLOB to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-02-22 14:19:56 +00:00
func (s *Stmt) BindZeroBlob(param int, n int64) error {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_zeroblob64",
stk_t(s.handle), stk_t(param), stk_t(n)))
return s.c.error(rc)
2023-02-22 14:19:56 +00:00
}
2023-02-10 14:14:19 +00:00
// BindNull binds a NULL to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-01-17 13:43:16 +00:00
func (s *Stmt) BindNull(param int) error {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_null",
stk_t(s.handle), stk_t(param)))
return s.c.error(rc)
2023-01-15 04:35:37 +00:00
}
2023-01-17 18:31:46 +00:00
2023-02-21 04:30:24 +00:00
// BindTime binds a [time.Time] to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-02-21 04:30:24 +00:00
func (s *Stmt) BindTime(param int, value time.Time, format TimeFormat) error {
switch format {
case TimeFormatDefault, TimeFormatAuto, time.RFC3339Nano:
2023-04-18 01:00:59 +01:00
return s.bindRFC3339Nano(param, value)
}
2023-02-21 04:30:24 +00:00
switch v := format.Encode(value).(type) {
case string:
2025-01-17 14:40:12 +00:00
return s.BindText(param, v)
2023-02-21 04:30:24 +00:00
case int64:
2025-01-17 14:40:12 +00:00
return s.BindInt64(param, v)
2023-02-21 04:30:24 +00:00
case float64:
2025-01-17 14:40:12 +00:00
return s.BindFloat(param, v)
2023-02-21 04:30:24 +00:00
default:
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-02-21 04:30:24 +00:00
}
}
2023-04-18 01:00:59 +01:00
func (s *Stmt) bindRFC3339Nano(param int, value time.Time) error {
2025-01-21 01:42:57 +00:00
const maxlen = int64(len(time.RFC3339Nano)) + 5
2023-04-18 01:00:59 +01:00
ptr := s.c.new(maxlen)
buf := util.View(s.c.mod, ptr, maxlen)
buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_text_go",
stk_t(s.handle), stk_t(param),
stk_t(ptr), stk_t(len(buf))))
return s.c.error(rc)
2023-04-18 01:00:59 +01:00
}
2023-11-07 00:50:43 +00:00
// BindPointer binds a NULL to the prepared statement, just like [Stmt.BindNull],
// but 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-20 13:37:25 +00:00
// The leftmost SQL parameter has an index of 1.
2023-11-07 00:50:43 +00:00
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-11-07 00:50:43 +00:00
func (s *Stmt) BindPointer(param int, ptr any) error {
valPtr := util.AddHandle(s.c.ctx, ptr)
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_pointer_go",
stk_t(s.handle), stk_t(param), stk_t(valPtr)))
return s.c.error(rc)
2023-11-07 00:50:43 +00:00
}
2023-10-13 17:06:05 +01:00
// BindJSON binds the JSON encoding of value to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/bind_blob.html
2023-10-13 17:06:05 +01:00
func (s *Stmt) BindJSON(param int, value any) error {
data, err := json.Marshal(value)
if err != nil {
return err
}
2023-11-10 13:42:11 +00:00
return s.BindRawText(param, data)
2023-10-13 17:06:05 +01:00
}
2023-11-29 16:09:30 +00:00
// BindValue binds a copy of value to the prepared statement.
// The leftmost SQL parameter has an index of 1.
//
// https://sqlite.org/c3ref/bind_blob.html
func (s *Stmt) BindValue(param int, value Value) error {
2024-01-08 19:23:32 +00:00
if value.c != s.c {
2023-11-29 16:09:30 +00:00
return MISUSE
}
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_bind_value",
stk_t(s.handle), stk_t(param), stk_t(value.handle)))
return s.c.error(rc)
2023-11-29 16:09:30 +00:00
}
2024-10-04 13:31:53 +01:00
// DataCount resets the number of columns in a result set.
//
2024-10-07 14:42:09 +01:00
// https://sqlite.org/c3ref/data_count.html
2024-10-04 13:31:53 +01:00
func (s *Stmt) DataCount() int {
2025-01-21 01:42:57 +00:00
n := int32(s.c.call("sqlite3_data_count",
stk_t(s.handle)))
return int(n)
2024-10-04 13:31:53 +01:00
}
2023-02-17 02:21:07 +00:00
// ColumnCount returns the number of columns in a result set.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_count.html
2023-02-17 02:21:07 +00:00
func (s *Stmt) ColumnCount() int {
2025-01-21 01:42:57 +00:00
n := int32(s.c.call("sqlite3_column_count",
stk_t(s.handle)))
return int(n)
2023-02-17 02:21:07 +00:00
}
// ColumnName returns the name of the result column.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_name.html
2023-02-17 02:21:07 +00:00
func (s *Stmt) ColumnName(col int) string {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_column_name",
stk_t(s.handle), stk_t(col)))
if ptr == 0 {
2023-03-29 15:01:25 +01:00
panic(util.OOMErr)
2023-02-17 02:21:07 +00:00
}
2025-01-21 01:42:57 +00:00
return util.ReadString(s.c.mod, ptr, _MAX_NAME)
2023-02-17 02:21:07 +00:00
}
2023-02-10 14:14:19 +00:00
// ColumnType returns the initial [Datatype] of the result column.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-02-08 00:00:53 +00:00
func (s *Stmt) ColumnType(col int) Datatype {
2025-01-21 01:42:57 +00:00
return Datatype(s.c.call("sqlite3_column_type",
stk_t(s.handle), stk_t(col)))
2023-02-08 00:00:53 +00:00
}
2023-12-01 02:38:56 +00:00
// ColumnDeclType returns the declared datatype of the result column.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_decltype.html
func (s *Stmt) ColumnDeclType(col int) string {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_column_decltype",
stk_t(s.handle), stk_t(col)))
if ptr == 0 {
2023-12-01 02:38:56 +00:00
return ""
}
2025-01-21 01:42:57 +00:00
return util.ReadString(s.c.mod, ptr, _MAX_NAME)
2023-12-01 02:38:56 +00:00
}
2024-05-24 11:27:03 +01:00
// ColumnDatabaseName returns the name of the database
// that is the origin of a particular result column.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_database_name.html
func (s *Stmt) ColumnDatabaseName(col int) string {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_column_database_name",
stk_t(s.handle), stk_t(col)))
if ptr == 0 {
2024-05-24 11:27:03 +01:00
return ""
}
2025-01-21 01:42:57 +00:00
return util.ReadString(s.c.mod, ptr, _MAX_NAME)
2024-05-24 11:27:03 +01:00
}
// ColumnTableName returns the name of the table
// that is the origin of a particular result column.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_database_name.html
func (s *Stmt) ColumnTableName(col int) string {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_column_table_name",
stk_t(s.handle), stk_t(col)))
if ptr == 0 {
2024-05-24 11:27:03 +01:00
return ""
}
2025-01-21 01:42:57 +00:00
return util.ReadString(s.c.mod, ptr, _MAX_NAME)
2024-05-24 11:27:03 +01:00
}
// ColumnOriginName returns the name of the table column
// that is the origin of a particular result column.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_database_name.html
func (s *Stmt) ColumnOriginName(col int) string {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_column_origin_name",
stk_t(s.handle), stk_t(col)))
if ptr == 0 {
2024-05-24 11:27:03 +01:00
return ""
}
2025-01-21 01:42:57 +00:00
return util.ReadString(s.c.mod, ptr, _MAX_NAME)
2024-05-24 11:27:03 +01:00
}
2023-02-10 14:14:19 +00:00
// ColumnBool returns the value of the result column as a bool.
// The leftmost column of the result set has the index 0.
// SQLite does not have a separate boolean storage class.
2024-06-06 16:41:20 +01:00
// Instead, boolean values are retrieved as numbers,
2023-02-10 14:14:19 +00:00
// with 0 converted to false and any other value to true.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-01-17 18:31:46 +00:00
func (s *Stmt) ColumnBool(col int) bool {
2024-06-06 16:41:20 +01:00
return s.ColumnFloat(col) != 0
2023-01-17 18:31:46 +00:00
}
2023-02-10 14:14:19 +00:00
// ColumnInt returns the value of the result column as an int.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-01-17 18:31:46 +00:00
func (s *Stmt) ColumnInt(col int) int {
return int(s.ColumnInt64(col))
}
2023-02-10 14:14:19 +00:00
// ColumnInt64 returns the value of the result column as an int64.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-01-17 18:31:46 +00:00
func (s *Stmt) ColumnInt64(col int) int64 {
2025-01-21 01:42:57 +00:00
return int64(s.c.call("sqlite3_column_int64",
stk_t(s.handle), stk_t(col)))
2023-01-17 18:31:46 +00:00
}
2023-02-10 14:14:19 +00:00
// ColumnFloat returns the value of the result column as a float64.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-01-17 18:31:46 +00:00
func (s *Stmt) ColumnFloat(col int) float64 {
2025-01-21 01:42:57 +00:00
f := uint64(s.c.call("sqlite3_column_double",
stk_t(s.handle), stk_t(col)))
return math.Float64frombits(f)
2023-01-17 18:31:46 +00:00
}
2023-02-21 04:30:24 +00:00
// ColumnTime returns the value of the result column as a [time.Time].
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-02-21 04:30:24 +00:00
func (s *Stmt) ColumnTime(col int, format TimeFormat) time.Time {
var v any
switch s.ColumnType(col) {
case INTEGER:
v = s.ColumnInt64(col)
case FLOAT:
v = s.ColumnFloat(col)
case TEXT, BLOB:
v = s.ColumnText(col)
case NULL:
return time.Time{}
default:
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-02-21 04:30:24 +00:00
}
t, err := format.Decode(v)
if err != nil {
s.err = err
}
return t
}
2023-02-10 14:14:19 +00:00
// ColumnText returns the value of the result column as a string.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-01-17 18:31:46 +00:00
func (s *Stmt) ColumnText(col int) string {
2023-03-20 02:16:42 +00:00
return string(s.ColumnRawText(col))
}
// ColumnBlob appends to buf and returns
// the value of the result column as a []byte.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-03-20 02:16:42 +00:00
func (s *Stmt) ColumnBlob(col int, buf []byte) []byte {
return append(buf, s.ColumnRawBlob(col)...)
}
// ColumnRawText returns the value of the result column as a []byte.
// The []byte is owned by SQLite and may be invalidated by
// subsequent calls to [Stmt] methods.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-03-20 02:16:42 +00:00
func (s *Stmt) ColumnRawText(col int) []byte {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_column_text",
stk_t(s.handle), stk_t(col)))
2025-03-31 13:02:41 +01:00
return s.columnRawBytes(col, ptr, 1)
2023-01-17 18:31:46 +00:00
}
2023-03-20 02:16:42 +00:00
// ColumnRawBlob returns the value of the result column as a []byte.
// The []byte is owned by SQLite and may be invalidated by
// subsequent calls to [Stmt] methods.
2023-02-10 14:14:19 +00:00
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-03-20 02:16:42 +00:00
func (s *Stmt) ColumnRawBlob(col int) []byte {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_column_blob",
stk_t(s.handle), stk_t(col)))
2025-03-31 13:02:41 +01:00
return s.columnRawBytes(col, ptr, 0)
2023-06-30 10:45:16 +01:00
}
2023-01-17 18:31:46 +00:00
2025-03-31 13:02:41 +01:00
func (s *Stmt) columnRawBytes(col int, ptr ptr_t, nul int32) []byte {
2023-01-17 18:31:46 +00:00
if ptr == 0 {
2025-01-21 01:42:57 +00:00
rc := res_t(s.c.call("sqlite3_errcode", stk_t(s.c.handle)))
if rc != _ROW && rc != _DONE {
s.err = s.c.error(rc)
2024-12-10 18:25:49 +00:00
}
2023-03-20 02:16:42 +00:00
return nil
2023-01-17 18:31:46 +00:00
}
2025-01-21 01:42:57 +00:00
n := int32(s.c.call("sqlite3_column_bytes",
stk_t(s.handle), stk_t(col)))
2025-03-31 13:02:41 +01:00
return util.View(s.c.mod, ptr, int64(n+nul))[:n]
2023-01-17 18:31:46 +00:00
}
2023-02-24 15:06:19 +00:00
2023-10-13 17:06:05 +01:00
// ColumnJSON parses the JSON-encoded value of the result column
// and stores it in the value pointed to by ptr.
// The leftmost column of the result set has the index 0.
//
2023-11-09 16:35:45 +00:00
// https://sqlite.org/c3ref/column_blob.html
2023-10-13 17:06:05 +01:00
func (s *Stmt) ColumnJSON(col int, ptr any) error {
var data []byte
switch s.ColumnType(col) {
case NULL:
2024-06-11 22:57:29 +01:00
data = []byte("null")
2023-10-19 16:46:58 +01:00
case TEXT:
data = s.ColumnRawText(col)
case BLOB:
2023-10-13 17:06:05 +01:00
data = s.ColumnRawBlob(col)
case INTEGER:
data = strconv.AppendInt(nil, s.ColumnInt64(col), 10)
case FLOAT:
2025-01-20 14:39:36 +00:00
data = util.AppendNumber(nil, s.ColumnFloat(col))
2023-10-13 17:06:05 +01:00
default:
panic(util.AssertErr())
}
return json.Unmarshal(data, ptr)
}
2023-11-29 16:09:30 +00:00
// ColumnValue returns the unprotected value of the result column.
// The leftmost column of the result set has the index 0.
//
// https://sqlite.org/c3ref/column_blob.html
func (s *Stmt) ColumnValue(col int) Value {
2025-01-21 01:42:57 +00:00
ptr := ptr_t(s.c.call("sqlite3_column_value",
stk_t(s.handle), stk_t(col)))
2023-11-29 16:09:30 +00:00
return Value{
2024-01-08 19:23:32 +00:00
c: s.c,
2023-11-29 16:09:30 +00:00
unprot: true,
2025-01-21 01:42:57 +00:00
handle: ptr,
2023-11-29 16:09:30 +00:00
}
}
2024-01-16 15:18:14 +00:00
2024-03-22 00:21:00 +00:00
// Columns populates result columns into the provided slice.
// The slice must have [Stmt.ColumnCount] length.
//
// [INTEGER] columns will be retrieved as int64 values,
// [FLOAT] as float64, [NULL] as nil,
// [TEXT] as string, and [BLOB] as []byte.
2024-12-04 17:09:22 +00:00
func (s *Stmt) Columns(dest ...any) error {
2025-03-31 13:02:41 +01:00
types, ptr, err := s.columns(int64(len(dest)))
if err != nil {
2024-01-16 15:18:14 +00:00
return err
}
2024-09-28 10:37:47 +01:00
// Avoid bounds checks on types below.
if len(types) != len(dest) {
panic(util.AssertErr())
}
2024-01-16 15:18:14 +00:00
for i := range dest {
switch types[i] {
case byte(INTEGER):
2025-03-31 13:02:41 +01:00
dest[i] = util.Read64[int64](s.c.mod, ptr)
2024-01-16 15:18:14 +00:00
case byte(FLOAT):
2025-03-31 13:02:41 +01:00
dest[i] = util.ReadFloat64(s.c.mod, ptr)
2024-01-16 15:18:14 +00:00
case byte(NULL):
dest[i] = nil
2025-03-31 13:02:41 +01:00
case byte(TEXT):
len := util.Read32[int32](s.c.mod, ptr+4)
2025-03-17 12:16:19 +00:00
if len != 0 {
2025-03-31 13:02:41 +01:00
ptr := util.Read32[ptr_t](s.c.mod, ptr)
2025-03-17 12:16:19 +00:00
buf := util.View(s.c.mod, ptr, int64(len))
2025-03-31 13:02:41 +01:00
dest[i] = string(buf)
} else {
dest[i] = ""
}
case byte(BLOB):
len := util.Read32[int32](s.c.mod, ptr+4)
if len != 0 {
ptr := util.Read32[ptr_t](s.c.mod, ptr)
buf := util.View(s.c.mod, ptr, int64(len))
tmp, _ := dest[i].([]byte)
dest[i] = append(tmp[:0], buf...)
2024-10-02 12:59:49 +01:00
} else {
2025-03-31 13:02:41 +01:00
dest[i], _ = dest[i].([]byte)
}
}
ptr += 8
}
return nil
}
// ColumnsRaw populates result columns into the provided slice.
// The slice must have [Stmt.ColumnCount] length.
//
// [INTEGER] columns will be retrieved as int64 values,
// [FLOAT] as float64, [NULL] as nil,
// [TEXT] and [BLOB] as []byte.
// Any []byte are owned by SQLite and may be invalidated by
// subsequent calls to [Stmt] methods.
func (s *Stmt) ColumnsRaw(dest ...any) error {
types, ptr, err := s.columns(int64(len(dest)))
if err != nil {
return err
}
// Avoid bounds checks on types below.
if len(types) != len(dest) {
panic(util.AssertErr())
}
for i := range dest {
switch types[i] {
case byte(INTEGER):
dest[i] = util.Read64[int64](s.c.mod, ptr)
case byte(FLOAT):
dest[i] = util.ReadFloat64(s.c.mod, ptr)
case byte(NULL):
dest[i] = nil
default:
len := util.Read32[int32](s.c.mod, ptr+4)
if len == 0 && types[i] == byte(BLOB) {
dest[i] = []byte{}
} else {
cap := len
2025-03-17 12:16:19 +00:00
if types[i] == byte(TEXT) {
2025-03-31 13:02:41 +01:00
cap++
2025-03-17 12:16:19 +00:00
}
2025-03-31 13:02:41 +01:00
ptr := util.Read32[ptr_t](s.c.mod, ptr)
buf := util.View(s.c.mod, ptr, int64(cap))[:len]
dest[i] = buf
2024-10-02 12:59:49 +01:00
}
2024-01-16 15:18:14 +00:00
}
2025-03-31 13:02:41 +01:00
ptr += 8
2024-01-16 15:18:14 +00:00
}
return nil
}
2025-03-31 13:02:41 +01:00
func (s *Stmt) columns(count int64) ([]byte, ptr_t, error) {
defer s.c.arena.mark()()
typePtr := s.c.arena.new(count)
dataPtr := s.c.arena.new(count * 8)
rc := res_t(s.c.call("sqlite3_columns_go",
stk_t(s.handle), stk_t(count), stk_t(typePtr), stk_t(dataPtr)))
if rc == res_t(MISUSE) {
return nil, 0, MISUSE
}
if err := s.c.error(rc); err != nil {
return nil, 0, err
}
return util.View(s.c.mod, typePtr, count), dataPtr, nil
}