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/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