rubyfb 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
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);