swift 0.7.2 → 0.8.0
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/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
|