sqlite3 1.7.3-aarch64-linux → 2.9.0

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