Files
sqlite3/driver/driver.go

879 lines
21 KiB
Go
Raw Normal View History

2023-02-14 18:21:18 +00:00
// Package driver provides a database/sql driver for SQLite.
2023-02-28 14:50:15 +00:00
//
// Importing package driver registers a [database/sql] driver named "sqlite3".
// You may also need to import package embed.
//
// import _ "github.com/ncruces/go-sqlite3/driver"
// import _ "github.com/ncruces/go-sqlite3/embed"
//
// The data source name for "sqlite3" databases can be a filename or a "file:" [URI].
//
// # Default transaction mode
//
2023-02-28 14:50:15 +00:00
// The [TRANSACTION] mode can be specified using "_txlock":
//
// sql.Open("sqlite3", "file:demo.db?_txlock=immediate")
//
2024-07-30 13:30:23 +01:00
// Possible values are: "deferred" (the default), "immediate", "exclusive".
// Regardless of "_txlock":
// - a [linearizable] transaction is always "exclusive";
// - a [serializable] transaction is always "immediate";
// - a [read-only] transaction is always "deferred".
2023-12-07 03:09:37 -08:00
//
2025-03-31 13:02:41 +01:00
// # Datatypes In SQLite
//
// SQLite is dynamically typed.
// Columns can mostly hold any value regardless of their declared type.
// SQLite supports most [driver.Value] types out of the box,
// but bool and [time.Time] require special care.
//
// Booleans can be stored on any column type and scanned back to a *bool.
// However, if scanned to a *any, booleans may either become an
// int64, string or bool, depending on the declared type of the column.
// If you use BOOLEAN for your column type,
// 1 and 0 will always scan as true and false.
//
// # Working with time
//
2025-03-31 13:02:41 +01:00
// Time values can similarly be stored on any column type.
2023-12-07 03:09:37 -08:00
// The time encoding/decoding format can be specified using "_timefmt":
//
// sql.Open("sqlite3", "file:demo.db?_timefmt=sqlite")
//
2025-03-31 13:02:41 +01:00
// Special values are: "auto" (the default), "sqlite", "rfc3339";
2024-07-30 13:30:23 +01:00
// - "auto" encodes as RFC 3339 and decodes any [format] supported by SQLite;
// - "sqlite" encodes as SQLite and decodes any [format] supported by SQLite;
// - "rfc3339" encodes and decodes RFC 3339 only.
2023-12-07 03:09:37 -08:00
//
2025-03-31 13:02:41 +01:00
// You can also set "_timefmt" to an arbitrary [sqlite3.TimeFormat] or [time.Layout].
//
// If you encode as RFC 3339 (the default),
// consider using the TIME [collating sequence] to produce time-ordered sequences.
//
// If you encode as RFC 3339 (the default),
2025-03-31 13:02:41 +01:00
// time values will scan back to a *time.Time unless your column type is TEXT.
// Otherwise, if scanned to a *any, time values may either become an
// int64, float64 or string, depending on the time format and declared type of the column.
// If you use DATE, TIME, DATETIME, or TIMESTAMP for your column type,
// "_timefmt" will be used to decode values.
//
2025-03-31 13:02:41 +01:00
// To scan values in custom formats, [sqlite3.TimeFormat.Scanner] may be helpful.
// To bind values in custom formats, [sqlite3.TimeFormat.Encode] them before binding.
//
// When using a custom time struct, you'll have to implement
// [database/sql/driver.Valuer] and [database/sql.Scanner].
//
2024-10-04 16:39:34 +01:00
// The Value method should ideally encode to a time [format] supported by SQLite.
// This ensures SQL date and time functions work as they should,
// and that your schema works with other SQLite tools.
// [sqlite3.TimeFormat.Encode] may help.
//
// The Scan method needs to take into account that the value it receives can be of differing types.
// It can already be a [time.Time], if the driver decoded the value according to "_timefmt" rules.
2024-10-04 16:39:34 +01:00
// Or it can be a: string, int64, float64, []byte, or nil,
2025-03-31 13:02:41 +01:00
// depending on the column type and whoever wrote the value.
// [sqlite3.TimeFormat.Decode] may help.
//
// # Setting PRAGMAs
//
2023-02-28 14:50:15 +00:00
// [PRAGMA] statements can be specified using "_pragma":
//
2023-06-24 02:18:56 +01:00
// sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)")
2023-02-28 14:50:15 +00:00
//
2023-06-24 02:18:56 +01:00
// If no PRAGMAs are specified, a busy timeout of 1 minute is set.
2023-02-28 14:50:15 +00:00
//
2023-05-25 11:14:18 +01:00
// Order matters:
// encryption keys, busy timeout and locking mode should be the first PRAGMAs set,
// in that order.
2023-05-25 11:14:18 +01:00
//
2023-11-09 16:35:45 +00:00
// [URI]: https://sqlite.org/uri.html
// [PRAGMA]: https://sqlite.org/pragma.html
// [TRANSACTION]: https://sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
2024-07-30 13:30:23 +01:00
// [linearizable]: https://pkg.go.dev/database/sql#TxOptions
// [serializable]: https://pkg.go.dev/database/sql#TxOptions
2023-12-07 03:09:37 -08:00
// [read-only]: https://pkg.go.dev/database/sql#TxOptions
2024-07-30 13:30:23 +01:00
// [format]: https://sqlite.org/lang_datefunc.html#time_values
// [collating sequence]: https://sqlite.org/datatype3.html#collating_sequences
2023-02-14 18:21:18 +00:00
package driver
import (
2023-02-18 02:16:11 +00:00
"context"
2023-02-14 18:21:18 +00:00
"database/sql"
"database/sql/driver"
2023-10-25 12:56:52 +01:00
"errors"
2023-02-20 13:30:01 +00:00
"fmt"
2023-02-17 02:21:07 +00:00
"io"
2023-02-18 12:20:42 +00:00
"net/url"
"reflect"
2023-02-18 12:20:42 +00:00
"strings"
2023-02-17 02:21:07 +00:00
"time"
2024-01-16 15:18:14 +00:00
"unsafe"
2023-02-14 18:21:18 +00:00
"github.com/ncruces/go-sqlite3"
2023-03-29 15:01:25 +01:00
"github.com/ncruces/go-sqlite3/internal/util"
2023-02-14 18:21:18 +00:00
)
2023-09-20 02:41:09 +01:00
// This variable can be replaced with -ldflags:
//
2023-12-07 03:09:37 -08:00
// go build -ldflags="-X github.com/ncruces/go-sqlite3/driver.driverName=sqlite"
2023-09-20 02:41:09 +01:00
var driverName = "sqlite3"
2023-02-14 18:21:18 +00:00
func init() {
2023-09-20 02:41:09 +01:00
if driverName != "" {
sql.Register(driverName, &SQLite{})
2023-09-20 02:41:09 +01:00
}
}
// Open opens the SQLite database specified by dataSourceName as a [database/sql.DB].
//
// Open accepts zero, one, or two callbacks (nil callbacks are ignored).
// The first callback is called when the driver opens a new connection.
// The second callback is called before the driver closes a connection.
2024-04-22 15:28:19 +01:00
// The [sqlite3.Conn] can be used to execute queries, register functions, etc.
func Open(dataSourceName string, fn ...func(*sqlite3.Conn) error) (*sql.DB, error) {
if len(fn) > 2 {
2024-08-12 17:50:23 +01:00
return nil, sqlite3.MISUSE
}
2024-11-28 00:12:11 +00:00
var init, term func(*sqlite3.Conn) error
if len(fn) > 1 {
2024-11-28 00:12:11 +00:00
term = fn[1]
}
if len(fn) > 0 {
2024-11-28 00:12:11 +00:00
init = fn[0]
}
2024-11-28 00:12:11 +00:00
c, err := newConnector(dataSourceName, init, term)
2023-09-20 02:41:09 +01:00
if err != nil {
return nil, err
}
return sql.OpenDB(c), nil
2023-02-14 18:21:18 +00:00
}
2024-04-22 15:28:19 +01:00
// SQLite implements [database/sql/driver.Driver].
2024-11-28 00:12:11 +00:00
type SQLite struct{}
2023-02-14 18:21:18 +00:00
2024-09-03 11:22:24 +01:00
var (
// Ensure these interfaces are implemented:
_ driver.DriverContext = &SQLite{}
)
2024-04-22 15:28:19 +01:00
// Open implements [database/sql/driver.Driver].
func (d *SQLite) Open(name string) (driver.Conn, error) {
2024-11-28 00:12:11 +00:00
c, err := newConnector(name, nil, nil)
2023-08-10 13:18:13 +01:00
if err != nil {
return nil, err
}
return c.Connect(context.Background())
}
2024-04-22 15:28:19 +01:00
// OpenConnector implements [database/sql/driver.DriverContext].
func (d *SQLite) OpenConnector(name string) (driver.Connector, error) {
2024-11-28 00:12:11 +00:00
return newConnector(name, nil, nil)
2023-09-20 02:41:09 +01:00
}
2024-11-28 00:12:11 +00:00
func newConnector(name string, init, term func(*sqlite3.Conn) error) (*connector, error) {
c := connector{name: name, init: init, term: term}
2023-12-07 03:09:37 -08:00
var txlock, timefmt string
2023-08-10 13:18:13 +01:00
if strings.HasPrefix(name, "file:") {
if _, after, ok := strings.Cut(name, "?"); ok {
query, err := url.ParseQuery(after)
if err != nil {
return nil, err
}
2023-12-07 03:09:37 -08:00
txlock = query.Get("_txlock")
timefmt = query.Get("_timefmt")
c.pragmas = query.Has("_pragma")
2023-08-10 13:18:13 +01:00
}
}
2023-12-07 03:09:37 -08:00
switch txlock {
2024-07-24 20:03:23 +01:00
case "", "deferred", "concurrent", "immediate", "exclusive":
c.txLock = txlock
2023-12-07 03:09:37 -08:00
default:
return nil, fmt.Errorf("sqlite3: invalid _txlock: %s", txlock)
}
switch timefmt {
case "":
c.tmRead = sqlite3.TimeFormatAuto
c.tmWrite = sqlite3.TimeFormatDefault
case "sqlite":
c.tmRead = sqlite3.TimeFormatAuto
c.tmWrite = sqlite3.TimeFormat3
case "rfc3339":
c.tmRead = sqlite3.TimeFormatDefault
c.tmWrite = sqlite3.TimeFormatDefault
default:
c.tmRead = sqlite3.TimeFormat(timefmt)
c.tmWrite = sqlite3.TimeFormat(timefmt)
}
2023-08-10 13:18:13 +01:00
return &c, nil
}
type connector struct {
2024-11-28 00:12:11 +00:00
init func(*sqlite3.Conn) error
term func(*sqlite3.Conn) error
2023-08-10 13:18:13 +01:00
name string
2024-07-24 20:03:23 +01:00
txLock string
2023-12-07 03:09:37 -08:00
tmRead sqlite3.TimeFormat
tmWrite sqlite3.TimeFormat
2023-08-10 13:18:13 +01:00
pragmas bool
}
func (n *connector) Driver() driver.Driver {
2024-11-28 00:12:11 +00:00
return &SQLite{}
2023-08-10 13:18:13 +01:00
}
2025-01-21 01:42:57 +00:00
func (n *connector) Connect(ctx context.Context) (ret driver.Conn, err error) {
2023-12-07 03:09:37 -08:00
c := &conn{
2024-07-24 20:03:23 +01:00
txLock: n.txLock,
2023-12-07 03:09:37 -08:00
tmRead: n.tmRead,
tmWrite: n.tmWrite,
}
2024-10-04 13:31:53 +01:00
c.Conn, err = sqlite3.OpenContext(ctx, n.name)
2023-02-17 16:19:55 +00:00
if err != nil {
return nil, err
}
2023-07-13 11:07:54 +01:00
defer func() {
2025-01-21 01:42:57 +00:00
if ret == nil {
2024-10-07 13:22:31 +01:00
c.Close()
2023-07-13 11:07:54 +01:00
}
}()
2023-02-19 16:16:13 +00:00
2025-04-08 13:48:49 +01:00
if old := c.Conn.SetInterrupt(ctx); old != ctx {
defer c.Conn.SetInterrupt(old)
}
2023-02-28 16:03:31 +00:00
2023-08-10 13:18:13 +01:00
if !n.pragmas {
2024-07-25 13:00:35 +01:00
err = c.Conn.BusyTimeout(time.Minute)
2023-04-17 00:29:20 +01:00
if err != nil {
return nil, err
}
2023-10-13 18:53:37 +01:00
}
2024-11-28 00:12:11 +00:00
if n.init != nil {
err = n.init(c.Conn)
2023-02-28 16:03:31 +00:00
if err != nil {
return nil, err
}
2023-10-13 18:53:37 +01:00
}
2024-11-28 00:12:11 +00:00
if n.pragmas || n.init != nil {
2023-10-13 18:53:37 +01:00
s, _, err := c.Conn.Prepare(`PRAGMA query_only`)
2023-04-17 00:29:20 +01:00
if err != nil {
return nil, err
}
2024-10-07 13:22:31 +01:00
defer s.Close()
2025-11-19 11:27:42 +00:00
if s.Step() {
c.readOnly = s.ColumnBool(0)
2023-10-13 18:53:37 +01:00
}
err = s.Close()
2023-09-20 02:41:09 +01:00
if err != nil {
return nil, err
}
}
2024-11-28 00:12:11 +00:00
if n.term != nil {
err = c.Conn.Trace(sqlite3.TRACE_CLOSE, func(sqlite3.TraceEvent, any, any) error {
2024-11-28 00:12:11 +00:00
return n.term(c.Conn)
})
if err != nil {
return nil, err
}
}
2023-12-07 03:09:37 -08:00
return c, nil
2023-02-14 18:21:18 +00:00
}
2024-09-03 11:22:24 +01:00
// Conn is implemented by the SQLite [database/sql] driver connections.
//
// It can be used to access SQLite features like [online backup]:
//
// db, err := driver.Open("temp.db")
// if err != nil {
// log.Fatal(err)
// }
// defer db.Close()
//
// conn, err := db.Conn(context.TODO())
// if err != nil {
// log.Fatal(err)
// }
2024-12-19 14:52:25 +00:00
// defer conn.Close()
2024-09-03 11:22:24 +01:00
//
// err = conn.Raw(func(driverConn any) error {
// conn := driverConn.(driver.Conn)
// return conn.Raw().Backup("main", "backup.db")
// })
// if err != nil {
// log.Fatal(err)
// }
//
// [online backup]: https://sqlite.org/backup.html
type Conn interface {
Raw() *sqlite3.Conn
driver.Conn
2024-11-28 00:12:11 +00:00
driver.ConnBeginTx
driver.ConnPrepareContext
2024-09-03 11:22:24 +01:00
}
2023-02-18 12:20:42 +00:00
type conn struct {
2023-05-30 13:39:34 +01:00
*sqlite3.Conn
2024-07-24 20:03:23 +01:00
txLock string
txReset string
tmRead sqlite3.TimeFormat
tmWrite sqlite3.TimeFormat
2025-11-19 11:27:42 +00:00
readOnly bool
2023-02-18 12:20:42 +00:00
}
2023-02-17 02:21:07 +00:00
var (
2023-02-17 16:19:55 +00:00
// Ensure these interfaces are implemented:
2024-11-28 00:12:11 +00:00
_ Conn = &conn{}
_ driver.ExecerContext = &conn{}
2023-02-17 02:21:07 +00:00
)
2023-09-20 02:41:09 +01:00
func (c *conn) Raw() *sqlite3.Conn {
return c.Conn
}
2024-06-21 13:01:55 +01:00
// Deprecated: use BeginTx instead.
2023-05-30 13:39:34 +01:00
func (c *conn) Begin() (driver.Tx, error) {
2024-07-10 15:41:28 +01:00
// notest
2023-02-19 16:16:13 +00:00
return c.BeginTx(context.Background(), driver.TxOptions{})
}
2023-05-30 13:39:34 +01:00
func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
2024-07-24 20:03:23 +01:00
var txLock string
2023-03-08 18:05:18 +00:00
switch opts.Isolation {
default:
2023-03-29 15:01:25 +01:00
return nil, util.IsolationErr
2024-07-24 20:03:23 +01:00
case driver.IsolationLevel(sql.LevelLinearizable):
txLock = "exclusive"
case driver.IsolationLevel(sql.LevelSerializable):
txLock = "immediate"
case driver.IsolationLevel(sql.LevelDefault):
if !opts.ReadOnly {
txLock = c.txLock
}
}
c.txReset = ``
txBegin := `BEGIN ` + txLock
2025-11-19 11:27:42 +00:00
if opts.ReadOnly && !c.readOnly {
2024-07-24 20:03:23 +01:00
txBegin += ` ; PRAGMA query_only=on`
2025-11-19 11:27:42 +00:00
c.txReset = `; PRAGMA query_only=off`
2023-02-19 16:16:13 +00:00
}
2025-04-08 13:48:49 +01:00
if old := c.Conn.SetInterrupt(ctx); old != ctx {
defer c.Conn.SetInterrupt(old)
}
2023-05-30 13:39:34 +01:00
err := c.Conn.Exec(txBegin)
2023-02-17 02:21:07 +00:00
if err != nil {
return nil, err
}
return c, nil
}
2023-05-30 13:39:34 +01:00
func (c *conn) Commit() error {
2024-07-24 20:03:23 +01:00
err := c.Conn.Exec(`COMMIT` + c.txReset)
2023-09-20 02:41:09 +01:00
if err != nil && !c.Conn.GetAutocommit() {
2023-02-17 02:21:07 +00:00
c.Rollback()
}
return err
}
2023-02-14 18:21:18 +00:00
2023-05-30 13:39:34 +01:00
func (c *conn) Rollback() error {
2025-03-28 11:10:51 +00:00
// ROLLBACK even if interrupted.
2025-04-08 13:48:49 +01:00
ctx := context.Background()
if old := c.Conn.SetInterrupt(ctx); old != ctx {
defer c.Conn.SetInterrupt(old)
}
2025-03-28 11:10:51 +00:00
return c.Conn.Exec(`ROLLBACK` + c.txReset)
2023-02-17 02:21:07 +00:00
}
2023-02-14 18:21:18 +00:00
2023-05-30 13:39:34 +01:00
func (c *conn) Prepare(query string) (driver.Stmt, error) {
2024-07-10 15:41:28 +01:00
// notest
2023-05-30 13:39:34 +01:00
return c.PrepareContext(context.Background(), query)
}
func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
2025-04-08 13:48:49 +01:00
if old := c.Conn.SetInterrupt(ctx); old != ctx {
defer c.Conn.SetInterrupt(old)
}
2023-05-30 13:39:34 +01:00
s, tail, err := c.Conn.Prepare(query)
2023-02-17 02:21:07 +00:00
if err != nil {
return nil, err
}
2024-12-12 12:57:18 +00:00
if notWhitespace(tail) {
2023-11-30 12:26:15 +00:00
s.Close()
return nil, util.TailErr
2023-02-18 02:57:47 +00:00
}
2024-06-19 13:54:58 +01:00
return &stmt{Stmt: s, tmRead: c.tmRead, tmWrite: c.tmWrite, inputs: -2}, nil
2023-02-17 02:21:07 +00:00
}
2023-05-30 13:39:34 +01:00
func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
2023-02-18 02:57:47 +00:00
if len(args) != 0 {
// Slow path.
return nil, driver.ErrSkip
}
2023-11-07 15:19:40 +00:00
if savept, ok := ctx.(*saveptCtx); ok {
// Called from driver.Savepoint.
2023-12-07 03:09:37 -08:00
savept.Savepoint = c.Conn.Savepoint()
2023-11-08 07:28:48 +00:00
return resultRowsAffected(0), nil
2023-11-07 15:19:40 +00:00
}
2025-04-08 13:48:49 +01:00
if old := c.Conn.SetInterrupt(ctx); old != ctx {
defer c.Conn.SetInterrupt(old)
}
2023-02-18 02:57:47 +00:00
2023-05-30 13:39:34 +01:00
err := c.Conn.Exec(query)
2023-02-18 02:57:47 +00:00
if err != nil {
return nil, err
}
2023-05-30 13:39:34 +01:00
return newResult(c.Conn), nil
2023-05-17 14:29:59 +01:00
}
2024-04-28 10:33:39 +01:00
func (c *conn) CheckNamedValue(arg *driver.NamedValue) error {
2024-07-25 13:00:35 +01:00
// Fast path: short circuit argument verification.
// Arguments will be rejected by conn.ExecContext.
2023-10-18 23:14:46 +01:00
return nil
}
2025-11-07 11:20:03 +00:00
// Deprecated: for Litestream use only; may be removed at any time.
func (c *conn) FileControlPersistWAL(schema string, mode int) (int, error) {
// notest
arg := make([]any, 1)
if mode >= 0 {
arg[0] = mode > 0
} else {
arg = arg[:0]
}
res, err := c.Conn.FileControl(schema, sqlite3.FCNTL_PERSIST_WAL, arg...)
if res == true {
return 1, err
}
return 0, err
}
2023-02-17 02:21:07 +00:00
type stmt struct {
2023-12-04 12:37:53 +00:00
*sqlite3.Stmt
2023-12-07 03:09:37 -08:00
tmWrite sqlite3.TimeFormat
tmRead sqlite3.TimeFormat
2024-06-19 13:54:58 +01:00
inputs int
2023-02-17 02:21:07 +00:00
}
2023-02-17 16:19:55 +00:00
var (
// Ensure these interfaces are implemented:
2023-05-30 13:39:34 +01:00
_ driver.StmtExecContext = &stmt{}
_ driver.StmtQueryContext = &stmt{}
_ driver.NamedValueChecker = &stmt{}
2023-02-17 16:19:55 +00:00
)
2023-05-30 13:39:34 +01:00
func (s *stmt) NumInput() int {
2024-06-19 13:54:58 +01:00
if s.inputs >= -1 {
return s.inputs
}
2023-05-30 13:39:34 +01:00
n := s.Stmt.BindCount()
2023-02-20 13:30:01 +00:00
for i := 1; i <= n; i++ {
2023-05-30 13:39:34 +01:00
if s.Stmt.BindName(i) != "" {
2024-06-19 13:54:58 +01:00
s.inputs = -1
2023-02-20 13:30:01 +00:00
return -1
}
}
2024-06-19 13:54:58 +01:00
s.inputs = n
2023-02-20 13:30:01 +00:00
return n
2023-02-17 02:21:07 +00:00
}
2023-02-18 02:16:11 +00:00
// Deprecated: use ExecContext instead.
2023-05-30 13:39:34 +01:00
func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
2024-07-10 15:41:28 +01:00
// notest
2023-02-18 02:16:11 +00:00
return s.ExecContext(context.Background(), namedValues(args))
}
// Deprecated: use QueryContext instead.
2023-05-30 13:39:34 +01:00
func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
2024-07-10 15:41:28 +01:00
// notest
2023-02-18 02:16:11 +00:00
return s.QueryContext(context.Background(), namedValues(args))
}
2023-05-30 13:39:34 +01:00
func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
2023-08-10 13:18:13 +01:00
err := s.setupBindings(args)
2023-02-14 18:21:18 +00:00
if err != nil {
return nil, err
}
2023-02-17 02:21:07 +00:00
2025-04-08 13:48:49 +01:00
c := s.Stmt.Conn()
if old := c.SetInterrupt(ctx); old != ctx {
defer c.SetInterrupt(old)
}
2023-08-10 13:18:13 +01:00
2025-01-17 14:40:12 +00:00
err = errors.Join(
s.Stmt.Exec(),
s.Stmt.ClearBindings())
2023-02-17 02:21:07 +00:00
if err != nil {
return nil, err
}
2025-04-08 13:48:49 +01:00
return newResult(c), nil
2023-02-17 02:21:07 +00:00
}
2023-05-30 13:39:34 +01:00
func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
2023-08-10 13:18:13 +01:00
err := s.setupBindings(args)
2023-02-18 02:16:11 +00:00
if err != nil {
return nil, err
}
2023-12-14 14:02:41 +00:00
return &rows{ctx: ctx, stmt: s}, nil
2023-08-04 14:12:36 +01:00
}
2024-06-19 13:54:58 +01:00
func (s *stmt) setupBindings(args []driver.NamedValue) (err error) {
2023-02-18 02:16:11 +00:00
var ids [3]int
for _, arg := range args {
ids := ids[:0]
if arg.Name == "" {
ids = append(ids, arg.Ordinal)
} else {
2024-10-03 17:25:14 +01:00
for _, prefix := range [...]string{":", "@", "$"} {
2023-05-30 13:39:34 +01:00
if id := s.Stmt.BindIndex(prefix + arg.Name); id != 0 {
2023-02-18 02:16:11 +00:00
ids = append(ids, id)
}
}
}
for _, id := range ids {
switch a := arg.Value.(type) {
case bool:
2023-05-30 13:39:34 +01:00
err = s.Stmt.BindBool(id, a)
2023-02-22 14:19:56 +00:00
case int:
2023-05-30 13:39:34 +01:00
err = s.Stmt.BindInt(id, a)
2023-02-18 02:16:11 +00:00
case int64:
2023-05-30 13:39:34 +01:00
err = s.Stmt.BindInt64(id, a)
2023-02-18 02:16:11 +00:00
case float64:
2023-05-30 13:39:34 +01:00
err = s.Stmt.BindFloat(id, a)
2023-02-18 02:16:11 +00:00
case string:
2023-05-30 13:39:34 +01:00
err = s.Stmt.BindText(id, a)
2023-02-18 02:16:11 +00:00
case []byte:
2023-05-30 13:39:34 +01:00
err = s.Stmt.BindBlob(id, a)
2023-02-22 14:19:56 +00:00
case sqlite3.ZeroBlob:
2023-05-30 13:39:34 +01:00
err = s.Stmt.BindZeroBlob(id, int64(a))
2023-02-18 02:16:11 +00:00
case time.Time:
2023-12-07 03:09:37 -08:00
err = s.Stmt.BindTime(id, a, s.tmWrite)
2023-12-29 11:37:50 +00:00
case util.JSON:
err = s.Stmt.BindJSON(id, a.Value)
2025-07-10 13:05:38 +01:00
case util.Pointer:
err = s.Stmt.BindPointer(id, a.Value)
2023-02-18 02:16:11 +00:00
case nil:
2023-05-30 13:39:34 +01:00
err = s.Stmt.BindNull(id)
2023-02-18 02:16:11 +00:00
default:
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-02-18 02:16:11 +00:00
}
2024-10-03 17:25:14 +01:00
if err != nil {
return err
}
2023-02-17 02:21:07 +00:00
}
}
2023-08-04 14:12:36 +01:00
return nil
2023-02-17 02:21:07 +00:00
}
2023-05-30 13:39:34 +01:00
func (s *stmt) CheckNamedValue(arg *driver.NamedValue) error {
2023-02-22 14:19:56 +00:00
switch arg.Value.(type) {
case bool, int, int64, float64, string, []byte,
2023-12-29 11:37:50 +00:00
time.Time, sqlite3.ZeroBlob,
2025-07-10 13:05:38 +01:00
util.JSON, util.Pointer,
2023-11-09 16:16:48 +00:00
nil:
2023-02-22 14:19:56 +00:00
return nil
default:
return driver.ErrSkip
}
}
2023-05-08 10:34:33 +01:00
func newResult(c *sqlite3.Conn) driver.Result {
rows := c.Changes()
if rows != 0 {
id := c.LastInsertRowID()
if id != 0 {
return result{id, rows}
}
}
return resultRowsAffected(rows)
}
2023-02-17 02:21:07 +00:00
type result struct{ lastInsertId, rowsAffected int64 }
func (r result) LastInsertId() (int64, error) {
return r.lastInsertId, nil
}
func (r result) RowsAffected() (int64, error) {
return r.rowsAffected, nil
}
2023-05-08 10:34:33 +01:00
type resultRowsAffected int64
func (r resultRowsAffected) LastInsertId() (int64, error) {
return 0, nil
}
func (r resultRowsAffected) RowsAffected() (int64, error) {
return int64(r), nil
}
type scantype byte
const (
2025-09-24 13:56:50 +01:00
_ANY scantype = iota
_INT
_REAL
_TEXT
_BLOB
_NULL
_BOOL
_TIME
2025-09-24 13:56:50 +01:00
_NOT_NULL
)
var (
_ [0]struct{} = [scantype(sqlite3.INTEGER) - _INT]struct{}{}
_ [0]struct{} = [scantype(sqlite3.FLOAT) - _REAL]struct{}{}
_ [0]struct{} = [scantype(sqlite3.TEXT) - _TEXT]struct{}{}
_ [0]struct{} = [scantype(sqlite3.BLOB) - _BLOB]struct{}{}
_ [0]struct{} = [scantype(sqlite3.NULL) - _NULL]struct{}{}
_ [0]struct{} = [_NOT_NULL & (_NOT_NULL - 1)]struct{}{}
)
2025-03-31 13:02:41 +01:00
func scanFromDecl(decl string) scantype {
// These types are only used before we have rows,
// and otherwise as type hints.
// The first few ensure STRICT tables are strictly typed.
// The other two are type hints for booleans and time.
switch decl {
case "INT", "INTEGER":
return _INT
case "REAL":
return _REAL
case "TEXT":
return _TEXT
case "BLOB":
return _BLOB
case "BOOLEAN":
return _BOOL
case "DATE", "TIME", "DATETIME", "TIMESTAMP":
return _TIME
}
return _ANY
}
2025-08-14 01:36:45 +01:00
type rows struct {
ctx context.Context
*stmt
names []string
types []string
scans []scantype
2025-09-24 13:56:50 +01:00
dest []driver.Value
2025-08-14 01:36:45 +01:00
}
2024-09-24 12:49:53 +01:00
var (
// Ensure these interfaces are implemented:
_ driver.RowsColumnTypeDatabaseTypeName = &rows{}
_ driver.RowsColumnTypeNullable = &rows{}
2025-08-14 01:36:45 +01:00
// _ driver.RowsColumnScanner = &rows{}
2024-09-24 12:49:53 +01:00
)
2023-05-30 13:39:34 +01:00
func (r *rows) Close() error {
2025-01-17 14:40:12 +00:00
return errors.Join(
r.Stmt.Reset(),
r.Stmt.ClearBindings())
2023-02-17 02:21:07 +00:00
}
2023-05-30 13:39:34 +01:00
func (r *rows) Columns() []string {
2023-12-14 14:02:41 +00:00
if r.names == nil {
count := r.Stmt.ColumnCount()
2024-09-30 11:03:50 +01:00
names := make([]string, count)
for i := range names {
names[i] = r.Stmt.ColumnName(i)
2023-12-14 14:02:41 +00:00
}
2024-09-30 11:03:50 +01:00
r.names = names
2023-12-14 14:02:41 +00:00
}
return r.names
}
2025-03-31 13:02:41 +01:00
func (r *rows) scanType(index int) scantype {
if r.scans == nil {
2025-09-24 13:56:50 +01:00
count := len(r.names)
2025-03-31 13:02:41 +01:00
scans := make([]scantype, count)
for i := range scans {
scans[i] = scanFromDecl(strings.ToUpper(r.Stmt.ColumnDeclType(i)))
}
r.scans = scans
}
2025-09-24 13:56:50 +01:00
return r.scans[index] &^ _NOT_NULL
2025-03-31 13:02:41 +01:00
}
func (r *rows) loadColumnMetadata() {
2025-09-24 13:56:50 +01:00
if r.types == nil {
2025-04-08 13:48:49 +01:00
c := r.Stmt.Conn()
2025-09-24 13:56:50 +01:00
count := len(r.names)
2024-09-30 11:03:50 +01:00
types := make([]string, count)
scans := make([]scantype, count)
2025-09-24 13:56:50 +01:00
for i := range types {
var notnull bool
2024-09-16 12:05:37 +01:00
if col := r.Stmt.ColumnOriginName(i); col != "" {
2025-09-24 13:56:50 +01:00
types[i], _, notnull, _, _, _ = c.TableColumnMetadata(
2024-09-16 12:05:37 +01:00
r.Stmt.ColumnDatabaseName(i),
r.Stmt.ColumnTableName(i),
col)
2024-12-08 11:47:11 +00:00
types[i] = strings.ToUpper(types[i])
2025-03-31 13:02:41 +01:00
scans[i] = scanFromDecl(types[i])
2025-09-24 13:56:50 +01:00
if notnull {
scans[i] |= _NOT_NULL
}
2024-09-16 12:05:37 +01:00
}
}
2024-09-30 11:03:50 +01:00
r.types = types
r.scans = scans
2024-09-16 12:05:37 +01:00
}
}
2023-12-01 02:38:56 +00:00
func (r *rows) ColumnTypeDatabaseTypeName(index int) string {
r.loadColumnMetadata()
2025-03-31 13:02:41 +01:00
decl := r.types[index]
if len := len(decl); len > 0 && decl[len-1] == ')' {
if i := strings.LastIndexByte(decl, '('); i >= 0 {
decl = decl[:i]
2023-12-01 02:38:56 +00:00
}
}
2025-03-31 13:02:41 +01:00
return strings.TrimSpace(decl)
2023-12-01 02:38:56 +00:00
}
2024-09-16 12:05:37 +01:00
func (r *rows) ColumnTypeNullable(index int) (nullable, ok bool) {
r.loadColumnMetadata()
2025-09-24 13:56:50 +01:00
nullable = r.scans[index]&^_NOT_NULL == 0
return nullable, !nullable
2024-09-16 12:05:37 +01:00
}
func (r *rows) ColumnTypeScanType(index int) (typ reflect.Type) {
r.loadColumnMetadata()
2025-09-24 13:56:50 +01:00
scan := r.scans[index] &^ _NOT_NULL
if r.Stmt.Busy() {
// SQLite is dynamically typed and we now have a row.
// Always use the type of the value itself,
// unless the scan type is more specific
// and can scan the actual value.
val := scantype(r.Stmt.ColumnType(index))
useValType := true
switch {
case scan == _TIME && val != _BLOB && val != _NULL:
t := r.Stmt.ColumnTime(index, r.tmRead)
2025-08-13 03:31:12 +01:00
useValType = t.IsZero()
case scan == _BOOL && val == _INT:
i := r.Stmt.ColumnInt64(index)
useValType = i != 0 && i != 1
case scan == _BLOB && val == _NULL:
useValType = false
}
if useValType {
scan = val
}
}
switch scan {
case _INT:
2025-01-24 10:46:05 +00:00
return reflect.TypeFor[int64]()
case _REAL:
2025-01-24 10:46:05 +00:00
return reflect.TypeFor[float64]()
case _TEXT:
2025-01-24 10:46:05 +00:00
return reflect.TypeFor[string]()
case _BLOB:
2025-01-24 10:46:05 +00:00
return reflect.TypeFor[[]byte]()
case _BOOL:
2025-01-24 10:46:05 +00:00
return reflect.TypeFor[bool]()
case _TIME:
2025-01-24 10:46:05 +00:00
return reflect.TypeFor[time.Time]()
default:
2025-01-24 10:46:05 +00:00
return reflect.TypeFor[any]()
}
}
2023-05-30 13:39:34 +01:00
func (r *rows) Next(dest []driver.Value) error {
2025-09-24 13:56:50 +01:00
r.dest = nil
2025-04-08 13:48:49 +01:00
c := r.Stmt.Conn()
if old := c.SetInterrupt(r.ctx); old != r.ctx {
defer c.SetInterrupt(old)
}
2023-02-18 02:16:11 +00:00
2023-05-30 13:39:34 +01:00
if !r.Stmt.Step() {
if err := r.Stmt.Err(); err != nil {
2023-02-17 12:30:07 +00:00
return err
2023-02-17 02:21:07 +00:00
}
2023-02-17 12:30:07 +00:00
return io.EOF
2023-02-17 02:21:07 +00:00
}
2023-02-14 18:21:18 +00:00
2024-01-16 15:18:14 +00:00
data := unsafe.Slice((*any)(unsafe.SliceData(dest)), len(dest))
2025-03-31 13:02:41 +01:00
if err := r.Stmt.ColumnsRaw(data...); err != nil {
return err
2023-02-17 02:21:07 +00:00
}
2025-03-31 13:02:41 +01:00
for i := range dest {
scan := r.scanType(i)
2025-10-01 10:48:54 +01:00
if v, ok := dest[i].([]byte); ok {
2025-03-31 13:02:41 +01:00
if len(v) == cap(v) { // a BLOB
continue
}
if scan != _TEXT {
switch r.tmWrite {
case "", time.RFC3339, time.RFC3339Nano:
t, ok := maybeTime(v)
if ok {
dest[i] = t
continue
}
}
}
dest[i] = string(v)
2024-10-04 16:39:34 +01:00
}
2025-10-01 10:48:54 +01:00
switch scan {
case _TIME:
2025-03-31 13:02:41 +01:00
t, err := r.tmRead.Decode(dest[i])
if err == nil {
dest[i] = t
2025-10-01 10:48:54 +01:00
}
case _BOOL:
switch dest[i] {
case int64(0):
dest[i] = false
case int64(1):
dest[i] = true
2025-03-31 13:02:41 +01:00
}
2024-10-02 12:59:59 +01:00
}
2023-12-07 03:09:37 -08:00
}
2025-09-24 13:56:50 +01:00
r.dest = dest
2025-03-31 13:02:41 +01:00
return nil
2023-12-07 03:09:37 -08:00
}
2025-08-14 01:36:45 +01:00
2025-09-24 13:56:50 +01:00
func (r *rows) ScanColumn(dest any, index int) (err error) {
2025-08-14 01:36:45 +01:00
// notest // Go 1.26
2025-09-19 11:13:23 +01:00
var tm *time.Time
var ok *bool
2025-08-14 01:36:45 +01:00
switch d := dest.(type) {
case *time.Time:
2025-09-19 11:13:23 +01:00
tm = d
2025-08-14 01:36:45 +01:00
case *sql.NullTime:
2025-09-19 11:13:23 +01:00
tm = &d.Time
ok = &d.Valid
2025-08-14 01:36:45 +01:00
case *sql.Null[time.Time]:
2025-09-19 11:13:23 +01:00
tm = &d.V
ok = &d.Valid
2025-08-14 01:36:45 +01:00
default:
return driver.ErrSkip
}
2025-09-24 13:56:50 +01:00
value := r.dest[index]
*tm, err = r.tmRead.Decode(value)
if ok != nil {
*ok = err == nil
if value == nil {
return nil
}
2025-08-14 01:36:45 +01:00
}
2025-09-19 11:13:23 +01:00
return err
2025-08-14 01:36:45 +01:00
}