sbf-do_sqlite3 0.10.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog.markdown +119 -0
  3. data/LICENSE +20 -0
  4. data/README.markdown +94 -0
  5. data/Rakefile +21 -0
  6. data/ext/do_sqlite3/compat.h +55 -0
  7. data/ext/do_sqlite3/do_common.c +510 -0
  8. data/ext/do_sqlite3/do_common.h +132 -0
  9. data/ext/do_sqlite3/do_sqlite3.c +448 -0
  10. data/ext/do_sqlite3/do_sqlite3.h +22 -0
  11. data/ext/do_sqlite3/do_sqlite3_extension.c +87 -0
  12. data/ext/do_sqlite3/error.h +85 -0
  13. data/ext/do_sqlite3/extconf.rb +26 -0
  14. data/lib/do_sqlite3/transaction.rb +21 -0
  15. data/lib/do_sqlite3/version.rb +5 -0
  16. data/lib/do_sqlite3.rb +13 -0
  17. data/spec/command_spec.rb +6 -0
  18. data/spec/connection_spec.rb +26 -0
  19. data/spec/encoding_spec.rb +7 -0
  20. data/spec/error/sql_error_spec.rb +7 -0
  21. data/spec/reader_spec.rb +6 -0
  22. data/spec/result_spec.rb +17 -0
  23. data/spec/spec_helper.rb +138 -0
  24. data/spec/typecast/array_spec.rb +6 -0
  25. data/spec/typecast/bigdecimal_spec.rb +9 -0
  26. data/spec/typecast/boolean_spec.rb +9 -0
  27. data/spec/typecast/byte_array_spec.rb +6 -0
  28. data/spec/typecast/class_spec.rb +6 -0
  29. data/spec/typecast/date_spec.rb +9 -0
  30. data/spec/typecast/datetime_spec.rb +9 -0
  31. data/spec/typecast/float_spec.rb +10 -0
  32. data/spec/typecast/integer_spec.rb +6 -0
  33. data/spec/typecast/nil_spec.rb +18 -0
  34. data/spec/typecast/other_spec.rb +6 -0
  35. data/spec/typecast/range_spec.rb +6 -0
  36. data/spec/typecast/string_spec.rb +6 -0
  37. data/spec/typecast/time_spec.rb +7 -0
  38. data/tasks/compile.rake +23 -0
  39. data/tasks/release.rake +14 -0
  40. data/tasks/retrieve.rake +16 -0
  41. data/tasks/spec.rake +10 -0
  42. metadata +100 -0
@@ -0,0 +1,448 @@
1
+ #include "do_sqlite3.h"
2
+ #include "error.h"
3
+
4
+ #include "do_common.h"
5
+
6
+ VALUE mDO_Sqlite3;
7
+ VALUE cDO_Sqlite3Connection;
8
+ VALUE cDO_Sqlite3Command;
9
+ VALUE cDO_Sqlite3Result;
10
+ VALUE cDO_Sqlite3Reader;
11
+
12
+ VALUE DO_OPEN_FLAG_READONLY;
13
+ VALUE DO_OPEN_FLAG_READWRITE;
14
+ VALUE DO_OPEN_FLAG_CREATE;
15
+ VALUE DO_OPEN_FLAG_NO_MUTEX;
16
+ VALUE DO_OPEN_FLAG_FULL_MUTEX;
17
+
18
+ void do_sqlite3_raise_error(VALUE self, sqlite3 *result, VALUE query) {
19
+ int errnum = sqlite3_errcode(result);
20
+ VALUE message = rb_str_new2(sqlite3_errmsg(result));
21
+ VALUE sql_state = rb_str_new2("");
22
+
23
+ data_objects_raise_error(self, do_sqlite3_errors, errnum, message, query, sql_state);
24
+ }
25
+
26
+ VALUE do_sqlite3_typecast(sqlite3_stmt *stmt, int i, VALUE type, int encoding) {
27
+ int original_type = sqlite3_column_type(stmt, i);
28
+ int length = sqlite3_column_bytes(stmt, i);
29
+
30
+ if (original_type == SQLITE_NULL) {
31
+ return Qnil;
32
+ }
33
+
34
+ #ifdef HAVE_RUBY_ENCODING_H
35
+ rb_encoding *internal_encoding = rb_default_internal_encoding();
36
+ #else
37
+ void *internal_encoding = NULL;
38
+ #endif
39
+
40
+ if (type == Qnil) {
41
+ switch (original_type) {
42
+ case SQLITE_INTEGER:
43
+ type = rb_cInteger;
44
+ break;
45
+
46
+ case SQLITE_FLOAT:
47
+ type = rb_cFloat;
48
+ break;
49
+
50
+ case SQLITE_BLOB:
51
+ type = rb_cByteArray;
52
+ break;
53
+
54
+ default:
55
+ type = rb_cString;
56
+ break;
57
+ }
58
+ }
59
+
60
+ if (type == rb_cInteger) {
61
+ return LL2NUM(sqlite3_column_int64(stmt, i));
62
+ }
63
+ else if (type == rb_cString) {
64
+ return DATA_OBJECTS_STR_NEW((char*)sqlite3_column_text(stmt, i), length, encoding, internal_encoding);
65
+ }
66
+ else if (type == rb_cFloat) {
67
+ return rb_float_new(sqlite3_column_double(stmt, i));
68
+ }
69
+ else if (type == rb_cBigDecimal) {
70
+ return rb_funcall(rb_cObject, rb_intern("BigDecimal"), 1, rb_str_new((char*)sqlite3_column_text(stmt, i), length));
71
+ }
72
+ else if (type == rb_cDate) {
73
+ return data_objects_parse_date((char*)sqlite3_column_text(stmt, i));
74
+ }
75
+ else if (type == rb_cDateTime) {
76
+ return data_objects_parse_date_time((char*)sqlite3_column_text(stmt, i));
77
+ }
78
+ else if (type == rb_cTime) {
79
+ return data_objects_parse_time((char*)sqlite3_column_text(stmt, i));
80
+ }
81
+ else if (type == rb_cTrueClass) {
82
+ return strcmp((char*)sqlite3_column_text(stmt, i), "t") == 0 ? Qtrue : Qfalse;
83
+ }
84
+ else if (type == rb_cByteArray) {
85
+ return rb_funcall(rb_cByteArray, DO_ID_NEW, 1, rb_str_new((char*)sqlite3_column_blob(stmt, i), length));
86
+ }
87
+ else if (type == rb_cClass) {
88
+ return rb_funcall(mDO, rb_intern("full_const_get"), 1, rb_str_new((char*)sqlite3_column_text(stmt, i), length));
89
+ }
90
+ else if (type == rb_cNilClass) {
91
+ return Qnil;
92
+ }
93
+ else {
94
+ return DATA_OBJECTS_STR_NEW((char*)sqlite3_column_text(stmt, i), length, encoding, internal_encoding);
95
+ }
96
+ }
97
+
98
+ #ifdef HAVE_SQLITE3_OPEN_V2
99
+
100
+ #define FLAG_PRESENT(query_values, flag) !NIL_P(rb_hash_aref(query_values, flag))
101
+
102
+ int do_sqlite3_flags_from_uri(VALUE uri) {
103
+ VALUE query_values = rb_funcall(uri, rb_intern("query"), 0);
104
+ int flags = 0;
105
+
106
+ if (!NIL_P(query_values) && TYPE(query_values) == T_HASH) {
107
+ /// scan for flags
108
+ #ifdef SQLITE_OPEN_READONLY
109
+ if (FLAG_PRESENT(query_values, DO_OPEN_FLAG_READONLY)) {
110
+ flags |= SQLITE_OPEN_READONLY;
111
+ }
112
+ else {
113
+ flags |= SQLITE_OPEN_READWRITE;
114
+ }
115
+ #endif
116
+
117
+ #ifdef SQLITE_OPEN_NOMUTEX
118
+ if (FLAG_PRESENT(query_values, DO_OPEN_FLAG_NO_MUTEX)) {
119
+ flags |= SQLITE_OPEN_NOMUTEX;
120
+ }
121
+ #endif
122
+
123
+ #ifdef SQLITE_OPEN_FULLMUTEX
124
+ if (FLAG_PRESENT(query_values, DO_OPEN_FLAG_FULL_MUTEX)) {
125
+ flags |= SQLITE_OPEN_FULLMUTEX;
126
+ }
127
+ #endif
128
+
129
+ flags |= SQLITE_OPEN_CREATE;
130
+ }
131
+ else {
132
+ flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
133
+ }
134
+
135
+ return flags;
136
+ }
137
+
138
+ #endif
139
+
140
+
141
+ int do_sqlite3_busy_timeout_from_uri(VALUE uri) {
142
+ VALUE query_values = rb_funcall(uri, rb_intern("query"), 0);
143
+ if(query_values != Qnil && TYPE(query_values) == T_HASH) {
144
+ VALUE timeout = rb_hash_aref(query_values, rb_str_new2("busy_timeout"));
145
+ if(timeout == Qnil) {
146
+ return -1;
147
+ }
148
+
149
+ return rb_cstr2inum(RSTRING_PTR(timeout), 0);
150
+ }
151
+ return -1;
152
+ }
153
+
154
+ /****** Public API ******/
155
+
156
+ VALUE do_sqlite3_cConnection_initialize(VALUE self, VALUE uri) {
157
+ VALUE path = rb_funcall(uri, rb_intern("path"), 0);
158
+ sqlite3 *db = NULL;
159
+ int ret;
160
+
161
+ #ifdef HAVE_SQLITE3_OPEN_V2
162
+ ret = sqlite3_open_v2(StringValuePtr(path), &db, do_sqlite3_flags_from_uri(uri), 0);
163
+ #else
164
+ ret = sqlite3_open(StringValuePtr(path), &db);
165
+ #endif
166
+
167
+ if (ret != SQLITE_OK) {
168
+ do_sqlite3_raise_error(self, db, Qnil);
169
+ }
170
+
171
+ int timeout = do_sqlite3_busy_timeout_from_uri(uri);
172
+ if(timeout > 0) {
173
+ sqlite3_busy_timeout(db, timeout);
174
+ }
175
+
176
+ rb_iv_set(self, "@uri", uri);
177
+ rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
178
+ // Sqlite3 only supports UTF-8, so this is the standard encoding
179
+ rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
180
+ #ifdef HAVE_RUBY_ENCODING_H
181
+ rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8")));
182
+ #endif
183
+
184
+ return Qtrue;
185
+ }
186
+
187
+ VALUE do_sqlite3_cConnection_dispose(VALUE self) {
188
+ VALUE connection_container = rb_iv_get(self, "@connection");
189
+
190
+ if (connection_container == Qnil) {
191
+ return Qfalse;
192
+ }
193
+
194
+ sqlite3 *db;
195
+ Data_Get_Struct(connection_container, sqlite3, db);
196
+
197
+ if (!db) {
198
+ return Qfalse;
199
+ }
200
+
201
+ sqlite3_close(db);
202
+ rb_iv_set(self, "@connection", Qnil);
203
+ return Qtrue;
204
+ }
205
+
206
+ VALUE do_sqlite3_cConnection_quote_boolean(VALUE self, VALUE value) {
207
+ return rb_str_new2(value == Qtrue ? "'t'" : "'f'");
208
+ }
209
+
210
+ VALUE do_sqlite3_cConnection_quote_string(VALUE self, VALUE string) {
211
+ const char *source = rb_str_ptr_readonly(string);
212
+
213
+ // Wrap the escaped string in single-quotes, this is DO's convention
214
+ char *escaped_with_quotes = sqlite3_mprintf("%Q", source);
215
+
216
+ if(!escaped_with_quotes) {
217
+ rb_memerror();
218
+ }
219
+
220
+ VALUE result = rb_str_new2(escaped_with_quotes);
221
+
222
+ #ifdef HAVE_RUBY_ENCODING_H
223
+ rb_enc_associate_index(result, FIX2INT(rb_iv_get(self, "@encoding_id")));
224
+ #endif
225
+ sqlite3_free(escaped_with_quotes);
226
+ return result;
227
+ }
228
+
229
+ VALUE do_sqlite3_cConnection_quote_byte_array(VALUE self, VALUE string) {
230
+ VALUE source = StringValue(string);
231
+ VALUE array = rb_funcall(source, rb_intern("unpack"), 1, rb_str_new2("H*"));
232
+
233
+ rb_ary_unshift(array, rb_str_new2("X'"));
234
+ rb_ary_push(array, rb_str_new2("'"));
235
+ return rb_ary_join(array, Qnil);
236
+ }
237
+
238
+ VALUE do_sqlite3_cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
239
+ VALUE query = data_objects_build_query_from_args(self, argc, argv);
240
+ VALUE connection = rb_iv_get(self, "@connection");
241
+ VALUE sqlite3_connection = rb_iv_get(connection, "@connection");
242
+
243
+ if (sqlite3_connection == Qnil) {
244
+ rb_raise(eDO_ConnectionError, "This connection has already been closed.");
245
+ }
246
+
247
+ sqlite3 *db = NULL;
248
+
249
+ Data_Get_Struct(sqlite3_connection, sqlite3, db);
250
+
251
+ struct timeval start;
252
+ char *error_message;
253
+ int status;
254
+
255
+ gettimeofday(&start, NULL);
256
+ status = sqlite3_exec(db, rb_str_ptr_readonly(query), 0, 0, &error_message);
257
+
258
+ if (status != SQLITE_OK) {
259
+ do_sqlite3_raise_error(self, db, query);
260
+ }
261
+
262
+ data_objects_debug(connection, query, &start);
263
+
264
+ int affected_rows = sqlite3_changes(db);
265
+ do_int64 insert_id = sqlite3_last_insert_rowid(db);
266
+
267
+ return rb_funcall(cDO_Sqlite3Result, DO_ID_NEW, 3, self, INT2NUM(affected_rows), INT2NUM(insert_id));
268
+ }
269
+
270
+ VALUE do_sqlite3_cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
271
+ VALUE query = data_objects_build_query_from_args(self, argc, argv);
272
+ VALUE connection = rb_iv_get(self, "@connection");
273
+ VALUE sqlite3_connection = rb_iv_get(connection, "@connection");
274
+
275
+ if (sqlite3_connection == Qnil) {
276
+ rb_raise(eDO_ConnectionError, "This connection has already been closed.");
277
+ }
278
+
279
+ sqlite3 *db = NULL;
280
+
281
+ Data_Get_Struct(sqlite3_connection, sqlite3, db);
282
+
283
+ sqlite3_stmt *sqlite3_reader;
284
+ struct timeval start;
285
+ int status;
286
+
287
+ gettimeofday(&start, NULL);
288
+ status = sqlite3_prepare_v2(db, rb_str_ptr_readonly(query), -1, &sqlite3_reader, 0);
289
+ data_objects_debug(connection, query, &start);
290
+
291
+ if (status != SQLITE_OK) {
292
+ do_sqlite3_raise_error(self, db, query);
293
+ }
294
+
295
+ int field_count = sqlite3_column_count(sqlite3_reader);
296
+ VALUE reader = rb_funcall(cDO_Sqlite3Reader, DO_ID_NEW, 0);
297
+
298
+ rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, sqlite3_reader));
299
+ rb_iv_set(reader, "@field_count", INT2NUM(field_count));
300
+ rb_iv_set(reader, "@connection", connection);
301
+
302
+ VALUE field_types = rb_iv_get(self, "@field_types");
303
+
304
+ if (field_types == Qnil || RARRAY_LEN(field_types) == 0) {
305
+ field_types = rb_ary_new();
306
+ }
307
+ else if (RARRAY_LEN(field_types) != field_count) {
308
+ // Whoops... wrong number of types passed to set_types. Close the reader and raise
309
+ // and error
310
+ rb_funcall(reader, rb_intern("close"), 0);
311
+ rb_raise(rb_eArgError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
312
+ }
313
+
314
+ VALUE field_names = rb_ary_new();
315
+ int i;
316
+
317
+ for (i = 0; i < field_count; i++) {
318
+ rb_ary_push(field_names, rb_str_new2((char *)sqlite3_column_name(sqlite3_reader, i)));
319
+ }
320
+
321
+ rb_iv_set(reader, "@fields", field_names);
322
+ rb_iv_set(reader, "@field_types", field_types);
323
+ return reader;
324
+ }
325
+
326
+ VALUE do_sqlite3_cReader_close(VALUE self) {
327
+ VALUE reader_obj = rb_iv_get(self, "@reader");
328
+
329
+ if (reader_obj != Qnil) {
330
+ sqlite3_stmt *reader = NULL;
331
+
332
+ Data_Get_Struct(reader_obj, sqlite3_stmt, reader);
333
+ sqlite3_finalize(reader);
334
+ rb_iv_set(self, "@reader", Qnil);
335
+ return Qtrue;
336
+ }
337
+
338
+ return Qfalse;
339
+ }
340
+
341
+ VALUE do_sqlite3_cReader_next(VALUE self) {
342
+
343
+ VALUE reader = rb_iv_get(self, "@reader");
344
+
345
+ if(reader == Qnil) {
346
+ rb_raise(eDO_ConnectionError, "This result set has already been closed.");
347
+ }
348
+
349
+ if (rb_iv_get(self, "@done") == Qtrue) {
350
+ return Qfalse;
351
+ }
352
+
353
+ sqlite3_stmt *sqlite_reader = NULL;
354
+ int result;
355
+
356
+ Data_Get_Struct(reader, sqlite3_stmt, sqlite_reader);
357
+
358
+ result = sqlite3_step(sqlite_reader);
359
+ rb_iv_set(self, "@state", INT2NUM(result));
360
+
361
+ if (result != SQLITE_ROW) {
362
+ rb_iv_set(self, "@values", Qnil);
363
+ rb_iv_set(self, "@done", Qtrue);
364
+ return Qfalse;
365
+ }
366
+
367
+ int enc = -1;
368
+ #ifdef HAVE_RUBY_ENCODING_H
369
+ VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id");
370
+
371
+ if (encoding_id != Qnil) {
372
+ enc = FIX2INT(encoding_id);
373
+ }
374
+ #endif
375
+
376
+ VALUE field_types = rb_iv_get(self, "@field_types");
377
+ int field_count = NUM2INT(rb_iv_get(self, "@field_count"));
378
+ VALUE arr = rb_ary_new();
379
+ VALUE field_type;
380
+ VALUE value;
381
+ int i;
382
+
383
+ for (i = 0; i < field_count; i++) {
384
+ field_type = rb_ary_entry(field_types, i);
385
+ value = do_sqlite3_typecast(sqlite_reader, i, field_type, enc);
386
+ rb_ary_push(arr, value);
387
+ }
388
+
389
+ rb_iv_set(self, "@values", arr);
390
+ return Qtrue;
391
+ }
392
+
393
+ VALUE do_sqlite3_cReader_values(VALUE self) {
394
+ VALUE state = rb_iv_get(self, "@state");
395
+
396
+ if (state == Qnil || NUM2INT(state) != SQLITE_ROW) {
397
+ rb_raise(eDO_DataError, "Reader is not initialized");
398
+ return Qnil;
399
+ }
400
+
401
+ return rb_iv_get(self, "@values");
402
+ }
403
+
404
+ void Init_do_sqlite3(void) {
405
+ data_objects_common_init();
406
+
407
+ mDO_Sqlite3 = rb_define_module_under(mDO, "Sqlite3");
408
+
409
+ cDO_Sqlite3Connection = rb_define_class_under(mDO_Sqlite3, "Connection", cDO_Connection);
410
+ rb_define_method(cDO_Sqlite3Connection, "initialize", do_sqlite3_cConnection_initialize, 1);
411
+ rb_define_method(cDO_Sqlite3Connection, "dispose", do_sqlite3_cConnection_dispose, 0);
412
+ rb_define_method(cDO_Sqlite3Connection, "quote_boolean", do_sqlite3_cConnection_quote_boolean, 1);
413
+ rb_define_method(cDO_Sqlite3Connection, "quote_string", do_sqlite3_cConnection_quote_string, 1);
414
+ rb_define_method(cDO_Sqlite3Connection, "quote_byte_array", do_sqlite3_cConnection_quote_byte_array, 1);
415
+ rb_define_method(cDO_Sqlite3Connection, "character_set", data_objects_cConnection_character_set, 0);
416
+
417
+ cDO_Sqlite3Command = rb_define_class_under(mDO_Sqlite3, "Command", cDO_Command);
418
+ rb_define_method(cDO_Sqlite3Command, "set_types", data_objects_cCommand_set_types, -1);
419
+ rb_define_method(cDO_Sqlite3Command, "execute_non_query", do_sqlite3_cCommand_execute_non_query, -1);
420
+ rb_define_method(cDO_Sqlite3Command, "execute_reader", do_sqlite3_cCommand_execute_reader, -1);
421
+
422
+ cDO_Sqlite3Result = rb_define_class_under(mDO_Sqlite3, "Result", cDO_Result);
423
+
424
+ cDO_Sqlite3Reader = rb_define_class_under(mDO_Sqlite3, "Reader", cDO_Reader);
425
+ rb_define_method(cDO_Sqlite3Reader, "close", do_sqlite3_cReader_close, 0);
426
+ rb_define_method(cDO_Sqlite3Reader, "next!", do_sqlite3_cReader_next, 0);
427
+ rb_define_method(cDO_Sqlite3Reader, "values", do_sqlite3_cReader_values, 0); // TODO: DRY?
428
+ rb_define_method(cDO_Sqlite3Reader, "fields", data_objects_cReader_fields, 0);
429
+ rb_define_method(cDO_Sqlite3Reader, "field_count", data_objects_cReader_field_count, 0);
430
+
431
+ rb_global_variable(&cDO_Sqlite3Result);
432
+ rb_global_variable(&cDO_Sqlite3Reader);
433
+
434
+ DO_OPEN_FLAG_READONLY = rb_str_new2("read_only");
435
+ rb_global_variable(&DO_OPEN_FLAG_READONLY);
436
+ DO_OPEN_FLAG_READWRITE = rb_str_new2("read_write");
437
+ rb_global_variable(&DO_OPEN_FLAG_READWRITE);
438
+ DO_OPEN_FLAG_CREATE = rb_str_new2("create");
439
+ rb_global_variable(&DO_OPEN_FLAG_CREATE);
440
+ DO_OPEN_FLAG_NO_MUTEX = rb_str_new2("no_mutex");
441
+ rb_global_variable(&DO_OPEN_FLAG_NO_MUTEX);
442
+ DO_OPEN_FLAG_FULL_MUTEX = rb_str_new2("full_mutex");
443
+ rb_global_variable(&DO_OPEN_FLAG_FULL_MUTEX);
444
+
445
+ Init_do_sqlite3_extension();
446
+
447
+ data_objects_define_errors(mDO_Sqlite3, do_sqlite3_errors);
448
+ }
@@ -0,0 +1,22 @@
1
+ #ifndef DO_SQLITE3_H
2
+ #define DO_SQLITE3_H
3
+
4
+ #include <ruby.h>
5
+ #include <string.h>
6
+ #include <math.h>
7
+ #include <time.h>
8
+ #ifndef _WIN32
9
+ #include <sys/time.h>
10
+ #endif
11
+ #include <locale.h>
12
+ #include <sqlite3.h>
13
+ #include "compat.h"
14
+
15
+ #ifndef HAVE_SQLITE3_PREPARE_V2
16
+ #define sqlite3_prepare_v2 sqlite3_prepare
17
+ #endif
18
+
19
+ extern VALUE mDO_Sqlite3;
20
+ extern void Init_do_sqlite3_extension();
21
+
22
+ #endif
@@ -0,0 +1,87 @@
1
+ #include <ruby.h>
2
+ #include "do_common.h"
3
+ #include "do_sqlite3.h"
4
+
5
+ VALUE cDO_Sqlite3Extension;
6
+
7
+ /*****************************************************/
8
+ /* File used for providing extensions on the default */
9
+ /* API that are driver specific. */
10
+ /*****************************************************/
11
+ VALUE do_sqlite3_cExtension_enable_load_extension(VALUE self, VALUE on) {
12
+ #ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
13
+ VALUE id_connection = rb_intern("connection");
14
+ VALUE connection = rb_funcall(self, id_connection, 0);
15
+
16
+ if (connection == Qnil) { return Qfalse; }
17
+
18
+ // Retrieve the actual connection from the
19
+ VALUE sqlite3_connection = rb_iv_get(connection, "@connection");
20
+
21
+ if (sqlite3_connection == Qnil) { return Qfalse; }
22
+
23
+ sqlite3 *db;
24
+
25
+ Data_Get_Struct(sqlite3_connection, sqlite3, db);
26
+
27
+
28
+ if (!(db = DATA_PTR(connection))) {
29
+ return Qfalse;
30
+ }
31
+
32
+ int status = sqlite3_enable_load_extension(db, on == Qtrue ? 1 : 0);
33
+
34
+ if (status != SQLITE_OK) {
35
+ rb_raise(eDO_ConnectionError, "Couldn't enable extension loading");
36
+ }
37
+
38
+ return Qtrue;
39
+ #else
40
+ return Qfalse;
41
+ #endif
42
+ }
43
+
44
+ VALUE do_sqlite3_cExtension_load_extension(VALUE self, VALUE path) {
45
+ #ifdef HAVE_SQLITE3_ENABLE_LOAD_EXTENSION
46
+ VALUE connection = rb_iv_get(self, "@connection");
47
+
48
+ if (connection == Qnil) { return Qfalse; }
49
+
50
+ // Retrieve the actual connection from the object
51
+ VALUE sqlite3_connection = rb_iv_get(connection, "@connection");
52
+
53
+ if (sqlite3_connection == Qnil) { return Qfalse; }
54
+
55
+ sqlite3 *db;
56
+
57
+ Data_Get_Struct(sqlite3_connection, sqlite3, db);
58
+
59
+ const char *extension_path = rb_str_ptr_readonly(path);
60
+ char *errmsg = sqlite3_malloc(1024);
61
+
62
+ if (!errmsg) {
63
+ return Qfalse;
64
+ }
65
+
66
+ int status = sqlite3_load_extension(db, extension_path, 0, &errmsg);
67
+
68
+ if (status != SQLITE_OK) {
69
+ VALUE errexp = rb_exc_new2(eDO_ConnectionError, errmsg);
70
+
71
+ sqlite3_free(errmsg);
72
+ rb_exc_raise(errexp);
73
+ }
74
+
75
+ sqlite3_free(errmsg);
76
+ return Qtrue;
77
+ #else
78
+ return Qfalse;
79
+ #endif
80
+ }
81
+
82
+ void Init_do_sqlite3_extension(void) {
83
+ cDO_Sqlite3Extension = rb_define_class_under(mDO_Sqlite3, "Extension", cDO_Extension);
84
+ rb_global_variable(&cDO_Sqlite3Extension);
85
+ rb_define_method(cDO_Sqlite3Extension, "load_extension", do_sqlite3_cExtension_load_extension, 1);
86
+ rb_define_method(cDO_Sqlite3Extension, "enable_load_extension", do_sqlite3_cExtension_enable_load_extension, 1);
87
+ }
@@ -0,0 +1,85 @@
1
+ #ifndef _DO_SQLITE3_ERROR_H_
2
+ #define _DO_SQLITE3_ERROR_H_
3
+
4
+ #include "do_common.h"
5
+
6
+ static struct errcodes do_sqlite3_errors[] = {
7
+ #ifdef SQLITE_ERROR
8
+ ERRCODE(SQLITE_ERROR, "SyntaxError"),
9
+ #endif
10
+ #ifdef SQLITE_INTERNAL
11
+ ERRCODE(SQLITE_INTERNAL, "SQLError"),
12
+ #endif
13
+ #ifdef SQLITE_PERM
14
+ ERRCODE(SQLITE_PERM, "ConnectionError"),
15
+ #endif
16
+ #ifdef SQLITE_ABORT
17
+ ERRCODE(SQLITE_ABORT, "ConnectionError"),
18
+ #endif
19
+ #ifdef SQLITE_BUSY
20
+ ERRCODE(SQLITE_BUSY, "ConnectionError"),
21
+ #endif
22
+
23
+ #ifdef SQLITE_LOCKED
24
+ ERRCODE(SQLITE_LOCKED, "ConnectionError"),
25
+ #endif
26
+ #ifdef SQLITE_NOMEM
27
+ ERRCODE(SQLITE_NOMEM, "ConnectionError"),
28
+ #endif
29
+ #ifdef SQLITE_READONLY
30
+ ERRCODE(SQLITE_READONLY, "ConnectionError"),
31
+ #endif
32
+ #ifdef SQLITE_INTERRUPT
33
+ ERRCODE(SQLITE_INTERRUPT, "ConnectionError"),
34
+ #endif
35
+ #ifdef SQLITE_IOERR
36
+ ERRCODE(SQLITE_IOERR, "ConnectionError"),
37
+ #endif
38
+ #ifdef SQLITE_CORRUPT
39
+ ERRCODE(SQLITE_CORRUPT, "ConnectionError"),
40
+ #endif
41
+ #ifdef SQLITE_FULL
42
+ ERRCODE(SQLITE_FULL, "ConnectionError"),
43
+ #endif
44
+ #ifdef SQLITE_CANTOPEN
45
+ ERRCODE(SQLITE_CANTOPEN, "ConnectionError"),
46
+ #endif
47
+ #ifdef SQLITE_EMPTY
48
+ ERRCODE(SQLITE_EMPTY, "ConnectionError"),
49
+ #endif
50
+ #ifdef SQLITE_SCHEMA
51
+ ERRCODE(SQLITE_SCHEMA, "DataError"),
52
+ #endif
53
+ #ifdef SQLITE_TOOBIG
54
+ ERRCODE(SQLITE_TOOBIG, "DataError"),
55
+ #endif
56
+ #ifdef SQLITE_MISMATCH
57
+ ERRCODE(SQLITE_MISMATCH, "DataError"),
58
+ #endif
59
+ #ifdef SQLITE_CONSTRAINT
60
+ ERRCODE(SQLITE_CONSTRAINT, "IntegrityError"),
61
+ #endif
62
+ #ifdef SQLITE_MISUSE
63
+ ERRCODE(SQLITE_MISUSE, "SQLError"),
64
+ #endif
65
+
66
+ #ifdef SQLITE_NOLFS
67
+ ERRCODE(SQLITE_NOLFS, "ConnectionError"),
68
+ #endif
69
+ #ifdef SQLITE_FORMAT
70
+ ERRCODE(SQLITE_FORMAT, "SyntaxError"),
71
+ #endif
72
+ #ifdef SQLITE_RANGE
73
+ ERRCODE(SQLITE_RANGE, "DataError"),
74
+ #endif
75
+ #ifdef SQLITE_NOTADB
76
+ ERRCODE(SQLITE_NOTADB, "ConnectionError"),
77
+ #endif
78
+
79
+ #ifdef SQLITE_ROW
80
+ ERRCODE(SQLITE_ROW, "SyntaxError"),
81
+ #endif
82
+ {0, NULL, NULL}
83
+ };
84
+
85
+ #endif
@@ -0,0 +1,26 @@
1
+ # Loads mkmf which is used to make makefiles for Ruby extensions
2
+ require 'mkmf'
3
+ require 'date'
4
+
5
+ # Allow for custom compiler to be specified.
6
+ RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
7
+
8
+ # Use some default search paths
9
+ dir_config('sqlite3', %w[/usr/local /opt/local /usr])
10
+
11
+ # NOTE: use GCC flags unless Visual C compiler is used
12
+ $CFLAGS << ' -Wall '
13
+
14
+ $CFLAGS << ' -DHAVE_NO_DATETIME_NEWBANG' unless DateTime.respond_to?(:new!)
15
+
16
+ # Do the work
17
+ # create_makefile(extension_name)
18
+ if have_header('sqlite3.h') && have_library('sqlite3', 'sqlite3_open')
19
+ have_func('localtime_r')
20
+ have_func('gmtime_r')
21
+ have_func('sqlite3_prepare_v2')
22
+ have_func('sqlite3_open_v2')
23
+ have_func('sqlite3_enable_load_extension')
24
+
25
+ create_makefile('do_sqlite3/do_sqlite3')
26
+ end
@@ -0,0 +1,21 @@
1
+ module DataObjects
2
+ module Sqlite3
3
+ class Transaction < DataObjects::Transaction
4
+ def begin_prepared
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def commit_prepared
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def rollback_prepared
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def prepare
17
+ raise NotImplementedError
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module DataObjects
2
+ module Sqlite3
3
+ VERSION = '0.10.17'.freeze
4
+ end
5
+ end
data/lib/do_sqlite3.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'data_objects'
2
+
3
+ begin
4
+ require 'do_sqlite3/do_sqlite3'
5
+ rescue LoadError
6
+ raise unless RUBY_PLATFORM =~ /mingw|mswin/
7
+
8
+ RUBY_VERSION =~ /(\d+.\d+)/
9
+ require "do_sqlite3/#{Regexp.last_match(1)}/do_sqlite3"
10
+ end
11
+
12
+ require 'do_sqlite3/version'
13
+ require 'do_sqlite3/transaction'