swift-db-sqlite3 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ == 0.1.0 (2012-07-20)
2
+
3
+ * Initial version.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Swift Sqlite3 adapter
2
+
3
+ MRI adapter for sqlite3 for use in Swift ORM.
4
+
5
+ ## Features
6
+
7
+ * Lightweight & fast
8
+ * Result typecasting
9
+ * Prepared statements
10
+ * Nested transactions
11
+
12
+ ## API
13
+
14
+ ```
15
+ Swift::DB::Sqlite3
16
+ .new(options)
17
+ #execute(sql, *bind)
18
+ #prepare(sql)
19
+ #begin(savepoint = nil)
20
+ #commit(savepoint = nil)
21
+ #rollback(savepoint = nil)
22
+ #transaction(savepoint = nil, &block)
23
+ #close
24
+ #closed?
25
+ #escape(text)
26
+
27
+ Swift::DB::Sqlite3::Statement
28
+ .new(Swift::DB::Sqlite3, sql)
29
+ #execute(*bind)
30
+ #release
31
+
32
+ Swift::DB::Sqlite3::Result
33
+ #selected_rows
34
+ #affected_rows
35
+ #fields
36
+ #types
37
+ #each
38
+ #insert_id
39
+ ```
40
+
41
+ ## Example
42
+
43
+ ```ruby
44
+ require 'swift/db/sqlite3'
45
+
46
+ db = Swift::DB::Sqlite3.new(db: ':memory:')
47
+
48
+ db.execute('drop table if exists users')
49
+ db.execute('create table users (id integer primary key, name text, age integer, created_at datetime)')
50
+ db.execute('insert into users(name, age, created_at) values(?, ?, ?)', 'test', 30, Time.now.utc)
51
+
52
+ row = db.execute('select * from users').first
53
+ p row #=> {:id => 1, :name => 'test', :age => 30, :created_at=> #<Swift::DateTime>}
54
+ ```
55
+
56
+ ## Performance
57
+
58
+ Don't read too much into it. Each library has its advantages and disadvantages.
59
+
60
+ ```
61
+ # insert 1000 rows and read them back 100 times with typecasting enabled.
62
+
63
+ user system total real
64
+ do_sqlite3 insert 0.050000 0.020000 0.070000 ( 0.062814)
65
+ do_sqlite3 select 0.720000 0.000000 0.720000 ( 0.723628)
66
+
67
+ sqlite3 insert 0.040000 0.000000 0.040000 ( 0.046895)
68
+ sqlite3 select 4.390000 0.000000 4.390000 ( 4.400678)
69
+
70
+ swift insert 0.030000 0.000000 0.030000 ( 0.030628)
71
+ swift select 0.480000 0.000000 0.480000 ( 0.488608)
72
+ ```
73
+
74
+ ## License
75
+
76
+ MIT
@@ -0,0 +1,231 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #include "adapter.h"
6
+
7
+ /* declaration */
8
+ VALUE cDSA;
9
+ VALUE db_sqlite3_statement_allocate(VALUE);
10
+ VALUE db_sqlite3_statement_initialize(VALUE, VALUE, VALUE);
11
+ VALUE db_sqlite3_statement_execute(int argc, VALUE *argv, VALUE self);
12
+
13
+ /* definition */
14
+ Adapter* db_sqlite3_adapter_handle(VALUE self) {
15
+ Adapter *a;
16
+ Data_Get_Struct(self, Adapter, a);
17
+ if (!a)
18
+ rb_raise(eSwiftRuntimeError, "Invalid sqlite3 adapter");
19
+ return a;
20
+ }
21
+
22
+ Adapter* db_sqlite3_adapter_handle_safe(VALUE self) {
23
+ Adapter *a = db_sqlite3_adapter_handle(self);
24
+ if (!a->connection)
25
+ rb_raise(eSwiftConnectionError, "sqlite3 database is not open");
26
+ return a;
27
+ }
28
+
29
+ VALUE db_sqlite3_adapter_deallocate(Adapter *a) {
30
+ if (a && a->connection)
31
+ sqlite3_close(a->connection);
32
+ if (a)
33
+ free(a);
34
+ }
35
+
36
+ VALUE db_sqlite3_adapter_allocate(VALUE klass) {
37
+ Adapter *a = (Adapter*)malloc(sizeof(Adapter));
38
+
39
+ a->connection = 0;
40
+ a->t_nesting = 0;
41
+ return Data_Wrap_Struct(klass, 0, db_sqlite3_adapter_deallocate, a);
42
+ }
43
+
44
+ VALUE db_sqlite3_adapter_initialize(VALUE self, VALUE options) {
45
+ VALUE db;
46
+ sqlite3* connection;
47
+ Adapter *a = db_sqlite3_adapter_handle(self);
48
+
49
+ if (TYPE(options) != T_HASH)
50
+ rb_raise(eSwiftArgumentError, "options needs to be a hash");
51
+
52
+ db = rb_hash_aref(options, ID2SYM(rb_intern("db")));
53
+ if (NIL_P(db))
54
+ rb_raise(eSwiftConnectionError, "Invalid db name");
55
+
56
+ if (sqlite3_open_v2(CSTRING(db), &connection, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0) != SQLITE_OK)
57
+ rb_raise(eSwiftConnectionError, "%s", sqlite3_errmsg(connection));
58
+
59
+ a->connection = connection;
60
+ return Qnil;
61
+ }
62
+
63
+ VALUE db_sqlite3_adapter_execute(int argc, VALUE *argv, VALUE self) {
64
+ VALUE sql, bind;
65
+ rb_scan_args(argc, argv, "10*", &sql, &bind);
66
+
67
+ return db_sqlite3_statement_execute(
68
+ RARRAY_LEN(bind),
69
+ RARRAY_PTR(bind),
70
+ db_sqlite3_statement_initialize(db_sqlite3_statement_allocate(cDSS), self, sql)
71
+ );
72
+ }
73
+
74
+ VALUE db_sqlite3_adapter_prepare(VALUE self, VALUE sql) {
75
+ return db_sqlite3_statement_initialize(db_sqlite3_statement_allocate(cDSS), self, sql);
76
+ }
77
+
78
+ VALUE db_sqlite3_adapter_begin(int argc, VALUE *argv, VALUE self) {
79
+ int auto_commit;
80
+ VALUE savepoint, sql;
81
+ char command[256];
82
+
83
+ Adapter *a = db_sqlite3_adapter_handle_safe(self);
84
+ rb_scan_args(argc, argv, "01", &savepoint);
85
+
86
+ if (a->t_nesting == 0) {
87
+ sql = rb_str_new2("begin");
88
+ db_sqlite3_adapter_execute(1, &sql, self);
89
+ a->t_nesting++;
90
+ if (NIL_P(savepoint))
91
+ return Qtrue;
92
+ }
93
+
94
+ if (NIL_P(savepoint))
95
+ savepoint = rb_uuid_string();
96
+
97
+ snprintf(command, 256, "savepoint %s", CSTRING(savepoint));
98
+ sql = rb_str_new2(command);
99
+ db_sqlite3_adapter_execute(1, &sql, self);
100
+ a->t_nesting++;
101
+ return savepoint;
102
+ }
103
+
104
+ VALUE db_sqlite3_adapter_commit(int argc, VALUE *argv, VALUE self) {
105
+ VALUE savepoint, sql;
106
+ char command[256];
107
+
108
+ Adapter *a = db_sqlite3_adapter_handle_safe(self);
109
+ rb_scan_args(argc, argv, "01", &savepoint);
110
+
111
+ if (a->t_nesting == 0)
112
+ return Qfalse;
113
+
114
+ if (NIL_P(savepoint)) {
115
+ sql = rb_str_new2("commit");
116
+ db_sqlite3_adapter_execute(1, &sql, self);
117
+ a->t_nesting--;
118
+ }
119
+ else {
120
+ snprintf(command, 256, "release savepoint %s", CSTRING(savepoint));
121
+ sql = rb_str_new2(command);
122
+ db_sqlite3_adapter_execute(1, &sql, self);
123
+ a->t_nesting--;
124
+ }
125
+ return Qtrue;
126
+ }
127
+
128
+ VALUE db_sqlite3_adapter_rollback(int argc, VALUE *argv, VALUE self) {
129
+ VALUE savepoint, sql;
130
+ char command[256];
131
+
132
+ Adapter *a = db_sqlite3_adapter_handle_safe(self);
133
+ rb_scan_args(argc, argv, "01", &savepoint);
134
+
135
+ if (a->t_nesting == 0)
136
+ return Qfalse;
137
+
138
+ if (NIL_P(savepoint)) {
139
+ sql = rb_str_new2("rollback");
140
+ db_sqlite3_adapter_execute(1, &sql, self);
141
+ a->t_nesting--;
142
+ }
143
+ else {
144
+ snprintf(command, 256, "rollback to savepoint %s", CSTRING(savepoint));
145
+ sql = rb_str_new2(command);
146
+ db_sqlite3_adapter_execute(1, &sql, self);
147
+ a->t_nesting--;
148
+ }
149
+ return Qtrue;
150
+ }
151
+
152
+ VALUE db_sqlite3_adapter_transaction(int argc, VALUE *argv, VALUE self) {
153
+ int status;
154
+ VALUE savepoint, block, block_result;
155
+
156
+ Adapter *a = db_sqlite3_adapter_handle_safe(self);
157
+ rb_scan_args(argc, argv, "01&", &savepoint, &block);
158
+
159
+ if (NIL_P(block))
160
+ rb_raise(eSwiftRuntimeError, "sqlite3 transaction requires a block");
161
+
162
+ if (a->t_nesting == 0) {
163
+ db_sqlite3_adapter_begin(1, &savepoint, self);
164
+ block_result = rb_protect(rb_yield, self, &status);
165
+ if (!status) {
166
+ db_sqlite3_adapter_commit(1, &savepoint, self);
167
+ if (!NIL_P(savepoint))
168
+ db_sqlite3_adapter_commit(0, 0, self);
169
+ }
170
+ else {
171
+ db_sqlite3_adapter_rollback(1, &savepoint, self);
172
+ if (!NIL_P(savepoint))
173
+ db_sqlite3_adapter_rollback(0, 0, self);
174
+ rb_jump_tag(status);
175
+ }
176
+ }
177
+ else {
178
+ if (NIL_P(savepoint))
179
+ savepoint = rb_uuid_string();
180
+ db_sqlite3_adapter_begin(1, &savepoint, self);
181
+ block_result = rb_protect(rb_yield, self, &status);
182
+ if (!status)
183
+ db_sqlite3_adapter_commit(1, &savepoint, self);
184
+ else {
185
+ db_sqlite3_adapter_rollback(1, &savepoint, self);
186
+ rb_jump_tag(status);
187
+ }
188
+ }
189
+
190
+ return block_result;
191
+ }
192
+
193
+ VALUE db_sqlite3_adapter_close(VALUE self) {
194
+ Adapter *a = db_sqlite3_adapter_handle(self);
195
+ if (a->connection) {
196
+ sqlite3_close(a->connection);
197
+ a->connection = 0;
198
+ return Qtrue;
199
+ }
200
+ return Qfalse;
201
+ }
202
+
203
+ VALUE db_sqlite3_adapter_closed_q(VALUE self) {
204
+ Adapter *a = db_sqlite3_adapter_handle(self);
205
+ return a->connection ? Qfalse : Qtrue;
206
+ }
207
+
208
+ VALUE db_sqlite3_adapter_escape(VALUE self, VALUE text) {
209
+ VALUE escaped;
210
+ Adapter *a = db_sqlite3_adapter_handle_safe(self);
211
+ char *sqlite3_escaped = sqlite3_mprintf("%q", CSTRING(text));
212
+ escaped = rb_str_new2(sqlite3_escaped);
213
+ sqlite3_free(sqlite3_escaped);
214
+ return escaped;
215
+ }
216
+
217
+ void init_swift_db_sqlite3_adapter() {
218
+ cDSA = rb_define_class_under(mDB, "Sqlite3", rb_cObject);
219
+ rb_define_alloc_func(cDSA, db_sqlite3_adapter_allocate);
220
+
221
+ rb_define_method(cDSA, "initialize", db_sqlite3_adapter_initialize, 1);
222
+ rb_define_method(cDSA, "prepare", db_sqlite3_adapter_prepare, 1);
223
+ rb_define_method(cDSA, "execute", db_sqlite3_adapter_execute, -1);
224
+ rb_define_method(cDSA, "begin", db_sqlite3_adapter_begin, -1);
225
+ rb_define_method(cDSA, "commit", db_sqlite3_adapter_commit, -1);
226
+ rb_define_method(cDSA, "rollback", db_sqlite3_adapter_rollback, -1);
227
+ rb_define_method(cDSA, "transaction", db_sqlite3_adapter_transaction, -1);
228
+ rb_define_method(cDSA, "close", db_sqlite3_adapter_close, 0);
229
+ rb_define_method(cDSA, "closed?", db_sqlite3_adapter_closed_q, 0);
230
+ rb_define_method(cDSA, "escape", db_sqlite3_adapter_escape, 1);
231
+ }
@@ -0,0 +1,14 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #pragma once
6
+
7
+ #include "common.h"
8
+
9
+ typedef struct Adapter {
10
+ sqlite3 *connection;
11
+ int t_nesting;
12
+ } Adapter;
13
+
14
+ void init_swift_db_sqlite3_adapter();
@@ -0,0 +1,19 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #include "common.h"
6
+ #include "uuid/uuid.h"
7
+
8
+ VALUE rb_uuid_string() {
9
+ size_t n;
10
+ uuid_t uuid;
11
+ char uuid_hex[sizeof(uuid_t) * 2 + 1];
12
+
13
+ uuid_generate(uuid);
14
+ for (n = 0; n < sizeof(uuid_t); n++)
15
+ sprintf(uuid_hex + n * 2 + 1, "%02x", uuid[n]);
16
+
17
+ uuid_hex[0] = 'u';
18
+ return rb_str_new(uuid_hex, sizeof(uuid_t) * 2 + 1);
19
+ }
@@ -0,0 +1,22 @@
1
+ #pragma once
2
+
3
+ #define DLL_PRIVATE __attribute__ ((visibility ("hidden")))
4
+ #define CONST_GET(scope, constant) rb_funcall(scope, rb_intern("const_get"), 1, rb_str_new2(constant))
5
+ #define TO_S(v) rb_funcall(v, rb_intern("to_s"), 0)
6
+ #define CSTRING(v) RSTRING_PTR(TO_S(v))
7
+
8
+ #include <ruby/ruby.h>
9
+ #include <ruby/encoding.h>
10
+
11
+ #include <fcntl.h>
12
+ #include <sqlite3.h>
13
+ #include <sys/stat.h>
14
+ #include <sys/types.h>
15
+ #include <time.h>
16
+ #include <unistd.h>
17
+
18
+ extern VALUE mSwift, mDB;
19
+ extern VALUE cDSA, cDSS, cDSR;
20
+ extern VALUE eSwiftError, eSwiftArgumentError, eSwiftRuntimeError, eSwiftConnectionError;
21
+
22
+ VALUE rb_uuid_string();
@@ -0,0 +1,99 @@
1
+ #include "datetime.h"
2
+ #include <ctype.h>
3
+
4
+ extern VALUE dtformat;
5
+
6
+ VALUE cSwiftDateTime, day_seconds;
7
+ ID fcivil, fparse, fstrptime;
8
+
9
+ // NOTE: only parses '%F %T.%N %z' format and falls back to the built-in DateTime#parse
10
+ // and is almost 2x faster than doing:
11
+ //
12
+ // rb_funcall(klass, fstrptime, 2, rb_str_new(data, size), dtformat);
13
+ //
14
+ VALUE datetime_parse(VALUE klass, const char *data, size_t size) {
15
+ struct tm tm;
16
+ double seconds;
17
+ const char *ptr;
18
+ char tzsign = 0, fraction[32];
19
+ int tzhour = 0, tzmin = 0, lastmatch = -1, offset = 0, idx;
20
+
21
+ memset(&tm, 0, sizeof(struct tm));
22
+ sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%n",
23
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &lastmatch);
24
+
25
+ // fallback to default datetime parser, this is more expensive.
26
+ if (tm.tm_mday == 0)
27
+ return Qnil;
28
+
29
+ seconds = tm.tm_sec;
30
+
31
+ // parse millisecs if any -- tad faster than using %lf in sscanf above.
32
+ if (lastmatch > 0 && lastmatch < (int)size && *(data + lastmatch) == '.') {
33
+ idx = 0;
34
+ ptr = data + ++lastmatch;
35
+ while (*ptr && isdigit(*ptr) && idx < 31) {
36
+ lastmatch++;
37
+ fraction[idx++] = *ptr++;
38
+ }
39
+
40
+ fraction[idx] = 0;
41
+ seconds += (double)atoll(fraction) / pow(10, idx);
42
+ }
43
+
44
+ // parse timezone offsets if any - matches +HH:MM +HH MM +HHMM
45
+ if (lastmatch > 0 && lastmatch < (int)size) {
46
+ const char *ptr = data + lastmatch;
47
+ while(*ptr && *ptr != '+' && *ptr != '-') ptr++;
48
+ tzsign = *ptr++;
49
+ if (*ptr && isdigit(*ptr)) {
50
+ tzhour = *ptr++ - '0';
51
+ if (*ptr && isdigit(*ptr)) tzhour = tzhour * 10 + *ptr++ - '0';
52
+ while(*ptr && !isdigit(*ptr)) ptr++;
53
+ if (*ptr) {
54
+ tzmin = *ptr++ - '0';
55
+ if (*ptr && isdigit(*ptr)) tzmin = tzmin * 10 + *ptr++ - '0';
56
+ }
57
+ }
58
+ }
59
+
60
+ if (tzsign) {
61
+ offset = tzsign == '+'
62
+ ? (time_t)tzhour * 3600 + (time_t)tzmin * 60
63
+ : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
64
+ }
65
+
66
+ return rb_funcall(klass, fcivil, 7,
67
+ INT2FIX(tm.tm_year), INT2FIX(tm.tm_mon), INT2FIX(tm.tm_mday),
68
+ INT2FIX(tm.tm_hour), INT2FIX(tm.tm_min), DBL2NUM(seconds),
69
+ offset == 0 ? INT2FIX(0) : rb_Rational(INT2FIX(offset), day_seconds)
70
+ );
71
+ }
72
+
73
+ VALUE rb_datetime_parse(VALUE self, VALUE string) {
74
+ VALUE datetime;
75
+ const char *data = CSTRING(string);
76
+ size_t size = TYPE(string) == T_STRING ? (size_t)RSTRING_LEN(string) : strlen(data);
77
+
78
+ if (NIL_P(string))
79
+ return Qnil;
80
+
81
+ datetime = datetime_parse(self, data, size);
82
+ return NIL_P(datetime) ? rb_call_super(1, &string) : datetime;
83
+ }
84
+
85
+ void init_swift_datetime() {
86
+ VALUE mSwift, cDateTime;
87
+
88
+ rb_require("date");
89
+ mSwift = rb_define_module("Swift");
90
+ cDateTime = CONST_GET(rb_mKernel, "DateTime");
91
+ cSwiftDateTime = rb_define_class_under(mSwift, "DateTime", cDateTime);
92
+ fcivil = rb_intern("civil");
93
+ fparse = rb_intern("parse");
94
+ fstrptime = rb_intern("strptime");
95
+ day_seconds = INT2FIX(86400);
96
+
97
+ rb_global_variable(&day_seconds);
98
+ rb_define_singleton_method(cSwiftDateTime, "parse", RUBY_METHOD_FUNC(rb_datetime_parse), 1);
99
+ }
@@ -0,0 +1,8 @@
1
+ #pragma once
2
+
3
+ #include "common.h"
4
+ #include <math.h>
5
+
6
+ DLL_PRIVATE extern VALUE cSwiftDateTime;
7
+ DLL_PRIVATE void init_swift_datetime();
8
+ DLL_PRIVATE VALUE datetime_parse(VALUE klass, const char *data, size_t size);
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mkmf'
4
+
5
+ find_library('sqlite3', 'main', '/usr/lib /usr/local/lib /opt/lib /opt/local/lib')
6
+ find_library('uuid', 'main', '/usr/lib /usr/local/lib /opt/lib /opt/local/lib')
7
+ create_makefile('swift_db_sqlite3_ext')
8
+
@@ -0,0 +1,28 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #include "common.h"
6
+ #include "adapter.h"
7
+ #include "statement.h"
8
+ #include "result.h"
9
+ #include "datetime.h"
10
+
11
+ VALUE mSwift, mDB;
12
+ VALUE eSwiftError, eSwiftArgumentError, eSwiftRuntimeError, eSwiftConnectionError;
13
+
14
+ void Init_swift_db_sqlite3_ext() {
15
+ mSwift = rb_define_module("Swift");
16
+ mDB = rb_define_module_under(mSwift, "DB");
17
+
18
+ eSwiftError = rb_define_class_under(mSwift, "Error", rb_eStandardError);
19
+ eSwiftArgumentError = rb_define_class_under(mSwift, "ArgumentError", eSwiftError);
20
+ eSwiftRuntimeError = rb_define_class_under(mSwift, "RuntimeError", eSwiftError);
21
+ eSwiftConnectionError = rb_define_class_under(mSwift, "ConnectionError", eSwiftError);
22
+
23
+ init_swift_db_sqlite3_adapter();
24
+ init_swift_db_sqlite3_statement();
25
+ init_swift_db_sqlite3_result();
26
+ init_swift_datetime();
27
+ init_swift_db_sqlite3_typecast();
28
+ }
@@ -0,0 +1,236 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #include "result.h"
6
+
7
+ /* declaration */
8
+
9
+ typedef struct Result {
10
+ VALUE fields;
11
+ VALUE types;
12
+ VALUE rows;
13
+ VALUE statement;
14
+ sqlite3* c;
15
+ sqlite3_stmt *s;
16
+ size_t affected;
17
+ size_t insert_id;
18
+ } Result;
19
+
20
+ typedef struct Type {
21
+ int value;
22
+ const char *definition;
23
+ } Type;
24
+
25
+ VALUE cDSR;
26
+
27
+ Statement* db_sqlite3_statement_handle(VALUE);
28
+
29
+ /* definition */
30
+
31
+ Result* db_sqlite3_result_handle(VALUE self) {
32
+ Result *r;
33
+ Data_Get_Struct(self, Result, r);
34
+ if (!r)
35
+ rb_raise(eSwiftRuntimeError, "Invalid sqlite3 result");
36
+ return r;
37
+ }
38
+
39
+ void db_sqlite3_result_mark(Result *r) {
40
+ if (r) {
41
+ if (!NIL_P(r->statement))
42
+ rb_gc_mark_maybe(r->statement);
43
+ if (!NIL_P(r->fields))
44
+ rb_gc_mark_maybe(r->fields);
45
+ if (!NIL_P(r->types))
46
+ rb_gc_mark_maybe(r->types);
47
+ if (!NIL_P(r->rows))
48
+ rb_gc_mark_maybe(r->rows);
49
+ }
50
+ }
51
+
52
+ VALUE db_sqlite3_result_deallocate(Result *r) {
53
+ if (r) free(r);
54
+ }
55
+
56
+ VALUE db_sqlite3_result_allocate(VALUE klass) {
57
+ Result *r = (Result*)malloc(sizeof(Result));
58
+ memset(r, 0, sizeof(Result));
59
+ return Data_Wrap_Struct(klass, db_sqlite3_result_mark, db_sqlite3_result_deallocate, r);
60
+ }
61
+
62
+ VALUE db_sqlite3_result_initialize(VALUE self, VALUE statement) {
63
+ Result *r = db_sqlite3_result_handle(self);
64
+ Statement *s = db_sqlite3_statement_handle(statement);
65
+
66
+ r->fields = rb_ary_new();
67
+ r->types = rb_ary_new();
68
+ r->rows = rb_ary_new();
69
+ r->statement = statement;
70
+ r->s = s->s;
71
+ r->c = s->c;
72
+ r->affected = 0;
73
+
74
+ return self;
75
+ }
76
+
77
+ VALUE db_sqlite3_result_consume(VALUE self) {
78
+ int n, i, rc;
79
+ const char *type, *data;
80
+ Result *r = db_sqlite3_result_handle(self);
81
+
82
+ Type types[] = {
83
+ {SWIFT_TYPE_INT, "int"},
84
+ {SWIFT_TYPE_INT, "integer"},
85
+ {SWIFT_TYPE_INT, "bigint"},
86
+ {SWIFT_TYPE_FLOAT, "real"},
87
+ {SWIFT_TYPE_FLOAT, "float"},
88
+ {SWIFT_TYPE_NUMERIC, "decimal"},
89
+ {SWIFT_TYPE_NUMERIC, "numeric"},
90
+ {SWIFT_TYPE_BOOLEAN, "bool"},
91
+ {SWIFT_TYPE_BOOLEAN, "boolean"},
92
+ {SWIFT_TYPE_DATE, "date"},
93
+ {SWIFT_TYPE_TIME, "time"},
94
+ {SWIFT_TYPE_TIMESTAMP, "timestamp"},
95
+ {SWIFT_TYPE_TIMESTAMP, "datetime"},
96
+ {SWIFT_TYPE_TEXT, "text"},
97
+ {SWIFT_TYPE_TEXT, "char"},
98
+ {SWIFT_TYPE_TEXT, "varchar"},
99
+ {SWIFT_TYPE_BLOB, "blob"},
100
+ {SWIFT_TYPE_UNKNOWN, "unknown"}
101
+ };
102
+
103
+ int lazy_types = 0;
104
+ size_t ntypes = sizeof(types) / sizeof(Type);
105
+
106
+ rb_ary_clear(r->fields);
107
+ rb_ary_clear(r->types);
108
+ rb_ary_clear(r->rows);
109
+
110
+ for (n = 0; n < sqlite3_column_count(r->s); n++) {
111
+ rb_ary_push(r->fields, ID2SYM(rb_intern(sqlite3_column_name(r->s, n))));
112
+
113
+ type = sqlite3_column_decltype(r->s, n);
114
+ if (!type) {
115
+ lazy_types = 1;
116
+ rb_ary_push(r->types, INT2NUM(SWIFT_TYPE_UNKNOWN));
117
+ continue;
118
+ }
119
+
120
+ for (i = 0; i < (int)ntypes; i++) {
121
+ if (strcmp(type, types[i].definition) == 0 || types[i].value == SWIFT_TYPE_UNKNOWN) {
122
+ rb_ary_push(r->types, INT2NUM(types[i].value));
123
+ break;
124
+ }
125
+ }
126
+ }
127
+
128
+ r->affected = sqlite3_total_changes(r->c);
129
+
130
+ while ((rc = sqlite3_step(r->s)) == SQLITE_ROW) {
131
+ VALUE row = rb_ary_new();
132
+
133
+ /* type determination of aggregrations can only be determined after a row is pulled out */
134
+ if (lazy_types) {
135
+ for (n = 0; n < RARRAY_LEN(r->types); n++) {
136
+ if (NUM2INT(rb_ary_entry(r->types, n)) == SWIFT_TYPE_UNKNOWN) {
137
+ switch(sqlite3_column_type(r->s, n)) {
138
+ case SQLITE_INTEGER:
139
+ rb_ary_store(r->types, n, INT2NUM(SWIFT_TYPE_INT)); break;
140
+ case SQLITE_FLOAT:
141
+ rb_ary_store(r->types, n, INT2NUM(SWIFT_TYPE_FLOAT)); break;
142
+ case SQLITE_BLOB:
143
+ rb_ary_store(r->types, n, INT2NUM(SWIFT_TYPE_BLOB)); break;
144
+ default:
145
+ rb_ary_store(r->types, n, INT2NUM(SWIFT_TYPE_TEXT));
146
+ }
147
+ }
148
+ }
149
+ lazy_types = 0;
150
+ }
151
+
152
+ for (n = 0; n < sqlite3_column_count(r->s); n++) {
153
+ switch (sqlite3_column_type(r->s, n)) {
154
+ case SQLITE_NULL:
155
+ rb_ary_push(row, Qnil);
156
+ break;
157
+ case SQLITE_TEXT:
158
+ case SQLITE_BLOB:
159
+ data = sqlite3_column_blob(r->s, n);
160
+ rb_ary_push(row, typecast_detect(data, sqlite3_column_bytes(r->s, n), NUM2INT(rb_ary_entry(r->types, n))));
161
+ break;
162
+ default:
163
+ data = sqlite3_column_text(r->s, n);
164
+ rb_ary_push(row, typecast_detect(data, strlen(data), NUM2INT(rb_ary_entry(r->types, n))));
165
+ }
166
+ }
167
+ rb_ary_push(r->rows, row);
168
+ }
169
+
170
+ if (rc != SQLITE_DONE)
171
+ rb_raise(eSwiftRuntimeError, "%s\nSQL: %s", sqlite3_errmsg(r->c), sqlite3_sql(r->s));
172
+
173
+ r->affected = sqlite3_total_changes(r->c) - r->affected;
174
+ r->insert_id = sqlite3_last_insert_rowid(r->c);
175
+ sqlite3_reset(r->s);
176
+
177
+ return self;
178
+ }
179
+
180
+ VALUE db_sqlite3_result_each(VALUE self) {
181
+ int n, f;
182
+ Result *r = db_sqlite3_result_handle(self);
183
+
184
+ if (!r->rows) return Qnil;
185
+
186
+ for (n = 0; n < RARRAY_LEN(r->rows); n++) {
187
+ VALUE tuple = rb_hash_new();
188
+ VALUE row = rb_ary_entry(r->rows, n);
189
+ for (f = 0; f < RARRAY_LEN(r->fields); f++)
190
+ rb_hash_aset(tuple, rb_ary_entry(r->fields, f), rb_ary_entry(row, f));
191
+ rb_yield(tuple);
192
+ }
193
+ }
194
+
195
+ VALUE db_sqlite3_result_selected_rows(VALUE self) {
196
+ Result *r = db_sqlite3_result_handle(self);
197
+ return r->rows ? SIZET2NUM(RARRAY_LEN(r->rows)) : INT2NUM(0);
198
+ }
199
+
200
+ VALUE db_sqlite3_result_affected_rows(VALUE self) {
201
+ Result *r = db_sqlite3_result_handle(self);
202
+ return SIZET2NUM(r->affected);
203
+ }
204
+
205
+ VALUE db_sqlite3_result_fields(VALUE self) {
206
+ Result *r = db_sqlite3_result_handle(self);
207
+ return r->fields ? r->fields : rb_ary_new();
208
+ }
209
+
210
+ VALUE db_sqlite3_result_types(VALUE self) {
211
+ Result *r = db_sqlite3_result_handle(self);
212
+ return r->types ? typecast_description(r->types) : rb_ary_new();
213
+ }
214
+
215
+ VALUE db_sqlite3_result_insert_id(VALUE self) {
216
+ Result *r = db_sqlite3_result_handle(self);
217
+ return SIZET2NUM(r->insert_id);
218
+ }
219
+
220
+ void init_swift_db_sqlite3_result() {
221
+ rb_require("bigdecimal");
222
+ rb_require("stringio");
223
+ rb_require("date");
224
+
225
+ cDSR = rb_define_class_under(cDSA, "Result", rb_cObject);
226
+
227
+ rb_include_module(cDSR, rb_mEnumerable);
228
+ rb_define_alloc_func(cDSR, db_sqlite3_result_allocate);
229
+ rb_define_method(cDSR, "initialize", db_sqlite3_result_initialize, 1);
230
+ rb_define_method(cDSR, "each", db_sqlite3_result_each, 0);
231
+ rb_define_method(cDSR, "selected_rows", db_sqlite3_result_selected_rows, 0);
232
+ rb_define_method(cDSR, "affected_rows", db_sqlite3_result_affected_rows, 0);
233
+ rb_define_method(cDSR, "fields", db_sqlite3_result_fields, 0);
234
+ rb_define_method(cDSR, "types", db_sqlite3_result_types, 0);
235
+ rb_define_method(cDSR, "insert_id", db_sqlite3_result_insert_id, 0);
236
+ }
@@ -0,0 +1,11 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #pragma once
6
+
7
+ #include "common.h"
8
+ #include "statement.h"
9
+ #include "typecast.h"
10
+
11
+ void init_swift_db_sqlite3_result();
@@ -0,0 +1,114 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #include "statement.h"
6
+ #include "typecast.h"
7
+
8
+ /* declaration */
9
+
10
+ VALUE cDSS;
11
+
12
+ Adapter* db_sqlite3_adapter_handle_safe(VALUE);
13
+ VALUE db_sqlite3_result_allocate(VALUE);
14
+ VALUE db_sqlite3_result_initialize(VALUE, VALUE);
15
+ VALUE db_sqlite3_result_consume(VALUE);
16
+ VALUE db_sqlite3_result_each(VALUE);
17
+
18
+ /* definition */
19
+
20
+ Statement* db_sqlite3_statement_handle(VALUE self) {
21
+ Statement *s;
22
+ Data_Get_Struct(self, Statement, s);
23
+ if (!s)
24
+ rb_raise(eSwiftRuntimeError, "Invalid sqlite3 statement");
25
+ return s;
26
+ }
27
+
28
+ Statement* db_sqlite3_statement_handle_safe(VALUE self) {
29
+ Statement *s = db_sqlite3_statement_handle(self);
30
+ if (!s->s)
31
+ rb_raise(eSwiftRuntimeError, "Statement instance not allocated or has been released");
32
+ return s;
33
+ }
34
+
35
+ void db_sqlite3_statement_mark(Statement *s) {
36
+ if (s && !NIL_P(s->adapter))
37
+ rb_gc_mark_maybe(s->adapter);
38
+ }
39
+
40
+ VALUE db_sqlite3_statement_deallocate(Statement *s) {
41
+ if (s && s->s) {
42
+ sqlite3_finalize(s->s);
43
+ free(s);
44
+ }
45
+ }
46
+
47
+ VALUE db_sqlite3_statement_allocate(VALUE klass) {
48
+ Statement *s = (Statement*)malloc(sizeof(Statement));
49
+ memset(s, 0, sizeof(Statement));
50
+ return Data_Wrap_Struct(klass, db_sqlite3_statement_mark, db_sqlite3_statement_deallocate, s);
51
+ }
52
+
53
+ VALUE db_sqlite3_statement_initialize(VALUE self, VALUE adapter, VALUE sql) {
54
+ Statement *s = db_sqlite3_statement_handle(self);
55
+
56
+ s->s = 0;
57
+ s->c = db_sqlite3_adapter_handle_safe(adapter)->connection;
58
+ s->adapter = adapter;
59
+
60
+ if (sqlite3_prepare_v2(s->c, RSTRING_PTR(sql), RSTRING_LEN(sql), &(s->s), 0) != SQLITE_OK)
61
+ rb_raise(eSwiftRuntimeError, "%s\nSQL: %s", sqlite3_errmsg(s->c), RSTRING_PTR(sql));
62
+
63
+ return self;
64
+ }
65
+
66
+ VALUE db_sqlite3_statement_insert_id(VALUE self) {
67
+ Statement *s = db_sqlite3_statement_handle_safe(self);
68
+ return SIZET2NUM(sqlite3_last_insert_rowid(s->c));
69
+ }
70
+
71
+ VALUE db_sqlite3_statement_execute(int argc, VALUE *argv, VALUE self) {
72
+ int expect, n;
73
+ VALUE bind, result;
74
+
75
+ Statement *s = db_sqlite3_statement_handle_safe(self);
76
+
77
+ sqlite3_reset(s->s);
78
+ sqlite3_clear_bindings(s->s);
79
+
80
+ rb_scan_args(argc, argv, "00*", &bind);
81
+ expect = sqlite3_bind_parameter_count(s->s);
82
+ if (expect != RARRAY_LEN(bind))
83
+ rb_raise(eSwiftArgumentError, "expected %d bind values got %d", expect, RARRAY_LEN(bind));
84
+
85
+ for (n = 0; n < expect; n++) {
86
+ VALUE value = rb_ary_entry(bind, n);
87
+ if (NIL_P(value))
88
+ sqlite3_bind_null(s->s, n + 1);
89
+ else {
90
+ VALUE text = typecast_to_string(value);
91
+ sqlite3_bind_text(s->s, n + 1, RSTRING_PTR(text), RSTRING_LEN(text), 0);
92
+ }
93
+ }
94
+
95
+ result = db_sqlite3_result_allocate(cDSR);
96
+ db_sqlite3_result_initialize(result, self);
97
+ db_sqlite3_result_consume(result);
98
+ return result;
99
+ }
100
+
101
+ VALUE db_sqlite3_statement_release(VALUE self) {
102
+ Statement *s = db_sqlite3_statement_handle_safe(self);
103
+ sqlite3_finalize(s->s);
104
+ s->s = 0;
105
+ return Qtrue;
106
+ }
107
+
108
+ void init_swift_db_sqlite3_statement() {
109
+ cDSS = rb_define_class_under(cDSA, "Statement", rb_cObject);
110
+ rb_define_alloc_func(cDSS, db_sqlite3_statement_allocate);
111
+ rb_define_method(cDSS, "initialize", db_sqlite3_statement_initialize, 2);
112
+ rb_define_method(cDSS, "execute", db_sqlite3_statement_execute, -1);
113
+ rb_define_method(cDSS, "release", db_sqlite3_statement_release, 0);
114
+ }
@@ -0,0 +1,17 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #pragma once
6
+
7
+ #include "common.h"
8
+ #include "adapter.h"
9
+
10
+ void init_swift_db_sqlite3_statement();
11
+
12
+ typedef struct Statement {
13
+ sqlite3 *c;
14
+ sqlite3_stmt *s;
15
+ VALUE adapter;
16
+ } Statement;
17
+
@@ -0,0 +1,106 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #include "common.h"
6
+ #include "typecast.h"
7
+ #include "datetime.h"
8
+
9
+ #define date_parse(klass, data,len) rb_funcall(datetime_parse(klass, data, len), fto_date, 0)
10
+
11
+ ID fnew, fto_date, fstrftime;
12
+ VALUE cBigDecimal, cStringIO;
13
+ VALUE dtformat;
14
+ VALUE cDateTime;
15
+
16
+ VALUE typecast_string(const char *data, size_t n) {
17
+ return rb_enc_str_new(data, n, rb_utf8_encoding());
18
+ }
19
+
20
+ VALUE typecast_detect(const char *data, size_t size, int type) {
21
+ switch (type) {
22
+ case SWIFT_TYPE_INT:
23
+ return rb_cstr2inum(data, 10);
24
+ case SWIFT_TYPE_FLOAT:
25
+ return rb_float_new(atof(data));
26
+ case SWIFT_TYPE_NUMERIC:
27
+ return rb_funcall(cBigDecimal, fnew, 1, rb_str_new(data, size));
28
+ case SWIFT_TYPE_BOOLEAN:
29
+ return (data && (data[0] =='t' || data[0] == '1')) ? Qtrue : Qfalse;
30
+ case SWIFT_TYPE_BLOB:
31
+ return rb_funcall(cStringIO, fnew, 1, rb_str_new(data, size));
32
+ case SWIFT_TYPE_TIMESTAMP:
33
+ return datetime_parse(cSwiftDateTime, data, size);
34
+ case SWIFT_TYPE_DATE:
35
+ return date_parse(cSwiftDateTime, data, size);
36
+ default:
37
+ return rb_enc_str_new(data, size, rb_utf8_encoding());
38
+ }
39
+ }
40
+
41
+ #define TO_UTF8(value) rb_str_encode(value, rb_str_new2("UTF-8"), 0, Qnil)
42
+ #define UTF8_STRING(value) strcmp(rb_enc_get(value)->name, "UTF-8") ? TO_UTF8(value) : value
43
+
44
+ VALUE typecast_to_string(VALUE value) {
45
+ switch (TYPE(value)) {
46
+ case T_STRING:
47
+ return UTF8_STRING(value);
48
+ case T_TRUE:
49
+ return rb_str_new2("1");
50
+ case T_FALSE:
51
+ return rb_str_new2("0");
52
+ default:
53
+ if (rb_obj_is_kind_of(value, rb_cTime) || rb_obj_is_kind_of(value, cDateTime))
54
+ return rb_funcall(value, fstrftime, 1, dtformat);
55
+ else if (rb_obj_is_kind_of(value, rb_cIO) || rb_obj_is_kind_of(value, cStringIO))
56
+ return rb_funcall(value, rb_intern("read"), 0);
57
+ else
58
+ return UTF8_STRING(rb_funcall(value, rb_intern("to_s"), 0));
59
+ }
60
+ }
61
+
62
+ VALUE typecast_description(VALUE list) {
63
+ int n;
64
+ VALUE types = rb_ary_new();
65
+
66
+ for (n = 0; n < RARRAY_LEN(list); n++) {
67
+ switch (NUM2INT(rb_ary_entry(list, n))) {
68
+ case SWIFT_TYPE_INT:
69
+ rb_ary_push(types, rb_str_new2("integer")); break;
70
+ case SWIFT_TYPE_NUMERIC:
71
+ rb_ary_push(types, rb_str_new2("numeric")); break;
72
+ case SWIFT_TYPE_FLOAT:
73
+ rb_ary_push(types, rb_str_new2("float")); break;
74
+ case SWIFT_TYPE_BLOB:
75
+ rb_ary_push(types, rb_str_new2("blob")); break;
76
+ case SWIFT_TYPE_DATE:
77
+ rb_ary_push(types, rb_str_new2("date")); break;
78
+ case SWIFT_TYPE_TIME:
79
+ rb_ary_push(types, rb_str_new2("time")); break;
80
+ case SWIFT_TYPE_TIMESTAMP:
81
+ rb_ary_push(types, rb_str_new2("timestamp")); break;
82
+ case SWIFT_TYPE_BOOLEAN:
83
+ rb_ary_push(types, rb_str_new2("boolean")); break;
84
+ default:
85
+ rb_ary_push(types, rb_str_new2("text"));
86
+
87
+ }
88
+ }
89
+ return types;
90
+ }
91
+
92
+ void init_swift_db_sqlite3_typecast() {
93
+ rb_require("bigdecimal");
94
+ rb_require("stringio");
95
+ rb_require("date");
96
+
97
+ cStringIO = CONST_GET(rb_mKernel, "StringIO");
98
+ cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
99
+ cDateTime = CONST_GET(rb_mKernel, "DateTime");
100
+ fnew = rb_intern("new");
101
+ fto_date = rb_intern("to_date");
102
+ fstrftime = rb_intern("strftime");
103
+ dtformat = rb_str_new2("%F %T.%N %z");
104
+
105
+ rb_global_variable(&dtformat);
106
+ }
@@ -0,0 +1,24 @@
1
+ // vim:ts=4:sts=4:sw=4:expandtab
2
+
3
+ // (c) Bharanee Rathna 2012
4
+
5
+ #pragma once
6
+
7
+ #include "common.h"
8
+
9
+ #define SWIFT_TYPE_INT 0
10
+ #define SWIFT_TYPE_FLOAT 1
11
+ #define SWIFT_TYPE_NUMERIC 2
12
+ #define SWIFT_TYPE_BOOLEAN 3
13
+ #define SWIFT_TYPE_DATE 4
14
+ #define SWIFT_TYPE_TIME 5
15
+ #define SWIFT_TYPE_TIMESTAMP 6
16
+ #define SWIFT_TYPE_TEXT 7
17
+ #define SWIFT_TYPE_BLOB 8
18
+ #define SWIFT_TYPE_UNKNOWN 9
19
+
20
+ DLL_PRIVATE VALUE typecast_to_string(VALUE);
21
+ DLL_PRIVATE VALUE typecast_string(const char *, size_t);
22
+ DLL_PRIVATE VALUE typecast_detect(const char *, size_t, int);
23
+ DLL_PRIVATE VALUE typecast_description(VALUE list);
24
+ DLL_PRIVATE void init_swift_db_sqlite3_typecast();
@@ -0,0 +1 @@
1
+ require 'swift/db/sqlite3'
@@ -0,0 +1 @@
1
+ require 'swift/db/sqlite3/swift_db_sqlite3_ext'
data/test/helper.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'minitest/autorun'
2
+ require 'swift/db/sqlite3'
3
+
4
+ class MiniTest::Spec
5
+ def db
6
+ @db ||= Swift::DB::Sqlite3.new(db: ':memory:')
7
+ end
8
+ end
@@ -0,0 +1,68 @@
1
+ require 'helper'
2
+
3
+ describe 'sqlite3 adapter' do
4
+ it 'should initialize' do
5
+ assert db
6
+ end
7
+
8
+ it 'should execute sql' do
9
+ assert db.execute("select name from sqlite_master")
10
+ end
11
+
12
+ it 'should expect the correct number of bind args' do
13
+ assert_raises(Swift::ArgumentError) { db.execute("select * from sqlite_master where name = ?", 1, 2) }
14
+ end
15
+
16
+ it 'should return result on #execute' do
17
+ now = Time.now
18
+ assert db.execute('create table users (id integer primary key, name text, age integer, created_at timestamp)')
19
+ assert db.execute('insert into users(name, age, created_at) values(?, ?, ?)', 'test', nil, now)
20
+
21
+ result = db.execute('select * from users')
22
+
23
+ assert_equal 1, result.selected_rows
24
+ assert_equal 0, result.affected_rows
25
+ assert_equal %w(id name age created_at).map(&:to_sym), result.fields
26
+ assert_equal %w(integer text integer timestamp), result.types
27
+
28
+ row = result.first
29
+ assert_equal 1, row[:id]
30
+ assert_equal 'test', row[:name]
31
+ assert_equal nil, row[:age]
32
+ assert_equal now, row[:created_at].to_time
33
+
34
+ result = db.execute('delete from users where id = 0')
35
+ assert_equal 0, result.selected_rows
36
+ assert_equal 0, result.affected_rows
37
+
38
+ assert_equal 1, db.execute('select count(*) as count from users').first[:count]
39
+
40
+ result = db.execute('delete from users')
41
+ assert_equal 0, result.selected_rows
42
+ assert_equal 1, result.affected_rows
43
+ end
44
+
45
+ it 'should close handle' do
46
+ assert !db.closed?
47
+ assert db.close
48
+ assert db.closed?
49
+
50
+ assert_raises(Swift::ConnectionError) { db.execute("select * from users") }
51
+ end
52
+
53
+ it 'should prepare & release statement' do
54
+ assert db.execute("create table users(id integer primary key, name text)")
55
+ assert db.execute("insert into users (name) values (?)", "test")
56
+ assert s = db.prepare("select * from users where id > ?")
57
+
58
+ assert_equal 1, s.execute(0).selected_rows
59
+ assert_equal 0, s.execute(1).selected_rows
60
+
61
+ assert s.release
62
+ assert_raises(Swift::RuntimeError) { s.execute(1) }
63
+ end
64
+
65
+ it 'should escape whatever' do
66
+ assert_equal "foo''bar", db.escape("foo'bar")
67
+ end
68
+ end
@@ -0,0 +1,29 @@
1
+ require 'helper'
2
+
3
+ describe 'utf-8 encoding' do
4
+ before do
5
+ assert db.execute('create table users (name text)')
6
+
7
+ @text = ["King of \u2665s", "\xA1\xB8".force_encoding('euc-jp')]
8
+ end
9
+
10
+ it 'should store and retrieve utf8 characters with Statement#execute' do
11
+ @text.each do |name|
12
+ db.prepare('insert into users (name) values(?)').execute(name)
13
+ value = db.prepare('select * from users limit 1').execute.first[:name]
14
+ assert_equal Encoding::UTF_8, value.encoding
15
+ assert_equal name.encode('utf-8'), value
16
+ db.execute('delete from users')
17
+ end
18
+ end
19
+
20
+ it 'should store and retrieve utf8 characters Adapter#execute' do
21
+ @text.each do |name|
22
+ db.execute('insert into users (name) values(?)', name)
23
+ value = db.execute('select * from users limit 1').first[:name]
24
+ assert_equal Encoding::UTF_8, value.encoding
25
+ assert_equal name.encode('utf-8'), value
26
+ db.execute('delete from users')
27
+ end
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: swift-db-sqlite3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bharanee Rathna
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Swift adapter for Sqlite3 database
31
+ email:
32
+ - deepfryed@gmail.com
33
+ executables: []
34
+ extensions:
35
+ - ext/swift/db/sqlite3/extconf.rb
36
+ extra_rdoc_files: []
37
+ files:
38
+ - ext/swift/db/sqlite3/adapter.c
39
+ - ext/swift/db/sqlite3/datetime.c
40
+ - ext/swift/db/sqlite3/typecast.c
41
+ - ext/swift/db/sqlite3/common.c
42
+ - ext/swift/db/sqlite3/main.c
43
+ - ext/swift/db/sqlite3/statement.c
44
+ - ext/swift/db/sqlite3/result.c
45
+ - ext/swift/db/sqlite3/adapter.h
46
+ - ext/swift/db/sqlite3/statement.h
47
+ - ext/swift/db/sqlite3/typecast.h
48
+ - ext/swift/db/sqlite3/common.h
49
+ - ext/swift/db/sqlite3/result.h
50
+ - ext/swift/db/sqlite3/datetime.h
51
+ - ext/swift/db/sqlite3/extconf.rb
52
+ - test/test_encoding.rb
53
+ - test/helper.rb
54
+ - test/test_adapter.rb
55
+ - lib/swift/db/sqlite3.rb
56
+ - lib/swift-db-sqlite3.rb
57
+ - README.md
58
+ - CHANGELOG
59
+ homepage: http://github.com/deepfryed/swift-db-sqlite3
60
+ licenses: []
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ - ext
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 1.8.24
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Swift sqlite3 adapter
84
+ test_files: []
85
+ has_rdoc: