stmt.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// Stmt is a prepared statement object.
 13//
 14// https://sqlite.org/c3ref/stmt.html
 15type Stmt struct {
 16	c      *Conn
 17	err    error
 18	sql    string
 19	handle ptr_t
 20}
 21
 22// Close destroys the prepared statement object.
 23//
 24// It is safe to close a nil, zero or closed Stmt.
 25//
 26// https://sqlite.org/c3ref/finalize.html
 27func (s *Stmt) Close() error {
 28	if s == nil || s.handle == 0 {
 29		return nil
 30	}
 31
 32	rc := res_t(s.c.call("sqlite3_finalize", stk_t(s.handle)))
 33	stmts := s.c.stmts
 34	for i := range stmts {
 35		if s == stmts[i] {
 36			l := len(stmts) - 1
 37			stmts[i] = stmts[l]
 38			stmts[l] = nil
 39			s.c.stmts = stmts[:l]
 40			break
 41		}
 42	}
 43
 44	s.handle = 0
 45	return s.c.error(rc)
 46}
 47
 48// Conn returns the database connection to which the prepared statement belongs.
 49//
 50// https://sqlite.org/c3ref/db_handle.html
 51func (s *Stmt) Conn() *Conn {
 52	return s.c
 53}
 54
 55// SQL returns the SQL text used to create the prepared statement.
 56//
 57// https://sqlite.org/c3ref/expanded_sql.html
 58func (s *Stmt) SQL() string {
 59	return s.sql
 60}
 61
 62// ExpandedSQL returns the SQL text of the prepared statement
 63// with bound parameters expanded.
 64//
 65// https://sqlite.org/c3ref/expanded_sql.html
 66func (s *Stmt) ExpandedSQL() string {
 67	ptr := ptr_t(s.c.call("sqlite3_expanded_sql", stk_t(s.handle)))
 68	sql := util.ReadString(s.c.mod, ptr, _MAX_SQL_LENGTH)
 69	s.c.free(ptr)
 70	return sql
 71}
 72
 73// ReadOnly returns true if and only if the statement
 74// makes no direct changes to the content of the database file.
 75//
 76// https://sqlite.org/c3ref/stmt_readonly.html
 77func (s *Stmt) ReadOnly() bool {
 78	b := int32(s.c.call("sqlite3_stmt_readonly", stk_t(s.handle)))
 79	return b != 0
 80}
 81
 82// Reset resets the prepared statement object.
 83//
 84// https://sqlite.org/c3ref/reset.html
 85func (s *Stmt) Reset() error {
 86	rc := res_t(s.c.call("sqlite3_reset", stk_t(s.handle)))
 87	s.err = nil
 88	return s.c.error(rc)
 89}
 90
 91// Busy determines if a prepared statement has been reset.
 92//
 93// https://sqlite.org/c3ref/stmt_busy.html
 94func (s *Stmt) Busy() bool {
 95	rc := res_t(s.c.call("sqlite3_stmt_busy", stk_t(s.handle)))
 96	return rc != 0
 97}
 98
 99// Step evaluates the SQL statement.
100// If the SQL statement being executed returns any data,
101// then true is returned each time a new row of data is ready for processing by the caller.
102// The values may be accessed using the Column access functions.
103// Step is called again to retrieve the next row of data.
104// If an error has occurred, Step returns false;
105// call [Stmt.Err] or [Stmt.Reset] to get the error.
106//
107// https://sqlite.org/c3ref/step.html
108func (s *Stmt) Step() bool {
109	if s.c.interrupt.Err() != nil {
110		s.err = INTERRUPT
111		return false
112	}
113	return s.step()
114}
115
116func (s *Stmt) step() bool {
117	rc := res_t(s.c.call("sqlite3_step", stk_t(s.handle)))
118	switch rc {
119	case _ROW:
120		s.err = nil
121		return true
122	case _DONE:
123		s.err = nil
124	default:
125		s.err = s.c.error(rc)
126	}
127	return false
128}
129
130// Err gets the last error occurred during [Stmt.Step].
131// Err returns nil after [Stmt.Reset] is called.
132//
133// https://sqlite.org/c3ref/step.html
134func (s *Stmt) Err() error {
135	return s.err
136}
137
138// Exec is a convenience function that repeatedly calls [Stmt.Step] until it returns false,
139// then calls [Stmt.Reset] to reset the statement and get any error that occurred.
140func (s *Stmt) Exec() error {
141	if s.c.interrupt.Err() != nil {
142		return INTERRUPT
143	}
144	// TODO: implement this in C.
145	for s.step() {
146	}
147	return s.Reset()
148}
149
150// Status monitors the performance characteristics of prepared statements.
151//
152// https://sqlite.org/c3ref/stmt_status.html
153func (s *Stmt) Status(op StmtStatus, reset bool) int {
154	if op > STMTSTATUS_FILTER_HIT && op != STMTSTATUS_MEMUSED {
155		return 0
156	}
157	var i int32
158	if reset {
159		i = 1
160	}
161	n := int32(s.c.call("sqlite3_stmt_status", stk_t(s.handle),
162		stk_t(op), stk_t(i)))
163	return int(n)
164}
165
166// ClearBindings resets all bindings on the prepared statement.
167//
168// https://sqlite.org/c3ref/clear_bindings.html
169func (s *Stmt) ClearBindings() error {
170	rc := res_t(s.c.call("sqlite3_clear_bindings", stk_t(s.handle)))
171	return s.c.error(rc)
172}
173
174// BindCount returns the number of SQL parameters in the prepared statement.
175//
176// https://sqlite.org/c3ref/bind_parameter_count.html
177func (s *Stmt) BindCount() int {
178	n := int32(s.c.call("sqlite3_bind_parameter_count",
179		stk_t(s.handle)))
180	return int(n)
181}
182
183// BindIndex returns the index of a parameter in the prepared statement
184// given its name.
185//
186// https://sqlite.org/c3ref/bind_parameter_index.html
187func (s *Stmt) BindIndex(name string) int {
188	defer s.c.arena.mark()()
189	namePtr := s.c.arena.string(name)
190	i := int32(s.c.call("sqlite3_bind_parameter_index",
191		stk_t(s.handle), stk_t(namePtr)))
192	return int(i)
193}
194
195// BindName returns the name of a parameter in the prepared statement.
196// The leftmost SQL parameter has an index of 1.
197//
198// https://sqlite.org/c3ref/bind_parameter_name.html
199func (s *Stmt) BindName(param int) string {
200	ptr := ptr_t(s.c.call("sqlite3_bind_parameter_name",
201		stk_t(s.handle), stk_t(param)))
202	if ptr == 0 {
203		return ""
204	}
205	return util.ReadString(s.c.mod, ptr, _MAX_NAME)
206}
207
208// BindBool binds a bool to the prepared statement.
209// The leftmost SQL parameter has an index of 1.
210// SQLite does not have a separate boolean storage class.
211// Instead, boolean values are stored as integers 0 (false) and 1 (true).
212//
213// https://sqlite.org/c3ref/bind_blob.html
214func (s *Stmt) BindBool(param int, value bool) error {
215	var i int64
216	if value {
217		i = 1
218	}
219	return s.BindInt64(param, i)
220}
221
222// BindInt binds an int to the prepared statement.
223// The leftmost SQL parameter has an index of 1.
224//
225// https://sqlite.org/c3ref/bind_blob.html
226func (s *Stmt) BindInt(param int, value int) error {
227	return s.BindInt64(param, int64(value))
228}
229
230// BindInt64 binds an int64 to the prepared statement.
231// The leftmost SQL parameter has an index of 1.
232//
233// https://sqlite.org/c3ref/bind_blob.html
234func (s *Stmt) BindInt64(param int, value int64) error {
235	rc := res_t(s.c.call("sqlite3_bind_int64",
236		stk_t(s.handle), stk_t(param), stk_t(value)))
237	return s.c.error(rc)
238}
239
240// BindFloat binds a float64 to the prepared statement.
241// The leftmost SQL parameter has an index of 1.
242//
243// https://sqlite.org/c3ref/bind_blob.html
244func (s *Stmt) BindFloat(param int, value float64) error {
245	rc := res_t(s.c.call("sqlite3_bind_double",
246		stk_t(s.handle), stk_t(param),
247		stk_t(math.Float64bits(value))))
248	return s.c.error(rc)
249}
250
251// BindText binds a string to the prepared statement.
252// The leftmost SQL parameter has an index of 1.
253//
254// https://sqlite.org/c3ref/bind_blob.html
255func (s *Stmt) BindText(param int, value string) error {
256	if len(value) > _MAX_LENGTH {
257		return TOOBIG
258	}
259	ptr := s.c.newString(value)
260	rc := res_t(s.c.call("sqlite3_bind_text_go",
261		stk_t(s.handle), stk_t(param),
262		stk_t(ptr), stk_t(len(value))))
263	return s.c.error(rc)
264}
265
266// BindRawText binds a []byte to the prepared statement as text.
267// The leftmost SQL parameter has an index of 1.
268//
269// https://sqlite.org/c3ref/bind_blob.html
270func (s *Stmt) BindRawText(param int, value []byte) error {
271	if len(value) > _MAX_LENGTH {
272		return TOOBIG
273	}
274	if len(value) == 0 {
275		return s.BindText(param, "")
276	}
277	ptr := s.c.newBytes(value)
278	rc := res_t(s.c.call("sqlite3_bind_text_go",
279		stk_t(s.handle), stk_t(param),
280		stk_t(ptr), stk_t(len(value))))
281	return s.c.error(rc)
282}
283
284// BindBlob binds a []byte to the prepared statement.
285// The leftmost SQL parameter has an index of 1.
286//
287// https://sqlite.org/c3ref/bind_blob.html
288func (s *Stmt) BindBlob(param int, value []byte) error {
289	if len(value) > _MAX_LENGTH {
290		return TOOBIG
291	}
292	if len(value) == 0 {
293		return s.BindZeroBlob(param, 0)
294	}
295	ptr := s.c.newBytes(value)
296	rc := res_t(s.c.call("sqlite3_bind_blob_go",
297		stk_t(s.handle), stk_t(param),
298		stk_t(ptr), stk_t(len(value))))
299	return s.c.error(rc)
300}
301
302// BindZeroBlob binds a zero-filled, length n BLOB to the prepared statement.
303// The leftmost SQL parameter has an index of 1.
304//
305// https://sqlite.org/c3ref/bind_blob.html
306func (s *Stmt) BindZeroBlob(param int, n int64) error {
307	rc := res_t(s.c.call("sqlite3_bind_zeroblob64",
308		stk_t(s.handle), stk_t(param), stk_t(n)))
309	return s.c.error(rc)
310}
311
312// BindNull binds a NULL to the prepared statement.
313// The leftmost SQL parameter has an index of 1.
314//
315// https://sqlite.org/c3ref/bind_blob.html
316func (s *Stmt) BindNull(param int) error {
317	rc := res_t(s.c.call("sqlite3_bind_null",
318		stk_t(s.handle), stk_t(param)))
319	return s.c.error(rc)
320}
321
322// BindTime binds a [time.Time] to the prepared statement.
323// The leftmost SQL parameter has an index of 1.
324//
325// https://sqlite.org/c3ref/bind_blob.html
326func (s *Stmt) BindTime(param int, value time.Time, format TimeFormat) error {
327	switch format {
328	case TimeFormatDefault, TimeFormatAuto, time.RFC3339Nano:
329		return s.bindRFC3339Nano(param, value)
330	}
331	switch v := format.Encode(value).(type) {
332	case string:
333		return s.BindText(param, v)
334	case int64:
335		return s.BindInt64(param, v)
336	case float64:
337		return s.BindFloat(param, v)
338	default:
339		panic(util.AssertErr())
340	}
341}
342
343func (s *Stmt) bindRFC3339Nano(param int, value time.Time) error {
344	const maxlen = int64(len(time.RFC3339Nano)) + 5
345
346	ptr := s.c.new(maxlen)
347	buf := util.View(s.c.mod, ptr, maxlen)
348	buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
349
350	rc := res_t(s.c.call("sqlite3_bind_text_go",
351		stk_t(s.handle), stk_t(param),
352		stk_t(ptr), stk_t(len(buf))))
353	return s.c.error(rc)
354}
355
356// BindPointer binds a NULL to the prepared statement, just like [Stmt.BindNull],
357// but it also associates ptr with that NULL value such that it can be retrieved
358// within an application-defined SQL function using [Value.Pointer].
359// The leftmost SQL parameter has an index of 1.
360//
361// https://sqlite.org/c3ref/bind_blob.html
362func (s *Stmt) BindPointer(param int, ptr any) error {
363	valPtr := util.AddHandle(s.c.ctx, ptr)
364	rc := res_t(s.c.call("sqlite3_bind_pointer_go",
365		stk_t(s.handle), stk_t(param), stk_t(valPtr)))
366	return s.c.error(rc)
367}
368
369// BindJSON binds the JSON encoding of value to the prepared statement.
370// The leftmost SQL parameter has an index of 1.
371//
372// https://sqlite.org/c3ref/bind_blob.html
373func (s *Stmt) BindJSON(param int, value any) error {
374	data, err := json.Marshal(value)
375	if err != nil {
376		return err
377	}
378	return s.BindRawText(param, data)
379}
380
381// BindValue binds a copy of value to the prepared statement.
382// The leftmost SQL parameter has an index of 1.
383//
384// https://sqlite.org/c3ref/bind_blob.html
385func (s *Stmt) BindValue(param int, value Value) error {
386	if value.c != s.c {
387		return MISUSE
388	}
389	rc := res_t(s.c.call("sqlite3_bind_value",
390		stk_t(s.handle), stk_t(param), stk_t(value.handle)))
391	return s.c.error(rc)
392}
393
394// DataCount resets the number of columns in a result set.
395//
396// https://sqlite.org/c3ref/data_count.html
397func (s *Stmt) DataCount() int {
398	n := int32(s.c.call("sqlite3_data_count",
399		stk_t(s.handle)))
400	return int(n)
401}
402
403// ColumnCount returns the number of columns in a result set.
404//
405// https://sqlite.org/c3ref/column_count.html
406func (s *Stmt) ColumnCount() int {
407	n := int32(s.c.call("sqlite3_column_count",
408		stk_t(s.handle)))
409	return int(n)
410}
411
412// ColumnName returns the name of the result column.
413// The leftmost column of the result set has the index 0.
414//
415// https://sqlite.org/c3ref/column_name.html
416func (s *Stmt) ColumnName(col int) string {
417	ptr := ptr_t(s.c.call("sqlite3_column_name",
418		stk_t(s.handle), stk_t(col)))
419	if ptr == 0 {
420		panic(util.OOMErr)
421	}
422	return util.ReadString(s.c.mod, ptr, _MAX_NAME)
423}
424
425// ColumnType returns the initial [Datatype] of the result column.
426// The leftmost column of the result set has the index 0.
427//
428// https://sqlite.org/c3ref/column_blob.html
429func (s *Stmt) ColumnType(col int) Datatype {
430	return Datatype(s.c.call("sqlite3_column_type",
431		stk_t(s.handle), stk_t(col)))
432}
433
434// ColumnDeclType returns the declared datatype of the result column.
435// The leftmost column of the result set has the index 0.
436//
437// https://sqlite.org/c3ref/column_decltype.html
438func (s *Stmt) ColumnDeclType(col int) string {
439	ptr := ptr_t(s.c.call("sqlite3_column_decltype",
440		stk_t(s.handle), stk_t(col)))
441	if ptr == 0 {
442		return ""
443	}
444	return util.ReadString(s.c.mod, ptr, _MAX_NAME)
445}
446
447// ColumnDatabaseName returns the name of the database
448// that is the origin of a particular result column.
449// The leftmost column of the result set has the index 0.
450//
451// https://sqlite.org/c3ref/column_database_name.html
452func (s *Stmt) ColumnDatabaseName(col int) string {
453	ptr := ptr_t(s.c.call("sqlite3_column_database_name",
454		stk_t(s.handle), stk_t(col)))
455	if ptr == 0 {
456		return ""
457	}
458	return util.ReadString(s.c.mod, ptr, _MAX_NAME)
459}
460
461// ColumnTableName returns the name of the table
462// that is the origin of a particular result column.
463// The leftmost column of the result set has the index 0.
464//
465// https://sqlite.org/c3ref/column_database_name.html
466func (s *Stmt) ColumnTableName(col int) string {
467	ptr := ptr_t(s.c.call("sqlite3_column_table_name",
468		stk_t(s.handle), stk_t(col)))
469	if ptr == 0 {
470		return ""
471	}
472	return util.ReadString(s.c.mod, ptr, _MAX_NAME)
473}
474
475// ColumnOriginName returns the name of the table column
476// that is the origin of a particular result column.
477// The leftmost column of the result set has the index 0.
478//
479// https://sqlite.org/c3ref/column_database_name.html
480func (s *Stmt) ColumnOriginName(col int) string {
481	ptr := ptr_t(s.c.call("sqlite3_column_origin_name",
482		stk_t(s.handle), stk_t(col)))
483	if ptr == 0 {
484		return ""
485	}
486	return util.ReadString(s.c.mod, ptr, _MAX_NAME)
487}
488
489// ColumnBool returns the value of the result column as a bool.
490// The leftmost column of the result set has the index 0.
491// SQLite does not have a separate boolean storage class.
492// Instead, boolean values are retrieved as numbers,
493// with 0 converted to false and any other value to true.
494//
495// https://sqlite.org/c3ref/column_blob.html
496func (s *Stmt) ColumnBool(col int) bool {
497	return s.ColumnFloat(col) != 0
498}
499
500// ColumnInt returns the value of the result column as an int.
501// The leftmost column of the result set has the index 0.
502//
503// https://sqlite.org/c3ref/column_blob.html
504func (s *Stmt) ColumnInt(col int) int {
505	return int(s.ColumnInt64(col))
506}
507
508// ColumnInt64 returns the value of the result column as an int64.
509// The leftmost column of the result set has the index 0.
510//
511// https://sqlite.org/c3ref/column_blob.html
512func (s *Stmt) ColumnInt64(col int) int64 {
513	return int64(s.c.call("sqlite3_column_int64",
514		stk_t(s.handle), stk_t(col)))
515}
516
517// ColumnFloat returns the value of the result column as a float64.
518// The leftmost column of the result set has the index 0.
519//
520// https://sqlite.org/c3ref/column_blob.html
521func (s *Stmt) ColumnFloat(col int) float64 {
522	f := uint64(s.c.call("sqlite3_column_double",
523		stk_t(s.handle), stk_t(col)))
524	return math.Float64frombits(f)
525}
526
527// ColumnTime returns the value of the result column as a [time.Time].
528// The leftmost column of the result set has the index 0.
529//
530// https://sqlite.org/c3ref/column_blob.html
531func (s *Stmt) ColumnTime(col int, format TimeFormat) time.Time {
532	var v any
533	switch s.ColumnType(col) {
534	case INTEGER:
535		v = s.ColumnInt64(col)
536	case FLOAT:
537		v = s.ColumnFloat(col)
538	case TEXT, BLOB:
539		v = s.ColumnText(col)
540	case NULL:
541		return time.Time{}
542	default:
543		panic(util.AssertErr())
544	}
545	t, err := format.Decode(v)
546	if err != nil {
547		s.err = err
548	}
549	return t
550}
551
552// ColumnText returns the value of the result column as a string.
553// The leftmost column of the result set has the index 0.
554//
555// https://sqlite.org/c3ref/column_blob.html
556func (s *Stmt) ColumnText(col int) string {
557	return string(s.ColumnRawText(col))
558}
559
560// ColumnBlob appends to buf and returns
561// the value of the result column as a []byte.
562// The leftmost column of the result set has the index 0.
563//
564// https://sqlite.org/c3ref/column_blob.html
565func (s *Stmt) ColumnBlob(col int, buf []byte) []byte {
566	return append(buf, s.ColumnRawBlob(col)...)
567}
568
569// ColumnRawText returns the value of the result column as a []byte.
570// The []byte is owned by SQLite and may be invalidated by
571// subsequent calls to [Stmt] methods.
572// The leftmost column of the result set has the index 0.
573//
574// https://sqlite.org/c3ref/column_blob.html
575func (s *Stmt) ColumnRawText(col int) []byte {
576	ptr := ptr_t(s.c.call("sqlite3_column_text",
577		stk_t(s.handle), stk_t(col)))
578	return s.columnRawBytes(col, ptr, 1)
579}
580
581// ColumnRawBlob returns the value of the result column as a []byte.
582// The []byte is owned by SQLite and may be invalidated by
583// subsequent calls to [Stmt] methods.
584// The leftmost column of the result set has the index 0.
585//
586// https://sqlite.org/c3ref/column_blob.html
587func (s *Stmt) ColumnRawBlob(col int) []byte {
588	ptr := ptr_t(s.c.call("sqlite3_column_blob",
589		stk_t(s.handle), stk_t(col)))
590	return s.columnRawBytes(col, ptr, 0)
591}
592
593func (s *Stmt) columnRawBytes(col int, ptr ptr_t, nul int32) []byte {
594	if ptr == 0 {
595		rc := res_t(s.c.call("sqlite3_errcode", stk_t(s.c.handle)))
596		if rc != _ROW && rc != _DONE {
597			s.err = s.c.error(rc)
598		}
599		return nil
600	}
601
602	n := int32(s.c.call("sqlite3_column_bytes",
603		stk_t(s.handle), stk_t(col)))
604	return util.View(s.c.mod, ptr, int64(n+nul))[:n]
605}
606
607// ColumnJSON parses the JSON-encoded value of the result column
608// and stores it in the value pointed to by ptr.
609// The leftmost column of the result set has the index 0.
610//
611// https://sqlite.org/c3ref/column_blob.html
612func (s *Stmt) ColumnJSON(col int, ptr any) error {
613	var data []byte
614	switch s.ColumnType(col) {
615	case NULL:
616		data = []byte("null")
617	case TEXT:
618		data = s.ColumnRawText(col)
619	case BLOB:
620		data = s.ColumnRawBlob(col)
621	case INTEGER:
622		data = strconv.AppendInt(nil, s.ColumnInt64(col), 10)
623	case FLOAT:
624		data = util.AppendNumber(nil, s.ColumnFloat(col))
625	default:
626		panic(util.AssertErr())
627	}
628	return json.Unmarshal(data, ptr)
629}
630
631// ColumnValue returns the unprotected value of the result column.
632// The leftmost column of the result set has the index 0.
633//
634// https://sqlite.org/c3ref/column_blob.html
635func (s *Stmt) ColumnValue(col int) Value {
636	ptr := ptr_t(s.c.call("sqlite3_column_value",
637		stk_t(s.handle), stk_t(col)))
638	return Value{
639		c:      s.c,
640		unprot: true,
641		handle: ptr,
642	}
643}
644
645// Columns populates result columns into the provided slice.
646// The slice must have [Stmt.ColumnCount] length.
647//
648// [INTEGER] columns will be retrieved as int64 values,
649// [FLOAT] as float64, [NULL] as nil,
650// [TEXT] as string, and [BLOB] as []byte.
651func (s *Stmt) Columns(dest ...any) error {
652	types, ptr, err := s.columns(int64(len(dest)))
653	if err != nil {
654		return err
655	}
656
657	// Avoid bounds checks on types below.
658	if len(types) != len(dest) {
659		panic(util.AssertErr())
660	}
661
662	for i := range dest {
663		switch types[i] {
664		case byte(INTEGER):
665			dest[i] = util.Read64[int64](s.c.mod, ptr)
666		case byte(FLOAT):
667			dest[i] = util.ReadFloat64(s.c.mod, ptr)
668		case byte(NULL):
669			dest[i] = nil
670		case byte(TEXT):
671			len := util.Read32[int32](s.c.mod, ptr+4)
672			if len != 0 {
673				ptr := util.Read32[ptr_t](s.c.mod, ptr)
674				buf := util.View(s.c.mod, ptr, int64(len))
675				dest[i] = string(buf)
676			} else {
677				dest[i] = ""
678			}
679		case byte(BLOB):
680			len := util.Read32[int32](s.c.mod, ptr+4)
681			if len != 0 {
682				ptr := util.Read32[ptr_t](s.c.mod, ptr)
683				buf := util.View(s.c.mod, ptr, int64(len))
684				tmp, _ := dest[i].([]byte)
685				dest[i] = append(tmp[:0], buf...)
686			} else {
687				dest[i], _ = dest[i].([]byte)
688			}
689		}
690		ptr += 8
691	}
692	return nil
693}
694
695// ColumnsRaw populates result columns into the provided slice.
696// The slice must have [Stmt.ColumnCount] length.
697//
698// [INTEGER] columns will be retrieved as int64 values,
699// [FLOAT] as float64, [NULL] as nil,
700// [TEXT] and [BLOB] as []byte.
701// Any []byte are owned by SQLite and may be invalidated by
702// subsequent calls to [Stmt] methods.
703func (s *Stmt) ColumnsRaw(dest ...any) error {
704	types, ptr, err := s.columns(int64(len(dest)))
705	if err != nil {
706		return err
707	}
708
709	// Avoid bounds checks on types below.
710	if len(types) != len(dest) {
711		panic(util.AssertErr())
712	}
713
714	for i := range dest {
715		switch types[i] {
716		case byte(INTEGER):
717			dest[i] = util.Read64[int64](s.c.mod, ptr)
718		case byte(FLOAT):
719			dest[i] = util.ReadFloat64(s.c.mod, ptr)
720		case byte(NULL):
721			dest[i] = nil
722		default:
723			len := util.Read32[int32](s.c.mod, ptr+4)
724			if len == 0 && types[i] == byte(BLOB) {
725				dest[i] = []byte{}
726			} else {
727				cap := len
728				if types[i] == byte(TEXT) {
729					cap++
730				}
731				ptr := util.Read32[ptr_t](s.c.mod, ptr)
732				buf := util.View(s.c.mod, ptr, int64(cap))[:len]
733				dest[i] = buf
734			}
735		}
736		ptr += 8
737	}
738	return nil
739}
740
741func (s *Stmt) columns(count int64) ([]byte, ptr_t, error) {
742	defer s.c.arena.mark()()
743	typePtr := s.c.arena.new(count)
744	dataPtr := s.c.arena.new(count * 8)
745
746	rc := res_t(s.c.call("sqlite3_columns_go",
747		stk_t(s.handle), stk_t(count), stk_t(typePtr), stk_t(dataPtr)))
748	if rc == res_t(MISUSE) {
749		return nil, 0, MISUSE
750	}
751	if err := s.c.error(rc); err != nil {
752		return nil, 0, err
753	}
754
755	return util.View(s.c.mod, typePtr, count), dataPtr, nil
756}