rubyfb 0.5.2-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/CHANGELOG +6 -0
  2. data/LICENSE +411 -0
  3. data/Manifest +75 -0
  4. data/README +460 -0
  5. data/Rakefile +21 -0
  6. data/examples/example01.rb +65 -0
  7. data/ext/AddUser.c +464 -0
  8. data/ext/AddUser.h +37 -0
  9. data/ext/Backup.c +783 -0
  10. data/ext/Backup.h +37 -0
  11. data/ext/Blob.c +421 -0
  12. data/ext/Blob.h +65 -0
  13. data/ext/Common.c +54 -0
  14. data/ext/Common.h +37 -0
  15. data/ext/Connection.c +863 -0
  16. data/ext/Connection.h +50 -0
  17. data/ext/DataArea.c +274 -0
  18. data/ext/DataArea.h +38 -0
  19. data/ext/Database.c +449 -0
  20. data/ext/Database.h +48 -0
  21. data/ext/FireRuby.c +240 -0
  22. data/ext/FireRuby.h +50 -0
  23. data/ext/FireRubyException.c +268 -0
  24. data/ext/FireRubyException.h +51 -0
  25. data/ext/Generator.c +689 -0
  26. data/ext/Generator.h +53 -0
  27. data/ext/RemoveUser.c +212 -0
  28. data/ext/RemoveUser.h +37 -0
  29. data/ext/Restore.c +855 -0
  30. data/ext/Restore.h +37 -0
  31. data/ext/ResultSet.c +810 -0
  32. data/ext/ResultSet.h +60 -0
  33. data/ext/Row.c +965 -0
  34. data/ext/Row.h +55 -0
  35. data/ext/ServiceManager.c +316 -0
  36. data/ext/ServiceManager.h +48 -0
  37. data/ext/Services.c +124 -0
  38. data/ext/Services.h +42 -0
  39. data/ext/Statement.c +785 -0
  40. data/ext/Statement.h +62 -0
  41. data/ext/Transaction.c +684 -0
  42. data/ext/Transaction.h +50 -0
  43. data/ext/TypeMap.c +1182 -0
  44. data/ext/TypeMap.h +51 -0
  45. data/ext/extconf.rb +30 -0
  46. data/lib/SQLType.rb +224 -0
  47. data/lib/active_record/connection_adapters/rubyfb_adapter.rb +805 -0
  48. data/lib/mkdoc +1 -0
  49. data/lib/rubyfb.rb +2 -0
  50. data/lib/rubyfb_lib.so +0 -0
  51. data/lib/src.rb +1800 -0
  52. data/mswin32fb/fbclient_ms.lib +0 -0
  53. data/mswin32fb/ibase.h +2555 -0
  54. data/mswin32fb/iberror.h +1741 -0
  55. data/rubyfb.gemspec +31 -0
  56. data/test/AddRemoveUserTest.rb +56 -0
  57. data/test/BackupRestoreTest.rb +99 -0
  58. data/test/BlobTest.rb +57 -0
  59. data/test/CharacterSetTest.rb +63 -0
  60. data/test/ConnectionTest.rb +111 -0
  61. data/test/DDLTest.rb +54 -0
  62. data/test/DatabaseTest.rb +83 -0
  63. data/test/GeneratorTest.rb +50 -0
  64. data/test/KeyTest.rb +140 -0
  65. data/test/ResultSetTest.rb +162 -0
  66. data/test/RoleTest.rb +73 -0
  67. data/test/RowCountTest.rb +65 -0
  68. data/test/RowTest.rb +203 -0
  69. data/test/SQLTest.rb +182 -0
  70. data/test/SQLTypeTest.rb +101 -0
  71. data/test/ServiceManagerTest.rb +29 -0
  72. data/test/StatementTest.rb +135 -0
  73. data/test/TestSetup.rb +11 -0
  74. data/test/TransactionTest.rb +112 -0
  75. data/test/TypeTest.rb +92 -0
  76. data/test/UnitTest.rb +65 -0
  77. metadata +143 -0
data/ext/Restore.h ADDED
@@ -0,0 +1,37 @@
1
+ /*------------------------------------------------------------------------------
2
+ * Restore.h
3
+ *----------------------------------------------------------------------------*/
4
+ /**
5
+ * Copyright � Peter Wood, 2005
6
+ *
7
+ * The contents of this file are subject to the Mozilla Public License Version
8
+ * 1.1 (the "License"); you may not use this file except in compliance with the
9
+ * License. You may obtain a copy of the License at
10
+ *
11
+ * http://www.mozilla.org/MPL/
12
+ *
13
+ * Software distributed under the License is distributed on an "AS IS" basis,
14
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
15
+ * the specificlanguage governing rights and limitations under the License.
16
+ *
17
+ * The Original Code is the FireRuby extension for the Ruby language.
18
+ *
19
+ * The Initial Developer of the Original Code is Peter Wood. All Rights
20
+ * Reserved.
21
+ *
22
+ * @author Peter Wood
23
+ * @version 1.0
24
+ */
25
+ #ifndef FIRERUBY_RESTORE_H
26
+ #define FIRERUBY_RESTORE_H
27
+
28
+ /* Includes. */
29
+ #ifndef RUBY_H_INCLUDED
30
+ #include "ruby.h"
31
+ #define RUBY_H_INCLUDED
32
+ #endif
33
+
34
+ /* Function prototypes. */
35
+ void Init_Restore(VALUE);
36
+
37
+ #endif /* FIRERUBY_RESTORE_H */
data/ext/ResultSet.c ADDED
@@ -0,0 +1,810 @@
1
+ /*------------------------------------------------------------------------------
2
+ * ResultSet.c
3
+ *----------------------------------------------------------------------------*/
4
+ /**
5
+ * Copyright � Peter Wood, 2005
6
+ *
7
+ * The contents of this file are subject to the Mozilla Public License Version
8
+ * 1.1 (the "License"); you may not use this file except in compliance with the
9
+ * License. You may obtain a copy of the License at
10
+ *
11
+ * http://www.mozilla.org/MPL/
12
+ *
13
+ * Software distributed under the License is distributed on an "AS IS" basis,
14
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
15
+ * the specificlanguage governing rights and limitations under the License.
16
+ *
17
+ * The Original Code is the FireRuby extension for the Ruby language.
18
+ *
19
+ * The Initial Developer of the Original Code is Peter Wood. All Rights
20
+ * Reserved.
21
+ *
22
+ * @author Peter Wood
23
+ * @version 1.0
24
+ */
25
+
26
+ /* Includes. */
27
+ #include "ResultSet.h"
28
+ #include "Common.h"
29
+ #include "Statement.h"
30
+ #include "Connection.h"
31
+ #include "Transaction.h"
32
+ #include "DataArea.h"
33
+ #include "Row.h"
34
+ #include "TypeMap.h"
35
+ #include "ruby.h"
36
+
37
+ /* Function prototypes. */
38
+ static VALUE allocateResultSet(VALUE);
39
+ static VALUE initializeResultSet(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
40
+ static VALUE fetchResultSetEntry(VALUE);
41
+ static VALUE closeResultSet(VALUE);
42
+ static VALUE getResultSetCount(VALUE);
43
+ static VALUE getResultSetConnection(VALUE);
44
+ static VALUE getResultSetTransaction(VALUE);
45
+ static VALUE getResultSetSQL(VALUE);
46
+ static VALUE getResultSetDialect(VALUE);
47
+ static VALUE getResultSetColumnCount(VALUE);
48
+ static VALUE getResultSetColumnName(VALUE, VALUE);
49
+ static VALUE getResultSetColumnAlias(VALUE, VALUE);
50
+ static VALUE getResultSetColumnTable(VALUE, VALUE);
51
+ static VALUE getResultSetColumnType(VALUE, VALUE);
52
+ static VALUE eachResultSetRow(VALUE);
53
+ static VALUE isResultSetExhausted(VALUE);
54
+ static void resultSetMark(void *);
55
+ static void cleanupHandle(isc_stmt_handle *handle);
56
+ static void resolveResultsTransaction(ResultsHandle *results, char *resolveMethod);
57
+
58
+
59
+ /* Globals. */
60
+ VALUE cResultSet;
61
+
62
+ /**
63
+ * This method allocates a new ResultSet object.
64
+ *
65
+ * @param klass A reference to the ResultSet Class object.
66
+ *
67
+ * @return A reference to the newly allocated ResultSet object.
68
+ *
69
+ */
70
+ VALUE allocateResultSet(VALUE klass)
71
+ {
72
+ ResultsHandle *results = ALLOC(ResultsHandle);
73
+
74
+ if(results == NULL)
75
+ {
76
+ rb_raise(rb_eNoMemError,
77
+ "Memory allocation failure allocating a result set.");
78
+ }
79
+ results->handle = 0;
80
+ results->output = NULL;
81
+ results->exhausted = 0;
82
+ results->fetched = 0;
83
+ results->dialect = 0;
84
+ results->procedure_output_fetch_state = -1;
85
+ results->transaction = Qnil;
86
+
87
+ return(Data_Wrap_Struct(klass, resultSetMark, resultSetFree, results));
88
+ }
89
+
90
+
91
+ /**
92
+ * This function provides the initialize method for the ResultSet class.
93
+ *
94
+ * @param self A reference to the ResultSet object to be initialized.
95
+ * @param connection A reference to a Connection object that will be used
96
+ * in executing the statement.
97
+ * @param transaction A reference to a Transaction object that will be used
98
+ * in executing the statement.
99
+ * @param sql A reference to a String containing the SQL statement to
100
+ * be executed. Must be a query.
101
+ * @param dialect A reference to an integer containing the SQL dialect to
102
+ * be used in executing the query.
103
+ * @param parameters A reference to an array containing the parameters to be
104
+ * used in executing the query.
105
+ *
106
+ * @return A reference to the newly initialize ResultSet object.
107
+ *
108
+ */
109
+ VALUE initializeResultSet(VALUE self, VALUE connection, VALUE transaction,
110
+ VALUE sql, VALUE dialect, VALUE parameters)
111
+ {
112
+ short setting = 0;
113
+ int type = 0,
114
+ inputs = 0,
115
+ outputs = 0;
116
+ long affected = 0;
117
+ ResultsHandle *results = NULL;
118
+ VALUE value = Qnil;
119
+ ConnectionHandle *cHandle = NULL;
120
+ TransactionHandle *tHandle = NULL;
121
+ XSQLDA *params = NULL;
122
+
123
+ /* Validate the inputs. */
124
+ if(TYPE(connection) == T_DATA &&
125
+ RDATA(connection)->dfree == (RUBY_DATA_FUNC)connectionFree)
126
+ {
127
+ if(rb_funcall(connection, rb_intern("open?"), 0) == Qfalse)
128
+ {
129
+ rb_fireruby_raise(NULL, "Closed connection specified for result set.");
130
+ }
131
+ }
132
+ else
133
+ {
134
+ rb_fireruby_raise(NULL, "Invalid connection specified for result set.");
135
+ }
136
+
137
+ if(TYPE(transaction) == T_DATA &&
138
+ RDATA(transaction)->dfree == (RUBY_DATA_FUNC)transactionFree)
139
+ {
140
+ if(rb_funcall(transaction, rb_intern("active?"), 0) == Qfalse)
141
+ {
142
+ rb_fireruby_raise(NULL, "Inactive transaction specified for result set.");
143
+ }
144
+ }
145
+ else
146
+ {
147
+ rb_fireruby_raise(NULL, "Invalid transaction specified for result set.");
148
+ }
149
+
150
+ value = rb_funcall(dialect, rb_intern("to_i"), 0);
151
+ if(TYPE(value) == T_FIXNUM)
152
+ {
153
+ setting = FIX2INT(value);
154
+ if(setting < 1 || setting > 3)
155
+ {
156
+ rb_fireruby_raise(NULL,
157
+ "Invalid dialect value specified for result set. "\
158
+ "The dialect value must be between 1 and 3.");
159
+ }
160
+ }
161
+ else
162
+ {
163
+ rb_fireruby_raise(NULL,
164
+ "Invalid dialect value specified for result set. The "\
165
+ "dialect value must be between 1 and 3.");
166
+ }
167
+
168
+ /* Prepare the result set. */
169
+ Data_Get_Struct(connection, ConnectionHandle, cHandle);
170
+ Data_Get_Struct(transaction, TransactionHandle, tHandle);
171
+ Data_Get_Struct(self, ResultsHandle, results);
172
+ prepare(&cHandle->handle, &tHandle->handle, STR2CSTR(sql), &results->handle,
173
+ setting, &type, &inputs, &outputs);
174
+
175
+ if(type != isc_info_sql_stmt_select &&
176
+ type != isc_info_sql_stmt_select_for_upd &&
177
+ type != isc_info_sql_stmt_exec_procedure)
178
+ {
179
+ cleanupHandle(&results->handle);
180
+ rb_fireruby_raise(NULL,
181
+ "Non-query SQL statement specified for result set.");
182
+ }
183
+
184
+ rb_iv_set(self, "@connection", connection);
185
+ rb_iv_set(self, "@transaction", transaction);
186
+ rb_iv_set(self, "@sql", rb_funcall(sql, rb_intern("to_s"), 0));
187
+ rb_iv_set(self, "@dialect", value);
188
+ results->dialect = setting;
189
+
190
+ /* UNCOMMENT FOR DEBUGGING PURPOSES! */
191
+ /*strcpy(results->sql, STR2CSTR(sql));*/
192
+
193
+ /* Check if input parameters are needed. */
194
+ if(inputs > 0)
195
+ {
196
+ VALUE value = Qnil;
197
+ int size = 0;
198
+
199
+ if(parameters == Qnil)
200
+ {
201
+ cleanupHandle(&results->handle);
202
+ rb_fireruby_raise(NULL,
203
+ "Empty parameter list specified for result set.");
204
+ }
205
+
206
+ value = rb_funcall(parameters, rb_intern("size"), 0);
207
+ size = TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value);
208
+ if(size < inputs)
209
+ {
210
+ cleanupHandle(&results->handle);
211
+ rb_fireruby_raise(NULL,
212
+ "Insufficient parameters specified for result set.");
213
+ }
214
+
215
+ /* Allocate the XSQLDA and populate it. */
216
+ params = allocateInXSQLDA(inputs, &results->handle, setting);
217
+ prepareDataArea(params);
218
+ setParameters(params, parameters, self);
219
+ }
220
+
221
+ /* Allocate output storage. */
222
+ results->output = allocateOutXSQLDA(outputs, &results->handle, setting);
223
+ prepareDataArea(results->output);
224
+
225
+ /* Execute the statement and clean up. */
226
+ if(type == isc_info_sql_stmt_exec_procedure) {
227
+ /* Execute with output params */
228
+ execute_2(&tHandle->handle, &results->handle, setting, params, type,
229
+ &affected, results->output);
230
+ /* Initialize procedure output fetch */
231
+ results->procedure_output_fetch_state = 0;
232
+ /* Early resolve transaction */
233
+ resolveResultsTransaction (results, "commit");
234
+ } else {
235
+ execute(&tHandle->handle, &results->handle, setting, params, type,
236
+ &affected);
237
+ }
238
+ if(params != NULL)
239
+ {
240
+ releaseDataArea(params);
241
+ }
242
+
243
+ return(self);
244
+ }
245
+
246
+
247
+ /**
248
+ * This function provides the fetch method for the ResultSet class.
249
+ *
250
+ * @param self A reference to the ResultSet object to make the call on.
251
+ *
252
+ * @return Either a reference to a Row object or nil.
253
+ *
254
+ */
255
+ VALUE fetchResultSetEntry(VALUE self)
256
+ {
257
+ VALUE row = Qnil;
258
+ ResultsHandle *results = NULL;
259
+ ISC_STATUS status[20],
260
+ value;
261
+
262
+ Data_Get_Struct(self, ResultsHandle, results);
263
+ if(results->handle != 0)
264
+ {
265
+ VALUE array,number;
266
+ value = results->procedure_output_fetch_state;
267
+ if(value < 0) {
268
+ value = isc_dsql_fetch(status, &results->handle, results->dialect,
269
+ results->output);
270
+ } else {
271
+ /* move procedure_output_fetch_state ahead - fetch only one row */
272
+ results->procedure_output_fetch_state = 100;
273
+ }
274
+ array = Qnil;
275
+ number = Qnil;
276
+ switch(value)
277
+ {
278
+ case 0 :
279
+ array = toArray(self);
280
+ number = INT2NUM(++(results->fetched));
281
+ row = rb_row_new(self, array, number);
282
+ break;
283
+ case 100 :
284
+ results->exhausted = 1;
285
+ resolveResultsTransaction(results, "commit");
286
+ break;
287
+ default :
288
+ rb_fireruby_raise(status, "Error fetching query row.");
289
+ }
290
+ }
291
+
292
+ return(row);
293
+ }
294
+
295
+
296
+ /**
297
+ * This function provides the close method for the ResultSet class, releasing
298
+ * resources associated with the ResultSet.
299
+ *
300
+ * @param self A reference to the ResultSet object to be closed.
301
+ *
302
+ * @return A reference to the closed ResultSet object.
303
+ *
304
+ */
305
+ VALUE closeResultSet(VALUE self)
306
+ {
307
+ ResultsHandle *results = NULL;
308
+
309
+ Data_Get_Struct(self, ResultsHandle, results);
310
+ if(results->handle != 0)
311
+ {
312
+ ISC_STATUS status[20];
313
+
314
+ if(isc_dsql_free_statement(status, &results->handle, DSQL_drop))
315
+ {
316
+ rb_fireruby_raise(status, "Error closing result set.");
317
+ }
318
+ results->handle = 0;
319
+ }
320
+
321
+ if(results->output != NULL)
322
+ {
323
+ releaseDataArea(results->output);
324
+ results->output = NULL;
325
+ }
326
+
327
+ resolveResultsTransaction(results, "commit");
328
+
329
+ return(self);
330
+ }
331
+
332
+
333
+ /**
334
+ * This function provides the count method for the ResultSet class.
335
+ *
336
+ * @param self A reference to the ResultSet object to fetch the current row
337
+ * count for.
338
+ *
339
+ * @return A reference to an integer containing a count of the number of rows
340
+ * fetched from the ResultSet so far.
341
+ *
342
+ */
343
+ VALUE getResultSetCount(VALUE self)
344
+ {
345
+ ResultsHandle *results = NULL;
346
+
347
+ Data_Get_Struct(self, ResultsHandle, results);
348
+
349
+ return(INT2NUM(results->fetched));
350
+ }
351
+
352
+
353
+ /**
354
+ * This method provides the accessor method for the connection ResultSet
355
+ * attribute.
356
+ *
357
+ * @param self A reference to the ResultSet object to fetch the attribute
358
+ * from.
359
+ *
360
+ * @return A reference to the requested attribute object.
361
+ *
362
+ */
363
+ VALUE getResultSetConnection(VALUE self)
364
+ {
365
+ return(rb_iv_get(self, "@connection"));
366
+ }
367
+
368
+
369
+ /**
370
+ * This method provides the accessor method for the transaction ResultSet
371
+ * attribute.
372
+ *
373
+ * @param self A reference to the ResultSet object to fetch the attribute
374
+ * from.
375
+ *
376
+ * @return A reference to the requested attribute object.
377
+ *
378
+ */
379
+ VALUE getResultSetTransaction(VALUE self)
380
+ {
381
+ return(rb_iv_get(self, "@transaction"));
382
+ }
383
+
384
+
385
+ /**
386
+ * This method provides the accessor method for the SQL ResultSet attribute.
387
+ *
388
+ * @param self A reference to the ResultSet object to fetch the attribute
389
+ * from.
390
+ *
391
+ * @return A reference to the requested attribute object.
392
+ *
393
+ */
394
+ VALUE getResultSetSQL(VALUE self)
395
+ {
396
+ return(rb_iv_get(self, "@sql"));
397
+ }
398
+
399
+
400
+ /**
401
+ * This method provides the accessor method for the dialect ResultSet attribute.
402
+ *
403
+ * @param self A reference to the ResultSet object to fetch the attribute
404
+ * from.
405
+ *
406
+ * @return A reference to the requested attribute object.
407
+ *
408
+ */
409
+ VALUE getResultSetDialect(VALUE self)
410
+ {
411
+ return(rb_iv_get(self, "@dialect"));
412
+ }
413
+
414
+
415
+ /**
416
+ * This function provides the column_count attribute accessor for the ResultSet
417
+ * class.
418
+ *
419
+ * @param self A reference to the ResultSet object to fetch the attribute for.
420
+ *
421
+ * @return A reference to an integer containing the column count.
422
+ *
423
+ */
424
+ VALUE getResultSetColumnCount(VALUE self)
425
+ {
426
+ VALUE count = Qnil;
427
+ ResultsHandle *results = NULL;
428
+
429
+ Data_Get_Struct(self, ResultsHandle, results);
430
+ if(results != NULL)
431
+ {
432
+ count = INT2NUM(results->output->sqld);
433
+ }
434
+
435
+ return(count);
436
+ }
437
+
438
+
439
+ /**
440
+ * This function provides the column_name method for the ResultSet class.
441
+ *
442
+ * @param self A reference to the ResultSet object to retrieve the column
443
+ * name from.
444
+ * @param column An offset to the column to retrieve the name for.
445
+ *
446
+ * @return A String containing the column name or nil if an invalid column
447
+ * was specified.
448
+ *
449
+ */
450
+ static VALUE getResultSetColumnName(VALUE self, VALUE column)
451
+ {
452
+ VALUE name = Qnil;
453
+ ResultsHandle *results = NULL;
454
+
455
+ Data_Get_Struct(self, ResultsHandle, results);
456
+ if(results != NULL)
457
+ {
458
+ int offset = 0;
459
+
460
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
461
+ if(offset >= 0 && offset < results->output->sqld)
462
+ {
463
+ XSQLVAR *var = results->output->sqlvar;
464
+ int index;
465
+
466
+ for(index = 0; index < offset; index++, var++);
467
+ name = rb_str_new(var->sqlname, var->sqlname_length);
468
+ }
469
+ }
470
+
471
+ return(name);
472
+ }
473
+
474
+
475
+ /**
476
+ * This function provides the column_alias method for the ResultSet class.
477
+ *
478
+ * @param self A reference to the ResultSet object to retrieve the column
479
+ * alias from.
480
+ * @param column An offset to the column to retrieve the alias for.
481
+ *
482
+ * @return A String containing the column alias or nil if an invalid column
483
+ * was specified.
484
+ *
485
+ */
486
+ static VALUE getResultSetColumnAlias(VALUE self, VALUE column)
487
+ {
488
+ VALUE alias = Qnil;
489
+ ResultsHandle *results = NULL;
490
+
491
+ Data_Get_Struct(self, ResultsHandle, results);
492
+ if(results != NULL)
493
+ {
494
+ int offset = 0;
495
+
496
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
497
+ if(offset >= 0 && offset < results->output->sqld)
498
+ {
499
+ XSQLVAR *var = results->output->sqlvar;
500
+ int index;
501
+
502
+ for(index = 0; index < offset; index++, var++);
503
+ alias = rb_str_new(var->aliasname, var->aliasname_length);
504
+ }
505
+ }
506
+
507
+ return(alias);
508
+ }
509
+
510
+
511
+ /**
512
+ * This function provides the column_table method for the ResultSet class.
513
+ *
514
+ * @param self A reference to the ResultSet object to retrieve the column
515
+ * table name from.
516
+ * @param column An offset to the column to retrieve the table name for.
517
+ *
518
+ * @return A String containing the column table name or nil if an invalid
519
+ * column was specified.
520
+ *
521
+ */
522
+ static VALUE getResultSetColumnTable(VALUE self, VALUE column)
523
+ {
524
+ VALUE name = Qnil;
525
+ ResultsHandle *results = NULL;
526
+
527
+ Data_Get_Struct(self, ResultsHandle, results);
528
+ if(results != NULL)
529
+ {
530
+ int offset = 0;
531
+
532
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
533
+ if(offset >= 0 && offset < results->output->sqld)
534
+ {
535
+ XSQLVAR *var = results->output->sqlvar;
536
+ int index;
537
+
538
+ for(index = 0; index < offset; index++, var++);
539
+ name = rb_str_new(var->relname, var->relname_length);
540
+ }
541
+ }
542
+
543
+ return(name);
544
+ }
545
+
546
+
547
+ /**
548
+ * This function attempts to extract basic type information for a column within
549
+ * a ResultSet object.
550
+ *
551
+ * @param self A reference to the ResultSet to execute on.
552
+ * @param column A integer offset for the column to extract the type of.
553
+ *
554
+ * @return A Symbol representing the basic data type.
555
+ *
556
+ */
557
+ static VALUE getResultSetColumnType(VALUE self, VALUE column)
558
+ {
559
+ VALUE type = toSymbol("UNKNOWN");
560
+
561
+ if(TYPE(column) == T_FIXNUM)
562
+ {
563
+ ResultsHandle *handle = NULL;
564
+
565
+ Data_Get_Struct(self, ResultsHandle, handle);
566
+ if(handle != NULL)
567
+ {
568
+ int index = FIX2INT(column);
569
+
570
+ /* Fix negative index values. */
571
+ if(index < 0)
572
+ {
573
+ index = handle->output->sqln + index;
574
+ }
575
+
576
+ if(index >= 0 && index < handle->output->sqln)
577
+ {
578
+ type = getColumnType(&handle->output->sqlvar[index]);
579
+ }
580
+ }
581
+ }
582
+
583
+
584
+ return(type);
585
+ }
586
+
587
+
588
+ /**
589
+ * This function provides the each method for the ResultSet class.
590
+ *
591
+ * @param self A reference to the ResultSet object to execute the method for.
592
+ *
593
+ * @return A reference to the last value returned by the associated block or
594
+ * nil.
595
+ *
596
+ */
597
+ VALUE eachResultSetRow(VALUE self)
598
+ {
599
+ VALUE result = Qnil;
600
+
601
+ /* Check if a block was provided. */
602
+ if(rb_block_given_p())
603
+ {
604
+ VALUE row;
605
+
606
+ while((row = fetchResultSetEntry(self)) != Qnil)
607
+ {
608
+ result = rb_yield(row);
609
+ }
610
+ }
611
+
612
+ return(result);
613
+ }
614
+
615
+
616
+ /**
617
+ * This function provides the exhausted? method of the ResultSet class.
618
+ *
619
+ * @param self A reference to the ResultSet object to make the call for.
620
+ *
621
+ * @return True if all rows have been fetched from the result set, false
622
+ * if they haven't.
623
+ *
624
+ */
625
+ VALUE isResultSetExhausted(VALUE self)
626
+ {
627
+ VALUE exhausted = Qfalse;
628
+ ResultsHandle *results = NULL;
629
+
630
+ Data_Get_Struct(self, ResultsHandle, results);
631
+ if(results->exhausted)
632
+ {
633
+ exhausted = Qtrue;
634
+ }
635
+
636
+ return(exhausted);
637
+ }
638
+
639
+
640
+ /**
641
+ * This method integrates with the Ruby garbage collector to insure that, if
642
+ * a ResultSet contains a reference to a Transaction object, it doesn't get
643
+ * collected by the garbage collector unnecessarily.
644
+ *
645
+ * @param handle A void pointer to the structure associated with the object
646
+ * being scanned by the garbage collector.
647
+ *
648
+ */
649
+ void resultSetMark(void *handle)
650
+ {
651
+ ResultsHandle *results = (ResultsHandle *)handle;
652
+
653
+ if(results != NULL)
654
+ {
655
+ if(results->transaction != Qnil)
656
+ {
657
+ rb_gc_mark(results->transaction);
658
+ }
659
+ }
660
+ }
661
+
662
+
663
+ /**
664
+ * This function provides a programmatic means of creating a ResultSet object.
665
+ *
666
+ * @param connection A reference to a Connection object that will be used
667
+ * in executing the statement.
668
+ * @param transaction A reference to a Transaction object that will be used
669
+ * in executing the statement.
670
+ * @param sql A reference to a String containing the SQL statement to
671
+ * be executed. Must be a query.
672
+ * @param dialect A reference to an integer containing the SQL dialect to
673
+ * be used in executing the query.
674
+ * @param parameters A reference to an array containing the parameters to be
675
+ * used in executing the query.
676
+ *
677
+ * @return A reference to the newly created ResultSet object.
678
+ *
679
+ */
680
+ VALUE rb_result_set_new(VALUE connection, VALUE transaction, VALUE sql,
681
+ VALUE dialect, VALUE parameters)
682
+ {
683
+ VALUE instance = allocateResultSet(cResultSet);
684
+
685
+ initializeResultSet(instance, connection, transaction, sql, dialect,
686
+ parameters);
687
+
688
+ return(instance);
689
+ }
690
+
691
+
692
+ /**
693
+ * This function assigns an anonymous transaction to a ResultSet, giving the
694
+ * object responsibility for closing it.
695
+ *
696
+ * @param set A reference to the ResultSet object that will be taking
697
+ * ownership of the Transaction.
698
+ * @param transaction A reference to the Transaction object that the ResultSet
699
+ * is assuming responsibility for.
700
+ *
701
+ */
702
+ void rb_assign_transaction(VALUE set, VALUE transaction)
703
+ {
704
+ ResultsHandle *results = NULL;
705
+
706
+ Data_Get_Struct(set, ResultsHandle, results);
707
+ results->transaction = transaction;
708
+ }
709
+
710
+
711
+ /**
712
+ * This function integrates with the Ruby garbage collector to free all of the
713
+ * resources for a ResultSet object that is being collected.
714
+ *
715
+ * @param handle A pointer to the ResultsHandle structure associated with the
716
+ * object being collected.
717
+ *
718
+ */
719
+ void resultSetFree(void *handle)
720
+ {
721
+ if(handle != NULL)
722
+ {
723
+ ResultsHandle *results = (ResultsHandle *)handle;
724
+
725
+ if(results->handle != 0)
726
+ {
727
+ ISC_STATUS status[20];
728
+
729
+ /* UNCOMMENT FOR DEBUG PURPOSES! */
730
+ /*fprintf(stderr, "Releasing statement handle for...\n%s\n", results->sql);*/
731
+ isc_dsql_free_statement(status, &results->handle, DSQL_drop);
732
+ }
733
+
734
+ if(results->output != NULL)
735
+ {
736
+ releaseDataArea(results->output);
737
+ }
738
+
739
+ resolveResultsTransaction(results, "rollback");
740
+ free(results);
741
+ }
742
+ }
743
+
744
+
745
+ /**
746
+ * This is a simple function to aid in the clean up of statement handles.
747
+ *
748
+ * @param handle A pointer to the statement handle to be cleaned up.
749
+ *
750
+ */
751
+ void cleanupHandle(isc_stmt_handle *handle)
752
+ {
753
+ if(*handle != 0)
754
+ {
755
+ ISC_STATUS status[20];
756
+
757
+ /* UNCOMMENT FOR DEBUG PURPOSES! */
758
+ /*fprintf(stderr, "Cleaning up a statement handle.\n");*/
759
+ isc_dsql_free_statement(status, handle, DSQL_drop);
760
+ }
761
+ }
762
+
763
+
764
+ /**
765
+ * Simple helper function to resolve ResultsHandle associated transaction
766
+ *
767
+ * @param results - the ResultsHandle handle
768
+ *
769
+ * @param resolveMethod - transaction resolving method - eg. commit, rollback
770
+ *
771
+ */
772
+ void resolveResultsTransaction(ResultsHandle *results, char *resolveMethod)
773
+ {
774
+ if(results->transaction != Qnil)
775
+ {
776
+ rb_funcall(results->transaction, rb_intern(resolveMethod), 0);
777
+ results->transaction = Qnil;
778
+ }
779
+ }
780
+
781
+
782
+ /**
783
+ * This function initializes the ResultSet class within the Ruby environment.
784
+ * The class is established under the module specified to the function.
785
+ *
786
+ * @param module A reference to the module to create the class within.
787
+ *
788
+ */
789
+ void Init_ResultSet(VALUE module)
790
+ {
791
+ cResultSet = rb_define_class_under(module, "ResultSet", rb_cObject);
792
+ rb_define_alloc_func(cResultSet, allocateResultSet);
793
+ rb_include_module(cResultSet, rb_mEnumerable);
794
+ rb_define_method(cResultSet, "initialize", initializeResultSet, 5);
795
+ rb_define_method(cResultSet, "initialize_copy", forbidObjectCopy, 1);
796
+ rb_define_method(cResultSet, "row_count", getResultSetCount, 0);
797
+ rb_define_method(cResultSet, "fetch", fetchResultSetEntry, 0);
798
+ rb_define_method(cResultSet, "close", closeResultSet, 0);
799
+ rb_define_method(cResultSet, "connection", getResultSetConnection, 0);
800
+ rb_define_method(cResultSet, "transaction", getResultSetTransaction, 0);
801
+ rb_define_method(cResultSet, "sql", getResultSetSQL, 0);
802
+ rb_define_method(cResultSet, "dialect", getResultSetDialect, 0);
803
+ rb_define_method(cResultSet, "each", eachResultSetRow, 0);
804
+ rb_define_method(cResultSet, "column_name", getResultSetColumnName, 1);
805
+ rb_define_method(cResultSet, "column_alias", getResultSetColumnAlias, 1);
806
+ rb_define_method(cResultSet, "column_table", getResultSetColumnTable, 1);
807
+ rb_define_method(cResultSet, "column_count", getResultSetColumnCount, 0);
808
+ rb_define_method(cResultSet, "exhausted?", isResultSetExhausted, 0);
809
+ rb_define_method(cResultSet, "get_base_type", getResultSetColumnType, 1);
810
+ }