nuodb 1.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }