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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +390 -0
- data/CONTRIBUTING.md +34 -2
- data/{faq/faq.md → FAQ.md} +0 -43
- data/INSTALLATION.md +269 -0
- data/LICENSE +18 -22
- data/README.md +76 -128
- data/dependencies.yml +13 -0
- data/ext/sqlite3/aggregator.c +142 -146
- data/ext/sqlite3/aggregator.h +2 -4
- data/ext/sqlite3/backup.c +86 -64
- data/ext/sqlite3/backup.h +2 -2
- data/ext/sqlite3/database.c +543 -465
- data/ext/sqlite3/database.h +9 -4
- data/ext/sqlite3/exception.c +111 -92
- data/ext/sqlite3/exception.h +3 -1
- data/ext/sqlite3/extconf.rb +83 -51
- data/ext/sqlite3/sqlite3.c +160 -115
- data/ext/sqlite3/sqlite3_ruby.h +2 -2
- data/ext/sqlite3/statement.c +518 -293
- data/ext/sqlite3/statement.h +3 -3
- data/ext/sqlite3/timespec.h +20 -0
- data/lib/sqlite3/constants.rb +171 -47
- data/lib/sqlite3/database.rb +141 -181
- data/lib/sqlite3/errors.rb +26 -1
- data/lib/sqlite3/pragmas.rb +128 -138
- data/lib/sqlite3/resultset.rb +14 -105
- data/lib/sqlite3/statement.rb +58 -13
- data/lib/sqlite3/value.rb +17 -20
- data/lib/sqlite3/version.rb +1 -21
- data/lib/sqlite3.rb +6 -4
- data/ports/archives/sqlite-autoconf-3460000.tar.gz +0 -0
- metadata +19 -107
- data/API_CHANGES.md +0 -49
- data/ChangeLog.cvs +0 -88
- data/Gemfile +0 -3
- data/LICENSE-DEPENDENCIES +0 -20
- data/faq/faq.rb +0 -145
- data/faq/faq.yml +0 -426
- data/lib/sqlite3/translator.rb +0 -118
- data/ports/archives/sqlite-autoconf-3380500.tar.gz +0 -0
- data/test/helper.rb +0 -27
- data/test/test_backup.rb +0 -33
- data/test/test_collation.rb +0 -82
- data/test/test_database.rb +0 -545
- data/test/test_database_flags.rb +0 -95
- data/test/test_database_readonly.rb +0 -36
- data/test/test_database_readwrite.rb +0 -41
- data/test/test_deprecated.rb +0 -44
- data/test/test_encoding.rb +0 -155
- data/test/test_integration.rb +0 -507
- data/test/test_integration_aggregate.rb +0 -336
- data/test/test_integration_open_close.rb +0 -30
- data/test/test_integration_pending.rb +0 -115
- data/test/test_integration_resultset.rb +0 -142
- data/test/test_integration_statement.rb +0 -194
- data/test/test_result_set.rb +0 -37
- data/test/test_sqlite3.rb +0 -30
- data/test/test_statement.rb +0 -263
- data/test/test_statement_execute.rb +0 -35
data/ext/sqlite3/statement.c
CHANGED
@@ -6,67 +6,73 @@
|
|
6
6
|
|
7
7
|
VALUE cSqlite3Statement;
|
8
8
|
|
9
|
-
static void
|
9
|
+
static void
|
10
|
+
statement_deallocate(void *data)
|
10
11
|
{
|
11
|
-
|
12
|
-
xfree(c);
|
13
|
-
}
|
12
|
+
sqlite3StmtRubyPtr s = (sqlite3StmtRubyPtr)data;
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
ctx->st = NULL;
|
19
|
-
ctx->done_p = 0;
|
14
|
+
if (s->st) {
|
15
|
+
sqlite3_finalize(s->st);
|
16
|
+
}
|
20
17
|
|
21
|
-
|
18
|
+
xfree(data);
|
22
19
|
}
|
23
20
|
|
24
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
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
|
-
|
41
|
-
|
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
|
-
|
44
|
-
rb_raise(rb_eArgError, "prepare called on a closed database");
|
56
|
+
StringValue(sql);
|
45
57
|
|
46
|
-
|
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
|
-
|
61
|
+
status = sqlite3_prepare_v2(
|
52
62
|
#else
|
53
|
-
|
63
|
+
status = sqlite3_prepare(
|
54
64
|
#endif
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
65
|
-
|
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
|
-
|
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
|
83
|
+
static VALUE
|
84
|
+
sqlite3_rb_close(VALUE self)
|
78
85
|
{
|
79
|
-
|
86
|
+
sqlite3StmtRubyPtr ctx;
|
80
87
|
|
81
|
-
|
88
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
82
89
|
|
83
|
-
|
90
|
+
REQUIRE_OPEN_STMT(ctx);
|
84
91
|
|
85
|
-
|
86
|
-
|
92
|
+
sqlite3_finalize(ctx->st);
|
93
|
+
ctx->st = NULL;
|
87
94
|
|
88
|
-
|
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
|
102
|
+
static VALUE
|
103
|
+
closed_p(VALUE self)
|
96
104
|
{
|
97
|
-
|
98
|
-
|
105
|
+
sqlite3StmtRubyPtr ctx;
|
106
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
99
107
|
|
100
|
-
|
108
|
+
if (!ctx->st) { return Qtrue; }
|
101
109
|
|
102
|
-
|
110
|
+
return Qfalse;
|
103
111
|
}
|
104
112
|
|
105
|
-
static VALUE
|
113
|
+
static VALUE
|
114
|
+
step(VALUE self)
|
106
115
|
{
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
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
|
211
|
+
static VALUE
|
212
|
+
bind_param(VALUE self, VALUE key, VALUE value)
|
204
213
|
{
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
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
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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
|
305
|
+
static VALUE
|
306
|
+
reset_bang(VALUE self)
|
296
307
|
{
|
297
|
-
|
308
|
+
sqlite3StmtRubyPtr ctx;
|
298
309
|
|
299
|
-
|
300
|
-
|
310
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
311
|
+
REQUIRE_OPEN_STMT(ctx);
|
301
312
|
|
302
|
-
|
313
|
+
sqlite3_reset(ctx->st);
|
303
314
|
|
304
|
-
|
315
|
+
ctx->done_p = 0;
|
305
316
|
|
306
|
-
|
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
|
325
|
+
static VALUE
|
326
|
+
clear_bindings_bang(VALUE self)
|
315
327
|
{
|
316
|
-
|
328
|
+
sqlite3StmtRubyPtr ctx;
|
317
329
|
|
318
|
-
|
319
|
-
|
330
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
331
|
+
REQUIRE_OPEN_STMT(ctx);
|
320
332
|
|
321
|
-
|
333
|
+
sqlite3_clear_bindings(ctx->st);
|
322
334
|
|
323
|
-
|
335
|
+
ctx->done_p = 0;
|
324
336
|
|
325
|
-
|
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
|
344
|
+
static VALUE
|
345
|
+
done_p(VALUE self)
|
333
346
|
{
|
334
|
-
|
335
|
-
|
347
|
+
sqlite3StmtRubyPtr ctx;
|
348
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
336
349
|
|
337
|
-
|
338
|
-
|
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
|
358
|
+
static VALUE
|
359
|
+
column_count(VALUE self)
|
346
360
|
{
|
347
|
-
|
348
|
-
|
349
|
-
|
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
|
-
|
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
|
387
|
+
static VALUE
|
388
|
+
column_name(VALUE self, VALUE index)
|
359
389
|
{
|
360
|
-
|
361
|
-
|
390
|
+
sqlite3StmtRubyPtr ctx;
|
391
|
+
const char *name;
|
362
392
|
|
363
|
-
|
364
|
-
|
393
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
394
|
+
REQUIRE_OPEN_STMT(ctx);
|
365
395
|
|
366
|
-
|
396
|
+
name = sqlite3_column_name(ctx->st, (int)NUM2INT(index));
|
367
397
|
|
368
|
-
|
369
|
-
|
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
|
410
|
+
static VALUE
|
411
|
+
column_decltype(VALUE self, VALUE index)
|
377
412
|
{
|
378
|
-
|
379
|
-
|
413
|
+
sqlite3StmtRubyPtr ctx;
|
414
|
+
const char *name;
|
380
415
|
|
381
|
-
|
382
|
-
|
416
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
417
|
+
REQUIRE_OPEN_STMT(ctx);
|
383
418
|
|
384
|
-
|
419
|
+
name = sqlite3_column_decltype(ctx->st, (int)NUM2INT(index));
|
385
420
|
|
386
|
-
|
387
|
-
|
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
|
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
|
-
|
397
|
-
|
398
|
-
|
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
|
-
|
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
|
589
|
+
static VALUE
|
590
|
+
database_name(VALUE self, VALUE index)
|
410
591
|
{
|
411
|
-
|
412
|
-
|
413
|
-
|
592
|
+
sqlite3StmtRubyPtr ctx;
|
593
|
+
TypedData_Get_Struct(self, sqlite3StmtRuby, &statement_type, ctx);
|
594
|
+
REQUIRE_OPEN_STMT(ctx);
|
414
595
|
|
415
|
-
|
416
|
-
|
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
|
-
|
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
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
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
|
-
|
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
|
}
|