do_sqlite3 0.9.12-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,14 @@
1
+ == 0.9.11 2009-01-19
2
+ * Improvements
3
+ * Ruby 1.9 support
4
+ * Fixes
5
+ * Fix Windows gem
6
+
7
+ == 0.9.9 2008-11-27
8
+ * Improvements
9
+ * Added cross compile rake tasks for Windows gems [Jonathan Stott, Luis Lavena]
10
+ * Added initial support for Ruby 1.9 [John Harrison]
11
+
12
+ * Bug Fixes
13
+ * Removed sqlite3.dll from source gem [Dan Kubb]
14
+ * Removed hard coded .bundle from source [Dirkjan Bussink]
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007, 2008, 2009 Yehuda Katz, Dirkjan Bussink
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,31 @@
1
+ .gitignore
2
+ History.txt
3
+ LICENSE
4
+ Manifest.txt
5
+ README.txt
6
+ Rakefile
7
+ buildfile
8
+ ext-java/src/main/java/DoSqlite3ExtService.java
9
+ ext-java/src/main/java/do_sqlite3/Sqlite3DriverDefinition.java
10
+ ext/do_sqlite3_ext/do_sqlite3_ext.c
11
+ ext/do_sqlite3_ext/extconf.rb
12
+ lib/do_sqlite3.rb
13
+ lib/do_sqlite3/transaction.rb
14
+ lib/do_sqlite3/version.rb
15
+ spec/command_spec.rb
16
+ spec/connection_spec.rb
17
+ spec/reader_spec.rb
18
+ spec/result_spec.rb
19
+ spec/spec.opts
20
+ spec/spec_helper.rb
21
+ spec/typecast/bigdecimal_spec.rb
22
+ spec/typecast/boolean_spec.rb
23
+ spec/typecast/byte_array_spec.rb
24
+ spec/typecast/class_spec.rb
25
+ spec/typecast/date_spec.rb
26
+ spec/typecast/datetime_spec.rb
27
+ spec/typecast/float_spec.rb
28
+ spec/typecast/integer_spec.rb
29
+ spec/typecast/nil_spec.rb
30
+ spec/typecast/string_spec.rb
31
+ spec/typecast/time_spec.rb
data/README.txt ADDED
@@ -0,0 +1,3 @@
1
+ = do_sqlite3
2
+
3
+ A DataObjects driver for SQLite3
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+
5
+ require 'pathname'
6
+ require 'lib/do_sqlite3/version'
7
+
8
+ ROOT = Pathname(__FILE__).dirname.expand_path
9
+ JRUBY = RUBY_PLATFORM =~ /java/
10
+ WINDOWS = Gem.win_platform?
11
+ SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
12
+ BINARY_VERSION = '3_6_13'
13
+
14
+ Dir['tasks/*.rake'].each { |f| import f }
15
+
16
+ CLEAN.include(%w[ {tmp,pkg}/ **/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,exp,DS_Store,rbc,db} ext/do_sqlite3_ext/Makefile ext-java/target ])
@@ -0,0 +1,706 @@
1
+ #include <ruby.h>
2
+ #include <string.h>
3
+ #include <math.h>
4
+ #include <time.h>
5
+ #include <locale.h>
6
+ #include <sqlite3.h>
7
+
8
+ #define ID_CONST_GET rb_intern("const_get")
9
+ #define ID_PATH rb_intern("path")
10
+ #define ID_NEW rb_intern("new")
11
+ #define ID_ESCAPE rb_intern("escape_sql")
12
+ #define ID_QUERY rb_intern("query")
13
+
14
+ #define RUBY_CLASS(name) rb_const_get(rb_cObject, rb_intern(name))
15
+ #define RUBY_STRING(char_ptr) rb_str_new2(char_ptr)
16
+ #define TAINTED_STRING(name, length) rb_tainted_str_new(name, length)
17
+ #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
18
+ #define SQLITE3_CLASS(klass, parent) (rb_define_class_under(mSqlite3, klass, parent))
19
+
20
+ #define TRUE_CLASS CONST_GET(rb_mKernel, "TrueClass")
21
+
22
+ #ifndef RSTRING_PTR
23
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
24
+ #endif
25
+
26
+ #ifndef RSTRING_LEN
27
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
28
+ #endif
29
+
30
+ #ifndef RARRAY_LEN
31
+ #define RARRAY_LEN(a) RARRAY(a)->len
32
+ #endif
33
+
34
+ #ifdef _WIN32
35
+ #define do_int64 signed __int64
36
+ #else
37
+ #define do_int64 signed long long int
38
+ #endif
39
+
40
+ #ifndef HAVE_SQLITE3_PREPARE_V2
41
+ #define sqlite3_prepare_v2 sqlite3_prepare
42
+ #endif
43
+
44
+ // To store rb_intern values
45
+ static ID ID_NEW_DATE;
46
+ static ID ID_RATIONAL;
47
+ static ID ID_LOGGER;
48
+ static ID ID_DEBUG;
49
+ static ID ID_LEVEL;
50
+
51
+ static VALUE mExtlib;
52
+
53
+ static VALUE mDO;
54
+ static VALUE cDO_Quoting;
55
+ static VALUE cDO_Connection;
56
+ static VALUE cDO_Command;
57
+ static VALUE cDO_Result;
58
+ static VALUE cDO_Reader;
59
+
60
+ static VALUE rb_cDate;
61
+ static VALUE rb_cDateTime;
62
+ static VALUE rb_cBigDecimal;
63
+ static VALUE rb_cByteArray;
64
+
65
+ static VALUE mSqlite3;
66
+ static VALUE cConnection;
67
+ static VALUE cCommand;
68
+ static VALUE cResult;
69
+ static VALUE cReader;
70
+
71
+ static VALUE eArgumentError;
72
+ static VALUE eSqlite3Error;
73
+
74
+ static VALUE OPEN_FLAG_READONLY;
75
+ static VALUE OPEN_FLAG_READWRITE;
76
+ static VALUE OPEN_FLAG_CREATE;
77
+ static VALUE OPEN_FLAG_NO_MUTEX;
78
+ static VALUE OPEN_FLAG_FULL_MUTEX;
79
+
80
+ // Find the greatest common denominator and reduce the provided numerator and denominator.
81
+ // This replaces calles to Rational.reduce! which does the same thing, but really slowly.
82
+ static void reduce( do_int64 *numerator, do_int64 *denominator ) {
83
+ do_int64 a, b, c = 0;
84
+ a = *numerator;
85
+ b = *denominator;
86
+ while ( a != 0 ) {
87
+ c = a; a = b % a; b = c;
88
+ }
89
+ *numerator = *numerator / b;
90
+ *denominator = *denominator / b;
91
+ }
92
+
93
+ // Generate the date integer which Date.civil_to_jd returns
94
+ static int jd_from_date(int year, int month, int day) {
95
+ int a, b;
96
+ if ( month <= 2 ) {
97
+ year -= 1;
98
+ month += 12;
99
+ }
100
+ a = year / 100;
101
+ b = 2 - a + (a / 4);
102
+ return floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524;
103
+ }
104
+
105
+ static void data_objects_debug(VALUE string, struct timeval* start) {
106
+ struct timeval stop;
107
+ char *message;
108
+
109
+ char *query = RSTRING_PTR(string);
110
+ int length = RSTRING_LEN(string);
111
+ char total_time[32];
112
+ do_int64 duration = 0;
113
+
114
+ VALUE logger = rb_funcall(mSqlite3, ID_LOGGER, 0);
115
+ int log_level = NUM2INT(rb_funcall(logger, ID_LEVEL, 0));
116
+
117
+ if (0 == log_level) {
118
+ gettimeofday(&stop, NULL);
119
+
120
+ duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec;
121
+
122
+ snprintf(total_time, 32, "%.6f", duration / 1000000.0);
123
+ message = (char *)calloc(length + strlen(total_time) + 4, sizeof(char));
124
+ snprintf(message, length + strlen(total_time) + 4, "(%s) %s", total_time, query);
125
+ rb_funcall(logger, ID_DEBUG, 1, rb_str_new(message, length + strlen(total_time) + 3));
126
+ }
127
+ }
128
+
129
+
130
+ static VALUE parse_date(char *date) {
131
+ int year, month, day;
132
+ int jd, ajd;
133
+ VALUE rational;
134
+
135
+ sscanf(date, "%4d-%2d-%2d", &year, &month, &day);
136
+
137
+ jd = jd_from_date(year, month, day);
138
+
139
+ // Math from Date.jd_to_ajd
140
+ ajd = jd * 2 - 1;
141
+ rational = rb_funcall(rb_mKernel, ID_RATIONAL, 2, INT2NUM(ajd), INT2NUM(2));
142
+ return rb_funcall(rb_cDate, ID_NEW_DATE, 3, rational, INT2NUM(0), INT2NUM(2299161));
143
+ }
144
+
145
+ // Creates a Rational for use as a Timezone offset to be passed to DateTime.new!
146
+ static VALUE seconds_to_offset(do_int64 num) {
147
+ do_int64 den = 86400;
148
+ reduce(&num, &den);
149
+ return rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ll2inum(num), rb_ll2inum(den));
150
+ }
151
+
152
+ static VALUE timezone_to_offset(int hour_offset, int minute_offset) {
153
+ do_int64 seconds = 0;
154
+
155
+ seconds += hour_offset * 3600;
156
+ seconds += minute_offset * 60;
157
+
158
+ return seconds_to_offset(seconds);
159
+ }
160
+
161
+ static VALUE parse_date_time(char *date) {
162
+ VALUE ajd, offset;
163
+
164
+ int year, month, day, hour, min, sec, usec, hour_offset, minute_offset;
165
+ int jd;
166
+ do_int64 num, den;
167
+
168
+ long int gmt_offset;
169
+ int is_dst;
170
+
171
+ time_t rawtime;
172
+ struct tm * timeinfo;
173
+
174
+ int tokens_read, max_tokens;
175
+
176
+ if ( strcmp(date, "") == 0 ) {
177
+ return Qnil;
178
+ }
179
+
180
+ if (0 != strchr(date, '.')) {
181
+ // This is a datetime with sub-second precision
182
+ tokens_read = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d.%d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &usec, &hour_offset, &minute_offset);
183
+ max_tokens = 9;
184
+ } else {
185
+ // This is a datetime second precision
186
+ tokens_read = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset);
187
+ max_tokens = 8;
188
+ }
189
+
190
+ if (max_tokens == tokens_read) {
191
+ // We read the Date, Time, and Timezone info
192
+ minute_offset *= hour_offset < 0 ? -1 : 1;
193
+ } else if ((max_tokens - 1) == tokens_read) {
194
+ // We read the Date and Time, but no Minute Offset
195
+ minute_offset = 0;
196
+ } else if (tokens_read == 3 || tokens_read >= (max_tokens - 3)) {
197
+ if (tokens_read == 3) {
198
+ hour = 0;
199
+ min = 0;
200
+ hour_offset = 0;
201
+ minute_offset = 0;
202
+ sec = 0;
203
+ }
204
+ // We read the Date and Time, default to the current locale's offset
205
+
206
+ // Get localtime
207
+ time(&rawtime);
208
+ timeinfo = localtime(&rawtime);
209
+
210
+ is_dst = timeinfo->tm_isdst * 3600;
211
+
212
+ // Reset to GM Time
213
+ timeinfo = gmtime(&rawtime);
214
+
215
+ gmt_offset = mktime(timeinfo) - rawtime;
216
+
217
+ if ( is_dst > 0 )
218
+ gmt_offset -= is_dst;
219
+
220
+ hour_offset = -(gmt_offset / 3600);
221
+ minute_offset = -(gmt_offset % 3600 / 60);
222
+
223
+ } else {
224
+ // Something went terribly wrong
225
+ rb_raise(eSqlite3Error, "Couldn't parse date: %s", date);
226
+ }
227
+
228
+ jd = jd_from_date(year, month, day);
229
+
230
+ // Generate ajd with fractional days for the time
231
+ // Extracted from Date#jd_to_ajd, Date#day_fraction_to_time, and Rational#+ and #-
232
+ num = (hour * 1440) + (min * 24);
233
+
234
+ // Modify the numerator so when we apply the timezone everything works out
235
+ num -= (hour_offset * 1440) + (minute_offset * 24);
236
+
237
+ den = (24 * 1440);
238
+ reduce(&num, &den);
239
+
240
+ num = (num * 86400) + (sec * den);
241
+ den = den * 86400;
242
+ reduce(&num, &den);
243
+
244
+ num = (jd * den) + num;
245
+
246
+ num = num * 2;
247
+ num = num - den;
248
+ den = den * 2;
249
+
250
+ reduce(&num, &den);
251
+
252
+ ajd = rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ull2inum(num), rb_ull2inum(den));
253
+ offset = timezone_to_offset(hour_offset, minute_offset);
254
+
255
+ return rb_funcall(rb_cDateTime, ID_NEW_DATE, 3, ajd, offset, INT2NUM(2299161));
256
+ }
257
+
258
+ static VALUE parse_time(char *date) {
259
+
260
+ int year, month, day, hour, min, sec, usec, tokens, hour_offset, minute_offset;
261
+
262
+ if (0 != strchr(date, '.')) {
263
+ // This is a datetime with sub-second precision
264
+ tokens = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d.%d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &usec, &hour_offset, &minute_offset);
265
+ } else {
266
+ // This is a datetime second precision
267
+ tokens = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset);
268
+ usec = 0;
269
+ if(tokens == 3) {
270
+ hour = 0;
271
+ min = 0;
272
+ sec = 0;
273
+ hour_offset = 0;
274
+ minute_offset = 0;
275
+ }
276
+ }
277
+
278
+ return rb_funcall(rb_cTime, rb_intern("local"), 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
279
+ }
280
+
281
+ static VALUE typecast(sqlite3_stmt *stmt, int i, VALUE type) {
282
+ VALUE ruby_value = Qnil;
283
+ int original_type = sqlite3_column_type(stmt, i);
284
+ int length = sqlite3_column_bytes(stmt, i);
285
+ if ( original_type == SQLITE_NULL ) {
286
+ return ruby_value;
287
+ }
288
+
289
+ if(type == Qnil) {
290
+ switch(original_type) {
291
+ case SQLITE_INTEGER: {
292
+ type = rb_cInteger;
293
+ break;
294
+ }
295
+ case SQLITE_FLOAT: {
296
+ type = rb_cFloat;
297
+ break;
298
+ }
299
+ case SQLITE_BLOB: {
300
+ type = rb_cByteArray;
301
+ break;
302
+ }
303
+ default: {
304
+ type = rb_cString;
305
+ break;
306
+ }
307
+ }
308
+ }
309
+
310
+ if (type == rb_cInteger) {
311
+ return LL2NUM(sqlite3_column_int64(stmt, i));
312
+ } else if (type == rb_cString) {
313
+ return TAINTED_STRING((char*)sqlite3_column_text(stmt, i), length);
314
+ } else if (type == rb_cFloat) {
315
+ return rb_float_new(sqlite3_column_double(stmt, i));
316
+ } else if (type == rb_cBigDecimal) {
317
+ return rb_funcall(rb_cBigDecimal, ID_NEW, 1, TAINTED_STRING((char*)sqlite3_column_text(stmt, i), length));
318
+ } else if (type == rb_cDate) {
319
+ return parse_date((char*)sqlite3_column_text(stmt, i));
320
+ } else if (type == rb_cDateTime) {
321
+ return parse_date_time((char*)sqlite3_column_text(stmt, i));
322
+ } else if (type == rb_cTime) {
323
+ return parse_time((char*)sqlite3_column_text(stmt, i));
324
+ } else if (type == rb_cTrueClass) {
325
+ return strcmp((char*)sqlite3_column_text(stmt, i), "t") == 0 ? Qtrue : Qfalse;
326
+ } else if (type == rb_cByteArray) {
327
+ return rb_funcall(rb_cByteArray, ID_NEW, 1, TAINTED_STRING((char*)sqlite3_column_blob(stmt, i), length));
328
+ } else if (type == rb_cClass) {
329
+ return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, TAINTED_STRING((char*)sqlite3_column_text(stmt, i), length));
330
+ } else if (type == rb_cObject) {
331
+ return rb_marshal_load(rb_str_new((char*)sqlite3_column_text(stmt, i), length));
332
+ } else if (type == rb_cNilClass) {
333
+ return Qnil;
334
+ } else {
335
+ return TAINTED_STRING((char*)sqlite3_column_text(stmt, i), length);
336
+ }
337
+ }
338
+
339
+ #ifdef HAVE_SQLITE3_OPEN_V2
340
+
341
+ #define FLAG_PRESENT(query_values, flag) !NIL_P(rb_hash_aref(query_values, flag))
342
+
343
+ static int flags_from_uri(VALUE uri) {
344
+ VALUE query_values = rb_funcall(uri, ID_QUERY, 0);
345
+
346
+ int flags = 0;
347
+
348
+ if (!NIL_P(query_values) && TYPE(query_values) == T_HASH) {
349
+ /// scan for flags
350
+ #ifdef SQLITE_OPEN_READONLY
351
+ if (FLAG_PRESENT(query_values, OPEN_FLAG_READONLY)) {
352
+ flags |= SQLITE_OPEN_READONLY;
353
+ } else {
354
+ flags |= SQLITE_OPEN_READWRITE;
355
+ }
356
+ #endif
357
+ #ifdef SQLITE_OPEN_NOMUTEX
358
+ if (FLAG_PRESENT(query_values, OPEN_FLAG_NO_MUTEX)) {
359
+ flags |= SQLITE_OPEN_NOMUTEX;
360
+ }
361
+ #endif
362
+ #ifdef SQLITE_OPEN_FULLMUTEX
363
+ if (FLAG_PRESENT(query_values, OPEN_FLAG_FULL_MUTEX)) {
364
+ flags |= SQLITE_OPEN_FULLMUTEX;
365
+ }
366
+ #endif
367
+ flags |= SQLITE_OPEN_CREATE;
368
+ } else {
369
+ flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
370
+ }
371
+
372
+ return flags;
373
+ }
374
+
375
+ #endif
376
+
377
+ /****** Public API ******/
378
+
379
+ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
380
+ int ret;
381
+ VALUE path;
382
+ sqlite3 *db;
383
+
384
+ path = rb_funcall(uri, ID_PATH, 0);
385
+
386
+ #ifdef HAVE_SQLITE3_OPEN_V2
387
+ ret = sqlite3_open_v2(StringValuePtr(path), &db, flags_from_uri(uri), 0);
388
+ #else
389
+ ret = sqlite3_open(StringValuePtr(path), &db);
390
+ #endif
391
+
392
+ if ( ret != SQLITE_OK ) {
393
+ rb_raise(eSqlite3Error, sqlite3_errmsg(db));
394
+ }
395
+
396
+ rb_iv_set(self, "@uri", uri);
397
+ rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
398
+
399
+ return Qtrue;
400
+ }
401
+
402
+ static VALUE cConnection_dispose(VALUE self) {
403
+ VALUE connection_container = rb_iv_get(self, "@connection");
404
+
405
+ sqlite3 *db;
406
+
407
+ if (Qnil == connection_container)
408
+ return Qfalse;
409
+
410
+ db = DATA_PTR(connection_container);
411
+
412
+ if (NULL == db)
413
+ return Qfalse;
414
+
415
+ sqlite3_close(db);
416
+ rb_iv_set(self, "@connection", Qnil);
417
+
418
+ return Qtrue;
419
+
420
+ }
421
+
422
+ static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
423
+ VALUE type_strings = rb_ary_new();
424
+ VALUE array = rb_ary_new();
425
+
426
+ int i, j;
427
+
428
+ for ( i = 0; i < argc; i++) {
429
+ rb_ary_push(array, argv[i]);
430
+ }
431
+
432
+ for (i = 0; i < RARRAY_LEN(array); i++) {
433
+ VALUE entry = rb_ary_entry(array, i);
434
+ if(TYPE(entry) == T_CLASS) {
435
+ rb_ary_push(type_strings, entry);
436
+ } else if (TYPE(entry) == T_ARRAY) {
437
+ for (j = 0; j < RARRAY_LEN(entry); j++) {
438
+ VALUE sub_entry = rb_ary_entry(entry, j);
439
+ if(TYPE(sub_entry) == T_CLASS) {
440
+ rb_ary_push(type_strings, sub_entry);
441
+ } else {
442
+ rb_raise(eArgumentError, "Invalid type given");
443
+ }
444
+ }
445
+ } else {
446
+ rb_raise(eArgumentError, "Invalid type given");
447
+ }
448
+ }
449
+
450
+ rb_iv_set(self, "@field_types", type_strings);
451
+
452
+ return array;
453
+ }
454
+
455
+ static VALUE cConnection_quote_boolean(VALUE self, VALUE value) {
456
+ return rb_tainted_str_new2(value == Qtrue ? "'t'" : "'f'");
457
+ }
458
+
459
+ static VALUE cConnection_quote_string(VALUE self, VALUE string) {
460
+ const char *source = StringValuePtr(string);
461
+ char *escaped_with_quotes;
462
+ VALUE result;
463
+
464
+ // Wrap the escaped string in single-quotes, this is DO's convention
465
+ escaped_with_quotes = sqlite3_mprintf("%Q", source);
466
+
467
+ result = rb_tainted_str_new2(escaped_with_quotes);
468
+ sqlite3_free(escaped_with_quotes);
469
+ return result;
470
+ }
471
+
472
+ static VALUE build_query_from_args(VALUE klass, int count, VALUE *args) {
473
+ VALUE query = rb_iv_get(klass, "@text");
474
+ int i;
475
+ VALUE array = rb_ary_new();
476
+ for ( i = 0; i < count; i++) {
477
+ rb_ary_push(array, (VALUE)args[i]);
478
+ }
479
+ query = rb_funcall(klass, ID_ESCAPE, 1, array);
480
+ return query;
481
+ }
482
+
483
+ static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
484
+ sqlite3 *db;
485
+ char *error_message;
486
+ int status;
487
+ int affected_rows;
488
+ int insert_id;
489
+ VALUE conn_obj;
490
+ VALUE query;
491
+ struct timeval start;
492
+
493
+ query = build_query_from_args(self, argc, argv);
494
+
495
+ conn_obj = rb_iv_get(self, "@connection");
496
+ Data_Get_Struct(rb_iv_get(conn_obj, "@connection"), sqlite3, db);
497
+
498
+ gettimeofday(&start, NULL);
499
+ status = sqlite3_exec(db, StringValuePtr(query), 0, 0, &error_message);
500
+
501
+ if ( status != SQLITE_OK ) {
502
+ rb_raise(eSqlite3Error, "%s\nQuery: %s", sqlite3_errmsg(db), StringValuePtr(query));
503
+ }
504
+ data_objects_debug(query, &start);
505
+
506
+ affected_rows = sqlite3_changes(db);
507
+ insert_id = sqlite3_last_insert_rowid(db);
508
+
509
+ return rb_funcall(cResult, ID_NEW, 3, self, INT2NUM(affected_rows), INT2NUM(insert_id));
510
+ }
511
+
512
+ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
513
+ sqlite3 *db;
514
+ sqlite3_stmt *sqlite3_reader;
515
+ int status;
516
+ int field_count;
517
+ int i;
518
+ VALUE reader;
519
+ VALUE conn_obj;
520
+ VALUE query;
521
+ VALUE field_names, field_types;
522
+ struct timeval start;
523
+
524
+ conn_obj = rb_iv_get(self, "@connection");
525
+ Data_Get_Struct(rb_iv_get(conn_obj, "@connection"), sqlite3, db);
526
+
527
+ query = build_query_from_args(self, argc, argv);
528
+
529
+ gettimeofday(&start, NULL);
530
+ status = sqlite3_prepare_v2(db, StringValuePtr(query), -1, &sqlite3_reader, 0);
531
+ data_objects_debug(query, &start);
532
+
533
+ if ( status != SQLITE_OK ) {
534
+ rb_raise(eSqlite3Error, "%s\nQuery: %s", sqlite3_errmsg(db), StringValuePtr(query));
535
+ }
536
+
537
+ field_count = sqlite3_column_count(sqlite3_reader);
538
+ reader = rb_funcall(cReader, ID_NEW, 0);
539
+
540
+ rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, sqlite3_reader));
541
+ rb_iv_set(reader, "@field_count", INT2NUM(field_count));
542
+
543
+ field_names = rb_ary_new();
544
+ field_types = rb_iv_get(self, "@field_types");
545
+
546
+ if ( field_types == Qnil || 0 == RARRAY_LEN(field_types) ) {
547
+ field_types = rb_ary_new();
548
+ } else if (RARRAY_LEN(field_types) != field_count) {
549
+ // Whoops... wrong number of types passed to set_types. Close the reader and raise
550
+ // and error
551
+ rb_funcall(reader, rb_intern("close"), 0);
552
+ rb_raise(eArgumentError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
553
+ }
554
+
555
+ for ( i = 0; i < field_count; i++ ) {
556
+ rb_ary_push(field_names, rb_str_new2((char *)sqlite3_column_name(sqlite3_reader, i)));
557
+ }
558
+
559
+ rb_iv_set(reader, "@fields", field_names);
560
+ rb_iv_set(reader, "@field_types", field_types);
561
+
562
+ return reader;
563
+ }
564
+
565
+ static VALUE cReader_close(VALUE self) {
566
+ VALUE reader_obj = rb_iv_get(self, "@reader");
567
+
568
+ if ( reader_obj != Qnil ) {
569
+ sqlite3_stmt *reader;
570
+ Data_Get_Struct(reader_obj, sqlite3_stmt, reader);
571
+ sqlite3_finalize(reader);
572
+ rb_iv_set(self, "@reader", Qnil);
573
+ return Qtrue;
574
+ }
575
+ else {
576
+ return Qfalse;
577
+ }
578
+ }
579
+
580
+ static VALUE cReader_next(VALUE self) {
581
+ sqlite3_stmt *reader;
582
+ int field_count;
583
+ int result;
584
+ int i;
585
+ int ft_length;
586
+ VALUE arr = rb_ary_new();
587
+ VALUE field_types;
588
+ VALUE field_type;
589
+ VALUE value;
590
+
591
+ Data_Get_Struct(rb_iv_get(self, "@reader"), sqlite3_stmt, reader);
592
+ field_count = NUM2INT(rb_iv_get(self, "@field_count"));
593
+
594
+ field_types = rb_iv_get(self, "@field_types");
595
+ ft_length = RARRAY_LEN(field_types);
596
+
597
+ result = sqlite3_step(reader);
598
+
599
+ rb_iv_set(self, "@state", INT2NUM(result));
600
+
601
+ if ( result != SQLITE_ROW ) {
602
+ rb_iv_set(self, "@values", Qnil);
603
+ return Qfalse;
604
+ }
605
+
606
+ for ( i = 0; i < field_count; i++ ) {
607
+ field_type = rb_ary_entry(field_types, i);
608
+ value = typecast(reader, i, field_type);
609
+ rb_ary_push(arr, value);
610
+ }
611
+
612
+ rb_iv_set(self, "@values", arr);
613
+
614
+ return Qtrue;
615
+ }
616
+
617
+ static VALUE cReader_values(VALUE self) {
618
+ VALUE state = rb_iv_get(self, "@state");
619
+ if ( state == Qnil || NUM2INT(state) != SQLITE_ROW ) {
620
+ rb_raise(eSqlite3Error, "Reader is not initialized");
621
+ return Qnil;
622
+ }
623
+ else {
624
+ return rb_iv_get(self, "@values");
625
+ }
626
+ }
627
+
628
+ static VALUE cReader_fields(VALUE self) {
629
+ return rb_iv_get(self, "@fields");
630
+ }
631
+
632
+ static VALUE cReader_field_count(VALUE self) {
633
+ return rb_iv_get(self, "@field_count");
634
+ }
635
+
636
+ void Init_do_sqlite3_ext() {
637
+ rb_require("bigdecimal");
638
+ rb_require("date");
639
+
640
+ // Get references classes needed for Date/Time parsing
641
+ rb_cDate = RUBY_CLASS("Date");
642
+ rb_cDateTime = RUBY_CLASS( "DateTime");
643
+ rb_cBigDecimal = RUBY_CLASS("BigDecimal");
644
+
645
+ rb_funcall(rb_mKernel, rb_intern("require"), 1, rb_str_new2("data_objects"));
646
+
647
+ #ifdef RUBY_LESS_THAN_186
648
+ ID_NEW_DATE = rb_intern("new0");
649
+ #else
650
+ ID_NEW_DATE = rb_intern("new!");
651
+ #endif
652
+ ID_RATIONAL = rb_intern("Rational");
653
+ ID_LOGGER = rb_intern("logger");
654
+ ID_DEBUG = rb_intern("debug");
655
+ ID_LEVEL = rb_intern("level");
656
+
657
+ // Get references to the Extlib module
658
+ mExtlib = CONST_GET(rb_mKernel, "Extlib");
659
+ rb_cByteArray = CONST_GET(mExtlib, "ByteArray");
660
+
661
+ // Get references to the DataObjects module and its classes
662
+ mDO = CONST_GET(rb_mKernel, "DataObjects");
663
+ cDO_Quoting = CONST_GET(mDO, "Quoting");
664
+ cDO_Connection = CONST_GET(mDO, "Connection");
665
+ cDO_Command = CONST_GET(mDO, "Command");
666
+ cDO_Result = CONST_GET(mDO, "Result");
667
+ cDO_Reader = CONST_GET(mDO, "Reader");
668
+
669
+ // Initialize the DataObjects::Sqlite3 module, and define its classes
670
+ mSqlite3 = rb_define_module_under(mDO, "Sqlite3");
671
+
672
+ eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
673
+ eSqlite3Error = rb_define_class("Sqlite3Error", rb_eStandardError);
674
+
675
+ cConnection = SQLITE3_CLASS("Connection", cDO_Connection);
676
+ rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
677
+ rb_define_method(cConnection, "dispose", cConnection_dispose, 0);
678
+ rb_define_method(cConnection, "quote_boolean", cConnection_quote_boolean, 1);
679
+ rb_define_method(cConnection, "quote_string", cConnection_quote_string, 1);
680
+
681
+ cCommand = SQLITE3_CLASS("Command", cDO_Command);
682
+ rb_define_method(cCommand, "set_types", cCommand_set_types, -1);
683
+ rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
684
+ rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
685
+
686
+ cResult = SQLITE3_CLASS("Result", cDO_Result);
687
+
688
+ cReader = SQLITE3_CLASS("Reader", cDO_Reader);
689
+ rb_define_method(cReader, "close", cReader_close, 0);
690
+ rb_define_method(cReader, "next!", cReader_next, 0);
691
+ rb_define_method(cReader, "values", cReader_values, 0);
692
+ rb_define_method(cReader, "fields", cReader_fields, 0);
693
+ rb_define_method(cReader, "field_count", cReader_field_count, 0);
694
+
695
+ OPEN_FLAG_READONLY = rb_str_new2("read_only");
696
+ rb_global_variable(&OPEN_FLAG_READONLY);
697
+ OPEN_FLAG_READWRITE = rb_str_new2("read_write");
698
+ rb_global_variable(&OPEN_FLAG_READWRITE);
699
+ OPEN_FLAG_CREATE = rb_str_new2("create");
700
+ rb_global_variable(&OPEN_FLAG_CREATE);
701
+ OPEN_FLAG_NO_MUTEX = rb_str_new2("no_mutex");
702
+ rb_global_variable(&OPEN_FLAG_NO_MUTEX);
703
+ OPEN_FLAG_FULL_MUTEX = rb_str_new2("full_mutex");
704
+ rb_global_variable(&OPEN_FLAG_FULL_MUTEX);
705
+
706
+ }