swift 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +27 -32
- data/VERSION +1 -1
- data/examples/db.rb +1 -1
- data/ext/adapter.cc +6 -22
- data/ext/{iostream.cc → adapter_io.cc} +26 -8
- data/ext/adapter_io.h +24 -0
- data/ext/extconf.rb +1 -1
- data/ext/pool.cc +2 -2
- data/ext/query.cc +2 -3
- data/ext/query.h +6 -6
- data/ext/result.cc +1 -13
- data/ext/statement.cc +22 -25
- data/ext/swift.h +11 -1
- data/lib/swift/db.rb +28 -37
- data/lib/swift/pool.rb +3 -7
- data/swift.gemspec +68 -69
- data/test/helper.rb +5 -6
- data/test/test_adapter.rb +14 -15
- data/test/test_encoding.rb +3 -3
- data/test/test_error.rb +2 -2
- data/test/test_io.rb +18 -2
- data/test/test_pool.rb +1 -1
- data/test/test_timestamps.rb +1 -2
- data/test/test_transactions.rb +10 -7
- data/test/test_types.rb +7 -3
- metadata +26 -19
- data/ext/iostream.h +0 -17
data/README.rdoc
CHANGED
@@ -10,15 +10,7 @@ A rational rudimentary object relational mapper.
|
|
10
10
|
|
11
11
|
* ruby >= 1.9.1
|
12
12
|
* dbic++ >= 0.4.0 (http://github.com/deepfryed/dbicpp)
|
13
|
-
* mysql >= 5.0.17
|
14
|
-
|
15
|
-
== Caveats
|
16
|
-
|
17
|
-
=== DB2
|
18
|
-
* The server needs to be running under DB2_COMPATIBILITY_VECTOR=77FF if you want to use the ORM
|
19
|
-
features of swift.
|
20
|
-
* DB2 asynchronous operations are highly experimental at this point due to inherent limitations of the
|
21
|
-
underlying api. It is more an academic exercise and is not ready for real-world use.
|
13
|
+
* mysql >= 5.0.17, postgresql >= 8.4 or sqlite3 >= 3.7
|
22
14
|
|
23
15
|
== Features
|
24
16
|
|
@@ -26,7 +18,7 @@ A rational rudimentary object relational mapper.
|
|
26
18
|
* Prepared statements.
|
27
19
|
* Bind values.
|
28
20
|
* Transactions and named save points.
|
29
|
-
* EventMachine asynchronous interface.
|
21
|
+
* EventMachine asynchronous interface (mysql and postgresql).
|
30
22
|
* IdentityMap.
|
31
23
|
* Migrations.
|
32
24
|
|
@@ -175,7 +167,7 @@ Swift comes with a simple identity map. Just require it after you load swift.
|
|
175
167
|
|
176
168
|
=== Bulk inserts
|
177
169
|
|
178
|
-
Swift comes with adapter level support for bulk inserts for MySQL
|
170
|
+
Swift comes with adapter level support for bulk inserts for MySQL and PostgreSQL. This
|
179
171
|
is usually very fast (~5-10x faster) than regular prepared insert statements for larger
|
180
172
|
sets of data.
|
181
173
|
|
@@ -225,25 +217,25 @@ Intel Core2Duo P8700 2.53GHz and stock PostgreSQL 8.4.1.
|
|
225
217
|
|
226
218
|
./simple.rb -n1 -r10000 -s ar -s dm -s sequel -s swift
|
227
219
|
|
228
|
-
benchmark sys user total
|
229
|
-
ar #create 0.
|
230
|
-
ar #select 0.
|
231
|
-
ar #update 0.
|
220
|
+
benchmark sys user total real rss
|
221
|
+
ar #create 0.790000 8.290000 9.08000 11.679886 405.07m
|
222
|
+
ar #select 0.040000 0.310000 0.35000 0.383573 40.56m
|
223
|
+
ar #update 0.720000 9.890000 10.6100 13.765735 503.48m
|
232
224
|
|
233
|
-
dm #create 0.
|
234
|
-
dm #select 0.
|
235
|
-
dm #update 0.
|
225
|
+
dm #create 0.310000 3.300000 3.61000 4.593075 211.01m
|
226
|
+
dm #select 0.040000 1.720000 1.76000 1.776852 114.51m
|
227
|
+
dm #update 0.450000 7.600000 8.05000 9.610320 531.26m
|
236
228
|
|
237
|
-
sequel #create 0.
|
238
|
-
sequel #select 0.
|
239
|
-
sequel #update 0.
|
229
|
+
sequel #create 0.670000 4.670000 5.34000 7.991811 235.39m
|
230
|
+
sequel #select 0.000000 0.130000 0.13000 0.178447 12.76m
|
231
|
+
sequel #update 0.790000 4.540000 5.33000 7.854936 229.70m
|
240
232
|
|
241
|
-
swift #create 0.
|
242
|
-
swift #select 0.000000 0.
|
243
|
-
swift #update 0.
|
233
|
+
swift #create 0.100000 0.710000 0.81000 1.562289 85.84m
|
234
|
+
swift #select 0.000000 0.120000 0.12000 0.145567 8.96m
|
235
|
+
swift #update 0.190000 0.690000 0.88000 1.628918 59.50m
|
244
236
|
|
245
237
|
-- bulk insert api --
|
246
|
-
swift #write 0.
|
238
|
+
swift #write 0.010000 0.100000 0.11000 0.180514 14.80m
|
247
239
|
|
248
240
|
|
249
241
|
==== Adapter
|
@@ -258,21 +250,20 @@ The adapter level SELECT benchmarks without using ORM.
|
|
258
250
|
===== PostgreSQL
|
259
251
|
|
260
252
|
benchmark sys user total real rss
|
261
|
-
do #select 0.
|
262
|
-
pg #select 0.
|
263
|
-
swift #select 0.
|
253
|
+
do #select 0.020000 1.250000 1.270000 1.441281 71.98m
|
254
|
+
pg #select 0.000000 0.580000 0.580000 0.769186 42.93m
|
255
|
+
swift #select 0.040000 0.510000 0.550000 0.627581 43.23m
|
264
256
|
|
265
257
|
===== MySQL
|
266
258
|
|
267
259
|
benchmark sys user total real rss
|
268
|
-
do #select 0.030000 1.
|
269
|
-
mysql2 #select 0.
|
270
|
-
swift #select 0.
|
260
|
+
do #select 0.030000 1.130000 1.160000 1.172205 71.86m
|
261
|
+
mysql2 #select 0.040000 0.660000 0.700000 0.704414 72.72m
|
262
|
+
swift #select 0.010000 0.480000 0.490000 0.499643 42.03m
|
271
263
|
|
272
264
|
== TODO
|
273
265
|
|
274
266
|
* More tests.
|
275
|
-
* Make db2 async api more stable.
|
276
267
|
* Assertions for dumb stuff.
|
277
268
|
* Abstract interface for other adapters? Move dbic++ to Swift::DBI::(Adapter, Pool, Result, Statment etc.)
|
278
269
|
|
@@ -280,3 +271,7 @@ The adapter level SELECT benchmarks without using ORM.
|
|
280
271
|
|
281
272
|
Go nuts! There is no style guide and I do not care if you write tests or comment code. If you write something neat just
|
282
273
|
send a pull request, tweet, email or yell it at me line by line in person.
|
274
|
+
|
275
|
+
== Feature suggestions and support
|
276
|
+
|
277
|
+
{Suggest features and support Swift ORM on fundry.}[https://fundry.com/project/14-swift-orm]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0
|
data/examples/db.rb
CHANGED
data/ext/adapter.cc
CHANGED
@@ -86,18 +86,14 @@ static VALUE adapter_execute(int argc, VALUE *argv, VALUE self) {
|
|
86
86
|
query.sql = CSTRING(statement);
|
87
87
|
query.handle = handle;
|
88
88
|
|
89
|
-
if (RARRAY_LEN(bind_values) > 0) query_bind_values(&query, bind_values
|
89
|
+
if (RARRAY_LEN(bind_values) > 0) query_bind_values(&query, bind_values);
|
90
90
|
if (dbi::_trace) dbi::logMessage(dbi::_trace_fd, dbi::formatParams(query.sql, query.bind));
|
91
91
|
|
92
92
|
if ((rows = rb_thread_blocking_region(((VALUE (*)(void*))query_execute), &query, RUBY_UBF_IO, 0)) == Qfalse)
|
93
93
|
rb_raise(eSwiftRuntimeError, "%s", query.error);
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
return result_each(result_wrap_handle(cSwiftResult, self, result, false));
|
98
|
-
}
|
99
|
-
else
|
100
|
-
return rows;
|
95
|
+
VALUE result = result_wrap_handle(cSwiftResult, self, handle->conn()->result(), true);
|
96
|
+
return rb_block_given_p() ? result_each(result) : result;
|
101
97
|
}
|
102
98
|
CATCH_DBI_EXCEPTIONS();
|
103
99
|
}
|
@@ -110,7 +106,7 @@ static VALUE adapter_initialize(VALUE self, VALUE options) {
|
|
110
106
|
if (NIL_P(db)) rb_raise(eSwiftArgumentError, "Adapter#new called without :db");
|
111
107
|
if (NIL_P(driver)) rb_raise(eSwiftArgumentError, "Adapter#new called without :driver");
|
112
108
|
|
113
|
-
user = NIL_P(user) ?
|
109
|
+
user = NIL_P(user) ? CURRENT_USER() : user;
|
114
110
|
|
115
111
|
try {
|
116
112
|
DATA_PTR(self) = new dbi::Handle(
|
@@ -215,11 +211,11 @@ static VALUE adapter_write(int argc, VALUE *argv, VALUE self) {
|
|
215
211
|
rb_gc();
|
216
212
|
|
217
213
|
if (TYPE(stream) == T_STRING) {
|
218
|
-
dbi::
|
214
|
+
dbi::StringIO io(RSTRING_PTR(stream), RSTRING_LEN(stream));
|
219
215
|
rows = handle->write(RSTRING_PTR(table), write_fields, &io);
|
220
216
|
}
|
221
217
|
else {
|
222
|
-
|
218
|
+
AdapterIO io(stream);
|
223
219
|
rows = handle->write(RSTRING_PTR(table), write_fields, &io);
|
224
220
|
}
|
225
221
|
return SIZET2NUM(rows);
|
@@ -227,15 +223,6 @@ static VALUE adapter_write(int argc, VALUE *argv, VALUE self) {
|
|
227
223
|
CATCH_DBI_EXCEPTIONS();
|
228
224
|
}
|
229
225
|
|
230
|
-
VALUE adapter_results(VALUE self) {
|
231
|
-
dbi::Handle *handle = adapter_handle(self);
|
232
|
-
try {
|
233
|
-
dbi::AbstractResult *result = handle->results();
|
234
|
-
return result_wrap_handle(cSwiftResult, self, result, false);
|
235
|
-
}
|
236
|
-
CATCH_DBI_EXCEPTIONS();
|
237
|
-
}
|
238
|
-
|
239
226
|
void init_swift_adapter() {
|
240
227
|
VALUE mSwift = rb_define_module("Swift");
|
241
228
|
cSwiftAdapter = rb_define_class_under(mSwift, "Adapter", rb_cObject);
|
@@ -254,9 +241,6 @@ void init_swift_adapter() {
|
|
254
241
|
rb_define_method(cSwiftAdapter, "write", RUBY_METHOD_FUNC(adapter_write), -1);
|
255
242
|
|
256
243
|
rb_define_alloc_func(cSwiftAdapter, adapter_alloc);
|
257
|
-
|
258
|
-
// TODO Figure out how to avoid race conditions.
|
259
|
-
rb_define_method(cSwiftAdapter, "results", RUBY_METHOD_FUNC(adapter_results), 0);
|
260
244
|
}
|
261
245
|
|
262
246
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
#include "
|
1
|
+
#include "adapter_io.h"
|
2
2
|
|
3
|
-
|
3
|
+
AdapterIO::AdapterIO(VALUE s) {
|
4
4
|
stream = s;
|
5
5
|
}
|
6
6
|
|
7
|
-
std::string&
|
7
|
+
std::string& AdapterIO::read() {
|
8
8
|
VALUE response = rb_funcall(stream, rb_intern("read"), 0);
|
9
9
|
if (response == Qnil) {
|
10
10
|
return empty;
|
@@ -17,12 +17,12 @@ std::string& IOStream::read() {
|
|
17
17
|
"Write can only process string data. You need to stringify values returned in the callback."
|
18
18
|
);
|
19
19
|
}
|
20
|
-
|
21
|
-
return
|
20
|
+
stringdata = std::string(RSTRING_PTR(response), RSTRING_LEN(response));
|
21
|
+
return stringdata;
|
22
22
|
}
|
23
23
|
}
|
24
24
|
|
25
|
-
uint32_t
|
25
|
+
uint32_t AdapterIO::read(char *buffer, uint32_t length) {
|
26
26
|
VALUE response = rb_funcall(stream, rb_intern("read"), 1, INT2NUM(length));
|
27
27
|
if (response == Qnil) {
|
28
28
|
return 0;
|
@@ -34,11 +34,29 @@ uint32_t IOStream::read(char *buffer, uint32_t length) {
|
|
34
34
|
}
|
35
35
|
}
|
36
36
|
|
37
|
-
void
|
37
|
+
void AdapterIO::write(const char *str) {
|
38
38
|
rb_funcall(stream, rb_intern("write"), 1, rb_str_new2(str));
|
39
39
|
}
|
40
40
|
|
41
|
-
void
|
41
|
+
void AdapterIO::write(const char *str, uint64_t l) {
|
42
42
|
rb_funcall(stream, rb_intern("write"), 1, rb_str_new(str, l));
|
43
43
|
}
|
44
44
|
|
45
|
+
bool AdapterIO::readline(std::string &line) {
|
46
|
+
VALUE response = rb_funcall(stream, rb_intern("gets"), 0);
|
47
|
+
if (response == Qnil) {
|
48
|
+
return false;
|
49
|
+
}
|
50
|
+
else {
|
51
|
+
line = std::string(RSTRING_PTR(response), RSTRING_LEN(response));
|
52
|
+
return true;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
char* AdapterIO::readline() {
|
57
|
+
return readline(stringdata) ? (char*)stringdata.c_str() : 0;
|
58
|
+
}
|
59
|
+
|
60
|
+
void AdapterIO::truncate() {
|
61
|
+
rb_funcall(stream, rb_intern("truncate"), 0);
|
62
|
+
}
|
data/ext/adapter_io.h
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#ifndef SWIFT_ADAPTER_IO_H
|
2
|
+
#define SWIFT_ADAPTER_IO_H
|
3
|
+
|
4
|
+
#include "swift.h"
|
5
|
+
|
6
|
+
class AdapterIO : public dbi::IO {
|
7
|
+
private:
|
8
|
+
VALUE stream;
|
9
|
+
std::string stringdata, empty;
|
10
|
+
public:
|
11
|
+
AdapterIO(VALUE);
|
12
|
+
std::string& read();
|
13
|
+
uint32_t read(char *, uint32_t);
|
14
|
+
|
15
|
+
void write(const char *);
|
16
|
+
void write(const char *, uint64_t);
|
17
|
+
|
18
|
+
void truncate();
|
19
|
+
|
20
|
+
bool readline(string&);
|
21
|
+
char* readline();
|
22
|
+
};
|
23
|
+
|
24
|
+
#endif
|
data/ext/extconf.rb
CHANGED
@@ -55,6 +55,6 @@ exit 1 unless library_installed? 'pcrecpp', apt_install_hint('libpcre3-dev')
|
|
55
55
|
exit 1 unless library_installed? 'uuid', apt_install_hint('uuid-dev')
|
56
56
|
exit 1 unless library_installed? 'dbic++', apt_install_hint('dbic++-dev')
|
57
57
|
|
58
|
-
assert_dbicpp_version '0.
|
58
|
+
assert_dbicpp_version '0.5.2'
|
59
59
|
|
60
60
|
create_makefile 'swift'
|
data/ext/pool.cc
CHANGED
@@ -26,7 +26,7 @@ VALUE pool_init(VALUE self, VALUE n, VALUE options) {
|
|
26
26
|
if (NIL_P(db)) rb_raise(eSwiftArgumentError, "Pool#new called without :db");
|
27
27
|
if (NIL_P(driver)) rb_raise(eSwiftArgumentError, "#new called without :driver");
|
28
28
|
|
29
|
-
user = NIL_P(user) ?
|
29
|
+
user = NIL_P(user) ? CURRENT_USER() : user;
|
30
30
|
if (NUM2INT(n) < 1) rb_raise(eSwiftArgumentError, "Pool#new called with invalid pool size.");
|
31
31
|
|
32
32
|
try {
|
@@ -76,7 +76,7 @@ VALUE pool_execute(int argc, VALUE *argv, VALUE self) {
|
|
76
76
|
|
77
77
|
try {
|
78
78
|
Query query;
|
79
|
-
query_bind_values(&query, bind_values
|
79
|
+
query_bind_values(&query, bind_values);
|
80
80
|
request = request_alloc(cSwiftRequest);
|
81
81
|
DATA_PTR(request) = pool->execute(CSTRING(sql), query.bind, pool_callback, (void*)callback);
|
82
82
|
return request;
|
data/ext/query.cc
CHANGED
@@ -31,7 +31,7 @@ VALUE query_execute_statement(Query *query) {
|
|
31
31
|
}
|
32
32
|
}
|
33
33
|
|
34
|
-
void query_bind_values(Query *query, VALUE bind_values
|
34
|
+
void query_bind_values(Query *query, VALUE bind_values) {
|
35
35
|
for (int i = 0; i < RARRAY_LEN(bind_values); i++) {
|
36
36
|
VALUE bind_value = rb_ary_entry(bind_values, i);
|
37
37
|
|
@@ -53,8 +53,7 @@ void query_bind_values(Query *query, VALUE bind_values, std::string driver) {
|
|
53
53
|
std::string timestamp = RSTRING_PTR(rb_funcall(bind_value, fstrftime, 1, dtformat));
|
54
54
|
|
55
55
|
timestamp += RSTRING_PTR(rb_funcall(rb_funcall(bind_value, fusec, 0), fto_s, 0));
|
56
|
-
|
57
|
-
timestamp += RSTRING_PTR(rb_funcall(bind_value, fstrftime, 1, tzformat));
|
56
|
+
timestamp += RSTRING_PTR(rb_funcall(bind_value, fstrftime, 1, tzformat));
|
58
57
|
|
59
58
|
query->bind.push_back(dbi::PARAM(timestamp));
|
60
59
|
}
|
data/ext/query.h
CHANGED
@@ -4,16 +4,16 @@
|
|
4
4
|
#include "swift.h"
|
5
5
|
|
6
6
|
struct Query {
|
7
|
-
char
|
8
|
-
dbi::Handle
|
9
|
-
dbi::AbstractStatement
|
10
|
-
dbi::
|
11
|
-
const char
|
7
|
+
char *sql;
|
8
|
+
dbi::Handle *handle;
|
9
|
+
dbi::AbstractStatement *statement;
|
10
|
+
std::vector<dbi::Param> bind;
|
11
|
+
const char *error;
|
12
12
|
};
|
13
13
|
|
14
14
|
VALUE query_execute(Query*);
|
15
15
|
VALUE query_execute_statement(Query*);
|
16
|
-
void query_bind_values(Query*, VALUE
|
16
|
+
void query_bind_values(Query*, VALUE);
|
17
17
|
void init_swift_query();
|
18
18
|
|
19
19
|
#endif
|
data/ext/result.cc
CHANGED
@@ -14,10 +14,7 @@ void result_mark(ResultWrapper *handle) {
|
|
14
14
|
|
15
15
|
void result_free(ResultWrapper *handle) {
|
16
16
|
if (handle) {
|
17
|
-
if (handle->free)
|
18
|
-
handle->result->cleanup();
|
19
|
-
delete handle->result;
|
20
|
-
}
|
17
|
+
if (handle->free) delete handle->result;
|
21
18
|
delete handle;
|
22
19
|
}
|
23
20
|
}
|
@@ -99,14 +96,6 @@ VALUE result_each(VALUE self) {
|
|
99
96
|
return Qnil;
|
100
97
|
}
|
101
98
|
|
102
|
-
static VALUE result_finish(VALUE self) {
|
103
|
-
dbi::AbstractResult *result = result_handle(self);
|
104
|
-
try {
|
105
|
-
result->finish();
|
106
|
-
}
|
107
|
-
CATCH_DBI_EXCEPTIONS();
|
108
|
-
}
|
109
|
-
|
110
99
|
// Calculates local offset at a given time, including dst.
|
111
100
|
int64_t client_tzoffset(int64_t local, int isdst) {
|
112
101
|
struct tm tm;
|
@@ -296,7 +285,6 @@ void init_swift_result() {
|
|
296
285
|
rb_define_method(cSwiftResult, "clone", RUBY_METHOD_FUNC(result_clone), 0);
|
297
286
|
rb_define_method(cSwiftResult, "dup", RUBY_METHOD_FUNC(result_dup), 0);
|
298
287
|
rb_define_method(cSwiftResult, "each", RUBY_METHOD_FUNC(result_each), 0);
|
299
|
-
rb_define_method(cSwiftResult, "finish", RUBY_METHOD_FUNC(result_finish), 0);
|
300
288
|
rb_define_method(cSwiftResult, "insert_id", RUBY_METHOD_FUNC(result_insert_id), 0);
|
301
289
|
rb_define_method(cSwiftResult, "rows", RUBY_METHOD_FUNC(result_rows), 0);
|
302
290
|
rb_define_method(cSwiftResult, "columns", RUBY_METHOD_FUNC(result_columns), 0);
|
data/ext/statement.cc
CHANGED
@@ -12,10 +12,7 @@ void statement_mark(StatementWrapper *handle) {
|
|
12
12
|
|
13
13
|
void statement_free(StatementWrapper *handle) {
|
14
14
|
if (handle) {
|
15
|
-
if (handle->free)
|
16
|
-
handle->statement->cleanup();
|
17
|
-
delete handle->statement;
|
18
|
-
}
|
15
|
+
if (handle->free) delete handle->statement;
|
19
16
|
delete handle;
|
20
17
|
}
|
21
18
|
}
|
@@ -55,7 +52,7 @@ static VALUE statement_execute(int argc, VALUE *argv, VALUE self) {
|
|
55
52
|
try {
|
56
53
|
Query query;
|
57
54
|
query.statement = statement;
|
58
|
-
if (RARRAY_LEN(bind_values) > 0) query_bind_values(&query, bind_values
|
55
|
+
if (RARRAY_LEN(bind_values) > 0) query_bind_values(&query, bind_values);
|
59
56
|
if (dbi::_trace) dbi::logMessage(dbi::_trace_fd, dbi::formatParams(statement->command(), query.bind));
|
60
57
|
|
61
58
|
if (rb_thread_blocking_region(((VALUE (*)(void*))query_execute_statement), &query, RUBY_UBF_IO, 0) == Qfalse)
|
@@ -63,8 +60,22 @@ static VALUE statement_execute(int argc, VALUE *argv, VALUE self) {
|
|
63
60
|
}
|
64
61
|
CATCH_DBI_EXCEPTIONS();
|
65
62
|
|
66
|
-
|
67
|
-
|
63
|
+
StatementWrapper *handle;
|
64
|
+
Data_Get_Struct(self, StatementWrapper, handle);
|
65
|
+
|
66
|
+
VALUE result = result_wrap_handle(cSwiftResult, handle->adapter, statement->result(), true);
|
67
|
+
rb_iv_set(result, "@scheme", rb_iv_get(self, "@scheme"));
|
68
|
+
|
69
|
+
return rb_block_given_p() ? result_each(result) : result;
|
70
|
+
}
|
71
|
+
|
72
|
+
VALUE statement_insert_id(VALUE self) {
|
73
|
+
dbi::AbstractStatement *statement = statement_handle(self);
|
74
|
+
try {
|
75
|
+
return SIZET2NUM(statement->lastInsertID());
|
76
|
+
}
|
77
|
+
CATCH_DBI_EXCEPTIONS();
|
78
|
+
return Qnil;
|
68
79
|
}
|
69
80
|
|
70
81
|
VALUE statement_initialize(VALUE self, VALUE adapter, VALUE sql) {
|
@@ -90,23 +101,9 @@ VALUE statement_initialize(VALUE self, VALUE adapter, VALUE sql) {
|
|
90
101
|
void init_swift_statement() {
|
91
102
|
VALUE mSwift = rb_define_module("Swift");
|
92
103
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
dbi::Statement < dbi::AbstractStatement
|
98
|
-
dbi::AbstractStatement < dbi::AbstractResult
|
99
|
-
|
100
|
-
Swift has this,
|
101
|
-
Statement < Result
|
102
|
-
|
103
|
-
Not sure if this hierarchy is correct or perfect. I reckon Statement should not
|
104
|
-
inherit Result and just return a Result on execute() - maybe cleaner but very
|
105
|
-
inefficient when doing tons on non-select style queries.
|
106
|
-
*/
|
107
|
-
|
108
|
-
cSwiftStatement = rb_define_class_under(mSwift, "Statement", cSwiftResult);
|
109
|
-
rb_define_method(cSwiftStatement, "execute", RUBY_METHOD_FUNC(statement_execute), -1);
|
110
|
-
rb_define_method(cSwiftStatement, "initialize", RUBY_METHOD_FUNC(statement_initialize), 2);
|
104
|
+
cSwiftStatement = rb_define_class_under(mSwift, "Statement", rb_cObject);
|
105
|
+
rb_define_method(cSwiftStatement, "execute", RUBY_METHOD_FUNC(statement_execute), -1);
|
106
|
+
rb_define_method(cSwiftStatement, "initialize", RUBY_METHOD_FUNC(statement_initialize), 2);
|
107
|
+
rb_define_method(cSwiftStatement, "insert_id", RUBY_METHOD_FUNC(statement_insert_id), 0);
|
111
108
|
rb_define_alloc_func(cSwiftStatement, statement_alloc);
|
112
109
|
}
|
data/ext/swift.h
CHANGED
@@ -5,6 +5,9 @@
|
|
5
5
|
#include <ruby/ruby.h>
|
6
6
|
#include <ruby/io.h>
|
7
7
|
#include <stdint.h>
|
8
|
+
#include <unistd.h>
|
9
|
+
#include <sys/types.h>
|
10
|
+
#include <pwd.h>
|
8
11
|
|
9
12
|
#define CONST_GET(scope, constant) rb_funcall(scope, rb_intern("const_get"), 1, rb_str_new2(constant))
|
10
13
|
#define TO_S(v) rb_funcall(v, rb_intern("to_s"), 0)
|
@@ -26,8 +29,15 @@ extern VALUE eSwiftConnectionError;
|
|
26
29
|
rb_raise(rb_eNoMemError, "%s", error.what()); \
|
27
30
|
}
|
28
31
|
|
32
|
+
|
33
|
+
// works without a controlling tty, getlogin() will fail when process is daemonized.
|
34
|
+
inline VALUE CURRENT_USER() {
|
35
|
+
struct passwd *ptr = getpwuid(getuid());
|
36
|
+
return ptr ? rb_str_new2(ptr->pw_name) : rb_str_new2("root");
|
37
|
+
}
|
38
|
+
|
29
39
|
#include "adapter.h"
|
30
|
-
#include "
|
40
|
+
#include "adapter_io.h"
|
31
41
|
#include "query.h"
|
32
42
|
#include "result.h"
|
33
43
|
#include "statement.h"
|
data/lib/swift/db.rb
CHANGED
@@ -10,64 +10,55 @@ module Swift
|
|
10
10
|
end
|
11
11
|
end # Mysql
|
12
12
|
|
13
|
-
class
|
13
|
+
class Sqlite3 < Adapter
|
14
14
|
def initialize options = {}
|
15
|
-
super options.update(driver: '
|
15
|
+
super options.update(driver: 'sqlite3')
|
16
16
|
end
|
17
17
|
|
18
18
|
def returning?
|
19
|
-
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def migrate! scheme
|
23
|
+
keys = scheme.header.keys
|
24
|
+
serial = scheme.header.find(&:serial)
|
25
|
+
fields = scheme.header.map{|p| field_definition(p)}.join(', ')
|
26
|
+
fields += ", primary key (#{keys.join(', ')})" unless serial or keys.empty?
|
27
|
+
|
28
|
+
execute("drop table if exists #{scheme.store}")
|
29
|
+
execute("create table #{scheme.store} (#{fields})")
|
20
30
|
end
|
21
31
|
|
22
32
|
def field_type attribute
|
23
33
|
case attribute
|
24
|
-
when Type::
|
25
|
-
|
34
|
+
when Type::String then 'text'
|
35
|
+
when Type::Integer then attribute.serial ? 'integer primary key' : 'integer'
|
36
|
+
when Type::Float then 'float'
|
37
|
+
when Type::BigDecimal then 'numeric'
|
38
|
+
when Type::Time then 'timestamp'
|
39
|
+
when Type::Date then 'date'
|
40
|
+
when Type::Boolean then 'boolean'
|
41
|
+
when Type::IO then 'blob'
|
42
|
+
else 'text'
|
26
43
|
end
|
27
44
|
end
|
28
|
-
end #
|
45
|
+
end # Sqlite3
|
29
46
|
|
30
|
-
class
|
47
|
+
class Postgres < Adapter
|
31
48
|
def initialize options = {}
|
32
|
-
super options.update(driver: '
|
49
|
+
super options.update(driver: 'postgresql')
|
33
50
|
end
|
34
51
|
|
35
52
|
def returning?
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
def migrate!
|
40
|
-
keys = scheme.header.keys
|
41
|
-
fields = scheme.header.map{|p| field_definition(p)}.join(', ')
|
42
|
-
fields += ", primary key (#{keys.join(', ')})" unless keys.empty?
|
43
|
-
|
44
|
-
sql = <<-SQL
|
45
|
-
select count(*) as exists from syscat.tables
|
46
|
-
where tabschema = CURRENT_SCEMA and tabname = '#{scheme.store.upcase}'
|
47
|
-
SQL
|
48
|
-
|
49
|
-
execute(sql) {|result| execute("drop table #{scheme.store}") if result[:exists] > 0 }
|
50
|
-
execute("create table #{scheme.store} (#{fields})")
|
53
|
+
true
|
51
54
|
end
|
52
55
|
|
53
56
|
def field_type attribute
|
54
57
|
case attribute
|
55
|
-
when Type::
|
56
|
-
when Type::Integer then attribute.serial ? 'integer not null generated by default as identity' : 'integer'
|
57
|
-
when Type::Boolean then 'char(1)'
|
58
|
-
when Type::Float then 'real'
|
59
|
-
when Type::BigDecimal then 'double'
|
58
|
+
when Type::IO then 'bytea'
|
60
59
|
else super
|
61
60
|
end
|
62
61
|
end
|
63
|
-
|
64
|
-
def prepare_create scheme
|
65
|
-
prepare_cached(scheme, :create) do
|
66
|
-
values = (['?'] * scheme.header.insertable.size).join(', ')
|
67
|
-
sql = "insert into #{scheme.store} (#{scheme.header.insertable.join(', ')}) values (#{values})"
|
68
|
-
scheme.header.serial ? "select #{scheme.header.serial} from final table (#{sql})" : sql
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end # DB2
|
62
|
+
end # Postgres
|
72
63
|
end # DB
|
73
64
|
end # Swift
|
data/lib/swift/pool.rb
CHANGED
@@ -27,9 +27,8 @@ module Swift
|
|
27
27
|
def initialize size, options
|
28
28
|
@pool = Swift::DB::Pool.new size, options
|
29
29
|
|
30
|
-
#
|
31
|
-
@writable =
|
32
|
-
|
30
|
+
# used to be used for db2
|
31
|
+
@writable = false
|
33
32
|
@pending = {}
|
34
33
|
@queue = []
|
35
34
|
end
|
@@ -52,10 +51,7 @@ module Swift
|
|
52
51
|
|
53
52
|
def execute sql, *bind, &callback
|
54
53
|
request = @pool.execute sql, *bind, &callback
|
55
|
-
#
|
56
|
-
# This is somehow causing everything to unravel and result in a segfault which
|
57
|
-
# I cannot track down. I'll buy a beer for someone who can get this fixed :)
|
58
|
-
# Oh, here it throws an exception if we try to attach same fd twice.
|
54
|
+
# NOTE EM segfaults if we try to attach same fd twice.
|
59
55
|
if request && !attached?(request.socket)
|
60
56
|
EM.watch(request.socket, Handler, request, self) do |c|
|
61
57
|
attach c
|
data/swift.gemspec
CHANGED
@@ -1,101 +1,100 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{swift}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Shane Hanna", "Bharanee 'Barney' Rathna"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-05}
|
13
13
|
s.description = %q{A rational rudimentary database abstraction.}
|
14
14
|
s.email = ["shane.hanna@gmail.com", "deepfryed@gmail.com"]
|
15
15
|
s.extensions = ["ext/extconf.rb"]
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"LICENSE",
|
18
|
-
|
18
|
+
"README.rdoc"
|
19
19
|
]
|
20
20
|
s.files = [
|
21
21
|
"API.rdoc",
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"ext/adapter.cc",
|
27
|
+
"ext/adapter.h",
|
28
|
+
"ext/adapter_io.cc",
|
29
|
+
"ext/adapter_io.h",
|
30
|
+
"ext/attribute.cc",
|
31
|
+
"ext/attribute.h",
|
32
|
+
"ext/extconf.rb",
|
33
|
+
"ext/pool.cc",
|
34
|
+
"ext/pool.h",
|
35
|
+
"ext/query.cc",
|
36
|
+
"ext/query.h",
|
37
|
+
"ext/request.cc",
|
38
|
+
"ext/request.h",
|
39
|
+
"ext/result.cc",
|
40
|
+
"ext/result.h",
|
41
|
+
"ext/statement.cc",
|
42
|
+
"ext/statement.h",
|
43
|
+
"ext/swift.cc",
|
44
|
+
"ext/swift.h",
|
45
|
+
"lib/swift.rb",
|
46
|
+
"lib/swift/adapter.rb",
|
47
|
+
"lib/swift/attribute.rb",
|
48
|
+
"lib/swift/db.rb",
|
49
|
+
"lib/swift/header.rb",
|
50
|
+
"lib/swift/identity_map.rb",
|
51
|
+
"lib/swift/migrations.rb",
|
52
|
+
"lib/swift/pool.rb",
|
53
|
+
"lib/swift/scheme.rb",
|
54
|
+
"lib/swift/type.rb",
|
55
|
+
"lib/swift/validations.rb",
|
56
|
+
"swift.gemspec",
|
57
|
+
"test/helper.rb",
|
58
|
+
"test/house-explode.jpg",
|
59
|
+
"test/test_adapter.rb",
|
60
|
+
"test/test_encoding.rb",
|
61
|
+
"test/test_error.rb",
|
62
|
+
"test/test_identity_map.rb",
|
63
|
+
"test/test_io.rb",
|
64
|
+
"test/test_pool.rb",
|
65
|
+
"test/test_scheme.rb",
|
66
|
+
"test/test_timestamps.rb",
|
67
|
+
"test/test_transactions.rb",
|
68
|
+
"test/test_types.rb",
|
69
|
+
"test/test_validations.rb"
|
70
70
|
]
|
71
71
|
s.homepage = %q{http://github.com/shanna/swift}
|
72
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
73
72
|
s.require_paths = ["lib"]
|
74
|
-
s.rubygems_version = %q{1.3.
|
73
|
+
s.rubygems_version = %q{1.3.7}
|
75
74
|
s.summary = %q{A rational rudimentary database abstraction.}
|
76
75
|
s.test_files = [
|
76
|
+
"examples/async.rb",
|
77
|
+
"examples/db.rb",
|
78
|
+
"examples/scheme.rb",
|
79
|
+
"test/helper.rb",
|
77
80
|
"test/test_adapter.rb",
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
"test/test_pool.rb",
|
89
|
-
"examples/async.rb",
|
90
|
-
"examples/scheme.rb",
|
91
|
-
"examples/db.rb"
|
81
|
+
"test/test_encoding.rb",
|
82
|
+
"test/test_error.rb",
|
83
|
+
"test/test_identity_map.rb",
|
84
|
+
"test/test_io.rb",
|
85
|
+
"test/test_pool.rb",
|
86
|
+
"test/test_scheme.rb",
|
87
|
+
"test/test_timestamps.rb",
|
88
|
+
"test/test_transactions.rb",
|
89
|
+
"test/test_types.rb",
|
90
|
+
"test/test_validations.rb"
|
92
91
|
]
|
93
92
|
|
94
93
|
if s.respond_to? :specification_version then
|
95
94
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
96
95
|
s.specification_version = 3
|
97
96
|
|
98
|
-
if Gem::Version.new(Gem::
|
97
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
99
98
|
s.add_development_dependency(%q<minitest>, [">= 1.7.0"])
|
100
99
|
s.add_development_dependency(%q<eventmachine>, [">= 0"])
|
101
100
|
else
|
data/test/helper.rb
CHANGED
@@ -5,22 +5,21 @@ require 'minitest/unit'
|
|
5
5
|
require 'swift'
|
6
6
|
require 'etc'
|
7
7
|
|
8
|
-
# db2 database name is limited to 8 characters, gonna use swift instead of swift_test
|
9
|
-
|
10
8
|
class MiniTest::Spec
|
11
9
|
def self.supported_by *adapters, &block
|
12
|
-
|
10
|
+
adapter_defaults = { Swift::DB::Sqlite3 => { db: ':memory:' } }
|
11
|
+
connection_defaults = { db: 'swift_test', user: Etc.getlogin, host: '127.0.0.1' }
|
13
12
|
adapters.each do |adapter|
|
14
13
|
begin
|
15
|
-
Swift.setup :default, adapter, connection_defaults
|
14
|
+
Swift.setup :default, adapter, connection_defaults.merge(adapter_defaults.fetch(adapter, {}))
|
16
15
|
rescue => error
|
17
|
-
warn "Unable to setup '
|
16
|
+
warn "Unable to setup 'swift_test' db for #{adapter}, #{error.message}. Skipping..."
|
18
17
|
next
|
19
18
|
end
|
20
19
|
|
21
20
|
describe("Adapter #{adapter.name}") do
|
22
21
|
before do
|
23
|
-
Swift.setup :default, adapter, connection_defaults
|
22
|
+
Swift.setup :default, adapter, connection_defaults.merge(adapter_defaults.fetch(adapter, {}))
|
24
23
|
end
|
25
24
|
block.call(adapter)
|
26
25
|
end
|
data/test/test_adapter.rb
CHANGED
@@ -2,16 +2,16 @@ require_relative 'helper'
|
|
2
2
|
require 'stringio'
|
3
3
|
|
4
4
|
describe 'Adapter' do
|
5
|
-
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::
|
5
|
+
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::Sqlite3 do
|
6
6
|
describe 'db' do
|
7
7
|
before do
|
8
8
|
@db = Swift.db
|
9
|
-
@db.execute('drop table users')
|
10
|
-
|
11
|
-
when Swift::DB::
|
9
|
+
@db.execute('drop table if exists users')
|
10
|
+
serial = case @db
|
11
|
+
when Swift::DB::Sqlite3 then 'integer primary key'
|
12
12
|
else 'serial'
|
13
13
|
end
|
14
|
-
@db.execute %Q{create table users(id #{
|
14
|
+
@db.execute %Q{create table users(id #{serial}, name text, email text, created_at timestamp)}
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'yields db to block' do
|
@@ -34,7 +34,7 @@ describe 'Adapter' do
|
|
34
34
|
it 'executes via Statement#new' do
|
35
35
|
result = []
|
36
36
|
Swift::Statement.new(@db, 'select count(*) as n from users').execute {|r| result << r[:n] }
|
37
|
-
assert_kind_of
|
37
|
+
assert_kind_of Fixnum, result[0]
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'executes without bind values' do
|
@@ -54,10 +54,9 @@ describe 'Adapter' do
|
|
54
54
|
it 'has insert_id' do
|
55
55
|
sql = case @db
|
56
56
|
when Swift::DB::Postgres then %q{insert into users (name) values (?) returning id}
|
57
|
-
|
58
|
-
when Swift::DB::DB2 then %q{select id from final table(insert into users(name) values(?))}
|
57
|
+
else %q{insert into users (name) values (?)}
|
59
58
|
end
|
60
|
-
assert_kind_of
|
59
|
+
assert_kind_of Fixnum, @db.prepare(sql).execute('Connie Arthurton').insert_id
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
@@ -66,11 +65,12 @@ describe 'Adapter' do
|
|
66
65
|
insert = @db.prepare(%q{insert into users (name, created_at) values (?, current_timestamp)})
|
67
66
|
insert.execute('Apple Arthurton')
|
68
67
|
insert.execute('Benny Arthurton')
|
69
|
-
@sth = @db.prepare('select * from users')
|
68
|
+
@sth = @db.prepare('select * from users')
|
69
|
+
@res = @sth.execute
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'enumerates' do
|
73
|
-
assert_kind_of Enumerable, @
|
73
|
+
assert_kind_of Enumerable, @res
|
74
74
|
end
|
75
75
|
|
76
76
|
it 'enumerates block' do
|
@@ -84,7 +84,7 @@ describe 'Adapter' do
|
|
84
84
|
end
|
85
85
|
|
86
86
|
it 'returns hash tuples for enumerable methods' do
|
87
|
-
assert_kind_of Hash, @
|
87
|
+
assert_kind_of Hash, @res.first
|
88
88
|
end
|
89
89
|
|
90
90
|
it 'returns a result set on Adapter#execute{}' do
|
@@ -92,12 +92,11 @@ describe 'Adapter' do
|
|
92
92
|
end
|
93
93
|
|
94
94
|
it 'returns a result set on Adapter#results' do
|
95
|
-
@db.execute('select * from users')
|
96
|
-
assert_kind_of Swift::Result, @db.results
|
95
|
+
assert_kind_of Swift::Result, @db.execute('select * from users')
|
97
96
|
end
|
98
97
|
|
99
98
|
it 'returns fields' do
|
100
|
-
assert_equal [ :id, :name, :email, :created_at ], @
|
99
|
+
assert_equal [ :id, :name, :email, :created_at ], @res.fields
|
101
100
|
end
|
102
101
|
end
|
103
102
|
|
data/test/test_encoding.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
describe 'Adapter' do
|
4
|
-
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::
|
4
|
+
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::Sqlite3 do
|
5
5
|
describe 'character encoding' do
|
6
6
|
before do
|
7
7
|
Swift.db do |db|
|
8
|
-
db.execute %q{drop table users}
|
9
|
-
db.execute %q{create table users(name
|
8
|
+
db.execute %q{drop table if exists users}
|
9
|
+
db.execute %q{create table users(name text)}
|
10
10
|
|
11
11
|
# Mysql on debian at least doesn't default to utf8.
|
12
12
|
if db.kind_of? Swift::DB::Mysql
|
data/test/test_error.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
describe 'Error' do
|
4
|
-
supported_by Swift::DB::Postgres, Swift::DB::Mysql do
|
4
|
+
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::Sqlite3 do
|
5
5
|
describe 'prepare' do
|
6
6
|
before do
|
7
7
|
Swift.db do |db|
|
8
8
|
db.execute %q{drop table if exists users}
|
9
|
-
db.execute %q{create table users(id
|
9
|
+
db.execute %q{create table users(id integer, name text, primary key(id))}
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
data/test/test_io.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
describe 'Adapter' do
|
4
|
-
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::
|
4
|
+
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::Sqlite3 do
|
5
5
|
describe 'Storing binary objects' do
|
6
6
|
before do
|
7
7
|
user = Class.new(Swift::Scheme) do
|
@@ -13,7 +13,7 @@ describe 'Adapter' do
|
|
13
13
|
Swift.db.migrate! user
|
14
14
|
end
|
15
15
|
|
16
|
-
it 'stores and retrieves an image' do
|
16
|
+
it 'stores and retrieves an image via prepared statement' do
|
17
17
|
Swift.db do |db|
|
18
18
|
io = File.open(File.dirname(__FILE__) + '/house-explode.jpg')
|
19
19
|
db.prepare('insert into users (name, image) values(?, ?)').execute('test', io)
|
@@ -28,6 +28,22 @@ describe 'Adapter' do
|
|
28
28
|
assert_equal io.read.force_encoding('ASCII-8BIT'), data
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
it 'stores and retrieves an image via Adapter#execute' do
|
33
|
+
Swift.db do |db|
|
34
|
+
io = File.open(File.dirname(__FILE__) + '/house-explode.jpg')
|
35
|
+
db.execute('insert into users (name, image) values(?, ?)', 'test', io)
|
36
|
+
|
37
|
+
blob = db.prepare('select image from users limit 1').execute.first[:image]
|
38
|
+
|
39
|
+
io.rewind
|
40
|
+
assert_kind_of StringIO, blob
|
41
|
+
|
42
|
+
data = blob.read
|
43
|
+
assert_equal Encoding::ASCII_8BIT, data.encoding
|
44
|
+
assert_equal io.read.force_encoding('ASCII-8BIT'), data
|
45
|
+
end
|
46
|
+
end
|
31
47
|
end
|
32
48
|
end
|
33
49
|
end
|
data/test/test_pool.rb
CHANGED
data/test/test_timestamps.rb
CHANGED
data/test/test_transactions.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
describe 'Adapter' do
|
4
|
-
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::
|
4
|
+
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::Sqlite3 do
|
5
5
|
describe 'transactions' do
|
6
6
|
before do
|
7
7
|
@name = 'test1 - transaction 1'
|
8
8
|
@db = Swift.db
|
9
|
-
@db.execute %q{drop table users}
|
10
|
-
@db.execute %q{create table users(name
|
11
|
-
|
9
|
+
@db.execute %q{drop table if exists users}
|
10
|
+
@db.execute %q{create table users(name text, created_at timestamp)}
|
11
|
+
|
12
|
+
# In case of MyISAM default.
|
13
|
+
@db.kind_of?(Swift::DB::Mysql) && @db.execute('alter table users engine=innodb')
|
14
|
+
|
12
15
|
@sth = @db.prepare('select count(*) as c from users where name = ?')
|
13
16
|
end
|
14
17
|
|
@@ -24,7 +27,7 @@ describe 'Adapter' do
|
|
24
27
|
|
25
28
|
describe 'commits work' do
|
26
29
|
before do
|
27
|
-
@db.execute('
|
30
|
+
@db.execute('delete from users')
|
28
31
|
end
|
29
32
|
|
30
33
|
after do
|
@@ -47,7 +50,7 @@ describe 'Adapter' do
|
|
47
50
|
|
48
51
|
describe 'rollbacks work' do
|
49
52
|
before do
|
50
|
-
@db.execute('
|
53
|
+
@db.execute('delete from users')
|
51
54
|
end
|
52
55
|
|
53
56
|
after do
|
@@ -73,7 +76,7 @@ describe 'Adapter' do
|
|
73
76
|
|
74
77
|
describe 'nested transactions' do
|
75
78
|
before do
|
76
|
-
@db.execute('
|
79
|
+
@db.execute('delete from users')
|
77
80
|
end
|
78
81
|
|
79
82
|
after do
|
data/test/test_types.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
describe 'Adapter' do
|
4
|
-
supported_by Swift::DB::Postgres, Swift::DB::Mysql do
|
4
|
+
supported_by Swift::DB::Postgres, Swift::DB::Mysql, Swift::DB::Sqlite3 do
|
5
5
|
describe 'typecasting' do
|
6
6
|
before do
|
7
7
|
@db = Swift.db
|
8
8
|
@db.execute %q{drop table if exists users}
|
9
|
-
@db
|
9
|
+
serial = case @db
|
10
|
+
when Swift::DB::Sqlite3 then 'integer primary key'
|
11
|
+
else 'serial'
|
12
|
+
end
|
13
|
+
@db.execute %Q{
|
10
14
|
create table users(
|
11
|
-
id serial,
|
15
|
+
id #{serial},
|
12
16
|
name text,
|
13
17
|
age integer,
|
14
18
|
height float,
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 8
|
8
|
+
- 0
|
9
|
+
version: 0.8.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Shane Hanna
|
@@ -15,13 +15,14 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-05 00:00:00 +11:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: minitest
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
@@ -36,6 +37,7 @@ dependencies:
|
|
36
37
|
name: eventmachine
|
37
38
|
prerelease: false
|
38
39
|
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
39
41
|
requirements:
|
40
42
|
- - ">="
|
41
43
|
- !ruby/object:Gem::Version
|
@@ -63,11 +65,11 @@ files:
|
|
63
65
|
- VERSION
|
64
66
|
- ext/adapter.cc
|
65
67
|
- ext/adapter.h
|
68
|
+
- ext/adapter_io.cc
|
69
|
+
- ext/adapter_io.h
|
66
70
|
- ext/attribute.cc
|
67
71
|
- ext/attribute.h
|
68
72
|
- ext/extconf.rb
|
69
|
-
- ext/iostream.cc
|
70
|
-
- ext/iostream.h
|
71
73
|
- ext/pool.cc
|
72
74
|
- ext/pool.h
|
73
75
|
- ext/query.cc
|
@@ -105,16 +107,20 @@ files:
|
|
105
107
|
- test/test_transactions.rb
|
106
108
|
- test/test_types.rb
|
107
109
|
- test/test_validations.rb
|
110
|
+
- examples/async.rb
|
111
|
+
- examples/db.rb
|
112
|
+
- examples/scheme.rb
|
108
113
|
has_rdoc: true
|
109
114
|
homepage: http://github.com/shanna/swift
|
110
115
|
licenses: []
|
111
116
|
|
112
117
|
post_install_message:
|
113
|
-
rdoc_options:
|
114
|
-
|
118
|
+
rdoc_options: []
|
119
|
+
|
115
120
|
require_paths:
|
116
121
|
- lib
|
117
122
|
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
118
124
|
requirements:
|
119
125
|
- - ">="
|
120
126
|
- !ruby/object:Gem::Version
|
@@ -122,6 +128,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
128
|
- 0
|
123
129
|
version: "0"
|
124
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
125
132
|
requirements:
|
126
133
|
- - ">="
|
127
134
|
- !ruby/object:Gem::Version
|
@@ -131,23 +138,23 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
138
|
requirements: []
|
132
139
|
|
133
140
|
rubyforge_project:
|
134
|
-
rubygems_version: 1.3.
|
141
|
+
rubygems_version: 1.3.7
|
135
142
|
signing_key:
|
136
143
|
specification_version: 3
|
137
144
|
summary: A rational rudimentary database abstraction.
|
138
145
|
test_files:
|
146
|
+
- examples/async.rb
|
147
|
+
- examples/db.rb
|
148
|
+
- examples/scheme.rb
|
149
|
+
- test/helper.rb
|
139
150
|
- test/test_adapter.rb
|
140
|
-
- test/
|
141
|
-
- test/test_types.rb
|
151
|
+
- test/test_encoding.rb
|
142
152
|
- test/test_error.rb
|
153
|
+
- test/test_identity_map.rb
|
143
154
|
- test/test_io.rb
|
144
|
-
- test/
|
155
|
+
- test/test_pool.rb
|
156
|
+
- test/test_scheme.rb
|
157
|
+
- test/test_timestamps.rb
|
145
158
|
- test/test_transactions.rb
|
159
|
+
- test/test_types.rb
|
146
160
|
- test/test_validations.rb
|
147
|
-
- test/test_timestamps.rb
|
148
|
-
- test/helper.rb
|
149
|
-
- test/test_identity_map.rb
|
150
|
-
- test/test_pool.rb
|
151
|
-
- examples/async.rb
|
152
|
-
- examples/scheme.rb
|
153
|
-
- examples/db.rb
|
data/ext/iostream.h
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
#ifndef SWIFT_IOSTREAM_H
|
2
|
-
#define SWIFT_IOSTREAM_H
|
3
|
-
|
4
|
-
#include "swift.h"
|
5
|
-
|
6
|
-
class IOStream : public dbi::IOStream {
|
7
|
-
private:
|
8
|
-
VALUE stream;
|
9
|
-
public:
|
10
|
-
IOStream(VALUE);
|
11
|
-
std::string& read();
|
12
|
-
uint32_t read(char *, uint32_t);
|
13
|
-
void write(const char *);
|
14
|
-
void write(const char *, uint64_t);
|
15
|
-
};
|
16
|
-
|
17
|
-
#endif
|