do_sqlite3 0.10.3-x86-mswin32-60 → 0.10.4.rc1-x86-mswin32-60
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.
- data/LICENSE +1 -1
- data/README.markdown +2 -9
- data/Rakefile +12 -45
- data/ext/do_sqlite3/do_common.c +526 -0
- data/ext/do_sqlite3/do_common.h +170 -0
- data/ext/do_sqlite3/do_sqlite3.c +171 -537
- data/ext/do_sqlite3/do_sqlite3.h +3 -49
- data/ext/do_sqlite3/do_sqlite3_extension.c +28 -29
- data/ext/do_sqlite3/error.h +30 -56
- data/lib/do_sqlite3.rb +8 -3
- data/lib/do_sqlite3/1.8/do_sqlite3.so +0 -0
- data/lib/do_sqlite3/1.9/do_sqlite3.so +0 -0
- data/lib/do_sqlite3/version.rb +1 -1
- data/spec/command_spec.rb +2 -2
- data/spec/connection_spec.rb +9 -9
- data/spec/encoding_spec.rb +3 -3
- data/spec/error/sql_error_spec.rb +2 -2
- data/spec/reader_spec.rb +2 -2
- data/spec/result_spec.rb +4 -4
- data/spec/spec_helper.rb +14 -11
- data/spec/typecast/array_spec.rb +2 -2
- data/spec/typecast/bigdecimal_spec.rb +2 -2
- data/spec/typecast/boolean_spec.rb +2 -2
- data/spec/typecast/byte_array_spec.rb +2 -2
- data/spec/typecast/class_spec.rb +2 -2
- data/spec/typecast/date_spec.rb +2 -2
- data/spec/typecast/datetime_spec.rb +2 -2
- data/spec/typecast/float_spec.rb +3 -3
- data/spec/typecast/integer_spec.rb +2 -2
- data/spec/typecast/nil_spec.rb +5 -5
- data/spec/typecast/other_spec.rb +2 -2
- data/spec/typecast/range_spec.rb +2 -2
- data/spec/typecast/string_spec.rb +2 -2
- data/spec/typecast/time_spec.rb +2 -2
- data/tasks/compile.rake +28 -29
- data/tasks/spec.rake +8 -19
- metadata +50 -47
@@ -0,0 +1,170 @@
|
|
1
|
+
#ifndef _DO_COMMON_H_
|
2
|
+
#define _DO_COMMON_H_
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
|
6
|
+
#ifdef _WIN32
|
7
|
+
#define cCommand_execute cCommand_execute_sync
|
8
|
+
typedef signed __int64 do_int64;
|
9
|
+
#else
|
10
|
+
#define cCommand_execute cCommand_execute_async
|
11
|
+
typedef signed long long int do_int64;
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
15
|
+
#include <ruby/encoding.h>
|
16
|
+
|
17
|
+
#define DO_STR_NEW2(str, encoding, internal_encoding) \
|
18
|
+
({ \
|
19
|
+
VALUE _string = rb_str_new2((const char *)str); \
|
20
|
+
if(encoding != -1) { \
|
21
|
+
rb_enc_associate_index(_string, encoding); \
|
22
|
+
} \
|
23
|
+
if(internal_encoding) { \
|
24
|
+
_string = rb_str_export_to_enc(_string, internal_encoding); \
|
25
|
+
} \
|
26
|
+
_string; \
|
27
|
+
})
|
28
|
+
|
29
|
+
#define DO_STR_NEW(str, len, encoding, internal_encoding) \
|
30
|
+
({ \
|
31
|
+
VALUE _string = rb_str_new((const char *)str, (long)len); \
|
32
|
+
if(encoding != -1) { \
|
33
|
+
rb_enc_associate_index(_string, encoding); \
|
34
|
+
} \
|
35
|
+
if(internal_encoding) { \
|
36
|
+
_string = rb_str_export_to_enc(_string, internal_encoding); \
|
37
|
+
} \
|
38
|
+
_string; \
|
39
|
+
})
|
40
|
+
|
41
|
+
# else
|
42
|
+
|
43
|
+
#define DO_STR_NEW2(str, encoding, internal_encoding) \
|
44
|
+
rb_str_new2((const char *)str)
|
45
|
+
|
46
|
+
#define DO_STR_NEW(str, len, encoding, internal_encoding) \
|
47
|
+
rb_str_new((const char *)str, (long)len)
|
48
|
+
#endif
|
49
|
+
|
50
|
+
// Needed for defining error.h
|
51
|
+
struct errcodes {
|
52
|
+
int error_no;
|
53
|
+
const char *error_name;
|
54
|
+
const char *exception;
|
55
|
+
};
|
56
|
+
|
57
|
+
#define ERRCODE(name,message) {name, #name, message}
|
58
|
+
|
59
|
+
// To store rb_intern values
|
60
|
+
extern ID ID_NEW;
|
61
|
+
extern ID ID_NEW_DATE;
|
62
|
+
extern ID ID_CONST_GET;
|
63
|
+
extern ID ID_RATIONAL;
|
64
|
+
extern ID ID_ESCAPE;
|
65
|
+
extern ID ID_STRFTIME;
|
66
|
+
extern ID ID_LOG;
|
67
|
+
|
68
|
+
// Reference to Extlib module
|
69
|
+
extern VALUE mExtlib;
|
70
|
+
extern VALUE rb_cByteArray;
|
71
|
+
|
72
|
+
// References to DataObjects base classes
|
73
|
+
extern VALUE mDO;
|
74
|
+
extern VALUE mEncoding;
|
75
|
+
extern VALUE cDO_Quoting;
|
76
|
+
extern VALUE cDO_Connection;
|
77
|
+
extern VALUE cDO_Command;
|
78
|
+
extern VALUE cDO_Result;
|
79
|
+
extern VALUE cDO_Reader;
|
80
|
+
extern VALUE cDO_Logger;
|
81
|
+
extern VALUE cDO_Logger_Message;
|
82
|
+
extern VALUE cDO_Extension;
|
83
|
+
extern VALUE eConnectionError;
|
84
|
+
extern VALUE eDataError;
|
85
|
+
|
86
|
+
// References to Ruby classes that we'll need
|
87
|
+
extern VALUE rb_cDate;
|
88
|
+
extern VALUE rb_cDateTime;
|
89
|
+
extern VALUE rb_cBigDecimal;
|
90
|
+
|
91
|
+
extern void data_objects_debug(VALUE connection, VALUE string, struct timeval *start);
|
92
|
+
extern char *get_uri_option(VALUE query_hash, const char *key);
|
93
|
+
extern void assert_file_exists(char *file, const char *message);
|
94
|
+
extern VALUE build_query_from_args(VALUE klass, int count, VALUE *args);
|
95
|
+
|
96
|
+
extern void reduce(do_int64 *numerator, do_int64 *denominator);
|
97
|
+
extern int jd_from_date(int year, int month, int day);
|
98
|
+
extern VALUE seconds_to_offset(long seconds_offset);
|
99
|
+
extern VALUE timezone_to_offset(int hour_offset, int minute_offset);
|
100
|
+
|
101
|
+
extern VALUE parse_date(const char *date);
|
102
|
+
extern VALUE parse_time(const char *date);
|
103
|
+
extern VALUE parse_date_time(const char *date);
|
104
|
+
|
105
|
+
extern VALUE cConnection_character_set(VALUE self);
|
106
|
+
extern VALUE cConnection_is_using_socket(VALUE self);
|
107
|
+
extern VALUE cConnection_ssl_cipher(VALUE self);
|
108
|
+
extern VALUE cConnection_quote_time(VALUE self, VALUE value);
|
109
|
+
extern VALUE cConnection_quote_date_time(VALUE self, VALUE value);
|
110
|
+
extern VALUE cConnection_quote_date(VALUE self, VALUE value);
|
111
|
+
|
112
|
+
extern VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self);
|
113
|
+
|
114
|
+
extern VALUE cReader_values(VALUE self);
|
115
|
+
extern VALUE cReader_fields(VALUE self);
|
116
|
+
extern VALUE cReader_field_count(VALUE self);
|
117
|
+
|
118
|
+
extern void common_init(void);
|
119
|
+
|
120
|
+
static inline VALUE do_const_get(VALUE scope, const char *constant) {
|
121
|
+
return rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant));
|
122
|
+
}
|
123
|
+
|
124
|
+
static inline VALUE do_str_new(const void *string, long length, int encoding, void *internal_encoding) {
|
125
|
+
VALUE new_string = rb_str_new(string, length);
|
126
|
+
|
127
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
128
|
+
if(encoding != -1) {
|
129
|
+
rb_enc_associate_index(new_string, encoding);
|
130
|
+
}
|
131
|
+
|
132
|
+
if(internal_encoding) {
|
133
|
+
new_string = rb_str_export_to_enc(new_string, internal_encoding);
|
134
|
+
}
|
135
|
+
#endif
|
136
|
+
|
137
|
+
return new_string;
|
138
|
+
}
|
139
|
+
|
140
|
+
static inline VALUE do_str_new2(const void *string, int encoding, void *internal_encoding) {
|
141
|
+
VALUE new_string = rb_str_new2(string);
|
142
|
+
|
143
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
144
|
+
if(encoding != -1) {
|
145
|
+
rb_enc_associate_index(new_string, encoding);
|
146
|
+
}
|
147
|
+
|
148
|
+
if(internal_encoding) {
|
149
|
+
new_string = rb_str_export_to_enc(new_string, internal_encoding);
|
150
|
+
}
|
151
|
+
#endif
|
152
|
+
|
153
|
+
return new_string;
|
154
|
+
}
|
155
|
+
|
156
|
+
static inline void do_define_errors(VALUE scope, const struct errcodes *errors) {
|
157
|
+
const struct errcodes *e;
|
158
|
+
|
159
|
+
for (e = errors; e->error_name; e++) {
|
160
|
+
rb_const_set(scope, rb_intern(e->error_name), INT2NUM(e->error_no));
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
extern void do_raise_error(VALUE self, const struct errcodes *errors, int errnum, const char *message, VALUE query, VALUE state);
|
165
|
+
|
166
|
+
extern VALUE do_typecast(const char *value, long length, const VALUE type, int encoding);
|
167
|
+
|
168
|
+
#define RSTRING_NOT_MODIFIED
|
169
|
+
|
170
|
+
#endif
|
data/ext/do_sqlite3/do_sqlite3.c
CHANGED
@@ -1,343 +1,96 @@
|
|
1
1
|
#include "do_sqlite3.h"
|
2
2
|
#include "error.h"
|
3
|
-
// To store rb_intern values
|
4
|
-
|
5
|
-
static ID ID_NEW;
|
6
|
-
static ID ID_NEW_DATE;
|
7
|
-
static ID ID_CONST_GET;
|
8
|
-
static ID ID_RATIONAL;
|
9
|
-
static ID ID_ESCAPE;
|
10
|
-
static ID ID_LOG;
|
11
|
-
|
12
|
-
static VALUE mExtlib;
|
13
|
-
|
14
|
-
static VALUE mDO;
|
15
|
-
static VALUE cDO_Quoting;
|
16
|
-
static VALUE cDO_Connection;
|
17
|
-
static VALUE cDO_Command;
|
18
|
-
static VALUE cDO_Result;
|
19
|
-
static VALUE cDO_Reader;
|
20
|
-
static VALUE cDO_Logger;
|
21
|
-
static VALUE cDO_Logger_Message;
|
22
|
-
|
23
|
-
static VALUE rb_cDate;
|
24
|
-
static VALUE rb_cDateTime;
|
25
|
-
static VALUE rb_cBigDecimal;
|
26
|
-
static VALUE rb_cByteArray;
|
27
|
-
|
28
|
-
static VALUE mSqlite3;
|
29
|
-
static VALUE cConnection;
|
30
|
-
static VALUE cCommand;
|
31
|
-
static VALUE cResult;
|
32
|
-
static VALUE cReader;
|
33
|
-
static VALUE eConnectionError;
|
34
|
-
static VALUE eDataError;
|
35
|
-
|
36
|
-
static VALUE OPEN_FLAG_READONLY;
|
37
|
-
static VALUE OPEN_FLAG_READWRITE;
|
38
|
-
static VALUE OPEN_FLAG_CREATE;
|
39
|
-
static VALUE OPEN_FLAG_NO_MUTEX;
|
40
|
-
static VALUE OPEN_FLAG_FULL_MUTEX;
|
41
|
-
|
42
|
-
// Find the greatest common denominator and reduce the provided numerator and denominator.
|
43
|
-
// This replaces calles to Rational.reduce! which does the same thing, but really slowly.
|
44
|
-
static void reduce( do_int64 *numerator, do_int64 *denominator ) {
|
45
|
-
do_int64 a, b, c = 0;
|
46
|
-
a = *numerator;
|
47
|
-
b = *denominator;
|
48
|
-
while ( a != 0 ) {
|
49
|
-
c = a; a = b % a; b = c;
|
50
|
-
}
|
51
|
-
*numerator = *numerator / b;
|
52
|
-
*denominator = *denominator / b;
|
53
|
-
}
|
54
|
-
|
55
|
-
// Generate the date integer which Date.civil_to_jd returns
|
56
|
-
static int jd_from_date(int year, int month, int day) {
|
57
|
-
int a, b;
|
58
|
-
if ( month <= 2 ) {
|
59
|
-
year -= 1;
|
60
|
-
month += 12;
|
61
|
-
}
|
62
|
-
a = year / 100;
|
63
|
-
b = 2 - a + (a / 4);
|
64
|
-
return (int) (floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524);
|
65
|
-
}
|
66
|
-
|
67
|
-
static void data_objects_debug(VALUE connection, VALUE string, struct timeval* start) {
|
68
|
-
struct timeval stop;
|
69
|
-
VALUE message;
|
70
3
|
|
71
|
-
|
72
|
-
do_int64 duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec;
|
4
|
+
#include "do_common.h"
|
73
5
|
|
74
|
-
|
6
|
+
VALUE mSqlite3;
|
7
|
+
VALUE cConnection;
|
8
|
+
VALUE cCommand;
|
9
|
+
VALUE cResult;
|
10
|
+
VALUE cReader;
|
75
11
|
|
76
|
-
|
77
|
-
|
12
|
+
VALUE OPEN_FLAG_READONLY;
|
13
|
+
VALUE OPEN_FLAG_READWRITE;
|
14
|
+
VALUE OPEN_FLAG_CREATE;
|
15
|
+
VALUE OPEN_FLAG_NO_MUTEX;
|
16
|
+
VALUE OPEN_FLAG_FULL_MUTEX;
|
78
17
|
|
79
|
-
|
80
|
-
|
18
|
+
void raise_error(VALUE self, sqlite3 *result, VALUE query) {
|
19
|
+
int errnum = sqlite3_errcode(result);
|
81
20
|
const char *message = sqlite3_errmsg(result);
|
82
|
-
|
83
|
-
int sqlite3_errno = sqlite3_errcode(result);
|
84
|
-
|
85
|
-
struct errcodes *errs;
|
86
|
-
|
87
|
-
for (errs = errors; errs->error_name; errs++) {
|
88
|
-
if(errs->error_no == sqlite3_errno) {
|
89
|
-
exception_type = errs->exception;
|
90
|
-
break;
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
|
95
|
-
VALUE uri = rb_funcall(rb_iv_get(self, "@connection"), rb_intern("to_s"), 0);
|
96
|
-
|
97
|
-
exception = rb_funcall(CONST_GET(mDO, exception_type), ID_NEW, 5,
|
98
|
-
rb_str_new2(message),
|
99
|
-
INT2NUM(sqlite3_errno),
|
100
|
-
rb_str_new2(""),
|
101
|
-
query,
|
102
|
-
uri);
|
103
|
-
rb_exc_raise(exception);
|
104
|
-
}
|
105
|
-
|
106
|
-
static VALUE parse_date(char *date) {
|
107
|
-
int year, month, day;
|
108
|
-
int jd, ajd;
|
109
|
-
VALUE rational;
|
110
|
-
|
111
|
-
sscanf(date, "%4d-%2d-%2d", &year, &month, &day);
|
112
|
-
|
113
|
-
jd = jd_from_date(year, month, day);
|
114
|
-
|
115
|
-
// Math from Date.jd_to_ajd
|
116
|
-
ajd = jd * 2 - 1;
|
117
|
-
rational = rb_funcall(rb_mKernel, ID_RATIONAL, 2, INT2NUM(ajd), INT2NUM(2));
|
118
|
-
return rb_funcall(rb_cDate, ID_NEW_DATE, 3, rational, INT2NUM(0), INT2NUM(2299161));
|
119
|
-
}
|
120
|
-
|
121
|
-
// Creates a Rational for use as a Timezone offset to be passed to DateTime.new!
|
122
|
-
static VALUE seconds_to_offset(do_int64 num) {
|
123
|
-
do_int64 den = 86400;
|
124
|
-
reduce(&num, &den);
|
125
|
-
return rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ll2inum(num), rb_ll2inum(den));
|
126
|
-
}
|
127
|
-
|
128
|
-
static VALUE timezone_to_offset(int hour_offset, int minute_offset) {
|
129
|
-
do_int64 seconds = 0;
|
130
|
-
|
131
|
-
seconds += hour_offset * 3600;
|
132
|
-
seconds += minute_offset * 60;
|
21
|
+
VALUE sql_state = rb_str_new2("");
|
133
22
|
|
134
|
-
|
23
|
+
do_raise_error(self, errors, errnum, message, query, sql_state);
|
135
24
|
}
|
136
25
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
int year, month, day, hour, min, sec, usec, hour_offset, minute_offset;
|
141
|
-
int jd;
|
142
|
-
do_int64 num, den;
|
143
|
-
|
144
|
-
long int gmt_offset;
|
145
|
-
int dst_adjustment;
|
146
|
-
|
147
|
-
time_t rawtime;
|
148
|
-
struct tm timeinfo;
|
149
|
-
|
150
|
-
int tokens_read, max_tokens;
|
26
|
+
VALUE typecast(sqlite3_stmt *stmt, int i, VALUE type, int encoding) {
|
27
|
+
int original_type = sqlite3_column_type(stmt, i);
|
28
|
+
int length = sqlite3_column_bytes(stmt, i);
|
151
29
|
|
152
|
-
if (
|
30
|
+
if (original_type == SQLITE_NULL) {
|
153
31
|
return Qnil;
|
154
32
|
}
|
155
33
|
|
156
|
-
if (0 != strchr(date, '.')) {
|
157
|
-
// This is a datetime with sub-second precision
|
158
|
-
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);
|
159
|
-
max_tokens = 9;
|
160
|
-
} else {
|
161
|
-
// This is a datetime second precision
|
162
|
-
tokens_read = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset);
|
163
|
-
max_tokens = 8;
|
164
|
-
}
|
165
|
-
|
166
|
-
if (max_tokens == tokens_read) {
|
167
|
-
// We read the Date, Time, and Timezone info
|
168
|
-
minute_offset *= hour_offset < 0 ? -1 : 1;
|
169
|
-
} else if ((max_tokens - 1) == tokens_read) {
|
170
|
-
// We read the Date and Time, but no Minute Offset
|
171
|
-
minute_offset = 0;
|
172
|
-
} else if (tokens_read == 3 || tokens_read >= (max_tokens - 3)) {
|
173
|
-
if (tokens_read == 3) {
|
174
|
-
hour = 0;
|
175
|
-
min = 0;
|
176
|
-
hour_offset = 0;
|
177
|
-
minute_offset = 0;
|
178
|
-
sec = 0;
|
179
|
-
}
|
180
|
-
// We read the Date and Time, default to the current locale's offset
|
181
|
-
|
182
|
-
tzset();
|
183
|
-
|
184
|
-
// Get localtime
|
185
|
-
time(&rawtime);
|
186
|
-
#ifdef HAVE_LOCALTIME_R
|
187
|
-
localtime_r(&rawtime, &timeinfo);
|
188
|
-
#else
|
189
|
-
timeinfo = *localtime(&rawtime);
|
190
|
-
#endif
|
191
|
-
|
192
|
-
timeinfo.tm_sec = sec;
|
193
|
-
timeinfo.tm_min = min;
|
194
|
-
timeinfo.tm_hour = hour;
|
195
|
-
timeinfo.tm_mday = day;
|
196
|
-
timeinfo.tm_mon = month;
|
197
|
-
timeinfo.tm_year = year - 1900;
|
198
|
-
timeinfo.tm_isdst = -1;
|
199
|
-
|
200
|
-
// Update tm_isdst
|
201
|
-
mktime(&timeinfo);
|
202
|
-
|
203
|
-
if (timeinfo.tm_isdst) {
|
204
|
-
dst_adjustment = 3600;
|
205
|
-
} else {
|
206
|
-
dst_adjustment = 0;
|
207
|
-
}
|
208
|
-
|
209
|
-
// Reset to GM Time
|
210
|
-
#ifdef HAVE_GMTIME_R
|
211
|
-
gmtime_r(&rawtime, &timeinfo);
|
212
|
-
#else
|
213
|
-
timeinfo = *gmtime(&rawtime);
|
214
|
-
#endif
|
215
|
-
|
216
|
-
gmt_offset = rawtime - mktime(&timeinfo);
|
217
|
-
|
218
|
-
if (dst_adjustment) {
|
219
|
-
gmt_offset += dst_adjustment;
|
220
|
-
}
|
221
|
-
|
222
|
-
hour_offset = ((int)gmt_offset / 3600);
|
223
|
-
minute_offset = ((int)gmt_offset % 3600 / 60);
|
224
|
-
|
225
|
-
} else {
|
226
|
-
// Something went terribly wrong
|
227
|
-
rb_raise(eDataError, "Couldn't parse date: %s", date);
|
228
|
-
}
|
229
|
-
|
230
|
-
jd = jd_from_date(year, month, day);
|
231
|
-
|
232
|
-
// Generate ajd with fractional days for the time
|
233
|
-
// Extracted from Date#jd_to_ajd, Date#day_fraction_to_time, and Rational#+ and #-
|
234
|
-
num = (hour * 1440) + (min * 24);
|
235
|
-
|
236
|
-
// Modify the numerator so when we apply the timezone everything works out
|
237
|
-
num -= (hour_offset * 1440) + (minute_offset * 24);
|
238
|
-
|
239
|
-
den = (24 * 1440);
|
240
|
-
reduce(&num, &den);
|
241
|
-
|
242
|
-
num = (num * 86400) + (sec * den);
|
243
|
-
den = den * 86400;
|
244
|
-
reduce(&num, &den);
|
245
|
-
|
246
|
-
num = (jd * den) + num;
|
247
|
-
|
248
|
-
num = num * 2;
|
249
|
-
num = num - den;
|
250
|
-
den = den * 2;
|
251
|
-
|
252
|
-
reduce(&num, &den);
|
253
|
-
|
254
|
-
ajd = rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ull2inum(num), rb_ull2inum(den));
|
255
|
-
offset = timezone_to_offset(hour_offset, minute_offset);
|
256
|
-
|
257
|
-
return rb_funcall(rb_cDateTime, ID_NEW_DATE, 3, ajd, offset, INT2NUM(2299161));
|
258
|
-
}
|
259
|
-
|
260
|
-
static VALUE parse_time(char *date) {
|
261
|
-
|
262
|
-
int year, month, day, hour, min, sec, usec, tokens, hour_offset, minute_offset;
|
263
|
-
|
264
|
-
if (0 != strchr(date, '.')) {
|
265
|
-
// This is a datetime with sub-second precision
|
266
|
-
tokens = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d.%d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &usec, &hour_offset, &minute_offset);
|
267
|
-
} else {
|
268
|
-
// This is a datetime second precision
|
269
|
-
tokens = sscanf(date, "%4d-%2d-%2d%*c%2d:%2d:%2d%3d:%2d", &year, &month, &day, &hour, &min, &sec, &hour_offset, &minute_offset);
|
270
|
-
usec = 0;
|
271
|
-
if(tokens == 3) {
|
272
|
-
hour = 0;
|
273
|
-
min = 0;
|
274
|
-
sec = 0;
|
275
|
-
hour_offset = 0;
|
276
|
-
minute_offset = 0;
|
277
|
-
}
|
278
|
-
}
|
279
|
-
|
280
|
-
return rb_funcall(rb_cTime, rb_intern("local"), 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
|
281
|
-
}
|
282
|
-
|
283
|
-
static VALUE typecast(sqlite3_stmt *stmt, int i, VALUE type, int encoding) {
|
284
|
-
VALUE ruby_value = Qnil;
|
285
|
-
int original_type = sqlite3_column_type(stmt, i);
|
286
|
-
int length = sqlite3_column_bytes(stmt, i);
|
287
|
-
if ( original_type == SQLITE_NULL ) {
|
288
|
-
return ruby_value;
|
289
|
-
}
|
290
|
-
|
291
34
|
#ifdef HAVE_RUBY_ENCODING_H
|
292
|
-
rb_encoding *
|
35
|
+
rb_encoding *internal_encoding = rb_default_internal_encoding();
|
293
36
|
#else
|
294
|
-
void *
|
37
|
+
void *internal_encoding = NULL;
|
295
38
|
#endif
|
296
39
|
|
297
|
-
if(type == Qnil) {
|
298
|
-
switch(original_type) {
|
299
|
-
case SQLITE_INTEGER:
|
40
|
+
if (type == Qnil) {
|
41
|
+
switch (original_type) {
|
42
|
+
case SQLITE_INTEGER:
|
300
43
|
type = rb_cInteger;
|
301
44
|
break;
|
302
|
-
|
303
|
-
case SQLITE_FLOAT:
|
45
|
+
|
46
|
+
case SQLITE_FLOAT:
|
304
47
|
type = rb_cFloat;
|
305
48
|
break;
|
306
|
-
|
307
|
-
case SQLITE_BLOB:
|
49
|
+
|
50
|
+
case SQLITE_BLOB:
|
308
51
|
type = rb_cByteArray;
|
309
52
|
break;
|
310
|
-
|
311
|
-
default:
|
53
|
+
|
54
|
+
default:
|
312
55
|
type = rb_cString;
|
313
56
|
break;
|
314
|
-
}
|
315
57
|
}
|
316
58
|
}
|
317
59
|
|
318
60
|
if (type == rb_cInteger) {
|
319
61
|
return LL2NUM(sqlite3_column_int64(stmt, i));
|
320
|
-
}
|
62
|
+
}
|
63
|
+
else if (type == rb_cString) {
|
321
64
|
return DO_STR_NEW((char*)sqlite3_column_text(stmt, i), length, encoding, internal_encoding);
|
322
|
-
}
|
65
|
+
}
|
66
|
+
else if (type == rb_cFloat) {
|
323
67
|
return rb_float_new(sqlite3_column_double(stmt, i));
|
324
|
-
}
|
68
|
+
}
|
69
|
+
else if (type == rb_cBigDecimal) {
|
325
70
|
return rb_funcall(rb_cBigDecimal, ID_NEW, 1, rb_str_new((char*)sqlite3_column_text(stmt, i), length));
|
326
|
-
}
|
71
|
+
}
|
72
|
+
else if (type == rb_cDate) {
|
327
73
|
return parse_date((char*)sqlite3_column_text(stmt, i));
|
328
|
-
}
|
74
|
+
}
|
75
|
+
else if (type == rb_cDateTime) {
|
329
76
|
return parse_date_time((char*)sqlite3_column_text(stmt, i));
|
330
|
-
}
|
77
|
+
}
|
78
|
+
else if (type == rb_cTime) {
|
331
79
|
return parse_time((char*)sqlite3_column_text(stmt, i));
|
332
|
-
}
|
80
|
+
}
|
81
|
+
else if (type == rb_cTrueClass) {
|
333
82
|
return strcmp((char*)sqlite3_column_text(stmt, i), "t") == 0 ? Qtrue : Qfalse;
|
334
|
-
}
|
83
|
+
}
|
84
|
+
else if (type == rb_cByteArray) {
|
335
85
|
return rb_funcall(rb_cByteArray, ID_NEW, 1, rb_str_new((char*)sqlite3_column_blob(stmt, i), length));
|
336
|
-
}
|
86
|
+
}
|
87
|
+
else if (type == rb_cClass) {
|
337
88
|
return rb_funcall(mDO, rb_intern("full_const_get"), 1, rb_str_new((char*)sqlite3_column_text(stmt, i), length));
|
338
|
-
}
|
89
|
+
}
|
90
|
+
else if (type == rb_cNilClass) {
|
339
91
|
return Qnil;
|
340
|
-
}
|
92
|
+
}
|
93
|
+
else {
|
341
94
|
return DO_STR_NEW((char*)sqlite3_column_text(stmt, i), length, encoding, internal_encoding);
|
342
95
|
}
|
343
96
|
}
|
@@ -346,9 +99,8 @@ static VALUE typecast(sqlite3_stmt *stmt, int i, VALUE type, int encoding) {
|
|
346
99
|
|
347
100
|
#define FLAG_PRESENT(query_values, flag) !NIL_P(rb_hash_aref(query_values, flag))
|
348
101
|
|
349
|
-
|
102
|
+
int flags_from_uri(VALUE uri) {
|
350
103
|
VALUE query_values = rb_funcall(uri, rb_intern("query"), 0);
|
351
|
-
|
352
104
|
int flags = 0;
|
353
105
|
|
354
106
|
if (!NIL_P(query_values) && TYPE(query_values) == T_HASH) {
|
@@ -356,22 +108,27 @@ static int flags_from_uri(VALUE uri) {
|
|
356
108
|
#ifdef SQLITE_OPEN_READONLY
|
357
109
|
if (FLAG_PRESENT(query_values, OPEN_FLAG_READONLY)) {
|
358
110
|
flags |= SQLITE_OPEN_READONLY;
|
359
|
-
}
|
111
|
+
}
|
112
|
+
else {
|
360
113
|
flags |= SQLITE_OPEN_READWRITE;
|
361
114
|
}
|
362
115
|
#endif
|
116
|
+
|
363
117
|
#ifdef SQLITE_OPEN_NOMUTEX
|
364
118
|
if (FLAG_PRESENT(query_values, OPEN_FLAG_NO_MUTEX)) {
|
365
119
|
flags |= SQLITE_OPEN_NOMUTEX;
|
366
120
|
}
|
367
121
|
#endif
|
122
|
+
|
368
123
|
#ifdef SQLITE_OPEN_FULLMUTEX
|
369
124
|
if (FLAG_PRESENT(query_values, OPEN_FLAG_FULL_MUTEX)) {
|
370
125
|
flags |= SQLITE_OPEN_FULLMUTEX;
|
371
126
|
}
|
372
127
|
#endif
|
128
|
+
|
373
129
|
flags |= SQLITE_OPEN_CREATE;
|
374
|
-
}
|
130
|
+
}
|
131
|
+
else {
|
375
132
|
flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
376
133
|
}
|
377
134
|
|
@@ -382,12 +139,10 @@ static int flags_from_uri(VALUE uri) {
|
|
382
139
|
|
383
140
|
/****** Public API ******/
|
384
141
|
|
385
|
-
|
142
|
+
VALUE cConnection_initialize(VALUE self, VALUE uri) {
|
143
|
+
VALUE path = rb_funcall(uri, rb_intern("path"), 0);
|
144
|
+
sqlite3 *db = NULL;
|
386
145
|
int ret;
|
387
|
-
VALUE path;
|
388
|
-
sqlite3 *db;
|
389
|
-
|
390
|
-
path = rb_funcall(uri, rb_intern("path"), 0);
|
391
146
|
|
392
147
|
#ifdef HAVE_SQLITE3_OPEN_V2
|
393
148
|
ret = sqlite3_open_v2(StringValuePtr(path), &db, flags_from_uri(uri), 0);
|
@@ -395,7 +150,7 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
|
|
395
150
|
ret = sqlite3_open(StringValuePtr(path), &db);
|
396
151
|
#endif
|
397
152
|
|
398
|
-
if (
|
153
|
+
if (ret != SQLITE_OK) {
|
399
154
|
raise_error(self, db, Qnil);
|
400
155
|
}
|
401
156
|
|
@@ -410,72 +165,40 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
|
|
410
165
|
return Qtrue;
|
411
166
|
}
|
412
167
|
|
413
|
-
|
168
|
+
VALUE cConnection_dispose(VALUE self) {
|
414
169
|
VALUE connection_container = rb_iv_get(self, "@connection");
|
415
170
|
|
416
|
-
|
417
|
-
|
418
|
-
if (Qnil == connection_container)
|
171
|
+
if (connection_container == Qnil) {
|
419
172
|
return Qfalse;
|
173
|
+
}
|
420
174
|
|
421
|
-
db = DATA_PTR(connection_container);
|
175
|
+
sqlite3 *db = DATA_PTR(connection_container);
|
422
176
|
|
423
|
-
if (
|
177
|
+
if (!db) {
|
424
178
|
return Qfalse;
|
179
|
+
}
|
425
180
|
|
426
181
|
sqlite3_close(db);
|
427
182
|
rb_iv_set(self, "@connection", Qnil);
|
428
|
-
|
429
183
|
return Qtrue;
|
430
|
-
|
431
|
-
}
|
432
|
-
|
433
|
-
static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
|
434
|
-
VALUE type_strings = rb_ary_new();
|
435
|
-
VALUE array = rb_ary_new();
|
436
|
-
|
437
|
-
int i, j;
|
438
|
-
|
439
|
-
for ( i = 0; i < argc; i++) {
|
440
|
-
rb_ary_push(array, argv[i]);
|
441
|
-
}
|
442
|
-
|
443
|
-
for (i = 0; i < RARRAY_LEN(array); i++) {
|
444
|
-
VALUE entry = rb_ary_entry(array, i);
|
445
|
-
if(TYPE(entry) == T_CLASS) {
|
446
|
-
rb_ary_push(type_strings, entry);
|
447
|
-
} else if (TYPE(entry) == T_ARRAY) {
|
448
|
-
for (j = 0; j < RARRAY_LEN(entry); j++) {
|
449
|
-
VALUE sub_entry = rb_ary_entry(entry, j);
|
450
|
-
if(TYPE(sub_entry) == T_CLASS) {
|
451
|
-
rb_ary_push(type_strings, sub_entry);
|
452
|
-
} else {
|
453
|
-
rb_raise(rb_eArgError, "Invalid type given");
|
454
|
-
}
|
455
|
-
}
|
456
|
-
} else {
|
457
|
-
rb_raise(rb_eArgError, "Invalid type given");
|
458
|
-
}
|
459
|
-
}
|
460
|
-
|
461
|
-
rb_iv_set(self, "@field_types", type_strings);
|
462
|
-
|
463
|
-
return array;
|
464
184
|
}
|
465
185
|
|
466
|
-
|
186
|
+
VALUE cConnection_quote_boolean(VALUE self, VALUE value) {
|
467
187
|
return rb_str_new2(value == Qtrue ? "'t'" : "'f'");
|
468
188
|
}
|
469
189
|
|
470
|
-
|
190
|
+
VALUE cConnection_quote_string(VALUE self, VALUE string) {
|
471
191
|
const char *source = rb_str_ptr_readonly(string);
|
472
|
-
char *escaped_with_quotes;
|
473
|
-
VALUE result;
|
474
192
|
|
475
193
|
// Wrap the escaped string in single-quotes, this is DO's convention
|
476
|
-
escaped_with_quotes = sqlite3_mprintf("%Q", source);
|
194
|
+
char *escaped_with_quotes = sqlite3_mprintf("%Q", source);
|
195
|
+
|
196
|
+
if(!escaped_with_quotes) {
|
197
|
+
rb_memerror();
|
198
|
+
}
|
199
|
+
|
200
|
+
VALUE result = rb_str_new2(escaped_with_quotes);
|
477
201
|
|
478
|
-
result = rb_str_new2(escaped_with_quotes);
|
479
202
|
#ifdef HAVE_RUBY_ENCODING_H
|
480
203
|
rb_enc_associate_index(result, FIX2INT(rb_iv_get(self, "@encoding_id")));
|
481
204
|
#endif
|
@@ -483,209 +206,176 @@ static VALUE cConnection_quote_string(VALUE self, VALUE string) {
|
|
483
206
|
return result;
|
484
207
|
}
|
485
208
|
|
486
|
-
|
209
|
+
VALUE cConnection_quote_byte_array(VALUE self, VALUE string) {
|
487
210
|
VALUE source = StringValue(string);
|
488
211
|
VALUE array = rb_funcall(source, rb_intern("unpack"), 1, rb_str_new2("H*"));
|
212
|
+
|
489
213
|
rb_ary_unshift(array, rb_str_new2("X'"));
|
490
214
|
rb_ary_push(array, rb_str_new2("'"));
|
491
215
|
return rb_ary_join(array, Qnil);
|
492
216
|
}
|
493
217
|
|
494
|
-
|
495
|
-
|
496
|
-
}
|
497
|
-
|
498
|
-
static VALUE cConnection_enable_load_extension(VALUE self, VALUE value) {
|
499
|
-
VALUE connection;
|
500
|
-
int status;
|
501
|
-
sqlite3 *db;
|
218
|
+
VALUE cConnection_enable_load_extension(VALUE self, VALUE value) {
|
219
|
+
VALUE connection = rb_iv_get(self, "@connection");
|
502
220
|
|
503
|
-
connection
|
504
|
-
|
505
|
-
if (Qnil == connection)
|
221
|
+
if (connection == Qnil) {
|
506
222
|
return Qfalse;
|
223
|
+
}
|
507
224
|
|
508
|
-
db = DATA_PTR(connection);
|
225
|
+
sqlite3 *db = DATA_PTR(connection);
|
509
226
|
|
510
|
-
if (
|
227
|
+
if (!db) {
|
511
228
|
return Qfalse;
|
229
|
+
}
|
512
230
|
|
513
|
-
status = sqlite3_enable_load_extension(db, value == Qtrue ? 1 : 0);
|
514
|
-
|
231
|
+
int status = sqlite3_enable_load_extension(db, value == Qtrue ? 1 : 0);
|
232
|
+
|
233
|
+
if (status != SQLITE_OK) {
|
515
234
|
rb_raise(eConnectionError, "Error enabling load extension.");
|
516
235
|
}
|
517
236
|
return Qtrue;
|
518
237
|
}
|
519
238
|
|
520
|
-
|
521
|
-
VALUE connection;
|
522
|
-
sqlite3 *db;
|
523
|
-
const char *extension_name = rb_str_ptr_readonly(string);
|
524
|
-
char* errmsg;
|
525
|
-
int status;
|
239
|
+
VALUE cConnection_load_extension(VALUE self, VALUE string) {
|
240
|
+
VALUE connection = rb_iv_get(self, "@connection");
|
526
241
|
|
527
|
-
connection
|
528
|
-
|
529
|
-
if (Qnil == connection)
|
242
|
+
if (connection == Qnil) {
|
530
243
|
return Qfalse;
|
244
|
+
}
|
531
245
|
|
532
|
-
db = DATA_PTR(connection);
|
246
|
+
sqlite3 *db = DATA_PTR(connection);
|
533
247
|
|
534
|
-
if (
|
248
|
+
if (!db) {
|
535
249
|
return Qfalse;
|
250
|
+
}
|
251
|
+
|
252
|
+
const char *extension_name = rb_str_ptr_readonly(string);
|
253
|
+
char *errmsg = NULL;
|
254
|
+
int status = sqlite3_load_extension(db, extension_name, 0, &errmsg);
|
536
255
|
|
537
|
-
|
538
|
-
if ( status != SQLITE_OK ) {
|
256
|
+
if (status != SQLITE_OK) {
|
539
257
|
rb_raise(eConnectionError, "%s", errmsg);
|
540
258
|
}
|
541
259
|
return Qtrue;
|
542
260
|
}
|
543
261
|
|
544
|
-
|
545
|
-
VALUE query =
|
546
|
-
|
547
|
-
VALUE
|
548
|
-
for ( i = 0; i < count; i++) {
|
549
|
-
rb_ary_push(array, (VALUE)args[i]);
|
550
|
-
}
|
551
|
-
query = rb_funcall(klass, ID_ESCAPE, 1, array);
|
552
|
-
return query;
|
553
|
-
}
|
554
|
-
|
555
|
-
static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
|
556
|
-
sqlite3 *db;
|
557
|
-
char *error_message;
|
558
|
-
int status;
|
559
|
-
int affected_rows;
|
560
|
-
do_int64 insert_id;
|
561
|
-
VALUE connection, sqlite3_connection;
|
562
|
-
VALUE query;
|
563
|
-
struct timeval start;
|
564
|
-
|
565
|
-
query = build_query_from_args(self, argc, argv);
|
262
|
+
VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
|
263
|
+
VALUE query = build_query_from_args(self, argc, argv);
|
264
|
+
VALUE connection = rb_iv_get(self, "@connection");
|
265
|
+
VALUE sqlite3_connection = rb_iv_get(connection, "@connection");
|
566
266
|
|
567
|
-
|
568
|
-
sqlite3_connection = rb_iv_get(connection, "@connection");
|
569
|
-
if (Qnil == sqlite3_connection) {
|
267
|
+
if (sqlite3_connection == Qnil) {
|
570
268
|
rb_raise(eConnectionError, "This connection has already been closed.");
|
571
269
|
}
|
572
270
|
|
271
|
+
sqlite3 *db = NULL;
|
272
|
+
|
573
273
|
Data_Get_Struct(sqlite3_connection, sqlite3, db);
|
574
274
|
|
275
|
+
struct timeval start;
|
276
|
+
char *error_message;
|
277
|
+
int status;
|
278
|
+
|
575
279
|
gettimeofday(&start, NULL);
|
576
280
|
status = sqlite3_exec(db, rb_str_ptr_readonly(query), 0, 0, &error_message);
|
577
281
|
|
578
|
-
if (
|
282
|
+
if (status != SQLITE_OK) {
|
579
283
|
raise_error(self, db, query);
|
580
284
|
}
|
285
|
+
|
581
286
|
data_objects_debug(connection, query, &start);
|
582
287
|
|
583
|
-
affected_rows = sqlite3_changes(db);
|
584
|
-
insert_id = sqlite3_last_insert_rowid(db);
|
288
|
+
int affected_rows = sqlite3_changes(db);
|
289
|
+
do_int64 insert_id = sqlite3_last_insert_rowid(db);
|
585
290
|
|
586
291
|
return rb_funcall(cResult, ID_NEW, 3, self, INT2NUM(affected_rows), INT2NUM(insert_id));
|
587
292
|
}
|
588
293
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
int field_count;
|
594
|
-
int i;
|
595
|
-
VALUE reader;
|
596
|
-
VALUE connection, sqlite3_connection;
|
597
|
-
VALUE query;
|
598
|
-
VALUE field_names, field_types;
|
599
|
-
struct timeval start;
|
294
|
+
VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
|
295
|
+
VALUE query = build_query_from_args(self, argc, argv);
|
296
|
+
VALUE connection = rb_iv_get(self, "@connection");
|
297
|
+
VALUE sqlite3_connection = rb_iv_get(connection, "@connection");
|
600
298
|
|
601
|
-
|
602
|
-
sqlite3_connection = rb_iv_get(connection, "@connection");
|
603
|
-
if (Qnil == sqlite3_connection) {
|
299
|
+
if (sqlite3_connection == Qnil) {
|
604
300
|
rb_raise(eConnectionError, "This connection has already been closed.");
|
605
301
|
}
|
606
302
|
|
303
|
+
sqlite3 *db = NULL;
|
304
|
+
|
607
305
|
Data_Get_Struct(sqlite3_connection, sqlite3, db);
|
608
306
|
|
609
|
-
|
307
|
+
sqlite3_stmt *sqlite3_reader;
|
308
|
+
struct timeval start;
|
309
|
+
int status;
|
610
310
|
|
611
311
|
gettimeofday(&start, NULL);
|
612
312
|
status = sqlite3_prepare_v2(db, rb_str_ptr_readonly(query), -1, &sqlite3_reader, 0);
|
613
313
|
data_objects_debug(connection, query, &start);
|
614
314
|
|
615
|
-
if (
|
315
|
+
if (status != SQLITE_OK) {
|
616
316
|
raise_error(self, db, query);
|
617
317
|
}
|
618
318
|
|
619
|
-
field_count = sqlite3_column_count(sqlite3_reader);
|
620
|
-
reader = rb_funcall(cReader, ID_NEW, 0);
|
319
|
+
int field_count = sqlite3_column_count(sqlite3_reader);
|
320
|
+
VALUE reader = rb_funcall(cReader, ID_NEW, 0);
|
621
321
|
|
622
322
|
rb_iv_set(reader, "@reader", Data_Wrap_Struct(rb_cObject, 0, 0, sqlite3_reader));
|
623
323
|
rb_iv_set(reader, "@field_count", INT2NUM(field_count));
|
624
324
|
rb_iv_set(reader, "@connection", connection);
|
625
325
|
|
626
|
-
|
627
|
-
field_types = rb_iv_get(self, "@field_types");
|
326
|
+
VALUE field_types = rb_iv_get(self, "@field_types");
|
628
327
|
|
629
|
-
if (
|
328
|
+
if (field_types == Qnil || RARRAY_LEN(field_types) == 0) {
|
630
329
|
field_types = rb_ary_new();
|
631
|
-
}
|
330
|
+
}
|
331
|
+
else if (RARRAY_LEN(field_types) != field_count) {
|
632
332
|
// Whoops... wrong number of types passed to set_types. Close the reader and raise
|
633
333
|
// and error
|
634
334
|
rb_funcall(reader, rb_intern("close"), 0);
|
635
335
|
rb_raise(rb_eArgError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
|
636
336
|
}
|
637
337
|
|
638
|
-
|
338
|
+
VALUE field_names = rb_ary_new();
|
339
|
+
int i;
|
340
|
+
|
341
|
+
for (i = 0; i < field_count; i++) {
|
639
342
|
rb_ary_push(field_names, rb_str_new2((char *)sqlite3_column_name(sqlite3_reader, i)));
|
640
343
|
}
|
641
344
|
|
642
345
|
rb_iv_set(reader, "@fields", field_names);
|
643
346
|
rb_iv_set(reader, "@field_types", field_types);
|
644
|
-
|
645
347
|
return reader;
|
646
348
|
}
|
647
349
|
|
648
|
-
|
350
|
+
VALUE cReader_close(VALUE self) {
|
649
351
|
VALUE reader_obj = rb_iv_get(self, "@reader");
|
650
352
|
|
651
|
-
if (
|
652
|
-
sqlite3_stmt *reader;
|
353
|
+
if (reader_obj != Qnil) {
|
354
|
+
sqlite3_stmt *reader = NULL;
|
355
|
+
|
653
356
|
Data_Get_Struct(reader_obj, sqlite3_stmt, reader);
|
654
357
|
sqlite3_finalize(reader);
|
655
358
|
rb_iv_set(self, "@reader", Qnil);
|
656
359
|
return Qtrue;
|
657
360
|
}
|
658
|
-
else {
|
659
|
-
return Qfalse;
|
660
|
-
}
|
661
|
-
}
|
662
361
|
|
663
|
-
|
664
|
-
|
665
|
-
int field_count;
|
666
|
-
int result;
|
667
|
-
int i;
|
668
|
-
size_t ft_length;
|
669
|
-
VALUE arr = rb_ary_new();
|
670
|
-
VALUE field_types;
|
671
|
-
VALUE field_type;
|
672
|
-
VALUE value;
|
362
|
+
return Qfalse;
|
363
|
+
}
|
673
364
|
|
674
|
-
|
365
|
+
VALUE cReader_next(VALUE self) {
|
366
|
+
if (rb_iv_get(self, "@done") == Qtrue) {
|
675
367
|
return Qfalse;
|
676
368
|
}
|
677
369
|
|
678
|
-
|
679
|
-
|
370
|
+
sqlite3_stmt *reader = NULL;
|
371
|
+
int result;
|
680
372
|
|
681
|
-
|
682
|
-
ft_length = RARRAY_LEN(field_types);
|
373
|
+
Data_Get_Struct(rb_iv_get(self, "@reader"), sqlite3_stmt, reader);
|
683
374
|
|
684
375
|
result = sqlite3_step(reader);
|
685
|
-
|
686
376
|
rb_iv_set(self, "@state", INT2NUM(result));
|
687
377
|
|
688
|
-
if (
|
378
|
+
if (result != SQLITE_ROW) {
|
689
379
|
rb_iv_set(self, "@values", Qnil);
|
690
380
|
rb_iv_set(self, "@done", Qtrue);
|
691
381
|
return Qfalse;
|
@@ -694,86 +384,46 @@ static VALUE cReader_next(VALUE self) {
|
|
694
384
|
int enc = -1;
|
695
385
|
#ifdef HAVE_RUBY_ENCODING_H
|
696
386
|
VALUE encoding_id = rb_iv_get(rb_iv_get(self, "@connection"), "@encoding_id");
|
387
|
+
|
697
388
|
if (encoding_id != Qnil) {
|
698
389
|
enc = FIX2INT(encoding_id);
|
699
390
|
}
|
700
391
|
#endif
|
701
392
|
|
393
|
+
VALUE field_types = rb_iv_get(self, "@field_types");
|
394
|
+
int field_count = NUM2INT(rb_iv_get(self, "@field_count"));
|
395
|
+
VALUE arr = rb_ary_new();
|
396
|
+
VALUE field_type;
|
397
|
+
VALUE value;
|
398
|
+
int i;
|
702
399
|
|
703
|
-
for (
|
400
|
+
for (i = 0; i < field_count; i++) {
|
704
401
|
field_type = rb_ary_entry(field_types, i);
|
705
402
|
value = typecast(reader, i, field_type, enc);
|
706
403
|
rb_ary_push(arr, value);
|
707
404
|
}
|
708
405
|
|
709
406
|
rb_iv_set(self, "@values", arr);
|
710
|
-
|
711
407
|
return Qtrue;
|
712
408
|
}
|
713
409
|
|
714
|
-
|
410
|
+
VALUE cReader_values_sqlite(VALUE self) {
|
715
411
|
VALUE state = rb_iv_get(self, "@state");
|
716
|
-
|
412
|
+
|
413
|
+
if (state == Qnil || NUM2INT(state) != SQLITE_ROW) {
|
717
414
|
rb_raise(eDataError, "Reader is not initialized");
|
718
415
|
return Qnil;
|
719
416
|
}
|
720
|
-
else {
|
721
|
-
return rb_iv_get(self, "@values");
|
722
|
-
}
|
723
|
-
}
|
724
|
-
|
725
|
-
static VALUE cReader_fields(VALUE self) {
|
726
|
-
return rb_iv_get(self, "@fields");
|
727
|
-
}
|
728
417
|
|
729
|
-
|
730
|
-
return rb_iv_get(self, "@field_count");
|
418
|
+
return rb_iv_get(self, "@values");
|
731
419
|
}
|
732
420
|
|
733
421
|
void Init_do_sqlite3() {
|
734
|
-
|
735
|
-
rb_require("date");
|
736
|
-
rb_require("rational");
|
737
|
-
rb_require("data_objects");
|
738
|
-
|
739
|
-
ID_CONST_GET = rb_intern("const_get");
|
740
|
-
|
741
|
-
// Get references classes needed for Date/Time parsing
|
742
|
-
rb_cDate = CONST_GET(rb_mKernel, "Date");
|
743
|
-
rb_cDateTime = CONST_GET(rb_mKernel, "DateTime");
|
744
|
-
rb_cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
|
422
|
+
common_init();
|
745
423
|
|
746
|
-
#ifdef RUBY_LESS_THAN_186
|
747
|
-
ID_NEW_DATE = rb_intern("new0");
|
748
|
-
#else
|
749
|
-
ID_NEW_DATE = rb_intern("new!");
|
750
|
-
#endif
|
751
|
-
ID_RATIONAL = rb_intern("Rational");
|
752
|
-
ID_NEW = rb_intern("new");
|
753
|
-
ID_ESCAPE = rb_intern("escape_sql");
|
754
|
-
ID_LOG = rb_intern("log");
|
755
|
-
|
756
|
-
// Get references to the Extlib module
|
757
|
-
mExtlib = CONST_GET(rb_mKernel, "Extlib");
|
758
|
-
rb_cByteArray = CONST_GET(mExtlib, "ByteArray");
|
759
|
-
|
760
|
-
// Get references to the DataObjects module and its classes
|
761
|
-
mDO = CONST_GET(rb_mKernel, "DataObjects");
|
762
|
-
cDO_Quoting = CONST_GET(mDO, "Quoting");
|
763
|
-
cDO_Connection = CONST_GET(mDO, "Connection");
|
764
|
-
cDO_Command = CONST_GET(mDO, "Command");
|
765
|
-
cDO_Result = CONST_GET(mDO, "Result");
|
766
|
-
cDO_Reader = CONST_GET(mDO, "Reader");
|
767
|
-
cDO_Logger = CONST_GET(mDO, "Logger");
|
768
|
-
cDO_Logger_Message = CONST_GET(cDO_Logger, "Message");
|
769
|
-
|
770
|
-
// Initialize the DataObjects::Sqlite3 module, and define its classes
|
771
424
|
mSqlite3 = rb_define_module_under(mDO, "Sqlite3");
|
772
425
|
|
773
|
-
|
774
|
-
eDataError = CONST_GET(mDO, "DataError");
|
775
|
-
|
776
|
-
cConnection = DRIVER_CLASS("Connection", cDO_Connection);
|
426
|
+
cConnection = rb_define_class_under(mSqlite3, "Connection", cDO_Connection);
|
777
427
|
rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
|
778
428
|
rb_define_method(cConnection, "dispose", cConnection_dispose, 0);
|
779
429
|
rb_define_method(cConnection, "quote_boolean", cConnection_quote_boolean, 1);
|
@@ -783,41 +433,23 @@ void Init_do_sqlite3() {
|
|
783
433
|
rb_define_method(cConnection, "enable_load_extension", cConnection_enable_load_extension, 1);
|
784
434
|
rb_define_method(cConnection, "load_extension", cConnection_load_extension, 1);
|
785
435
|
|
786
|
-
cCommand =
|
436
|
+
cCommand = rb_define_class_under(mSqlite3, "Command", cDO_Command);
|
787
437
|
rb_define_method(cCommand, "set_types", cCommand_set_types, -1);
|
788
438
|
rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
|
789
439
|
rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
|
790
440
|
|
791
|
-
cResult =
|
441
|
+
cResult = rb_define_class_under(mSqlite3, "Result", cDO_Result);
|
792
442
|
|
793
|
-
cReader =
|
443
|
+
cReader = rb_define_class_under(mSqlite3, "Reader", cDO_Reader);
|
794
444
|
rb_define_method(cReader, "close", cReader_close, 0);
|
795
445
|
rb_define_method(cReader, "next!", cReader_next, 0);
|
796
|
-
rb_define_method(cReader, "values",
|
446
|
+
rb_define_method(cReader, "values", cReader_values_sqlite, 0); // TODO: DRY?
|
797
447
|
rb_define_method(cReader, "fields", cReader_fields, 0);
|
798
448
|
rb_define_method(cReader, "field_count", cReader_field_count, 0);
|
799
449
|
|
800
|
-
rb_global_variable(&ID_NEW_DATE);
|
801
|
-
rb_global_variable(&ID_RATIONAL);
|
802
|
-
rb_global_variable(&ID_CONST_GET);
|
803
|
-
rb_global_variable(&ID_ESCAPE);
|
804
|
-
rb_global_variable(&ID_LOG);
|
805
|
-
rb_global_variable(&ID_NEW);
|
806
|
-
|
807
|
-
rb_global_variable(&rb_cDate);
|
808
|
-
rb_global_variable(&rb_cDateTime);
|
809
|
-
rb_global_variable(&rb_cBigDecimal);
|
810
|
-
rb_global_variable(&rb_cByteArray);
|
811
|
-
|
812
|
-
rb_global_variable(&mDO);
|
813
|
-
rb_global_variable(&cDO_Logger_Message);
|
814
|
-
|
815
450
|
rb_global_variable(&cResult);
|
816
451
|
rb_global_variable(&cReader);
|
817
452
|
|
818
|
-
rb_global_variable(&eConnectionError);
|
819
|
-
rb_global_variable(&eDataError);
|
820
|
-
|
821
453
|
OPEN_FLAG_READONLY = rb_str_new2("read_only");
|
822
454
|
rb_global_variable(&OPEN_FLAG_READONLY);
|
823
455
|
OPEN_FLAG_READWRITE = rb_str_new2("read_write");
|
@@ -830,4 +462,6 @@ void Init_do_sqlite3() {
|
|
830
462
|
rb_global_variable(&OPEN_FLAG_FULL_MUTEX);
|
831
463
|
|
832
464
|
Init_do_sqlite3_extension();
|
465
|
+
|
466
|
+
do_define_errors(mSqlite3, errors);
|
833
467
|
}
|