swift 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/swift.cc CHANGED
@@ -1,573 +1,30 @@
1
- #include <dbic++.h>
2
- #include <ruby/ruby.h>
3
- #include <ruby/io.h>
4
- #include <time.h>
5
- #include <unistd.h>
6
-
7
- #define CONST_GET(scope, constant) rb_const_get(scope, rb_intern(constant))
1
+ #include "swift.h"
8
2
 
9
3
  static VALUE mSwift;
10
- static VALUE cAdapter;
11
- static VALUE cStatement;
12
- static VALUE cResultSet;
13
- static VALUE cPool;
14
- static VALUE cRequest;
15
- static VALUE cBigDecimal;
16
- static VALUE cStringIO;
17
-
18
- static VALUE eRuntimeError;
19
- static VALUE eArgumentError;
20
- static VALUE eStandardError;
21
- static VALUE eConnectionError;
22
-
23
- static VALUE fLoad;
24
- static VALUE fStringify;
25
- static VALUE fNew;
26
- static VALUE fRead;
27
- static VALUE fWrite;
28
-
29
- size_t tzoffset;
30
- char errstr[8192];
31
-
32
- #define CSTRING(v) RSTRING_PTR(TYPE(v) == T_STRING ? v : rb_funcall(v, fStringify, 0))
33
- #define OBJ2STRING(v) (TYPE(v) == T_STRING ? v : rb_funcall(v, fStringify, 0))
34
-
35
- #define EXCEPTION(type) (dbi::ConnectionError &e) { \
36
- snprintf(errstr, 4096, "%s", e.what()); \
37
- rb_raise(eConnectionError, "%s : %s", type, errstr); \
38
- } \
39
- catch (dbi::Error &e) {\
40
- snprintf(errstr, 4096, "%s", e.what()); \
41
- rb_raise(eRuntimeError, "%s : %s", type, errstr); \
42
- }
43
-
44
-
45
- class IOStream : public dbi::IOStream {
46
- private:
47
- string empty, data;
48
- VALUE stream;
49
- public:
50
- IOStream(VALUE s) {
51
- stream = s;
52
- }
53
- string& read() {
54
- VALUE response = rb_funcall(stream, fRead, 0);
55
- if (response == Qnil)
56
- return empty;
57
- else {
58
- if (TYPE(response) != T_STRING)
59
- rb_raise(eArgumentError,
60
- "Adapter#write can only process string data. You need to stringify values returned in the callback.");
61
- data = string(RSTRING_PTR(response), RSTRING_LEN(response));
62
- return data;
63
- }
64
- }
65
-
66
- uint read(char *buffer, uint len) {
67
- VALUE response = rb_funcall(stream, fRead, 1, INT2NUM(len));
68
- if (response == Qnil)
69
- return 0;
70
- else {
71
- len = len < RSTRING_LEN(response) ? len : RSTRING_LEN(response);
72
- memcpy(buffer, RSTRING_PTR(response), len);
73
- return len;
74
- }
75
- }
76
-
77
- void write(const char *str) {
78
- rb_funcall(stream, fWrite, 1, rb_str_new2(str));
79
- }
80
- void write(const char *str, ulong l) {
81
- rb_funcall(stream, fWrite, 1, rb_str_new(str, l));
82
- }
83
- void truncate() {
84
- data = "";
85
- }
86
- };
87
-
88
-
89
- static dbi::Handle* DBI_HANDLE(VALUE self) {
90
- dbi::Handle *h;
91
- Data_Get_Struct(self, dbi::Handle, h);
92
- if (!h) rb_raise(eRuntimeError, "Invalid object, did you forget to call #super ?");
93
- return h;
94
- }
95
-
96
- static dbi::AbstractStatement* DBI_STATEMENT(VALUE self) {
97
- dbi::AbstractStatement *st;
98
- Data_Get_Struct(self, dbi::AbstractStatement, st);
99
- if (!st) rb_raise(eRuntimeError, "Invalid object, did you forget to call #super ?");
100
- return st;
101
- }
102
-
103
- static dbi::ConnectionPool* DBI_CPOOL(VALUE self) {
104
- dbi::ConnectionPool *cp;
105
- Data_Get_Struct(self, dbi::ConnectionPool, cp);
106
- if (!cp) rb_raise(eRuntimeError, "Invalid object, did you forget to call #super ?");
107
- return cp;
108
- }
109
-
110
- static dbi::Request* DBI_REQUEST(VALUE self) {
111
- dbi::Request *r;
112
- Data_Get_Struct(self, dbi::Request, r);
113
- if (!r) rb_raise(eRuntimeError, "Invalid object, did you forget to call #super ?");
114
- return r;
115
- }
116
-
117
- void static inline rb_extract_bind_params(int argc, VALUE* argv, std::vector<dbi::Param> &bind) {
118
- for (int i = 0; i < argc; i++) {
119
- VALUE arg = argv[i];
120
- if (arg == Qnil)
121
- bind.push_back(dbi::PARAM(dbi::null()));
122
- else if (rb_obj_is_kind_of(arg, rb_cIO) == Qtrue || rb_obj_is_kind_of(arg, cStringIO) == Qtrue) {
123
- arg = rb_funcall(arg, fRead, 0);
124
- bind.push_back(dbi::PARAM_BINARY((unsigned char*)RSTRING_PTR(arg), RSTRING_LEN(arg)));
125
- }
126
- else {
127
- arg = OBJ2STRING(arg);
128
- if (strcmp(rb_enc_get(arg)->name, "UTF-8") != 0)
129
- arg = rb_str_encode(arg, rb_str_new2("UTF-8"), 0, Qnil);
130
- bind.push_back(dbi::PARAM((unsigned char*)RSTRING_PTR(arg), RSTRING_LEN(arg)));
131
- }
132
- }
133
- }
134
-
135
- VALUE rb_swift_init(VALUE self, VALUE path) {
136
- try { dbi::dbiInitialize(CSTRING(path)); } catch EXCEPTION("Swift#init");
137
- return Qtrue;
138
- }
139
-
140
- static void free_connection(dbi::Handle *self) {
141
- if (self) delete self;
142
- }
143
-
144
- int compute_tzoffset() {
145
- struct tm tm;
146
- memset(&tm, 0, sizeof(struct tm));
147
- tm.tm_year = 70;
148
- tm.tm_mday = 1;
149
- return -1 * mktime(&tm);
150
- }
151
-
152
- VALUE rb_adapter_alloc(VALUE klass) {
153
- dbi::Handle *h = 0;
154
- return Data_Wrap_Struct(klass, 0, free_connection, h);
155
- }
156
-
157
- VALUE rb_adapter_init(VALUE self, VALUE opts) {
158
- VALUE db = rb_hash_aref(opts, ID2SYM(rb_intern("db")));
159
- VALUE host = rb_hash_aref(opts, ID2SYM(rb_intern("host")));
160
- VALUE port = rb_hash_aref(opts, ID2SYM(rb_intern("port")));
161
- VALUE user = rb_hash_aref(opts, ID2SYM(rb_intern("user")));
162
- VALUE driver = rb_hash_aref(opts, ID2SYM(rb_intern("driver")));
163
- VALUE password = rb_hash_aref(opts, ID2SYM(rb_intern("password")));
164
-
165
- if (NIL_P(db)) rb_raise(eArgumentError, "Adapter#new called without :db");
166
- if (NIL_P(driver)) rb_raise(eArgumentError, "Adapter#new called without :driver");
167
-
168
- host = NIL_P(host) ? rb_str_new2("") : host;
169
- port = NIL_P(port) ? rb_str_new2("") : port;
170
- user = NIL_P(user) ? rb_str_new2(getlogin()) : user;
171
- password = NIL_P(password) ? rb_str_new2("") : password;
172
-
173
- try {
174
- DATA_PTR(self) = new dbi::Handle(
175
- CSTRING(driver), CSTRING(user), CSTRING(password),
176
- CSTRING(db), CSTRING(host), CSTRING(port)
177
- );
178
- } catch EXCEPTION("Adapter#new");
179
-
180
- rb_iv_set(self, "@options", opts);
181
- return Qnil;
182
- }
183
-
184
- VALUE rb_adapter_close(VALUE self) {
185
- dbi::Handle *h = DBI_HANDLE(self);
186
- try {
187
- h->close();
188
- } catch EXCEPTION("Adapter#close");
189
- return Qtrue;
190
- }
191
-
192
- static void free_statement(dbi::AbstractStatement *self) {
193
- if (self) {
194
- self->cleanup();
195
- delete self;
196
- }
197
- }
198
-
199
- static VALUE rb_adapter_prepare(int argc, VALUE *argv, VALUE self) {
200
- VALUE sql, scheme, prepared;
201
- dbi::Handle *h = DBI_HANDLE(self);
202
-
203
- rb_scan_args(argc, argv, "11", &scheme, &sql);
204
- if (TYPE(scheme) != T_CLASS) {
205
- sql = scheme;
206
- scheme = Qnil;
207
- }
208
-
209
- try {
210
- dbi::AbstractStatement *st = h->conn()->prepare(CSTRING(sql));
211
- prepared = Data_Wrap_Struct(cStatement, 0, free_statement, st);
212
- rb_iv_set(prepared, "@scheme", scheme);
213
- rb_iv_set(prepared, "@adapter", self);
214
- } catch EXCEPTION("Adapter#prepare");
215
-
216
- return prepared;
217
- }
218
-
219
- static VALUE rb_statement_each(VALUE self);
220
- VALUE rb_statement_execute(int argc, VALUE *argv, VALUE self);
221
-
222
- VALUE rb_adapter_execute(int argc, VALUE *argv, VALUE self) {
223
- uint rows = 0;
224
- VALUE result = 0;
225
- dbi::Handle *h = DBI_HANDLE(self);
226
- if (argc == 0 || NIL_P(argv[0]))
227
- rb_raise(eArgumentError, "Adapter#execute called without a SQL command");
228
- try {
229
- if (argc == 1)
230
- rows = h->execute(CSTRING(argv[0]));
231
- else {
232
- dbi::ResultRow bind;
233
- rb_extract_bind_params(argc-1, argv+1, bind);
234
- if (dbi::_trace)
235
- dbi::logMessage(dbi::_trace_fd, dbi::formatParams(CSTRING(argv[0]), bind));
236
- rows = h->conn()->execute(CSTRING(argv[0]), bind);
237
- }
238
- if (rb_block_given_p()) {
239
- dbi::AbstractResultSet *rs = h->results();
240
- result = Data_Wrap_Struct(cResultSet, 0, free_statement, rs);
241
- rb_iv_set(result, "@adapter", self);
242
- }
243
- } catch EXCEPTION("Adapter#execute");
244
-
245
- return result ? rb_statement_each(result) : INT2NUM(rows);
246
- }
247
-
248
- VALUE rb_adapter_results(VALUE self) {
249
- VALUE result = Qnil;
250
- dbi::Handle *h = DBI_HANDLE(self);
251
- try {
252
- dbi::AbstractResultSet *rs = h->results();
253
- result = Data_Wrap_Struct(cResultSet, 0, free_statement, rs);
254
- rb_iv_set(result, "@adapter", self);
255
- } catch EXCEPTION("Adapter#results");
256
- return result;
257
- }
258
-
259
- VALUE rb_adapter_begin(int argc, VALUE *argv, VALUE self) {
260
- dbi::Handle *h = DBI_HANDLE(self);
261
- VALUE save;
262
- rb_scan_args(argc, argv, "01", &save);
263
- try { NIL_P(save) ? h->begin() : h->begin(CSTRING(save)); } catch EXCEPTION("Adapter#begin");
264
- }
265
-
266
- VALUE rb_adapter_commit(int argc, VALUE *argv, VALUE self) {
267
- dbi::Handle *h = DBI_HANDLE(self);
268
- VALUE save;
269
- rb_scan_args(argc, argv, "01", &save);
270
- try { NIL_P(save) ? h->commit() : h->commit(CSTRING(save)); } catch EXCEPTION("Adapter#commit");
271
- }
272
-
273
- VALUE rb_adapter_rollback(int argc, VALUE *argv, VALUE self) {
274
- dbi::Handle *h = DBI_HANDLE(self);
275
- VALUE save_point;
276
- rb_scan_args(argc, argv, "01", &save_point);
277
- try { NIL_P(save_point) ? h->rollback() : h->rollback(CSTRING(save_point)); } catch EXCEPTION("Adapter#rollback");
278
- }
279
-
280
- VALUE rb_adapter_transaction(int argc, VALUE *argv, VALUE self) {
281
- int status;
282
- VALUE sp, block;
283
- rb_scan_args(argc, argv, "01&", &sp, &block);
284
-
285
- std::string save_point = NIL_P(sp) ? "SP" + dbi::generateCompactUUID() : CSTRING(sp);
286
- dbi::Handle *h = DBI_HANDLE(self);
287
-
288
- try {
289
- h->begin(save_point);
290
- rb_protect(rb_yield, self, &status);
291
- if (status == 0 && h->transactions().back() == save_point) {
292
- h->commit(save_point);
293
- }
294
- else if (status != 0) {
295
- if (h->transactions().back() == save_point) h->rollback(save_point);
296
- rb_jump_tag(status);
297
- }
298
- } catch EXCEPTION("Adapter#transaction{}");
299
- }
300
-
301
- VALUE rb_adapter_write(int argc, VALUE *argv, VALUE self) {
302
- ulong rows = 0;
303
- VALUE stream, table, fields;
304
-
305
- rb_scan_args(argc, argv, "30", &table, &fields, &stream);
306
- if (TYPE(stream) != T_STRING && !rb_respond_to(stream, fRead))
307
- rb_raise(eArgumentError, "Adapter#write: stream should be a string or kind_of?(IO)");
308
- if (TYPE(fields) != T_ARRAY)
309
- rb_raise(eArgumentError, "Adapter#write: fields should be an array of string values");
310
-
311
- dbi::Handle *h = DBI_HANDLE(self);
312
- try {
313
- dbi::ResultRow rfields;
314
- for (int n = 0; n < RARRAY_LEN(fields); n++) {
315
- VALUE f = rb_ary_entry(fields, n);
316
- rfields << std::string(RSTRING_PTR(f), RSTRING_LEN(f));
317
- }
318
- // This is just for the friggin mysql support - mysql does not like a statement close
319
- // command being send on a handle when the writing has started.
320
- rb_gc();
321
- if (TYPE(stream) == T_STRING) {
322
- dbi::IOStream io(RSTRING_PTR(stream), RSTRING_LEN(stream));
323
- rows = h->copyIn(RSTRING_PTR(table), rfields, &io);
324
- }
325
- else {
326
- IOStream io(stream);
327
- rows = h->copyIn(RSTRING_PTR(table), rfields, &io);
328
- }
329
- } catch EXCEPTION("Adapter#write");
330
-
331
- return ULONG2NUM(rows);
332
- }
333
-
334
- VALUE rb_adapter_timezone(int argc, VALUE *argv, VALUE self) {
335
- VALUE name, tzhour, tzmin;
336
- if (argc == 1)
337
- rb_scan_args(argc, argv, "10", &name);
338
- else {
339
- rb_scan_args(argc, argv, "20", &tzhour, &tzmin);
340
- if (TYPE(tzhour) != T_FIXNUM && TYPE(tzmin) != T_FIXNUM)
341
- rb_raise(eArgumentError, "Adapter#timezone: tzhour and tzmin must be Fixnum");
342
- }
343
- dbi::Handle *h = DBI_HANDLE(self);
344
- try {
345
- if (argc == 1)
346
- h->setTimeZone(CSTRING(name));
347
- else
348
- h->setTimeZoneOffset(NUM2INT(tzhour), NUM2INT(tzmin));
349
- } catch EXCEPTION("Adapter#timezone");
350
- return Qtrue;
351
- }
352
-
353
- VALUE rb_statement_alloc(VALUE klass) {
354
- dbi::AbstractStatement *st = 0;
355
- return Data_Wrap_Struct(klass, 0, free_statement, st);
356
- }
357
-
358
- VALUE rb_statement_init(VALUE self, VALUE hl, VALUE sql) {
359
- dbi::Handle *h = DBI_HANDLE(hl);
360
-
361
- if (NIL_P(hl) || !h)
362
- rb_raise(eArgumentError, "Statement#new called without an Adapter instance");
363
- if (NIL_P(sql))
364
- rb_raise(eArgumentError, "Statement#new called without a SQL command");
365
-
366
- try {
367
- DATA_PTR(self) = h->conn()->prepare(CSTRING(sql));
368
- } catch EXCEPTION("Statement#new");
369
-
370
- return Qnil;
371
- }
372
-
373
- VALUE rb_statement_execute(int argc, VALUE *argv, VALUE self) {
374
- dbi::AbstractStatement *st = DBI_STATEMENT(self);
375
- try {
376
- if (argc == 0) {
377
- dbi::ResultRow params;
378
- if (dbi::_trace)
379
- dbi::logMessage(dbi::_trace_fd, dbi::formatParams(st->command(), params));
380
- st->execute();
381
- }
382
- else {
383
- dbi::ResultRow bind;
384
- rb_extract_bind_params(argc, argv, bind);
385
- if (dbi::_trace)
386
- dbi::logMessage(dbi::_trace_fd, dbi::formatParams(st->command(), bind));
387
- st->execute(bind);
388
- }
389
- } catch EXCEPTION("Statement#execute");
390
-
391
- if (rb_block_given_p()) return rb_statement_each(self);
392
- return self;
393
- }
394
-
395
- VALUE rb_statement_finish(VALUE self) {
396
- dbi::AbstractStatement *st = DBI_STATEMENT(self);
397
- try {
398
- st->finish();
399
- } catch EXCEPTION("Statement#finish");
400
- }
401
-
402
- VALUE rb_statement_rows(VALUE self) {
403
- uint rows;
404
- dbi::AbstractStatement *st = DBI_STATEMENT(self);
405
- try { rows = st->rows(); } catch EXCEPTION("Statement#rows");
406
- return INT2NUM(rows);
407
- }
408
-
409
- VALUE rb_statement_insert_id(VALUE self) {
410
- dbi::AbstractStatement *st = DBI_STATEMENT(self);
411
- VALUE insert_id = Qnil;
412
- try {
413
- if (st->rows() > 0) insert_id = LONG2NUM(st->lastInsertID());
414
- } catch EXCEPTION("Statement#insert_id");
415
-
416
- return insert_id;
417
- }
418
4
 
419
- VALUE rb_field_typecast(VALUE adapter, int type, const char *data, ulong len) {
420
- time_t epoch, offset;
421
- struct tm tm;
5
+ VALUE eSwiftError;
6
+ VALUE eSwiftArgumentError;
7
+ VALUE eSwiftRuntimeError;
8
+ VALUE eSwiftConnectionError;
422
9
 
423
- char tzsign = ' ';
424
- int tzhour = 0, tzmin = 0;
425
- double usec = 0;
426
-
427
- switch(type) {
428
- case DBI_TYPE_BOOLEAN:
429
- return strcmp(data, "t") == 0 || strcmp(data, "1") == 0 ? Qtrue : Qfalse;
430
- case DBI_TYPE_INT:
431
- return rb_cstr2inum(data, 10);
432
- case DBI_TYPE_BLOB:
433
- return rb_funcall(cStringIO, fNew, 1, rb_str_new(data, len));
434
- // forcing UTF8 convention here - do we really care about people using non utf8
435
- // client encodings and databases ?
436
- case DBI_TYPE_TEXT:
437
- return rb_enc_str_new(data, len, rb_utf8_encoding());
438
- case DBI_TYPE_TIME:
439
- /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
440
- NOTE Flexibility sacrificed for performance.
441
- Timestamp parser is very unforgiving and only parses
442
- YYYY-MM-DD HH:MM:SS.ms[+-]HH:MM
443
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
444
- memset(&tm, 0, sizeof(struct tm));
445
- if (strchr(data, '.')) {
446
- sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%lf%c%02d:%02d",
447
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
448
- &usec, &tzsign, &tzhour, &tzmin);
449
- }
450
- else {
451
- sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d",
452
- &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
453
- &tzsign, &tzhour, &tzmin);
454
- }
455
- tm.tm_year -= 1900;
456
- tm.tm_mon -= 1;
457
- if (tm.tm_mday > 0) {
458
- offset = tzoffset;
459
- epoch = mktime(&tm);
460
- if (tzsign == '+' || tzsign == '-') {
461
- offset += tzsign == '+' ?
462
- (time_t)tzhour * -3600 + (time_t)tzmin * -60
463
- : (time_t)tzhour * 3600 + (time_t)tzmin * 60;
464
- }
465
- else {
466
- VALUE database_offset = rb_iv_get(adapter, "@tzoffset");
467
- offset -= NIL_P(database_offset) ? 0 : NUM2ULONG(database_offset);
468
- }
469
- return rb_time_new(epoch + offset, usec*1000000);
470
- }
471
- else {
472
- fprintf(stderr, "typecast failed to parse date: %s\n", data);
473
- return rb_str_new(data, len);
474
- }
475
- // does bigdecimal solve all floating point woes ? dunno :)
476
- case DBI_TYPE_NUMERIC:
477
- return rb_funcall(cBigDecimal, fNew, 1, rb_str_new2(data));
478
- case DBI_TYPE_FLOAT:
479
- return rb_float_new(atof(data));
480
- }
481
- }
482
-
483
- static VALUE rb_statement_each(VALUE self) {
484
- uint r, c;
485
- ulong len;
486
- const char *data;
487
-
488
- dbi::AbstractStatement *st = DBI_STATEMENT(self);
489
- VALUE scheme = rb_iv_get(self, "@scheme");
490
- VALUE adapter = rb_iv_get(self, "@adapter");
491
-
492
- try {
493
- VALUE attrs = rb_ary_new();
494
- std::vector<string> fields = st->fields();
495
- std::vector<int> types = st->types();
496
- for (c = 0; c < fields.size(); c++) {
497
- rb_ary_push(attrs, ID2SYM(rb_intern(fields[c].c_str())));
498
- }
499
-
500
- // TODO Code duplication
501
- // Avoiding a rb_yield(NIL_P(scheme) ? row : rb_funcall(scheme, load, row))
502
- // Maybe an inline method will help ?
503
- st->seek(0);
504
- tzoffset = compute_tzoffset();
505
- if (NIL_P(scheme) || scheme == Qnil) {
506
- for (r = 0; r < st->rows(); r++) {
507
- VALUE row = rb_hash_new();
508
- for (c = 0; c < st->columns(); c++) {
509
- data = (const char*)st->fetchValue(r,c, &len);
510
- if (data)
511
- rb_hash_aset(row, rb_ary_entry(attrs, c), rb_field_typecast(adapter, types[c], data, len));
512
- else
513
- rb_hash_aset(row, rb_ary_entry(attrs, c), Qnil);
514
- }
515
- rb_yield(row);
516
- }
517
- }
518
- else {
519
- for (r = 0; r < st->rows(); r++) {
520
- VALUE row = rb_hash_new();
521
- for (c = 0; c < st->columns(); c++) {
522
- data = (const char*)st->fetchValue(r,c, &len);
523
- if (data)
524
- rb_hash_aset(row, rb_ary_entry(attrs, c), rb_field_typecast(adapter, types[c], data, len));
525
- else
526
- rb_hash_aset(row, rb_ary_entry(attrs, c), Qnil);
527
- }
528
- rb_yield(rb_funcall(scheme, fLoad, 1, row));
529
- }
530
- }
531
- } catch EXCEPTION("Statment#each");
532
- return Qnil;
533
- }
534
-
535
- VALUE rb_statement_fetchrow(VALUE self) {
536
- const char *data;
537
- uint r, c;
538
- ulong len;
539
- VALUE row = Qnil;
540
- dbi::AbstractStatement *st = DBI_STATEMENT(self);
541
- try {
542
- r = st->currentRow();
543
- if (r < st->rows()) {
544
- row = rb_ary_new();
545
- for (c = 0; c < st->columns(); c++) {
546
- data = (const char*)st->fetchValue(r, c, &len);
547
- rb_ary_push(row, data ? rb_str_new(data, len) : Qnil);
548
- }
549
- }
550
- } catch EXCEPTION("Statement#fetchrow");
551
-
552
- return row;
10
+ VALUE rb_special_constant(VALUE self, VALUE obj) {
11
+ return rb_special_const_p(obj) ? Qtrue : Qfalse;
553
12
  }
554
13
 
555
- VALUE rb_statement_rewind(VALUE self) {
556
- dbi::AbstractStatement *st = DBI_STATEMENT(self);
557
- try { st->rewind(); } catch EXCEPTION("Statement#rewind");
558
- return Qnil;
14
+ VALUE swift_init(VALUE self, VALUE path) {
15
+ try { dbi::dbiInitialize(CSTRING(path)); } CATCH_DBI_EXCEPTIONS();
16
+ return Qtrue;
559
17
  }
560
18
 
561
- VALUE rb_swift_trace(int argc, VALUE *argv, VALUE self) {
562
- // by default log all messages to stderr.
563
- int fd = 2;
564
- rb_io_t *fptr;
19
+ VALUE swift_trace(int argc, VALUE *argv, VALUE self) {
565
20
  VALUE flag, io;
21
+ rb_io_t *fptr;
22
+ int fd = 2; // defaults to stderr
566
23
 
567
24
  rb_scan_args(argc, argv, "11", &flag, &io);
568
25
 
569
26
  if (TYPE(flag) != T_TRUE && TYPE(flag) != T_FALSE)
570
- rb_raise(eArgumentError, "Swift#trace expects a boolean flag, got %s", CSTRING(flag));
27
+ rb_raise(eSwiftArgumentError, "Swift#trace expects a boolean flag, got %s", CSTRING(flag));
571
28
 
572
29
  if (!NIL_P(io)) {
573
30
  GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
@@ -575,192 +32,27 @@ VALUE rb_swift_trace(int argc, VALUE *argv, VALUE self) {
575
32
  }
576
33
 
577
34
  dbi::trace(flag == Qtrue ? true : false, fd);
578
- }
579
-
580
- VALUE rb_adapter_dup(VALUE self) {
581
- rb_raise(eRuntimeError, "Adapter#dup or Adapter#clone is not allowed.");
582
- }
583
-
584
- VALUE rb_statement_dup(VALUE self) {
585
- rb_raise(eRuntimeError, "Statement#dup or Statement#clone is not allowed.");
586
- }
587
-
588
- static void free_request(dbi::Request *self) {
589
- if(self) delete self;
590
- }
591
-
592
- VALUE rb_request_alloc(VALUE klass) {
593
- dbi::Request *r = 0;
594
- return Data_Wrap_Struct(klass, 0, free_request, r);
595
- }
596
-
597
- static void free_cpool(dbi::ConnectionPool *self) {
598
- if (self) delete self;
599
- }
600
-
601
- VALUE rb_cpool_alloc(VALUE klass) {
602
- dbi::ConnectionPool *c = 0;
603
- return Data_Wrap_Struct(klass, 0, free_cpool, c);
604
- }
605
-
606
- VALUE rb_cpool_init(VALUE self, VALUE n, VALUE opts) {
607
- VALUE db = rb_hash_aref(opts, ID2SYM(rb_intern("db")));
608
- VALUE host = rb_hash_aref(opts, ID2SYM(rb_intern("host")));
609
- VALUE port = rb_hash_aref(opts, ID2SYM(rb_intern("port")));
610
- VALUE user = rb_hash_aref(opts, ID2SYM(rb_intern("user")));
611
- VALUE driver = rb_hash_aref(opts, ID2SYM(rb_intern("driver")));
612
- VALUE password = rb_hash_aref(opts, ID2SYM(rb_intern("password")));
613
-
614
- if (NIL_P(db)) rb_raise(eArgumentError, "ConnectionPool#new called without :db");
615
- if (NIL_P(driver)) rb_raise(eArgumentError, "ConnectionPool#new called without :driver");
616
-
617
- host = NIL_P(host) ? rb_str_new2("") : host;
618
- port = NIL_P(port) ? rb_str_new2("") : port;
619
- user = NIL_P(user) ? rb_str_new2(getlogin()) : user;
620
- password = NIL_P(password) ? rb_str_new2("") : password;
621
-
622
- if (NUM2INT(n) < 1) rb_raise(eArgumentError, "ConnectionPool#new called with invalid pool size.");
623
-
624
- try {
625
- DATA_PTR(self) = new dbi::ConnectionPool(
626
- NUM2INT(n), CSTRING(driver), CSTRING(user), CSTRING(password), CSTRING(db), CSTRING(host), CSTRING(port)
627
- );
628
- } catch EXCEPTION("ConnectionPool#new");
629
-
630
- return Qnil;
631
- }
632
-
633
- void rb_cpool_callback(dbi::AbstractResultSet *rs) {
634
- VALUE callback = (VALUE)rs->context;
635
- // NOTE: ResultSet will be free'd by the underlying connection pool dispatcher.
636
- if (!NIL_P(callback))
637
- rb_proc_call(callback, rb_ary_new3(1, Data_Wrap_Struct(cResultSet, 0, 0, rs)));
638
- }
639
-
640
- VALUE rb_cpool_execute(int argc, VALUE *argv, VALUE self) {
641
- dbi::ConnectionPool *cp = DBI_CPOOL(self);
642
- int n;
643
- VALUE sql;
644
- VALUE args;
645
- VALUE callback;
646
- VALUE request = Qnil;
647
-
648
- rb_scan_args(argc, argv, "1*&", &sql, &args, &callback);
649
- try {
650
- dbi::ResultRow bind;
651
- for (n = 0; n < RARRAY_LEN(args); n++) {
652
- VALUE arg = rb_ary_entry(args, n);
653
- if (arg == Qnil)
654
- bind.push_back(dbi::PARAM(dbi::null()));
655
- else if (rb_obj_is_kind_of(arg, rb_cIO) == Qtrue || rb_obj_is_kind_of(arg, cStringIO) == Qtrue) {
656
- arg = rb_funcall(arg, fRead, 0);
657
- bind.push_back(dbi::PARAM_BINARY((unsigned char*)RSTRING_PTR(arg), RSTRING_LEN(arg)));
658
- }
659
- else {
660
- arg = OBJ2STRING(arg);
661
- if (strcmp(rb_enc_get(arg)->name, "UTF-8") != 0)
662
- arg = rb_str_encode(arg, rb_str_new2("UTF-8"), 0, Qnil);
663
- bind.push_back(dbi::PARAM((unsigned char*)RSTRING_PTR(arg), RSTRING_LEN(arg)));
664
- }
665
- }
666
- // TODO GC mark callback.
667
- request = rb_request_alloc(cRequest);
668
- DATA_PTR(request) = cp->execute(CSTRING(sql), bind, rb_cpool_callback, (void*)callback);
669
- } catch EXCEPTION("ConnectionPool#execute");
670
-
671
- return DATA_PTR(request) ? request : Qnil;
672
- }
673
-
674
- VALUE rb_request_socket(VALUE self) {
675
- dbi::Request *r = DBI_REQUEST(self);
676
- VALUE fd = Qnil;
677
- try {
678
- fd = INT2NUM(r->socket());
679
- } catch EXCEPTION("Request#socket");
680
- return fd;
681
- }
682
-
683
- VALUE rb_request_process(VALUE self) {
684
- VALUE rc = Qnil;
685
- dbi::Request *r = DBI_REQUEST(self);
686
-
687
- try {
688
- rc = r->process() ? Qtrue : Qfalse;
689
- } catch EXCEPTION("Request#process");
690
-
691
- return rc;
35
+ return flag;
692
36
  }
693
37
 
694
38
  extern "C" {
695
- void Init_swift(void) {
696
- rb_require("bigdecimal");
697
- rb_require("stringio");
698
-
699
- fNew = rb_intern("new");
700
- fStringify = rb_intern("to_s");
701
- fLoad = rb_intern("load");
702
- fRead = rb_intern("read");
703
- fWrite = rb_intern("write");
704
-
705
- eRuntimeError = CONST_GET(rb_mKernel, "RuntimeError");
706
- eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
707
- eStandardError = CONST_GET(rb_mKernel, "StandardError");
708
- cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
709
- cStringIO = CONST_GET(rb_mKernel, "StringIO");
710
- eConnectionError = rb_define_class("ConnectionError", eRuntimeError);
711
-
712
- mSwift = rb_define_module("Swift");
713
- cAdapter = rb_define_class_under(mSwift, "Adapter", rb_cObject);
714
- cStatement = rb_define_class_under(mSwift, "Statement", rb_cObject);
715
- cResultSet = rb_define_class_under(mSwift, "ResultSet", cStatement);
716
- cPool = rb_define_class_under(mSwift, "ConnectionPool", rb_cObject);
717
- cRequest = rb_define_class_under(mSwift, "Request", rb_cObject);
718
-
719
- rb_define_module_function(mSwift, "init", RUBY_METHOD_FUNC(rb_swift_init), 1);
720
- rb_define_module_function(mSwift, "trace", RUBY_METHOD_FUNC(rb_swift_trace), -1);
721
-
722
- rb_define_alloc_func(cAdapter, rb_adapter_alloc);
39
+ void Init_swift(void) {
40
+ mSwift = rb_define_module("Swift");
723
41
 
724
- rb_define_method(cAdapter, "initialize", RUBY_METHOD_FUNC(rb_adapter_init), 1);
725
- rb_define_method(cAdapter, "prepare", RUBY_METHOD_FUNC(rb_adapter_prepare), -1);
726
- rb_define_method(cAdapter, "execute", RUBY_METHOD_FUNC(rb_adapter_execute), -1);
727
- rb_define_method(cAdapter, "begin", RUBY_METHOD_FUNC(rb_adapter_begin), -1);
728
- rb_define_method(cAdapter, "commit", RUBY_METHOD_FUNC(rb_adapter_commit), -1);
729
- rb_define_method(cAdapter, "rollback", RUBY_METHOD_FUNC(rb_adapter_rollback), -1);
730
- rb_define_method(cAdapter, "transaction", RUBY_METHOD_FUNC(rb_adapter_transaction), -1);
731
- rb_define_method(cAdapter, "close", RUBY_METHOD_FUNC(rb_adapter_close), 0);
732
- rb_define_method(cAdapter, "dup", RUBY_METHOD_FUNC(rb_adapter_dup), 0);
733
- rb_define_method(cAdapter, "clone", RUBY_METHOD_FUNC(rb_adapter_dup), 0);
734
- rb_define_method(cAdapter, "write", RUBY_METHOD_FUNC(rb_adapter_write), -1);
735
- rb_define_method(cAdapter, "results", RUBY_METHOD_FUNC(rb_adapter_results), 0);
736
- rb_define_method(cAdapter, "timezone", RUBY_METHOD_FUNC(rb_adapter_timezone), -1);
42
+ eSwiftError = rb_define_class("SwiftError", CONST_GET(rb_mKernel, "StandardError"));
43
+ eSwiftArgumentError = rb_define_class("SwiftArgumentError", eSwiftError);
44
+ eSwiftRuntimeError = rb_define_class("SwiftRuntimeError", eSwiftError);
45
+ eSwiftConnectionError = rb_define_class("SwiftConnectionError", eSwiftError);
737
46
 
738
- rb_define_alloc_func(cStatement, rb_statement_alloc);
47
+ init_swift_adapter();
48
+ init_swift_result();
49
+ init_swift_statement();
50
+ init_swift_request();
51
+ init_swift_pool();
739
52
 
740
- rb_define_method(cStatement, "initialize", RUBY_METHOD_FUNC(rb_statement_init), 2);
741
- rb_define_method(cStatement, "execute", RUBY_METHOD_FUNC(rb_statement_execute), -1);
742
- rb_define_method(cStatement, "each", RUBY_METHOD_FUNC(rb_statement_each), 0);
743
- rb_define_method(cStatement, "rows", RUBY_METHOD_FUNC(rb_statement_rows), 0);
744
- rb_define_method(cStatement, "fetchrow", RUBY_METHOD_FUNC(rb_statement_fetchrow), 0);
745
- rb_define_method(cStatement, "finish", RUBY_METHOD_FUNC(rb_statement_finish), 0);
746
- rb_define_method(cStatement, "dup", RUBY_METHOD_FUNC(rb_statement_dup), 0);
747
- rb_define_method(cStatement, "clone", RUBY_METHOD_FUNC(rb_statement_dup), 0);
748
- rb_define_method(cStatement, "insert_id", RUBY_METHOD_FUNC(rb_statement_insert_id), 0);
749
- rb_define_method(cStatement, "rewind", RUBY_METHOD_FUNC(rb_statement_rewind), 0);
750
-
751
- rb_include_module(cStatement, CONST_GET(rb_mKernel, "Enumerable"));
752
-
753
-
754
- rb_define_alloc_func(cPool, rb_cpool_alloc);
755
-
756
- rb_define_method(cPool, "initialize", RUBY_METHOD_FUNC(rb_cpool_init), 2);
757
- rb_define_method(cPool, "execute", RUBY_METHOD_FUNC(rb_cpool_execute), -1);
758
-
759
- rb_define_alloc_func(cRequest, rb_request_alloc);
760
-
761
- rb_define_method(cRequest, "socket", RUBY_METHOD_FUNC(rb_request_socket), 0);
762
- rb_define_method(cRequest, "process", RUBY_METHOD_FUNC(rb_request_process), 0);
763
-
764
- rb_define_method(cResultSet, "execute", RUBY_METHOD_FUNC(Qnil), 0);
765
- }
53
+ rb_define_module_function(mSwift, "init", RUBY_METHOD_FUNC(swift_init), 1);
54
+ rb_define_module_function(mSwift, "trace", RUBY_METHOD_FUNC(swift_trace), -1);
55
+ rb_define_module_function(mSwift, "special_constant?", RUBY_METHOD_FUNC(rb_special_constant), 1);
56
+ }
766
57
  }
58
+