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/database.c
CHANGED
@@ -12,73 +12,110 @@
|
|
12
12
|
|
13
13
|
VALUE cSqlite3Database;
|
14
14
|
|
15
|
-
static void
|
15
|
+
static void
|
16
|
+
database_mark(void *ctx)
|
16
17
|
{
|
17
|
-
|
18
|
-
|
18
|
+
sqlite3RubyPtr c = (sqlite3RubyPtr)ctx;
|
19
|
+
rb_gc_mark(c->busy_handler);
|
20
|
+
}
|
21
|
+
|
22
|
+
static void
|
23
|
+
deallocate(void *ctx)
|
24
|
+
{
|
25
|
+
sqlite3RubyPtr c = (sqlite3RubyPtr)ctx;
|
26
|
+
sqlite3 *db = c->db;
|
27
|
+
|
28
|
+
if (db) { sqlite3_close(db); }
|
29
|
+
xfree(c);
|
30
|
+
}
|
19
31
|
|
20
|
-
|
21
|
-
|
32
|
+
static size_t
|
33
|
+
database_memsize(const void *ctx)
|
34
|
+
{
|
35
|
+
const sqlite3RubyPtr c = (const sqlite3RubyPtr)ctx;
|
36
|
+
// NB: can't account for ctx->db because the type is incomplete.
|
37
|
+
return sizeof(*c);
|
22
38
|
}
|
23
39
|
|
24
|
-
static
|
40
|
+
static const rb_data_type_t database_type = {
|
41
|
+
.wrap_struct_name = "SQLite3::Backup",
|
42
|
+
.function = {
|
43
|
+
.dmark = database_mark,
|
44
|
+
.dfree = deallocate,
|
45
|
+
.dsize = database_memsize,
|
46
|
+
},
|
47
|
+
.flags = RUBY_TYPED_WB_PROTECTED, // Not freed immediately because the dfree function do IOs.
|
48
|
+
};
|
49
|
+
|
50
|
+
static VALUE
|
51
|
+
allocate(VALUE klass)
|
25
52
|
{
|
26
|
-
|
27
|
-
|
53
|
+
sqlite3RubyPtr ctx;
|
54
|
+
return TypedData_Make_Struct(klass, sqlite3Ruby, &database_type, ctx);
|
28
55
|
}
|
29
56
|
|
30
57
|
static char *
|
31
58
|
utf16_string_value_ptr(VALUE str)
|
32
59
|
{
|
33
|
-
|
34
|
-
|
35
|
-
|
60
|
+
StringValue(str);
|
61
|
+
rb_str_buf_cat(str, "\x00\x00", 2L);
|
62
|
+
return RSTRING_PTR(str);
|
36
63
|
}
|
37
64
|
|
38
65
|
static VALUE sqlite3_rb_close(VALUE self);
|
39
66
|
|
40
|
-
|
67
|
+
sqlite3RubyPtr
|
68
|
+
sqlite3_database_unwrap(VALUE database)
|
69
|
+
{
|
70
|
+
sqlite3RubyPtr ctx;
|
71
|
+
TypedData_Get_Struct(database, sqlite3Ruby, &database_type, ctx);
|
72
|
+
return ctx;
|
73
|
+
}
|
74
|
+
|
75
|
+
static VALUE
|
76
|
+
rb_sqlite3_open_v2(VALUE self, VALUE file, VALUE mode, VALUE zvfs)
|
41
77
|
{
|
42
|
-
|
43
|
-
|
78
|
+
sqlite3RubyPtr ctx;
|
79
|
+
int status;
|
44
80
|
|
45
|
-
|
81
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
46
82
|
|
47
83
|
#if defined TAINTING_SUPPORT
|
48
84
|
# if defined StringValueCStr
|
49
|
-
|
50
|
-
|
85
|
+
StringValuePtr(file);
|
86
|
+
rb_check_safe_obj(file);
|
51
87
|
# else
|
52
|
-
|
88
|
+
Check_SafeStr(file);
|
53
89
|
# endif
|
54
90
|
#endif
|
55
91
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
92
|
+
status = sqlite3_open_v2(
|
93
|
+
StringValuePtr(file),
|
94
|
+
&ctx->db,
|
95
|
+
NUM2INT(mode),
|
96
|
+
NIL_P(zvfs) ? NULL : StringValuePtr(zvfs)
|
97
|
+
);
|
62
98
|
|
63
|
-
|
99
|
+
CHECK(ctx->db, status)
|
64
100
|
|
65
|
-
|
101
|
+
return self;
|
66
102
|
}
|
67
103
|
|
68
|
-
static VALUE
|
104
|
+
static VALUE
|
105
|
+
rb_sqlite3_disable_quirk_mode(VALUE self)
|
69
106
|
{
|
70
107
|
#if defined SQLITE_DBCONFIG_DQS_DDL
|
71
|
-
|
72
|
-
|
108
|
+
sqlite3RubyPtr ctx;
|
109
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
73
110
|
|
74
|
-
|
111
|
+
if (!ctx->db) { return Qfalse; }
|
75
112
|
|
76
|
-
|
77
|
-
|
113
|
+
sqlite3_db_config(ctx->db, SQLITE_DBCONFIG_DQS_DDL, 0, (void *)0);
|
114
|
+
sqlite3_db_config(ctx->db, SQLITE_DBCONFIG_DQS_DML, 0, (void *)0);
|
78
115
|
|
79
|
-
|
116
|
+
return Qtrue;
|
80
117
|
#else
|
81
|
-
|
118
|
+
return Qfalse;
|
82
119
|
#endif
|
83
120
|
}
|
84
121
|
|
@@ -86,34 +123,36 @@ static VALUE rb_sqlite3_disable_quirk_mode(VALUE self)
|
|
86
123
|
*
|
87
124
|
* Closes this database.
|
88
125
|
*/
|
89
|
-
static VALUE
|
126
|
+
static VALUE
|
127
|
+
sqlite3_rb_close(VALUE self)
|
90
128
|
{
|
91
|
-
|
92
|
-
|
93
|
-
|
129
|
+
sqlite3RubyPtr ctx;
|
130
|
+
sqlite3 *db;
|
131
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
94
132
|
|
95
|
-
|
96
|
-
|
133
|
+
db = ctx->db;
|
134
|
+
CHECK(db, sqlite3_close(ctx->db));
|
97
135
|
|
98
|
-
|
136
|
+
ctx->db = NULL;
|
99
137
|
|
100
|
-
|
138
|
+
rb_iv_set(self, "-aggregators", Qnil);
|
101
139
|
|
102
|
-
|
140
|
+
return self;
|
103
141
|
}
|
104
142
|
|
105
143
|
/* call-seq: db.closed?
|
106
144
|
*
|
107
145
|
* Returns +true+ if this database instance has been closed (see #close).
|
108
146
|
*/
|
109
|
-
static VALUE
|
147
|
+
static VALUE
|
148
|
+
closed_p(VALUE self)
|
110
149
|
{
|
111
|
-
|
112
|
-
|
150
|
+
sqlite3RubyPtr ctx;
|
151
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
113
152
|
|
114
|
-
|
153
|
+
if (!ctx->db) { return Qtrue; }
|
115
154
|
|
116
|
-
|
155
|
+
return Qfalse;
|
117
156
|
}
|
118
157
|
|
119
158
|
/* call-seq: total_changes
|
@@ -121,20 +160,22 @@ static VALUE closed_p(VALUE self)
|
|
121
160
|
* Returns the total number of changes made to this database instance
|
122
161
|
* since it was opened.
|
123
162
|
*/
|
124
|
-
static VALUE
|
163
|
+
static VALUE
|
164
|
+
total_changes(VALUE self)
|
125
165
|
{
|
126
|
-
|
127
|
-
|
128
|
-
|
166
|
+
sqlite3RubyPtr ctx;
|
167
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
168
|
+
REQUIRE_OPEN_DB(ctx);
|
129
169
|
|
130
|
-
|
170
|
+
return INT2NUM(sqlite3_total_changes(ctx->db));
|
131
171
|
}
|
132
172
|
|
133
|
-
static void
|
173
|
+
static void
|
174
|
+
tracefunc(void *data, const char *sql)
|
134
175
|
{
|
135
|
-
|
136
|
-
|
137
|
-
|
176
|
+
VALUE self = (VALUE)data;
|
177
|
+
VALUE thing = rb_iv_get(self, "@tracefunc");
|
178
|
+
rb_funcall(thing, rb_intern("call"), 1, rb_str_new2(sql));
|
138
179
|
}
|
139
180
|
|
140
181
|
/* call-seq:
|
@@ -145,34 +186,37 @@ static void tracefunc(void * data, const char *sql)
|
|
145
186
|
* statement executed. The block receives one parameter: the SQL statement
|
146
187
|
* executed. If the block is +nil+, any existing tracer will be uninstalled.
|
147
188
|
*/
|
148
|
-
static VALUE
|
189
|
+
static VALUE
|
190
|
+
trace(int argc, VALUE *argv, VALUE self)
|
149
191
|
{
|
150
|
-
|
151
|
-
|
192
|
+
sqlite3RubyPtr ctx;
|
193
|
+
VALUE block;
|
152
194
|
|
153
|
-
|
154
|
-
|
195
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
196
|
+
REQUIRE_OPEN_DB(ctx);
|
155
197
|
|
156
|
-
|
198
|
+
rb_scan_args(argc, argv, "01", &block);
|
157
199
|
|
158
|
-
|
200
|
+
if (NIL_P(block) && rb_block_given_p()) { block = rb_block_proc(); }
|
159
201
|
|
160
|
-
|
202
|
+
rb_iv_set(self, "@tracefunc", block);
|
161
203
|
|
162
|
-
|
204
|
+
sqlite3_trace(ctx->db, NIL_P(block) ? NULL : tracefunc, (void *)self);
|
163
205
|
|
164
|
-
|
206
|
+
return self;
|
165
207
|
}
|
166
208
|
|
167
|
-
static int
|
209
|
+
static int
|
210
|
+
rb_sqlite3_busy_handler(void *context, int count)
|
168
211
|
{
|
169
|
-
|
170
|
-
|
171
|
-
|
212
|
+
sqlite3RubyPtr ctx = (sqlite3RubyPtr)context;
|
213
|
+
|
214
|
+
VALUE handle = ctx->busy_handler;
|
215
|
+
VALUE result = rb_funcall(handle, rb_intern("call"), 1, INT2NUM(count));
|
172
216
|
|
173
|
-
|
217
|
+
if (Qfalse == result) { return 0; }
|
174
218
|
|
175
|
-
|
219
|
+
return 1;
|
176
220
|
}
|
177
221
|
|
178
222
|
/* call-seq:
|
@@ -189,27 +233,68 @@ static int rb_sqlite3_busy_handler(void * ctx, int count)
|
|
189
233
|
*
|
190
234
|
* See also the mutually exclusive #busy_timeout.
|
191
235
|
*/
|
192
|
-
static VALUE
|
236
|
+
static VALUE
|
237
|
+
busy_handler(int argc, VALUE *argv, VALUE self)
|
193
238
|
{
|
194
|
-
|
195
|
-
|
196
|
-
|
239
|
+
sqlite3RubyPtr ctx;
|
240
|
+
VALUE block;
|
241
|
+
int status;
|
197
242
|
|
198
|
-
|
199
|
-
|
243
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
244
|
+
REQUIRE_OPEN_DB(ctx);
|
200
245
|
|
201
|
-
|
246
|
+
rb_scan_args(argc, argv, "01", &block);
|
202
247
|
|
203
|
-
|
248
|
+
if (NIL_P(block) && rb_block_given_p()) { block = rb_block_proc(); }
|
249
|
+
ctx->busy_handler = block;
|
204
250
|
|
205
|
-
|
251
|
+
status = sqlite3_busy_handler(
|
252
|
+
ctx->db,
|
253
|
+
NIL_P(block) ? NULL : rb_sqlite3_busy_handler,
|
254
|
+
(void *)ctx
|
255
|
+
);
|
206
256
|
|
207
|
-
|
208
|
-
ctx->db, NIL_P(block) ? NULL : rb_sqlite3_busy_handler, (void *)self);
|
257
|
+
CHECK(ctx->db, status);
|
209
258
|
|
210
|
-
|
259
|
+
return self;
|
260
|
+
}
|
261
|
+
|
262
|
+
static int
|
263
|
+
rb_sqlite3_statement_timeout(void *context)
|
264
|
+
{
|
265
|
+
sqlite3RubyPtr ctx = (sqlite3RubyPtr)context;
|
266
|
+
struct timespec currentTime;
|
267
|
+
clock_gettime(CLOCK_MONOTONIC, ¤tTime);
|
211
268
|
|
212
|
-
|
269
|
+
if (!timespecisset(&ctx->stmt_deadline)) {
|
270
|
+
// Set stmt_deadline if not already set
|
271
|
+
ctx->stmt_deadline = currentTime;
|
272
|
+
} else if (timespecafter(¤tTime, &ctx->stmt_deadline)) {
|
273
|
+
return 1;
|
274
|
+
}
|
275
|
+
|
276
|
+
return 0;
|
277
|
+
}
|
278
|
+
|
279
|
+
/* call-seq: db.statement_timeout = ms
|
280
|
+
*
|
281
|
+
* Indicates that if a query lasts longer than the indicated number of
|
282
|
+
* milliseconds, SQLite should interrupt that query and return an error.
|
283
|
+
* By default, SQLite does not interrupt queries. To restore the default
|
284
|
+
* behavior, send 0 as the +ms+ parameter.
|
285
|
+
*/
|
286
|
+
static VALUE
|
287
|
+
set_statement_timeout(VALUE self, VALUE milliseconds)
|
288
|
+
{
|
289
|
+
sqlite3RubyPtr ctx;
|
290
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
291
|
+
|
292
|
+
ctx->stmt_timeout = NUM2INT(milliseconds);
|
293
|
+
int n = NUM2INT(milliseconds) == 0 ? -1 : 1000;
|
294
|
+
|
295
|
+
sqlite3_progress_handler(ctx->db, n, rb_sqlite3_statement_timeout, (void *)ctx);
|
296
|
+
|
297
|
+
return self;
|
213
298
|
}
|
214
299
|
|
215
300
|
/* call-seq: last_insert_row_id
|
@@ -217,115 +302,122 @@ static VALUE busy_handler(int argc, VALUE *argv, VALUE self)
|
|
217
302
|
* Obtains the unique row ID of the last row to be inserted by this Database
|
218
303
|
* instance.
|
219
304
|
*/
|
220
|
-
static VALUE
|
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
|
-
|
305
|
+
static VALUE
|
306
|
+
last_insert_row_id(VALUE self)
|
307
|
+
{
|
308
|
+
sqlite3RubyPtr ctx;
|
309
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
310
|
+
REQUIRE_OPEN_DB(ctx);
|
311
|
+
|
312
|
+
return LL2NUM(sqlite3_last_insert_rowid(ctx->db));
|
313
|
+
}
|
314
|
+
|
315
|
+
VALUE
|
316
|
+
sqlite3val2rb(sqlite3_value *val)
|
317
|
+
{
|
318
|
+
VALUE rb_val;
|
319
|
+
|
320
|
+
switch (sqlite3_value_type(val)) {
|
321
|
+
case SQLITE_INTEGER:
|
322
|
+
rb_val = LL2NUM(sqlite3_value_int64(val));
|
323
|
+
break;
|
324
|
+
case SQLITE_FLOAT:
|
325
|
+
rb_val = rb_float_new(sqlite3_value_double(val));
|
326
|
+
break;
|
327
|
+
case SQLITE_TEXT: {
|
328
|
+
rb_val = rb_utf8_str_new_cstr((const char *)sqlite3_value_text(val));
|
329
|
+
rb_obj_freeze(rb_val);
|
330
|
+
break;
|
331
|
+
}
|
332
|
+
case SQLITE_BLOB: {
|
333
|
+
int len = sqlite3_value_bytes(val);
|
334
|
+
rb_val = rb_str_new((const char *)sqlite3_value_blob(val), len);
|
335
|
+
rb_obj_freeze(rb_val);
|
336
|
+
break;
|
337
|
+
}
|
338
|
+
case SQLITE_NULL:
|
339
|
+
rb_val = Qnil;
|
340
|
+
break;
|
341
|
+
default:
|
342
|
+
rb_raise(rb_eRuntimeError, "bad type");
|
250
343
|
}
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
sqlite3_result_int64(ctx, (sqlite3_int64)FIX2LONG(result));
|
267
|
-
break;
|
268
|
-
case T_BIGNUM: {
|
344
|
+
|
345
|
+
return rb_val;
|
346
|
+
}
|
347
|
+
|
348
|
+
void
|
349
|
+
set_sqlite3_func_result(sqlite3_context *ctx, VALUE result)
|
350
|
+
{
|
351
|
+
switch (TYPE(result)) {
|
352
|
+
case T_NIL:
|
353
|
+
sqlite3_result_null(ctx);
|
354
|
+
break;
|
355
|
+
case T_FIXNUM:
|
356
|
+
sqlite3_result_int64(ctx, (sqlite3_int64)FIX2LONG(result));
|
357
|
+
break;
|
358
|
+
case T_BIGNUM: {
|
269
359
|
#if SIZEOF_LONG < 8
|
270
|
-
|
360
|
+
sqlite3_int64 num64;
|
271
361
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
362
|
+
if (bignum_to_int64(result, &num64)) {
|
363
|
+
sqlite3_result_int64(ctx, num64);
|
364
|
+
break;
|
365
|
+
}
|
276
366
|
#endif
|
367
|
+
}
|
368
|
+
case T_FLOAT:
|
369
|
+
sqlite3_result_double(ctx, NUM2DBL(result));
|
370
|
+
break;
|
371
|
+
case T_STRING:
|
372
|
+
if (CLASS_OF(result) == cSqlite3Blob
|
373
|
+
|| rb_enc_get_index(result) == rb_ascii8bit_encindex()
|
374
|
+
) {
|
375
|
+
sqlite3_result_blob(
|
376
|
+
ctx,
|
377
|
+
(const void *)StringValuePtr(result),
|
378
|
+
(int)RSTRING_LEN(result),
|
379
|
+
SQLITE_TRANSIENT
|
380
|
+
);
|
381
|
+
} else {
|
382
|
+
sqlite3_result_text(
|
383
|
+
ctx,
|
384
|
+
(const char *)StringValuePtr(result),
|
385
|
+
(int)RSTRING_LEN(result),
|
386
|
+
SQLITE_TRANSIENT
|
387
|
+
);
|
388
|
+
}
|
389
|
+
break;
|
390
|
+
default:
|
391
|
+
rb_raise(rb_eRuntimeError, "can't return %s",
|
392
|
+
rb_class2name(CLASS_OF(result)));
|
277
393
|
}
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
ctx,
|
294
|
-
(const char *)StringValuePtr(result),
|
295
|
-
(int)RSTRING_LEN(result),
|
296
|
-
SQLITE_TRANSIENT
|
297
|
-
);
|
298
|
-
}
|
299
|
-
break;
|
300
|
-
default:
|
301
|
-
rb_raise(rb_eRuntimeError, "can't return %s",
|
302
|
-
rb_class2name(CLASS_OF(result)));
|
303
|
-
}
|
304
|
-
}
|
305
|
-
|
306
|
-
static void rb_sqlite3_func(sqlite3_context * ctx, int argc, sqlite3_value **argv)
|
307
|
-
{
|
308
|
-
VALUE callable = (VALUE)sqlite3_user_data(ctx);
|
309
|
-
VALUE params = rb_ary_new2(argc);
|
310
|
-
VALUE result;
|
311
|
-
int i;
|
312
|
-
|
313
|
-
if (argc > 0) {
|
314
|
-
for(i = 0; i < argc; i++) {
|
315
|
-
VALUE param = sqlite3val2rb(argv[i]);
|
316
|
-
rb_ary_push(params, param);
|
394
|
+
}
|
395
|
+
|
396
|
+
static void
|
397
|
+
rb_sqlite3_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
|
398
|
+
{
|
399
|
+
VALUE callable = (VALUE)sqlite3_user_data(ctx);
|
400
|
+
VALUE params = rb_ary_new2(argc);
|
401
|
+
VALUE result;
|
402
|
+
int i;
|
403
|
+
|
404
|
+
if (argc > 0) {
|
405
|
+
for (i = 0; i < argc; i++) {
|
406
|
+
VALUE param = sqlite3val2rb(argv[i]);
|
407
|
+
rb_ary_push(params, param);
|
408
|
+
}
|
317
409
|
}
|
318
|
-
}
|
319
410
|
|
320
|
-
|
411
|
+
result = rb_apply(callable, rb_intern("call"), params);
|
321
412
|
|
322
|
-
|
413
|
+
set_sqlite3_func_result(ctx, result);
|
323
414
|
}
|
324
415
|
|
325
416
|
#ifndef HAVE_RB_PROC_ARITY
|
326
|
-
int
|
417
|
+
int
|
418
|
+
rb_proc_arity(VALUE self)
|
327
419
|
{
|
328
|
-
|
420
|
+
return (int)NUM2INT(rb_funcall(self, rb_intern("arity"), 0));
|
329
421
|
}
|
330
422
|
#endif
|
331
423
|
|
@@ -334,33 +426,34 @@ int rb_proc_arity(VALUE self)
|
|
334
426
|
* Define a function named +name+ with +args+ using TextRep bitflags +flags+. The arity of the block
|
335
427
|
* will be used as the arity for the function defined.
|
336
428
|
*/
|
337
|
-
static VALUE
|
429
|
+
static VALUE
|
430
|
+
define_function_with_flags(VALUE self, VALUE name, VALUE flags)
|
338
431
|
{
|
339
|
-
|
340
|
-
|
341
|
-
|
432
|
+
sqlite3RubyPtr ctx;
|
433
|
+
VALUE block;
|
434
|
+
int status;
|
342
435
|
|
343
|
-
|
344
|
-
|
436
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
437
|
+
REQUIRE_OPEN_DB(ctx);
|
345
438
|
|
346
|
-
|
439
|
+
block = rb_block_proc();
|
347
440
|
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
441
|
+
status = sqlite3_create_function(
|
442
|
+
ctx->db,
|
443
|
+
StringValuePtr(name),
|
444
|
+
rb_proc_arity(block),
|
445
|
+
NUM2INT(flags),
|
446
|
+
(void *)block,
|
447
|
+
rb_sqlite3_func,
|
448
|
+
NULL,
|
449
|
+
NULL
|
450
|
+
);
|
358
451
|
|
359
|
-
|
452
|
+
CHECK(ctx->db, status);
|
360
453
|
|
361
|
-
|
454
|
+
rb_hash_aset(rb_iv_get(self, "@functions"), name, block);
|
362
455
|
|
363
|
-
|
456
|
+
return self;
|
364
457
|
}
|
365
458
|
|
366
459
|
/* call-seq: define_function(name) { |args,...| }
|
@@ -368,24 +461,26 @@ static VALUE define_function_with_flags(VALUE self, VALUE name, VALUE flags)
|
|
368
461
|
* Define a function named +name+ with +args+. The arity of the block
|
369
462
|
* will be used as the arity for the function defined.
|
370
463
|
*/
|
371
|
-
static VALUE
|
464
|
+
static VALUE
|
465
|
+
define_function(VALUE self, VALUE name)
|
372
466
|
{
|
373
|
-
|
467
|
+
return define_function_with_flags(self, name, INT2FIX(SQLITE_UTF8));
|
374
468
|
}
|
375
469
|
|
376
470
|
/* call-seq: interrupt
|
377
471
|
*
|
378
472
|
* Interrupts the currently executing operation, causing it to abort.
|
379
473
|
*/
|
380
|
-
static VALUE
|
474
|
+
static VALUE
|
475
|
+
interrupt(VALUE self)
|
381
476
|
{
|
382
|
-
|
383
|
-
|
384
|
-
|
477
|
+
sqlite3RubyPtr ctx;
|
478
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
479
|
+
REQUIRE_OPEN_DB(ctx);
|
385
480
|
|
386
|
-
|
481
|
+
sqlite3_interrupt(ctx->db);
|
387
482
|
|
388
|
-
|
483
|
+
return self;
|
389
484
|
}
|
390
485
|
|
391
486
|
/* call-seq: errmsg
|
@@ -393,13 +488,14 @@ static VALUE interrupt(VALUE self)
|
|
393
488
|
* Return a string describing the last error to have occurred with this
|
394
489
|
* database.
|
395
490
|
*/
|
396
|
-
static VALUE
|
491
|
+
static VALUE
|
492
|
+
errmsg(VALUE self)
|
397
493
|
{
|
398
|
-
|
399
|
-
|
400
|
-
|
494
|
+
sqlite3RubyPtr ctx;
|
495
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
496
|
+
REQUIRE_OPEN_DB(ctx);
|
401
497
|
|
402
|
-
|
498
|
+
return rb_str_new2(sqlite3_errmsg(ctx->db));
|
403
499
|
}
|
404
500
|
|
405
501
|
/* call-seq: errcode
|
@@ -407,13 +503,14 @@ static VALUE errmsg(VALUE self)
|
|
407
503
|
* Return an integer representing the last error to have occurred with this
|
408
504
|
* database.
|
409
505
|
*/
|
410
|
-
static VALUE
|
506
|
+
static VALUE
|
507
|
+
errcode_(VALUE self)
|
411
508
|
{
|
412
|
-
|
413
|
-
|
414
|
-
|
509
|
+
sqlite3RubyPtr ctx;
|
510
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
511
|
+
REQUIRE_OPEN_DB(ctx);
|
415
512
|
|
416
|
-
|
513
|
+
return INT2NUM(sqlite3_errcode(ctx->db));
|
417
514
|
}
|
418
515
|
|
419
516
|
/* call-seq: complete?(sql)
|
@@ -421,12 +518,14 @@ static VALUE errcode_(VALUE self)
|
|
421
518
|
* Return +true+ if the string is a valid (ie, parsable) SQL statement, and
|
422
519
|
* +false+ otherwise.
|
423
520
|
*/
|
424
|
-
static VALUE
|
521
|
+
static VALUE
|
522
|
+
complete_p(VALUE UNUSED(self), VALUE sql)
|
425
523
|
{
|
426
|
-
|
427
|
-
|
524
|
+
if (sqlite3_complete(StringValuePtr(sql))) {
|
525
|
+
return Qtrue;
|
526
|
+
}
|
428
527
|
|
429
|
-
|
528
|
+
return Qfalse;
|
430
529
|
}
|
431
530
|
|
432
531
|
/* call-seq: changes
|
@@ -435,37 +534,39 @@ static VALUE complete_p(VALUE UNUSED(self), VALUE sql)
|
|
435
534
|
* operation performed. Note that a "delete from table" without a where
|
436
535
|
* clause will not affect this value.
|
437
536
|
*/
|
438
|
-
static VALUE
|
537
|
+
static VALUE
|
538
|
+
changes(VALUE self)
|
439
539
|
{
|
440
|
-
|
441
|
-
|
442
|
-
|
540
|
+
sqlite3RubyPtr ctx;
|
541
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
542
|
+
REQUIRE_OPEN_DB(ctx);
|
443
543
|
|
444
|
-
|
544
|
+
return INT2NUM(sqlite3_changes(ctx->db));
|
445
545
|
}
|
446
546
|
|
447
|
-
static int
|
547
|
+
static int
|
548
|
+
rb_sqlite3_auth(
|
448
549
|
void *ctx,
|
449
550
|
int _action,
|
450
|
-
const char *
|
451
|
-
const char *
|
452
|
-
const char *
|
453
|
-
const char *
|
551
|
+
const char *_a,
|
552
|
+
const char *_b,
|
553
|
+
const char *_c,
|
554
|
+
const char *_d)
|
454
555
|
{
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
556
|
+
VALUE self = (VALUE)ctx;
|
557
|
+
VALUE action = INT2NUM(_action);
|
558
|
+
VALUE a = _a ? rb_str_new2(_a) : Qnil;
|
559
|
+
VALUE b = _b ? rb_str_new2(_b) : Qnil;
|
560
|
+
VALUE c = _c ? rb_str_new2(_c) : Qnil;
|
561
|
+
VALUE d = _d ? rb_str_new2(_d) : Qnil;
|
562
|
+
VALUE callback = rb_iv_get(self, "@authorizer");
|
563
|
+
VALUE result = rb_funcall(callback, rb_intern("call"), 5, action, a, b, c, d);
|
463
564
|
|
464
|
-
|
465
|
-
|
466
|
-
|
565
|
+
if (T_FIXNUM == TYPE(result)) { return (int)NUM2INT(result); }
|
566
|
+
if (Qtrue == result) { return SQLITE_OK; }
|
567
|
+
if (Qfalse == result) { return SQLITE_DENY; }
|
467
568
|
|
468
|
-
|
569
|
+
return SQLITE_IGNORE;
|
469
570
|
}
|
470
571
|
|
471
572
|
/* call-seq: set_authorizer = auth
|
@@ -478,23 +579,24 @@ static int rb_sqlite3_auth(
|
|
478
579
|
* is allowed to proceed. Returning 1 or false causes an authorization error to
|
479
580
|
* occur, and returning 2 or nil causes the access to be silently denied.
|
480
581
|
*/
|
481
|
-
static VALUE
|
582
|
+
static VALUE
|
583
|
+
set_authorizer(VALUE self, VALUE authorizer)
|
482
584
|
{
|
483
|
-
|
484
|
-
|
585
|
+
sqlite3RubyPtr ctx;
|
586
|
+
int status;
|
485
587
|
|
486
|
-
|
487
|
-
|
588
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
589
|
+
REQUIRE_OPEN_DB(ctx);
|
488
590
|
|
489
|
-
|
490
|
-
|
491
|
-
|
591
|
+
status = sqlite3_set_authorizer(
|
592
|
+
ctx->db, NIL_P(authorizer) ? NULL : rb_sqlite3_auth, (void *)self
|
593
|
+
);
|
492
594
|
|
493
|
-
|
595
|
+
CHECK(ctx->db, status);
|
494
596
|
|
495
|
-
|
597
|
+
rb_iv_set(self, "@authorizer", authorizer);
|
496
598
|
|
497
|
-
|
599
|
+
return self;
|
498
600
|
}
|
499
601
|
|
500
602
|
/* call-seq: db.busy_timeout = ms
|
@@ -507,15 +609,16 @@ static VALUE set_authorizer(VALUE self, VALUE authorizer)
|
|
507
609
|
*
|
508
610
|
* See also the mutually exclusive #busy_handler.
|
509
611
|
*/
|
510
|
-
static VALUE
|
612
|
+
static VALUE
|
613
|
+
set_busy_timeout(VALUE self, VALUE timeout)
|
511
614
|
{
|
512
|
-
|
513
|
-
|
514
|
-
|
615
|
+
sqlite3RubyPtr ctx;
|
616
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
617
|
+
REQUIRE_OPEN_DB(ctx);
|
515
618
|
|
516
|
-
|
619
|
+
CHECK(ctx->db, sqlite3_busy_timeout(ctx->db, (int)NUM2INT(timeout)));
|
517
620
|
|
518
|
-
|
621
|
+
return self;
|
519
622
|
}
|
520
623
|
|
521
624
|
/* call-seq: db.extended_result_codes = true
|
@@ -523,42 +626,44 @@ static VALUE set_busy_timeout(VALUE self, VALUE timeout)
|
|
523
626
|
* Enable extended result codes in SQLite. These result codes allow for more
|
524
627
|
* detailed exception reporting, such a which type of constraint is violated.
|
525
628
|
*/
|
526
|
-
static VALUE
|
629
|
+
static VALUE
|
630
|
+
set_extended_result_codes(VALUE self, VALUE enable)
|
527
631
|
{
|
528
|
-
|
529
|
-
|
530
|
-
|
632
|
+
sqlite3RubyPtr ctx;
|
633
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
634
|
+
REQUIRE_OPEN_DB(ctx);
|
531
635
|
|
532
|
-
|
636
|
+
CHECK(ctx->db, sqlite3_extended_result_codes(ctx->db, RTEST(enable) ? 1 : 0));
|
533
637
|
|
534
|
-
|
638
|
+
return self;
|
535
639
|
}
|
536
640
|
|
537
|
-
int
|
641
|
+
int
|
642
|
+
rb_comparator_func(void *ctx, int a_len, const void *a, int b_len, const void *b)
|
538
643
|
{
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
644
|
+
VALUE comparator;
|
645
|
+
VALUE a_str;
|
646
|
+
VALUE b_str;
|
647
|
+
VALUE comparison;
|
648
|
+
rb_encoding *internal_encoding;
|
544
649
|
|
545
|
-
|
650
|
+
internal_encoding = rb_default_internal_encoding();
|
546
651
|
|
547
|
-
|
548
|
-
|
549
|
-
|
652
|
+
comparator = (VALUE)ctx;
|
653
|
+
a_str = rb_str_new((const char *)a, a_len);
|
654
|
+
b_str = rb_str_new((const char *)b, b_len);
|
550
655
|
|
551
|
-
|
552
|
-
|
656
|
+
rb_enc_associate_index(a_str, rb_utf8_encindex());
|
657
|
+
rb_enc_associate_index(b_str, rb_utf8_encindex());
|
553
658
|
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
659
|
+
if (internal_encoding) {
|
660
|
+
a_str = rb_str_export_to_enc(a_str, internal_encoding);
|
661
|
+
b_str = rb_str_export_to_enc(b_str, internal_encoding);
|
662
|
+
}
|
558
663
|
|
559
|
-
|
664
|
+
comparison = rb_funcall(comparator, rb_intern("compare"), 2, a_str, b_str);
|
560
665
|
|
561
|
-
|
666
|
+
return NUM2INT(comparison);
|
562
667
|
}
|
563
668
|
|
564
669
|
/* call-seq: db.collation(name, comparator)
|
@@ -568,23 +673,24 @@ int rb_comparator_func(void * ctx, int a_len, const void * a, int b_len, const v
|
|
568
673
|
* two parameters and returns an integer less than, equal to, or greater than
|
569
674
|
* 0.
|
570
675
|
*/
|
571
|
-
static VALUE
|
676
|
+
static VALUE
|
677
|
+
collation(VALUE self, VALUE name, VALUE comparator)
|
572
678
|
{
|
573
|
-
|
574
|
-
|
575
|
-
|
679
|
+
sqlite3RubyPtr ctx;
|
680
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
681
|
+
REQUIRE_OPEN_DB(ctx);
|
576
682
|
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
683
|
+
CHECK(ctx->db, sqlite3_create_collation(
|
684
|
+
ctx->db,
|
685
|
+
StringValuePtr(name),
|
686
|
+
SQLITE_UTF8,
|
687
|
+
(void *)comparator,
|
688
|
+
NIL_P(comparator) ? NULL : rb_comparator_func));
|
583
689
|
|
584
|
-
|
585
|
-
|
690
|
+
/* Make sure our comparator doesn't get garbage collected. */
|
691
|
+
rb_hash_aset(rb_iv_get(self, "@collations"), name, comparator);
|
586
692
|
|
587
|
-
|
693
|
+
return self;
|
588
694
|
}
|
589
695
|
|
590
696
|
#ifdef HAVE_SQLITE3_LOAD_EXTENSION
|
@@ -594,24 +700,21 @@ static VALUE collation(VALUE self, VALUE name, VALUE comparator)
|
|
594
700
|
* loading must be enabled using db.enable_load_extension(true) prior
|
595
701
|
* to calling this API.
|
596
702
|
*/
|
597
|
-
static VALUE
|
703
|
+
static VALUE
|
704
|
+
load_extension(VALUE self, VALUE file)
|
598
705
|
{
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
706
|
+
sqlite3RubyPtr ctx;
|
707
|
+
int status;
|
708
|
+
char *errMsg;
|
709
|
+
|
710
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
711
|
+
REQUIRE_OPEN_DB(ctx);
|
605
712
|
|
606
|
-
|
607
|
-
if (status != SQLITE_OK)
|
608
|
-
{
|
609
|
-
errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
|
610
|
-
sqlite3_free(errMsg);
|
611
|
-
rb_exc_raise(errexp);
|
612
|
-
}
|
713
|
+
status = sqlite3_load_extension(ctx->db, StringValuePtr(file), 0, &errMsg);
|
613
714
|
|
614
|
-
|
715
|
+
CHECK_MSG(ctx->db, status, errMsg);
|
716
|
+
|
717
|
+
return self;
|
615
718
|
}
|
616
719
|
#endif
|
617
720
|
|
@@ -620,107 +723,79 @@ static VALUE load_extension(VALUE self, VALUE file)
|
|
620
723
|
*
|
621
724
|
* Enable or disable extension loading.
|
622
725
|
*/
|
623
|
-
static VALUE
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
726
|
+
static VALUE
|
727
|
+
enable_load_extension(VALUE self, VALUE onoff)
|
728
|
+
{
|
729
|
+
sqlite3RubyPtr ctx;
|
730
|
+
int onoffparam;
|
731
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
732
|
+
REQUIRE_OPEN_DB(ctx);
|
733
|
+
|
734
|
+
if (Qtrue == onoff) {
|
735
|
+
onoffparam = 1;
|
736
|
+
} else if (Qfalse == onoff) {
|
737
|
+
onoffparam = 0;
|
738
|
+
} else {
|
739
|
+
onoffparam = (int)NUM2INT(onoff);
|
740
|
+
}
|
637
741
|
|
638
|
-
|
742
|
+
CHECK(ctx->db, sqlite3_enable_load_extension(ctx->db, onoffparam));
|
639
743
|
|
640
|
-
|
744
|
+
return self;
|
641
745
|
}
|
642
746
|
#endif
|
643
747
|
|
644
|
-
static int enc_cb(void * _self, int UNUSED(columns), char **data, char **UNUSED(names))
|
645
|
-
{
|
646
|
-
VALUE self = (VALUE)_self;
|
647
|
-
|
648
|
-
int index = rb_enc_find_index(data[0]);
|
649
|
-
rb_encoding * e = rb_enc_from_index(index);
|
650
|
-
rb_iv_set(self, "@encoding", rb_enc_from_encoding(e));
|
651
|
-
|
652
|
-
return 0;
|
653
|
-
}
|
654
|
-
|
655
|
-
/* call-seq: db.encoding
|
656
|
-
*
|
657
|
-
* Fetch the encoding set on this database
|
658
|
-
*/
|
659
|
-
static VALUE db_encoding(VALUE self)
|
660
|
-
{
|
661
|
-
sqlite3RubyPtr ctx;
|
662
|
-
VALUE enc;
|
663
|
-
|
664
|
-
Data_Get_Struct(self, sqlite3Ruby, ctx);
|
665
|
-
REQUIRE_OPEN_DB(ctx);
|
666
|
-
|
667
|
-
enc = rb_iv_get(self, "@encoding");
|
668
|
-
|
669
|
-
if(NIL_P(enc)) {
|
670
|
-
sqlite3_exec(ctx->db, "PRAGMA encoding", enc_cb, (void *)self, NULL);
|
671
|
-
}
|
672
|
-
|
673
|
-
return rb_iv_get(self, "@encoding");
|
674
|
-
}
|
675
|
-
|
676
748
|
/* call-seq: db.transaction_active?
|
677
749
|
*
|
678
750
|
* Returns +true+ if there is a transaction active, and +false+ otherwise.
|
679
751
|
*
|
680
752
|
*/
|
681
|
-
static VALUE
|
753
|
+
static VALUE
|
754
|
+
transaction_active_p(VALUE self)
|
682
755
|
{
|
683
|
-
|
684
|
-
|
685
|
-
|
756
|
+
sqlite3RubyPtr ctx;
|
757
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
758
|
+
REQUIRE_OPEN_DB(ctx);
|
686
759
|
|
687
|
-
|
760
|
+
return sqlite3_get_autocommit(ctx->db) ? Qfalse : Qtrue;
|
688
761
|
}
|
689
762
|
|
690
|
-
static int
|
763
|
+
static int
|
764
|
+
hash_callback_function(VALUE callback_ary, int count, char **data, char **columns)
|
691
765
|
{
|
692
|
-
|
693
|
-
|
766
|
+
VALUE new_hash = rb_hash_new();
|
767
|
+
int i;
|
694
768
|
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
769
|
+
for (i = 0; i < count; i++) {
|
770
|
+
if (data[i] == NULL) {
|
771
|
+
rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), Qnil);
|
772
|
+
} else {
|
773
|
+
rb_hash_aset(new_hash, rb_str_new_cstr(columns[i]), rb_str_new_cstr(data[i]));
|
774
|
+
}
|
700
775
|
}
|
701
|
-
}
|
702
776
|
|
703
|
-
|
777
|
+
rb_ary_push(callback_ary, new_hash);
|
704
778
|
|
705
|
-
|
779
|
+
return 0;
|
706
780
|
}
|
707
781
|
|
708
|
-
static int
|
782
|
+
static int
|
783
|
+
regular_callback_function(VALUE callback_ary, int count, char **data, char **columns)
|
709
784
|
{
|
710
|
-
|
711
|
-
|
785
|
+
VALUE new_ary = rb_ary_new();
|
786
|
+
int i;
|
712
787
|
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
788
|
+
for (i = 0; i < count; i++) {
|
789
|
+
if (data[i] == NULL) {
|
790
|
+
rb_ary_push(new_ary, Qnil);
|
791
|
+
} else {
|
792
|
+
rb_ary_push(new_ary, rb_str_new_cstr(data[i]));
|
793
|
+
}
|
718
794
|
}
|
719
|
-
}
|
720
795
|
|
721
|
-
|
796
|
+
rb_ary_push(callback_ary, new_ary);
|
722
797
|
|
723
|
-
|
798
|
+
return 0;
|
724
799
|
}
|
725
800
|
|
726
801
|
|
@@ -732,31 +807,30 @@ static int regular_callback_function(VALUE callback_ary, int count, char **data,
|
|
732
807
|
* so the user may parse values with a block.
|
733
808
|
* If no query is made, an empty array will be returned.
|
734
809
|
*/
|
735
|
-
static VALUE
|
810
|
+
static VALUE
|
811
|
+
exec_batch(VALUE self, VALUE sql, VALUE results_as_hash)
|
736
812
|
{
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
VALUE errexp;
|
813
|
+
sqlite3RubyPtr ctx;
|
814
|
+
int status;
|
815
|
+
VALUE callback_ary = rb_ary_new();
|
816
|
+
char *errMsg;
|
742
817
|
|
743
|
-
|
744
|
-
|
818
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
819
|
+
REQUIRE_OPEN_DB(ctx);
|
745
820
|
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
821
|
+
if (results_as_hash == Qtrue) {
|
822
|
+
status = sqlite3_exec(ctx->db, StringValuePtr(sql), (sqlite3_callback)hash_callback_function,
|
823
|
+
(void *)callback_ary,
|
824
|
+
&errMsg);
|
825
|
+
} else {
|
826
|
+
status = sqlite3_exec(ctx->db, StringValuePtr(sql), (sqlite3_callback)regular_callback_function,
|
827
|
+
(void *)callback_ary,
|
828
|
+
&errMsg);
|
829
|
+
}
|
751
830
|
|
752
|
-
|
753
|
-
{
|
754
|
-
errexp = rb_exc_new2(rb_eRuntimeError, errMsg);
|
755
|
-
sqlite3_free(errMsg);
|
756
|
-
rb_exc_raise(errexp);
|
757
|
-
}
|
831
|
+
CHECK_MSG(ctx->db, status, errMsg);
|
758
832
|
|
759
|
-
|
833
|
+
return callback_ary;
|
760
834
|
}
|
761
835
|
|
762
836
|
/* call-seq: db.db_filename(database_name)
|
@@ -764,88 +838,92 @@ static VALUE exec_batch(VALUE self, VALUE sql, VALUE results_as_hash)
|
|
764
838
|
* Returns the file associated with +database_name+. Can return nil or an
|
765
839
|
* empty string if the database is temporary, or in-memory.
|
766
840
|
*/
|
767
|
-
static VALUE
|
841
|
+
static VALUE
|
842
|
+
db_filename(VALUE self, VALUE db_name)
|
768
843
|
{
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
844
|
+
sqlite3RubyPtr ctx;
|
845
|
+
const char *fname;
|
846
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
847
|
+
REQUIRE_OPEN_DB(ctx);
|
773
848
|
|
774
|
-
|
849
|
+
fname = sqlite3_db_filename(ctx->db, StringValueCStr(db_name));
|
775
850
|
|
776
|
-
|
777
|
-
|
851
|
+
if (fname) { return SQLITE3_UTF8_STR_NEW2(fname); }
|
852
|
+
return Qnil;
|
778
853
|
}
|
779
854
|
|
780
|
-
static VALUE
|
855
|
+
static VALUE
|
856
|
+
rb_sqlite3_open16(VALUE self, VALUE file)
|
781
857
|
{
|
782
|
-
|
783
|
-
|
858
|
+
int status;
|
859
|
+
sqlite3RubyPtr ctx;
|
784
860
|
|
785
|
-
|
861
|
+
TypedData_Get_Struct(self, sqlite3Ruby, &database_type, ctx);
|
786
862
|
|
787
863
|
#if defined TAINTING_SUPPORT
|
788
864
|
#if defined StringValueCStr
|
789
|
-
|
790
|
-
|
865
|
+
StringValuePtr(file);
|
866
|
+
rb_check_safe_obj(file);
|
791
867
|
#else
|
792
|
-
|
868
|
+
Check_SafeStr(file);
|
793
869
|
#endif
|
794
870
|
#endif
|
795
871
|
|
796
|
-
|
872
|
+
status = sqlite3_open16(utf16_string_value_ptr(file), &ctx->db);
|
797
873
|
|
798
|
-
|
874
|
+
CHECK(ctx->db, status)
|
799
875
|
|
800
|
-
|
876
|
+
return INT2NUM(status);
|
801
877
|
}
|
802
878
|
|
803
|
-
void
|
879
|
+
void
|
880
|
+
init_sqlite3_database(void)
|
804
881
|
{
|
805
882
|
#if 0
|
806
|
-
|
883
|
+
VALUE mSqlite3 = rb_define_module("SQLite3");
|
884
|
+
#endif
|
885
|
+
cSqlite3Database = rb_define_class_under(mSqlite3, "Database", rb_cObject);
|
886
|
+
|
887
|
+
rb_define_alloc_func(cSqlite3Database, allocate);
|
888
|
+
rb_define_private_method(cSqlite3Database, "open_v2", rb_sqlite3_open_v2, 3);
|
889
|
+
rb_define_private_method(cSqlite3Database, "open16", rb_sqlite3_open16, 1);
|
890
|
+
rb_define_method(cSqlite3Database, "collation", collation, 2);
|
891
|
+
rb_define_method(cSqlite3Database, "close", sqlite3_rb_close, 0);
|
892
|
+
rb_define_method(cSqlite3Database, "closed?", closed_p, 0);
|
893
|
+
rb_define_method(cSqlite3Database, "total_changes", total_changes, 0);
|
894
|
+
rb_define_method(cSqlite3Database, "trace", trace, -1);
|
895
|
+
rb_define_method(cSqlite3Database, "last_insert_row_id", last_insert_row_id, 0);
|
896
|
+
rb_define_method(cSqlite3Database, "define_function", define_function, 1);
|
897
|
+
rb_define_method(cSqlite3Database, "define_function_with_flags", define_function_with_flags, 2);
|
898
|
+
/* public "define_aggregator" is now a shim around define_aggregator2
|
899
|
+
* implemented in Ruby */
|
900
|
+
rb_define_private_method(cSqlite3Database, "define_aggregator2", rb_sqlite3_define_aggregator2, 2);
|
901
|
+
rb_define_private_method(cSqlite3Database, "disable_quirk_mode", rb_sqlite3_disable_quirk_mode, 0);
|
902
|
+
rb_define_method(cSqlite3Database, "interrupt", interrupt, 0);
|
903
|
+
rb_define_method(cSqlite3Database, "errmsg", errmsg, 0);
|
904
|
+
rb_define_method(cSqlite3Database, "errcode", errcode_, 0);
|
905
|
+
rb_define_method(cSqlite3Database, "complete?", complete_p, 1);
|
906
|
+
rb_define_method(cSqlite3Database, "changes", changes, 0);
|
907
|
+
rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
|
908
|
+
rb_define_method(cSqlite3Database, "busy_handler", busy_handler, -1);
|
909
|
+
rb_define_method(cSqlite3Database, "busy_timeout=", set_busy_timeout, 1);
|
910
|
+
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
911
|
+
rb_define_method(cSqlite3Database, "statement_timeout=", set_statement_timeout, 1);
|
807
912
|
#endif
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
rb_define_private_method(cSqlite3Database, "open16", rb_sqlite3_open16, 1);
|
813
|
-
rb_define_method(cSqlite3Database, "collation", collation, 2);
|
814
|
-
rb_define_method(cSqlite3Database, "close", sqlite3_rb_close, 0);
|
815
|
-
rb_define_method(cSqlite3Database, "closed?", closed_p, 0);
|
816
|
-
rb_define_method(cSqlite3Database, "total_changes", total_changes, 0);
|
817
|
-
rb_define_method(cSqlite3Database, "trace", trace, -1);
|
818
|
-
rb_define_method(cSqlite3Database, "last_insert_row_id", last_insert_row_id, 0);
|
819
|
-
rb_define_method(cSqlite3Database, "define_function", define_function, 1);
|
820
|
-
rb_define_method(cSqlite3Database, "define_function_with_flags", define_function_with_flags, 2);
|
821
|
-
/* public "define_aggregator" is now a shim around define_aggregator2
|
822
|
-
* implemented in Ruby */
|
823
|
-
rb_define_private_method(cSqlite3Database, "define_aggregator2", rb_sqlite3_define_aggregator2, 2);
|
824
|
-
rb_define_private_method(cSqlite3Database, "disable_quirk_mode", rb_sqlite3_disable_quirk_mode, 0);
|
825
|
-
rb_define_method(cSqlite3Database, "interrupt", interrupt, 0);
|
826
|
-
rb_define_method(cSqlite3Database, "errmsg", errmsg, 0);
|
827
|
-
rb_define_method(cSqlite3Database, "errcode", errcode_, 0);
|
828
|
-
rb_define_method(cSqlite3Database, "complete?", complete_p, 1);
|
829
|
-
rb_define_method(cSqlite3Database, "changes", changes, 0);
|
830
|
-
rb_define_method(cSqlite3Database, "authorizer=", set_authorizer, 1);
|
831
|
-
rb_define_method(cSqlite3Database, "busy_handler", busy_handler, -1);
|
832
|
-
rb_define_method(cSqlite3Database, "busy_timeout=", set_busy_timeout, 1);
|
833
|
-
rb_define_method(cSqlite3Database, "extended_result_codes=", set_extended_result_codes, 1);
|
834
|
-
rb_define_method(cSqlite3Database, "transaction_active?", transaction_active_p, 0);
|
835
|
-
rb_define_private_method(cSqlite3Database, "exec_batch", exec_batch, 2);
|
836
|
-
rb_define_private_method(cSqlite3Database, "db_filename", db_filename, 1);
|
913
|
+
rb_define_method(cSqlite3Database, "extended_result_codes=", set_extended_result_codes, 1);
|
914
|
+
rb_define_method(cSqlite3Database, "transaction_active?", transaction_active_p, 0);
|
915
|
+
rb_define_private_method(cSqlite3Database, "exec_batch", exec_batch, 2);
|
916
|
+
rb_define_private_method(cSqlite3Database, "db_filename", db_filename, 1);
|
837
917
|
|
838
918
|
#ifdef HAVE_SQLITE3_LOAD_EXTENSION
|
839
|
-
|
919
|
+
rb_define_method(cSqlite3Database, "load_extension", load_extension, 1);
|
840
920
|
#endif
|
841
921
|
|
842
922
|
#ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
|
843
|
-
|
923
|
+
rb_define_method(cSqlite3Database, "enable_load_extension", enable_load_extension, 1);
|
844
924
|
#endif
|
845
925
|
|
846
|
-
|
847
|
-
|
848
|
-
rb_sqlite3_aggregator_init();
|
926
|
+
rb_sqlite3_aggregator_init();
|
849
927
|
}
|
850
928
|
|
851
929
|
#ifdef _MSC_VER
|