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}