sqlite3 1.5.0 → 2.0.2

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