sqlite3 1.7.3-arm64-darwin → 2.0.0-arm64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +152 -0
  3. data/CONTRIBUTING.md +23 -1
  4. data/FAQ.md +0 -43
  5. data/INSTALLATION.md +13 -5
  6. data/LICENSE +18 -22
  7. data/README.md +75 -4
  8. data/dependencies.yml +10 -11
  9. data/ext/sqlite3/aggregator.c +142 -145
  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 +535 -482
  14. data/ext/sqlite3/database.h +7 -4
  15. data/ext/sqlite3/exception.c +111 -92
  16. data/ext/sqlite3/exception.h +3 -1
  17. data/ext/sqlite3/extconf.rb +21 -22
  18. data/ext/sqlite3/sqlite3.c +159 -115
  19. data/ext/sqlite3/sqlite3_ruby.h +2 -2
  20. data/ext/sqlite3/statement.c +516 -300
  21. data/ext/sqlite3/statement.h +3 -3
  22. data/ext/sqlite3/timespec.h +20 -0
  23. data/lib/sqlite3/3.0/sqlite3_native.bundle +0 -0
  24. data/lib/sqlite3/3.1/sqlite3_native.bundle +0 -0
  25. data/lib/sqlite3/3.2/sqlite3_native.bundle +0 -0
  26. data/lib/sqlite3/3.3/sqlite3_native.bundle +0 -0
  27. data/lib/sqlite3/constants.rb +171 -47
  28. data/lib/sqlite3/database.rb +105 -165
  29. data/lib/sqlite3/errors.rb +26 -1
  30. data/lib/sqlite3/pragmas.rb +126 -136
  31. data/lib/sqlite3/resultset.rb +14 -97
  32. data/lib/sqlite3/statement.rb +58 -13
  33. data/lib/sqlite3/value.rb +17 -20
  34. data/lib/sqlite3/version.rb +1 -21
  35. data/lib/sqlite3.rb +6 -4
  36. metadata +3 -28
  37. data/API_CHANGES.md +0 -49
  38. data/ChangeLog.cvs +0 -88
  39. data/Gemfile +0 -10
  40. data/LICENSE-DEPENDENCIES +0 -20
  41. data/lib/sqlite3/translator.rb +0 -117
  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 -668
  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 -49
  50. data/test/test_encoding.rb +0 -165
  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_pragmas.rb +0 -22
  58. data/test/test_result_set.rb +0 -47
  59. data/test/test_sqlite3.rb +0 -30
  60. data/test/test_statement.rb +0 -290
  61. data/test/test_statement_execute.rb +0 -39
@@ -6,76 +6,73 @@
6
6
 
7
7
  VALUE cSqlite3Statement;
8
8
 
9
- static size_t statement_memsize(const void *data)
9
+ static void
10
+ statement_deallocate(void *data)
10
11
  {
11
- const sqlite3StmtRubyPtr s = (const sqlite3StmtRubyPtr)data;
12
- // NB: can't account for s->st because the type is incomplete.
13
- return sizeof(*s);
12
+ sqlite3StmtRubyPtr s = (sqlite3StmtRubyPtr)data;
13
+
14
+ if (s->st) {
15
+ sqlite3_finalize(s->st);
16
+ }
17
+
18
+ xfree(data);
19
+ }
20
+
21
+ static size_t
22
+ statement_memsize(const void *data)
23
+ {
24
+ const sqlite3StmtRubyPtr s = (const sqlite3StmtRubyPtr)data;
25
+ // NB: can't account for s->st because the type is incomplete.
26
+ return sizeof(*s);
14
27
  }
15
28
 
16
29
  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,
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,
26
39
  };
27
40
 
28
- static VALUE allocate(VALUE klass)
41
+ static VALUE
42
+ allocate(VALUE klass)
29
43
  {
30
- sqlite3StmtRubyPtr ctx;
31
- return TypedData_Make_Struct(klass, sqlite3StmtRuby, &statement_type, ctx);
44
+ sqlite3StmtRubyPtr ctx;
45
+ return TypedData_Make_Struct(klass, sqlite3StmtRuby, &statement_type, ctx);
32
46
  }
33
47
 
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)
48
+ static VALUE
49
+ prepare(VALUE self, VALUE db, VALUE sql)
42
50
  {
43
- sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
44
- sqlite3StmtRubyPtr ctx;
45
- const char *tail = NULL;
46
- int status;
47
-
48
- StringValue(sql);
49
-
50
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
51
+ sqlite3RubyPtr db_ctx = sqlite3_database_unwrap(db);
52
+ sqlite3StmtRubyPtr ctx;
53
+ const char *tail = NULL;
54
+ int status;
51
55
 
52
- if(!db_ctx->db)
53
- rb_raise(rb_eArgError, "prepare called on a closed database");
56
+ StringValue(sql);
54
57
 
55
- if(!UTF8_P(sql)) {
56
- sql = rb_str_export_to_enc(sql, rb_utf8_encoding());
57
- }
58
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
58
59
 
59
60
  #ifdef HAVE_SQLITE3_PREPARE_V2
60
- status = sqlite3_prepare_v2(
61
+ status = sqlite3_prepare_v2(
61
62
  #else
62
- status = sqlite3_prepare(
63
+ status = sqlite3_prepare(
63
64
  #endif
64
- db_ctx->db,
65
- (const char *)StringValuePtr(sql),
66
- (int)RSTRING_LEN(sql),
67
- &ctx->st,
68
- &tail
69
- );
65
+ db_ctx->db,
66
+ (const char *)StringValuePtr(sql),
67
+ (int)RSTRING_LEN(sql),
68
+ &ctx->st,
69
+ &tail
70
+ );
70
71
 
71
- CHECK(db_ctx->db, status);
72
+ CHECK(db_ctx->db, status);
73
+ timespecclear(&db_ctx->stmt_deadline);
72
74
 
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;
75
+ return rb_str_new2(tail);
79
76
  }
80
77
 
81
78
  /* call-seq: stmt.close
@@ -83,122 +80,124 @@ static VALUE initialize(VALUE self, VALUE db, VALUE sql)
83
80
  * Closes the statement by finalizing the underlying statement
84
81
  * handle. The statement must not be used after being closed.
85
82
  */
86
- static VALUE sqlite3_rb_close(VALUE self)
83
+ static VALUE
84
+ sqlite3_rb_close(VALUE self)
87
85
  {
88
- sqlite3StmtRubyPtr ctx;
86
+ sqlite3StmtRubyPtr ctx;
89
87
 
90
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
88
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
91
89
 
92
- REQUIRE_OPEN_STMT(ctx);
90
+ REQUIRE_OPEN_STMT(ctx);
93
91
 
94
- sqlite3_finalize(ctx->st);
95
- ctx->st = NULL;
92
+ sqlite3_finalize(ctx->st);
93
+ ctx->st = NULL;
96
94
 
97
- return self;
95
+ return self;
98
96
  }
99
97
 
100
98
  /* call-seq: stmt.closed?
101
99
  *
102
100
  * Returns true if the statement has been closed.
103
101
  */
104
- static VALUE closed_p(VALUE self)
102
+ static VALUE
103
+ closed_p(VALUE self)
105
104
  {
106
- sqlite3StmtRubyPtr ctx;
107
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
105
+ sqlite3StmtRubyPtr ctx;
106
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
108
107
 
109
- if(!ctx->st) return Qtrue;
108
+ if (!ctx->st) { return Qtrue; }
110
109
 
111
- return Qfalse;
110
+ return Qfalse;
112
111
  }
113
112
 
114
- static VALUE step(VALUE self)
113
+ static VALUE
114
+ step(VALUE self)
115
115
  {
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
- }
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
+ }
188
186
  }
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;
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;
202
201
  }
203
202
 
204
203
  /* call-seq: stmt.bind_param(key, value)
@@ -209,91 +208,93 @@ static VALUE step(VALUE self)
209
208
  *
210
209
  * See also #bind_params.
211
210
  */
212
- static VALUE bind_param(VALUE self, VALUE key, VALUE value)
211
+ static VALUE
212
+ bind_param(VALUE self, VALUE key, VALUE value)
213
213
  {
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
- );
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
+ }
269
279
  }
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
- }
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;
278
293
  }
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;
294
+
295
+ CHECK(sqlite3_db_handle(ctx->st), status);
296
+
297
+ return self;
297
298
  }
298
299
 
299
300
  /* call-seq: stmt.reset!
@@ -301,18 +302,19 @@ static VALUE bind_param(VALUE self, VALUE key, VALUE value)
301
302
  * Resets the statement. This is typically done internally, though it might
302
303
  * occasionally be necessary to manually reset the statement.
303
304
  */
304
- static VALUE reset_bang(VALUE self)
305
+ static VALUE
306
+ reset_bang(VALUE self)
305
307
  {
306
- sqlite3StmtRubyPtr ctx;
308
+ sqlite3StmtRubyPtr ctx;
307
309
 
308
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
309
- REQUIRE_OPEN_STMT(ctx);
310
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
311
+ REQUIRE_OPEN_STMT(ctx);
310
312
 
311
- sqlite3_reset(ctx->st);
313
+ sqlite3_reset(ctx->st);
312
314
 
313
- ctx->done_p = 0;
315
+ ctx->done_p = 0;
314
316
 
315
- return self;
317
+ return self;
316
318
  }
317
319
 
318
320
  /* call-seq: stmt.clear_bindings!
@@ -320,94 +322,263 @@ static VALUE reset_bang(VALUE self)
320
322
  * Resets the statement. This is typically done internally, though it might
321
323
  * occasionally be necessary to manually reset the statement.
322
324
  */
323
- static VALUE clear_bindings_bang(VALUE self)
325
+ static VALUE
326
+ clear_bindings_bang(VALUE self)
324
327
  {
325
- sqlite3StmtRubyPtr ctx;
328
+ sqlite3StmtRubyPtr ctx;
326
329
 
327
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
328
- REQUIRE_OPEN_STMT(ctx);
330
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
331
+ REQUIRE_OPEN_STMT(ctx);
329
332
 
330
- sqlite3_clear_bindings(ctx->st);
333
+ sqlite3_clear_bindings(ctx->st);
331
334
 
332
- ctx->done_p = 0;
335
+ ctx->done_p = 0;
333
336
 
334
- return self;
337
+ return self;
335
338
  }
336
339
 
337
340
  /* call-seq: stmt.done?
338
341
  *
339
342
  * returns true if all rows have been returned.
340
343
  */
341
- static VALUE done_p(VALUE self)
344
+ static VALUE
345
+ done_p(VALUE self)
342
346
  {
343
- sqlite3StmtRubyPtr ctx;
344
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
347
+ sqlite3StmtRubyPtr ctx;
348
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
345
349
 
346
- if(ctx->done_p) return Qtrue;
347
- return Qfalse;
350
+ if (ctx->done_p) { return Qtrue; }
351
+ return Qfalse;
348
352
  }
349
353
 
350
354
  /* call-seq: stmt.column_count
351
355
  *
352
356
  * Returns the number of columns to be returned for this statement
353
357
  */
354
- static VALUE column_count(VALUE self)
358
+ static VALUE
359
+ column_count(VALUE self)
355
360
  {
356
- sqlite3StmtRubyPtr ctx;
357
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
358
- REQUIRE_OPEN_STMT(ctx);
361
+ sqlite3StmtRubyPtr ctx;
362
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
363
+ REQUIRE_OPEN_STMT(ctx);
359
364
 
360
- return INT2NUM(sqlite3_column_count(ctx->st));
365
+ return INT2NUM(sqlite3_column_count(ctx->st));
361
366
  }
362
367
 
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);
380
+ }
381
+ #endif
382
+
363
383
  /* call-seq: stmt.column_name(index)
364
384
  *
365
385
  * Get the column name at +index+. 0 based.
366
386
  */
367
- static VALUE column_name(VALUE self, VALUE index)
387
+ static VALUE
388
+ column_name(VALUE self, VALUE index)
368
389
  {
369
- sqlite3StmtRubyPtr ctx;
370
- const char * name;
390
+ sqlite3StmtRubyPtr ctx;
391
+ const char *name;
371
392
 
372
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
373
- REQUIRE_OPEN_STMT(ctx);
393
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
394
+ REQUIRE_OPEN_STMT(ctx);
374
395
 
375
- name = sqlite3_column_name(ctx->st, (int)NUM2INT(index));
396
+ name = sqlite3_column_name(ctx->st, (int)NUM2INT(index));
376
397
 
377
- if(name) return SQLITE3_UTF8_STR_NEW2(name);
378
- return Qnil;
398
+ VALUE ret = Qnil;
399
+
400
+ if (name) {
401
+ ret = interned_utf8_cstr(name);
402
+ }
403
+ return ret;
379
404
  }
380
405
 
381
406
  /* call-seq: stmt.column_decltype(index)
382
407
  *
383
408
  * Get the column type at +index+. 0 based.
384
409
  */
385
- static VALUE column_decltype(VALUE self, VALUE index)
410
+ static VALUE
411
+ column_decltype(VALUE self, VALUE index)
386
412
  {
387
- sqlite3StmtRubyPtr ctx;
388
- const char * name;
413
+ sqlite3StmtRubyPtr ctx;
414
+ const char *name;
389
415
 
390
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
391
- REQUIRE_OPEN_STMT(ctx);
416
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
417
+ REQUIRE_OPEN_STMT(ctx);
392
418
 
393
- name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
419
+ name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
394
420
 
395
- if(name) return rb_str_new2(name);
396
- return Qnil;
421
+ if (name) { return rb_str_new2(name); }
422
+ return Qnil;
397
423
  }
398
424
 
399
425
  /* call-seq: stmt.bind_parameter_count
400
426
  *
401
427
  * Return the number of bind parameters
402
428
  */
403
- 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)
538
+ {
539
+ sqlite3StmtRubyPtr ctx;
540
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
541
+ REQUIRE_OPEN_STMT(ctx);
542
+ VALUE arg = rb_hash_new();
543
+
544
+ stmt_stat_internal(arg, ctx->st);
545
+ return arg;
546
+ }
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)
404
554
  {
405
- sqlite3StmtRubyPtr ctx;
406
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
407
- REQUIRE_OPEN_STMT(ctx);
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
+ }
408
566
 
409
- return INT2NUM(sqlite3_bind_parameter_count(ctx->st));
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));
410
580
  }
581
+ #endif
411
582
 
412
583
  #ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
413
584
 
@@ -415,37 +586,82 @@ static VALUE bind_parameter_count(VALUE self)
415
586
  *
416
587
  * Return the database name for the column at +column_index+
417
588
  */
418
- static VALUE database_name(VALUE self, VALUE index)
589
+ static VALUE
590
+ database_name(VALUE self, VALUE index)
419
591
  {
420
- sqlite3StmtRubyPtr ctx;
421
- TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
422
- REQUIRE_OPEN_STMT(ctx);
592
+ sqlite3StmtRubyPtr ctx;
593
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
594
+ REQUIRE_OPEN_STMT(ctx);
423
595
 
424
- return SQLITE3_UTF8_STR_NEW2(
425
- sqlite3_column_database_name(ctx->st, NUM2INT(index)));
596
+ return SQLITE3_UTF8_STR_NEW2(
597
+ sqlite3_column_database_name(ctx->st, NUM2INT(index)));
426
598
  }
427
599
 
428
600
  #endif
429
601
 
430
- void init_sqlite3_statement(void)
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)
431
608
  {
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);
609
+ sqlite3StmtRubyPtr ctx;
610
+ TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
611
+ REQUIRE_OPEN_STMT(ctx);
447
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)
623
+ {
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);
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);
448
657
  #ifdef HAVE_SQLITE3_COLUMN_DATABASE_NAME
449
- 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);
450
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);
451
667
  }