do_sqlite3 0.9.12 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{History.txt → HISTORY.markdown} +10 -2
- data/Manifest.txt +2 -2
- data/{README.txt → README.markdown} +2 -1
- data/Rakefile +2 -2
- data/ext/do_sqlite3_ext/do_sqlite3_ext.c +94 -19
- data/ext/do_sqlite3_ext/error.h +106 -0
- data/ext/do_sqlite3_ext/extconf.rb +3 -19
- data/lib/do_sqlite3.rb +19 -18
- data/lib/do_sqlite3/transaction.rb +6 -14
- data/lib/do_sqlite3/version.rb +1 -1
- data/spec/result_spec.rb +10 -0
- data/spec/spec_helper.rb +39 -10
- data/spec/typecast/bigdecimal_spec.rb +3 -0
- data/spec/typecast/boolean_spec.rb +3 -0
- data/spec/typecast/date_spec.rb +3 -0
- data/spec/typecast/datetime_spec.rb +3 -0
- data/spec/typecast/float_spec.rb +4 -0
- data/spec/typecast/nil_spec.rb +11 -1
- data/tasks/gem.rake +1 -54
- data/tasks/release.rake +7 -7
- data/tasks/retrieve.rake +2 -2
- data/tasks/spec.rake +1 -0
- metadata +9 -8
@@ -1,10 +1,18 @@
|
|
1
|
-
|
1
|
+
## 0.10.0 2009-10-15
|
2
|
+
* Improvements
|
3
|
+
* JRuby Support (using *do_jdbc*)
|
4
|
+
|
5
|
+
## 0.9.12 2009-05-17
|
6
|
+
* Improvements
|
7
|
+
* rake-compiler for Windows support
|
8
|
+
|
9
|
+
## 0.9.11 2009-01-19
|
2
10
|
* Improvements
|
3
11
|
* Ruby 1.9 support
|
4
12
|
* Fixes
|
5
13
|
* Fix Windows gem
|
6
14
|
|
7
|
-
|
15
|
+
## 0.9.9 2008-11-27
|
8
16
|
* Improvements
|
9
17
|
* Added cross compile rake tasks for Windows gems [Jonathan Stott, Luis Lavena]
|
10
18
|
* Added initial support for Ruby 1.9 [John Harrison]
|
data/Manifest.txt
CHANGED
data/Rakefile
CHANGED
@@ -8,9 +8,9 @@ require 'lib/do_sqlite3/version'
|
|
8
8
|
ROOT = Pathname(__FILE__).dirname.expand_path
|
9
9
|
JRUBY = RUBY_PLATFORM =~ /java/
|
10
10
|
WINDOWS = Gem.win_platform?
|
11
|
-
SUDO =
|
11
|
+
SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
|
12
12
|
BINARY_VERSION = '3_6_13'
|
13
13
|
|
14
|
-
Dir['tasks/*.rake'].each { |f| import f }
|
14
|
+
Dir['tasks/*.rake'].sort.each { |f| import f }
|
15
15
|
|
16
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 ])
|
@@ -4,6 +4,38 @@
|
|
4
4
|
#include <time.h>
|
5
5
|
#include <locale.h>
|
6
6
|
#include <sqlite3.h>
|
7
|
+
#include "error.h"
|
8
|
+
|
9
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
10
|
+
#include <ruby/encoding.h>
|
11
|
+
|
12
|
+
#define DO_STR_NEW2(str, encoding) \
|
13
|
+
({ \
|
14
|
+
VALUE _string = rb_str_new2((const char *)str); \
|
15
|
+
if(encoding != -1) { \
|
16
|
+
rb_enc_associate_index(_string, encoding); \
|
17
|
+
} \
|
18
|
+
_string; \
|
19
|
+
})
|
20
|
+
|
21
|
+
#define DO_STR_NEW(str, len, encoding) \
|
22
|
+
({ \
|
23
|
+
VALUE _string = rb_str_new((const char *)str, (long)len); \
|
24
|
+
if(encoding != -1) { \
|
25
|
+
rb_enc_associate_index(_string, encoding); \
|
26
|
+
} \
|
27
|
+
_string; \
|
28
|
+
})
|
29
|
+
|
30
|
+
#else
|
31
|
+
|
32
|
+
#define DO_STR_NEW2(str, encoding) \
|
33
|
+
rb_str_new2((const char *)str)
|
34
|
+
|
35
|
+
#define DO_STR_NEW(str, len, encoding) \
|
36
|
+
rb_str_new((const char *)str, (long)len)
|
37
|
+
#endif
|
38
|
+
|
7
39
|
|
8
40
|
#define ID_CONST_GET rb_intern("const_get")
|
9
41
|
#define ID_PATH rb_intern("path")
|
@@ -12,8 +44,6 @@
|
|
12
44
|
#define ID_QUERY rb_intern("query")
|
13
45
|
|
14
46
|
#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
47
|
#define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
|
18
48
|
#define SQLITE3_CLASS(klass, parent) (rb_define_class_under(mSqlite3, klass, parent))
|
19
49
|
|
@@ -69,7 +99,8 @@ static VALUE cResult;
|
|
69
99
|
static VALUE cReader;
|
70
100
|
|
71
101
|
static VALUE eArgumentError;
|
72
|
-
static VALUE
|
102
|
+
static VALUE eConnectionError;
|
103
|
+
static VALUE eDataError;
|
73
104
|
|
74
105
|
static VALUE OPEN_FLAG_READONLY;
|
75
106
|
static VALUE OPEN_FLAG_READWRITE;
|
@@ -126,6 +157,32 @@ static void data_objects_debug(VALUE string, struct timeval* start) {
|
|
126
157
|
}
|
127
158
|
}
|
128
159
|
|
160
|
+
static void raise_error(VALUE self, sqlite3 *result, VALUE query) {
|
161
|
+
VALUE exception;
|
162
|
+
const char *message = sqlite3_errmsg(result);
|
163
|
+
const char *exception_type = "SQLError";
|
164
|
+
int sqlite3_errno = sqlite3_errcode(result);
|
165
|
+
|
166
|
+
struct errcodes *errs;
|
167
|
+
|
168
|
+
for (errs = errors; errs->error_name; errs++) {
|
169
|
+
if(errs->error_no == sqlite3_errno) {
|
170
|
+
exception_type = errs->exception;
|
171
|
+
break;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
|
176
|
+
VALUE uri = rb_funcall(rb_iv_get(self, "@connection"), rb_intern("to_s"), 0);
|
177
|
+
|
178
|
+
exception = rb_funcall(CONST_GET(mDO, exception_type), ID_NEW, 5,
|
179
|
+
rb_str_new2(message),
|
180
|
+
INT2NUM(sqlite3_errno),
|
181
|
+
rb_str_new2(""),
|
182
|
+
query,
|
183
|
+
uri);
|
184
|
+
rb_exc_raise(exception);
|
185
|
+
}
|
129
186
|
|
130
187
|
static VALUE parse_date(char *date) {
|
131
188
|
int year, month, day;
|
@@ -200,7 +257,7 @@ static VALUE parse_date_time(char *date) {
|
|
200
257
|
hour_offset = 0;
|
201
258
|
minute_offset = 0;
|
202
259
|
sec = 0;
|
203
|
-
}
|
260
|
+
}
|
204
261
|
// We read the Date and Time, default to the current locale's offset
|
205
262
|
|
206
263
|
// Get localtime
|
@@ -222,7 +279,7 @@ static VALUE parse_date_time(char *date) {
|
|
222
279
|
|
223
280
|
} else {
|
224
281
|
// Something went terribly wrong
|
225
|
-
rb_raise(
|
282
|
+
rb_raise(eDataError, "Couldn't parse date: %s", date);
|
226
283
|
}
|
227
284
|
|
228
285
|
jd = jd_from_date(year, month, day);
|
@@ -278,7 +335,7 @@ static VALUE parse_time(char *date) {
|
|
278
335
|
return rb_funcall(rb_cTime, rb_intern("local"), 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
|
279
336
|
}
|
280
337
|
|
281
|
-
static VALUE typecast(sqlite3_stmt *stmt, int i, VALUE type) {
|
338
|
+
static VALUE typecast(sqlite3_stmt *stmt, int i, VALUE type, int encoding) {
|
282
339
|
VALUE ruby_value = Qnil;
|
283
340
|
int original_type = sqlite3_column_type(stmt, i);
|
284
341
|
int length = sqlite3_column_bytes(stmt, i);
|
@@ -310,11 +367,11 @@ static VALUE typecast(sqlite3_stmt *stmt, int i, VALUE type) {
|
|
310
367
|
if (type == rb_cInteger) {
|
311
368
|
return LL2NUM(sqlite3_column_int64(stmt, i));
|
312
369
|
} else if (type == rb_cString) {
|
313
|
-
return
|
370
|
+
return DO_STR_NEW((char*)sqlite3_column_text(stmt, i), length, encoding);
|
314
371
|
} else if (type == rb_cFloat) {
|
315
372
|
return rb_float_new(sqlite3_column_double(stmt, i));
|
316
373
|
} else if (type == rb_cBigDecimal) {
|
317
|
-
return rb_funcall(rb_cBigDecimal, ID_NEW, 1,
|
374
|
+
return rb_funcall(rb_cBigDecimal, ID_NEW, 1, rb_str_new((char*)sqlite3_column_text(stmt, i), length));
|
318
375
|
} else if (type == rb_cDate) {
|
319
376
|
return parse_date((char*)sqlite3_column_text(stmt, i));
|
320
377
|
} else if (type == rb_cDateTime) {
|
@@ -324,15 +381,15 @@ static VALUE typecast(sqlite3_stmt *stmt, int i, VALUE type) {
|
|
324
381
|
} else if (type == rb_cTrueClass) {
|
325
382
|
return strcmp((char*)sqlite3_column_text(stmt, i), "t") == 0 ? Qtrue : Qfalse;
|
326
383
|
} else if (type == rb_cByteArray) {
|
327
|
-
return rb_funcall(rb_cByteArray, ID_NEW, 1,
|
384
|
+
return rb_funcall(rb_cByteArray, ID_NEW, 1, rb_str_new((char*)sqlite3_column_blob(stmt, i), length));
|
328
385
|
} else if (type == rb_cClass) {
|
329
|
-
return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1,
|
386
|
+
return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, rb_str_new((char*)sqlite3_column_text(stmt, i), length));
|
330
387
|
} else if (type == rb_cObject) {
|
331
388
|
return rb_marshal_load(rb_str_new((char*)sqlite3_column_text(stmt, i), length));
|
332
389
|
} else if (type == rb_cNilClass) {
|
333
390
|
return Qnil;
|
334
391
|
} else {
|
335
|
-
return
|
392
|
+
return DO_STR_NEW((char*)sqlite3_column_text(stmt, i), length, encoding);
|
336
393
|
}
|
337
394
|
}
|
338
395
|
|
@@ -390,11 +447,16 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
|
|
390
447
|
#endif
|
391
448
|
|
392
449
|
if ( ret != SQLITE_OK ) {
|
393
|
-
|
450
|
+
raise_error(self, db, Qnil);
|
394
451
|
}
|
395
452
|
|
396
453
|
rb_iv_set(self, "@uri", uri);
|
397
454
|
rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
|
455
|
+
// Sqlite3 only supports UTF-8, so this is the standard encoding
|
456
|
+
rb_iv_set(self, "@encoding", rb_str_new2("UTF-8"));
|
457
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
458
|
+
rb_iv_set(self, "@encoding_id", INT2FIX(rb_enc_find_index("UTF-8")));
|
459
|
+
#endif
|
398
460
|
|
399
461
|
return Qtrue;
|
400
462
|
}
|
@@ -453,7 +515,7 @@ static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
|
|
453
515
|
}
|
454
516
|
|
455
517
|
static VALUE cConnection_quote_boolean(VALUE self, VALUE value) {
|
456
|
-
return
|
518
|
+
return rb_str_new2(value == Qtrue ? "'t'" : "'f'");
|
457
519
|
}
|
458
520
|
|
459
521
|
static VALUE cConnection_quote_string(VALUE self, VALUE string) {
|
@@ -464,7 +526,10 @@ static VALUE cConnection_quote_string(VALUE self, VALUE string) {
|
|
464
526
|
// Wrap the escaped string in single-quotes, this is DO's convention
|
465
527
|
escaped_with_quotes = sqlite3_mprintf("%Q", source);
|
466
528
|
|
467
|
-
result =
|
529
|
+
result = rb_str_new2(escaped_with_quotes);
|
530
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
531
|
+
rb_enc_associate_index(result, FIX2INT(rb_iv_get(self, "@encoding_id")));
|
532
|
+
#endif
|
468
533
|
sqlite3_free(escaped_with_quotes);
|
469
534
|
return result;
|
470
535
|
}
|
@@ -499,7 +564,7 @@ static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
|
|
499
564
|
status = sqlite3_exec(db, StringValuePtr(query), 0, 0, &error_message);
|
500
565
|
|
501
566
|
if ( status != SQLITE_OK ) {
|
502
|
-
|
567
|
+
raise_error(self, db, query);
|
503
568
|
}
|
504
569
|
data_objects_debug(query, &start);
|
505
570
|
|
@@ -531,7 +596,7 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
|
|
531
596
|
data_objects_debug(query, &start);
|
532
597
|
|
533
598
|
if ( status != SQLITE_OK ) {
|
534
|
-
|
599
|
+
raise_error(self, db, query);
|
535
600
|
}
|
536
601
|
|
537
602
|
field_count = sqlite3_column_count(sqlite3_reader);
|
@@ -603,9 +668,18 @@ static VALUE cReader_next(VALUE self) {
|
|
603
668
|
return Qfalse;
|
604
669
|
}
|
605
670
|
|
671
|
+
int enc = -1;
|
672
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
673
|
+
VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id");
|
674
|
+
if (encoding_id != Qnil) {
|
675
|
+
enc = FIX2INT(encoding_id);
|
676
|
+
}
|
677
|
+
#endif
|
678
|
+
|
679
|
+
|
606
680
|
for ( i = 0; i < field_count; i++ ) {
|
607
681
|
field_type = rb_ary_entry(field_types, i);
|
608
|
-
value = typecast(reader, i, field_type);
|
682
|
+
value = typecast(reader, i, field_type, enc);
|
609
683
|
rb_ary_push(arr, value);
|
610
684
|
}
|
611
685
|
|
@@ -617,7 +691,7 @@ static VALUE cReader_next(VALUE self) {
|
|
617
691
|
static VALUE cReader_values(VALUE self) {
|
618
692
|
VALUE state = rb_iv_get(self, "@state");
|
619
693
|
if ( state == Qnil || NUM2INT(state) != SQLITE_ROW ) {
|
620
|
-
rb_raise(
|
694
|
+
rb_raise(eDataError, "Reader is not initialized");
|
621
695
|
return Qnil;
|
622
696
|
}
|
623
697
|
else {
|
@@ -670,7 +744,8 @@ void Init_do_sqlite3_ext() {
|
|
670
744
|
mSqlite3 = rb_define_module_under(mDO, "Sqlite3");
|
671
745
|
|
672
746
|
eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
|
673
|
-
|
747
|
+
eConnectionError = CONST_GET(mDO, "ConnectionError");
|
748
|
+
eDataError = CONST_GET(mDO, "DataError");
|
674
749
|
|
675
750
|
cConnection = SQLITE3_CLASS("Connection", cDO_Connection);
|
676
751
|
rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
|
@@ -0,0 +1,106 @@
|
|
1
|
+
static struct errcodes {
|
2
|
+
int error_no;
|
3
|
+
const char *error_name;
|
4
|
+
const char *exception;
|
5
|
+
} errors [] = {
|
6
|
+
#ifdef SQLITE_ERROR
|
7
|
+
{ SQLITE_ERROR,
|
8
|
+
"SQLITE_ERROR", "SyntaxError"},
|
9
|
+
#endif
|
10
|
+
#ifdef SQLITE_INTERNAL
|
11
|
+
{ SQLITE_INTERNAL,
|
12
|
+
"SQLITE_INTERNAL", "SQLError"},
|
13
|
+
#endif
|
14
|
+
#ifdef SQLITE_PERM
|
15
|
+
{ SQLITE_PERM,
|
16
|
+
"SQLITE_PERM", "ConnectionError"},
|
17
|
+
#endif
|
18
|
+
#ifdef SQLITE_ABORT
|
19
|
+
{ SQLITE_ABORT,
|
20
|
+
"SQLITE_ABORT", "ConnectionError"},
|
21
|
+
#endif
|
22
|
+
#ifdef SQLITE_BUSY
|
23
|
+
{ SQLITE_BUSY,
|
24
|
+
"SQLITE_BUSY", "ConnectionError"},
|
25
|
+
#endif
|
26
|
+
|
27
|
+
#ifdef SQLITE_LOCKED
|
28
|
+
{ SQLITE_LOCKED,
|
29
|
+
"SQLITE_LOCKED", "ConnectionError"},
|
30
|
+
#endif
|
31
|
+
#ifdef SQLITE_NOMEM
|
32
|
+
{ SQLITE_NOMEM,
|
33
|
+
"SQLITE_NOMEM", "ConnectionError"},
|
34
|
+
#endif
|
35
|
+
#ifdef SQLITE_READONLY
|
36
|
+
{ SQLITE_READONLY,
|
37
|
+
"SQLITE_READONLY", "ConnectionError"},
|
38
|
+
#endif
|
39
|
+
#ifdef SQLITE_INTERRUPT
|
40
|
+
{ SQLITE_INTERRUPT,
|
41
|
+
"SQLITE_INTERRUPT", "ConnectionError"},
|
42
|
+
#endif
|
43
|
+
#ifdef SQLITE_IOERR
|
44
|
+
{ SQLITE_IOERR,
|
45
|
+
"SQLITE_IOERR", "ConnectionError"},
|
46
|
+
#endif
|
47
|
+
#ifdef SQLITE_CORRUPT
|
48
|
+
{ SQLITE_CORRUPT,
|
49
|
+
"SQLITE_CORRUPT", "ConnectionError"},
|
50
|
+
#endif
|
51
|
+
#ifdef SQLITE_FULL
|
52
|
+
{ SQLITE_FULL,
|
53
|
+
"SQLITE_FULL", "ConnectionError"},
|
54
|
+
#endif
|
55
|
+
#ifdef SQLITE_CANTOPEN
|
56
|
+
{ SQLITE_CANTOPEN,
|
57
|
+
"SQLITE_CANTOPEN", "ConnectionError"},
|
58
|
+
#endif
|
59
|
+
#ifdef SQLITE_EMPTY
|
60
|
+
{ SQLITE_EMPTY,
|
61
|
+
"SQLITE_EMPTY", "ConnectionError"},
|
62
|
+
#endif
|
63
|
+
#ifdef SQLITE_SCHEMA
|
64
|
+
{ SQLITE_SCHEMA,
|
65
|
+
"SQLITE_SCHEMA", "DataError"},
|
66
|
+
#endif
|
67
|
+
#ifdef SQLITE_TOOBIG
|
68
|
+
{ SQLITE_TOOBIG,
|
69
|
+
"SQLITE_TOOBIG", "DataError"},
|
70
|
+
#endif
|
71
|
+
#ifdef SQLITE_MISMATCH
|
72
|
+
{ SQLITE_MISMATCH,
|
73
|
+
"SQLITE_MISMATCH", "DataError"},
|
74
|
+
#endif
|
75
|
+
#ifdef SQLITE_CONSTRAINT
|
76
|
+
{ SQLITE_CONSTRAINT,
|
77
|
+
"SQLITE_CONSTRAINT", "IntegrityError"},
|
78
|
+
#endif
|
79
|
+
#ifdef SQLITE_MISUSE
|
80
|
+
{ SQLITE_MISUSE,
|
81
|
+
"SQLITE_MISUSE", "SQLError"},
|
82
|
+
#endif
|
83
|
+
|
84
|
+
#ifdef SQLITE_NOLFS
|
85
|
+
{ SQLITE_NOLFS,
|
86
|
+
"SQLITE_NOLFS", "ConnectionError"},
|
87
|
+
#endif
|
88
|
+
#ifdef SQLITE_FORMAT
|
89
|
+
{ SQLITE_FORMAT,
|
90
|
+
"SQLITE_FORMAT", "SyntaxError"},
|
91
|
+
#endif
|
92
|
+
#ifdef SQLITE_RANGE
|
93
|
+
{ SQLITE_RANGE,
|
94
|
+
"SQLITE_RANGE", "DataError"},
|
95
|
+
#endif
|
96
|
+
#ifdef SQLITE_NOTADB
|
97
|
+
{ SQLITE_NOTADB,
|
98
|
+
"SQLITE_NOTADB", "ConnectionError"},
|
99
|
+
#endif
|
100
|
+
|
101
|
+
#ifdef SQLITE_ROW
|
102
|
+
{ SQLITE_ROW,
|
103
|
+
"SQLITE_ROW", "SyntaxError"},
|
104
|
+
#endif
|
105
|
+
{0, NULL, NULL}
|
106
|
+
};
|
@@ -1,21 +1,4 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# require 'mkmf'
|
4
|
-
#
|
5
|
-
# SWIG_WRAP = "sqlite3_api_wrap.c"
|
6
|
-
#
|
7
|
-
# dir_config( "sqlite3", "/usr/local" )
|
8
|
-
#
|
9
|
-
# if have_header( "sqlite3.h" ) && have_library( "sqlite3", "sqlite3_open" )
|
10
|
-
# create_makefile( "sqlite3_c" )
|
11
|
-
# end
|
12
|
-
|
13
|
-
if RUBY_PLATFORM =~ /darwin/
|
14
|
-
ENV["RC_ARCHS"] = `uname -m`.chomp if `uname -sr` =~ /^Darwin/
|
15
|
-
|
16
|
-
# On PowerPC the defaults are fine
|
17
|
-
ENV["RC_ARCHS"] = '' if `uname -m` =~ /^Power Macintosh/
|
18
|
-
end
|
1
|
+
ENV["RC_ARCHS"] = "" if RUBY_PLATFORM =~ /darwin/
|
19
2
|
|
20
3
|
# Loads mkmf which is used to make makefiles for Ruby extensions
|
21
4
|
require 'mkmf'
|
@@ -23,7 +6,8 @@ require 'mkmf'
|
|
23
6
|
# Give it a name
|
24
7
|
extension_name = 'do_sqlite3_ext'
|
25
8
|
|
26
|
-
|
9
|
+
# Use some default search paths
|
10
|
+
dir_config("sqlite3", ["/usr/local", "/opt/local", "/usr"])
|
27
11
|
|
28
12
|
# NOTE: use GCC flags unless Visual C compiler is used
|
29
13
|
$CFLAGS << ' -Wall ' unless RUBY_PLATFORM =~ /mswin/
|
data/lib/do_sqlite3.rb
CHANGED
@@ -1,35 +1,36 @@
|
|
1
|
-
# HACK: If running on Windows, then add the current directory to the PATH
|
2
|
-
# for the current process so it can find the bundled dlls before the require
|
3
|
-
# of the actual extension file.
|
4
|
-
if RUBY_PLATFORM.match(/mingw|mswin/i)
|
5
|
-
libdir = File.expand_path(File.dirname(__FILE__)).gsub(File::SEPARATOR, File::ALT_SEPARATOR)
|
6
|
-
ENV['PATH'] = "#{libdir};" + ENV['PATH']
|
7
|
-
end
|
8
|
-
|
9
|
-
require 'rubygems'
|
10
1
|
require 'data_objects'
|
11
2
|
if RUBY_PLATFORM =~ /java/
|
12
3
|
require 'do_jdbc'
|
13
4
|
require 'java'
|
14
|
-
|
15
|
-
|
5
|
+
|
6
|
+
driver = 'org.sqlite.JDBC'
|
7
|
+
begin
|
8
|
+
java.lang.Thread.currentThread.getContextClassLoader().loadClass(driver, true)
|
9
|
+
rescue
|
10
|
+
require 'jdbc/sqlite3' # the JDBC driver, packaged as a gem
|
11
|
+
end
|
12
|
+
|
13
|
+
# Another way of loading the JDBC Class. This seems to be more reliable
|
14
|
+
# than Class.forName() or
|
15
|
+
# Thread.currentThread.getContextClassLoader().loadClass() within the
|
16
|
+
# data_objects.Connection Java class, which is currently not working as
|
17
|
+
# expected.
|
18
|
+
java_import driver
|
16
19
|
end
|
17
20
|
|
18
21
|
require 'do_sqlite3_ext'
|
19
|
-
require
|
20
|
-
require
|
22
|
+
require 'do_sqlite3/version'
|
23
|
+
require 'do_sqlite3/transaction'
|
21
24
|
|
22
25
|
if RUBY_PLATFORM =~ /java/
|
23
|
-
# Another way of loading the JDBC Class. This seems to be more reliable
|
24
|
-
# than Class.forName() within the data_objects.Connection Java class,
|
25
|
-
# which is currently not working as expected.
|
26
|
-
import 'org.sqlite.JDBC'
|
27
26
|
|
28
27
|
module DataObjects
|
29
28
|
module Sqlite3
|
30
29
|
class Connection
|
31
30
|
def self.pool_size
|
32
|
-
|
31
|
+
# sqlite3 can have only one write access at a time, with this
|
32
|
+
# concurrent write access will result in "Database locked" errors
|
33
|
+
1
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -5,28 +5,20 @@ module DataObjects
|
|
5
5
|
|
6
6
|
class Transaction < DataObjects::Transaction
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
connection.create_command(cmd).execute_non_query
|
8
|
+
def begin_prepared
|
9
|
+
raise NotImplementedError
|
11
10
|
end
|
12
11
|
|
13
|
-
def
|
14
|
-
|
15
|
-
connection.create_command(cmd).execute_non_query
|
16
|
-
end
|
17
|
-
|
18
|
-
def rollback
|
19
|
-
cmd = "ROLLBACK"
|
20
|
-
connection.create_command(cmd).execute_non_query
|
12
|
+
def commit_prepared
|
13
|
+
raise NotImplementedError
|
21
14
|
end
|
22
15
|
|
23
16
|
def rollback_prepared
|
24
|
-
|
25
|
-
connection.create_command(cmd).execute_non_query
|
17
|
+
raise NotImplementedError
|
26
18
|
end
|
27
19
|
|
28
20
|
def prepare
|
29
|
-
|
21
|
+
raise NotImplementedError
|
30
22
|
end
|
31
23
|
|
32
24
|
end
|
data/lib/do_sqlite3/version.rb
CHANGED
data/spec/result_spec.rb
CHANGED
@@ -3,7 +3,17 @@
|
|
3
3
|
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
4
4
|
require 'data_objects/spec/result_spec'
|
5
5
|
|
6
|
+
# splitting the descibe into two separate declaration avoids
|
7
|
+
# concurrent execution of the "it_should_behave_like ....." calls
|
8
|
+
# which would lock the database
|
9
|
+
|
10
|
+
# TODO
|
11
|
+
# the locked database created a deadlock which is worth exploring since
|
12
|
+
# such situation could appear in the wild too
|
6
13
|
describe DataObjects::Sqlite3::Result do
|
7
14
|
it_should_behave_like 'a Result'
|
15
|
+
end
|
16
|
+
|
17
|
+
describe DataObjects::Sqlite3::Result do
|
8
18
|
it_should_behave_like 'a Result which returns inserted keys'
|
9
19
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -11,21 +11,24 @@ require 'ostruct'
|
|
11
11
|
require 'pathname'
|
12
12
|
require 'fileutils'
|
13
13
|
|
14
|
+
dir = File.dirname(__FILE__)
|
15
|
+
lib_path = File.expand_path("#{dir}/../lib")
|
16
|
+
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
|
14
17
|
# put data_objects from repository in the load path
|
15
18
|
# DO NOT USE installed gem of data_objects!
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
DATAOBJECTS_SPEC_ROOT = Pathname(__FILE__).dirname.parent.parent + 'data_objects' + 'spec'
|
20
|
-
Pathname.glob((DATAOBJECTS_SPEC_ROOT + 'lib/**/*.rb').to_s).each { |f| require f }
|
19
|
+
do_lib_path = File.expand_path("#{dir}/../../data_objects/lib")
|
20
|
+
$LOAD_PATH.unshift do_lib_path unless $LOAD_PATH.include?(do_lib_path)
|
21
21
|
|
22
22
|
if JRUBY
|
23
|
-
|
23
|
+
jdbc_lib_path = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'do_jdbc', 'lib'))
|
24
|
+
$LOAD_PATH.unshift jdbc_lib_path unless $LOAD_PATH.include?(jdbc_lib_path)
|
24
25
|
require 'do_jdbc'
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
-
|
28
|
+
require 'data_objects'
|
29
|
+
|
30
|
+
DATAOBJECTS_SPEC_ROOT = Pathname(__FILE__).dirname.parent.parent + 'data_objects' + 'spec'
|
31
|
+
Pathname.glob((DATAOBJECTS_SPEC_ROOT + 'lib/**/*.rb').to_s).each { |f| require f }
|
29
32
|
require 'do_sqlite3'
|
30
33
|
|
31
34
|
log_path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'log', 'do.log'))
|
@@ -79,6 +82,8 @@ module DataObjectsSpecHelpers
|
|
79
82
|
);
|
80
83
|
EOF
|
81
84
|
|
85
|
+
local_offset = Rational(Time.local(2008, 2, 14).utc_offset, 86400)
|
86
|
+
t = DateTime.civil(2008, 2, 14, 00, 31, 12, local_offset)
|
82
87
|
conn.create_command(<<-EOF).execute_non_query
|
83
88
|
CREATE TABLE "widgets" (
|
84
89
|
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
@@ -91,7 +96,7 @@ module DataObjectsSpecHelpers
|
|
91
96
|
"ad_image" blob NULL,
|
92
97
|
"whitepaper_text" text NULL,
|
93
98
|
"cad_drawing" blob,
|
94
|
-
"flags"
|
99
|
+
"flags" boolean default 'f',
|
95
100
|
"number_in_stock" smallint default 500,
|
96
101
|
"number_sold" integer default 0,
|
97
102
|
"super_number" bigint default 9223372036854775807,
|
@@ -99,7 +104,7 @@ module DataObjectsSpecHelpers
|
|
99
104
|
"cost1" double precision default 10.23,
|
100
105
|
"cost2" decimal(8,2) default 50.23,
|
101
106
|
"release_date" date default '2008-02-14',
|
102
|
-
"release_datetime" timestamp default '
|
107
|
+
"release_datetime" timestamp default '#{t.to_s}',
|
103
108
|
"release_timestamp" timestamp with time zone default '2008-02-14 00:31:31'
|
104
109
|
);
|
105
110
|
EOF
|
@@ -118,6 +123,30 @@ module DataObjectsSpecHelpers
|
|
118
123
|
update widgets set ad_description = NULL where id = 3
|
119
124
|
EOF
|
120
125
|
|
126
|
+
conn.create_command(<<-EOF).execute_non_query
|
127
|
+
update widgets set flags = NULL where id = 4
|
128
|
+
EOF
|
129
|
+
|
130
|
+
conn.create_command(<<-EOF).execute_non_query
|
131
|
+
update widgets set cost1 = NULL where id = 5
|
132
|
+
EOF
|
133
|
+
|
134
|
+
conn.create_command(<<-EOF).execute_non_query
|
135
|
+
update widgets set cost2 = NULL where id = 6
|
136
|
+
EOF
|
137
|
+
|
138
|
+
conn.create_command(<<-EOF).execute_non_query
|
139
|
+
update widgets set release_date = NULL where id = 7
|
140
|
+
EOF
|
141
|
+
|
142
|
+
conn.create_command(<<-EOF).execute_non_query
|
143
|
+
update widgets set release_datetime = NULL where id = 8
|
144
|
+
EOF
|
145
|
+
|
146
|
+
conn.create_command(<<-EOF).execute_non_query
|
147
|
+
update widgets set release_timestamp = NULL where id = 9
|
148
|
+
EOF
|
149
|
+
|
121
150
|
conn.close
|
122
151
|
end
|
123
152
|
|
@@ -3,6 +3,9 @@
|
|
3
3
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
4
4
|
require 'data_objects/spec/typecast/bigdecimal_spec'
|
5
5
|
|
6
|
+
# Sqlite3 doesn't support decimals natively, so autocasting is not available:
|
7
|
+
# http://www.sqlite.org/datatype3.html
|
8
|
+
|
6
9
|
describe 'DataObjects::Sqlite3 with BigDecimal' do
|
7
10
|
it_should_behave_like 'supporting BigDecimal'
|
8
11
|
end
|
@@ -3,6 +3,9 @@
|
|
3
3
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
4
4
|
require 'data_objects/spec/typecast/boolean_spec'
|
5
5
|
|
6
|
+
# Sqlite3 doesn't support booleans natively, so autocasting is not available:
|
7
|
+
# http://www.sqlite.org/datatype3.html
|
8
|
+
|
6
9
|
describe 'DataObjects::Sqlite3 with Boolean' do
|
7
10
|
it_should_behave_like 'supporting Boolean'
|
8
11
|
end
|
data/spec/typecast/date_spec.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
4
4
|
require 'data_objects/spec/typecast/date_spec'
|
5
5
|
|
6
|
+
# Sqlite3 doesn't support dates natively, so autocasting is not available:
|
7
|
+
# http://www.sqlite.org/datatype3.html
|
8
|
+
|
6
9
|
describe 'DataObjects::Sqlite3 with Date' do
|
7
10
|
it_should_behave_like 'supporting Date'
|
8
11
|
end
|
@@ -3,6 +3,9 @@
|
|
3
3
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
4
4
|
require 'data_objects/spec/typecast/datetime_spec'
|
5
5
|
|
6
|
+
# Sqlite3 doesn't support datetimes natively, so autocasting is not available:
|
7
|
+
# http://www.sqlite.org/datatype3.html
|
8
|
+
|
6
9
|
describe 'DataObjects::Sqlite3 with DateTime' do
|
7
10
|
it_should_behave_like 'supporting DateTime'
|
8
11
|
end
|
data/spec/typecast/float_spec.rb
CHANGED
data/spec/typecast/nil_spec.rb
CHANGED
@@ -3,8 +3,18 @@
|
|
3
3
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
4
4
|
require 'data_objects/spec/typecast/nil_spec'
|
5
5
|
|
6
|
+
# splitting the descibe into two separate declaration avoids
|
7
|
+
# concurrent execution of the "it_should_behave_like ....." calls
|
8
|
+
# which would lock the database
|
9
|
+
|
6
10
|
describe 'DataObjects::Sqlite3 with Nil' do
|
7
11
|
it_should_behave_like 'supporting Nil'
|
8
|
-
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'DataObjects::Sqlite3 with Nil' do
|
15
|
+
it_should_behave_like 'supporting writing an Nil'
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'DataObjects::Sqlite3 with Nil' do
|
9
19
|
it_should_behave_like 'supporting Nil autocasting'
|
10
20
|
end
|
data/tasks/gem.rake
CHANGED
@@ -1,61 +1,8 @@
|
|
1
1
|
require 'rubygems/package_task'
|
2
2
|
|
3
|
-
GEM_SPEC =
|
4
|
-
# basic information
|
5
|
-
s.name = "do_sqlite3"
|
6
|
-
s.version = DataObjects::Sqlite3::VERSION
|
7
|
-
|
8
|
-
# description and details
|
9
|
-
s.summary = 'DataObjects Sqlite3 Driver'
|
10
|
-
s.description = "Implements the DataObjects API for Sqlite3"
|
11
|
-
|
12
|
-
# dependencies
|
13
|
-
s.add_dependency "addressable", "~>2.0.0"
|
14
|
-
s.add_dependency "extlib", "~>0.9.12"
|
15
|
-
s.add_dependency "data_objects", DataObjects::Sqlite3::VERSION
|
16
|
-
|
17
|
-
if JRUBY
|
18
|
-
s.add_dependency "jdbc-sqlite3", ">=3.5.8"
|
19
|
-
s.add_dependency "do_jdbc", DataObjects::Sqlite3::VERSION
|
20
|
-
s.platform = "java"
|
21
|
-
# components, files and paths
|
22
|
-
s.files = FileList["lib/**/*.rb", "spec/**/*.rb", "tasks/**/*.rake",
|
23
|
-
"LICENSE", "Rakefile", "*.{rdoc,txt,yml}", "lib/*.jar"]
|
24
|
-
else
|
25
|
-
s.platform = Gem::Platform::RUBY
|
26
|
-
s.extensions << 'ext/do_sqlite3_ext/extconf.rb'
|
27
|
-
# components, files and paths
|
28
|
-
s.files = FileList["lib/**/*.rb", "spec/**/*.rb", "tasks/**/*.rake", "ext/**/*.{rb,c}",
|
29
|
-
"LICENSE", "Rakefile", "*.{rdoc,txt,yml}"]
|
30
|
-
end
|
31
|
-
|
32
|
-
# development dependencies
|
33
|
-
s.add_development_dependency 'rspec', '~>1.2.0'
|
34
|
-
|
35
|
-
|
36
|
-
s.require_path = 'lib'
|
37
|
-
|
38
|
-
# documentation
|
39
|
-
s.has_rdoc = false
|
40
|
-
|
41
|
-
# project information
|
42
|
-
s.homepage = 'http://github.com/datamapper/do'
|
43
|
-
s.rubyforge_project = 'dorb'
|
44
|
-
|
45
|
-
# author and contributors
|
46
|
-
s.author = 'Dirkjan Bussink'
|
47
|
-
s.email = 'd.bussink@gmail.com'
|
48
|
-
end
|
3
|
+
GEM_SPEC = eval(File.read('do_sqlite3.gemspec'))
|
49
4
|
|
50
5
|
gem_package = Gem::PackageTask.new(GEM_SPEC) do |pkg|
|
51
6
|
pkg.need_tar = false
|
52
7
|
pkg.need_zip = false
|
53
8
|
end
|
54
|
-
|
55
|
-
file "#{GEM_SPEC.name}.gemspec" => ['Rakefile', 'tasks/gem.rake'] do |t|
|
56
|
-
puts "Generating #{t.name}"
|
57
|
-
File.open(t.name, 'w') { |f| f.puts GEM_SPEC.to_yaml }
|
58
|
-
end
|
59
|
-
|
60
|
-
desc "Generate or update the standalone gemspec file for the project"
|
61
|
-
task :gemspec => ["#{GEM_SPEC.name}.gemspec"]
|
data/tasks/release.rake
CHANGED
@@ -8,7 +8,7 @@ end
|
|
8
8
|
if defined?(RubyForge) then
|
9
9
|
if defined?(GEM_SPEC) then
|
10
10
|
desc 'Package and upload to RubyForge'
|
11
|
-
task :release
|
11
|
+
task :release do |t|
|
12
12
|
ver = ENV['VERSION'] or fail "Must supply VERSION (rake release VERSION=x.y.z)."
|
13
13
|
|
14
14
|
# compare versions to avoid mistakes
|
@@ -26,19 +26,19 @@ if defined?(RubyForge) then
|
|
26
26
|
|
27
27
|
# read project info and overview
|
28
28
|
notes = begin
|
29
|
-
r = File.read("README.
|
30
|
-
r.split(/^(
|
29
|
+
r = File.read("README.markdown")
|
30
|
+
r.split(/^(.*\n\-+)/)[1..4].join.strip
|
31
31
|
rescue
|
32
|
-
warn "Missing README.
|
32
|
+
warn "Missing README.markdown"
|
33
33
|
''
|
34
34
|
end
|
35
35
|
|
36
36
|
# read changes
|
37
37
|
changes = begin
|
38
|
-
h = File.read("
|
39
|
-
h.split(/^(
|
38
|
+
h = File.read("HISTORY.markdown")
|
39
|
+
h.split(/^(##+ .*)/)[1..2].join.strip
|
40
40
|
rescue
|
41
|
-
warn "Missing
|
41
|
+
warn "Missing HISTORY.markdown"
|
42
42
|
''
|
43
43
|
end
|
44
44
|
|
data/tasks/retrieve.rake
CHANGED
@@ -36,7 +36,7 @@ begin
|
|
36
36
|
url = "http://www.sqlite.org/#{File.basename(t.name)}"
|
37
37
|
when_writing "downloading #{t.name}" do
|
38
38
|
cd File.dirname(t.name) do
|
39
|
-
system "wget -c #{url} || curl -C - -O #{url}"
|
39
|
+
system "wget -c #{url} || curl -L -C - -O #{url}"
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -46,7 +46,7 @@ begin
|
|
46
46
|
url = "http://www.sqlite.org/#{File.basename(t.name)}"
|
47
47
|
when_writing "downloading #{t.name}" do
|
48
48
|
cd File.dirname(t.name) do
|
49
|
-
system "wget -c #{url} || curl -C - -O #{url}"
|
49
|
+
system "wget -c #{url} || curl -L -C - -O #{url}"
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
data/tasks/spec.rake
CHANGED
@@ -5,6 +5,7 @@ desc 'Run specifications'
|
|
5
5
|
Spec::Rake::SpecTask.new(:spec => [ :clean, :compile ]) do |t|
|
6
6
|
t.spec_opts << '--options' << ROOT + 'spec/spec.opts'
|
7
7
|
t.spec_files = Pathname.glob(ENV['FILES'] || 'spec/**/*_spec.rb').map { |f| f.to_s }
|
8
|
+
t.libs << 'lib'
|
8
9
|
|
9
10
|
begin
|
10
11
|
# RCov is run by default, except on the JRuby platform
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: do_sqlite3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dirkjan Bussink
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-15 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ~>
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 2.0
|
23
|
+
version: "2.0"
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: extlib
|
@@ -40,7 +40,7 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - "="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0.
|
43
|
+
version: 0.10.0
|
44
44
|
version:
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
46
|
name: rspec
|
@@ -91,12 +91,13 @@ files:
|
|
91
91
|
- tasks/spec.rake
|
92
92
|
- ext/do_sqlite3_ext/extconf.rb
|
93
93
|
- ext/do_sqlite3_ext/do_sqlite3_ext.c
|
94
|
+
- ext/do_sqlite3_ext/error.h
|
94
95
|
- LICENSE
|
95
96
|
- Rakefile
|
96
|
-
-
|
97
|
+
- HISTORY.markdown
|
98
|
+
- README.markdown
|
97
99
|
- Manifest.txt
|
98
|
-
|
99
|
-
has_rdoc: true
|
100
|
+
has_rdoc: false
|
100
101
|
homepage: http://github.com/datamapper/do
|
101
102
|
licenses: []
|
102
103
|
|
@@ -120,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
121
|
requirements: []
|
121
122
|
|
122
123
|
rubyforge_project: dorb
|
123
|
-
rubygems_version: 1.3.
|
124
|
+
rubygems_version: 1.3.5
|
124
125
|
signing_key:
|
125
126
|
specification_version: 3
|
126
127
|
summary: DataObjects Sqlite3 Driver
|