rubyfb 0.5.2-x86-linux

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.
Files changed (75) hide show
  1. data/CHANGELOG +6 -0
  2. data/LICENSE +411 -0
  3. data/Manifest +73 -0
  4. data/README +460 -0
  5. data/Rakefile +20 -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 +809 -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 +28 -0
  46. data/ext/mkmf.bat +1 -0
  47. data/lib/SQLType.rb +224 -0
  48. data/lib/active_record/connection_adapters/rubyfb_adapter.rb +805 -0
  49. data/lib/mkdoc +1 -0
  50. data/lib/rubyfb.rb +2 -0
  51. data/lib/rubyfb_lib.so +0 -0
  52. data/lib/src.rb +1800 -0
  53. data/rubyfb.gemspec +31 -0
  54. data/test/AddRemoveUserTest.rb +56 -0
  55. data/test/BackupRestoreTest.rb +99 -0
  56. data/test/BlobTest.rb +57 -0
  57. data/test/CharacterSetTest.rb +63 -0
  58. data/test/ConnectionTest.rb +111 -0
  59. data/test/DDLTest.rb +54 -0
  60. data/test/DatabaseTest.rb +83 -0
  61. data/test/GeneratorTest.rb +50 -0
  62. data/test/KeyTest.rb +140 -0
  63. data/test/ResultSetTest.rb +162 -0
  64. data/test/RoleTest.rb +73 -0
  65. data/test/RowCountTest.rb +65 -0
  66. data/test/RowTest.rb +203 -0
  67. data/test/SQLTest.rb +182 -0
  68. data/test/SQLTypeTest.rb +101 -0
  69. data/test/ServiceManagerTest.rb +29 -0
  70. data/test/StatementTest.rb +135 -0
  71. data/test/TestSetup.rb +11 -0
  72. data/test/TransactionTest.rb +112 -0
  73. data/test/TypeTest.rb +92 -0
  74. data/test/UnitTest.rb +65 -0
  75. metadata +149 -0
data/ext/ResultSet.c ADDED
@@ -0,0 +1,809 @@
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 = results->procedure_output_fetch_state;
266
+ if(value < 0) {
267
+ value = isc_dsql_fetch(status, &results->handle, results->dialect,
268
+ results->output);
269
+ } else {
270
+ /* move procedure_output_fetch_state ahead - fetch only one row */
271
+ results->procedure_output_fetch_state = 100;
272
+ }
273
+ VALUE array = Qnil,
274
+ number = Qnil;
275
+ switch(value)
276
+ {
277
+ case 0 :
278
+ array = toArray(self);
279
+ number = INT2NUM(++(results->fetched));
280
+ row = rb_row_new(self, array, number);
281
+ break;
282
+ case 100 :
283
+ results->exhausted = 1;
284
+ resolveResultsTransaction(results, "commit");
285
+ break;
286
+ default :
287
+ rb_fireruby_raise(status, "Error fetching query row.");
288
+ }
289
+ }
290
+
291
+ return(row);
292
+ }
293
+
294
+
295
+ /**
296
+ * This function provides the close method for the ResultSet class, releasing
297
+ * resources associated with the ResultSet.
298
+ *
299
+ * @param self A reference to the ResultSet object to be closed.
300
+ *
301
+ * @return A reference to the closed ResultSet object.
302
+ *
303
+ */
304
+ VALUE closeResultSet(VALUE self)
305
+ {
306
+ ResultsHandle *results = NULL;
307
+
308
+ Data_Get_Struct(self, ResultsHandle, results);
309
+ if(results->handle != 0)
310
+ {
311
+ ISC_STATUS status[20];
312
+
313
+ if(isc_dsql_free_statement(status, &results->handle, DSQL_drop))
314
+ {
315
+ rb_fireruby_raise(status, "Error closing result set.");
316
+ }
317
+ results->handle = 0;
318
+ }
319
+
320
+ if(results->output != NULL)
321
+ {
322
+ releaseDataArea(results->output);
323
+ results->output = NULL;
324
+ }
325
+
326
+ resolveResultsTransaction(results, "commit");
327
+
328
+ return(self);
329
+ }
330
+
331
+
332
+ /**
333
+ * This function provides the count method for the ResultSet class.
334
+ *
335
+ * @param self A reference to the ResultSet object to fetch the current row
336
+ * count for.
337
+ *
338
+ * @return A reference to an integer containing a count of the number of rows
339
+ * fetched from the ResultSet so far.
340
+ *
341
+ */
342
+ VALUE getResultSetCount(VALUE self)
343
+ {
344
+ ResultsHandle *results = NULL;
345
+
346
+ Data_Get_Struct(self, ResultsHandle, results);
347
+
348
+ return(INT2NUM(results->fetched));
349
+ }
350
+
351
+
352
+ /**
353
+ * This method provides the accessor method for the connection ResultSet
354
+ * attribute.
355
+ *
356
+ * @param self A reference to the ResultSet object to fetch the attribute
357
+ * from.
358
+ *
359
+ * @return A reference to the requested attribute object.
360
+ *
361
+ */
362
+ VALUE getResultSetConnection(VALUE self)
363
+ {
364
+ return(rb_iv_get(self, "@connection"));
365
+ }
366
+
367
+
368
+ /**
369
+ * This method provides the accessor method for the transaction ResultSet
370
+ * attribute.
371
+ *
372
+ * @param self A reference to the ResultSet object to fetch the attribute
373
+ * from.
374
+ *
375
+ * @return A reference to the requested attribute object.
376
+ *
377
+ */
378
+ VALUE getResultSetTransaction(VALUE self)
379
+ {
380
+ return(rb_iv_get(self, "@transaction"));
381
+ }
382
+
383
+
384
+ /**
385
+ * This method provides the accessor method for the SQL ResultSet attribute.
386
+ *
387
+ * @param self A reference to the ResultSet object to fetch the attribute
388
+ * from.
389
+ *
390
+ * @return A reference to the requested attribute object.
391
+ *
392
+ */
393
+ VALUE getResultSetSQL(VALUE self)
394
+ {
395
+ return(rb_iv_get(self, "@sql"));
396
+ }
397
+
398
+
399
+ /**
400
+ * This method provides the accessor method for the dialect ResultSet attribute.
401
+ *
402
+ * @param self A reference to the ResultSet object to fetch the attribute
403
+ * from.
404
+ *
405
+ * @return A reference to the requested attribute object.
406
+ *
407
+ */
408
+ VALUE getResultSetDialect(VALUE self)
409
+ {
410
+ return(rb_iv_get(self, "@dialect"));
411
+ }
412
+
413
+
414
+ /**
415
+ * This function provides the column_count attribute accessor for the ResultSet
416
+ * class.
417
+ *
418
+ * @param self A reference to the ResultSet object to fetch the attribute for.
419
+ *
420
+ * @return A reference to an integer containing the column count.
421
+ *
422
+ */
423
+ VALUE getResultSetColumnCount(VALUE self)
424
+ {
425
+ VALUE count = Qnil;
426
+ ResultsHandle *results = NULL;
427
+
428
+ Data_Get_Struct(self, ResultsHandle, results);
429
+ if(results != NULL)
430
+ {
431
+ count = INT2NUM(results->output->sqld);
432
+ }
433
+
434
+ return(count);
435
+ }
436
+
437
+
438
+ /**
439
+ * This function provides the column_name method for the ResultSet class.
440
+ *
441
+ * @param self A reference to the ResultSet object to retrieve the column
442
+ * name from.
443
+ * @param column An offset to the column to retrieve the name for.
444
+ *
445
+ * @return A String containing the column name or nil if an invalid column
446
+ * was specified.
447
+ *
448
+ */
449
+ static VALUE getResultSetColumnName(VALUE self, VALUE column)
450
+ {
451
+ VALUE name = Qnil;
452
+ ResultsHandle *results = NULL;
453
+
454
+ Data_Get_Struct(self, ResultsHandle, results);
455
+ if(results != NULL)
456
+ {
457
+ int offset = 0;
458
+
459
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
460
+ if(offset >= 0 && offset < results->output->sqld)
461
+ {
462
+ XSQLVAR *var = results->output->sqlvar;
463
+ int index;
464
+
465
+ for(index = 0; index < offset; index++, var++);
466
+ name = rb_str_new(var->sqlname, var->sqlname_length);
467
+ }
468
+ }
469
+
470
+ return(name);
471
+ }
472
+
473
+
474
+ /**
475
+ * This function provides the column_alias method for the ResultSet class.
476
+ *
477
+ * @param self A reference to the ResultSet object to retrieve the column
478
+ * alias from.
479
+ * @param column An offset to the column to retrieve the alias for.
480
+ *
481
+ * @return A String containing the column alias or nil if an invalid column
482
+ * was specified.
483
+ *
484
+ */
485
+ static VALUE getResultSetColumnAlias(VALUE self, VALUE column)
486
+ {
487
+ VALUE alias = Qnil;
488
+ ResultsHandle *results = NULL;
489
+
490
+ Data_Get_Struct(self, ResultsHandle, results);
491
+ if(results != NULL)
492
+ {
493
+ int offset = 0;
494
+
495
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
496
+ if(offset >= 0 && offset < results->output->sqld)
497
+ {
498
+ XSQLVAR *var = results->output->sqlvar;
499
+ int index;
500
+
501
+ for(index = 0; index < offset; index++, var++);
502
+ alias = rb_str_new(var->aliasname, var->aliasname_length);
503
+ }
504
+ }
505
+
506
+ return(alias);
507
+ }
508
+
509
+
510
+ /**
511
+ * This function provides the column_table method for the ResultSet class.
512
+ *
513
+ * @param self A reference to the ResultSet object to retrieve the column
514
+ * table name from.
515
+ * @param column An offset to the column to retrieve the table name for.
516
+ *
517
+ * @return A String containing the column table name or nil if an invalid
518
+ * column was specified.
519
+ *
520
+ */
521
+ static VALUE getResultSetColumnTable(VALUE self, VALUE column)
522
+ {
523
+ VALUE name = Qnil;
524
+ ResultsHandle *results = NULL;
525
+
526
+ Data_Get_Struct(self, ResultsHandle, results);
527
+ if(results != NULL)
528
+ {
529
+ int offset = 0;
530
+
531
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
532
+ if(offset >= 0 && offset < results->output->sqld)
533
+ {
534
+ XSQLVAR *var = results->output->sqlvar;
535
+ int index;
536
+
537
+ for(index = 0; index < offset; index++, var++);
538
+ name = rb_str_new(var->relname, var->relname_length);
539
+ }
540
+ }
541
+
542
+ return(name);
543
+ }
544
+
545
+
546
+ /**
547
+ * This function attempts to extract basic type information for a column within
548
+ * a ResultSet object.
549
+ *
550
+ * @param self A reference to the ResultSet to execute on.
551
+ * @param column A integer offset for the column to extract the type of.
552
+ *
553
+ * @return A Symbol representing the basic data type.
554
+ *
555
+ */
556
+ static VALUE getResultSetColumnType(VALUE self, VALUE column)
557
+ {
558
+ VALUE type = toSymbol("UNKNOWN");
559
+
560
+ if(TYPE(column) == T_FIXNUM)
561
+ {
562
+ ResultsHandle *handle = NULL;
563
+
564
+ Data_Get_Struct(self, ResultsHandle, handle);
565
+ if(handle != NULL)
566
+ {
567
+ int index = FIX2INT(column);
568
+
569
+ /* Fix negative index values. */
570
+ if(index < 0)
571
+ {
572
+ index = handle->output->sqln + index;
573
+ }
574
+
575
+ if(index >= 0 && index < handle->output->sqln)
576
+ {
577
+ type = getColumnType(&handle->output->sqlvar[index]);
578
+ }
579
+ }
580
+ }
581
+
582
+
583
+ return(type);
584
+ }
585
+
586
+
587
+ /**
588
+ * This function provides the each method for the ResultSet class.
589
+ *
590
+ * @param self A reference to the ResultSet object to execute the method for.
591
+ *
592
+ * @return A reference to the last value returned by the associated block or
593
+ * nil.
594
+ *
595
+ */
596
+ VALUE eachResultSetRow(VALUE self)
597
+ {
598
+ VALUE result = Qnil;
599
+
600
+ /* Check if a block was provided. */
601
+ if(rb_block_given_p())
602
+ {
603
+ VALUE row;
604
+
605
+ while((row = fetchResultSetEntry(self)) != Qnil)
606
+ {
607
+ result = rb_yield(row);
608
+ }
609
+ }
610
+
611
+ return(result);
612
+ }
613
+
614
+
615
+ /**
616
+ * This function provides the exhausted? method of the ResultSet class.
617
+ *
618
+ * @param self A reference to the ResultSet object to make the call for.
619
+ *
620
+ * @return True if all rows have been fetched from the result set, false
621
+ * if they haven't.
622
+ *
623
+ */
624
+ VALUE isResultSetExhausted(VALUE self)
625
+ {
626
+ VALUE exhausted = Qfalse;
627
+ ResultsHandle *results = NULL;
628
+
629
+ Data_Get_Struct(self, ResultsHandle, results);
630
+ if(results->exhausted)
631
+ {
632
+ exhausted = Qtrue;
633
+ }
634
+
635
+ return(exhausted);
636
+ }
637
+
638
+
639
+ /**
640
+ * This method integrates with the Ruby garbage collector to insure that, if
641
+ * a ResultSet contains a reference to a Transaction object, it doesn't get
642
+ * collected by the garbage collector unnecessarily.
643
+ *
644
+ * @param handle A void pointer to the structure associated with the object
645
+ * being scanned by the garbage collector.
646
+ *
647
+ */
648
+ void resultSetMark(void *handle)
649
+ {
650
+ ResultsHandle *results = (ResultsHandle *)handle;
651
+
652
+ if(results != NULL)
653
+ {
654
+ if(results->transaction != Qnil)
655
+ {
656
+ rb_gc_mark(results->transaction);
657
+ }
658
+ }
659
+ }
660
+
661
+
662
+ /**
663
+ * This function provides a programmatic means of creating a ResultSet object.
664
+ *
665
+ * @param connection A reference to a Connection object that will be used
666
+ * in executing the statement.
667
+ * @param transaction A reference to a Transaction object that will be used
668
+ * in executing the statement.
669
+ * @param sql A reference to a String containing the SQL statement to
670
+ * be executed. Must be a query.
671
+ * @param dialect A reference to an integer containing the SQL dialect to
672
+ * be used in executing the query.
673
+ * @param parameters A reference to an array containing the parameters to be
674
+ * used in executing the query.
675
+ *
676
+ * @return A reference to the newly created ResultSet object.
677
+ *
678
+ */
679
+ VALUE rb_result_set_new(VALUE connection, VALUE transaction, VALUE sql,
680
+ VALUE dialect, VALUE parameters)
681
+ {
682
+ VALUE instance = allocateResultSet(cResultSet);
683
+
684
+ initializeResultSet(instance, connection, transaction, sql, dialect,
685
+ parameters);
686
+
687
+ return(instance);
688
+ }
689
+
690
+
691
+ /**
692
+ * This function assigns an anonymous transaction to a ResultSet, giving the
693
+ * object responsibility for closing it.
694
+ *
695
+ * @param set A reference to the ResultSet object that will be taking
696
+ * ownership of the Transaction.
697
+ * @param transaction A reference to the Transaction object that the ResultSet
698
+ * is assuming responsibility for.
699
+ *
700
+ */
701
+ void rb_assign_transaction(VALUE set, VALUE transaction)
702
+ {
703
+ ResultsHandle *results = NULL;
704
+
705
+ Data_Get_Struct(set, ResultsHandle, results);
706
+ results->transaction = transaction;
707
+ }
708
+
709
+
710
+ /**
711
+ * This function integrates with the Ruby garbage collector to free all of the
712
+ * resources for a ResultSet object that is being collected.
713
+ *
714
+ * @param handle A pointer to the ResultsHandle structure associated with the
715
+ * object being collected.
716
+ *
717
+ */
718
+ void resultSetFree(void *handle)
719
+ {
720
+ if(handle != NULL)
721
+ {
722
+ ResultsHandle *results = (ResultsHandle *)handle;
723
+
724
+ if(results->handle != 0)
725
+ {
726
+ ISC_STATUS status[20];
727
+
728
+ /* UNCOMMENT FOR DEBUG PURPOSES! */
729
+ /*fprintf(stderr, "Releasing statement handle for...\n%s\n", results->sql);*/
730
+ isc_dsql_free_statement(status, &results->handle, DSQL_drop);
731
+ }
732
+
733
+ if(results->output != NULL)
734
+ {
735
+ releaseDataArea(results->output);
736
+ }
737
+
738
+ resolveResultsTransaction(results, "rollback");
739
+ free(results);
740
+ }
741
+ }
742
+
743
+
744
+ /**
745
+ * This is a simple function to aid in the clean up of statement handles.
746
+ *
747
+ * @param handle A pointer to the statement handle to be cleaned up.
748
+ *
749
+ */
750
+ void cleanupHandle(isc_stmt_handle *handle)
751
+ {
752
+ if(*handle != 0)
753
+ {
754
+ ISC_STATUS status[20];
755
+
756
+ /* UNCOMMENT FOR DEBUG PURPOSES! */
757
+ /*fprintf(stderr, "Cleaning up a statement handle.\n");*/
758
+ isc_dsql_free_statement(status, handle, DSQL_drop);
759
+ }
760
+ }
761
+
762
+
763
+ /**
764
+ * Simple helper function to resolve ResultsHandle associated transaction
765
+ *
766
+ * @param results - the ResultsHandle handle
767
+ *
768
+ * @param resolveMethod - transaction resolving method - eg. commit, rollback
769
+ *
770
+ */
771
+ void resolveResultsTransaction(ResultsHandle *results, char *resolveMethod)
772
+ {
773
+ if(results->transaction != Qnil)
774
+ {
775
+ rb_funcall(results->transaction, rb_intern(resolveMethod), 0);
776
+ results->transaction = Qnil;
777
+ }
778
+ }
779
+
780
+
781
+ /**
782
+ * This function initializes the ResultSet class within the Ruby environment.
783
+ * The class is established under the module specified to the function.
784
+ *
785
+ * @param module A reference to the module to create the class within.
786
+ *
787
+ */
788
+ void Init_ResultSet(VALUE module)
789
+ {
790
+ cResultSet = rb_define_class_under(module, "ResultSet", rb_cObject);
791
+ rb_define_alloc_func(cResultSet, allocateResultSet);
792
+ rb_include_module(cResultSet, rb_mEnumerable);
793
+ rb_define_method(cResultSet, "initialize", initializeResultSet, 5);
794
+ rb_define_method(cResultSet, "initialize_copy", forbidObjectCopy, 1);
795
+ rb_define_method(cResultSet, "row_count", getResultSetCount, 0);
796
+ rb_define_method(cResultSet, "fetch", fetchResultSetEntry, 0);
797
+ rb_define_method(cResultSet, "close", closeResultSet, 0);
798
+ rb_define_method(cResultSet, "connection", getResultSetConnection, 0);
799
+ rb_define_method(cResultSet, "transaction", getResultSetTransaction, 0);
800
+ rb_define_method(cResultSet, "sql", getResultSetSQL, 0);
801
+ rb_define_method(cResultSet, "dialect", getResultSetDialect, 0);
802
+ rb_define_method(cResultSet, "each", eachResultSetRow, 0);
803
+ rb_define_method(cResultSet, "column_name", getResultSetColumnName, 1);
804
+ rb_define_method(cResultSet, "column_alias", getResultSetColumnAlias, 1);
805
+ rb_define_method(cResultSet, "column_table", getResultSetColumnTable, 1);
806
+ rb_define_method(cResultSet, "column_count", getResultSetColumnCount, 0);
807
+ rb_define_method(cResultSet, "exhausted?", isResultSetExhausted, 0);
808
+ rb_define_method(cResultSet, "get_base_type", getResultSetColumnType, 1);
809
+ }