do_sqlite3 0.9.9 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -37,5 +37,6 @@ end
37
37
  # Do the work
38
38
  # create_makefile(extension_name)
39
39
  if have_header( "sqlite3.h" ) && have_library( "sqlite3", "sqlite3_open" )
40
+ have_func("sqlite3_prepare_v2")
40
41
  create_makefile(extension_name)
41
42
  end
@@ -1,4 +1,3 @@
1
-
2
1
  # HACK: If running on Windows, then add the current directory to the PATH
3
2
  # for the current process so it can find the bundled dlls before the require
4
3
  # of the actual extension file.
@@ -9,5 +8,31 @@ end
9
8
 
10
9
  require 'rubygems'
11
10
  require 'data_objects'
12
- require 'do_sqlite3_ext'
13
- require 'do_sqlite3/transaction'
11
+ if RUBY_PLATFORM =~ /java/
12
+ require 'do_jdbc'
13
+ require 'java'
14
+ gem 'jdbc-sqlite3'
15
+ require 'jdbc/sqlite3' # the JDBC driver, packaged as a gem
16
+ end
17
+
18
+ require File.expand_path(File.join(File.dirname(__FILE__), 'do_sqlite3_ext'))
19
+ require File.expand_path(File.join(File.dirname(__FILE__), 'do_sqlite3', 'version'))
20
+ require File.expand_path(File.join(File.dirname(__FILE__), 'do_sqlite3', 'transaction'))
21
+
22
+ 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
+
28
+ module DataObjects
29
+ module Sqlite3
30
+ class Connection
31
+ def self.pool_size
32
+ 20
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ end
@@ -1,5 +1,5 @@
1
1
  module DataObjects
2
2
  module Sqlite3
3
- VERSION = "0.9.9"
3
+ VERSION = "0.9.10"
4
4
  end
5
5
  end
@@ -15,7 +15,11 @@ describe "DataObjects::Sqlite3::Result" do
15
15
  include Sqlite3SpecHelpers
16
16
 
17
17
  before(:all) do
18
- @connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db")
18
+ if JRUBY # note the sqlite not sqlite3!
19
+ @connection = DataObjects::Connection.new("jdbc:sqlite:test.db")
20
+ else
21
+ @connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db")
22
+ end
19
23
  end
20
24
 
21
25
  after :all do
@@ -24,13 +28,13 @@ describe "DataObjects::Sqlite3::Result" do
24
28
 
25
29
  it "should raise an error for a bad query" do
26
30
  command = @connection.create_command("INSER INTO table_which_doesnt_exist (id) VALUES (1)")
27
- lambda { command.execute_non_query }.should raise_error('near "INSER": syntax error')
31
+ lambda { command.execute_non_query }.should raise_error(Sqlite3Error, /near "INSER": syntax error/)
28
32
 
29
33
  command = @connection.create_command("INSERT INTO table_which_doesnt_exist (id) VALUES (1)")
30
- lambda { command.execute_non_query }.should raise_error("no such table: table_which_doesnt_exist")
34
+ lambda { command.execute_non_query }.should raise_error(Sqlite3Error, /no such table: table_which_doesnt_exist/)
31
35
 
32
36
  command = @connection.create_command("SELECT * FROM table_which_doesnt_exist")
33
- lambda { command.execute_reader }.should raise_error("no such table: table_which_doesnt_exist")
37
+ lambda { command.execute_reader }.should raise_error(Sqlite3Error, /no such table: table_which_doesnt_exist/)
34
38
  end
35
39
 
36
40
  it "should return the affected rows and insert_id" do
@@ -48,14 +52,14 @@ describe "DataObjects::Sqlite3::Result" do
48
52
  command = @connection.create_command("SELECT * FROM users")
49
53
  reader = command.execute_reader
50
54
 
51
- lambda { reader.values }.should raise_error
55
+ lambda { reader.values }.should raise_error(Sqlite3Error, /Reader is not initialized/)
52
56
 
53
57
  while ( reader.next! )
54
58
  lambda { reader.values }.should_not raise_error
55
59
  reader.values.should be_a_kind_of(Array)
56
60
  end
57
61
 
58
- lambda { reader.values }.should raise_error
62
+ lambda { reader.values }.should raise_error(Sqlite3Error, /Reader is not initialized/)
59
63
 
60
64
  reader.close
61
65
  end
@@ -69,7 +73,7 @@ describe "DataObjects::Sqlite3::Result" do
69
73
 
70
74
  reader.next!
71
75
 
72
- lambda { reader.values }.should raise_error
76
+ lambda { reader.values }.should raise_error(Sqlite3Error, /Reader is not initialized/)
73
77
 
74
78
  reader.close
75
79
  end
@@ -103,7 +107,7 @@ describe "DataObjects::Sqlite3::Result" do
103
107
  end
104
108
 
105
109
  it "should raise an error when you pass too many or too few types for the expected result set" do
106
- lambda { select("SELECT name, id FROM users", [String, Integer, String]) }.should raise_error(Sqlite3Error)
110
+ lambda { select("SELECT name, id FROM users", [String, Integer, String]) }.should raise_error(Sqlite3Error, /Field-count mismatch. Expected 3 fields, but the query yielded 2/)
107
111
  end
108
112
 
109
113
  it "should do a custom typecast reader with Class" do
@@ -4,7 +4,11 @@ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
4
4
  describe DataObjects::Sqlite3::Command do
5
5
 
6
6
  before(:each) do
7
- @connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db")
7
+ if JRUBY # note the sqlite not sqlite3!
8
+ @connection = DataObjects::Connection.new("jdbc:sqlite:test.db")
9
+ else
10
+ @connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db")
11
+ end
8
12
  end
9
13
 
10
14
  after(:each) do
@@ -17,7 +21,7 @@ describe DataObjects::Sqlite3::Command do
17
21
  command = @connection.create_command("SELECT * FROM users")
18
22
  @mock_logger = mock('MockLogger', :level => 0)
19
23
  DataObjects::Sqlite3.should_receive(:logger).and_return(@mock_logger)
20
- @mock_logger.should_receive(:debug).with("SELECT * FROM users")
24
+ @mock_logger.should_receive(:debug).with(/\([\d.]+\) SELECT \* FROM users/)
21
25
  command.execute_reader
22
26
  end
23
27
 
@@ -35,7 +39,7 @@ describe DataObjects::Sqlite3::Command do
35
39
  command = @connection.create_command("INSERT INTO users (name) VALUES (?)")
36
40
  @mock_logger = mock('MockLogger', :level => 0)
37
41
  DataObjects::Sqlite3.should_receive(:logger).and_return(@mock_logger)
38
- @mock_logger.should_receive(:debug).with("INSERT INTO users (name) VALUES ('Blah')")
42
+ @mock_logger.should_receive(:debug).with(/\([\d.]+\) INSERT INTO users \(name\) VALUES \('Blah'\)/)
39
43
  command.execute_non_query('Blah')
40
44
  end
41
45
 
@@ -4,7 +4,11 @@ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
4
4
  describe DataObjects::Sqlite3::Command do
5
5
 
6
6
  before(:each) do
7
- @connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db")
7
+ if JRUBY # NOTE the sqlite not sqlite3
8
+ @connection = DataObjects::Connection.new("jdbc:sqlite:test.db")
9
+ else
10
+ @connection = DataObjects::Connection.new("sqlite3://#{File.expand_path(File.dirname(__FILE__))}/test.db")
11
+ end
8
12
  @command = @connection.create_command("INSERT INTO users (name) VALUES (?)")
9
13
  end
10
14
 
@@ -1,4 +1,5 @@
1
1
  $TESTING=true
2
+ JRUBY = RUBY_PLATFORM =~ /java/
2
3
 
3
4
  require 'rubygems'
4
5
  require 'spec'
@@ -10,6 +11,11 @@ require 'pathname'
10
11
  $:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data_objects', 'lib'))
11
12
  require 'data_objects'
12
13
 
14
+ if JRUBY
15
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'do_jdbc', 'lib'))
16
+ require 'do_jdbc'
17
+ end
18
+
13
19
  # put the pre-compiled extension in the path to be found
14
20
  $:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
15
21
  require 'do_sqlite3'
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.9.9
4
+ version: 0.9.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernerd Schaefer
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-27 00:00:00 -08:00
12
+ date: 2009-01-04 00:00:00 +01: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: 0.9.9
23
+ version: 0.9.10
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: hoe
@@ -38,7 +38,7 @@ email:
38
38
  executables: []
39
39
 
40
40
  extensions:
41
- - ext/extconf.rb
41
+ - ext/do_sqlite3_ext/extconf.rb
42
42
  extra_rdoc_files:
43
43
  - History.txt
44
44
  - Manifest.txt
@@ -51,8 +51,11 @@ files:
51
51
  - README.txt
52
52
  - Rakefile
53
53
  - TODO
54
- - ext/do_sqlite3_ext.c
55
- - ext/extconf.rb
54
+ - buildfile
55
+ - ext-java/src/main/java/DoSqlite3ExtService.java
56
+ - ext-java/src/main/java/do_sqlite3/Sqlite3DriverDefinition.java
57
+ - ext/do_sqlite3_ext/do_sqlite3_ext.c
58
+ - ext/do_sqlite3_ext/extconf.rb
56
59
  - lib/do_sqlite3.rb
57
60
  - lib/do_sqlite3/transaction.rb
58
61
  - lib/do_sqlite3/version.rb
@@ -1,568 +0,0 @@
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
-
13
- #define RUBY_STRING(char_ptr) rb_str_new2(char_ptr)
14
- #define TAINTED_STRING(name) rb_tainted_str_new2(name)
15
- #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
16
- #define SQLITE3_CLASS(klass, parent) (rb_define_class_under(mSqlite3, klass, parent))
17
-
18
- #define TRUE_CLASS CONST_GET(rb_mKernel, "TrueClass")
19
-
20
- #ifndef RSTRING_PTR
21
- #define RSTRING_PTR(s) (RSTRING(s)->ptr)
22
- #endif
23
-
24
- #ifndef RSTRING_LEN
25
- #define RSTRING_LEN(s) (RSTRING(s)->len)
26
- #endif
27
-
28
- #ifndef RARRAY_LEN
29
- #define RARRAY_LEN(a) RARRAY(a)->len
30
- #endif
31
-
32
- #ifdef _WIN32
33
- #define do_int64 signed __int64
34
- #else
35
- #define do_int64 signed long long int
36
- #endif
37
-
38
- // To store rb_intern values
39
- static ID ID_NEW_DATE;
40
- static ID ID_LOGGER;
41
- static ID ID_DEBUG;
42
- static ID ID_LEVEL;
43
-
44
- static VALUE mDO;
45
- static VALUE cDO_Quoting;
46
- static VALUE cDO_Connection;
47
- static VALUE cDO_Command;
48
- static VALUE cDO_Result;
49
- static VALUE cDO_Reader;
50
-
51
- static VALUE rb_cDate;
52
- static VALUE rb_cDateTime;
53
-
54
- #ifndef RUBY_19_COMPATIBILITY
55
- static VALUE rb_cRational;
56
- #endif
57
-
58
- static VALUE rb_cBigDecimal;
59
-
60
- static VALUE mSqlite3;
61
- static VALUE cConnection;
62
- static VALUE cCommand;
63
- static VALUE cResult;
64
- static VALUE cReader;
65
-
66
- static VALUE eSqlite3Error;
67
-
68
-
69
- /****** Typecasting ******/
70
- static VALUE native_typecast(sqlite3_value *value, int type) {
71
- VALUE ruby_value = Qnil;
72
-
73
- switch(type) {
74
- case SQLITE_NULL: {
75
- ruby_value = Qnil;
76
- break;
77
- }
78
- case SQLITE_INTEGER: {
79
- ruby_value = LL2NUM(sqlite3_value_int64(value));
80
- break;
81
- }
82
- case SQLITE3_TEXT: {
83
- ruby_value = rb_str_new2((char*)sqlite3_value_text(value));
84
- break;
85
- }
86
- case SQLITE_FLOAT: {
87
- ruby_value = rb_float_new(sqlite3_value_double(value));
88
- break;
89
- }
90
- }
91
- return ruby_value;
92
- }
93
-
94
- // Find the greatest common denominator and reduce the provided numerator and denominator.
95
- // This replaces calles to Rational.reduce! which does the same thing, but really slowly.
96
- static void reduce( do_int64 *numerator, do_int64 *denominator ) {
97
- do_int64 a, b, c = 0;
98
- a = *numerator;
99
- b = *denominator;
100
- while ( a != 0 ) {
101
- c = a; a = b % a; b = c;
102
- }
103
- *numerator = *numerator / b;
104
- *denominator = *denominator / b;
105
- }
106
-
107
- // Generate the date integer which Date.civil_to_jd returns
108
- static int jd_from_date(int year, int month, int day) {
109
- int a, b;
110
- if ( month <= 2 ) {
111
- year -= 1;
112
- month += 12;
113
- }
114
- a = year / 100;
115
- b = 2 - a + (a / 4);
116
- return floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524;
117
- }
118
-
119
- static void data_objects_debug(VALUE string) {
120
- VALUE logger = rb_funcall(mSqlite3, ID_LOGGER, 0);
121
- int log_level = NUM2INT(rb_funcall(logger, ID_LEVEL, 0));
122
-
123
- if (0 == log_level) {
124
- rb_funcall(logger, ID_DEBUG, 1, string);
125
- }
126
- }
127
-
128
- static VALUE parse_date(char *date) {
129
- int year, month, day;
130
- int jd, ajd;
131
- VALUE rational;
132
-
133
- sscanf(date, "%4d-%2d-%2d", &year, &month, &day);
134
-
135
- jd = jd_from_date(year, month, day);
136
-
137
- // Math from Date.jd_to_ajd
138
- ajd = jd * 2 - 1;
139
- rational = rb_funcall(rb_cRational, rb_intern("new!"), 2, INT2NUM(ajd), INT2NUM(2));
140
- return rb_funcall(rb_cDate, ID_NEW_DATE, 3, rational, INT2NUM(0), INT2NUM(2299161));
141
- }
142
-
143
- // Creates a Rational for use as a Timezone offset to be passed to DateTime.new!
144
- static VALUE seconds_to_offset(do_int64 num) {
145
- do_int64 den = 86400;
146
- reduce(&num, &den);
147
- return rb_funcall(rb_cRational, rb_intern("new!"), 2, rb_ll2inum(num), rb_ll2inum(den));
148
- }
149
-
150
- static VALUE timezone_to_offset(int hour_offset, int minute_offset) {
151
- do_int64 seconds = 0;
152
-
153
- seconds += hour_offset * 3600;
154
- seconds += minute_offset * 60;
155
-
156
- return seconds_to_offset(seconds);
157
- }
158
-
159
- static VALUE parse_date_time(char *date) {
160
- VALUE ajd, offset;
161
-
162
- int year, month, day, hour, min, sec, usec, hour_offset, minute_offset;
163
- int jd;
164
- do_int64 num, den;
165
-
166
- long int gmt_offset;
167
- int is_dst;
168
-
169
- time_t rawtime;
170
- struct tm * timeinfo;
171
-
172
- int tokens_read, max_tokens;
173
-
174
- if ( strcmp(date, "") == 0 ) {
175
- return Qnil;
176
- }
177
-
178
- if (0 != strchr(date, '.')) {
179
- // This is a datetime with sub-second precision
180
- 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);
181
- max_tokens = 9;
182
- } else {
183
- // This is a datetime second precision
184
- tokens_read = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset);
185
- max_tokens = 8;
186
- }
187
-
188
- if (max_tokens == tokens_read) {
189
- // We read the Date, Time, and Timezone info
190
- minute_offset *= hour_offset < 0 ? -1 : 1;
191
- } else if ((max_tokens - 1) == tokens_read) {
192
- // We read the Date and Time, but no Minute Offset
193
- minute_offset = 0;
194
- } else if (tokens_read == 3) {
195
- return parse_date(date);
196
- } else if (tokens_read >= (max_tokens - 3)) {
197
- // We read the Date and Time, default to the current locale's offset
198
-
199
- // Get localtime
200
- time(&rawtime);
201
- timeinfo = localtime(&rawtime);
202
-
203
- is_dst = timeinfo->tm_isdst * 3600;
204
-
205
- // Reset to GM Time
206
- timeinfo = gmtime(&rawtime);
207
-
208
- gmt_offset = mktime(timeinfo) - rawtime;
209
-
210
- if ( is_dst > 0 )
211
- gmt_offset -= is_dst;
212
-
213
- hour_offset = -(gmt_offset / 3600);
214
- minute_offset = -(gmt_offset % 3600 / 60);
215
-
216
- } else {
217
- // Something went terribly wrong
218
- rb_raise(eSqlite3Error, "Couldn't parse date: %s", date);
219
- }
220
-
221
- jd = jd_from_date(year, month, day);
222
-
223
- // Generate ajd with fractional days for the time
224
- // Extracted from Date#jd_to_ajd, Date#day_fraction_to_time, and Rational#+ and #-
225
- num = (hour * 1440) + (min * 24);
226
-
227
- // Modify the numerator so when we apply the timezone everything works out
228
- num -= (hour_offset * 1440) + (minute_offset * 24);
229
-
230
- den = (24 * 1440);
231
- reduce(&num, &den);
232
-
233
- num = (num * 86400) + (sec * den);
234
- den = den * 86400;
235
- reduce(&num, &den);
236
-
237
- num = (jd * den) + num;
238
-
239
- num = num * 2;
240
- num = num - den;
241
- den = den * 2;
242
-
243
- reduce(&num, &den);
244
-
245
- ajd = rb_funcall(rb_cRational, rb_intern("new!"), 2, rb_ull2inum(num), rb_ull2inum(den));
246
- offset = timezone_to_offset(hour_offset, minute_offset);
247
-
248
- return rb_funcall(rb_cDateTime, ID_NEW_DATE, 3, ajd, offset, INT2NUM(2299161));
249
- }
250
-
251
- static VALUE parse_time(char *date) {
252
-
253
- int year, month, day, hour, min, sec, usec;
254
- char subsec[7];
255
-
256
- if (0 != strchr(date, '.')) {
257
- // right padding usec with 0. e.g. '012' will become 12000 microsecond, since Time#local use microsecond
258
- sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d.%s", &year, &month, &day, &hour, &min, &sec, subsec);
259
- sscanf(subsec, "%d", &usec);
260
- } else {
261
- sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
262
- usec = 0;
263
- }
264
-
265
- return rb_funcall(rb_cTime, rb_intern("local"), 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
266
- }
267
-
268
- static VALUE ruby_typecast(sqlite3_value *value, char *type, int original_type) {
269
- VALUE ruby_value = Qnil;
270
-
271
- if ( original_type == SQLITE_NULL ) {
272
- return ruby_value;
273
- } else if ( strcmp(type, "Class") == 0) {
274
- ruby_value = rb_funcall(mDO, rb_intern("find_const"), 1, TAINTED_STRING((char*)sqlite3_value_text(value)));
275
- } else if ( strcmp(type, "Object") == 0 ) {
276
- ruby_value = rb_marshal_load(rb_str_new2((char*)sqlite3_value_text(value)));
277
- } else if ( strcmp(type, "TrueClass") == 0 ) {
278
- ruby_value = strcmp((char*)sqlite3_value_text(value), "t") == 0 ? Qtrue : Qfalse;
279
- } else if ( strcmp(type, "Integer") == 0 || strcmp(type, "Fixnum") == 0 || strcmp(type, "Bignum") == 0 ) {
280
- ruby_value = LL2NUM(sqlite3_value_int64(value));
281
- } else if ( strcmp(type, "BigDecimal") == 0 ) {
282
- ruby_value = rb_funcall(rb_cBigDecimal, ID_NEW, 1, TAINTED_STRING((char*)sqlite3_value_text(value)));
283
- } else if ( strcmp(type, "String") == 0 ) {
284
- ruby_value = TAINTED_STRING((char*)sqlite3_value_text(value));
285
- } else if ( strcmp(type, "Float") == 0 ) {
286
- ruby_value = rb_float_new(sqlite3_value_double(value));
287
- } else if ( strcmp(type, "Date") == 0 ) {
288
- ruby_value = parse_date((char*)sqlite3_value_text(value));
289
- } else if ( strcmp(type, "DateTime") == 0 ) {
290
- ruby_value = parse_date_time((char*)sqlite3_value_text(value));
291
- } else if ( strcmp(type, "Time") == 0 ) {
292
- ruby_value = parse_time((char*)sqlite3_value_text(value));
293
- }
294
-
295
- return ruby_value;
296
- }
297
-
298
-
299
- /****** Public API ******/
300
-
301
- static VALUE cConnection_initialize(VALUE self, VALUE uri) {
302
- int ret;
303
- VALUE path;
304
- sqlite3 *db;
305
-
306
- path = rb_funcall(uri, ID_PATH, 0);
307
- ret = sqlite3_open(StringValuePtr(path), &db);
308
-
309
- if ( ret != SQLITE_OK ) {
310
- rb_raise(eSqlite3Error, sqlite3_errmsg(db));
311
- }
312
-
313
- rb_iv_set(self, "@uri", uri);
314
- rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
315
-
316
- return Qtrue;
317
- }
318
-
319
- static VALUE cConnection_dispose(VALUE self) {
320
- sqlite3 *db;
321
- Data_Get_Struct(rb_iv_get(self, "@connection"), sqlite3, db);
322
- sqlite3_close(db);
323
- return Qtrue;
324
- }
325
-
326
- static VALUE cCommand_set_types(VALUE self, VALUE array) {
327
- rb_iv_set(self, "@field_types", array);
328
- return array;
329
- }
330
-
331
- static VALUE cCommand_quote_boolean(VALUE self, VALUE value) {
332
- return TAINTED_STRING(value == Qtrue ? "'t'" : "'f'");
333
- }
334
-
335
- static VALUE cCommand_quote_string(VALUE self, VALUE string) {
336
- const char *source = StringValuePtr(string);
337
- char *escaped_with_quotes;
338
-
339
- // Wrap the escaped string in single-quotes, this is DO's convention
340
- escaped_with_quotes = sqlite3_mprintf("%Q", source);
341
-
342
- return TAINTED_STRING(escaped_with_quotes);
343
- }
344
-
345
- static VALUE build_query_from_args(VALUE klass, int count, VALUE *args) {
346
- VALUE query = rb_iv_get(klass, "@text");
347
- if ( count > 0 ) {
348
- int i;
349
- VALUE array = rb_ary_new();
350
- for ( i = 0; i < count; i++) {
351
- rb_ary_push(array, (VALUE)args[i]);
352
- }
353
- query = rb_funcall(klass, ID_ESCAPE, 1, array);
354
- }
355
- return query;
356
- }
357
-
358
- static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
359
- sqlite3 *db;
360
- char *error_message;
361
- int status;
362
- int affected_rows;
363
- int insert_id;
364
- VALUE conn_obj;
365
- VALUE query;
366
-
367
- query = build_query_from_args(self, argc, argv);
368
- data_objects_debug(query);
369
-
370
- conn_obj = rb_iv_get(self, "@connection");
371
- Data_Get_Struct(rb_iv_get(conn_obj, "@connection"), sqlite3, db);
372
-
373
- status = sqlite3_exec(db, StringValuePtr(query), 0, 0, &error_message);
374
-
375
- if ( status != SQLITE_OK ) {
376
- rb_raise(eSqlite3Error, sqlite3_errmsg(db));
377
- }
378
-
379
- affected_rows = sqlite3_changes(db);
380
- insert_id = sqlite3_last_insert_rowid(db);
381
-
382
- return rb_funcall(cResult, ID_NEW, 3, self, INT2NUM(affected_rows), INT2NUM(insert_id));
383
- }
384
-
385
- static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
386
- sqlite3 *db;
387
- sqlite3_stmt *sqlite3_reader;
388
- int status;
389
- int field_count;
390
- int i;
391
- VALUE reader;
392
- VALUE conn_obj;
393
- VALUE query;
394
- VALUE field_names, field_types;
395
-
396
- conn_obj = rb_iv_get(self, "@connection");
397
- Data_Get_Struct(rb_iv_get(conn_obj, "@connection"), sqlite3, db);
398
-
399
- query = build_query_from_args(self, argc, argv);
400
-
401
- data_objects_debug(query);
402
-
403
- status = sqlite3_prepare_v2(db, StringValuePtr(query), -1, &sqlite3_reader, 0);
404
-
405
- if ( status != SQLITE_OK ) {
406
- rb_raise(eSqlite3Error, sqlite3_errmsg(db));
407
- }
408
-
409
- field_count = sqlite3_column_count(sqlite3_reader);
410
-
411
- reader = rb_funcall(cReader, ID_NEW, 0);
412
- rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, sqlite3_reader));
413
- rb_iv_set(reader, "@field_count", INT2NUM(field_count));
414
-
415
- field_names = rb_ary_new();
416
- field_types = rb_iv_get(self, "@field_types");
417
-
418
- // if ( field_types == Qnil ) {
419
- // field_types = rb_ary_new();
420
- // }
421
-
422
- if ( field_types == Qnil || 0 == RARRAY_LEN(field_types) ) {
423
- field_types = rb_ary_new();
424
- } else if (RARRAY_LEN(field_types) != field_count) {
425
- // Whoops... wrong number of types passed to set_types. Close the reader and raise
426
- // and error
427
- rb_funcall(reader, rb_intern("close"), 0);
428
- rb_raise(eSqlite3Error, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
429
- }
430
-
431
-
432
-
433
- for ( i = 0; i < field_count; i++ ) {
434
- rb_ary_push(field_names, rb_str_new2((char *)sqlite3_column_name(sqlite3_reader, i)));
435
- }
436
-
437
- rb_iv_set(reader, "@fields", field_names);
438
- rb_iv_set(reader, "@field_types", field_types);
439
-
440
- return reader;
441
- }
442
-
443
- static VALUE cReader_close(VALUE self) {
444
- VALUE reader_obj = rb_iv_get(self, "@reader");
445
-
446
- if ( reader_obj != Qnil ) {
447
- sqlite3_stmt *reader;
448
- Data_Get_Struct(reader_obj, sqlite3_stmt, reader);
449
- sqlite3_finalize(reader);
450
- rb_iv_set(self, "@reader", Qnil);
451
- return Qtrue;
452
- }
453
- else {
454
- return Qfalse;
455
- }
456
- }
457
-
458
- static VALUE cReader_next(VALUE self) {
459
- sqlite3_stmt *reader;
460
- int field_count;
461
- int result;
462
- int i;
463
- int ft_length;
464
- VALUE arr = rb_ary_new();
465
- VALUE field_types;
466
- VALUE value;
467
-
468
- Data_Get_Struct(rb_iv_get(self, "@reader"), sqlite3_stmt, reader);
469
- field_count = NUM2INT(rb_iv_get(self, "@field_count"));
470
-
471
- field_types = rb_iv_get(self, "@field_types");
472
- ft_length = RARRAY_LEN(field_types);
473
-
474
- result = sqlite3_step(reader);
475
-
476
- rb_iv_set(self, "@state", INT2NUM(result));
477
-
478
- if ( result != SQLITE_ROW ) {
479
- return Qnil;
480
- }
481
-
482
- for ( i = 0; i < field_count; i++ ) {
483
- if ( ft_length == 0 ) {
484
- value = native_typecast(sqlite3_column_value(reader, i), sqlite3_column_type(reader, i));
485
- }
486
- else {
487
- value = ruby_typecast(sqlite3_column_value(reader, i), rb_class2name(RARRAY_PTR(field_types)[i]), sqlite3_column_type(reader, i));
488
- }
489
- rb_ary_push(arr, value);
490
- }
491
-
492
- rb_iv_set(self, "@values", arr);
493
-
494
- return Qtrue;
495
- }
496
-
497
- static VALUE cReader_values(VALUE self) {
498
- VALUE state = rb_iv_get(self, "@state");
499
- if ( state == Qnil || NUM2INT(state) != SQLITE_ROW ) {
500
- rb_raise(eSqlite3Error, "Reader is not initialized");
501
- }
502
- else {
503
- return rb_iv_get(self, "@values");
504
- }
505
- }
506
-
507
- static VALUE cReader_fields(VALUE self) {
508
- return rb_iv_get(self, "@fields");
509
- }
510
-
511
- void Init_do_sqlite3_ext() {
512
-
513
- rb_require("rubygems");
514
- rb_require("bigdecimal");
515
- rb_require("date");
516
-
517
- // Get references classes needed for Date/Time parsing
518
- rb_cDate = CONST_GET(rb_mKernel, "Date");
519
- rb_cDateTime = CONST_GET(rb_mKernel, "DateTime");
520
- rb_cTime = CONST_GET(rb_mKernel, "Time");
521
- rb_cRational = CONST_GET(rb_mKernel, "Rational");
522
- rb_cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
523
-
524
- rb_funcall(rb_mKernel, rb_intern("require"), 1, rb_str_new2("data_objects"));
525
-
526
- #ifdef RUBY_LESS_THAN_186
527
- ID_NEW_DATE = rb_intern("new0");
528
- #else
529
- ID_NEW_DATE = rb_intern("new!");
530
- #endif
531
- ID_LOGGER = rb_intern("logger");
532
- ID_DEBUG = rb_intern("debug");
533
- ID_LEVEL = rb_intern("level");
534
-
535
- // Get references to the DataObjects module and its classes
536
- mDO = CONST_GET(rb_mKernel, "DataObjects");
537
- cDO_Quoting = CONST_GET(mDO, "Quoting");
538
- cDO_Connection = CONST_GET(mDO, "Connection");
539
- cDO_Command = CONST_GET(mDO, "Command");
540
- cDO_Result = CONST_GET(mDO, "Result");
541
- cDO_Reader = CONST_GET(mDO, "Reader");
542
-
543
- // Initialize the DataObjects::Sqlite3 module, and define its classes
544
- mSqlite3 = rb_define_module_under(mDO, "Sqlite3");
545
-
546
- eSqlite3Error = rb_define_class("Sqlite3Error", rb_eStandardError);
547
-
548
- cConnection = SQLITE3_CLASS("Connection", cDO_Connection);
549
- rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
550
- rb_define_method(cConnection, "dispose", cConnection_dispose, 0);
551
-
552
- cCommand = SQLITE3_CLASS("Command", cDO_Command);
553
- rb_include_module(cCommand, cDO_Quoting);
554
- rb_define_method(cCommand, "set_types", cCommand_set_types, 1);
555
- rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
556
- rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
557
- rb_define_method(cCommand, "quote_boolean", cCommand_quote_boolean, 1);
558
- rb_define_method(cCommand, "quote_string", cCommand_quote_string, 1);
559
-
560
- cResult = SQLITE3_CLASS("Result", cDO_Result);
561
-
562
- cReader = SQLITE3_CLASS("Reader", cDO_Reader);
563
- rb_define_method(cReader, "close", cReader_close, 0);
564
- rb_define_method(cReader, "next!", cReader_next, 0);
565
- rb_define_method(cReader, "values", cReader_values, 0);
566
- rb_define_method(cReader, "fields", cReader_fields, 0);
567
-
568
- }