rubyfb 0.6.4 → 0.6.7

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.
@@ -1,648 +0,0 @@
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 "ruby.h"
35
- #include "FireRuby.h"
36
-
37
- /* Function prototypes. */
38
- static VALUE allocateResultSet(VALUE);
39
- static VALUE initializeResultSet(VALUE, VALUE, VALUE);
40
- static VALUE getResultSetRow(VALUE);
41
- static VALUE fetchResultSetEntry(VALUE);
42
- static VALUE closeResultSet(VALUE);
43
- static VALUE getResultSetCount(VALUE);
44
- static VALUE getResultSetConnection(VALUE);
45
- static VALUE getResultSetTransaction(VALUE);
46
- static VALUE getResultSetStatement(VALUE);
47
- static VALUE getResultSetSQL(VALUE);
48
- static VALUE getResultSetDialect(VALUE);
49
- static VALUE getResultSetColumnCount(VALUE);
50
- static VALUE getResultSetColumnName(VALUE, VALUE);
51
- static VALUE getResultSetColumnAlias(VALUE, VALUE);
52
- static VALUE getResultSetColumnScale(VALUE, VALUE);
53
- static VALUE getResultSetColumnTable(VALUE, VALUE);
54
- static VALUE getResultSetColumnType(VALUE, VALUE);
55
- static VALUE eachResultSetRow(VALUE);
56
- static VALUE isResultSetExhausted(VALUE);
57
-
58
- /* Globals. */
59
- VALUE cResultSet;
60
-
61
- ID NEW_ID, SIZE_ID, AT_NAME_ID, AT_ALIAS_ID, AT_KEY_ID, AT_SCALE_ID, AT_COLUMNS_ID, AT_TYPE_ID,
62
- AT_RELATION_ID, AT_STATEMENT_ID, AT_TRANSACTION_ID, AT_COLUMNS_ID;
63
-
64
- static StatementHandle* getStatementHandle(VALUE self) {
65
- StatementHandle *hStatement;
66
- Data_Get_Struct(getResultSetStatement(self), StatementHandle, hStatement);
67
-
68
- return (hStatement);
69
- }
70
-
71
- short isActiveResultSet(VALUE self) {
72
- short result = 0;
73
- if ((Qtrue == rb_obj_is_kind_of(self, cResultSet))) {
74
- ResultsHandle *hResults = NULL;
75
- Data_Get_Struct(self, ResultsHandle, hResults);
76
- result = hResults->active;
77
- }
78
- return (result);
79
- }
80
-
81
- void resultSetManageTransaction(VALUE self) {
82
- ResultsHandle *hResults = NULL;
83
- Data_Get_Struct(self, ResultsHandle, hResults);
84
- hResults->manage_transaction = 1;
85
- }
86
-
87
- void resultSetManageStatement(VALUE self) {
88
- ResultsHandle *hResults = NULL;
89
- Data_Get_Struct(self, ResultsHandle, hResults);
90
- hResults->manage_statement = 1;
91
- }
92
-
93
- /**
94
- * @self - the result set object
95
- * @return - columns metadata array
96
- */
97
-
98
- VALUE getResultsColumns(VALUE self) {
99
- return rb_ivar_get(self, AT_COLUMNS_ID);
100
- }
101
-
102
- /**
103
- * This method allocates a new ResultSet object.
104
- *
105
- * @param klass A reference to the ResultSet Class object.
106
- *
107
- * @return A reference to the newly allocated ResultSet object.
108
- *
109
- */
110
- VALUE allocateResultSet(VALUE klass) {
111
- ResultsHandle *results = ALLOC(ResultsHandle);
112
-
113
- if(results == NULL) {
114
- rb_raise(rb_eNoMemError,
115
- "Memory allocation failure allocating a result set.");
116
- }
117
- results->fetched = 0;
118
- results->active = 0;
119
- results->manage_transaction = 0;
120
- results->manage_statement = 0;
121
-
122
- return(Data_Wrap_Struct(klass, NULL, resultSetFree, results));
123
- }
124
-
125
-
126
- /**
127
- * This function provides the initialize method for the ResultSet class.
128
- *
129
- * @param self A reference to the ResultSet object to be initialized.
130
- * @param statement A statement to iterate over
131
- * @param transaction A reference to a privater transaction object
132
- * taht should be managed by this ResultSet.
133
- *
134
- * @return A reference to the newly initialize ResultSet object.
135
- *
136
- */
137
- VALUE initializeResultSet(VALUE self, VALUE statement, VALUE transaction) {
138
- int index;
139
- ResultsHandle *hResults = NULL;
140
- StatementHandle *hStatement;
141
- XSQLVAR *var;
142
- VALUE columns, column, name, alias, key_flag;
143
-
144
- Data_Get_Struct(self, ResultsHandle, hResults);
145
- rb_ivar_set(self, AT_STATEMENT_ID, statement);
146
- rb_ivar_set(self, AT_TRANSACTION_ID, transaction);
147
-
148
- hStatement = getStatementHandle(self);
149
- var = hStatement->output->sqlvar;
150
- columns = rb_ary_new2(hStatement->output->sqld);
151
- rb_ivar_set(self, AT_COLUMNS_ID, columns);
152
-
153
- key_flag = getFireRubySetting("ALIAS_KEYS");
154
- for(index = 0; index < hStatement->output->sqld; index++, var++) {
155
- column = rb_funcall(rb_cObject, NEW_ID, 0);
156
- rb_ary_store(columns, index, column);
157
- name = rb_str_new(var->sqlname, var->sqlname_length);
158
- alias = rb_str_new(var->aliasname, var->aliasname_length);
159
- rb_ivar_set(column, AT_NAME_ID, name);
160
- rb_ivar_set(column, AT_ALIAS_ID, alias);
161
- if(key_flag == Qtrue) {
162
- rb_ivar_set(column, AT_KEY_ID, alias);
163
- } else {
164
- rb_ivar_set(column, AT_KEY_ID, name);
165
- }
166
- rb_ivar_set(column, AT_TYPE_ID, getColumnType(var));
167
- rb_ivar_set(column, AT_SCALE_ID, INT2FIX(var->sqlscale));
168
- rb_ivar_set(column, AT_RELATION_ID, rb_str_new(var->relname, var->relname_length));
169
- }
170
-
171
- hResults->active = 1;
172
- return(self);
173
- }
174
-
175
- /**
176
- * This function provides the row method for the ResultSet class.
177
- *
178
- * @param self A reference to the ResultSet object to make the call on.
179
- *
180
- * @return Either a reference to a Row object or nil.
181
- *
182
- */
183
- VALUE getResultSetRow(VALUE self) {
184
- VALUE row = Qnil;
185
- ResultsHandle *hResults = NULL;
186
-
187
- Data_Get_Struct(self, ResultsHandle, hResults);
188
- if(hResults->fetched) {
189
- row = rb_row_new(self, INT2FIX(hResults->fetched));
190
- }
191
- return (row);
192
- }
193
-
194
-
195
- /**
196
- * This function provides the fetch method for the ResultSet class.
197
- *
198
- * @param self A reference to the ResultSet object to make the call on.
199
- *
200
- * @return Either a reference to a Row object or nil.
201
- *
202
- */
203
- VALUE fetchResultSetEntry(VALUE self) {
204
- VALUE row = Qnil;
205
- StatementHandle *hStatement = getStatementHandle(self);
206
- ResultsHandle *hResults = NULL;
207
- ISC_STATUS status[ISC_STATUS_LENGTH],
208
- fetch_result;
209
-
210
- Data_Get_Struct(self, ResultsHandle, hResults);
211
- if(hResults->active) {
212
- if (isCursorStatement(hStatement)) {
213
- fetch_result = isc_dsql_fetch(status, &hStatement->handle, hStatement->dialect,
214
- hStatement->output);
215
- switch(fetch_result) {
216
- case 0:
217
- hResults->fetched += 1;
218
- row = getResultSetRow(self);
219
- break;
220
- case 100:
221
- hResults->active = 0;
222
- break;
223
- default:
224
- rb_fireruby_raise(status, "Error fetching query row.");
225
- }
226
- } else {
227
- hResults->active = 0;
228
- hResults->fetched = 1;
229
- row = getResultSetRow(self);
230
- }
231
- }
232
- return (row);
233
- }
234
-
235
- /**
236
- * This function provides the close method for the ResultSet class, releasing
237
- * resources associated with the ResultSet.
238
- *
239
- * @param self A reference to the ResultSet object to be closed.
240
- *
241
- * @return A reference to the closed ResultSet object.
242
- *
243
- */
244
- VALUE closeResultSet(VALUE self) {
245
- StatementHandle *hStatement = getStatementHandle(self);
246
- ResultsHandle *hResults = NULL;
247
- Data_Get_Struct(self, ResultsHandle, hResults);
248
- ISC_STATUS status[ISC_STATUS_LENGTH];
249
-
250
- hResults->active = 0;
251
- if(isc_dsql_free_statement(status, &hStatement->handle, DSQL_close)) {
252
- rb_fireruby_raise(status, "Error closing cursor.");
253
- }
254
- if(hResults->manage_statement) {
255
- VALUE statement = getResultSetStatement(self),
256
- menagement_required = rb_funcall(statement, rb_intern("prepared?"), 0);
257
- if(Qtrue == menagement_required) {
258
- rb_funcall(statement, rb_intern("close"), 0);
259
- }
260
- }
261
- if(hResults->manage_transaction) {
262
- VALUE transaction = getResultSetTransaction(self),
263
- menagement_required = rb_funcall(transaction, rb_intern("active?"), 0);
264
- if(Qtrue == menagement_required) {
265
- rb_funcall(transaction, rb_intern("commit"), 0);
266
- }
267
- }
268
-
269
- return(self);
270
- }
271
-
272
-
273
- /**
274
- * This function provides the count method for the ResultSet class.
275
- *
276
- * @param self A reference to the ResultSet object to fetch the current row
277
- * count for.
278
- *
279
- * @return A reference to an integer containing a count of the number of rows
280
- * fetched from the ResultSet so far.
281
- *
282
- */
283
- VALUE getResultSetCount(VALUE self) {
284
- ResultsHandle *results = NULL;
285
-
286
- Data_Get_Struct(self, ResultsHandle, results);
287
-
288
- return(INT2NUM(results->fetched));
289
- }
290
-
291
-
292
- /**
293
- * This method provides the accessor method for the connection ResultSet
294
- * attribute.
295
- *
296
- * @param self A reference to the ResultSet object to fetch the attribute
297
- * from.
298
- *
299
- * @return A reference to the requested attribute object.
300
- *
301
- */
302
- VALUE getResultSetConnection(VALUE self) {
303
- return(rb_funcall(getResultSetStatement(self), rb_intern("connection"), 0));
304
- }
305
-
306
-
307
- /**
308
- * This method provides the accessor method for the transaction ResultSet
309
- * attribute.
310
- *
311
- * @param self A reference to the ResultSet object to fetch the attribute
312
- * from.
313
- *
314
- * @return A reference to the requested attribute object.
315
- *
316
- */
317
- VALUE getResultSetTransaction(VALUE self) {
318
- return rb_ivar_get(self, AT_TRANSACTION_ID);
319
- }
320
-
321
- /**
322
- * This method provides the accessor method for the transaction ResultSet
323
- * statement.
324
- *
325
- * @param self A reference to the ResultSet object to fetch the attribute
326
- * from.
327
- *
328
- * @return A reference to the requested attribute object.
329
- *
330
- */
331
- VALUE getResultSetStatement(VALUE self) {
332
- return rb_ivar_get(self, AT_STATEMENT_ID);
333
- }
334
-
335
-
336
- /**
337
- * This method provides the accessor method for the SQL ResultSet attribute.
338
- *
339
- * @param self A reference to the ResultSet object to fetch the attribute
340
- * from.
341
- *
342
- * @return A reference to the requested attribute object.
343
- *
344
- */
345
- VALUE getResultSetSQL(VALUE self) {
346
- return(rb_funcall(getResultSetStatement(self), rb_intern("sql"), 0));
347
- }
348
-
349
-
350
- /**
351
- * This method provides the accessor method for the dialect ResultSet attribute.
352
- *
353
- * @param self A reference to the ResultSet object to fetch the attribute
354
- * from.
355
- *
356
- * @return A reference to the requested attribute object.
357
- *
358
- */
359
- VALUE getResultSetDialect(VALUE self) {
360
- return(rb_funcall(getResultSetStatement(self), rb_intern("dialect"), 0));
361
- }
362
-
363
-
364
- /**
365
- * This function provides the column_count attribute accessor for the ResultSet
366
- * class.
367
- *
368
- * @param self A reference to the ResultSet object to fetch the attribute for.
369
- *
370
- * @return A reference to an integer containing the column count.
371
- *
372
- */
373
- VALUE getResultSetColumnCount(VALUE self) {
374
- return rb_funcall(getResultsColumns(self), SIZE_ID, 0);
375
- }
376
-
377
-
378
- /**
379
- * This function provides the column_name method for the ResultSet class.
380
- *
381
- * @param self A reference to the ResultSet object to retrieve the column
382
- * name from.
383
- * @param column An offset to the column to retrieve the name for.
384
- *
385
- * @return A String containing the column name or nil if an invalid column
386
- * was specified.
387
- *
388
- */
389
- static VALUE getResultSetColumnName(VALUE self, VALUE column) {
390
- int offset = 0;
391
- VALUE name = Qnil;
392
- StatementHandle *hStatement = getStatementHandle(self);
393
-
394
- offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
395
- if(offset >= 0 && offset < hStatement->output->sqld) {
396
- XSQLVAR *var = hStatement->output->sqlvar;
397
- int index;
398
-
399
- for(index = 0; index < offset; index++, var++) ;
400
- name = rb_str_new(var->sqlname, var->sqlname_length);
401
- }
402
-
403
- return(name);
404
- }
405
-
406
-
407
- /**
408
- * This function provides the column_alias method for the ResultSet class.
409
- *
410
- * @param self A reference to the ResultSet object to retrieve the column
411
- * alias from.
412
- * @param column An offset to the column to retrieve the alias for.
413
- *
414
- * @return A String containing the column alias or nil if an invalid column
415
- * was specified.
416
- *
417
- */
418
- static VALUE getResultSetColumnAlias(VALUE self, VALUE column) {
419
- int offset = 0;
420
- VALUE alias = Qnil;
421
- StatementHandle *hStatement = getStatementHandle(self);
422
-
423
- offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
424
- if(offset >= 0 && offset < hStatement->output->sqld) {
425
- XSQLVAR *var = hStatement->output->sqlvar;
426
- int index;
427
-
428
- for(index = 0; index < offset; index++, var++) ;
429
- alias = rb_str_new(var->aliasname, var->aliasname_length);
430
- }
431
-
432
- return(alias);
433
- }
434
-
435
- /**
436
- * This function provides the column_scale method for the ResultSet class.
437
- *
438
- * @param self A reference to the ResultSet object to retrieve the column
439
- * alias from.
440
- * @param column An offset to the column to retrieve the scale of.
441
- *
442
- * @return An Integer representing the sqlscale of the column, or nil if an
443
- * invalid column was specified.
444
- *
445
- */
446
- static VALUE getResultSetColumnScale(VALUE self, VALUE column) {
447
- int offset = 0;
448
- VALUE scale = Qnil;
449
- StatementHandle *hStatement = getStatementHandle(self);
450
-
451
- offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
452
- if(offset >= 0 && offset < hStatement->output->sqld) {
453
- XSQLVAR *var = hStatement->output->sqlvar;
454
- int index;
455
-
456
- for(index = 0; index < offset; index++, var++) ;
457
- scale = INT2FIX(var->sqlscale);
458
- }
459
-
460
- return(scale);
461
- }
462
-
463
-
464
- /**
465
- * This function provides the column_table method for the ResultSet class.
466
- *
467
- * @param self A reference to the ResultSet object to retrieve the column
468
- * table name from.
469
- * @param column An offset to the column to retrieve the table name for.
470
- *
471
- * @return A String containing the column table name or nil if an invalid
472
- * column was specified.
473
- *
474
- */
475
- static VALUE getResultSetColumnTable(VALUE self, VALUE column) {
476
- int offset = 0;
477
- VALUE name = Qnil;
478
- StatementHandle *hStatement = getStatementHandle(self);
479
-
480
- offset = (TYPE(column) == T_FIXNUM ? FIX2INT(column) : NUM2INT(column));
481
- if(offset >= 0 && offset < hStatement->output->sqld) {
482
- XSQLVAR *var = hStatement->output->sqlvar;
483
- int index;
484
-
485
- for(index = 0; index < offset; index++, var++) ;
486
- name = rb_str_new(var->relname, var->relname_length);
487
- }
488
-
489
- return(name);
490
- }
491
-
492
-
493
- /**
494
- * This function attempts to extract basic type information for a column within
495
- * a ResultSet object.
496
- *
497
- * @param self A reference to the ResultSet to execute on.
498
- * @param column A integer offset for the column to extract the type of.
499
- *
500
- * @return A Symbol representing the basic data type.
501
- *
502
- */
503
- static VALUE getResultSetColumnType(VALUE self, VALUE column) {
504
- VALUE type = toSymbol("UNKNOWN");
505
-
506
- if(TYPE(column) == T_FIXNUM) {
507
- StatementHandle *hStatement = getStatementHandle(self);
508
- int index = FIX2INT(column);
509
-
510
- /* Fix negative index values. */
511
- if(index < 0) {
512
- index = hStatement->output->sqln + index;
513
- }
514
-
515
- if(index >= 0 && index < hStatement->output->sqln) {
516
- type = getColumnType(&hStatement->output->sqlvar[index]);
517
- }
518
- }
519
-
520
- return(type);
521
- }
522
-
523
- VALUE yieldRows(VALUE self) {
524
- VALUE result = Qnil;
525
-
526
- /* Check if a block was provided. */
527
- if(rb_block_given_p()) {
528
- VALUE row;
529
- while((row = fetchResultSetEntry(self)) != Qnil) {
530
- result = rb_yield(row);
531
- }
532
- }
533
-
534
- return(result);
535
- }
536
-
537
- VALUE yieldResultsRows(VALUE self) {
538
- return rb_ensure(yieldRows, self, closeResultSet, self);
539
- }
540
-
541
- /**
542
- * This function provides the each method for the ResultSet class.
543
- *
544
- * @param self A reference to the ResultSet object to execute the method for.
545
- *
546
- * @return A reference to the last value returned by the associated block or
547
- * nil.
548
- *
549
- */
550
- VALUE eachResultSetRow(VALUE self) {
551
- return yieldRows(self);
552
- }
553
-
554
- /**
555
- * This function provides the exhausted? method of the ResultSet class.
556
- *
557
- * @param self A reference to the ResultSet object to make the call for.
558
- *
559
- * @return True if all rows have been fetched from the result set, false
560
- * if they haven't.
561
- *
562
- */
563
- VALUE isResultSetExhausted(VALUE self) {
564
- VALUE exhausted = Qtrue;
565
- ResultsHandle *hResults = NULL;
566
-
567
- Data_Get_Struct(self, ResultsHandle, hResults);
568
- if(hResults->active) {
569
- exhausted = Qfalse;
570
- }
571
-
572
- return(exhausted);
573
- }
574
-
575
-
576
- /**
577
- * This function provides a programmatic means of creating a ResultSet object.
578
- *
579
- * @param statement A statement to iterate over
580
- * @param transaction A reference to a privater transaction object
581
- * taht should be managed by this ResultSet.
582
- * @param owns_transaction true if the result set should manage the transaction
583
- *
584
- * @return A reference to the newly created ResultSet object.
585
- *
586
- */
587
- VALUE rb_result_set_new(VALUE statement, VALUE transaction) {
588
- VALUE instance = allocateResultSet(cResultSet);
589
- return (initializeResultSet(instance, statement, transaction));
590
- }
591
-
592
- /**
593
- * This function integrates with the Ruby garbage collector to free all of the
594
- * resources for a ResultSet object that is being collected.
595
- *
596
- * @param handle A pointer to the ResultsHandle structure associated with the
597
- * object being collected.
598
- *
599
- */
600
- void resultSetFree(void *handle) {
601
- if(handle) {
602
- free(handle);
603
- }
604
- }
605
-
606
- /**
607
- * This function initializes the ResultSet class within the Ruby environment.
608
- * The class is established under the module specified to the function.
609
- *
610
- * @param module A reference to the module to create the class within.
611
- *
612
- */
613
- void Init_ResultSet(VALUE module) {
614
- NEW_ID = rb_intern("new");
615
- SIZE_ID = rb_intern("size");
616
- AT_NAME_ID = rb_intern("@name");
617
- AT_ALIAS_ID = rb_intern("@alias");
618
- AT_KEY_ID = rb_intern("@key");
619
- AT_SCALE_ID = rb_intern("@scale");
620
- AT_COLUMNS_ID = rb_intern("@columns");
621
- AT_TYPE_ID = rb_intern("@type");
622
- AT_RELATION_ID = rb_intern("@relation");
623
- AT_STATEMENT_ID = rb_intern("@statement");
624
- AT_TRANSACTION_ID = rb_intern("@transaction");
625
- AT_COLUMNS_ID = rb_intern("@columns");
626
-
627
- cResultSet = rb_define_class_under(module, "ResultSet", rb_cObject);
628
- rb_define_alloc_func(cResultSet, allocateResultSet);
629
- rb_include_module(cResultSet, rb_mEnumerable);
630
- rb_define_method(cResultSet, "initialize", initializeResultSet, 2);
631
- rb_define_method(cResultSet, "initialize_copy", forbidObjectCopy, 1);
632
- rb_define_method(cResultSet, "row_count", getResultSetCount, 0);
633
- rb_define_method(cResultSet, "fetch", fetchResultSetEntry, 0);
634
- rb_define_method(cResultSet, "close", closeResultSet, 0);
635
- rb_define_method(cResultSet, "connection", getResultSetConnection, 0);
636
- rb_define_method(cResultSet, "transaction", getResultSetTransaction, 0);
637
- rb_define_method(cResultSet, "statement", getResultSetStatement, 0);
638
- rb_define_method(cResultSet, "sql", getResultSetSQL, 0);
639
- rb_define_method(cResultSet, "dialect", getResultSetDialect, 0);
640
- rb_define_method(cResultSet, "each", eachResultSetRow, 0);
641
- rb_define_method(cResultSet, "column_name", getResultSetColumnName, 1);
642
- rb_define_method(cResultSet, "column_alias", getResultSetColumnAlias, 1);
643
- rb_define_method(cResultSet, "column_scale", getResultSetColumnScale, 1);
644
- rb_define_method(cResultSet, "column_table", getResultSetColumnTable, 1);
645
- rb_define_method(cResultSet, "column_count", getResultSetColumnCount, 0);
646
- rb_define_method(cResultSet, "exhausted?", isResultSetExhausted, 0);
647
- rb_define_method(cResultSet, "get_base_type", getResultSetColumnType, 1);
648
- }