aim-sqlite3 2.9.6.1.rc1-aarch64-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,755 @@
1
+ #include <sqlite3_ruby.h>
2
+
3
+ #define REQUIRE_OPEN_STMT(_ctxt) \
4
+ if (!_ctxt->st) \
5
+ rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a closed statement");
6
+
7
+ #define REQUIRE_LIVE_DB(_ctxt) \
8
+ if (_ctxt->db->flags & SQLITE3_RB_DATABASE_DISCARDED) \
9
+ rb_raise(rb_path2class("SQLite3::Exception"), "cannot use a statement associated with a discarded database");
10
+
11
+ VALUE cSqlite3Statement;
12
+
13
+ static void
14
+ statement_deallocate(void *data)
15
+ {
16
+ sqlite3StmtRubyPtr s = (sqlite3StmtRubyPtr)data;
17
+
18
+ if (s->st) {
19
+ sqlite3_finalize(s->st);
20
+ }
21
+
22
+ xfree(data);
23
+ }
24
+
25
+ static size_t
26
+ statement_memsize(const void *data)
27
+ {
28
+ const sqlite3StmtRubyPtr s = (const sqlite3StmtRubyPtr)data;
29
+ // NB: can't account for s->st because the type is incomplete.
30
+ return sizeof(*s);
31
+ }
32
+
33
+ static const rb_data_type_t statement_type = {
34
+ "SQLite3::Backup",
35
+ {
36
+ NULL,
37
+ statement_deallocate,
38
+ statement_memsize,
39
+ },
40
+ 0,
41
+ 0,
42
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
43
+ };
44
+
45
+ static VALUE
46
+ allocate(VALUE klass)
47
+ {
48
+ sqlite3StmtRubyPtr ctx;
49
+ return TypedData_Make_Struct(klass, sqlite3StmtRuby, &statement_type, ctx);
50
+ }
51
+
52
+ static VALUE
53
+ prepare(VALUE self, VALUE db, VALUE sql)
54
+ {
55
+ sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
56
+ sqlite3StmtRubyPtr ctx;
57
+ const char *tail = NULL;
58
+ int status;
59
+
60
+ StringValue(sql);
61
+
62
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
63
+
64
+ /* Dereferencing a pointer to the database struct will be faster than accessing it through the
65
+ * instance variable @connection. The struct pointer is guaranteed to be live because instance
66
+ * variable will keep it from being GCed. */
67
+ ctx->db = db_ctx;
68
+
69
+ #ifdef HAVE_SQLITE3_PREPARE_V2
70
+ status = sqlite3_prepare_v2(
71
+ #else
72
+ status = sqlite3_prepare(
73
+ #endif
74
+ db_ctx->db,
75
+ (const char *)StringValuePtr(sql),
76
+ (int)RSTRING_LEN(sql),
77
+ &ctx->st,
78
+ &tail
79
+ );
80
+
81
+ CHECK_PREPARE(db_ctx->db, status, StringValuePtr(sql));
82
+ timespecclear(&db_ctx->stmt_deadline);
83
+
84
+ return rb_utf8_str_new_cstr(tail);
85
+ }
86
+
87
+ /* call-seq: stmt.close
88
+ *
89
+ * Closes the statement by finalizing the underlying statement
90
+ * handle. The statement must not be used after being closed.
91
+ */
92
+ static VALUE
93
+ sqlite3_rb_close(VALUE self)
94
+ {
95
+ sqlite3StmtRubyPtr ctx;
96
+
97
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
98
+
99
+ REQUIRE_OPEN_STMT(ctx);
100
+
101
+ sqlite3_finalize(ctx->st);
102
+ ctx->st = NULL;
103
+
104
+ return self;
105
+ }
106
+
107
+ /* call-seq: stmt.closed?
108
+ *
109
+ * Returns true if the statement has been closed.
110
+ */
111
+ static VALUE
112
+ closed_p(VALUE self)
113
+ {
114
+ sqlite3StmtRubyPtr ctx;
115
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
116
+
117
+ if (!ctx->st) { return Qtrue; }
118
+
119
+ return Qfalse;
120
+ }
121
+
122
+ static VALUE
123
+ step(VALUE self)
124
+ {
125
+ sqlite3StmtRubyPtr ctx;
126
+ sqlite3_stmt *stmt;
127
+ int value, length;
128
+ VALUE list;
129
+ rb_encoding *internal_encoding;
130
+
131
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
132
+
133
+ REQUIRE_LIVE_DB(ctx);
134
+ REQUIRE_OPEN_STMT(ctx);
135
+
136
+ if (ctx->done_p) { return Qnil; }
137
+
138
+ internal_encoding = rb_default_internal_encoding();
139
+
140
+ stmt = ctx->st;
141
+
142
+ value = rb_sqlite3_step_without_gvl(stmt);
143
+ if (rb_errinfo() != Qnil) {
144
+ /* some user defined function was invoked as a callback during step and
145
+ * it raised an exception that has been suppressed until step returns.
146
+ * Now re-raise it. */
147
+ VALUE exception = rb_errinfo();
148
+ rb_set_errinfo(Qnil);
149
+ rb_exc_raise(exception);
150
+ }
151
+
152
+ length = sqlite3_column_count(stmt);
153
+ list = rb_ary_new2((long)length);
154
+
155
+ switch (value) {
156
+ case SQLITE_ROW: {
157
+ int i;
158
+ for (i = 0; i < length; i++) {
159
+ VALUE val;
160
+
161
+ switch (sqlite3_column_type(stmt, i)) {
162
+ case SQLITE_INTEGER:
163
+ val = LL2NUM(sqlite3_column_int64(stmt, i));
164
+ break;
165
+ case SQLITE_FLOAT:
166
+ val = rb_float_new(sqlite3_column_double(stmt, i));
167
+ break;
168
+ case SQLITE_TEXT: {
169
+ val = rb_utf8_str_new(
170
+ (const char *)sqlite3_column_text(stmt, i),
171
+ (long)sqlite3_column_bytes(stmt, i)
172
+ );
173
+ if (internal_encoding) {
174
+ val = rb_str_export_to_enc(val, internal_encoding);
175
+ }
176
+ rb_obj_freeze(val);
177
+ }
178
+ break;
179
+ case SQLITE_BLOB: {
180
+ val = rb_str_new(
181
+ (const char *)sqlite3_column_blob(stmt, i),
182
+ (long)sqlite3_column_bytes(stmt, i)
183
+ );
184
+ rb_obj_freeze(val);
185
+ }
186
+ break;
187
+ case SQLITE_NULL:
188
+ val = Qnil;
189
+ break;
190
+ default:
191
+ rb_raise(rb_eRuntimeError, "bad type");
192
+ }
193
+
194
+ rb_ary_store(list, (long)i, val);
195
+ }
196
+ }
197
+ break;
198
+ case SQLITE_DONE:
199
+ ctx->done_p = 1;
200
+ return Qnil;
201
+ break;
202
+ default:
203
+ sqlite3_reset(stmt);
204
+ ctx->done_p = 0;
205
+ CHECK(sqlite3_db_handle(ctx->st), value);
206
+ }
207
+
208
+ rb_obj_freeze(list);
209
+
210
+ return list;
211
+ }
212
+
213
+ /* call-seq: stmt.bind_param(key, value)
214
+ *
215
+ * Binds value to the named (or positional) placeholder. If +param+ is a
216
+ * Fixnum, it is treated as an index for a positional placeholder.
217
+ * Otherwise it is used as the name of the placeholder to bind to.
218
+ *
219
+ * Type mapping from Ruby to SQLite3:
220
+ * - +nil+ → NULL
221
+ * - Integer → INTEGER (or REAL when outside the signed int64 range)
222
+ * - Float → REAL
223
+ * - SQLite3::Blob → BLOB
224
+ * - String with Encoding::ASCII_8BIT (a.k.a. BINARY) → BLOB
225
+ * - String with Encoding::UTF_16LE or Encoding::UTF_16BE → TEXT (bound as UTF-16)
226
+ * - String (all other encodings) → TEXT (re-encoded to UTF-8 if necessary)
227
+ * - Any other type → raises RuntimeError
228
+ *
229
+ * Note: if you have a string with only ASCII characters but ASCII-8BIT
230
+ * encoding and want it bound as TEXT rather than BLOB, re-encode it first:
231
+ *
232
+ * stmt.bind_param(1, my_binary_str.encode(Encoding::UTF_8))
233
+ *
234
+ * See also #bind_params.
235
+ */
236
+ static VALUE
237
+ bind_param(VALUE self, VALUE key, VALUE value)
238
+ {
239
+ sqlite3StmtRubyPtr ctx;
240
+ int status;
241
+ int index;
242
+
243
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
244
+
245
+ REQUIRE_LIVE_DB(ctx);
246
+ REQUIRE_OPEN_STMT(ctx);
247
+
248
+ switch (TYPE(key)) {
249
+ case T_SYMBOL:
250
+ key = rb_funcall(key, rb_intern("to_s"), 0);
251
+ case T_STRING:
252
+ if (RSTRING_PTR(key)[0] != ':') { key = rb_str_plus(rb_str_new2(":"), key); }
253
+ index = sqlite3_bind_parameter_index(ctx->st, StringValuePtr(key));
254
+ break;
255
+ default:
256
+ index = (int)NUM2INT(key);
257
+ }
258
+
259
+ if (index == 0) {
260
+ rb_raise(rb_path2class("SQLite3::Exception"), "no such bind parameter");
261
+ }
262
+
263
+ switch (TYPE(value)) {
264
+ case T_STRING:
265
+ if (CLASS_OF(value) == cSqlite3Blob
266
+ || rb_enc_get_index(value) == rb_ascii8bit_encindex()
267
+ ) {
268
+ status = sqlite3_bind_blob(
269
+ ctx->st,
270
+ index,
271
+ (const char *)StringValuePtr(value),
272
+ (int)RSTRING_LEN(value),
273
+ SQLITE_TRANSIENT
274
+ );
275
+ } else {
276
+
277
+
278
+ if (UTF16_LE_P(value) || UTF16_BE_P(value)) {
279
+ status = sqlite3_bind_text16(
280
+ ctx->st,
281
+ index,
282
+ (const char *)StringValuePtr(value),
283
+ (int)RSTRING_LEN(value),
284
+ SQLITE_TRANSIENT
285
+ );
286
+ } else {
287
+ if (!UTF8_P(value) || !USASCII_P(value)) {
288
+ value = rb_str_encode(value, rb_enc_from_encoding(rb_utf8_encoding()), 0, Qnil);
289
+ }
290
+ status = sqlite3_bind_text(
291
+ ctx->st,
292
+ index,
293
+ (const char *)StringValuePtr(value),
294
+ (int)RSTRING_LEN(value),
295
+ SQLITE_TRANSIENT
296
+ );
297
+ }
298
+ }
299
+ break;
300
+ case T_BIGNUM: {
301
+ sqlite3_int64 num64;
302
+ if (bignum_to_int64(value, &num64)) {
303
+ status = sqlite3_bind_int64(ctx->st, index, num64);
304
+ break;
305
+ }
306
+ }
307
+ case T_FLOAT:
308
+ status = sqlite3_bind_double(ctx->st, index, NUM2DBL(value));
309
+ break;
310
+ case T_FIXNUM:
311
+ status = sqlite3_bind_int64(ctx->st, index, (sqlite3_int64)FIX2LONG(value));
312
+ break;
313
+ case T_NIL:
314
+ status = sqlite3_bind_null(ctx->st, index);
315
+ break;
316
+ default:
317
+ rb_raise(rb_eRuntimeError, "can't prepare %s",
318
+ rb_class2name(CLASS_OF(value)));
319
+ break;
320
+ }
321
+
322
+ CHECK(sqlite3_db_handle(ctx->st), status);
323
+
324
+ return self;
325
+ }
326
+
327
+ /* call-seq: stmt.reset!
328
+ *
329
+ * Resets the statement. This is typically done internally, though it might
330
+ * occasionally be necessary to manually reset the statement.
331
+ */
332
+ static VALUE
333
+ reset_bang(VALUE self)
334
+ {
335
+ sqlite3StmtRubyPtr ctx;
336
+
337
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
338
+
339
+ REQUIRE_LIVE_DB(ctx);
340
+ REQUIRE_OPEN_STMT(ctx);
341
+
342
+ sqlite3_reset(ctx->st);
343
+ timespecclear(&ctx->db->stmt_deadline);
344
+
345
+ ctx->done_p = 0;
346
+
347
+ return self;
348
+ }
349
+
350
+ /* call-seq: stmt.clear_bindings!
351
+ *
352
+ * Resets the statement. This is typically done internally, though it might
353
+ * occasionally be necessary to manually reset the statement.
354
+ */
355
+ static VALUE
356
+ clear_bindings_bang(VALUE self)
357
+ {
358
+ sqlite3StmtRubyPtr ctx;
359
+
360
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
361
+
362
+ REQUIRE_LIVE_DB(ctx);
363
+ REQUIRE_OPEN_STMT(ctx);
364
+
365
+ sqlite3_clear_bindings(ctx->st);
366
+
367
+ ctx->done_p = 0;
368
+
369
+ return self;
370
+ }
371
+
372
+ /* call-seq: stmt.done?
373
+ *
374
+ * returns true if all rows have been returned.
375
+ */
376
+ static VALUE
377
+ done_p(VALUE self)
378
+ {
379
+ sqlite3StmtRubyPtr ctx;
380
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
381
+
382
+ if (ctx->done_p) { return Qtrue; }
383
+ return Qfalse;
384
+ }
385
+
386
+ /* call-seq: stmt.column_count
387
+ *
388
+ * Returns the number of columns to be returned for this statement
389
+ */
390
+ static VALUE
391
+ column_count(VALUE self)
392
+ {
393
+ sqlite3StmtRubyPtr ctx;
394
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
395
+
396
+ REQUIRE_LIVE_DB(ctx);
397
+ REQUIRE_OPEN_STMT(ctx);
398
+
399
+ return INT2NUM(sqlite3_column_count(ctx->st));
400
+ }
401
+
402
+ #if HAVE_RB_ENC_INTERNED_STR_CSTR
403
+ static VALUE
404
+ interned_utf8_cstr(const char *str)
405
+ {
406
+ return rb_enc_interned_str_cstr(str, rb_utf8_encoding());
407
+ }
408
+ #else
409
+ static VALUE
410
+ interned_utf8_cstr(const char *str)
411
+ {
412
+ VALUE rb_str = rb_utf8_str_new_cstr(str);
413
+ return rb_funcall(rb_str, rb_intern("-@"), 0);
414
+ }
415
+ #endif
416
+
417
+ /* call-seq: stmt.column_name(index)
418
+ *
419
+ * Get the column name at +index+. 0 based.
420
+ */
421
+ static VALUE
422
+ column_name(VALUE self, VALUE index)
423
+ {
424
+ sqlite3StmtRubyPtr ctx;
425
+ const char *name;
426
+
427
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
428
+
429
+ REQUIRE_LIVE_DB(ctx);
430
+ REQUIRE_OPEN_STMT(ctx);
431
+
432
+ name = sqlite3_column_name(ctx->st, (int)NUM2INT(index));
433
+
434
+ VALUE ret = Qnil;
435
+
436
+ if (name) {
437
+ ret = interned_utf8_cstr(name);
438
+ }
439
+ return ret;
440
+ }
441
+
442
+ /* call-seq: stmt.column_decltype(index)
443
+ *
444
+ * Get the column type at +index+. 0 based.
445
+ */
446
+ static VALUE
447
+ column_decltype(VALUE self, VALUE index)
448
+ {
449
+ sqlite3StmtRubyPtr ctx;
450
+ const char *name;
451
+
452
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
453
+
454
+ REQUIRE_LIVE_DB(ctx);
455
+ REQUIRE_OPEN_STMT(ctx);
456
+
457
+ name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
458
+
459
+ if (name) { return rb_str_new2(name); }
460
+ return Qnil;
461
+ }
462
+
463
+ /* call-seq: stmt.bind_parameter_count
464
+ *
465
+ * Return the number of bind parameters
466
+ */
467
+ static VALUE
468
+ bind_parameter_count(VALUE self)
469
+ {
470
+ sqlite3StmtRubyPtr ctx;
471
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
472
+
473
+ REQUIRE_LIVE_DB(ctx);
474
+ REQUIRE_OPEN_STMT(ctx);
475
+
476
+ return INT2NUM(sqlite3_bind_parameter_count(ctx->st));
477
+ }
478
+
479
+ /** call-seq: stmt.named_params
480
+ *
481
+ * Return the list of named parameters in the statement.
482
+ * This returns a frozen array of strings (without the leading prefix character).
483
+ * The values of this list can be used to bind parameters
484
+ * to the statement using bind_param. Positional (?NNN) and anonymous (?)
485
+ * parameters are excluded.
486
+ *
487
+ */
488
+ static VALUE
489
+ named_params(VALUE self)
490
+ {
491
+ sqlite3StmtRubyPtr ctx;
492
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
493
+
494
+ REQUIRE_LIVE_DB(ctx);
495
+ REQUIRE_OPEN_STMT(ctx);
496
+
497
+ int param_count = sqlite3_bind_parameter_count(ctx->st);
498
+ VALUE params = rb_ary_new2(param_count);
499
+
500
+ // The first host parameter has an index of 1, not 0.
501
+ for (int i = 1; i <= param_count; i++) {
502
+ const char *name = sqlite3_bind_parameter_name(ctx->st, i);
503
+ // We ignore positional and anonymous parameters, and also null values, since there can be
504
+ // gaps in the list.
505
+ if (name && *name != '?') {
506
+ VALUE param = interned_utf8_cstr(name + 1);
507
+ rb_ary_push(params, param);
508
+ }
509
+ }
510
+ return rb_obj_freeze(params);
511
+ }
512
+
513
+ enum stmt_stat_sym {
514
+ stmt_stat_sym_fullscan_steps,
515
+ stmt_stat_sym_sorts,
516
+ stmt_stat_sym_autoindexes,
517
+ stmt_stat_sym_vm_steps,
518
+ #ifdef SQLITE_STMTSTATUS_REPREPARE
519
+ stmt_stat_sym_reprepares,
520
+ #endif
521
+ #ifdef SQLITE_STMTSTATUS_RUN
522
+ stmt_stat_sym_runs,
523
+ #endif
524
+ #ifdef SQLITE_STMTSTATUS_FILTER_MISS
525
+ stmt_stat_sym_filter_misses,
526
+ #endif
527
+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
528
+ stmt_stat_sym_filter_hits,
529
+ #endif
530
+ stmt_stat_sym_last
531
+ };
532
+
533
+ static VALUE stmt_stat_symbols[stmt_stat_sym_last];
534
+
535
+ static void
536
+ setup_stmt_stat_symbols(void)
537
+ {
538
+ if (stmt_stat_symbols[0] == 0) {
539
+ #define S(s) stmt_stat_symbols[stmt_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
540
+ S(fullscan_steps);
541
+ S(sorts);
542
+ S(autoindexes);
543
+ S(vm_steps);
544
+ #ifdef SQLITE_STMTSTATUS_REPREPARE
545
+ S(reprepares);
546
+ #endif
547
+ #ifdef SQLITE_STMTSTATUS_RUN
548
+ S(runs);
549
+ #endif
550
+ #ifdef SQLITE_STMTSTATUS_FILTER_MISS
551
+ S(filter_misses);
552
+ #endif
553
+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
554
+ S(filter_hits);
555
+ #endif
556
+ #undef S
557
+ }
558
+ }
559
+
560
+ static size_t
561
+ stmt_stat_internal(VALUE hash_or_sym, sqlite3_stmt *stmt)
562
+ {
563
+ VALUE hash = Qnil, key = Qnil;
564
+
565
+ setup_stmt_stat_symbols();
566
+
567
+ if (RB_TYPE_P(hash_or_sym, T_HASH)) {
568
+ hash = hash_or_sym;
569
+ } else if (SYMBOL_P(hash_or_sym)) {
570
+ key = hash_or_sym;
571
+ } else {
572
+ rb_raise(rb_eTypeError, "non-hash or symbol argument");
573
+ }
574
+
575
+ #define SET(name, stat_type) \
576
+ if (key == stmt_stat_symbols[stmt_stat_sym_##name]) \
577
+ return sqlite3_stmt_status(stmt, stat_type, 0); \
578
+ else if (hash != Qnil) \
579
+ rb_hash_aset(hash, stmt_stat_symbols[stmt_stat_sym_##name], SIZET2NUM(sqlite3_stmt_status(stmt, stat_type, 0)));
580
+
581
+ SET(fullscan_steps, SQLITE_STMTSTATUS_FULLSCAN_STEP);
582
+ SET(sorts, SQLITE_STMTSTATUS_SORT);
583
+ SET(autoindexes, SQLITE_STMTSTATUS_AUTOINDEX);
584
+ SET(vm_steps, SQLITE_STMTSTATUS_VM_STEP);
585
+ #ifdef SQLITE_STMTSTATUS_REPREPARE
586
+ SET(reprepares, SQLITE_STMTSTATUS_REPREPARE);
587
+ #endif
588
+ #ifdef SQLITE_STMTSTATUS_RUN
589
+ SET(runs, SQLITE_STMTSTATUS_RUN);
590
+ #endif
591
+ #ifdef SQLITE_STMTSTATUS_FILTER_MISS
592
+ SET(filter_misses, SQLITE_STMTSTATUS_FILTER_MISS);
593
+ #endif
594
+ #ifdef SQLITE_STMTSTATUS_FILTER_HIT
595
+ SET(filter_hits, SQLITE_STMTSTATUS_FILTER_HIT);
596
+ #endif
597
+ #undef SET
598
+
599
+ if (!NIL_P(key)) { /* matched key should return above */
600
+ rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
601
+ }
602
+
603
+ return 0;
604
+ }
605
+
606
+ /* call-seq: stmt.stats_as_hash(hash)
607
+ *
608
+ * Returns a Hash containing information about the statement.
609
+ */
610
+ static VALUE
611
+ stats_as_hash(VALUE self)
612
+ {
613
+ sqlite3StmtRubyPtr ctx;
614
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
615
+
616
+ REQUIRE_LIVE_DB(ctx);
617
+ REQUIRE_OPEN_STMT(ctx);
618
+
619
+ VALUE arg = rb_hash_new();
620
+
621
+ stmt_stat_internal(arg, ctx->st);
622
+ return arg;
623
+ }
624
+
625
+ /* call-seq: stmt.stmt_stat(hash_or_key)
626
+ *
627
+ * Returns a Hash containing information about the statement.
628
+ */
629
+ static VALUE
630
+ stat_for(VALUE self, VALUE key)
631
+ {
632
+ sqlite3StmtRubyPtr ctx;
633
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
634
+
635
+ REQUIRE_LIVE_DB(ctx);
636
+ REQUIRE_OPEN_STMT(ctx);
637
+
638
+ if (SYMBOL_P(key)) {
639
+ size_t value = stmt_stat_internal(key, ctx->st);
640
+ return SIZET2NUM(value);
641
+ } else {
642
+ rb_raise(rb_eTypeError, "non-symbol given");
643
+ }
644
+ }
645
+
646
+ #ifdef SQLITE_STMTSTATUS_MEMUSED
647
+ /* call-seq: stmt.memused
648
+ *
649
+ * Return the approximate number of bytes of heap memory used to store the prepared statement
650
+ */
651
+ static VALUE
652
+ memused(VALUE self)
653
+ {
654
+ sqlite3StmtRubyPtr ctx;
655
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
656
+
657
+ REQUIRE_LIVE_DB(ctx);
658
+ REQUIRE_OPEN_STMT(ctx);
659
+
660
+ return INT2NUM(sqlite3_stmt_status(ctx->st, SQLITE_STMTSTATUS_MEMUSED, 0));
661
+ }
662
+ #endif
663
+
664
+ #ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
665
+
666
+ /* call-seq: stmt.database_name(column_index)
667
+ *
668
+ * Return the database name for the column at +column_index+
669
+ */
670
+ static VALUE
671
+ database_name(VALUE self, VALUE index)
672
+ {
673
+ sqlite3StmtRubyPtr ctx;
674
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
675
+
676
+ REQUIRE_LIVE_DB(ctx);
677
+ REQUIRE_OPEN_STMT(ctx);
678
+
679
+ return SQLITE3_UTF8_STR_NEW2(
680
+ sqlite3_column_database_name(ctx->st, NUM2INT(index)));
681
+ }
682
+
683
+ #endif
684
+
685
+ /* call-seq: stmt.sql
686
+ *
687
+ * Returns the SQL statement used to create this prepared statement
688
+ */
689
+ static VALUE
690
+ get_sql(VALUE self)
691
+ {
692
+ sqlite3StmtRubyPtr ctx;
693
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
694
+
695
+ REQUIRE_LIVE_DB(ctx);
696
+ REQUIRE_OPEN_STMT(ctx);
697
+
698
+ return rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(sqlite3_sql(ctx->st)));
699
+ }
700
+
701
+ /* call-seq: stmt.expanded_sql
702
+ *
703
+ * Returns the SQL statement used to create this prepared statement, but
704
+ * with bind parameters substituted in to the statement.
705
+ */
706
+ static VALUE
707
+ get_expanded_sql(VALUE self)
708
+ {
709
+ sqlite3StmtRubyPtr ctx;
710
+ char *expanded_sql;
711
+ VALUE rb_expanded_sql;
712
+
713
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
714
+
715
+ REQUIRE_LIVE_DB(ctx);
716
+ REQUIRE_OPEN_STMT(ctx);
717
+
718
+ expanded_sql = sqlite3_expanded_sql(ctx->st);
719
+ rb_expanded_sql = rb_obj_freeze(SQLITE3_UTF8_STR_NEW2(expanded_sql));
720
+ sqlite3_free(expanded_sql);
721
+
722
+ return rb_expanded_sql;
723
+ }
724
+
725
+ void
726
+ init_sqlite3_statement(void)
727
+ {
728
+ cSqlite3Statement = rb_define_class_under(mSqlite3, "Statement", rb_cObject);
729
+
730
+ rb_define_alloc_func(cSqlite3Statement, allocate);
731
+ rb_define_method(cSqlite3Statement, "close", sqlite3_rb_close, 0);
732
+ rb_define_method(cSqlite3Statement, "closed?", closed_p, 0);
733
+ rb_define_method(cSqlite3Statement, "bind_param", bind_param, 2);
734
+ rb_define_method(cSqlite3Statement, "reset!", reset_bang, 0);
735
+ rb_define_method(cSqlite3Statement, "clear_bindings!", clear_bindings_bang, 0);
736
+ rb_define_method(cSqlite3Statement, "step", step, 0);
737
+ rb_define_method(cSqlite3Statement, "done?", done_p, 0);
738
+ rb_define_method(cSqlite3Statement, "column_count", column_count, 0);
739
+ rb_define_method(cSqlite3Statement, "column_name", column_name, 1);
740
+ rb_define_method(cSqlite3Statement, "column_decltype", column_decltype, 1);
741
+ rb_define_method(cSqlite3Statement, "bind_parameter_count", bind_parameter_count, 0);
742
+ rb_define_method(cSqlite3Statement, "named_params", named_params, 0);
743
+ rb_define_method(cSqlite3Statement, "sql", get_sql, 0);
744
+ rb_define_method(cSqlite3Statement, "expanded_sql", get_expanded_sql, 0);
745
+ #ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
746
+ rb_define_method(cSqlite3Statement, "database_name", database_name, 1);
747
+ #endif
748
+ #ifdef SQLITE_STMTSTATUS_MEMUSED
749
+ rb_define_method(cSqlite3Statement, "memused", memused, 0);
750
+ #endif
751
+
752
+ rb_define_private_method(cSqlite3Statement, "prepare", prepare, 2);
753
+ rb_define_private_method(cSqlite3Statement, "stats_as_hash", stats_as_hash, 0);
754
+ rb_define_private_method(cSqlite3Statement, "stat_for", stat_for, 1);
755
+ }