nuodb 1.0.0.rc.1

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.
@@ -0,0 +1,1130 @@
1
+ /****************************************************************************
2
+ * Copyright (c)2012, NuoDB, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions are met:
7
+ *
8
+ * * Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ * * Redistributions in binary form must reproduce the above copyright
11
+ * notice, this list of conditions and the following disclaimer in the
12
+ * documentation and/or other materials provided with the distribution.
13
+ * * Neither the name of NuoDB, Inc. nor the names of its contributors may
14
+ * be used to endorse or promote products derived from this software
15
+ * without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL NUODB, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
21
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23
+ * OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY OF
24
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25
+ * OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ ****************************************************************************/
28
+
29
+ /*
30
+ * NuoDB Adapter
31
+ */
32
+
33
+ #include <ruby.h>
34
+ #include <time.h>
35
+ #include <stdio.h>
36
+
37
+ extern "C" struct timeval rb_time_timeval(VALUE time);
38
+
39
+ //------------------------------------------------------------------------------
40
+ // class building macros
41
+
42
+ #define WRAPPER_COMMON(WT, RT) \
43
+ private: \
44
+ static VALUE type; \
45
+ RT* ptr; \
46
+ public: \
47
+ WT(RT* arg): ptr(arg) {} \
48
+ static VALUE getRubyType() { return type; } \
49
+ static void release(WT* self) \
50
+ { \
51
+ /*delete self->ptr;*/ \
52
+ delete self; \
53
+ } \
54
+ static RT* asPtr(VALUE value) \
55
+ { \
56
+ Check_Type(value, T_DATA); \
57
+ return ((WT*)DATA_PTR(value))->ptr; \
58
+ } \
59
+ static VALUE wrap(RT* value) \
60
+ { \
61
+ if (value == NULL) return Qnil; \
62
+ WT* w = new WT(value); \
63
+ VALUE obj = Data_Wrap_Struct(WT::getRubyType(), 0, WT::release, w); \
64
+ rb_obj_call_init(obj, 0, 0); \
65
+ return obj; \
66
+ }
67
+
68
+ #define WRAPPER_DEFINITION(WT) \
69
+ VALUE WT::type = 0;
70
+
71
+ #define AS_QBOOL(value)((value)? Qtrue : Qfalse)
72
+
73
+ //------------------------------------------------------------------------------
74
+ // utility function macros
75
+
76
+ #define SYMBOL_OF(value) \
77
+ ID2SYM(rb_intern(#value))
78
+
79
+ #define INIT_TYPE(name) \
80
+ type = rb_define_class_under(module, name, rb_cObject)
81
+
82
+ #define DEFINE_SINGLE(func, count) \
83
+ rb_define_singleton_method(type, #func, RUBY_METHOD_FUNC(func), count)
84
+
85
+ #define DEFINE_METHOD(func, count) \
86
+ rb_define_method(type, #func, RUBY_METHOD_FUNC(func), count)
87
+
88
+ //------------------------------------------------------------------------------
89
+ // exception mapper
90
+
91
+ static VALUE m_nuodb, c_nuodb_error;
92
+ static ID c_error_code_assignment;
93
+
94
+ static void rb_raise_nuodb_error(int code, const char * fmt, ...)
95
+ {
96
+ va_list args;
97
+ char text[BUFSIZ];
98
+
99
+ va_start(args, fmt);
100
+ vsnprintf(text, BUFSIZ, fmt, args);
101
+ va_end(args);
102
+
103
+ VALUE error = rb_exc_new2(c_nuodb_error, text);
104
+ rb_funcall(error, c_error_code_assignment, 1, UINT2NUM(code));
105
+ rb_exc_raise(error);
106
+ }
107
+
108
+ //------------------------------------------------------------------------------
109
+
110
+ #include "Connection.h"
111
+ #include "BigDecimal.h"
112
+ #include "Blob.h"
113
+ #include "Bytes.h"
114
+ #include "CallableStatement.h"
115
+ #include "Clob.h"
116
+ #include "DatabaseMetaData.h"
117
+ #include "DateClass.h"
118
+ #include "ParameterMetaData.h"
119
+ #include "PreparedStatement.h"
120
+ #include "Properties.h"
121
+ #include "ResultList.h"
122
+ #include "ResultSet.h"
123
+ #include "ResultSetMetaData.h"
124
+ #include "SQLException.h"
125
+ #include "Savepoint.h"
126
+ #include "Statement.h"
127
+ #include "TimeClass.h"
128
+ #include "Timestamp.h"
129
+ #include "SqlTimestamp.h"
130
+ #include "SqlDate.h"
131
+ #include "SqlTime.h"
132
+
133
+ using namespace NuoDB;
134
+
135
+ class WrapDatabaseMetaData
136
+ {
137
+ WRAPPER_COMMON(WrapDatabaseMetaData, DatabaseMetaData)
138
+
139
+ static void init(VALUE module);
140
+ static VALUE getDatabaseVersion(VALUE self);
141
+ static VALUE getIndexInfo(VALUE self, VALUE schemaValue, VALUE tableValue, VALUE uniqueValue, VALUE approxValue);
142
+ static VALUE getColumns(VALUE self, VALUE schemaValue, VALUE tablePattern);
143
+ static VALUE getTables(VALUE self, VALUE schemaValue, VALUE table);
144
+ };
145
+
146
+ WRAPPER_DEFINITION(WrapDatabaseMetaData);
147
+
148
+ //------------------------------------------------------------------------------
149
+
150
+ class WrapResultSetMetaData
151
+ {
152
+ WRAPPER_COMMON(WrapResultSetMetaData, ResultSetMetaData);
153
+
154
+ static void init(VALUE module);
155
+ static VALUE getColumnCount(VALUE self);
156
+ static VALUE getColumnName(VALUE self, VALUE columnValue);
157
+ static VALUE getScale(VALUE self, VALUE columnValue);
158
+ static VALUE getPrecision(VALUE self, VALUE columnValue);
159
+ static VALUE isNullable(VALUE self, VALUE columnValue);
160
+ static VALUE getColumnTypeName(VALUE self, VALUE columnValue);
161
+ static VALUE getType(VALUE self, VALUE columnValue);
162
+ };
163
+
164
+ WRAPPER_DEFINITION(WrapResultSetMetaData);
165
+
166
+ //------------------------------------------------------------------------------
167
+
168
+ class WrapResultSet
169
+ {
170
+ WRAPPER_COMMON(WrapResultSet, ResultSet)
171
+
172
+ static void init(VALUE module);
173
+ static VALUE next(VALUE self);
174
+ static VALUE getColumnCount(VALUE self);
175
+ static VALUE getMetaData(VALUE self);
176
+ static VALUE getBoolean(VALUE self, VALUE columnValue);
177
+ static VALUE getInteger(VALUE self, VALUE columnValue);
178
+ static VALUE getDouble(VALUE self, VALUE columnValue);
179
+ static VALUE getString(VALUE self, VALUE columnValue);
180
+ static VALUE getDate(VALUE self, VALUE columnValue);
181
+ static VALUE getTime(VALUE self, VALUE columnValue);
182
+ static VALUE getTimestamp(VALUE self, VALUE columnValue);
183
+ static VALUE getChar(VALUE self, VALUE columnValue);
184
+ };
185
+
186
+ WRAPPER_DEFINITION(WrapResultSet)
187
+
188
+ //------------------------------------------------------------------------------
189
+
190
+ class WrapStatement
191
+ {
192
+ WRAPPER_COMMON(WrapStatement, Statement);
193
+
194
+ static void init(VALUE module);
195
+ static VALUE close(VALUE self);
196
+ static VALUE execute(VALUE self, VALUE sqlValue);
197
+ static VALUE executeQuery(VALUE self, VALUE sqlValue);
198
+ static VALUE executeUpdate(VALUE self, VALUE sqlValue);
199
+ static VALUE getResultSet(VALUE self);
200
+ static VALUE getUpdateCount(VALUE self);
201
+ static VALUE getGeneratedKeys(VALUE self);
202
+ };
203
+
204
+ WRAPPER_DEFINITION(WrapStatement);
205
+
206
+ //------------------------------------------------------------------------------
207
+
208
+ class WrapPreparedStatement
209
+ {
210
+ WRAPPER_COMMON(WrapPreparedStatement, PreparedStatement);
211
+
212
+ static void init(VALUE module);
213
+ static VALUE close(VALUE self);
214
+ static VALUE setBoolean(VALUE self, VALUE indexValue, VALUE valueValue);
215
+ static VALUE setInteger(VALUE self, VALUE indexValue, VALUE valueValue);
216
+ static VALUE setDouble(VALUE self, VALUE indexValue, VALUE valueValue);
217
+ static VALUE setString(VALUE self, VALUE indexValue, VALUE valueValue);
218
+ static VALUE setTime(VALUE self, VALUE indexValue, VALUE valueValue);
219
+ static VALUE execute(VALUE self);
220
+ static VALUE executeQuery(VALUE self);
221
+ static VALUE executeUpdate(VALUE self);
222
+ static VALUE getResultSet(VALUE self);
223
+ static VALUE getUpdateCount(VALUE self);
224
+ static VALUE getGeneratedKeys(VALUE self);
225
+ };
226
+
227
+ WRAPPER_DEFINITION(WrapPreparedStatement);
228
+
229
+ //------------------------------------------------------------------------------
230
+
231
+ class WrapConnection
232
+ {
233
+ WRAPPER_COMMON(WrapConnection, Connection);
234
+
235
+ static void init(VALUE module);
236
+ static VALUE close(VALUE self);
237
+ static VALUE ping(VALUE self);
238
+ static VALUE createStatement(VALUE self);
239
+ static VALUE createPreparedStatement(VALUE self, VALUE sqlValue);
240
+ static VALUE setAutoCommit(VALUE self, VALUE autoCommitValue);
241
+ static VALUE hasAutoCommit(VALUE self);
242
+ static VALUE commit(VALUE self);
243
+ static VALUE rollback(VALUE self);
244
+ static VALUE getMetaData(VALUE self);
245
+ static VALUE getSchema(VALUE self);
246
+ static VALUE createSqlConnection(VALUE self,
247
+ VALUE databaseValue,
248
+ VALUE schemaValue,
249
+ VALUE usernameValue,
250
+ VALUE passwordValue);
251
+ };
252
+
253
+ WRAPPER_DEFINITION(WrapConnection);
254
+
255
+ //------------------------------------------------------------------------------
256
+
257
+ void WrapDatabaseMetaData::init(VALUE module)
258
+ {
259
+ INIT_TYPE("DatabaseMetaData");
260
+ DEFINE_METHOD(getDatabaseVersion, 0);
261
+ DEFINE_METHOD(getIndexInfo, 4);
262
+ DEFINE_METHOD(getColumns, 2);
263
+ DEFINE_METHOD(getTables, 2);
264
+ }
265
+
266
+ VALUE WrapDatabaseMetaData::getDatabaseVersion(VALUE self)
267
+ {
268
+ try
269
+ {
270
+ return rb_str_new2(asPtr(self)->getDatabaseProductVersion());
271
+ }
272
+ catch (SQLException & e)
273
+ {
274
+ rb_raise_nuodb_error(e.getSqlcode(), "Get database metadata database version failed: %s", e.getText());
275
+ }
276
+ }
277
+
278
+ VALUE WrapDatabaseMetaData::getIndexInfo(VALUE self, VALUE schemaValue, VALUE tableValue, VALUE uniqueValue, VALUE approxValue)
279
+ {
280
+ const char* schema = StringValuePtr(schemaValue);
281
+ const char* table = StringValuePtr(tableValue);
282
+ bool unique = !(RB_TYPE_P(uniqueValue, T_FALSE) || RB_TYPE_P(uniqueValue, T_NIL));
283
+ bool approx = !(RB_TYPE_P(approxValue, T_FALSE) || RB_TYPE_P(approxValue, T_NIL));
284
+ try
285
+ {
286
+ return WrapResultSet::wrap(asPtr(self)->getIndexInfo(NULL, schema, table, unique, approx));
287
+ }
288
+ catch (SQLException & e)
289
+ {
290
+ rb_raise_nuodb_error(e.getSqlcode(), "Get database metadata index info failed: %s", e.getText());
291
+ }
292
+ }
293
+
294
+ VALUE WrapDatabaseMetaData::getColumns(VALUE self, VALUE schemaValue, VALUE tableValue)
295
+ {
296
+ const char* schema = StringValuePtr(schemaValue);
297
+ const char* table = StringValuePtr(tableValue);
298
+ try
299
+ {
300
+ return WrapResultSet::wrap(asPtr(self)->getColumns(NULL, schema, table, NULL));
301
+ }
302
+ catch (SQLException & e)
303
+ {
304
+ rb_raise_nuodb_error(e.getSqlcode(), "Get columns failed: %s", e.getText());
305
+ }
306
+ }
307
+
308
+ VALUE WrapDatabaseMetaData::getTables(VALUE self, VALUE schemaValue, VALUE tableValue)
309
+ {
310
+ const char* schema = StringValuePtr(schemaValue);
311
+ const char* table = StringValuePtr(tableValue);
312
+
313
+ try
314
+ {
315
+ return WrapResultSet::wrap(asPtr(self)->getTables(NULL, schema, table, 0, NULL));
316
+ }
317
+ catch (SQLException & e)
318
+ {
319
+ rb_raise_nuodb_error(e.getSqlcode(), "Get tables failed: %s", e.getText());
320
+ }
321
+ }
322
+
323
+ //------------------------------------------------------------------------------
324
+
325
+ void WrapResultSet::init(VALUE module)
326
+ {
327
+ INIT_TYPE("ResultSet");
328
+ DEFINE_METHOD(next, 0);
329
+ DEFINE_METHOD(getMetaData, 0);
330
+ DEFINE_METHOD(getBoolean, 1);
331
+ DEFINE_METHOD(getInteger, 1);
332
+ DEFINE_METHOD(getDouble, 1);
333
+ DEFINE_METHOD(getString, 1);
334
+ DEFINE_METHOD(getDate, 1);
335
+ DEFINE_METHOD(getTime, 1);
336
+ DEFINE_METHOD(getTimestamp, 1);
337
+ DEFINE_METHOD(getChar, 1);
338
+ }
339
+
340
+ VALUE WrapResultSet::next(VALUE self)
341
+ {
342
+ try
343
+ {
344
+ return AS_QBOOL(asPtr(self)->next());
345
+ }
346
+ catch (SQLException & e)
347
+ {
348
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to move the cursor forward one row: %s", e.getText());
349
+ }
350
+ }
351
+
352
+ VALUE WrapResultSet::getMetaData(VALUE self)
353
+ {
354
+ try
355
+ {
356
+ return WrapResultSetMetaData::wrap(asPtr(self)->getMetaData());
357
+ }
358
+ catch (SQLException & e)
359
+ {
360
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to retrieve number, types, and properties of the result set: %s", e.getText());
361
+ }
362
+ }
363
+
364
+ VALUE WrapResultSet::getBoolean(VALUE self, VALUE columnValue)
365
+ {
366
+ int column = NUM2UINT(columnValue);
367
+ try
368
+ {
369
+ bool value = asPtr(self)->getBoolean(column);
370
+ return AS_QBOOL(value);
371
+ }
372
+ catch (SQLException & e)
373
+ {
374
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get boolean value for the designated column (%d): %s", column, e.getText());
375
+ }
376
+ }
377
+
378
+ VALUE WrapResultSet::getInteger(VALUE self, VALUE columnValue)
379
+ {
380
+ int column = NUM2UINT(columnValue);
381
+ try
382
+ {
383
+ return INT2NUM(asPtr(self)->getInt(column));
384
+ }
385
+ catch (SQLException & e)
386
+ {
387
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get integer value for the designated column (%d): %s", column, e.getText());
388
+ }
389
+ }
390
+
391
+ VALUE WrapResultSet::getDouble(VALUE self, VALUE columnValue)
392
+ {
393
+ int column = NUM2UINT(columnValue);
394
+ try
395
+ {
396
+ return rb_float_new(asPtr(self)->getDouble(column));
397
+ }
398
+ catch (SQLException & e)
399
+ {
400
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get double value for the designated column (%d): %s", column, e.getText());
401
+ }
402
+ }
403
+
404
+ VALUE WrapResultSet::getString(VALUE self, VALUE columnValue)
405
+ {
406
+ int column = NUM2UINT(columnValue);
407
+ try
408
+ {
409
+ return rb_str_new2(asPtr(self)->getString(column));
410
+ }
411
+ catch (SQLException & e)
412
+ {
413
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get string value for the designated column (%d): %s", column, e.getText());
414
+ }
415
+ }
416
+ VALUE WrapResultSet::getDate(VALUE self, VALUE columnValue)
417
+ {
418
+ int column = NUM2UINT(columnValue);
419
+ try
420
+ {
421
+ return rb_str_new2(asPtr(self)->getString(column));
422
+ //Date* date = asPtr(self)->getDate(column);
423
+ //SqlDate timestamp(date->getMilliseconds());
424
+ //struct tm utc;
425
+ //timestamp.getDate(&utc);
426
+ //char buffer[250];
427
+ //::strftime(buffer,sizeof(buffer),"%Y%m%dT%I%M%S+0000",&utc);
428
+ //return rb_str_new2(buffer);
429
+ }
430
+ catch (SQLException & e)
431
+ {
432
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get date value for the designated column (%d): %s", column, e.getText());
433
+ }
434
+ }
435
+
436
+ VALUE WrapResultSet::getTime(VALUE self, VALUE columnValue)
437
+ {
438
+ int column = NUM2UINT(columnValue);
439
+ try
440
+ {
441
+ return rb_str_new2(asPtr(self)->getString(column));
442
+ //Time* time = asPtr(self)->getTime(column);
443
+ //SqlTime timestamp(time->getMilliseconds());
444
+ //struct tm utc;
445
+ //timestamp.getTime(&utc);
446
+ //char buffer[250];
447
+ //::strftime(buffer,sizeof(buffer),"%Y%m%dT%I%M%S+0000",&utc);
448
+ // Workaround until we fix the Date/Time support
449
+ // Convert time to local time?
450
+ //snprintf(buffer, sizeof(buffer), "%u:%u:%u", utc.tm_hour, utc.tm_min, utc.tm_sec);
451
+ //return rb_str_new2(buffer);
452
+ }
453
+ catch (SQLException & e)
454
+ {
455
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get time value for the designated column (%d): %s", column, e.getText());
456
+ }
457
+ }
458
+
459
+ VALUE WrapResultSet::getTimestamp(VALUE self, VALUE columnValue)
460
+ {
461
+ int column = NUM2UINT(columnValue);
462
+ try
463
+ {
464
+ return rb_str_new2(asPtr(self)->getString(column));
465
+ //Timestamp* ts = asPtr(self)->getTimestamp(column);
466
+ //SqlTimestamp timestamp(ts->getMilliseconds());
467
+ //struct tm utc;
468
+ //timestamp.getTimestamp(&utc);
469
+ //char buffer[250];
470
+ //::strftime(buffer,sizeof(buffer),"%Y%m%dT%I%M%S+0000",&utc);
471
+ //return rb_str_new2(buffer);
472
+ }
473
+ catch (SQLException & e)
474
+ {
475
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get timestamp value for the designated column (%d): %s", column, e.getText());
476
+ }
477
+ }
478
+
479
+ VALUE WrapResultSet::getChar(VALUE self, VALUE columnValue)
480
+ {
481
+ int column = NUM2UINT(columnValue);
482
+ try
483
+ {
484
+ return rb_str_new2(asPtr(self)->getString(column));
485
+ }
486
+ catch (SQLException & e)
487
+ {
488
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get char value for the designated column (%d): %s", column, e.getText());
489
+ }
490
+ }
491
+
492
+ //------------------------------------------------------------------------------
493
+
494
+ void WrapResultSetMetaData::init(VALUE module)
495
+ {
496
+ INIT_TYPE("ResultMetaData");
497
+ DEFINE_METHOD(getColumnCount, 0);
498
+ DEFINE_METHOD(getColumnName, 1);
499
+ DEFINE_METHOD(getType, 1);
500
+ DEFINE_METHOD(getColumnTypeName, 1);
501
+ DEFINE_METHOD(getScale, 1);
502
+ DEFINE_METHOD(getPrecision, 1);
503
+ DEFINE_METHOD(isNullable, 1);
504
+ }
505
+
506
+ VALUE WrapResultSetMetaData::getColumnCount(VALUE self)
507
+ {
508
+ try
509
+ {
510
+ return UINT2NUM(asPtr(self)->getColumnCount());
511
+ }
512
+ catch (SQLException & e)
513
+ {
514
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get column count from the result set metadata: %s", e.getText());
515
+ }
516
+ }
517
+
518
+ VALUE WrapResultSetMetaData::getColumnName(VALUE self, VALUE columnValue)
519
+ {
520
+ int column = NUM2UINT(columnValue);
521
+ try
522
+ {
523
+ return rb_str_new2(asPtr(self)->getColumnName(column));
524
+ }
525
+ catch (SQLException & e)
526
+ {
527
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get column name from the result set metadata: %s", e.getText());
528
+ }
529
+ }
530
+
531
+ VALUE WrapResultSetMetaData::getScale(VALUE self, VALUE columnValue)
532
+ {
533
+ int column = NUM2UINT(columnValue);
534
+ try
535
+ {
536
+ return UINT2NUM(asPtr(self)->getScale(column));
537
+ }
538
+ catch (SQLException & e)
539
+ {
540
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get scale from the result set metadata: %s", e.getText());
541
+ }
542
+ }
543
+
544
+ VALUE WrapResultSetMetaData::getPrecision(VALUE self, VALUE columnValue)
545
+ {
546
+ int column = NUM2UINT(columnValue);
547
+ try
548
+ {
549
+ return UINT2NUM(asPtr(self)->getPrecision(column));
550
+ }
551
+ catch (SQLException & e)
552
+ {
553
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get precision from the result set metadata: %s", e.getText());
554
+ }
555
+ }
556
+
557
+ VALUE WrapResultSetMetaData::isNullable(VALUE self, VALUE columnValue)
558
+ {
559
+ int column = NUM2UINT(columnValue);
560
+ try
561
+ {
562
+ return AS_QBOOL(asPtr(self)->isNullable(column));
563
+ }
564
+ catch (SQLException & e)
565
+ {
566
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to determine nullability from the result set metadata: %s", e.getText());
567
+ }
568
+ }
569
+
570
+ VALUE WrapResultSetMetaData::getColumnTypeName(VALUE self, VALUE columnValue)
571
+ {
572
+ int column = NUM2UINT(columnValue);
573
+ try
574
+ {
575
+ return rb_str_new2(asPtr(self)->getColumnTypeName(column));
576
+ }
577
+ catch (SQLException & e)
578
+ {
579
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get column type name from the result set metadata for the designated column (%d): %s", column, e.getText());
580
+ }
581
+ }
582
+
583
+ VALUE WrapResultSetMetaData::getType(VALUE self, VALUE columnValue)
584
+ {
585
+ int column = NUM2UINT(columnValue);
586
+ SqlType t = (SqlType)asPtr(self)->getColumnType(column);
587
+
588
+ switch(t)
589
+ {
590
+ case NUOSQL_NULL:
591
+ return SYMBOL_OF(SQL_NULL);
592
+ case NUOSQL_BIT:
593
+ return SYMBOL_OF(SQL_BIT);
594
+ case NUOSQL_TINYINT:
595
+ return SYMBOL_OF(SQL_TINYINT);
596
+ case NUOSQL_SMALLINT:
597
+ return SYMBOL_OF(SQL_SMALLINT);
598
+ case NUOSQL_INTEGER:
599
+ return SYMBOL_OF(SQL_INTEGER);
600
+ case NUOSQL_BIGINT:
601
+ return SYMBOL_OF(SQL_BIGINT);
602
+ case NUOSQL_FLOAT:
603
+ return SYMBOL_OF(SQL_FLOAT);
604
+ case NUOSQL_DOUBLE:
605
+ return SYMBOL_OF(SQL_DOUBLE);
606
+ case NUOSQL_CHAR:
607
+ return SYMBOL_OF(SQL_CHAR);
608
+ case NUOSQL_VARCHAR:
609
+ return SYMBOL_OF(SQL_STRING);
610
+ case NUOSQL_LONGVARCHAR:
611
+ return SYMBOL_OF(SQL_LONGVARCHAR);
612
+ case NUOSQL_DATE:
613
+ return SYMBOL_OF(SQL_DATE);
614
+ case NUOSQL_TIME:
615
+ return SYMBOL_OF(SQL_TIME);
616
+ case NUOSQL_TIMESTAMP:
617
+ return SYMBOL_OF(SQL_TIMESTAMP);
618
+ case NUOSQL_BLOB:
619
+ return SYMBOL_OF(SQL_BLOB);
620
+ case NUOSQL_CLOB:
621
+ return SYMBOL_OF(SQL_CLOB);
622
+ case NUOSQL_NUMERIC:
623
+ return SYMBOL_OF(SQL_NUMERIC);
624
+ case NUOSQL_DECIMAL:
625
+ return SYMBOL_OF(SQL_DECIMAL);
626
+ case NUOSQL_BOOLEAN:
627
+ return SYMBOL_OF(SQL_BOOLEAN);
628
+ case NUOSQL_BINARY:
629
+ return SYMBOL_OF(SQL_BINARY);
630
+ case NUOSQL_LONGVARBINARY:
631
+ return SYMBOL_OF(SQL_LONGVARBINARY);
632
+ default:
633
+ // raise FEATURE_NOT_YET_IMPLEMENTED for unsupported types
634
+ rb_raise_nuodb_error(-2, "Invalid SQL type: %d", t);
635
+ }
636
+ }
637
+
638
+ //------------------------------------------------------------------------------
639
+
640
+ void WrapStatement::init(VALUE module)
641
+ {
642
+ INIT_TYPE("Statement");
643
+ DEFINE_METHOD(close, 0);
644
+ DEFINE_METHOD(execute, 1);
645
+ DEFINE_METHOD(executeQuery, 1);
646
+ DEFINE_METHOD(executeUpdate, 1);
647
+ DEFINE_METHOD(getResultSet, 0);
648
+ DEFINE_METHOD(getUpdateCount, 0);
649
+ DEFINE_METHOD(getGeneratedKeys, 0);
650
+ }
651
+
652
+ VALUE WrapStatement::close(VALUE self)
653
+ {
654
+ try
655
+ {
656
+ asPtr(self)->close();
657
+ return Qnil;
658
+ }
659
+ catch (SQLException & e)
660
+ {
661
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close statement: %s", e.getText());
662
+ }
663
+ }
664
+
665
+ VALUE WrapStatement::execute(VALUE self, VALUE sqlValue)
666
+ {
667
+ const char* sql = StringValuePtr(sqlValue);
668
+ try
669
+ {
670
+ return AS_QBOOL(asPtr(self)->execute(sql, NuoDB::RETURN_GENERATED_KEYS ));
671
+ }
672
+ catch (SQLException & e)
673
+ {
674
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to execute SQL statement (\"%s\"): %s", sql, e.getText());
675
+ }
676
+ }
677
+
678
+ VALUE WrapStatement::executeQuery(VALUE self, VALUE sqlValue)
679
+ {
680
+ const char* sql = StringValuePtr(sqlValue);
681
+ try
682
+ {
683
+ return WrapResultSet::wrap(asPtr(self)->executeQuery(sql));
684
+ }
685
+ catch (SQLException & e)
686
+ {
687
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to execute SQL query statement (\"%s\"): %s", sql, e.getText());
688
+ }
689
+ }
690
+
691
+ VALUE WrapStatement::executeUpdate(VALUE self, VALUE sqlValue)
692
+ {
693
+ const char* sql = StringValuePtr(sqlValue);
694
+ try
695
+ {
696
+ return INT2NUM(asPtr(self)->executeUpdate(sql));
697
+ }
698
+ catch (SQLException & e)
699
+ {
700
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to execute SQL update statement (\"%s\"): %s", sql, e.getText());
701
+ }
702
+ }
703
+
704
+ VALUE WrapStatement::getResultSet(VALUE self)
705
+ {
706
+ try
707
+ {
708
+ return WrapResultSet::wrap(asPtr(self)->getResultSet());
709
+ }
710
+ catch (SQLException & e)
711
+ {
712
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get statement result set: %s", e.getText());
713
+ }
714
+ }
715
+
716
+ VALUE WrapStatement::getUpdateCount(VALUE self)
717
+ {
718
+ try
719
+ {
720
+ return INT2NUM(asPtr(self)->getUpdateCount());
721
+ }
722
+ catch (SQLException & e)
723
+ {
724
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get update count for statement: %s", e.getText());
725
+ }
726
+ }
727
+
728
+ VALUE WrapStatement::getGeneratedKeys(VALUE self)
729
+ {
730
+ try
731
+ {
732
+ return WrapResultSet::wrap(asPtr(self)->getGeneratedKeys());
733
+ }
734
+ catch (SQLException & e)
735
+ {
736
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get generated keys for statement: %s", e.getText());
737
+ }
738
+ }
739
+
740
+ //------------------------------------------------------------------------------
741
+
742
+ void WrapPreparedStatement::init(VALUE module)
743
+ {
744
+ INIT_TYPE("PreparedStatement");
745
+ DEFINE_METHOD(close, 0);
746
+ DEFINE_METHOD(setBoolean, 2);
747
+ DEFINE_METHOD(setInteger, 2);
748
+ DEFINE_METHOD(setDouble, 2);
749
+ DEFINE_METHOD(setString, 2);
750
+ DEFINE_METHOD(setTime, 2);
751
+ DEFINE_METHOD(execute, 0);
752
+ DEFINE_METHOD(executeQuery, 0);
753
+ DEFINE_METHOD(executeUpdate, 0);
754
+ DEFINE_METHOD(getResultSet, 0);
755
+ DEFINE_METHOD(getUpdateCount, 0);
756
+ DEFINE_METHOD(getGeneratedKeys, 0);
757
+ }
758
+
759
+ VALUE WrapPreparedStatement::close(VALUE self)
760
+ {
761
+ try
762
+ {
763
+ asPtr(self)->close();
764
+ return Qnil;
765
+ }
766
+ catch (SQLException & e)
767
+ {
768
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully close prepared statement: %s", e.getText());
769
+ }
770
+ }
771
+
772
+ VALUE WrapPreparedStatement::setTime(VALUE self, VALUE indexValue, VALUE valueValue)
773
+ {
774
+ int32_t index = NUM2UINT(indexValue);
775
+ struct timeval tv = rb_time_timeval(valueValue);
776
+
777
+ SqlDate d( (((int64_t)tv.tv_sec)* 1000)+ (((int64_t)tv.tv_usec)/ 1000));
778
+ try
779
+ {
780
+ asPtr(self)->setDate(index, &d);
781
+ return Qnil;
782
+ }
783
+ catch (SQLException & e)
784
+ {
785
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to set prepared statement setTime(%d, %lld) failed: %s",
786
+ index, d.getMilliseconds(), e.getText());
787
+ }
788
+ }
789
+
790
+ VALUE WrapPreparedStatement::setBoolean(VALUE self, VALUE indexValue, VALUE valueValue)
791
+ {
792
+ int32_t index = NUM2UINT(indexValue);
793
+ bool value = valueValue ? true : false;
794
+ try
795
+ {
796
+ asPtr(self)->setInt(index, value);
797
+ return Qnil;
798
+ }
799
+ catch (SQLException & e)
800
+ {
801
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to set prepared statement boolean value (%d, %s): %s",
802
+ index, (value ? "true" : "false"), e.getText());
803
+ }
804
+ }
805
+
806
+ VALUE WrapPreparedStatement::setInteger(VALUE self, VALUE indexValue, VALUE valueValue)
807
+ {
808
+ int32_t index = NUM2UINT(indexValue);
809
+ int32_t value = NUM2INT(valueValue);
810
+ try
811
+ {
812
+ asPtr(self)->setInt(index, value);
813
+ return Qnil;
814
+ }
815
+ catch (SQLException & e)
816
+ {
817
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to set prepared statement integer value (%d, %d): %s", index, value, e.getText());
818
+ }
819
+ }
820
+
821
+ VALUE WrapPreparedStatement::setDouble(VALUE self, VALUE indexValue, VALUE valueValue)
822
+ {
823
+ int32_t index = NUM2UINT(indexValue);
824
+ double value = NUM2DBL(valueValue);
825
+ try
826
+ {
827
+ asPtr(self)->setDouble(index, value);
828
+ return Qnil;
829
+ }
830
+ catch (SQLException & e)
831
+ {
832
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to set prepared statement double value (%d, %g): %s", index, value, e.getText());
833
+ }
834
+ }
835
+
836
+ VALUE WrapPreparedStatement::setString(VALUE self, VALUE indexValue, VALUE valueValue)
837
+ {
838
+ int32_t index = NUM2UINT(indexValue);
839
+ char const* value = RSTRING_PTR(valueValue);
840
+ try
841
+ {
842
+ asPtr(self)->setString(index, value);
843
+ return Qnil;
844
+ }
845
+ catch (SQLException & e)
846
+ {
847
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to set prepared statement string value (%d, \"%s\"): %s", index, value, e.getText());
848
+ }
849
+ }
850
+
851
+ VALUE WrapPreparedStatement::execute(VALUE self)
852
+ {
853
+ try
854
+ {
855
+ return AS_QBOOL(asPtr(self)->execute());
856
+ }
857
+ catch (SQLException & e)
858
+ {
859
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to execute SQL prepared statement: %s", e.getText());
860
+ }
861
+ }
862
+
863
+ VALUE WrapPreparedStatement::executeQuery(VALUE self)
864
+ {
865
+ try
866
+ {
867
+ return WrapResultSet::wrap(asPtr(self)->executeQuery());
868
+ }
869
+ catch (SQLException & e)
870
+ {
871
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to execute SQL query prepared statement: %s", e.getText());
872
+ }
873
+ }
874
+
875
+ VALUE WrapPreparedStatement::executeUpdate(VALUE self)
876
+ {
877
+ try
878
+ {
879
+ return INT2NUM(asPtr(self)->executeUpdate());
880
+ }
881
+ catch (SQLException & e)
882
+ {
883
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to execute SQL update prepared statement: %s", e.getText());
884
+ }
885
+ }
886
+
887
+ VALUE WrapPreparedStatement::getResultSet(VALUE self)
888
+ {
889
+ try
890
+ {
891
+ return WrapResultSet::wrap(asPtr(self)->getResultSet());
892
+ }
893
+ catch (SQLException & e)
894
+ {
895
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get the result set for the prepared statement: %s", e.getText());
896
+ }
897
+ }
898
+
899
+ VALUE WrapPreparedStatement::getUpdateCount(VALUE self)
900
+ {
901
+ try
902
+ {
903
+ return INT2NUM(asPtr(self)->getUpdateCount());
904
+ }
905
+ catch (SQLException & e)
906
+ {
907
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get the update count for the prepared statement: %s", e.getText());
908
+ }
909
+ }
910
+
911
+ VALUE WrapPreparedStatement::getGeneratedKeys(VALUE self)
912
+ {
913
+ try
914
+ {
915
+ return WrapResultSet::wrap(asPtr(self)->getGeneratedKeys());
916
+ }
917
+ catch (SQLException & e)
918
+ {
919
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get the generated keys for the prepared statement: %s", e.getText());
920
+ }
921
+ }
922
+
923
+ //------------------------------------------------------------------------------
924
+
925
+ void WrapConnection::init(VALUE module)
926
+ {
927
+ type = rb_define_class_under(module, "Connection", rb_cObject);
928
+
929
+ // DBI
930
+
931
+ // todo add .columns, or not? If we did: .columns(table_name)
932
+ // todo and tie this into the SchemaCache on the Ruby side.
933
+ rb_define_method(type, "commit", RUBY_METHOD_FUNC(commit), 0);
934
+ rb_define_method(type, "disconnect", RUBY_METHOD_FUNC(close), 0);
935
+ rb_define_method(type, "ping", RUBY_METHOD_FUNC(ping), 0);
936
+ rb_define_method(type, "prepare", RUBY_METHOD_FUNC(createPreparedStatement), 1);
937
+ rb_define_method(type, "rollback", RUBY_METHOD_FUNC(rollback), 0);
938
+ // todo add .tables, definitely!
939
+
940
+ // NUODB EXTENSIONS
941
+
942
+ rb_define_method(type, "autocommit=", RUBY_METHOD_FUNC(setAutoCommit), 1);
943
+ rb_define_method(type, "autocommit?", RUBY_METHOD_FUNC(hasAutoCommit), 0);
944
+
945
+ // DEPRECATED, going away shortly...
946
+
947
+ // todo use .new and .initialize instead...
948
+ DEFINE_SINGLE(createSqlConnection, 4);
949
+ DEFINE_METHOD(createStatement, 0);
950
+ DEFINE_METHOD(createPreparedStatement, 1);
951
+ DEFINE_METHOD(setAutoCommit, 1);
952
+ DEFINE_METHOD(hasAutoCommit, 0);
953
+ DEFINE_METHOD(getMetaData, 0);
954
+ DEFINE_METHOD(close, 0);
955
+ DEFINE_METHOD(getSchema, 0);
956
+ }
957
+
958
+ VALUE WrapConnection::getSchema(VALUE self)
959
+ {
960
+ try
961
+ {
962
+ return rb_str_new2(asPtr(self)->getSchema());
963
+ }
964
+ catch (SQLException & e)
965
+ {
966
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get schema for connection: %s", e.getText());
967
+ }
968
+ }
969
+
970
+ VALUE WrapConnection::close(VALUE self)
971
+ {
972
+ try
973
+ {
974
+ asPtr(self)->close();
975
+ return Qnil;
976
+ }
977
+ catch (SQLException & e)
978
+ {
979
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to successfully disconnect connection: %s", e.getText());
980
+ }
981
+ }
982
+
983
+ VALUE WrapConnection::ping(VALUE self)
984
+ {
985
+ try
986
+ {
987
+ asPtr(self)->ping();
988
+ return Qtrue;
989
+ }
990
+ catch (SQLException & e)
991
+ {
992
+ return Qfalse;
993
+ }
994
+ }
995
+
996
+ VALUE WrapConnection::createStatement(VALUE self)
997
+ {
998
+ try
999
+ {
1000
+ return WrapStatement::wrap(asPtr(self)->createStatement());
1001
+ }
1002
+ catch (SQLException & e)
1003
+ {
1004
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to create statement: %s", e.getText());
1005
+ }
1006
+ }
1007
+
1008
+ VALUE WrapConnection::createPreparedStatement(VALUE self, VALUE sqlValue)
1009
+ {
1010
+ const char * sql = StringValuePtr(sqlValue);
1011
+ try
1012
+ {
1013
+ return WrapPreparedStatement::wrap( asPtr(self)->prepareStatement(sql, NuoDB::RETURN_GENERATED_KEYS));
1014
+ }
1015
+ catch (SQLException & e)
1016
+ {
1017
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to create prepared statement (%s): %s", sql, e.getText());
1018
+ }
1019
+ }
1020
+
1021
+ VALUE WrapConnection::setAutoCommit(VALUE self, VALUE autoCommitValue)
1022
+ {
1023
+ bool autoCommit = !(RB_TYPE_P(autoCommitValue, T_FALSE) || RB_TYPE_P(autoCommitValue, T_NIL));
1024
+ try
1025
+ {
1026
+ asPtr(self)->setAutoCommit(autoCommit);
1027
+ return Qnil;
1028
+ }
1029
+ catch (SQLException & e)
1030
+ {
1031
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to set auto-commit (%d) for connection: %s", autoCommit, e.getText());
1032
+ }
1033
+ }
1034
+
1035
+ VALUE WrapConnection::hasAutoCommit(VALUE self)
1036
+ {
1037
+ try
1038
+ {
1039
+ return AS_QBOOL(asPtr(self)->getAutoCommit());
1040
+ }
1041
+ catch (SQLException & e)
1042
+ {
1043
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to determine auto-commit state for connection: %s", e.getText());
1044
+ }
1045
+ }
1046
+
1047
+ VALUE WrapConnection::commit(VALUE self)
1048
+ {
1049
+ try
1050
+ {
1051
+ asPtr(self)->commit();
1052
+ return Qnil;
1053
+ }
1054
+ catch (SQLException & e)
1055
+ {
1056
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to commit transaction: %s", e.getText());
1057
+ }
1058
+ }
1059
+
1060
+ VALUE WrapConnection::rollback(VALUE self)
1061
+ {
1062
+ try
1063
+ {
1064
+ asPtr(self)->rollback();
1065
+ return Qnil;
1066
+ }
1067
+ catch (SQLException & e)
1068
+ {
1069
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to rollback transaction: %s", e.getText());
1070
+ }
1071
+ }
1072
+
1073
+ VALUE WrapConnection::getMetaData(VALUE self)
1074
+ {
1075
+ try
1076
+ {
1077
+ return WrapDatabaseMetaData::wrap( asPtr(self)->getMetaData());
1078
+ }
1079
+ catch (SQLException & e)
1080
+ {
1081
+ rb_raise_nuodb_error(e.getSqlcode(), "Failed to get database metadata: %s", e.getText());
1082
+ }
1083
+ }
1084
+
1085
+ VALUE WrapConnection::createSqlConnection(VALUE self,
1086
+ VALUE databaseValue,
1087
+ VALUE schemaValue,
1088
+ VALUE usernameValue,
1089
+ VALUE passwordValue)
1090
+ {
1091
+ char const* database = StringValuePtr(databaseValue);
1092
+ char const* schema = StringValuePtr(schemaValue);
1093
+ char const* username = StringValuePtr(usernameValue);
1094
+ char const* password = StringValuePtr(passwordValue);
1095
+
1096
+ try
1097
+ {
1098
+ return WrapConnection::wrap( getDatabaseConnection(database,
1099
+ username,
1100
+ password,
1101
+ 1,
1102
+ "schema",
1103
+ schema));
1104
+ }
1105
+ catch (SQLException & e)
1106
+ {
1107
+ rb_raise_nuodb_error(e.getSqlcode(),
1108
+ "Failed to create database connection (\"%s\", \"%s\", ********, \"%s\"): %s",
1109
+ database,
1110
+ username,
1111
+ schema,
1112
+ e.getText());
1113
+ }
1114
+ }
1115
+
1116
+ //------------------------------------------------------------------------------
1117
+
1118
+ extern "C" void Init_nuodb(void)
1119
+ {
1120
+ m_nuodb = rb_define_module("NuoDB");
1121
+ c_nuodb_error = rb_const_get(m_nuodb, rb_intern("Error"));
1122
+ c_error_code_assignment = rb_intern("error_code=");
1123
+
1124
+ WrapConnection::init(m_nuodb);
1125
+ WrapDatabaseMetaData::init(m_nuodb);
1126
+ WrapStatement::init(m_nuodb);
1127
+ WrapPreparedStatement::init(m_nuodb);
1128
+ WrapResultSet::init(m_nuodb);
1129
+ WrapResultSetMetaData::init(m_nuodb);
1130
+ }