sqlite3 1.5.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
  }