extralite 1.27 → 2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +1 -1
- data/LICENSE +1 -1
- data/README.md +40 -14
- data/TODO.md +21 -0
- data/ext/extralite/common.c +80 -58
- data/ext/extralite/database.c +138 -78
- data/ext/extralite/extconf.rb +16 -16
- data/ext/extralite/extralite.h +63 -17
- data/ext/extralite/extralite_ext.c +4 -2
- data/ext/extralite/iterator.c +208 -0
- data/ext/extralite/query.c +534 -0
- data/lib/extralite/sqlite3_constants.rb +1 -1
- data/lib/extralite/version.rb +1 -1
- data/lib/extralite.rb +0 -2
- data/lib/sequel/adapters/extralite.rb +104 -106
- data/test/perf_prepared.rb +2 -2
- data/test/test_database.rb +35 -9
- data/test/test_extralite.rb +1 -1
- data/test/test_iterator.rb +104 -0
- data/test/test_query.rb +519 -0
- data/test/test_sequel.rb +23 -4
- metadata +6 -4
- data/ext/extralite/prepared_statement.c +0 -333
- data/test/test_prepared_statement.rb +0 -225
data/ext/extralite/database.c
CHANGED
@@ -6,13 +6,17 @@ VALUE cError;
|
|
6
6
|
VALUE cSQLError;
|
7
7
|
VALUE cBusyError;
|
8
8
|
VALUE cInterruptError;
|
9
|
+
VALUE eArgumentError;
|
9
10
|
|
11
|
+
ID ID_bind;
|
10
12
|
ID ID_call;
|
11
13
|
ID ID_keys;
|
12
14
|
ID ID_new;
|
13
15
|
ID ID_strip;
|
14
16
|
ID ID_to_s;
|
15
17
|
|
18
|
+
VALUE SYM_read_only;
|
19
|
+
|
16
20
|
static size_t Database_size(const void *ptr) {
|
17
21
|
return sizeof(Database_t);
|
18
22
|
}
|
@@ -35,27 +39,21 @@ static VALUE Database_allocate(VALUE klass) {
|
|
35
39
|
return TypedData_Wrap_Struct(klass, &Database_type, db);
|
36
40
|
}
|
37
41
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
#define GetOpenDatabase(obj, database) { \
|
43
|
-
TypedData_Get_Struct((obj), Database_t, &Database_type, (database)); \
|
44
|
-
if (!(database)->sqlite3_db) { \
|
45
|
-
rb_raise(cError, "Database is closed"); \
|
46
|
-
} \
|
42
|
+
inline Database_t *self_to_database(VALUE self) {
|
43
|
+
Database_t *db;
|
44
|
+
TypedData_Get_Struct(self, Database_t, &Database_type, db);
|
45
|
+
return db;
|
47
46
|
}
|
48
47
|
|
49
|
-
Database_t *
|
50
|
-
Database_t *db;
|
51
|
-
|
48
|
+
inline Database_t *self_to_open_database(VALUE self) {
|
49
|
+
Database_t *db = self_to_database(self);
|
50
|
+
if (!(db)->sqlite3_db) rb_raise(cError, "Database is closed");
|
51
|
+
|
52
52
|
return db;
|
53
53
|
}
|
54
54
|
|
55
|
-
sqlite3 *Database_sqlite3_db(VALUE self) {
|
56
|
-
|
57
|
-
GetDatabase(self, db);
|
58
|
-
return db->sqlite3_db;
|
55
|
+
inline sqlite3 *Database_sqlite3_db(VALUE self) {
|
56
|
+
return self_to_database(self)->sqlite3_db;
|
59
57
|
}
|
60
58
|
|
61
59
|
/* call-seq:
|
@@ -68,18 +66,37 @@ VALUE Extralite_sqlite3_version(VALUE self) {
|
|
68
66
|
return rb_str_new_cstr(sqlite3_version);
|
69
67
|
}
|
70
68
|
|
71
|
-
|
72
|
-
|
69
|
+
static inline int db_open_flags_from_opts(VALUE opts) {
|
70
|
+
if (opts == Qnil) goto default_flags;
|
71
|
+
|
72
|
+
if (TYPE(opts) != T_HASH)
|
73
|
+
rb_raise(eArgumentError, "Expected hash as database initialization options");
|
74
|
+
|
75
|
+
VALUE read_only = rb_hash_aref(opts, SYM_read_only);
|
76
|
+
if (RTEST(read_only)) return SQLITE_OPEN_READONLY;
|
77
|
+
default_flags:
|
78
|
+
return SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
79
|
+
}
|
80
|
+
|
81
|
+
/* Initializes a new SQLite database with the given path and options.
|
73
82
|
*
|
74
|
-
*
|
83
|
+
* @overload initialize(path)
|
84
|
+
* @param path [String] file path (or ':memory:' for memory database)
|
85
|
+
* @return [void]
|
86
|
+
* @overload initialize(path, read_only: false)
|
87
|
+
* @param path [String] file path (or ':memory:' for memory database)
|
88
|
+
* @param read_only [boolean] true for opening the database for reading only
|
89
|
+
* @return [void]
|
75
90
|
*/
|
91
|
+
VALUE Database_initialize(int argc, VALUE *argv, VALUE self) {
|
92
|
+
Database_t *db = self_to_database(self);
|
93
|
+
VALUE path;
|
94
|
+
VALUE opts = Qnil;
|
76
95
|
|
77
|
-
|
78
|
-
int
|
79
|
-
Database_t *db;
|
80
|
-
GetDatabase(self, db);
|
96
|
+
rb_scan_args(argc, argv, "11", &path, &opts);
|
97
|
+
int flags = db_open_flags_from_opts(opts);
|
81
98
|
|
82
|
-
rc =
|
99
|
+
int rc = sqlite3_open_v2(StringValueCStr(path), &db->sqlite3_db, flags, NULL);
|
83
100
|
if (rc) {
|
84
101
|
sqlite3_close_v2(db->sqlite3_db);
|
85
102
|
rb_raise(cError, "%s", sqlite3_errstr(rc));
|
@@ -105,6 +122,16 @@ VALUE Database_initialize(VALUE self, VALUE path) {
|
|
105
122
|
return Qnil;
|
106
123
|
}
|
107
124
|
|
125
|
+
/* Returns true if the database was open for read only access.
|
126
|
+
*
|
127
|
+
* @return [boolean] true if database is open for read only access
|
128
|
+
*/
|
129
|
+
VALUE Database_read_only_p(VALUE self) {
|
130
|
+
Database_t *db = self_to_database(self);
|
131
|
+
int open = sqlite3_db_readonly(db->sqlite3_db, "main");
|
132
|
+
return (open == 1) ? Qtrue : Qfalse;
|
133
|
+
}
|
134
|
+
|
108
135
|
/* call-seq:
|
109
136
|
* db.close -> db
|
110
137
|
*
|
@@ -112,8 +139,7 @@ VALUE Database_initialize(VALUE self, VALUE path) {
|
|
112
139
|
*/
|
113
140
|
VALUE Database_close(VALUE self) {
|
114
141
|
int rc;
|
115
|
-
Database_t *db;
|
116
|
-
GetDatabase(self, db);
|
142
|
+
Database_t *db = self_to_database(self);
|
117
143
|
|
118
144
|
rc = sqlite3_close_v2(db->sqlite3_db);
|
119
145
|
if (rc) {
|
@@ -132,14 +158,12 @@ VALUE Database_close(VALUE self) {
|
|
132
158
|
* @return [bool] is database closed
|
133
159
|
*/
|
134
160
|
VALUE Database_closed_p(VALUE self) {
|
135
|
-
Database_t *db;
|
136
|
-
GetDatabase(self, db);
|
137
|
-
|
161
|
+
Database_t *db = self_to_database(self);
|
138
162
|
return db->sqlite3_db ? Qfalse : Qtrue;
|
139
163
|
}
|
140
164
|
|
141
165
|
static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VALUE (*call)(query_ctx *)) {
|
142
|
-
Database_t *db;
|
166
|
+
Database_t *db = self_to_open_database(self);
|
143
167
|
sqlite3_stmt *stmt;
|
144
168
|
VALUE sql;
|
145
169
|
|
@@ -149,13 +173,12 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
|
|
149
173
|
if (RSTRING_LEN(sql) == 0) return Qnil;
|
150
174
|
|
151
175
|
// prepare query ctx
|
152
|
-
GetOpenDatabase(self, db);
|
153
176
|
if (db->trace_block != Qnil) rb_funcall(db->trace_block, ID_call, 1, sql);
|
154
177
|
prepare_multi_stmt(db->sqlite3_db, &stmt, sql);
|
155
178
|
RB_GC_GUARD(sql);
|
156
179
|
|
157
180
|
bind_all_parameters(stmt, argc - 1, argv + 1);
|
158
|
-
query_ctx ctx = { self, db->sqlite3_db, stmt };
|
181
|
+
query_ctx ctx = { self, db->sqlite3_db, stmt, Qnil, QUERY_MODE(QUERY_MULTI_ROW), ALL_ROWS };
|
159
182
|
|
160
183
|
return rb_ensure(SAFE(call), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
161
184
|
}
|
@@ -170,7 +193,7 @@ static inline VALUE Database_perform_query(int argc, VALUE *argv, VALUE self, VA
|
|
170
193
|
*
|
171
194
|
* Query parameters to be bound to placeholders in the query can be specified as
|
172
195
|
* a list of values or as a hash mapping parameter names to values. When
|
173
|
-
* parameters are given as
|
196
|
+
* parameters are given as an array, the query should specify parameters using
|
174
197
|
* `?`:
|
175
198
|
*
|
176
199
|
* db.query('select * from foo where x = ?', 42)
|
@@ -195,7 +218,7 @@ VALUE Database_query_hash(int argc, VALUE *argv, VALUE self) {
|
|
195
218
|
*
|
196
219
|
* Query parameters to be bound to placeholders in the query can be specified as
|
197
220
|
* a list of values or as a hash mapping parameter names to values. When
|
198
|
-
* parameters are given as
|
221
|
+
* parameters are given as an array, the query should specify parameters using
|
199
222
|
* `?`:
|
200
223
|
*
|
201
224
|
* db.query_ary('select * from foo where x = ?', 42)
|
@@ -219,7 +242,7 @@ VALUE Database_query_ary(int argc, VALUE *argv, VALUE self) {
|
|
219
242
|
*
|
220
243
|
* Query parameters to be bound to placeholders in the query can be specified as
|
221
244
|
* a list of values or as a hash mapping parameter names to values. When
|
222
|
-
* parameters are given as
|
245
|
+
* parameters are given as an array, the query should specify parameters using
|
223
246
|
* `?`:
|
224
247
|
*
|
225
248
|
* db.query_single_row('select * from foo where x = ?', 42)
|
@@ -244,7 +267,7 @@ VALUE Database_query_single_row(int argc, VALUE *argv, VALUE self) {
|
|
244
267
|
*
|
245
268
|
* Query parameters to be bound to placeholders in the query can be specified as
|
246
269
|
* a list of values or as a hash mapping parameter names to values. When
|
247
|
-
* parameters are given as
|
270
|
+
* parameters are given as an array, the query should specify parameters using
|
248
271
|
* `?`:
|
249
272
|
*
|
250
273
|
* db.query_single_column('select x from foo where x = ?', 42)
|
@@ -268,7 +291,7 @@ VALUE Database_query_single_column(int argc, VALUE *argv, VALUE self) {
|
|
268
291
|
*
|
269
292
|
* Query parameters to be bound to placeholders in the query can be specified as
|
270
293
|
* a list of values or as a hash mapping parameter names to values. When
|
271
|
-
* parameters are given as
|
294
|
+
* parameters are given as an array, the query should specify parameters using
|
272
295
|
* `?`:
|
273
296
|
*
|
274
297
|
* db.query_single_value('select x from foo where x = ?', 42)
|
@@ -285,6 +308,31 @@ VALUE Database_query_single_value(int argc, VALUE *argv, VALUE self) {
|
|
285
308
|
return Database_perform_query(argc, argv, self, safe_query_single_value);
|
286
309
|
}
|
287
310
|
|
311
|
+
/* call-seq:
|
312
|
+
* db.execute(sql, *parameters) -> changes
|
313
|
+
*
|
314
|
+
* Runs a query returning the total changes effected. This method should be used
|
315
|
+
* for data- or schema-manipulation queries.
|
316
|
+
*
|
317
|
+
* Query parameters to be bound to placeholders in the query can be specified as
|
318
|
+
* a list of values or as a hash mapping parameter names to values. When
|
319
|
+
* parameters are given as an array, the query should specify parameters using
|
320
|
+
* `?`:
|
321
|
+
*
|
322
|
+
* db.execute('update foo set x = ? where y = ?', 42, 43)
|
323
|
+
*
|
324
|
+
* Named placeholders are specified using `:`. The placeholder values are
|
325
|
+
* specified using a hash, where keys are either strings are symbols. String
|
326
|
+
* keys can include or omit the `:` prefix. The following are equivalent:
|
327
|
+
*
|
328
|
+
* db.execute('update foo set x = :bar', bar: 42)
|
329
|
+
* db.execute('update foo set x = :bar', 'bar' => 42)
|
330
|
+
* db.execute('update foo set x = :bar', ':bar' => 42)
|
331
|
+
*/
|
332
|
+
VALUE Database_execute(int argc, VALUE *argv, VALUE self) {
|
333
|
+
return Database_perform_query(argc, argv, self, safe_query_changes);
|
334
|
+
}
|
335
|
+
|
288
336
|
/* call-seq:
|
289
337
|
* db.execute_multi(sql, params_array) -> changes
|
290
338
|
*
|
@@ -296,19 +344,18 @@ VALUE Database_query_single_value(int argc, VALUE *argv, VALUE self) {
|
|
296
344
|
* [1, 2, 3],
|
297
345
|
* [4, 5, 6]
|
298
346
|
* ]
|
299
|
-
* db.
|
347
|
+
* db.execute_multi('insert into foo values (?, ?, ?)', records)
|
300
348
|
*
|
301
349
|
*/
|
302
350
|
VALUE Database_execute_multi(VALUE self, VALUE sql, VALUE params_array) {
|
303
|
-
Database_t *db;
|
351
|
+
Database_t *db = self_to_open_database(self);
|
304
352
|
sqlite3_stmt *stmt;
|
305
353
|
|
306
354
|
if (RSTRING_LEN(sql) == 0) return Qnil;
|
307
355
|
|
308
356
|
// prepare query ctx
|
309
|
-
GetOpenDatabase(self, db);
|
310
357
|
prepare_single_stmt(db->sqlite3_db, &stmt, sql);
|
311
|
-
query_ctx ctx = { self, db->sqlite3_db, stmt, params_array };
|
358
|
+
query_ctx ctx = { self, db->sqlite3_db, stmt, params_array, QUERY_MODE(QUERY_MULTI_ROW), ALL_ROWS };
|
312
359
|
|
313
360
|
return rb_ensure(SAFE(safe_execute_multi), (VALUE)&ctx, SAFE(cleanup_stmt), (VALUE)&ctx);
|
314
361
|
}
|
@@ -328,8 +375,7 @@ VALUE Database_columns(VALUE self, VALUE sql) {
|
|
328
375
|
* Returns the rowid of the last inserted row.
|
329
376
|
*/
|
330
377
|
VALUE Database_last_insert_rowid(VALUE self) {
|
331
|
-
Database_t *db;
|
332
|
-
GetOpenDatabase(self, db);
|
378
|
+
Database_t *db = self_to_open_database(self);
|
333
379
|
|
334
380
|
return INT2FIX(sqlite3_last_insert_rowid(db->sqlite3_db));
|
335
381
|
}
|
@@ -340,8 +386,7 @@ VALUE Database_last_insert_rowid(VALUE self) {
|
|
340
386
|
* Returns the number of changes made to the database by the last operation.
|
341
387
|
*/
|
342
388
|
VALUE Database_changes(VALUE self) {
|
343
|
-
Database_t *db;
|
344
|
-
GetOpenDatabase(self, db);
|
389
|
+
Database_t *db = self_to_open_database(self);
|
345
390
|
|
346
391
|
return INT2FIX(sqlite3_changes(db->sqlite3_db));
|
347
392
|
}
|
@@ -354,8 +399,7 @@ VALUE Database_changes(VALUE self) {
|
|
354
399
|
VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
355
400
|
const char *db_name;
|
356
401
|
const char *filename;
|
357
|
-
Database_t *db;
|
358
|
-
GetOpenDatabase(self, db);
|
402
|
+
Database_t *db = self_to_open_database(self);
|
359
403
|
|
360
404
|
rb_check_arity(argc, 0, 1);
|
361
405
|
db_name = (argc == 1) ? StringValueCStr(argv[0]) : "main";
|
@@ -369,8 +413,7 @@ VALUE Database_filename(int argc, VALUE *argv, VALUE self) {
|
|
369
413
|
* Returns true if a transaction is currently in progress.
|
370
414
|
*/
|
371
415
|
VALUE Database_transaction_active_p(VALUE self) {
|
372
|
-
Database_t *db;
|
373
|
-
GetOpenDatabase(self, db);
|
416
|
+
Database_t *db = self_to_open_database(self);
|
374
417
|
|
375
418
|
return sqlite3_get_autocommit(db->sqlite3_db) ? Qfalse : Qtrue;
|
376
419
|
}
|
@@ -382,8 +425,7 @@ VALUE Database_transaction_active_p(VALUE self) {
|
|
382
425
|
* Loads an extension with the given path.
|
383
426
|
*/
|
384
427
|
VALUE Database_load_extension(VALUE self, VALUE path) {
|
385
|
-
Database_t *db;
|
386
|
-
GetOpenDatabase(self, db);
|
428
|
+
Database_t *db = self_to_open_database(self);
|
387
429
|
char *err_msg;
|
388
430
|
|
389
431
|
int rc = sqlite3_load_extension(db->sqlite3_db, RSTRING_PTR(path), 0, &err_msg);
|
@@ -398,12 +440,16 @@ VALUE Database_load_extension(VALUE self, VALUE path) {
|
|
398
440
|
#endif
|
399
441
|
|
400
442
|
/* call-seq:
|
401
|
-
* db.prepare(sql) -> Extralite::
|
443
|
+
* db.prepare(sql) -> Extralite::Query
|
402
444
|
*
|
403
445
|
* Creates a prepared statement with the given SQL query.
|
404
446
|
*/
|
405
|
-
VALUE Database_prepare(VALUE
|
406
|
-
|
447
|
+
VALUE Database_prepare(int argc, VALUE *argv, VALUE self) {
|
448
|
+
rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
|
449
|
+
VALUE query = rb_funcall(cQuery, ID_new, 2, self, argv[0]);
|
450
|
+
if (argc > 1) rb_funcallv(query, ID_bind, argc - 1, argv + 1);
|
451
|
+
RB_GC_GUARD(query);
|
452
|
+
return query;
|
407
453
|
}
|
408
454
|
|
409
455
|
/* call-seq:
|
@@ -417,8 +463,7 @@ VALUE Database_prepare(VALUE self, VALUE sql) {
|
|
417
463
|
* For more information, consult the [sqlite3 API docs](https://sqlite.org/c3ref/interrupt.html).
|
418
464
|
*/
|
419
465
|
VALUE Database_interrupt(VALUE self) {
|
420
|
-
Database_t *db;
|
421
|
-
GetOpenDatabase(self, db);
|
466
|
+
Database_t *db = self_to_open_database(self);
|
422
467
|
|
423
468
|
sqlite3_interrupt(db->sqlite3_db);
|
424
469
|
return self;
|
@@ -510,8 +555,7 @@ VALUE Database_backup(int argc, VALUE *argv, VALUE self) {
|
|
510
555
|
|
511
556
|
int dst_is_fn = TYPE(dst) == T_STRING;
|
512
557
|
|
513
|
-
Database_t *src;
|
514
|
-
GetOpenDatabase(self, src);
|
558
|
+
Database_t *src = self_to_open_database(self);
|
515
559
|
sqlite3 *dst_db;
|
516
560
|
|
517
561
|
if (dst_is_fn) {
|
@@ -522,8 +566,7 @@ VALUE Database_backup(int argc, VALUE *argv, VALUE self) {
|
|
522
566
|
}
|
523
567
|
}
|
524
568
|
else {
|
525
|
-
Database_t *dst_struct;
|
526
|
-
GetOpenDatabase(dst, dst_struct);
|
569
|
+
Database_t *dst_struct = self_to_open_database(dst);
|
527
570
|
dst_db = dst_struct->sqlite3_db;
|
528
571
|
}
|
529
572
|
|
@@ -540,6 +583,9 @@ VALUE Database_backup(int argc, VALUE *argv, VALUE self) {
|
|
540
583
|
backup_ctx ctx = { dst_db, dst_is_fn, backup, rb_block_given_p(), 0 };
|
541
584
|
rb_ensure(SAFE(backup_safe_iterate), (VALUE)&ctx, SAFE(backup_cleanup), (VALUE)&ctx);
|
542
585
|
|
586
|
+
RB_GC_GUARD(src_name);
|
587
|
+
RB_GC_GUARD(dst_name);
|
588
|
+
|
543
589
|
return self;
|
544
590
|
}
|
545
591
|
|
@@ -575,8 +621,7 @@ VALUE Database_status(int argc, VALUE *argv, VALUE self) {
|
|
575
621
|
|
576
622
|
rb_scan_args(argc, argv, "11", &op, &reset);
|
577
623
|
|
578
|
-
Database_t *db;
|
579
|
-
GetOpenDatabase(self, db);
|
624
|
+
Database_t *db = self_to_open_database(self);
|
580
625
|
|
581
626
|
int rc = sqlite3_db_status(db->sqlite3_db, NUM2INT(op), &cur, &hwm, RTEST(reset) ? 1 : 0);
|
582
627
|
if (rc != SQLITE_OK) rb_raise(cError, "%s", sqlite3_errstr(rc));
|
@@ -596,8 +641,7 @@ VALUE Database_limit(int argc, VALUE *argv, VALUE self) {
|
|
596
641
|
|
597
642
|
rb_scan_args(argc, argv, "11", &category, &new_value);
|
598
643
|
|
599
|
-
Database_t *db;
|
600
|
-
GetOpenDatabase(self, db);
|
644
|
+
Database_t *db = self_to_open_database(self);
|
601
645
|
|
602
646
|
int value = sqlite3_limit(db->sqlite3_db, NUM2INT(category), RTEST(new_value) ? NUM2INT(new_value) : -1);
|
603
647
|
|
@@ -614,8 +658,7 @@ VALUE Database_limit(int argc, VALUE *argv, VALUE self) {
|
|
614
658
|
* disable the busy timeout, set it to 0 or nil.
|
615
659
|
*/
|
616
660
|
VALUE Database_busy_timeout_set(VALUE self, VALUE sec) {
|
617
|
-
Database_t *db;
|
618
|
-
GetOpenDatabase(self, db);
|
661
|
+
Database_t *db = self_to_open_database(self);
|
619
662
|
|
620
663
|
int ms = (sec == Qnil) ? 0 : (int)(NUM2DBL(sec) * 1000);
|
621
664
|
int rc = sqlite3_busy_timeout(db->sqlite3_db, ms);
|
@@ -630,8 +673,7 @@ VALUE Database_busy_timeout_set(VALUE self, VALUE sec) {
|
|
630
673
|
* Returns the total number of changes made to the database since opening it.
|
631
674
|
*/
|
632
675
|
VALUE Database_total_changes(VALUE self) {
|
633
|
-
Database_t *db;
|
634
|
-
GetOpenDatabase(self, db);
|
676
|
+
Database_t *db = self_to_open_database(self);
|
635
677
|
|
636
678
|
int value = sqlite3_total_changes(db->sqlite3_db);
|
637
679
|
return INT2NUM(value);
|
@@ -645,8 +687,7 @@ VALUE Database_total_changes(VALUE self) {
|
|
645
687
|
* executed.
|
646
688
|
*/
|
647
689
|
VALUE Database_trace(VALUE self) {
|
648
|
-
Database_t *db;
|
649
|
-
GetOpenDatabase(self, db);
|
690
|
+
Database_t *db = self_to_open_database(self);
|
650
691
|
|
651
692
|
db->trace_block = rb_block_given_p() ? rb_block_proc() : Qnil;
|
652
693
|
return self;
|
@@ -658,8 +699,7 @@ VALUE Database_trace(VALUE self) {
|
|
658
699
|
* Returns the last error code for the database.
|
659
700
|
*/
|
660
701
|
VALUE Database_errcode(VALUE self) {
|
661
|
-
Database_t *db;
|
662
|
-
GetOpenDatabase(self, db);
|
702
|
+
Database_t *db = self_to_open_database(self);
|
663
703
|
|
664
704
|
return INT2NUM(sqlite3_errcode(db->sqlite3_db));
|
665
705
|
}
|
@@ -670,8 +710,7 @@ VALUE Database_errcode(VALUE self) {
|
|
670
710
|
* Returns the last error message for the database.
|
671
711
|
*/
|
672
712
|
VALUE Database_errmsg(VALUE self) {
|
673
|
-
Database_t *db;
|
674
|
-
GetOpenDatabase(self, db);
|
713
|
+
Database_t *db = self_to_open_database(self);
|
675
714
|
|
676
715
|
return rb_str_new2(sqlite3_errmsg(db->sqlite3_db));
|
677
716
|
}
|
@@ -683,13 +722,25 @@ VALUE Database_errmsg(VALUE self) {
|
|
683
722
|
* Returns the offset for the last error
|
684
723
|
*/
|
685
724
|
VALUE Database_error_offset(VALUE self) {
|
686
|
-
Database_t *db;
|
687
|
-
GetOpenDatabase(self, db);
|
725
|
+
Database_t *db = self_to_open_database(self);
|
688
726
|
|
689
727
|
return INT2NUM(sqlite3_error_offset(db->sqlite3_db));
|
690
728
|
}
|
691
729
|
#endif
|
692
730
|
|
731
|
+
/* Returns a short string representation of the database instance, including the
|
732
|
+
* database filename.
|
733
|
+
*
|
734
|
+
* @return [String] string representation
|
735
|
+
*/
|
736
|
+
VALUE Database_inspect(VALUE self) {
|
737
|
+
VALUE cname = rb_class_name(CLASS_OF(self));
|
738
|
+
VALUE filename = Database_filename(0, NULL, self);
|
739
|
+
if (RSTRING_LEN(filename) == 0) filename = rb_str_new_literal(":memory:");
|
740
|
+
|
741
|
+
return rb_sprintf("#<%"PRIsVALUE":%p %"PRIsVALUE">", cname, (void*)self, filename);
|
742
|
+
}
|
743
|
+
|
693
744
|
void Init_ExtraliteDatabase(void) {
|
694
745
|
VALUE mExtralite = rb_define_module("Extralite");
|
695
746
|
rb_define_singleton_method(mExtralite, "runtime_status", Extralite_runtime_status, -1);
|
@@ -711,19 +762,22 @@ void Init_ExtraliteDatabase(void) {
|
|
711
762
|
rb_define_method(cDatabase, "error_offset", Database_error_offset, 0);
|
712
763
|
#endif
|
713
764
|
|
765
|
+
rb_define_method(cDatabase, "execute", Database_execute, -1);
|
714
766
|
rb_define_method(cDatabase, "execute_multi", Database_execute_multi, 2);
|
715
767
|
rb_define_method(cDatabase, "filename", Database_filename, -1);
|
716
|
-
rb_define_method(cDatabase, "initialize", Database_initialize, 1);
|
768
|
+
rb_define_method(cDatabase, "initialize", Database_initialize, -1);
|
769
|
+
rb_define_method(cDatabase, "inspect", Database_inspect, 0);
|
717
770
|
rb_define_method(cDatabase, "interrupt", Database_interrupt, 0);
|
718
771
|
rb_define_method(cDatabase, "last_insert_rowid", Database_last_insert_rowid, 0);
|
719
772
|
rb_define_method(cDatabase, "limit", Database_limit, -1);
|
720
|
-
rb_define_method(cDatabase, "prepare", Database_prepare, 1);
|
773
|
+
rb_define_method(cDatabase, "prepare", Database_prepare, -1);
|
721
774
|
rb_define_method(cDatabase, "query", Database_query_hash, -1);
|
722
775
|
rb_define_method(cDatabase, "query_ary", Database_query_ary, -1);
|
723
776
|
rb_define_method(cDatabase, "query_hash", Database_query_hash, -1);
|
724
777
|
rb_define_method(cDatabase, "query_single_column", Database_query_single_column, -1);
|
725
778
|
rb_define_method(cDatabase, "query_single_row", Database_query_single_row, -1);
|
726
779
|
rb_define_method(cDatabase, "query_single_value", Database_query_single_value, -1);
|
780
|
+
rb_define_method(cDatabase, "read_only?", Database_read_only_p, 0);
|
727
781
|
rb_define_method(cDatabase, "status", Database_status, -1);
|
728
782
|
rb_define_method(cDatabase, "total_changes", Database_total_changes, 0);
|
729
783
|
rb_define_method(cDatabase, "trace", Database_trace, 0);
|
@@ -742,9 +796,15 @@ void Init_ExtraliteDatabase(void) {
|
|
742
796
|
rb_gc_register_mark_object(cBusyError);
|
743
797
|
rb_gc_register_mark_object(cInterruptError);
|
744
798
|
|
799
|
+
eArgumentError = rb_const_get(rb_cObject, rb_intern("ArgumentError"));
|
800
|
+
|
801
|
+
ID_bind = rb_intern("bind");
|
745
802
|
ID_call = rb_intern("call");
|
746
803
|
ID_keys = rb_intern("keys");
|
747
804
|
ID_new = rb_intern("new");
|
748
805
|
ID_strip = rb_intern("strip");
|
749
806
|
ID_to_s = rb_intern("to_s");
|
807
|
+
|
808
|
+
SYM_read_only = ID2SYM(rb_intern("read_only"));
|
809
|
+
rb_gc_register_mark_object(SYM_read_only);
|
750
810
|
}
|
data/ext/extralite/extconf.rb
CHANGED
@@ -4,13 +4,13 @@ if ENV['EXTRALITE_BUNDLE']
|
|
4
4
|
require_relative('extconf-bundle')
|
5
5
|
else
|
6
6
|
ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
|
7
|
-
|
7
|
+
|
8
8
|
require 'mkmf'
|
9
|
-
|
9
|
+
|
10
10
|
# :stopdoc:
|
11
|
-
|
11
|
+
|
12
12
|
RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
|
13
|
-
|
13
|
+
|
14
14
|
ldflags = cppflags = nil
|
15
15
|
if RbConfig::CONFIG["host_os"] =~ /darwin/
|
16
16
|
begin
|
@@ -25,7 +25,7 @@ else
|
|
25
25
|
cppflags = "#{brew_prefix}/include"
|
26
26
|
pkg_conf = "#{brew_prefix}/lib/pkgconfig"
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# pkg_config should be less error prone than parsing compiler
|
30
30
|
# commandline options, but we need to set default ldflags and cpp flags
|
31
31
|
# in case the user doesn't have pkg-config installed
|
@@ -33,13 +33,13 @@ else
|
|
33
33
|
rescue
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
if with_config('sqlcipher')
|
38
38
|
pkg_config("sqlcipher")
|
39
39
|
else
|
40
40
|
pkg_config("sqlite3")
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
# --with-sqlite3-{dir,include,lib}
|
44
44
|
if with_config('sqlcipher')
|
45
45
|
$CFLAGS << ' -DUSING_SQLCIPHER'
|
@@ -47,15 +47,15 @@ else
|
|
47
47
|
else
|
48
48
|
dir_config("sqlite3", cppflags, ldflags)
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
if RbConfig::CONFIG["host_os"] =~ /mswin/
|
52
52
|
$CFLAGS << ' -W3'
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
if RUBY_VERSION < '2.7'
|
56
56
|
$CFLAGS << ' -DTAINTING_SUPPORT'
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
# @!visibility private
|
60
60
|
def asplode missing
|
61
61
|
if RUBY_PLATFORM =~ /mingw|mswin/
|
@@ -70,25 +70,25 @@ else
|
|
70
70
|
error
|
71
71
|
end
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
asplode('sqlite3.h') unless find_header 'sqlite3.h'
|
75
75
|
find_library 'pthread', 'pthread_create' # 1.8 support. *shrug*
|
76
|
-
|
76
|
+
|
77
77
|
have_library 'dl' # for static builds
|
78
|
-
|
78
|
+
|
79
79
|
if with_config('sqlcipher')
|
80
80
|
asplode('sqlcipher') unless find_library 'sqlcipher', 'sqlite3_libversion_number'
|
81
81
|
else
|
82
82
|
asplode('sqlite3') unless find_library 'sqlite3', 'sqlite3_libversion_number'
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
have_func('sqlite3_enable_load_extension')
|
86
86
|
have_func('sqlite3_load_extension')
|
87
87
|
have_func('sqlite3_prepare_v2')
|
88
88
|
have_func('sqlite3_error_offset')
|
89
|
-
|
89
|
+
|
90
90
|
$defs << "-DEXTRALITE_NO_BUNDLE"
|
91
|
-
|
91
|
+
|
92
92
|
dir_config('extralite_ext')
|
93
93
|
create_makefile('extralite_ext')
|
94
94
|
end
|