rubyfb 0.5.9 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
data/ext/ResultSet.c CHANGED
@@ -36,12 +36,14 @@
36
36
 
37
37
  /* Function prototypes. */
38
38
  static VALUE allocateResultSet(VALUE);
39
- static VALUE initializeResultSet(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
39
+ static VALUE initializeResultSet(VALUE, VALUE, VALUE);
40
+ static VALUE getResultSetRow(VALUE);
40
41
  static VALUE fetchResultSetEntry(VALUE);
41
42
  static VALUE closeResultSet(VALUE);
42
43
  static VALUE getResultSetCount(VALUE);
43
44
  static VALUE getResultSetConnection(VALUE);
44
45
  static VALUE getResultSetTransaction(VALUE);
46
+ static VALUE getResultSetStatement(VALUE);
45
47
  static VALUE getResultSetSQL(VALUE);
46
48
  static VALUE getResultSetDialect(VALUE);
47
49
  static VALUE getResultSetColumnCount(VALUE);
@@ -52,14 +54,39 @@ static VALUE getResultSetColumnTable(VALUE, VALUE);
52
54
  static VALUE getResultSetColumnType(VALUE, VALUE);
53
55
  static VALUE eachResultSetRow(VALUE);
54
56
  static VALUE isResultSetExhausted(VALUE);
55
- static void resultSetMark(void *);
56
- static void cleanupHandle(isc_stmt_handle *handle);
57
- static void resolveResultsTransaction(ResultsHandle *results, char *resolveMethod);
58
-
59
57
 
60
58
  /* Globals. */
61
59
  VALUE cResultSet;
62
60
 
61
+ StatementHandle* getStatementHandle(VALUE self) {
62
+ StatementHandle *hStatement;
63
+ Data_Get_Struct(getResultSetStatement(self), StatementHandle, hStatement);
64
+
65
+ return (hStatement);
66
+ }
67
+
68
+ short isActiveResultSet(VALUE self) {
69
+ short result = 0;
70
+ if ((Qtrue == rb_obj_is_kind_of(self, cResultSet))) {
71
+ ResultsHandle *hResults = NULL;
72
+ Data_Get_Struct(self, ResultsHandle, hResults);
73
+ result = hResults->active;
74
+ }
75
+ return (result);
76
+ }
77
+
78
+ void resultSetManageTransaction(VALUE self) {
79
+ ResultsHandle *hResults = NULL;
80
+ Data_Get_Struct(self, ResultsHandle, hResults);
81
+ hResults->manage_transaction = 1;
82
+ }
83
+
84
+ void resultSetManageStatement(VALUE self) {
85
+ ResultsHandle *hResults = NULL;
86
+ Data_Get_Struct(self, ResultsHandle, hResults);
87
+ hResults->manage_statement = 1;
88
+ }
89
+
63
90
  /**
64
91
  * This method allocates a new ResultSet object.
65
92
  *
@@ -75,15 +102,12 @@ VALUE allocateResultSet(VALUE klass) {
75
102
  rb_raise(rb_eNoMemError,
76
103
  "Memory allocation failure allocating a result set.");
77
104
  }
78
- results->handle = 0;
79
- results->output = NULL;
80
- results->exhausted = 0;
81
105
  results->fetched = 0;
82
- results->dialect = 0;
83
- results->procedure_output_fetch_state = -1;
84
- results->transaction = Qnil;
106
+ results->active = 0;
107
+ results->manage_transaction = 0;
108
+ results->manage_statement = 0;
85
109
 
86
- return(Data_Wrap_Struct(klass, resultSetMark, resultSetFree, results));
110
+ return(Data_Wrap_Struct(klass, NULL, resultSetFree, results));
87
111
  }
88
112
 
89
113
 
@@ -91,137 +115,42 @@ VALUE allocateResultSet(VALUE klass) {
91
115
  * This function provides the initialize method for the ResultSet class.
92
116
  *
93
117
  * @param self A reference to the ResultSet object to be initialized.
94
- * @param connection A reference to a Connection object that will be used
95
- * in executing the statement.
96
- * @param transaction A reference to a Transaction object that will be used
97
- * in executing the statement.
98
- * @param sql A reference to a String containing the SQL statement to
99
- * be executed. Must be a query.
100
- * @param dialect A reference to an integer containing the SQL dialect to
101
- * be used in executing the query.
102
- * @param parameters A reference to an array containing the parameters to be
103
- * used in executing the query.
118
+ * @param statement A statement to iterate over
119
+ * @param transaction A reference to a privater transaction object
120
+ * taht should be managed by this ResultSet.
104
121
  *
105
122
  * @return A reference to the newly initialize ResultSet object.
106
123
  *
107
124
  */
108
- VALUE initializeResultSet(VALUE self, VALUE connection, VALUE transaction,
109
- VALUE sql, VALUE dialect, VALUE parameters) {
110
- short setting = 0;
111
- int type = 0,
112
- inputs = 0,
113
- outputs = 0;
114
- long affected = 0;
115
- ResultsHandle *results = NULL;
116
- VALUE value = Qnil;
117
- ConnectionHandle *cHandle = NULL;
118
- TransactionHandle *tHandle = NULL;
119
- XSQLDA *params = NULL;
120
-
121
- /* Validate the inputs. */
122
- if(TYPE(connection) == T_DATA &&
123
- RDATA(connection)->dfree == (RUBY_DATA_FUNC)connectionFree) {
124
- if(rb_funcall(connection, rb_intern("open?"), 0) == Qfalse) {
125
- rb_fireruby_raise(NULL, "Closed connection specified for result set.");
126
- }
127
- } else {
128
- rb_fireruby_raise(NULL, "Invalid connection specified for result set.");
129
- }
130
-
131
- if(TYPE(transaction) == T_DATA &&
132
- RDATA(transaction)->dfree == (RUBY_DATA_FUNC)transactionFree) {
133
- if(rb_funcall(transaction, rb_intern("active?"), 0) == Qfalse) {
134
- rb_fireruby_raise(NULL, "Inactive transaction specified for result set.");
135
- }
136
- } else {
137
- rb_fireruby_raise(NULL, "Invalid transaction specified for result set.");
138
- }
139
-
140
- value = rb_funcall(dialect, rb_intern("to_i"), 0);
141
- if(TYPE(value) == T_FIXNUM) {
142
- setting = FIX2INT(value);
143
- if(setting < 1 || setting > 3) {
144
- rb_fireruby_raise(NULL,
145
- "Invalid dialect value specified for result set. " \
146
- "The dialect value must be between 1 and 3.");
147
- }
148
- } else {
149
- rb_fireruby_raise(NULL,
150
- "Invalid dialect value specified for result set. The " \
151
- "dialect value must be between 1 and 3.");
152
- }
153
-
154
- /* Prepare the result set. */
155
- Data_Get_Struct(connection, ConnectionHandle, cHandle);
156
- Data_Get_Struct(transaction, TransactionHandle, tHandle);
157
- Data_Get_Struct(self, ResultsHandle, results);
158
- prepare(&cHandle->handle, &tHandle->handle, StringValuePtr(sql), &results->handle,
159
- setting, &type, &inputs, &outputs);
160
-
161
- if(type != isc_info_sql_stmt_select &&
162
- type != isc_info_sql_stmt_select_for_upd &&
163
- type != isc_info_sql_stmt_exec_procedure) {
164
- cleanupHandle(&results->handle);
165
- rb_fireruby_raise(NULL,
166
- "Non-query SQL statement specified for result set.");
167
- }
125
+ VALUE initializeResultSet(VALUE self, VALUE statement, VALUE transaction) {
126
+ ResultsHandle *hResults = NULL;
127
+ Data_Get_Struct(self, ResultsHandle, hResults);
168
128
 
169
- rb_iv_set(self, "@connection", connection);
129
+ rb_iv_set(self, "@statement", statement);
170
130
  rb_iv_set(self, "@transaction", transaction);
171
- rb_iv_set(self, "@sql", rb_funcall(sql, rb_intern("to_s"), 0));
172
- rb_iv_set(self, "@dialect", value);
173
- results->dialect = setting;
174
-
175
- /* UNCOMMENT FOR DEBUGGING PURPOSES! */
176
- /*strcpy(results->sql, StringValuePtr(sql));*/
177
-
178
- /* Check if input parameters are needed. */
179
- if(inputs > 0) {
180
- VALUE value = Qnil;
181
- int size = 0;
182
-
183
- if(parameters == Qnil) {
184
- cleanupHandle(&results->handle);
185
- rb_fireruby_raise(NULL,
186
- "Empty parameter list specified for result set.");
187
- }
188
-
189
- value = rb_funcall(parameters, rb_intern("size"), 0);
190
- size = TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value);
191
- if(size < inputs) {
192
- cleanupHandle(&results->handle);
193
- rb_fireruby_raise(NULL,
194
- "Insufficient parameters specified for result set.");
195
- }
131
+ hResults->active = 1;
132
+
133
+ return(self);
134
+ }
196
135
 
197
- /* Allocate the XSQLDA and populate it. */
198
- params = allocateInXSQLDA(inputs, &results->handle, setting);
199
- prepareDataArea(params);
200
- setParameters(params, parameters, self);
201
- }
136
+ /**
137
+ * This function provides the row method for the ResultSet class.
138
+ *
139
+ * @param self A reference to the ResultSet object to make the call on.
140
+ *
141
+ * @return Either a reference to a Row object or nil.
142
+ *
143
+ */
144
+ VALUE getResultSetRow(VALUE self) {
145
+ VALUE row = Qnil;
146
+ ResultsHandle *hResults = NULL;
202
147
 
203
- /* Allocate output storage. */
204
- results->output = allocateOutXSQLDA(outputs, &results->handle, setting);
205
- prepareDataArea(results->output);
206
-
207
- /* Execute the statement and clean up. */
208
- if(type == isc_info_sql_stmt_exec_procedure) {
209
- /* Execute with output params */
210
- execute_2(&tHandle->handle, &results->handle, setting, params, type,
211
- &affected, results->output);
212
- /* Initialize procedure output fetch */
213
- results->procedure_output_fetch_state = 0;
214
- /* Early resolve transaction */
215
- resolveResultsTransaction (results, "commit");
216
- } else {
217
- execute(&tHandle->handle, &results->handle, setting, params, type,
218
- &affected);
219
- }
220
- if(params != NULL) {
221
- releaseDataArea(params);
148
+ Data_Get_Struct(self, ResultsHandle, hResults);
149
+ if(hResults->fetched) {
150
+ VALUE array = toArray(self);
151
+ row = rb_row_new(self, array, INT2FIX(hResults->fetched));
222
152
  }
223
-
224
- return(self);
153
+ return (row);
225
154
  }
226
155
 
227
156
 
@@ -234,43 +163,37 @@ VALUE initializeResultSet(VALUE self, VALUE connection, VALUE transaction,
234
163
  *
235
164
  */
236
165
  VALUE fetchResultSetEntry(VALUE self) {
237
- VALUE row = Qnil;
238
- ResultsHandle *results = NULL;
239
- ISC_STATUS status[ISC_STATUS_LENGTH],
240
- value;
241
-
242
- Data_Get_Struct(self, ResultsHandle, results);
243
- if(results->handle != 0 && !results->exhausted) {
244
- VALUE array,number;
245
- value = results->procedure_output_fetch_state;
246
- if(value < 0) {
247
- value = isc_dsql_fetch(status, &results->handle, results->dialect,
248
- results->output);
166
+ VALUE row = Qnil;
167
+ StatementHandle *hStatement = getStatementHandle(self);
168
+ ResultsHandle *hResults = NULL;
169
+ ISC_STATUS status[ISC_STATUS_LENGTH],
170
+ fetch_result;
171
+
172
+ Data_Get_Struct(self, ResultsHandle, hResults);
173
+ if(hResults->active) {
174
+ if (isCursorStatement(hStatement)) {
175
+ fetch_result = isc_dsql_fetch(status, &hStatement->handle, hStatement->dialect,
176
+ hStatement->output);
177
+ switch(fetch_result) {
178
+ case 0:
179
+ hResults->fetched += 1;
180
+ row = getResultSetRow(self);
181
+ break;
182
+ case 100:
183
+ hResults->active = 0;
184
+ break;
185
+ default:
186
+ rb_fireruby_raise(status, "Error fetching query row.");
187
+ }
249
188
  } else {
250
- /* move procedure_output_fetch_state ahead - fetch only one row */
251
- results->procedure_output_fetch_state = 100;
252
- }
253
- array = Qnil;
254
- number = Qnil;
255
- switch(value) {
256
- case 0:
257
- array = toArray(self);
258
- number = INT2NUM(++(results->fetched));
259
- row = rb_row_new(self, array, number);
260
- break;
261
- case 100:
262
- results->exhausted = 1;
263
- resolveResultsTransaction(results, "commit");
264
- break;
265
- default:
266
- rb_fireruby_raise(status, "Error fetching query row.");
189
+ hResults->active = 0;
190
+ hResults->fetched = 1;
191
+ row = getResultSetRow(self);
267
192
  }
268
193
  }
269
-
270
- return(row);
194
+ return (row);
271
195
  }
272
196
 
273
-
274
197
  /**
275
198
  * This function provides the close method for the ResultSet class, releasing
276
199
  * resources associated with the ResultSet.
@@ -281,24 +204,29 @@ VALUE fetchResultSetEntry(VALUE self) {
281
204
  *
282
205
  */
283
206
  VALUE closeResultSet(VALUE self) {
284
- ResultsHandle *results = NULL;
285
-
286
- Data_Get_Struct(self, ResultsHandle, results);
287
- if(results->handle != 0) {
288
- ISC_STATUS status[ISC_STATUS_LENGTH];
289
-
290
- if(isc_dsql_free_statement(status, &results->handle, DSQL_drop)) {
291
- rb_fireruby_raise(status, "Error closing result set.");
292
- }
293
- results->handle = 0;
207
+ StatementHandle *hStatement = getStatementHandle(self);
208
+ ResultsHandle *hResults = NULL;
209
+ Data_Get_Struct(self, ResultsHandle, hResults);
210
+ ISC_STATUS status[ISC_STATUS_LENGTH];
211
+
212
+ hResults->active = 0;
213
+ if(isc_dsql_free_statement(status, &hStatement->handle, DSQL_close)) {
214
+ rb_fireruby_raise(status, "Error closing cursor.");
294
215
  }
295
-
296
- if(results->output != NULL) {
297
- releaseDataArea(results->output);
298
- results->output = NULL;
216
+ if(hResults->manage_statement) {
217
+ VALUE statement = getResultSetStatement(self),
218
+ menagement_required = rb_funcall(statement, rb_intern("prepared?"), 0);
219
+ if(Qtrue == menagement_required) {
220
+ rb_funcall(statement, rb_intern("close"), 0);
221
+ }
222
+ }
223
+ if(hResults->manage_transaction) {
224
+ VALUE transaction = getResultSetTransaction(self),
225
+ menagement_required = rb_funcall(transaction, rb_intern("active?"), 0);
226
+ if(Qtrue == menagement_required) {
227
+ rb_funcall(transaction, rb_intern("commit"), 0);
228
+ }
299
229
  }
300
-
301
- resolveResultsTransaction(results, "commit");
302
230
 
303
231
  return(self);
304
232
  }
@@ -334,7 +262,7 @@ VALUE getResultSetCount(VALUE self) {
334
262
  *
335
263
  */
336
264
  VALUE getResultSetConnection(VALUE self) {
337
- return(rb_iv_get(self, "@connection"));
265
+ return(rb_funcall(getResultSetStatement(self), rb_intern("connection"), 0));
338
266
  }
339
267
 
340
268
 
@@ -349,7 +277,21 @@ VALUE getResultSetConnection(VALUE self) {
349
277
  *
350
278
  */
351
279
  VALUE getResultSetTransaction(VALUE self) {
352
- return(rb_iv_get(self, "@transaction"));
280
+ return rb_iv_get(self, "@transaction");
281
+ }
282
+
283
+ /**
284
+ * This method provides the accessor method for the transaction ResultSet
285
+ * statement.
286
+ *
287
+ * @param self A reference to the ResultSet object to fetch the attribute
288
+ * from.
289
+ *
290
+ * @return A reference to the requested attribute object.
291
+ *
292
+ */
293
+ VALUE getResultSetStatement(VALUE self) {
294
+ return rb_iv_get(self, "@statement");
353
295
  }
354
296
 
355
297
 
@@ -363,7 +305,7 @@ VALUE getResultSetTransaction(VALUE self) {
363
305
  *
364
306
  */
365
307
  VALUE getResultSetSQL(VALUE self) {
366
- return(rb_iv_get(self, "@sql"));
308
+ return(rb_funcall(getResultSetStatement(self), rb_intern("sql"), 0));
367
309
  }
368
310
 
369
311
 
@@ -377,7 +319,7 @@ VALUE getResultSetSQL(VALUE self) {
377
319
  *
378
320
  */
379
321
  VALUE getResultSetDialect(VALUE self) {
380
- return(rb_iv_get(self, "@dialect"));
322
+ return(rb_funcall(getResultSetStatement(self), rb_intern("dialect"), 0));
381
323
  }
382
324
 
383
325
 
@@ -391,15 +333,7 @@ VALUE getResultSetDialect(VALUE self) {
391
333
  *
392
334
  */
393
335
  VALUE getResultSetColumnCount(VALUE self) {
394
- VALUE count = Qnil;
395
- ResultsHandle *results = NULL;
396
-
397
- Data_Get_Struct(self, ResultsHandle, results);
398
- if(results != NULL) {
399
- count = INT2NUM(results->output->sqld);
400
- }
401
-
402
- return(count);
336
+ return(INT2NUM(getStatementHandle(self)->output->sqld));
403
337
  }
404
338
 
405
339
 
@@ -415,21 +349,17 @@ VALUE getResultSetColumnCount(VALUE self) {
415
349
  *
416
350
  */
417
351
  static VALUE getResultSetColumnName(VALUE self, VALUE column) {
352
+ int offset = 0;
418
353
  VALUE name = Qnil;
419
- ResultsHandle *results = NULL;
420
-
421
- Data_Get_Struct(self, ResultsHandle, results);
422
- if(results != NULL) {
423
- int offset = 0;
354
+ StatementHandle *hStatement = getStatementHandle(self);
424
355
 
425
- offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
426
- if(offset >= 0 && offset < results->output->sqld) {
427
- XSQLVAR *var = results->output->sqlvar;
428
- int index;
356
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
357
+ if(offset >= 0 && offset < hStatement->output->sqld) {
358
+ XSQLVAR *var = hStatement->output->sqlvar;
359
+ int index;
429
360
 
430
- for(index = 0; index < offset; index++, var++) ;
431
- name = rb_str_new(var->sqlname, var->sqlname_length);
432
- }
361
+ for(index = 0; index < offset; index++, var++) ;
362
+ name = rb_str_new(var->sqlname, var->sqlname_length);
433
363
  }
434
364
 
435
365
  return(name);
@@ -448,21 +378,17 @@ static VALUE getResultSetColumnName(VALUE self, VALUE column) {
448
378
  *
449
379
  */
450
380
  static VALUE getResultSetColumnAlias(VALUE self, VALUE column) {
381
+ int offset = 0;
451
382
  VALUE alias = Qnil;
452
- ResultsHandle *results = NULL;
453
-
454
- Data_Get_Struct(self, ResultsHandle, results);
455
- if(results != NULL) {
456
- int offset = 0;
383
+ StatementHandle *hStatement = getStatementHandle(self);
457
384
 
458
- offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
459
- if(offset >= 0 && offset < results->output->sqld) {
460
- XSQLVAR *var = results->output->sqlvar;
461
- int index;
385
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
386
+ if(offset >= 0 && offset < hStatement->output->sqld) {
387
+ XSQLVAR *var = hStatement->output->sqlvar;
388
+ int index;
462
389
 
463
- for(index = 0; index < offset; index++, var++) ;
464
- alias = rb_str_new(var->aliasname, var->aliasname_length);
465
- }
390
+ for(index = 0; index < offset; index++, var++) ;
391
+ alias = rb_str_new(var->aliasname, var->aliasname_length);
466
392
  }
467
393
 
468
394
  return(alias);
@@ -480,21 +406,17 @@ static VALUE getResultSetColumnAlias(VALUE self, VALUE column) {
480
406
  *
481
407
  */
482
408
  static VALUE getResultSetColumnScale(VALUE self, VALUE column) {
409
+ int offset = 0;
483
410
  VALUE scale = Qnil;
484
- ResultsHandle *results = NULL;
411
+ StatementHandle *hStatement = getStatementHandle(self);
485
412
 
486
- Data_Get_Struct(self, ResultsHandle, results);
487
- if(results != NULL) {
488
- int offset = 0;
413
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
414
+ if(offset >= 0 && offset < hStatement->output->sqld) {
415
+ XSQLVAR *var = hStatement->output->sqlvar;
416
+ int index;
489
417
 
490
- offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
491
- if(offset >= 0 && offset < results->output->sqld) {
492
- XSQLVAR *var = results->output->sqlvar;
493
- int index;
494
-
495
- for(index = 0; index < offset; index++, var++) ;
496
- scale = INT2FIX(var->sqlscale);
497
- }
418
+ for(index = 0; index < offset; index++, var++) ;
419
+ scale = INT2FIX(var->sqlscale);
498
420
  }
499
421
 
500
422
  return(scale);
@@ -513,21 +435,17 @@ static VALUE getResultSetColumnScale(VALUE self, VALUE column) {
513
435
  *
514
436
  */
515
437
  static VALUE getResultSetColumnTable(VALUE self, VALUE column) {
438
+ int offset = 0;
516
439
  VALUE name = Qnil;
517
- ResultsHandle *results = NULL;
518
-
519
- Data_Get_Struct(self, ResultsHandle, results);
520
- if(results != NULL) {
521
- int offset = 0;
440
+ StatementHandle *hStatement = getStatementHandle(self);
522
441
 
523
- offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
524
- if(offset >= 0 && offset < results->output->sqld) {
525
- XSQLVAR *var = results->output->sqlvar;
526
- int index;
442
+ offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
443
+ if(offset >= 0 && offset < hStatement->output->sqld) {
444
+ XSQLVAR *var = hStatement->output->sqlvar;
445
+ int index;
527
446
 
528
- for(index = 0; index < offset; index++, var++) ;
529
- name = rb_str_new(var->relname, var->relname_length);
530
- }
447
+ for(index = 0; index < offset; index++, var++) ;
448
+ name = rb_str_new(var->relname, var->relname_length);
531
449
  }
532
450
 
533
451
  return(name);
@@ -548,44 +466,28 @@ static VALUE getResultSetColumnType(VALUE self, VALUE column) {
548
466
  VALUE type = toSymbol("UNKNOWN");
549
467
 
550
468
  if(TYPE(column) == T_FIXNUM) {
551
- ResultsHandle *handle = NULL;
552
-
553
- Data_Get_Struct(self, ResultsHandle, handle);
554
- if(handle != NULL) {
555
- int index = FIX2INT(column);
469
+ StatementHandle *hStatement = getStatementHandle(self);
470
+ int index = FIX2INT(column);
556
471
 
557
- /* Fix negative index values. */
558
- if(index < 0) {
559
- index = handle->output->sqln + index;
560
- }
472
+ /* Fix negative index values. */
473
+ if(index < 0) {
474
+ index = hStatement->output->sqln + index;
475
+ }
561
476
 
562
- if(index >= 0 && index < handle->output->sqln) {
563
- type = getColumnType(&handle->output->sqlvar[index]);
564
- }
477
+ if(index >= 0 && index < hStatement->output->sqln) {
478
+ type = getColumnType(&hStatement->output->sqlvar[index]);
565
479
  }
566
480
  }
567
481
 
568
-
569
482
  return(type);
570
483
  }
571
484
 
572
-
573
- /**
574
- * This function provides the each method for the ResultSet class.
575
- *
576
- * @param self A reference to the ResultSet object to execute the method for.
577
- *
578
- * @return A reference to the last value returned by the associated block or
579
- * nil.
580
- *
581
- */
582
- VALUE eachResultSetRow(VALUE self) {
485
+ VALUE yieldRows(VALUE self) {
583
486
  VALUE result = Qnil;
584
487
 
585
488
  /* Check if a block was provided. */
586
489
  if(rb_block_given_p()) {
587
490
  VALUE row;
588
-
589
491
  while((row = fetchResultSetEntry(self)) != Qnil) {
590
492
  result = rb_yield(row);
591
493
  }
@@ -594,6 +496,22 @@ VALUE eachResultSetRow(VALUE self) {
594
496
  return(result);
595
497
  }
596
498
 
499
+ VALUE yieldResultsRows(VALUE self) {
500
+ return rb_ensure(yieldRows, self, closeResultSet, self);
501
+ }
502
+
503
+ /**
504
+ * This function provides the each method for the ResultSet class.
505
+ *
506
+ * @param self A reference to the ResultSet object to execute the method for.
507
+ *
508
+ * @return A reference to the last value returned by the associated block or
509
+ * nil.
510
+ *
511
+ */
512
+ VALUE eachResultSetRow(VALUE self) {
513
+ return yieldRows(self);
514
+ }
597
515
 
598
516
  /**
599
517
  * This function provides the exhausted? method of the ResultSet class.
@@ -605,84 +523,34 @@ VALUE eachResultSetRow(VALUE self) {
605
523
  *
606
524
  */
607
525
  VALUE isResultSetExhausted(VALUE self) {
608
- VALUE exhausted = Qfalse;
609
- ResultsHandle *results = NULL;
526
+ VALUE exhausted = Qtrue;
527
+ ResultsHandle *hResults = NULL;
610
528
 
611
- Data_Get_Struct(self, ResultsHandle, results);
612
- if(results->exhausted) {
613
- exhausted = Qtrue;
529
+ Data_Get_Struct(self, ResultsHandle, hResults);
530
+ if(hResults->active) {
531
+ exhausted = Qfalse;
614
532
  }
615
533
 
616
534
  return(exhausted);
617
535
  }
618
536
 
619
537
 
620
- /**
621
- * This method integrates with the Ruby garbage collector to insure that, if
622
- * a ResultSet contains a reference to a Transaction object, it doesn't get
623
- * collected by the garbage collector unnecessarily.
624
- *
625
- * @param handle A void pointer to the structure associated with the object
626
- * being scanned by the garbage collector.
627
- *
628
- */
629
- void resultSetMark(void *handle) {
630
- ResultsHandle *results = (ResultsHandle *)handle;
631
-
632
- if(results != NULL) {
633
- if(results->transaction != Qnil) {
634
- rb_gc_mark(results->transaction);
635
- }
636
- }
637
- }
638
-
639
-
640
538
  /**
641
539
  * This function provides a programmatic means of creating a ResultSet object.
642
540
  *
643
- * @param connection A reference to a Connection object that will be used
644
- * in executing the statement.
645
- * @param transaction A reference to a Transaction object that will be used
646
- * in executing the statement.
647
- * @param sql A reference to a String containing the SQL statement to
648
- * be executed. Must be a query.
649
- * @param dialect A reference to an integer containing the SQL dialect to
650
- * be used in executing the query.
651
- * @param parameters A reference to an array containing the parameters to be
652
- * used in executing the query.
541
+ * @param statement A statement to iterate over
542
+ * @param transaction A reference to a privater transaction object
543
+ * taht should be managed by this ResultSet.
544
+ * @param owns_transaction true if the result set should manage the transaction
653
545
  *
654
546
  * @return A reference to the newly created ResultSet object.
655
547
  *
656
548
  */
657
- VALUE rb_result_set_new(VALUE connection, VALUE transaction, VALUE sql,
658
- VALUE dialect, VALUE parameters) {
549
+ VALUE rb_result_set_new(VALUE statement, VALUE transaction) {
659
550
  VALUE instance = allocateResultSet(cResultSet);
660
-
661
- initializeResultSet(instance, connection, transaction, sql, dialect,
662
- parameters);
663
-
664
- return(instance);
551
+ return (initializeResultSet(instance, statement, transaction));
665
552
  }
666
553
 
667
-
668
- /**
669
- * This function assigns an anonymous transaction to a ResultSet, giving the
670
- * object responsibility for closing it.
671
- *
672
- * @param set A reference to the ResultSet object that will be taking
673
- * ownership of the Transaction.
674
- * @param transaction A reference to the Transaction object that the ResultSet
675
- * is assuming responsibility for.
676
- *
677
- */
678
- void rb_assign_transaction(VALUE set, VALUE transaction) {
679
- ResultsHandle *results = NULL;
680
-
681
- Data_Get_Struct(set, ResultsHandle, results);
682
- results->transaction = transaction;
683
- }
684
-
685
-
686
554
  /**
687
555
  * This function integrates with the Ruby garbage collector to free all of the
688
556
  * resources for a ResultSet object that is being collected.
@@ -692,60 +560,11 @@ void rb_assign_transaction(VALUE set, VALUE transaction) {
692
560
  *
693
561
  */
694
562
  void resultSetFree(void *handle) {
695
- if(handle != NULL) {
696
- ResultsHandle *results = (ResultsHandle *)handle;
697
-
698
- if(results->handle != 0) {
699
- ISC_STATUS status[ISC_STATUS_LENGTH];
700
-
701
- /* UNCOMMENT FOR DEBUG PURPOSES! */
702
- /*fprintf(stderr, "Releasing statement handle for...\n%s\n", results->sql);*/
703
- isc_dsql_free_statement(status, &results->handle, DSQL_drop);
704
- }
705
-
706
- if(results->output != NULL) {
707
- releaseDataArea(results->output);
708
- }
709
-
710
- resolveResultsTransaction(results, "rollback");
711
- free(results);
712
- }
713
- }
714
-
715
-
716
- /**
717
- * This is a simple function to aid in the clean up of statement handles.
718
- *
719
- * @param handle A pointer to the statement handle to be cleaned up.
720
- *
721
- */
722
- void cleanupHandle(isc_stmt_handle *handle) {
723
- if(*handle != 0) {
724
- ISC_STATUS status[ISC_STATUS_LENGTH];
725
-
726
- /* UNCOMMENT FOR DEBUG PURPOSES! */
727
- /*fprintf(stderr, "Cleaning up a statement handle.\n");*/
728
- isc_dsql_free_statement(status, handle, DSQL_drop);
563
+ if(handle) {
564
+ free(handle);
729
565
  }
730
566
  }
731
567
 
732
-
733
- /**
734
- * Simple helper function to resolve ResultsHandle associated transaction
735
- *
736
- * @param results - the ResultsHandle handle
737
- *
738
- * @param resolveMethod - transaction resolving method - eg. commit, rollback
739
- *
740
- */
741
- void resolveResultsTransaction(ResultsHandle *results, char *resolveMethod) {
742
- if(results->transaction != Qnil) {
743
- rb_funcall(results->transaction, rb_intern(resolveMethod), 0);
744
- results->transaction = Qnil;
745
- }
746
- }
747
-
748
-
749
568
  /**
750
569
  * This function initializes the ResultSet class within the Ruby environment.
751
570
  * The class is established under the module specified to the function.
@@ -757,13 +576,14 @@ void Init_ResultSet(VALUE module) {
757
576
  cResultSet = rb_define_class_under(module, "ResultSet", rb_cObject);
758
577
  rb_define_alloc_func(cResultSet, allocateResultSet);
759
578
  rb_include_module(cResultSet, rb_mEnumerable);
760
- rb_define_method(cResultSet, "initialize", initializeResultSet, 5);
579
+ rb_define_method(cResultSet, "initialize", initializeResultSet, 2);
761
580
  rb_define_method(cResultSet, "initialize_copy", forbidObjectCopy, 1);
762
581
  rb_define_method(cResultSet, "row_count", getResultSetCount, 0);
763
582
  rb_define_method(cResultSet, "fetch", fetchResultSetEntry, 0);
764
583
  rb_define_method(cResultSet, "close", closeResultSet, 0);
765
584
  rb_define_method(cResultSet, "connection", getResultSetConnection, 0);
766
585
  rb_define_method(cResultSet, "transaction", getResultSetTransaction, 0);
586
+ rb_define_method(cResultSet, "statement", getResultSetStatement, 0);
767
587
  rb_define_method(cResultSet, "sql", getResultSetSQL, 0);
768
588
  rb_define_method(cResultSet, "dialect", getResultSetDialect, 0);
769
589
  rb_define_method(cResultSet, "each", eachResultSetRow, 0);