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/ext/Row.h CHANGED
@@ -31,23 +31,8 @@
31
31
  #define RUBY_H_INCLUDED
32
32
  #endif
33
33
 
34
- /* Type definitions. */
35
- typedef struct {
36
- char name[32],
37
- alias[32];
38
- VALUE value,
39
- type,
40
- scale;
41
- } ColumnHandle;
42
-
43
- typedef struct {
44
- unsigned int size,
45
- number;
46
- ColumnHandle *columns;
47
- } RowHandle;
48
-
49
34
  /* Function prototypes. */
50
35
  void Init_Row(VALUE);
51
- VALUE rb_row_new(VALUE, VALUE, VALUE);
36
+ VALUE rb_row_new(VALUE, VALUE);
52
37
 
53
38
  #endif // FIRERUBY_ROW_H
@@ -57,14 +57,18 @@ void populateDateField(VALUE, XSQLVAR *);
57
57
  void populateTimeField(VALUE, XSQLVAR *);
58
58
  void populateTimestampField(VALUE, XSQLVAR *);
59
59
 
60
+ ID NEW_ID, TO_F_ID, ROUND_ID, ASTERISK_ID, CLASS_ID, TRANSACTION_ID,
61
+ CONNECTION_ID, STATEMENT_ID, NAME_ID, AT_VALUE_ID, AT_TYPE_ID,
62
+ AT_COLUMN_ID;
63
+
60
64
  long long sql_scale(VALUE value, XSQLVAR *field) {
61
- value = rb_funcall(value, rb_intern("to_f"), 0);
65
+ value = rb_funcall(value, TO_F_ID, 0);
62
66
  if(field->sqlscale) {
63
67
  // this requires special care - decimal point shift can cause type overflow
64
68
  // the easyest way is to use ruby arithmetics (although it's not the fastes)
65
- value = rb_funcall(value, rb_intern("*"), 1, LONG2NUM((long)pow(10, abs(field->sqlscale))));
69
+ value = rb_funcall(value, ASTERISK_ID, 1, LONG2NUM((long)pow(10, abs(field->sqlscale))));
66
70
  }
67
- return NUM2LL(rb_funcall(value, rb_intern("round"), 0));
71
+ return NUM2LL(rb_funcall(value, ROUND_ID, 0));
68
72
  }
69
73
 
70
74
  VALUE sql_unscale(VALUE value, XSQLVAR *field) {
@@ -72,7 +76,7 @@ VALUE sql_unscale(VALUE value, XSQLVAR *field) {
72
76
  return value;
73
77
  }
74
78
  return rb_float_new(
75
- NUM2DBL(rb_funcall(value, rb_intern("to_f"), 0)) / pow(10, abs(field->sqlscale))
79
+ NUM2DBL(rb_funcall(value, TO_F_ID, 0)) / pow(10, abs(field->sqlscale))
76
80
  );
77
81
  }
78
82
 
@@ -88,10 +92,11 @@ VALUE sql_unscale(VALUE value, XSQLVAR *field) {
88
92
  * the field type referenced.
89
93
  *
90
94
  */
91
- VALUE toValue(XSQLVAR *entry,
95
+ VALUE toColumn(XSQLVAR *entry,
96
+ VALUE metadata,
92
97
  VALUE connection,
93
98
  VALUE transaction) {
94
- VALUE value = rb_ary_new();
99
+ VALUE column, value = Qnil;
95
100
 
96
101
  /* Check for NULL values. */
97
102
  if(!((entry->sqltype & 1) && (*entry->sqlind < 0))) {
@@ -107,10 +112,6 @@ VALUE toValue(XSQLVAR *entry,
107
112
  working = Qnil;
108
113
 
109
114
  switch(type) {
110
- case SQL_ARRAY: /* Type: ARRAY */
111
- /* TO BE DONE! */
112
- break;
113
-
114
115
  case SQL_BLOB: /* Type: BLOB */
115
116
  memset(column, 0, 256);
116
117
  memset(table, 0, 256);
@@ -119,8 +120,7 @@ VALUE toValue(XSQLVAR *entry,
119
120
  blob = openBlob(entry, column, table, connection,
120
121
  transaction);
121
122
  working = Data_Wrap_Struct(cBlob, NULL, blobFree, blob);
122
- rb_ary_push(value, initializeBlob(working, connection));
123
- rb_ary_push(value, getColumnType(entry));
123
+ value = initializeBlob(working, connection);
124
124
  break;
125
125
 
126
126
  case SQL_TYPE_DATE: /* Type: DATE */
@@ -130,41 +130,34 @@ VALUE toValue(XSQLVAR *entry,
130
130
  datetime.tm_min = 0;
131
131
  datetime.tm_hour = 0;
132
132
  if(setting == Qtrue) {
133
- rb_ary_push(value, createDate(&datetime));
133
+ value = createDate(&datetime);
134
134
  } else {
135
- rb_ary_push(value, createSafeTime(&datetime));
135
+ value = createSafeTime(&datetime);
136
136
  }
137
- rb_ary_push(value, getColumnType(entry));
138
137
  break;
139
138
 
140
139
  case SQL_DOUBLE: /* Type: DOUBLE PRECISION, DECIMAL, NUMERIC */
141
- rb_ary_push(value, rb_float_new(*((double *)entry->sqldata)));
142
- rb_ary_push(value, getColumnType(entry));
140
+ value = rb_float_new(*((double *)entry->sqldata));
143
141
  break;
144
142
 
145
143
  case SQL_FLOAT: /* Type: FLOAT */
146
- rb_ary_push(value, rb_float_new(*((float *)entry->sqldata)));
147
- rb_ary_push(value, getColumnType(entry));
144
+ value = rb_float_new(*((float *)entry->sqldata));
148
145
  break;
149
146
 
150
147
  case SQL_INT64: /* Type: DECIMAL, NUMERIC */
151
- rb_ary_push(value, sql_unscale(LL2NUM(*((long long *)entry->sqldata)), entry));
152
- rb_ary_push(value, getColumnType(entry));
148
+ value = sql_unscale(LL2NUM(*((long long *)entry->sqldata)), entry);
153
149
  break;
154
150
 
155
151
  case SQL_LONG: /* Type: INTEGER, DECIMAL, NUMERIC */
156
- rb_ary_push(value, sql_unscale(LONG2NUM(*((int32_t *)entry->sqldata)), entry));
157
- rb_ary_push(value, getColumnType(entry));
152
+ value = sql_unscale(LONG2NUM(*((int32_t *)entry->sqldata)), entry);
158
153
  break;
159
154
 
160
155
  case SQL_SHORT: /* Type: SMALLINT, DECIMAL, NUMERIC */
161
- rb_ary_push(value, sql_unscale(INT2NUM(*((short *)entry->sqldata)), entry));
162
- rb_ary_push(value, getColumnType(entry));
156
+ value = sql_unscale(INT2NUM(*((short *)entry->sqldata)), entry);
163
157
  break;
164
158
 
165
159
  case SQL_TEXT: /* Type: CHAR */
166
- rb_ary_push(value, rfbstr(connection, entry->sqlsubtype, entry->sqldata, entry->sqllen));
167
- rb_ary_push(value, getColumnType(entry));
160
+ value = rfbstr(connection, entry->sqlsubtype, entry->sqldata, entry->sqllen);
168
161
  break;
169
162
 
170
163
  case SQL_TYPE_TIME: /* Type: TIME */
@@ -172,32 +165,25 @@ VALUE toValue(XSQLVAR *entry,
172
165
  datetime.tm_year = 70;
173
166
  datetime.tm_mon = 0;
174
167
  datetime.tm_mday = 1;
175
- rb_ary_push(value, createSafeTime(&datetime));
176
- rb_ary_push(value, getColumnType(entry));
168
+ value = createSafeTime(&datetime);
177
169
  break;
178
170
 
179
171
  case SQL_TIMESTAMP: /* Type: TIMESTAMP */
180
172
  isc_decode_timestamp((ISC_TIMESTAMP *)entry->sqldata, &datetime);
181
- rb_ary_push(value, createSafeTime(&datetime));
182
- rb_ary_push(value, getColumnType(entry));
173
+ value = createSafeTime(&datetime);
183
174
  break;
184
175
 
185
176
  case SQL_VARYING:
186
177
  memcpy(&length, entry->sqldata, 2);
187
- rb_ary_push(value, rfbstr(connection, entry->sqlsubtype, &entry->sqldata[2], length));
188
- rb_ary_push(value, getColumnType(entry));
178
+ value = rfbstr(connection, entry->sqlsubtype, &entry->sqldata[2], length);
189
179
  break;
190
-
191
- default:
192
- rb_ary_push(value, Qnil);
193
- rb_ary_push(value, Qnil);
194
180
  } /* End of switch. */
195
- } else {
196
- rb_ary_push(value, Qnil);
197
- rb_ary_push(value, getColumnType(entry));
198
181
  }
199
182
 
200
- return(value);
183
+ column = rb_funcall(rb_cObject, NEW_ID, 0);
184
+ rb_ivar_set(column, AT_COLUMN_ID, metadata);
185
+ rb_ivar_set(column, AT_VALUE_ID, value);
186
+ return(column);
201
187
  }
202
188
 
203
189
 
@@ -211,20 +197,21 @@ VALUE toValue(XSQLVAR *entry,
211
197
  * @return A reference to the array containing the row data from the XSQLDA.
212
198
  *
213
199
  */
214
- VALUE toArray(VALUE results) {
215
- VALUE array = rb_ary_new(),
216
- transaction = rb_funcall(results, rb_intern("transaction"), 0),
217
- connection = rb_funcall(results, rb_intern("connection"), 0);
200
+ VALUE toRowColumns(VALUE results) {
201
+ VALUE array, transaction, connection, columns;
218
202
  XSQLVAR *entry = NULL;
219
203
  StatementHandle *hStatement = NULL;
220
204
  int i;
221
205
 
222
- Data_Get_Struct(rb_funcall(results, rb_intern("statement"), 0), StatementHandle, hStatement);
206
+ Data_Get_Struct(rb_funcall(results, STATEMENT_ID, 0), StatementHandle, hStatement);
207
+ transaction = rb_funcall(results, TRANSACTION_ID, 0);
208
+ connection = rb_funcall(results, CONNECTION_ID, 0);
209
+ array = rb_ary_new2(hStatement->output->sqln);
210
+
223
211
  entry = hStatement->output->sqlvar;
212
+ columns = getResultsColumns(results);
224
213
  for(i = 0; i < hStatement->output->sqln; i++, entry++) {
225
- VALUE value = toValue(entry, connection, transaction);
226
-
227
- rb_ary_push(array, value);
214
+ rb_ary_store(array, i, toColumn(entry, rb_ary_entry(columns, i), connection, transaction));
228
215
  }
229
216
 
230
217
  return(array);
@@ -246,14 +233,12 @@ VALUE toArray(VALUE results) {
246
233
  *
247
234
  */
248
235
  void setParameters(XSQLDA *parameters, VALUE array, VALUE transaction, VALUE connection) {
249
- VALUE value;
250
- int index,
251
- size;
236
+ long index,
237
+ size;
252
238
  XSQLVAR *parameter = NULL;
253
239
 
254
240
  /* Check that sufficient parameters have been provided. */
255
- value = rb_funcall(array, rb_intern("size"), 0);
256
- size = (TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value));
241
+ size = RARRAY_LEN(array);
257
242
  parameter = parameters->sqlvar;
258
243
  if(size != parameters->sqld) {
259
244
  rb_raise(rb_eException,
@@ -266,14 +251,14 @@ void setParameters(XSQLDA *parameters, VALUE array, VALUE transaction, VALUE con
266
251
  /* Populate the parameters from the array's contents. */
267
252
  for(index = 0; index < size; index++, parameter++) {
268
253
  int type = (parameter->sqltype & ~1);
254
+ VALUE value = rb_ary_entry(array, index);
269
255
 
270
- value = rb_ary_entry(array, index);
271
256
  /* Check for nils to indicate null values. */
272
257
  if(value != Qnil) {
273
- VALUE name = rb_funcall(value, rb_intern("class"), 0);
258
+ VALUE name = rb_funcall(value, CLASS_ID, 0);
274
259
 
275
260
  *parameter->sqlind = 0;
276
- name = rb_funcall(name, rb_intern("name"), 0);
261
+ name = rb_funcall(name, NAME_ID, 0);
277
262
  switch(type) {
278
263
  case SQL_ARRAY: /* Type: ARRAY */
279
264
  /* TO BE DONE! */
@@ -367,7 +352,7 @@ VALUE createDate(const struct tm *date) {
367
352
  arguments[2] = INT2FIX(date->tm_mday);
368
353
 
369
354
  /* Create the class instance. */
370
- result = rb_funcall2(klass, rb_intern("new"), 3, arguments);
355
+ result = rb_funcall2(klass, NEW_ID, 3, arguments);
371
356
  }
372
357
 
373
358
 
@@ -412,7 +397,7 @@ VALUE createDateTime(VALUE dt) {
412
397
  arguments[6] = rb_funcall(rb_funcall(klass, rb_intern("now"), 0), rb_intern("offset"), 0);
413
398
 
414
399
  /* Create the class instance. */
415
- result = rb_funcall2(klass, rb_intern("new"), 7, arguments);
400
+ result = rb_funcall2(klass, NEW_ID, 7, arguments);
416
401
  }
417
402
 
418
403
  return(result);
@@ -522,7 +507,7 @@ VALUE getModule(const char *name) {
522
507
  VALUE module = getConstant(name, Qnil);
523
508
 
524
509
  if(module != Qnil) {
525
- VALUE type = rb_funcall(module, rb_intern("class"), 0);
510
+ VALUE type = rb_funcall(module, CLASS_ID, 0);
526
511
 
527
512
  if(type != rb_cModule) {
528
513
  module = Qnil;
@@ -545,7 +530,7 @@ VALUE getClass(const char *name) {
545
530
  VALUE klass = getConstant(name, Qnil);
546
531
 
547
532
  if(klass != Qnil) {
548
- VALUE type = rb_funcall(klass, rb_intern("class"), 0);
533
+ VALUE type = rb_funcall(klass, CLASS_ID, 0);
549
534
 
550
535
  if(type != rb_cClass) {
551
536
  klass = Qnil;
@@ -570,7 +555,7 @@ VALUE getModuleInModule(const char *name, VALUE owner) {
570
555
  VALUE module = getConstant(name, owner);
571
556
 
572
557
  if(module != Qnil) {
573
- VALUE type = rb_funcall(module, rb_intern("class"), 0);
558
+ VALUE type = rb_funcall(module, CLASS_ID, 0);
574
559
 
575
560
  if(type != rb_cModule) {
576
561
  module = Qnil;
@@ -595,7 +580,7 @@ VALUE getClassInModule(const char *name, VALUE owner) {
595
580
  VALUE klass = getConstant(name, owner);
596
581
 
597
582
  if(klass != Qnil) {
598
- VALUE type = rb_funcall(klass, rb_intern("class"), 0);
583
+ VALUE type = rb_funcall(klass, CLASS_ID, 0);
599
584
 
600
585
  if(type != rb_cClass) {
601
586
  klass = Qnil;
@@ -617,7 +602,7 @@ VALUE getClassInModule(const char *name, VALUE owner) {
617
602
  */
618
603
  VALUE toDateTime(VALUE value) {
619
604
  VALUE result,
620
- klass = rb_funcall(value, rb_intern("class"), 0),
605
+ klass = rb_funcall(value, CLASS_ID, 0),
621
606
  date_time_class = getClass("DateTime");
622
607
 
623
608
  if((klass == rb_cTime) || (klass == date_time_class)) {
@@ -813,7 +798,7 @@ void populateDoubleField(VALUE value, XSQLVAR *field) {
813
798
 
814
799
  if(TYPE(value) != T_FLOAT) {
815
800
  if(rb_obj_is_kind_of(value, rb_cNumeric) || TYPE(value) == T_STRING) {
816
- actual = rb_funcall(value, rb_intern("to_f"), 0);
801
+ actual = rb_funcall(value, TO_F_ID, 0);
817
802
  } else {
818
803
  rb_fireruby_raise(NULL,
819
804
  "Error converting input parameter to double.");
@@ -840,7 +825,7 @@ void populateFloatField(VALUE value, XSQLVAR *field) {
840
825
 
841
826
  if(TYPE(value) != T_FLOAT) {
842
827
  if(rb_obj_is_kind_of(value, rb_cNumeric) || TYPE(value) == T_STRING) {
843
- actual = rb_funcall(value, rb_intern("to_f"), 0);
828
+ actual = rb_funcall(value, TO_F_ID, 0);
844
829
  } else {
845
830
  rb_fireruby_raise(NULL,
846
831
  "Error converting input parameter to double.");
@@ -981,3 +966,18 @@ void populateTimestampField(VALUE value, XSQLVAR *field) {
981
966
  isc_encode_timestamp(&datetime, (ISC_TIMESTAMP *)field->sqldata);
982
967
  field->sqltype = SQL_TIMESTAMP;
983
968
  }
969
+
970
+ void Init_TypeMap() {
971
+ NEW_ID = rb_intern("new");
972
+ TO_F_ID = rb_intern("to_f");
973
+ ROUND_ID = rb_intern("round");
974
+ ASTERISK_ID = rb_intern("*");
975
+ CLASS_ID = rb_intern("class");
976
+ CONNECTION_ID = rb_intern("connection");
977
+ TRANSACTION_ID = rb_intern("transaction");
978
+ STATEMENT_ID = rb_intern("statement");
979
+ NAME_ID = rb_intern("name");
980
+ AT_VALUE_ID = rb_intern("@value");
981
+ AT_TYPE_ID = rb_intern("@type");
982
+ AT_COLUMN_ID = rb_intern("@column");
983
+ }
@@ -40,6 +40,7 @@
40
40
  #endif
41
41
 
42
42
  /* Function prototypes. */
43
+ void Init_TypeMap();
43
44
  VALUE toArray(VALUE);
44
45
  void setParameters(XSQLDA *, VALUE, VALUE, VALUE);
45
46
  VALUE getModule(const char *);
Binary file
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rubyfb"
5
- s.version = "0.6.3"
5
+ s.version = "0.6.4"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["George Georgiev"]
9
- s.date = "2012-02-21"
9
+ s.date = "2012-03-23"
10
10
  s.description = "Firebird SQL access library"
11
11
  s.email = "georgiev@heatbs.com"
12
12
  s.extensions = ["ext/extconf.rb"]
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rubyfb", "--main", "README"]
17
17
  s.require_paths = ["lib", "ext"]
18
18
  s.rubyforge_project = "rubyfb"
19
- s.rubygems_version = "1.8.11"
19
+ s.rubygems_version = "1.8.20"
20
20
  s.summary = "Firebird SQL access library"
21
21
 
22
22
  if s.respond_to? :specification_version then
@@ -122,10 +122,10 @@ class KeyTest < Test::Unit::TestCase
122
122
  assert(array.include?(['COL03', 3]))
123
123
 
124
124
  hash = data.to_hash
125
- assert(hash.length == 3)
126
- assert(hash['COL01'] == 1)
127
- assert(hash['COL02'] == 'Two')
128
- assert(hash['COL03'] == 3)
125
+ assert_equal(3, hash.length)
126
+ assert_equal(1, hash['COL01'])
127
+ assert_equal('Two', hash['COL02'])
128
+ assert_equal(3, hash['COL03'])
129
129
 
130
130
  array = data.values_at('COL10', 'COL02', 'COL03')
131
131
  assert(array.size == 3)
@@ -20,20 +20,6 @@ class RowTest < Test::Unit::TestCase
20
20
  @connection = database.connect(DB_USER_NAME, DB_PASSWORD)
21
21
  @transaction = @connection.start_transaction
22
22
  @results = @connection.execute('SELECT * FROM RDB$FIELDS', @transaction)
23
- @empty = [[0, SQLType::INTEGER], [0, SQLType::INTEGER],
24
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
25
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
26
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
27
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
28
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
29
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
30
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
31
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
32
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
33
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
34
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
35
- [0, SQLType::INTEGER], [0, SQLType::INTEGER],
36
- [0, SQLType::INTEGER], [0, SQLType::INTEGER]]
37
23
 
38
24
  @connection.start_transaction do |tx|
39
25
  tx.execute('create table rowtest (COL01 integer, COL02 varchar(10), '\
@@ -68,17 +54,6 @@ class RowTest < Test::Unit::TestCase
68
54
  puts "#{self.class.name} finished." if TEST_LOGGING
69
55
  end
70
56
 
71
- def test01
72
- row = Row.new(@results, @empty, 100)
73
-
74
- assert(row.column_count == 28)
75
- assert(row.number == 100)
76
- assert(row.column_name(0) == 'RDB$FIELD_NAME')
77
- assert(row.column_alias(10) == 'RDB$FIELD_TYPE')
78
- assert(row[0] == 0)
79
- assert(row['RDB$FIELD_TYPE'] == 0)
80
- end
81
-
82
57
  def test02
83
58
  sql = 'select COL01 one, COL02 two, COL03 three from rowtest'
84
59
  rows = @connection.execute_immediate(sql)
@@ -86,7 +61,7 @@ class RowTest < Test::Unit::TestCase
86
61
 
87
62
  count = 0
88
63
  data.each do |name, value|
89
- assert(['ONE', 'TWO', 'THREE'].include?(name))
64
+ assert(['ONE', 'TWO', 'THREE'].include?(name), name)
90
65
  assert([1, 'Two', 3].include?(value))
91
66
  count += 1
92
67
  end
@@ -181,7 +156,7 @@ class RowTest < Test::Unit::TestCase
181
156
  results = @connection.execute_immediate('select * from all_types')
182
157
  row = results.fetch
183
158
 
184
- assert(row.get_base_type(0) == SQLType::BIGINT)
159
+ assert_equal(SQLType::BIGINT, row.get_base_type(0))
185
160
  assert(row.get_base_type(1) == SQLType::BLOB)
186
161
  assert(row.get_base_type(2) == SQLType::CHAR)
187
162
  assert(row.get_base_type(3) == SQLType::DATE)
@@ -214,4 +189,22 @@ class RowTest < Test::Unit::TestCase
214
189
  ensure
215
190
  results.close if results
216
191
  end
192
+
193
+ def test05
194
+ @connection.start_transaction do |tx|
195
+ tx.execute('create table rowtest2 (COL01 varchar(5000), COL02 varchar(5000), '\
196
+ 'COL03 integer)')
197
+ end
198
+ 1000.times do |i|
199
+ begin
200
+ st = @connection.create_statement("insert into rowtest2 values (?, ?, ?)")
201
+ st.exec(['a'*5000, 'b'*5000, i])
202
+ ensure
203
+ st.close
204
+ end
205
+ end
206
+ @connection.execute_immediate("select * from rowtest2") do |row|
207
+ puts "#{row}\n"
208
+ end
209
+ end
217
210
  end