driver.go

  1// Package driver provides a database/sql driver for SQLite.
  2//
  3// Importing package driver registers a [database/sql] driver named "sqlite3".
  4// You may also need to import package embed.
  5//
  6//	import _ "github.com/ncruces/go-sqlite3/driver"
  7//	import _ "github.com/ncruces/go-sqlite3/embed"
  8//
  9// The data source name for "sqlite3" databases can be a filename or a "file:" [URI].
 10//
 11// # Default transaction mode
 12//
 13// The [TRANSACTION] mode can be specified using "_txlock":
 14//
 15//	sql.Open("sqlite3", "file:demo.db?_txlock=immediate")
 16//
 17// Possible values are: "deferred" (the default), "immediate", "exclusive".
 18// Regardless of "_txlock":
 19//   - a [linearizable] transaction is always "exclusive";
 20//   - a [serializable] transaction is always "immediate";
 21//   - a [read-only] transaction is always "deferred".
 22//
 23// # Datatypes In SQLite
 24//
 25// SQLite is dynamically typed.
 26// Columns can mostly hold any value regardless of their declared type.
 27// SQLite supports most [driver.Value] types out of the box,
 28// but bool and [time.Time] require special care.
 29//
 30// Booleans can be stored on any column type and scanned back to a *bool.
 31// However, if scanned to a *any, booleans may either become an
 32// int64, string or bool, depending on the declared type of the column.
 33// If you use BOOLEAN for your column type,
 34// 1 and 0 will always scan as true and false.
 35//
 36// # Working with time
 37//
 38// Time values can similarly be stored on any column type.
 39// The time encoding/decoding format can be specified using "_timefmt":
 40//
 41//	sql.Open("sqlite3", "file:demo.db?_timefmt=sqlite")
 42//
 43// Special values are: "auto" (the default), "sqlite", "rfc3339";
 44//   - "auto" encodes as RFC 3339 and decodes any [format] supported by SQLite;
 45//   - "sqlite" encodes as SQLite and decodes any [format] supported by SQLite;
 46//   - "rfc3339" encodes and decodes RFC 3339 only.
 47//
 48// You can also set "_timefmt" to an arbitrary [sqlite3.TimeFormat] or [time.Layout].
 49//
 50// If you encode as RFC 3339 (the default),
 51// consider using the TIME [collating sequence] to produce time-ordered sequences.
 52//
 53// If you encode as RFC 3339 (the default),
 54// time values will scan back to a *time.Time unless your column type is TEXT.
 55// Otherwise, if scanned to a *any, time values may either become an
 56// int64, float64 or string, depending on the time format and declared type of the column.
 57// If you use DATE, TIME, DATETIME, or TIMESTAMP for your column type,
 58// "_timefmt" will be used to decode values.
 59//
 60// To scan values in custom formats, [sqlite3.TimeFormat.Scanner] may be helpful.
 61// To bind values in custom formats, [sqlite3.TimeFormat.Encode] them before binding.
 62//
 63// When using a custom time struct, you'll have to implement
 64// [database/sql/driver.Valuer] and [database/sql.Scanner].
 65//
 66// The Value method should ideally encode to a time [format] supported by SQLite.
 67// This ensures SQL date and time functions work as they should,
 68// and that your schema works with other SQLite tools.
 69// [sqlite3.TimeFormat.Encode] may help.
 70//
 71// The Scan method needs to take into account that the value it receives can be of differing types.
 72// It can already be a [time.Time], if the driver decoded the value according to "_timefmt" rules.
 73// Or it can be a: string, int64, float64, []byte, or nil,
 74// depending on the column type and whoever wrote the value.
 75// [sqlite3.TimeFormat.Decode] may help.
 76//
 77// # Setting PRAGMAs
 78//
 79// [PRAGMA] statements can be specified using "_pragma":
 80//
 81//	sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)")
 82//
 83// If no PRAGMAs are specified, a busy timeout of 1 minute is set.
 84//
 85// Order matters:
 86// encryption keys, busy timeout and locking mode should be the first PRAGMAs set,
 87// in that order.
 88//
 89// [URI]: https://sqlite.org/uri.html
 90// [PRAGMA]: https://sqlite.org/pragma.html
 91// [TRANSACTION]: https://sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
 92// [linearizable]: https://pkg.go.dev/database/sql#TxOptions
 93// [serializable]: https://pkg.go.dev/database/sql#TxOptions
 94// [read-only]: https://pkg.go.dev/database/sql#TxOptions
 95// [format]: https://sqlite.org/lang_datefunc.html#time_values
 96// [collating sequence]: https://sqlite.org/datatype3.html#collating_sequences
 97package driver
 98
 99import (
100	"context"
101	"database/sql"
102	"database/sql/driver"
103	"errors"
104	"fmt"
105	"io"
106	"net/url"
107	"reflect"
108	"strings"
109	"time"
110	"unsafe"
111
112	"github.com/ncruces/go-sqlite3"
113	"github.com/ncruces/go-sqlite3/internal/util"
114)
115
116// This variable can be replaced with -ldflags:
117//
118//	go build -ldflags="-X github.com/ncruces/go-sqlite3/driver.driverName=sqlite"
119var driverName = "sqlite3"
120
121func init() {
122	if driverName != "" {
123		sql.Register(driverName, &SQLite{})
124	}
125}
126
127// Open opens the SQLite database specified by dataSourceName as a [database/sql.DB].
128//
129// Open accepts zero, one, or two callbacks (nil callbacks are ignored).
130// The first callback is called when the driver opens a new connection.
131// The second callback is called before the driver closes a connection.
132// The [sqlite3.Conn] can be used to execute queries, register functions, etc.
133func Open(dataSourceName string, fn ...func(*sqlite3.Conn) error) (*sql.DB, error) {
134	if len(fn) > 2 {
135		return nil, sqlite3.MISUSE
136	}
137	var init, term func(*sqlite3.Conn) error
138	if len(fn) > 1 {
139		term = fn[1]
140	}
141	if len(fn) > 0 {
142		init = fn[0]
143	}
144	c, err := newConnector(dataSourceName, init, term)
145	if err != nil {
146		return nil, err
147	}
148	return sql.OpenDB(c), nil
149}
150
151// SQLite implements [database/sql/driver.Driver].
152type SQLite struct{}
153
154var (
155	// Ensure these interfaces are implemented:
156	_ driver.DriverContext = &SQLite{}
157)
158
159// Open implements [database/sql/driver.Driver].
160func (d *SQLite) Open(name string) (driver.Conn, error) {
161	c, err := newConnector(name, nil, nil)
162	if err != nil {
163		return nil, err
164	}
165	return c.Connect(context.Background())
166}
167
168// OpenConnector implements [database/sql/driver.DriverContext].
169func (d *SQLite) OpenConnector(name string) (driver.Connector, error) {
170	return newConnector(name, nil, nil)
171}
172
173func newConnector(name string, init, term func(*sqlite3.Conn) error) (*connector, error) {
174	c := connector{name: name, init: init, term: term}
175
176	var txlock, timefmt string
177	if strings.HasPrefix(name, "file:") {
178		if _, after, ok := strings.Cut(name, "?"); ok {
179			query, err := url.ParseQuery(after)
180			if err != nil {
181				return nil, err
182			}
183			txlock = query.Get("_txlock")
184			timefmt = query.Get("_timefmt")
185			c.pragmas = query.Has("_pragma")
186		}
187	}
188
189	switch txlock {
190	case "", "deferred", "concurrent", "immediate", "exclusive":
191		c.txLock = txlock
192	default:
193		return nil, fmt.Errorf("sqlite3: invalid _txlock: %s", txlock)
194	}
195
196	switch timefmt {
197	case "":
198		c.tmRead = sqlite3.TimeFormatAuto
199		c.tmWrite = sqlite3.TimeFormatDefault
200	case "sqlite":
201		c.tmRead = sqlite3.TimeFormatAuto
202		c.tmWrite = sqlite3.TimeFormat3
203	case "rfc3339":
204		c.tmRead = sqlite3.TimeFormatDefault
205		c.tmWrite = sqlite3.TimeFormatDefault
206	default:
207		c.tmRead = sqlite3.TimeFormat(timefmt)
208		c.tmWrite = sqlite3.TimeFormat(timefmt)
209	}
210	return &c, nil
211}
212
213type connector struct {
214	init    func(*sqlite3.Conn) error
215	term    func(*sqlite3.Conn) error
216	name    string
217	txLock  string
218	tmRead  sqlite3.TimeFormat
219	tmWrite sqlite3.TimeFormat
220	pragmas bool
221}
222
223func (n *connector) Driver() driver.Driver {
224	return &SQLite{}
225}
226
227func (n *connector) Connect(ctx context.Context) (ret driver.Conn, err error) {
228	c := &conn{
229		txLock:  n.txLock,
230		tmRead:  n.tmRead,
231		tmWrite: n.tmWrite,
232	}
233
234	c.Conn, err = sqlite3.OpenContext(ctx, n.name)
235	if err != nil {
236		return nil, err
237	}
238	defer func() {
239		if ret == nil {
240			c.Close()
241		}
242	}()
243
244	old := c.Conn.SetInterrupt(ctx)
245	defer c.Conn.SetInterrupt(old)
246
247	if !n.pragmas {
248		err = c.Conn.BusyTimeout(time.Minute)
249		if err != nil {
250			return nil, err
251		}
252	}
253	if n.init != nil {
254		err = n.init(c.Conn)
255		if err != nil {
256			return nil, err
257		}
258	}
259	if n.pragmas || n.init != nil {
260		s, _, err := c.Conn.Prepare(`PRAGMA query_only`)
261		if err != nil {
262			return nil, err
263		}
264		defer s.Close()
265		if s.Step() && s.ColumnBool(0) {
266			c.readOnly = '1'
267		} else {
268			c.readOnly = '0'
269		}
270		err = s.Close()
271		if err != nil {
272			return nil, err
273		}
274	}
275	if n.term != nil {
276		err = c.Conn.Trace(sqlite3.TRACE_CLOSE, func(sqlite3.TraceEvent, any, any) error {
277			return n.term(c.Conn)
278		})
279		if err != nil {
280			return nil, err
281		}
282	}
283	return c, nil
284}
285
286// Conn is implemented by the SQLite [database/sql] driver connections.
287//
288// It can be used to access SQLite features like [online backup]:
289//
290//	db, err := driver.Open("temp.db")
291//	if err != nil {
292//		log.Fatal(err)
293//	}
294//	defer db.Close()
295//
296//	conn, err := db.Conn(context.TODO())
297//	if err != nil {
298//		log.Fatal(err)
299//	}
300//	defer conn.Close()
301//
302//	err = conn.Raw(func(driverConn any) error {
303//		conn := driverConn.(driver.Conn)
304//		return conn.Raw().Backup("main", "backup.db")
305//	})
306//	if err != nil {
307//		log.Fatal(err)
308//	}
309//
310// [online backup]: https://sqlite.org/backup.html
311type Conn interface {
312	Raw() *sqlite3.Conn
313	driver.Conn
314	driver.ConnBeginTx
315	driver.ConnPrepareContext
316}
317
318type conn struct {
319	*sqlite3.Conn
320	txLock   string
321	txReset  string
322	tmRead   sqlite3.TimeFormat
323	tmWrite  sqlite3.TimeFormat
324	readOnly byte
325}
326
327var (
328	// Ensure these interfaces are implemented:
329	_ Conn                 = &conn{}
330	_ driver.ExecerContext = &conn{}
331)
332
333func (c *conn) Raw() *sqlite3.Conn {
334	return c.Conn
335}
336
337// Deprecated: use BeginTx instead.
338func (c *conn) Begin() (driver.Tx, error) {
339	// notest
340	return c.BeginTx(context.Background(), driver.TxOptions{})
341}
342
343func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
344	var txLock string
345	switch opts.Isolation {
346	default:
347		return nil, util.IsolationErr
348	case driver.IsolationLevel(sql.LevelLinearizable):
349		txLock = "exclusive"
350	case driver.IsolationLevel(sql.LevelSerializable):
351		txLock = "immediate"
352	case driver.IsolationLevel(sql.LevelDefault):
353		if !opts.ReadOnly {
354			txLock = c.txLock
355		}
356	}
357
358	c.txReset = ``
359	txBegin := `BEGIN ` + txLock
360	if opts.ReadOnly {
361		txBegin += ` ; PRAGMA query_only=on`
362		c.txReset = `; PRAGMA query_only=` + string(c.readOnly)
363	}
364
365	old := c.Conn.SetInterrupt(ctx)
366	defer c.Conn.SetInterrupt(old)
367
368	err := c.Conn.Exec(txBegin)
369	if err != nil {
370		return nil, err
371	}
372	return c, nil
373}
374
375func (c *conn) Commit() error {
376	err := c.Conn.Exec(`COMMIT` + c.txReset)
377	if err != nil && !c.Conn.GetAutocommit() {
378		c.Rollback()
379	}
380	return err
381}
382
383func (c *conn) Rollback() error {
384	// ROLLBACK even if interrupted.
385	old := c.Conn.SetInterrupt(context.Background())
386	defer c.Conn.SetInterrupt(old)
387	return c.Conn.Exec(`ROLLBACK` + c.txReset)
388}
389
390func (c *conn) Prepare(query string) (driver.Stmt, error) {
391	// notest
392	return c.PrepareContext(context.Background(), query)
393}
394
395func (c *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
396	old := c.Conn.SetInterrupt(ctx)
397	defer c.Conn.SetInterrupt(old)
398
399	s, tail, err := c.Conn.Prepare(query)
400	if err != nil {
401		return nil, err
402	}
403	if notWhitespace(tail) {
404		s.Close()
405		return nil, util.TailErr
406	}
407	return &stmt{Stmt: s, tmRead: c.tmRead, tmWrite: c.tmWrite, inputs: -2}, nil
408}
409
410func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
411	if len(args) != 0 {
412		// Slow path.
413		return nil, driver.ErrSkip
414	}
415
416	if savept, ok := ctx.(*saveptCtx); ok {
417		// Called from driver.Savepoint.
418		savept.Savepoint = c.Conn.Savepoint()
419		return resultRowsAffected(0), nil
420	}
421
422	old := c.Conn.SetInterrupt(ctx)
423	defer c.Conn.SetInterrupt(old)
424
425	err := c.Conn.Exec(query)
426	if err != nil {
427		return nil, err
428	}
429
430	return newResult(c.Conn), nil
431}
432
433func (c *conn) CheckNamedValue(arg *driver.NamedValue) error {
434	// Fast path: short circuit argument verification.
435	// Arguments will be rejected by conn.ExecContext.
436	return nil
437}
438
439type stmt struct {
440	*sqlite3.Stmt
441	tmWrite sqlite3.TimeFormat
442	tmRead  sqlite3.TimeFormat
443	inputs  int
444}
445
446var (
447	// Ensure these interfaces are implemented:
448	_ driver.StmtExecContext   = &stmt{}
449	_ driver.StmtQueryContext  = &stmt{}
450	_ driver.NamedValueChecker = &stmt{}
451)
452
453func (s *stmt) NumInput() int {
454	if s.inputs >= -1 {
455		return s.inputs
456	}
457	n := s.Stmt.BindCount()
458	for i := 1; i <= n; i++ {
459		if s.Stmt.BindName(i) != "" {
460			s.inputs = -1
461			return -1
462		}
463	}
464	s.inputs = n
465	return n
466}
467
468// Deprecated: use ExecContext instead.
469func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
470	// notest
471	return s.ExecContext(context.Background(), namedValues(args))
472}
473
474// Deprecated: use QueryContext instead.
475func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
476	// notest
477	return s.QueryContext(context.Background(), namedValues(args))
478}
479
480func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
481	err := s.setupBindings(args)
482	if err != nil {
483		return nil, err
484	}
485
486	old := s.Stmt.Conn().SetInterrupt(ctx)
487	defer s.Stmt.Conn().SetInterrupt(old)
488
489	err = errors.Join(
490		s.Stmt.Exec(),
491		s.Stmt.ClearBindings())
492	if err != nil {
493		return nil, err
494	}
495
496	return newResult(s.Stmt.Conn()), nil
497}
498
499func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
500	err := s.setupBindings(args)
501	if err != nil {
502		return nil, err
503	}
504	return &rows{ctx: ctx, stmt: s}, nil
505}
506
507func (s *stmt) setupBindings(args []driver.NamedValue) (err error) {
508	var ids [3]int
509	for _, arg := range args {
510		ids := ids[:0]
511		if arg.Name == "" {
512			ids = append(ids, arg.Ordinal)
513		} else {
514			for _, prefix := range [...]string{":", "@", "$"} {
515				if id := s.Stmt.BindIndex(prefix + arg.Name); id != 0 {
516					ids = append(ids, id)
517				}
518			}
519		}
520
521		for _, id := range ids {
522			switch a := arg.Value.(type) {
523			case bool:
524				err = s.Stmt.BindBool(id, a)
525			case int:
526				err = s.Stmt.BindInt(id, a)
527			case int64:
528				err = s.Stmt.BindInt64(id, a)
529			case float64:
530				err = s.Stmt.BindFloat(id, a)
531			case string:
532				err = s.Stmt.BindText(id, a)
533			case []byte:
534				err = s.Stmt.BindBlob(id, a)
535			case sqlite3.ZeroBlob:
536				err = s.Stmt.BindZeroBlob(id, int64(a))
537			case time.Time:
538				err = s.Stmt.BindTime(id, a, s.tmWrite)
539			case util.JSON:
540				err = s.Stmt.BindJSON(id, a.Value)
541			case util.PointerUnwrap:
542				err = s.Stmt.BindPointer(id, util.UnwrapPointer(a))
543			case nil:
544				err = s.Stmt.BindNull(id)
545			default:
546				panic(util.AssertErr())
547			}
548			if err != nil {
549				return err
550			}
551		}
552	}
553	return nil
554}
555
556func (s *stmt) CheckNamedValue(arg *driver.NamedValue) error {
557	switch arg.Value.(type) {
558	case bool, int, int64, float64, string, []byte,
559		time.Time, sqlite3.ZeroBlob,
560		util.JSON, util.PointerUnwrap,
561		nil:
562		return nil
563	default:
564		return driver.ErrSkip
565	}
566}
567
568func newResult(c *sqlite3.Conn) driver.Result {
569	rows := c.Changes()
570	if rows != 0 {
571		id := c.LastInsertRowID()
572		if id != 0 {
573			return result{id, rows}
574		}
575	}
576	return resultRowsAffected(rows)
577}
578
579type result struct{ lastInsertId, rowsAffected int64 }
580
581func (r result) LastInsertId() (int64, error) {
582	return r.lastInsertId, nil
583}
584
585func (r result) RowsAffected() (int64, error) {
586	return r.rowsAffected, nil
587}
588
589type resultRowsAffected int64
590
591func (r resultRowsAffected) LastInsertId() (int64, error) {
592	return 0, nil
593}
594
595func (r resultRowsAffected) RowsAffected() (int64, error) {
596	return int64(r), nil
597}
598
599type rows struct {
600	ctx context.Context
601	*stmt
602	names []string
603	types []string
604	nulls []bool
605	scans []scantype
606}
607
608type scantype byte
609
610const (
611	_ANY  scantype = iota
612	_INT  scantype = scantype(sqlite3.INTEGER)
613	_REAL scantype = scantype(sqlite3.FLOAT)
614	_TEXT scantype = scantype(sqlite3.TEXT)
615	_BLOB scantype = scantype(sqlite3.BLOB)
616	_NULL scantype = scantype(sqlite3.NULL)
617	_BOOL scantype = iota
618	_TIME
619)
620
621func scanFromDecl(decl string) scantype {
622	// These types are only used before we have rows,
623	// and otherwise as type hints.
624	// The first few ensure STRICT tables are strictly typed.
625	// The other two are type hints for booleans and time.
626	switch decl {
627	case "INT", "INTEGER":
628		return _INT
629	case "REAL":
630		return _REAL
631	case "TEXT":
632		return _TEXT
633	case "BLOB":
634		return _BLOB
635	case "BOOLEAN":
636		return _BOOL
637	case "DATE", "TIME", "DATETIME", "TIMESTAMP":
638		return _TIME
639	}
640	return _ANY
641}
642
643var (
644	// Ensure these interfaces are implemented:
645	_ driver.RowsColumnTypeDatabaseTypeName = &rows{}
646	_ driver.RowsColumnTypeNullable         = &rows{}
647)
648
649func (r *rows) Close() error {
650	return errors.Join(
651		r.Stmt.Reset(),
652		r.Stmt.ClearBindings())
653}
654
655func (r *rows) Columns() []string {
656	if r.names == nil {
657		count := r.Stmt.ColumnCount()
658		names := make([]string, count)
659		for i := range names {
660			names[i] = r.Stmt.ColumnName(i)
661		}
662		r.names = names
663	}
664	return r.names
665}
666
667func (r *rows) scanType(index int) scantype {
668	if r.scans == nil {
669		count := r.Stmt.ColumnCount()
670		scans := make([]scantype, count)
671		for i := range scans {
672			scans[i] = scanFromDecl(strings.ToUpper(r.Stmt.ColumnDeclType(i)))
673		}
674		r.scans = scans
675	}
676	return r.scans[index]
677}
678
679func (r *rows) loadColumnMetadata() {
680	if r.nulls == nil {
681		count := r.Stmt.ColumnCount()
682		nulls := make([]bool, count)
683		types := make([]string, count)
684		scans := make([]scantype, count)
685		for i := range nulls {
686			if col := r.Stmt.ColumnOriginName(i); col != "" {
687				types[i], _, nulls[i], _, _, _ = r.Stmt.Conn().TableColumnMetadata(
688					r.Stmt.ColumnDatabaseName(i),
689					r.Stmt.ColumnTableName(i),
690					col)
691				types[i] = strings.ToUpper(types[i])
692				scans[i] = scanFromDecl(types[i])
693			}
694		}
695		r.nulls = nulls
696		r.types = types
697		r.scans = scans
698	}
699}
700
701func (r *rows) ColumnTypeDatabaseTypeName(index int) string {
702	r.loadColumnMetadata()
703	decl := r.types[index]
704	if len := len(decl); len > 0 && decl[len-1] == ')' {
705		if i := strings.LastIndexByte(decl, '('); i >= 0 {
706			decl = decl[:i]
707		}
708	}
709	return strings.TrimSpace(decl)
710}
711
712func (r *rows) ColumnTypeNullable(index int) (nullable, ok bool) {
713	r.loadColumnMetadata()
714	if r.nulls[index] {
715		return false, true
716	}
717	return true, false
718}
719
720func (r *rows) ColumnTypeScanType(index int) (typ reflect.Type) {
721	r.loadColumnMetadata()
722	scan := r.scans[index]
723
724	if r.Stmt.Busy() {
725		// SQLite is dynamically typed and we now have a row.
726		// Always use the type of the value itself,
727		// unless the scan type is more specific
728		// and can scan the actual value.
729		val := scantype(r.Stmt.ColumnType(index))
730		useValType := true
731		switch {
732		case scan == _TIME && val != _BLOB && val != _NULL:
733			t := r.Stmt.ColumnTime(index, r.tmRead)
734			useValType = t == time.Time{}
735		case scan == _BOOL && val == _INT:
736			i := r.Stmt.ColumnInt64(index)
737			useValType = i != 0 && i != 1
738		case scan == _BLOB && val == _NULL:
739			useValType = false
740		}
741		if useValType {
742			scan = val
743		}
744	}
745
746	switch scan {
747	case _INT:
748		return reflect.TypeFor[int64]()
749	case _REAL:
750		return reflect.TypeFor[float64]()
751	case _TEXT:
752		return reflect.TypeFor[string]()
753	case _BLOB:
754		return reflect.TypeFor[[]byte]()
755	case _BOOL:
756		return reflect.TypeFor[bool]()
757	case _TIME:
758		return reflect.TypeFor[time.Time]()
759	default:
760		return reflect.TypeFor[any]()
761	}
762}
763
764func (r *rows) Next(dest []driver.Value) error {
765	old := r.Stmt.Conn().SetInterrupt(r.ctx)
766	defer r.Stmt.Conn().SetInterrupt(old)
767
768	if !r.Stmt.Step() {
769		if err := r.Stmt.Err(); err != nil {
770			return err
771		}
772		return io.EOF
773	}
774
775	data := unsafe.Slice((*any)(unsafe.SliceData(dest)), len(dest))
776	if err := r.Stmt.ColumnsRaw(data...); err != nil {
777		return err
778	}
779	for i := range dest {
780		scan := r.scanType(i)
781		switch v := dest[i].(type) {
782		case int64:
783			if scan == _BOOL {
784				switch v {
785				case 1:
786					dest[i] = true
787				case 0:
788					dest[i] = false
789				}
790				continue
791			}
792		case []byte:
793			if len(v) == cap(v) { // a BLOB
794				continue
795			}
796			if scan != _TEXT {
797				switch r.tmWrite {
798				case "", time.RFC3339, time.RFC3339Nano:
799					t, ok := maybeTime(v)
800					if ok {
801						dest[i] = t
802						continue
803					}
804				}
805			}
806			dest[i] = string(v)
807		case float64:
808			break
809		default:
810			continue
811		}
812		if scan == _TIME {
813			t, err := r.tmRead.Decode(dest[i])
814			if err == nil {
815				dest[i] = t
816				continue
817			}
818		}
819	}
820	return nil
821}