do_sqlite3 0.9.9 → 0.9.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
- }