rubyfb 0.6.3 → 0.6.4

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ v0.6.4 ==
2
+ Tyr to fix another Segmentation fault in Row class (GC integration issues)
3
+
1
4
  v0.6.3 ==
2
5
  Fix change_column() migration method
3
6
  Fix Segmentation fault in Row class (GC integration issues)
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'echoe'
2
- e = Echoe.new('rubyfb', '0.6.3') do |p|
2
+ e = Echoe.new('rubyfb', '0.6.4') do |p|
3
3
  p.description = "Firebird SQL access library"
4
4
  p.url = "http://rubyforge.org/projects/rubyfb"
5
5
  p.author = "George Georgiev"
@@ -31,8 +31,8 @@
31
31
  #include "Transaction.h"
32
32
  #include "DataArea.h"
33
33
  #include "Row.h"
34
- #include "TypeMap.h"
35
34
  #include "ruby.h"
35
+ #include "FireRuby.h"
36
36
 
37
37
  /* Function prototypes. */
38
38
  static VALUE allocateResultSet(VALUE);
@@ -58,7 +58,10 @@ static VALUE isResultSetExhausted(VALUE);
58
58
  /* Globals. */
59
59
  VALUE cResultSet;
60
60
 
61
- StatementHandle* getStatementHandle(VALUE self) {
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) {
62
65
  StatementHandle *hStatement;
63
66
  Data_Get_Struct(getResultSetStatement(self), StatementHandle, hStatement);
64
67
 
@@ -87,6 +90,15 @@ void resultSetManageStatement(VALUE self) {
87
90
  hResults->manage_statement = 1;
88
91
  }
89
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
+
90
102
  /**
91
103
  * This method allocates a new ResultSet object.
92
104
  *
@@ -123,13 +135,40 @@ VALUE allocateResultSet(VALUE klass) {
123
135
  *
124
136
  */
125
137
  VALUE initializeResultSet(VALUE self, VALUE statement, VALUE transaction) {
138
+ int index;
126
139
  ResultsHandle *hResults = NULL;
127
- Data_Get_Struct(self, ResultsHandle, hResults);
140
+ StatementHandle *hStatement;
141
+ XSQLVAR *var;
142
+ VALUE columns, column, name, alias, key_flag;
128
143
 
129
- rb_iv_set(self, "@statement", statement);
130
- rb_iv_set(self, "@transaction", transaction);
131
- hResults->active = 1;
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);
132
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;
133
172
  return(self);
134
173
  }
135
174
 
@@ -147,8 +186,7 @@ VALUE getResultSetRow(VALUE self) {
147
186
 
148
187
  Data_Get_Struct(self, ResultsHandle, hResults);
149
188
  if(hResults->fetched) {
150
- VALUE array = toArray(self);
151
- row = rb_row_new(self, array, INT2FIX(hResults->fetched));
189
+ row = rb_row_new(self, INT2FIX(hResults->fetched));
152
190
  }
153
191
  return (row);
154
192
  }
@@ -277,7 +315,7 @@ VALUE getResultSetConnection(VALUE self) {
277
315
  *
278
316
  */
279
317
  VALUE getResultSetTransaction(VALUE self) {
280
- return rb_iv_get(self, "@transaction");
318
+ return rb_ivar_get(self, AT_TRANSACTION_ID);
281
319
  }
282
320
 
283
321
  /**
@@ -291,7 +329,7 @@ VALUE getResultSetTransaction(VALUE self) {
291
329
  *
292
330
  */
293
331
  VALUE getResultSetStatement(VALUE self) {
294
- return rb_iv_get(self, "@statement");
332
+ return rb_ivar_get(self, AT_STATEMENT_ID);
295
333
  }
296
334
 
297
335
 
@@ -333,7 +371,7 @@ VALUE getResultSetDialect(VALUE self) {
333
371
  *
334
372
  */
335
373
  VALUE getResultSetColumnCount(VALUE self) {
336
- return(INT2NUM(getStatementHandle(self)->output->sqld));
374
+ return rb_funcall(getResultsColumns(self), SIZE_ID, 0);
337
375
  }
338
376
 
339
377
 
@@ -573,6 +611,19 @@ void resultSetFree(void *handle) {
573
611
  *
574
612
  */
575
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
+
576
627
  cResultSet = rb_define_class_under(module, "ResultSet", rb_cObject);
577
628
  rb_define_alloc_func(cResultSet, allocateResultSet);
578
629
  rb_include_module(cResultSet, rb_mEnumerable);
@@ -52,6 +52,7 @@ short isActiveResultSet(VALUE);
52
52
  VALUE yieldResultsRows(VALUE);
53
53
  void resultSetManageTransaction(VALUE);
54
54
  void resultSetManageStatement(VALUE);
55
+ VALUE getResultsColumns(VALUE);
55
56
 
56
57
  #endif /* FIRERUBY_RESULT_SET_H */
57
58
 
data/ext/Row.c CHANGED
@@ -25,13 +25,13 @@
25
25
 
26
26
  /* Includes. */
27
27
  #include "Row.h"
28
+ #include "TypeMap.h"
28
29
  #include "FireRuby.h"
29
30
  #include "ibase.h"
30
31
  #include "ruby.h"
31
32
 
32
33
  /* Function prototypes. */
33
- static VALUE allocateRow(VALUE);
34
- static VALUE initializeRow(VALUE, VALUE, VALUE, VALUE);
34
+ static VALUE initializeRow(VALUE, VALUE, VALUE);
35
35
  static VALUE columnsInRow(VALUE);
36
36
  static VALUE getRowNumber(VALUE);
37
37
  static VALUE getColumnName(VALUE, VALUE);
@@ -57,72 +57,71 @@ static VALUE rowValuesAt(int, VALUE *, VALUE);
57
57
 
58
58
  /* Globals. */
59
59
  VALUE cRow;
60
+ ID EQL_ID, FETCH_ID, NEW_ID,
61
+ AT_COLUMNS_ID, AT_NUMBER_ID,
62
+ AT_NAME_ID, AT_ALIAS_ID, AT_KEY_ID, AT_SCALE_ID,
63
+ AT_VALUE_ID, AT_TYPE_ID, AT_COLUMN_ID;
60
64
 
61
- /**
62
- * This function integrates with the Ruby garbage collector to insure that
63
- * all resources associated with a Row object are marked during the mark phase
64
- *
65
- * @param row A pointer to the RowHandle object for the Row object.
66
- *
67
- */
68
- void rowGCMark(void *handle) {
69
- if(handle != NULL) {
70
- RowHandle *row = (RowHandle *)handle;
71
- int i;
72
- for(i = 0; i < row->size; i++) {
73
- rb_gc_mark(row->columns[i].value);
74
- rb_gc_mark(row->columns[i].type);
75
- rb_gc_mark(row->columns[i].scale);
76
- }
65
+ static VALUE getColumns(VALUE self) {
66
+ return rb_ivar_get(self, AT_COLUMNS_ID);
67
+ }
68
+
69
+ static VALUE checkRowOffset(VALUE columns, VALUE index) {
70
+ int offset = FIX2INT(index);
71
+
72
+ /* Correct negative index values. */
73
+ if(offset < 0) {
74
+ return INT2NUM(RARRAY_LEN(columns) + offset);
77
75
  }
76
+ return index;
78
77
  }
79
78
 
80
- /**
81
- * This function integrates with the Ruby garbage collector to insure that
82
- * all resources associated with a Row object are released whenever the Row
83
- * object is collected.
84
- *
85
- * @param row A pointer to the RowHandle object for the Row object.
86
- *
87
- */
88
- void freeRow(void *row) {
89
- if(row != NULL) {
90
- RowHandle *handle = (RowHandle *)row;
79
+ static VALUE metadataScan(VALUE self, VALUE key, ID slot) {
80
+ long idx;
81
+ VALUE columns = getColumns(self);
91
82
 
92
- if(handle->columns != NULL) {
93
- free(handle->columns);
83
+ for(idx=0; idx < RARRAY_LEN(columns); idx++) {
84
+ VALUE column = rb_ary_entry(columns, idx),
85
+ meta_data = rb_ivar_get(column, AT_COLUMN_ID);
86
+ if(Qtrue == rb_funcall(rb_ivar_get(meta_data, slot), EQL_ID, 1, key)) {
87
+ return(column);
94
88
  }
95
- free(handle);
96
89
  }
90
+ return(Qnil);
97
91
  }
98
92
 
99
- /**
100
- * This function integrates with the Ruby memory allocation system to allocate
101
- * space for new Row objects.
102
- *
103
- * @param klass A reference to the Row class.
104
- *
105
- * @return A reference to the Row class instance allocated.
106
- *
107
- */
108
- static VALUE allocateRow(VALUE klass) {
109
- VALUE row;
110
- RowHandle *handle = ALLOC(RowHandle);
111
-
112
- if(handle != NULL) {
113
- /* Initialise the row fields. */
114
- handle->size = 0;
115
- handle->number = 0;
116
- handle->columns = NULL;
117
- row = Data_Wrap_Struct(klass, rowGCMark, freeRow, handle);
118
- } else {
119
- /* Generate an exception. */
120
- rb_raise(rb_eNoMemError, "Memory allocation failure allocating a row.");
93
+ static VALUE rowCollect(VALUE self, ID slot, short metadata_flag) {
94
+ VALUE columns = getColumns(self);
95
+ long idx, size = RARRAY_LEN(columns);
96
+ VALUE result = rb_ary_new2(size);
97
+ for(idx=0; idx < size; idx++) {
98
+ VALUE target = rb_ary_entry(columns, idx);
99
+ if(metadata_flag) {
100
+ target = rb_ivar_get(target, AT_COLUMN_ID);
101
+ }
102
+ rb_ary_store(result, idx, rb_ivar_get(target, slot));
121
103
  }
104
+ return(result);
105
+ }
122
106
 
123
- return(row);
107
+ static VALUE getColumn(VALUE columns, VALUE index) {
108
+ return rb_funcall(columns, FETCH_ID, 1, index);
124
109
  }
125
110
 
111
+ static VALUE getMetadata(VALUE columns, VALUE index) {
112
+ return rb_ivar_get(getColumn(columns, index), AT_COLUMN_ID);
113
+ }
114
+
115
+ static VALUE columnKey(VALUE column) {
116
+ return rb_ivar_get(rb_ivar_get(column, AT_COLUMN_ID), AT_KEY_ID);
117
+ }
118
+
119
+ static VALUE keyValuePair(VALUE column) {
120
+ VALUE result = rb_ary_new2(2);
121
+ rb_ary_store(result, 0, columnKey(column));
122
+ rb_ary_store(result, 1, rb_ivar_get(column, AT_VALUE_ID));
123
+ return(result);
124
+ }
126
125
 
127
126
  /**
128
127
  * This function provides the initialize method for the Row class.
@@ -140,46 +139,9 @@ static VALUE allocateRow(VALUE klass) {
140
139
  * @return A reference to the initialize Row object.
141
140
  *
142
141
  */
143
- static VALUE initializeRow(VALUE self, VALUE results, VALUE data, VALUE number) {
144
- RowHandle *row = NULL;
145
- VALUE value = rb_funcall(data, rb_intern("size"), 0);
146
-
147
- Data_Get_Struct(self, RowHandle, row);
148
- rb_iv_set(self, "@number", number);
149
- row->size = TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value);
150
- if(row->size > 0) {
151
- row->columns = ALLOC_N(ColumnHandle, row->size);
152
-
153
- if(row->columns != NULL) {
154
- int i;
155
-
156
- memset(row->columns, 0, sizeof(ColumnHandle) * row->size);
157
- for(i = 0; i < row->size; i++) {
158
- VALUE index,
159
- name,
160
- alias,
161
- scale,
162
- items;
163
-
164
- index = INT2NUM(i);
165
- name = rb_funcall(results, rb_intern("column_name"), 1, index);
166
- alias = rb_funcall(results, rb_intern("column_alias"), 1, index);
167
- strcpy(row->columns[i].name, StringValuePtr(name));
168
- strcpy(row->columns[i].alias, StringValuePtr(alias));
169
- items = rb_ary_entry(data, i);
170
- row->columns[i].value = rb_ary_entry(items, 0);
171
- row->columns[i].type = rb_ary_entry(items, 1);
172
- row->columns[i].scale = rb_funcall(results, rb_intern("column_scale"), 1, index);
173
-
174
- if(TYPE(rb_ary_entry(items, 1)) == T_NIL) {
175
- fprintf(stderr, "Nil column type encountered.\n");
176
- }
177
- }
178
- } else {
179
- rb_raise(rb_eNoMemError, "Memory allocation failure populating row.");
180
- }
181
- }
182
-
142
+ static VALUE initializeRow(VALUE self, VALUE results, VALUE number) {
143
+ rb_ivar_set(self, AT_NUMBER_ID, number);
144
+ rb_ivar_set(self, AT_COLUMNS_ID, toRowColumns(results));
183
145
  return(self);
184
146
  }
185
147
 
@@ -193,11 +155,7 @@ static VALUE initializeRow(VALUE self, VALUE results, VALUE data, VALUE number)
193
155
  *
194
156
  */
195
157
  static VALUE columnsInRow(VALUE self) {
196
- RowHandle *row = NULL;
197
-
198
- Data_Get_Struct(self, RowHandle, row);
199
-
200
- return(INT2NUM(row->size));
158
+ return LONG2NUM(RARRAY_LEN(getColumns(self)));
201
159
  }
202
160
 
203
161
 
@@ -210,7 +168,7 @@ static VALUE columnsInRow(VALUE self) {
210
168
  *
211
169
  */
212
170
  static VALUE getRowNumber(VALUE self) {
213
- return(rb_iv_get(self, "@number"));
171
+ return(rb_ivar_get(self, AT_NUMBER_ID));
214
172
  }
215
173
 
216
174
 
@@ -225,17 +183,7 @@ static VALUE getRowNumber(VALUE self) {
225
183
  *
226
184
  */
227
185
  static VALUE getColumnName(VALUE self, VALUE index) {
228
- VALUE name = Qnil;
229
- RowHandle *row = NULL;
230
- int number = 0;
231
-
232
- Data_Get_Struct(self, RowHandle, row);
233
- number = TYPE(index) == T_FIXNUM ? FIX2INT(index) : NUM2INT(index);
234
- if(number >= 0 && number < row->size) {
235
- name = rb_str_new2(row->columns[number].name);
236
- }
237
-
238
- return(name);
186
+ return rb_ivar_get(getMetadata(getColumns(self), index), AT_NAME_ID);
239
187
  }
240
188
 
241
189
 
@@ -250,17 +198,7 @@ static VALUE getColumnName(VALUE self, VALUE index) {
250
198
  *
251
199
  */
252
200
  static VALUE getColumnAlias(VALUE self, VALUE index) {
253
- VALUE alias = Qnil;
254
- RowHandle *row = NULL;
255
- int number = 0;
256
-
257
- Data_Get_Struct(self, RowHandle, row);
258
- number = TYPE(index) == T_FIXNUM ? FIX2INT(index) : NUM2INT(index);
259
- if(number >= 0 && number < row->size) {
260
- alias = rb_str_new2(row->columns[number].alias);
261
- }
262
-
263
- return(alias);
201
+ return rb_ivar_get(getMetadata(getColumns(self), index), AT_ALIAS_ID);
264
202
  }
265
203
 
266
204
 
@@ -276,41 +214,17 @@ static VALUE getColumnAlias(VALUE self, VALUE index) {
276
214
  *
277
215
  */
278
216
  static VALUE getColumnValue(VALUE self, VALUE index) {
279
- VALUE value = Qnil;
280
- RowHandle *row = NULL;
217
+ VALUE fld;
281
218
 
282
- Data_Get_Struct(self, RowHandle, row);
283
219
  if(TYPE(index) == T_STRING) {
284
- char name[32];
285
- int i,
286
- done = 0;
287
- VALUE flag = getFireRubySetting("ALIAS_KEYS");
288
-
289
- strcpy(name, StringValuePtr(index));
290
- for(i = 0; i < row->size && done == 0; i++) {
291
- int match;
292
-
293
- /* Check whether its column name or column alias to compare on. */
294
- if(flag == Qtrue) {
295
- match = strcmp(name, row->columns[i].alias);
296
- } else {
297
- match = strcmp(name, row->columns[i].name);
298
- }
299
-
300
- if(match == 0) {
301
- value = row->columns[i].value;
302
- done = 1;
303
- }
304
- }
220
+ fld = metadataScan(self, index, AT_KEY_ID);
305
221
  } else {
306
- int number = TYPE(index) == T_FIXNUM ? FIX2INT(index) : NUM2INT(index);
307
-
308
- if(number >= 0 && number < row->size) {
309
- value = row->columns[number].value;
310
- }
222
+ fld = getColumn(getColumns(self), index);
311
223
  }
312
-
313
- return(value);
224
+ if(Qnil == fld) {
225
+ return(Qnil);
226
+ }
227
+ return rb_ivar_get(fld, AT_VALUE_ID);
314
228
  }
315
229
 
316
230
 
@@ -328,22 +242,10 @@ VALUE eachColumn(VALUE self) {
328
242
  VALUE result = Qnil;
329
243
 
330
244
  if(rb_block_given_p()) {
331
- RowHandle *row = NULL;
332
- int i;
333
- VALUE flag = getFireRubySetting("ALIAS_KEYS");
334
-
335
- Data_Get_Struct(self, RowHandle, row);
336
- for(i = 0; i < row->size; i++) {
337
- VALUE parameters = rb_ary_new();
338
-
339
- /* Decide whether we're keying on column name or alias. */
340
- if(flag == Qtrue) {
341
- rb_ary_push(parameters, rb_str_new2(row->columns[i].alias));
342
- } else {
343
- rb_ary_push(parameters, rb_str_new2(row->columns[i].name));
344
- }
345
- rb_ary_push(parameters, row->columns[i].value);
346
- result = rb_yield(parameters);
245
+ long i;
246
+ VALUE columns = getColumns(self);
247
+ for(i = 0; i < RARRAY_LEN(columns); i++) {
248
+ result = rb_yield(keyValuePair(rb_ary_entry(columns, i)));
347
249
  }
348
250
  }
349
251
 
@@ -366,17 +268,10 @@ VALUE eachColumnKey(VALUE self) {
366
268
  VALUE result = Qnil;
367
269
 
368
270
  if(rb_block_given_p()) {
369
- RowHandle *row = NULL;
370
- int i;
371
- VALUE flag = getFireRubySetting("ALIAS_KEYS");
372
-
373
- Data_Get_Struct(self, RowHandle, row);
374
- for(i = 0; i < row->size; i++) {
375
- if(flag == Qtrue) {
376
- result = rb_yield(rb_str_new2(row->columns[i].alias));
377
- } else {
378
- result = rb_yield(rb_str_new2(row->columns[i].name));
379
- }
271
+ long i;
272
+ VALUE columns = getColumns(self);
273
+ for(i = 0; i < RARRAY_LEN(columns); i++) {
274
+ result = rb_yield(columnKey(rb_ary_entry(columns, i)));
380
275
  }
381
276
  }
382
277
 
@@ -398,12 +293,10 @@ VALUE eachColumnValue(VALUE self) {
398
293
  VALUE result = Qnil;
399
294
 
400
295
  if(rb_block_given_p()) {
401
- RowHandle *row = NULL;
402
- int i;
403
-
404
- Data_Get_Struct(self, RowHandle, row);
405
- for(i = 0; i < row->size; i++) {
406
- result = rb_yield(row->columns[i].value);
296
+ long i;
297
+ VALUE columns = getColumns(self);
298
+ for(i = 0; i < RARRAY_LEN(columns); i++) {
299
+ result = rb_yield(rb_ivar_get(rb_ary_entry(columns, i), AT_VALUE_ID));
407
300
  }
408
301
  }
409
302
 
@@ -460,30 +353,10 @@ VALUE fetchRowValue(int size, VALUE *parameters, VALUE self) {
460
353
  *
461
354
  */
462
355
  VALUE hasColumnKey(VALUE self, VALUE name) {
463
- VALUE result = Qfalse;
464
- RowHandle *row = NULL;
465
- char text[32];
466
- int i;
467
- VALUE flag = getFireRubySetting("ALIAS_KEYS");
468
-
469
- Data_Get_Struct(self, RowHandle, row);
470
- strcpy(text, StringValuePtr(name));
471
- for(i = 0; i < row->size && result == Qfalse; i++) {
472
- int match;
473
-
474
- /* Check whether key is column name or alias. */
475
- if(flag == Qtrue) {
476
- match = strcmp(text, row->columns[i].alias);
477
- } else {
478
- match = strcmp(text, row->columns[i].name);
479
- }
480
-
481
- if(match == 0) {
482
- result = Qtrue;
483
- }
356
+ if(Qnil == metadataScan(self, name, AT_KEY_ID)) {
357
+ return Qfalse;
484
358
  }
485
-
486
- return(result);
359
+ return Qtrue;
487
360
  }
488
361
 
489
362
 
@@ -499,20 +372,10 @@ VALUE hasColumnKey(VALUE self, VALUE name) {
499
372
  *
500
373
  */
501
374
  VALUE hasColumnName(VALUE self, VALUE name) {
502
- VALUE result = Qfalse;
503
- RowHandle *row = NULL;
504
- char text[32];
505
- int i;
506
-
507
- Data_Get_Struct(self, RowHandle, row);
508
- strcpy(text, StringValuePtr(name));
509
- for(i = 0; i < row->size && result == Qfalse; i++) {
510
- if(strcmp(text, row->columns[i].name) == 0) {
511
- result = Qtrue;
512
- }
375
+ if(Qnil == metadataScan(self, name, AT_NAME_ID)) {
376
+ return Qfalse;
513
377
  }
514
-
515
- return(result);
378
+ return Qtrue;
516
379
  }
517
380
 
518
381
 
@@ -528,20 +391,10 @@ VALUE hasColumnName(VALUE self, VALUE name) {
528
391
  *
529
392
  */
530
393
  VALUE hasColumnAlias(VALUE self, VALUE name) {
531
- VALUE result = Qfalse;
532
- RowHandle *row = NULL;
533
- char text[32];
534
- int i;
535
-
536
- Data_Get_Struct(self, RowHandle, row);
537
- strcpy(text, StringValuePtr(name));
538
- for(i = 0; i < row->size && result == Qfalse; i++) {
539
- if(strcmp(text, row->columns[i].alias) == 0) {
540
- result = Qtrue;
541
- }
394
+ if(Qnil == metadataScan(self, name, AT_ALIAS_ID)) {
395
+ return Qfalse;
542
396
  }
543
-
544
- return(result);
397
+ return Qtrue;
545
398
  }
546
399
 
547
400
 
@@ -555,19 +408,16 @@ VALUE hasColumnAlias(VALUE self, VALUE name) {
555
408
  *
556
409
  */
557
410
  VALUE hasColumnValue(VALUE self, VALUE value) {
558
- VALUE result = Qfalse;
559
- RowHandle *row = NULL;
560
- int i;
561
-
562
- Data_Get_Struct(self, RowHandle, row);
563
- for(i = 0; i < row->size && result == Qfalse; i++) {
564
- result = rb_funcall(row->columns[i].value, rb_intern("eql?"), 1, value);
411
+ long i;
412
+ VALUE columns = getColumns(self);
413
+ for(i = 0; i < RARRAY_LEN(columns); i++) {
414
+ if(Qtrue == rb_funcall(rb_ivar_get(rb_ary_entry(columns, i), AT_VALUE_ID), EQL_ID, 1, value)) {
415
+ return(Qtrue);
416
+ }
565
417
  }
566
-
567
- return(result);
418
+ return(Qfalse);
568
419
  }
569
420
 
570
-
571
421
  /**
572
422
  * This function fetches a list of column index keys for a Row object. What the
573
423
  * keys are depends on the library settings, but they will either be the column
@@ -579,16 +429,7 @@ VALUE hasColumnValue(VALUE self, VALUE value) {
579
429
  *
580
430
  */
581
431
  VALUE getColumnKeys(VALUE self) {
582
- VALUE flag = getFireRubySetting("ALIAS_KEYS"),
583
- keys = Qnil;
584
-
585
- if(flag == Qtrue) {
586
- keys = getColumnAliases(self);
587
- } else {
588
- keys = getColumnNames(self);
589
- }
590
-
591
- return(keys);
432
+ return rowCollect(self, AT_KEY_ID, 1);
592
433
  }
593
434
 
594
435
 
@@ -601,16 +442,7 @@ VALUE getColumnKeys(VALUE self) {
601
442
  *
602
443
  */
603
444
  VALUE getColumnNames(VALUE self) {
604
- VALUE result = rb_ary_new();
605
- RowHandle *row = NULL;
606
- int i;
607
-
608
- Data_Get_Struct(self, RowHandle, row);
609
- for(i = 0; i < row->size; i++) {
610
- rb_ary_push(result, rb_str_new2(row->columns[i].name));
611
- }
612
-
613
- return(result);
445
+ return rowCollect(self, AT_NAME_ID, 1);
614
446
  }
615
447
 
616
448
 
@@ -623,16 +455,7 @@ VALUE getColumnNames(VALUE self) {
623
455
  *
624
456
  */
625
457
  VALUE getColumnAliases(VALUE self) {
626
- VALUE result = rb_ary_new();
627
- RowHandle *row = NULL;
628
- int i;
629
-
630
- Data_Get_Struct(self, RowHandle, row);
631
- for(i = 0; i < row->size; i++) {
632
- rb_ary_push(result, rb_str_new2(row->columns[i].alias));
633
- }
634
-
635
- return(result);
458
+ return rowCollect(self, AT_ALIAS_ID, 1);
636
459
  }
637
460
 
638
461
 
@@ -645,16 +468,7 @@ VALUE getColumnAliases(VALUE self) {
645
468
  *
646
469
  */
647
470
  VALUE getColumnValues(VALUE self) {
648
- VALUE result = rb_ary_new();
649
- RowHandle *row = NULL;
650
- int i;
651
-
652
- Data_Get_Struct(self, RowHandle, row);
653
- for(i = 0; i < row->size; i++) {
654
- rb_ary_push(result, row->columns[i].value);
655
- }
656
-
657
- return(result);
471
+ return rowCollect(self, AT_VALUE_ID, 0);
658
472
  }
659
473
 
660
474
 
@@ -668,27 +482,8 @@ VALUE getColumnValues(VALUE self) {
668
482
  *
669
483
  */
670
484
  VALUE getColumnBaseType(VALUE self, VALUE index) {
671
- VALUE result = Qnil;
672
-
673
- if(TYPE(index) == T_FIXNUM) {
674
- RowHandle *row = NULL;
675
-
676
- Data_Get_Struct(self, RowHandle, row);
677
- if(row != NULL) {
678
- int offset = FIX2INT(index);
679
-
680
- /* Correct negative index values. */
681
- if(offset < 0) {
682
- offset = row->size + offset;
683
- }
684
-
685
- if(offset >= 0 && offset < row->size) {
686
- result = row->columns[offset].type;
687
- }
688
- }
689
- }
690
-
691
- return(result);
485
+ VALUE columns = getColumns(self);
486
+ return rb_ivar_get(getMetadata(columns, checkRowOffset(columns, index)), AT_TYPE_ID);
692
487
  }
693
488
 
694
489
  /**
@@ -703,27 +498,8 @@ VALUE getColumnBaseType(VALUE self, VALUE index) {
703
498
  *
704
499
  */
705
500
  static VALUE getColumnScale(VALUE self, VALUE index) {
706
- VALUE result = Qnil;
707
-
708
- if(TYPE(index) == T_FIXNUM) {
709
- RowHandle *row = NULL;
710
-
711
- Data_Get_Struct(self, RowHandle, row);
712
- if(row != NULL) {
713
- int offset = FIX2INT(index);
714
-
715
- /* Correct negative index values. */
716
- if(offset < 0) {
717
- offset = row->size + offset;
718
- }
719
-
720
- if(offset >= 0 && offset < row->size) {
721
- result = row->columns[offset].scale;
722
- }
723
- }
724
- }
725
-
726
- return(result);
501
+ VALUE columns = getColumns(self);
502
+ return rb_ivar_get(getMetadata(columns, checkRowOffset(columns, index)), AT_SCALE_ID);
727
503
  }
728
504
 
729
505
 
@@ -737,33 +513,21 @@ static VALUE getColumnScale(VALUE self, VALUE index) {
737
513
  *
738
514
  */
739
515
  VALUE selectRowEntries(VALUE self) {
740
- VALUE result = Qnil,
741
- flag = getFireRubySetting("ALIAS_KEYS");
742
- RowHandle *row = NULL;
743
- int i;
516
+ long i;
517
+ VALUE result = rb_ary_new(),
518
+ columns = getColumns(self);
744
519
 
745
520
  if(!rb_block_given_p()) {
746
521
  rb_raise(rb_eStandardError, "No block specified in call to Row#select.");
747
522
  }
748
523
 
749
- result = rb_ary_new();
750
- Data_Get_Struct(self, RowHandle, row);
751
- for(i = 0; i < row->size; i++) {
752
- VALUE parameters = rb_ary_new();
753
-
754
- /* Check whether we're keying on column name or alias. */
755
- if(flag == Qtrue) {
756
- rb_ary_push(parameters, rb_str_new2(row->columns[i].alias));
757
- } else {
758
- rb_ary_push(parameters, rb_str_new2(row->columns[i].name));
759
- }
760
- rb_ary_push(parameters, row->columns[i].value);
524
+ for(i = 0; i < RARRAY_LEN(columns); i++) {
525
+ VALUE parameters = keyValuePair(rb_ary_entry(columns, i));
761
526
  if(rb_yield(parameters) == Qtrue) {
762
527
  rb_ary_push(result, parameters);
763
528
  }
764
529
  }
765
530
 
766
-
767
531
  return(result);
768
532
  }
769
533
 
@@ -777,23 +541,12 @@ VALUE selectRowEntries(VALUE self) {
777
541
  *
778
542
  */
779
543
  VALUE rowToArray(VALUE self) {
544
+ long i;
780
545
  VALUE result = rb_ary_new(),
781
- flag = getFireRubySetting("ALIAS_KEYS");
782
- RowHandle *row = NULL;
783
- int i;
546
+ columns = getColumns(self);
784
547
 
785
- Data_Get_Struct(self, RowHandle, row);
786
- for(i = 0; i < row->size; i++) {
787
- VALUE parameters = rb_ary_new();
788
-
789
- /* Check whether we're keying on column name or alias. */
790
- if(flag == Qtrue) {
791
- rb_ary_push(parameters, rb_str_new2(row->columns[i].alias));
792
- } else {
793
- rb_ary_push(parameters, rb_str_new2(row->columns[i].name));
794
- }
795
- rb_ary_push(parameters, row->columns[i].value);
796
- rb_ary_push(result, parameters);
548
+ for(i = 0; i < RARRAY_LEN(columns); i++) {
549
+ rb_ary_push(result, keyValuePair(rb_ary_entry(columns, i)));
797
550
  }
798
551
 
799
552
  return(result);
@@ -809,22 +562,13 @@ VALUE rowToArray(VALUE self) {
809
562
  *
810
563
  */
811
564
  VALUE rowToHash(VALUE self) {
565
+ long i;
812
566
  VALUE result = rb_hash_new(),
813
- flag = getFireRubySetting("ALIAS_KEYS");
814
- RowHandle *row = NULL;
815
- int i;
567
+ columns = getColumns(self);
816
568
 
817
- Data_Get_Struct(self, RowHandle, row);
818
- for(i = 0; i < row->size; i++) {
819
- VALUE key = Qnil;
820
-
821
- /* Check if we're keying on column name or alias. */
822
- if(flag == Qtrue) {
823
- key = rb_str_new2(row->columns[i].alias);
824
- } else {
825
- key = rb_str_new2(row->columns[i].name);
826
- }
827
- rb_hash_aset(result, key, row->columns[i].value);
569
+ for(i = 0; i < RARRAY_LEN(columns); i++) {
570
+ VALUE fld = rb_ary_entry(columns, i);
571
+ rb_hash_aset(result, columnKey(fld), rb_ivar_get(fld, AT_VALUE_ID));
828
572
  }
829
573
 
830
574
  return(result);
@@ -842,8 +586,8 @@ VALUE rowToHash(VALUE self) {
842
586
  *
843
587
  */
844
588
  VALUE rowValuesAt(int size, VALUE *keys, VALUE self) {
845
- VALUE result = rb_ary_new();
846
589
  int i;
590
+ VALUE result = rb_ary_new();
847
591
 
848
592
  for(i = 0; i < size; i++) {
849
593
  rb_ary_push(result, getColumnValue(self, keys[i]));
@@ -863,10 +607,12 @@ VALUE rowValuesAt(int size, VALUE *keys, VALUE self) {
863
607
  * @return A reference to the Row object created.
864
608
  *
865
609
  */
866
- VALUE rb_row_new(VALUE results, VALUE data, VALUE number) {
867
- VALUE row = allocateRow(cRow);
610
+ VALUE rb_row_new(VALUE results, VALUE number) {
611
+ VALUE row = rb_funcall(cRow, NEW_ID, 2, results, number);
612
+
613
+ RB_GC_GUARD(row);
868
614
 
869
- initializeRow(row, results, data, number);
615
+ initializeRow(row, results, number);
870
616
 
871
617
  return(row);
872
618
  }
@@ -881,10 +627,23 @@ VALUE rb_row_new(VALUE results, VALUE data, VALUE number) {
881
627
  *
882
628
  */
883
629
  void Init_Row(VALUE module) {
630
+ Init_TypeMap();
631
+ EQL_ID = rb_intern("eql?");
632
+ FETCH_ID = rb_intern("fetch");
633
+ AT_NAME_ID = rb_intern("@name");
634
+ AT_ALIAS_ID = rb_intern("@alias");
635
+ AT_KEY_ID = rb_intern("@key");
636
+ AT_SCALE_ID = rb_intern("@scale");
637
+ AT_COLUMNS_ID = rb_intern("@columns");
638
+ AT_NUMBER_ID = rb_intern("@number");
639
+ AT_VALUE_ID = rb_intern("@value");
640
+ AT_TYPE_ID = rb_intern("@type");
641
+ NEW_ID = rb_intern("new");
642
+ AT_COLUMN_ID = rb_intern("@column");
643
+
884
644
  cRow = rb_define_class_under(module, "Row", rb_cObject);
885
- rb_define_alloc_func(cRow, allocateRow);
886
645
  rb_include_module(cRow, rb_mEnumerable);
887
- rb_define_method(cRow, "initialize", initializeRow, 3);
646
+ rb_define_method(cRow, "initialize", initializeRow, 2);
888
647
  rb_define_method(cRow, "number", getRowNumber, 0);
889
648
  rb_define_method(cRow, "column_count", columnsInRow, 0);
890
649
  rb_define_method(cRow, "column_name", getColumnName, 1);