rubyfb 0.6.4 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,3 +1,17 @@
1
+ v0.6.7 ==
2
+ Add test to ensure row numbering scheme
3
+ Fix row numbering
4
+ Minor AR adapter improvement
5
+
6
+ v0.6.6 ==
7
+ Include Enumerable in Row And ResultSet
8
+ Update tests
9
+
10
+ v0.6.5 ==
11
+ Row: pure ruby implementation
12
+ ResultSet: pure ruby implementation
13
+ Use static vars fo rb_intern caches - this should fix os x linkage issues - https://github.com/georgiev/rubyfb/issues/11
14
+
1
15
  v0.6.4 ==
2
16
  Tyr to fix another Segmentation fault in Row class (GC integration issues)
3
17
 
data/Manifest CHANGED
@@ -28,10 +28,6 @@ ext/RemoveUser.c
28
28
  ext/RemoveUser.h
29
29
  ext/Restore.c
30
30
  ext/Restore.h
31
- ext/ResultSet.c
32
- ext/ResultSet.h
33
- ext/Row.c
34
- ext/Row.h
35
31
  ext/ServiceManager.c
36
32
  ext/ServiceManager.h
37
33
  ext/Services.c
@@ -48,17 +44,20 @@ ext/rfbsleep.h
48
44
  ext/rfbstr.c
49
45
  ext/rfbstr.h
50
46
  ext/uncrustify.cfg
51
- lib/Connection.rb
52
- lib/ProcedureCall.rb
53
- lib/SQLType.rb
54
47
  lib/active_record/connection_adapters/rubyfb_adapter.rb
55
48
  lib/arel/visitors/fb15/rubyfb.rb
56
49
  lib/arel/visitors/rubyfb.rb
50
+ lib/connection.rb
57
51
  lib/mkdoc
52
+ lib/procedure_call.rb
53
+ lib/result_set.rb
54
+ lib/row.rb
58
55
  lib/rubyfb.rb
59
56
  lib/rubyfb_lib.so
60
57
  lib/rubyfb_options.rb
58
+ lib/sql_type.rb
61
59
  lib/src.rb
60
+ lib/statement.rb
62
61
  mswin32fb/fbclient_mingw.def
63
62
  mswin32fb/fbclient_mingw.lib
64
63
  mswin32fb/fbclient_ms.lib
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'echoe'
2
- e = Echoe.new('rubyfb', '0.6.4') do |p|
2
+ e = Echoe.new('rubyfb', '0.6.7') 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"
@@ -51,3 +51,77 @@ VALUE forbidObjectCopy(VALUE copy, VALUE original) {
51
51
 
52
52
  return(Qnil);
53
53
  }
54
+
55
+ /**
56
+ * This method fetches a Ruby constant definition. If the module specified to
57
+ * the function is nil then the top level is assume
58
+ *
59
+ * @param name The name of the constant to be retrieved.
60
+ * @param module A reference to the Ruby module that should contain the
61
+ * constant.
62
+ *
63
+ * @return A Ruby VALUE representing the constant.
64
+ *
65
+ */
66
+ static VALUE getConstant(const char *name, VALUE module) {
67
+ VALUE owner = module,
68
+ constants,
69
+ exists,
70
+ entry = Qnil,
71
+ symbol = ID2SYM(rb_intern(name));
72
+
73
+ /* Check that we've got somewhere to look. */
74
+ if(owner == Qnil) {
75
+ owner = rb_cModule;
76
+ }
77
+
78
+ constants = rb_funcall(owner, rb_intern("constants"), 0),
79
+ exists = rb_funcall(constants, rb_intern("include?"), 1, symbol);
80
+ if(exists == Qfalse) {
81
+ /* 1.8 style lookup */
82
+ exists = rb_funcall(constants, rb_intern("include?"), 1, rb_str_new2(name));
83
+ }
84
+ if(exists != Qfalse) {
85
+ entry = rb_funcall(owner, rb_intern("const_get"), 1, symbol);
86
+ }
87
+ return(entry);
88
+ }
89
+
90
+
91
+ /**
92
+ * This method fetches a Ruby class definition object based on a class name.
93
+ * The class is assumed to have been defined at the top level.
94
+ *
95
+ * @return A Ruby VALUE representing the requested class, or nil if the class
96
+ * could not be found.
97
+ *
98
+ */
99
+ VALUE getClass(const char *name) {
100
+ return getClassInModule(name, Qnil);
101
+ }
102
+
103
+
104
+ /**
105
+ * This function fetches a class from a specified module.
106
+ *
107
+ * @param name The name of the class to be retrieved.
108
+ * @param owner The module to search for the class in.
109
+ *
110
+ * @return A Ruby VALUE representing the requested module, or nil if it could
111
+ * not be located.
112
+ *
113
+ */
114
+ VALUE getClassInModule(const char *name, VALUE owner) {
115
+ VALUE klass = getConstant(name, owner);
116
+
117
+ if(klass != Qnil) {
118
+ VALUE type = rb_funcall(klass, rb_intern("class"), 0);
119
+
120
+ if(type != rb_cClass) {
121
+ klass = Qnil;
122
+ }
123
+ }
124
+
125
+ return(klass);
126
+ }
127
+
@@ -33,5 +33,7 @@
33
33
 
34
34
  /* Function prototypes. */
35
35
  VALUE forbidObjectCopy(VALUE, VALUE);
36
+ VALUE getClass(const char *);
37
+ VALUE getClassInModule(const char *, VALUE);
36
38
 
37
39
  #endif /* FIRERUBY_COMMON_H */
@@ -26,7 +26,6 @@
26
26
  /* Includes. */
27
27
  #include "Connection.h"
28
28
  #include "Database.h"
29
- #include "ResultSet.h"
30
29
  #include "Statement.h"
31
30
  #include "Transaction.h"
32
31
  #include "Common.h"
@@ -34,12 +34,10 @@
34
34
  #include "FireRubyException.h"
35
35
  #include "Generator.h"
36
36
  #include "RemoveUser.h"
37
- #include "ResultSet.h"
38
37
  #include "ServiceManager.h"
39
38
  #include "Statement.h"
40
39
  #include "Transaction.h"
41
40
  #include "Restore.h"
42
- #include "Row.h"
43
41
 
44
42
 
45
43
  /**
@@ -202,12 +200,11 @@ void Init_rubyfb_lib(void) {
202
200
  Init_Database(module);
203
201
  Init_Connection(module);
204
202
  Init_Transaction(module);
203
+ Init_TypeMap(module);
205
204
  Init_Statement(module);
206
- Init_ResultSet(module);
207
205
  Init_Generator(module);
208
206
  Init_FireRubyException(module);
209
207
  Init_Blob(module);
210
- Init_Row(module);
211
208
  Init_ServiceManager(module);
212
209
  Init_Backup(module);
213
210
  Init_AddUser(module);
@@ -26,7 +26,6 @@
26
26
  /* Includes. */
27
27
  #include "Generator.h"
28
28
  #include "Common.h"
29
- #include "ResultSet.h"
30
29
  #include "Statement.h"
31
30
  #include "Transaction.h"
32
31
  #include "DataArea.h"
@@ -30,7 +30,6 @@
30
30
  #include "Transaction.h"
31
31
  #include "DataArea.h"
32
32
  #include "TypeMap.h"
33
- #include "ResultSet.h"
34
33
 
35
34
  /* Function prototypes. */
36
35
  static VALUE allocateStatement(VALUE);
@@ -47,20 +46,46 @@ static VALUE getStatementPrepared(VALUE);
47
46
  static VALUE prepareStatement(int, VALUE*, VALUE);
48
47
  static VALUE getStatementPlan(VALUE);
49
48
 
50
- VALUE execAndManageTransaction(VALUE, VALUE, VALUE);
51
- VALUE execAndManageStatement(VALUE, VALUE, VALUE);
52
- VALUE rescueLocalTransaction(VALUE, VALUE);
53
- VALUE execStatementFromArray(VALUE);
54
- VALUE rescueStatement(VALUE, VALUE);
55
- VALUE execInTransactionFromArray(VALUE);
56
- VALUE execInTransaction(VALUE, VALUE, VALUE);
57
- void prepareInTransaction(VALUE, VALUE);
58
- VALUE prepareFromArray(VALUE);
59
- void statementFree(void *);
60
- StatementHandle* getPreparedHandle(VALUE self);
49
+ static VALUE execAndManageTransaction(VALUE, VALUE, VALUE);
50
+ static VALUE execAndManageStatement(VALUE, VALUE, VALUE);
51
+ static VALUE rescueLocalTransaction(VALUE, VALUE);
52
+ static VALUE execStatementFromArray(VALUE);
53
+ static VALUE rescueStatement(VALUE, VALUE);
54
+ static VALUE execInTransactionFromArray(VALUE);
55
+ static VALUE execInTransaction(VALUE, VALUE, VALUE);
56
+ static void prepareInTransaction(VALUE, VALUE);
57
+ static VALUE prepareFromArray(VALUE);
58
+ static void statementFree(void *);
59
+ static StatementHandle* getPreparedHandle(VALUE self);
61
60
 
62
61
  /* Globals. */
63
- VALUE cStatement;
62
+ static VALUE cStatement, cResultSet;
63
+
64
+ static ID
65
+ RB_INTERN_CREATE_COLUMN_METADATA,
66
+ RB_INTERN_AT_NAME,
67
+ RB_INTERN_AT_ALIAS,
68
+ RB_INTERN_AT_KEY,
69
+ RB_INTERN_AT_TYPE,
70
+ RB_INTERN_AT_SCALE,
71
+ RB_INTERN_AT_RELATION,
72
+ RB_INTERN_AT_METADATA,
73
+ RB_INTERN_AT_MANAGE_STATEMENT,
74
+ RB_INTERN_AT_MANAGE_TRANSACTION,
75
+ RB_INTERN_ACTIVE,
76
+ RB_INTERN_EACH,
77
+ RB_INTERN_COMMIT,
78
+ RB_INTERN_ROLLBACK,
79
+ RB_INTERN_SIZE,
80
+ RB_INTERN_CLOSE,
81
+ RB_INTERN_TO_S,
82
+ RB_INTERN_OPEN,
83
+ RB_INTERN_STRIP,
84
+ RB_INTERN_NEW;
85
+
86
+ static const ISC_STATUS FETCH_MORE = 0;
87
+ static const ISC_STATUS FETCH_COMPLETED = 100;
88
+ static const ISC_STATUS FETCH_ONE = 101;
64
89
 
65
90
  /**
66
91
  * This function prepares a Firebird SQL statement for execution.
@@ -176,6 +201,20 @@ long fb_query_affected(StatementHandle *statement) {
176
201
  return (result);
177
202
  }
178
203
 
204
+ static short isActiveResultSet(VALUE object) {
205
+ short result = 0;
206
+ if ((Qtrue == rb_obj_is_kind_of(object, cResultSet))) {
207
+ if(Qtrue == rb_funcall(object, RB_INTERN_ACTIVE, 0)) {
208
+ result = 1;
209
+ }
210
+ }
211
+ return (result);
212
+ }
213
+
214
+ VALUE getStatementMetadata(VALUE self) {
215
+ return rb_ivar_get(self, RB_INTERN_AT_METADATA);
216
+ }
217
+
179
218
  /**
180
219
  * Prepare statement parsing arguments array
181
220
  *
@@ -205,7 +244,7 @@ void prepareInTransaction(VALUE self, VALUE transaction) {
205
244
  if(0 == hStatement->handle) {
206
245
  ConnectionHandle *hConnection = NULL;
207
246
  TransactionHandle *hTransaction = NULL;
208
- VALUE sql = rb_iv_get(self, "@sql");
247
+ VALUE metadata, sql = rb_iv_get(self, "@sql");
209
248
  Data_Get_Struct(getStatementConnection(self), ConnectionHandle, hConnection);
210
249
  Data_Get_Struct(transaction, TransactionHandle, hTransaction);
211
250
 
@@ -214,12 +253,39 @@ void prepareInTransaction(VALUE self, VALUE transaction) {
214
253
  StringValuePtr(sql), &hStatement->handle,
215
254
  hStatement->dialect, &hStatement->type, &hStatement->inputs,
216
255
  &hStatement->outputs);
256
+
257
+ metadata = rb_ary_new2(hStatement->outputs);
258
+ rb_ivar_set(self, RB_INTERN_AT_METADATA, metadata);
259
+
217
260
  if(hStatement->outputs > 0) {
261
+ int index;
262
+ XSQLVAR *var;
263
+ VALUE column, name, alias, key_flag = getFireRubySetting("ALIAS_KEYS");
264
+
218
265
  /* Allocate the XSQLDA */
219
266
  hStatement->output = allocateOutXSQLDA(hStatement->outputs,
220
267
  &hStatement->handle,
221
268
  hStatement->dialect);
222
269
  prepareDataArea(hStatement->output);
270
+
271
+ var = hStatement->output->sqlvar;
272
+ for(index = 0; index < hStatement->output->sqld; index++, var++) {
273
+ column = rb_funcall(self, RB_INTERN_CREATE_COLUMN_METADATA, 0);
274
+ rb_ary_store(metadata, index, column);
275
+ name = rb_str_new(var->sqlname, var->sqlname_length);
276
+ alias = rb_str_new(var->aliasname, var->aliasname_length);
277
+ rb_ivar_set(column, RB_INTERN_AT_NAME, name);
278
+ rb_ivar_set(column, RB_INTERN_AT_ALIAS, alias);
279
+ if(key_flag == Qtrue) {
280
+ rb_ivar_set(column, RB_INTERN_AT_KEY, alias);
281
+ } else {
282
+ rb_ivar_set(column, RB_INTERN_AT_KEY, name);
283
+ }
284
+ rb_ivar_set(column, RB_INTERN_AT_TYPE, getColumnType(var));
285
+ rb_ivar_set(column, RB_INTERN_AT_SCALE, INT2FIX(var->sqlscale));
286
+ rb_ivar_set(column, RB_INTERN_AT_RELATION, rb_str_new(var->relname, var->relname_length));
287
+ }
288
+ rb_obj_freeze(metadata);
223
289
  }
224
290
  }
225
291
  }
@@ -268,12 +334,12 @@ VALUE initializeStatement(VALUE self, VALUE connection, VALUE sql) {
268
334
  StatementHandle *hStatement = NULL;
269
335
  short setting = 0;
270
336
 
271
- sql = rb_funcall(sql, rb_intern("to_s"), 0);
337
+ sql = rb_funcall(sql, RB_INTERN_TO_S, 0);
272
338
 
273
339
  /* Validate the inputs. */
274
340
  if(TYPE(connection) == T_DATA &&
275
341
  RDATA(connection)->dfree == (RUBY_DATA_FUNC)connectionFree) {
276
- if(rb_funcall(connection, rb_intern("open?"), 0) == Qfalse) {
342
+ if(rb_funcall(connection, RB_INTERN_OPEN, 0) == Qfalse) {
277
343
  rb_fireruby_raise(NULL, "Closed connection specified for statement.");
278
344
  }
279
345
  } else {
@@ -389,9 +455,9 @@ VALUE execAndManageTransaction(VALUE self, VALUE parameters, VALUE transaction)
389
455
 
390
456
  result = rb_rescue(execInTransactionFromArray, args, rescueLocalTransaction, transaction);
391
457
  if(isActiveResultSet(result)) {
392
- resultSetManageTransaction(result);
458
+ rb_ivar_set(result, RB_INTERN_AT_MANAGE_TRANSACTION, Qtrue);
393
459
  } else {
394
- rb_funcall(transaction, rb_intern("commit"), 0);
460
+ rb_funcall(transaction, RB_INTERN_COMMIT, 0);
395
461
  }
396
462
  } else {
397
463
  result = execInTransaction(self, transaction, parameters);
@@ -422,7 +488,7 @@ VALUE execAndManageStatement(VALUE self, VALUE parameters, VALUE transaction) {
422
488
  rb_ary_push(args, transaction);
423
489
  result = rb_rescue(execStatementFromArray, args, rescueStatement, self);
424
490
  if(isActiveResultSet(result)) {
425
- resultSetManageStatement(result);
491
+ rb_ivar_set(result, RB_INTERN_AT_MANAGE_STATEMENT, Qtrue);
426
492
  } else {
427
493
  closeStatement(self);
428
494
  }
@@ -440,7 +506,7 @@ VALUE execAndManageStatement(VALUE self, VALUE parameters, VALUE transaction) {
440
506
  *
441
507
  */
442
508
  VALUE rescueLocalTransaction(VALUE transaction, VALUE error) {
443
- rb_funcall(transaction, rb_intern("rollback"), 0);
509
+ rb_funcall(transaction, RB_INTERN_ROLLBACK, 0);
444
510
  rb_exc_raise(error);
445
511
  return(Qnil);
446
512
  }
@@ -456,7 +522,7 @@ VALUE rescueLocalTransaction(VALUE transaction, VALUE error) {
456
522
  *
457
523
  */
458
524
  VALUE rescueStatement(VALUE statement, VALUE error) {
459
- rb_funcall(statement, rb_intern("close"), 0);
525
+ rb_funcall(statement, RB_INTERN_CLOSE, 0);
460
526
  rb_exc_raise(error);
461
527
  return(Qnil);
462
528
  }
@@ -494,6 +560,10 @@ short isCursorStatement(StatementHandle *hStatement) {
494
560
  }
495
561
  }
496
562
 
563
+ static VALUE resultSetEach(VALUE resultSet) {
564
+ return rb_funcall(resultSet, RB_INTERN_EACH, 0);
565
+ }
566
+
497
567
  /**
498
568
  * Execute a statement within a transaction context
499
569
  *
@@ -526,7 +596,7 @@ VALUE execInTransaction(VALUE self, VALUE transaction, VALUE parameters) {
526
596
  "Empty parameter list specified for statement.");
527
597
  }
528
598
 
529
- value = rb_funcall(parameters, rb_intern("size"), 0);
599
+ value = rb_funcall(parameters, RB_INTERN_SIZE, 0);
530
600
  size = TYPE(value) == T_FIXNUM ? FIX2INT(value) : NUM2INT(value);
531
601
  if(size < hStatement->inputs) {
532
602
  rb_fireruby_raise(NULL,
@@ -554,9 +624,9 @@ VALUE execInTransaction(VALUE self, VALUE transaction, VALUE parameters) {
554
624
  rb_fireruby_raise(status, "Error executing SQL statement.");
555
625
  }
556
626
  if (hStatement->output) {
557
- result = rb_result_set_new(self, transaction);
627
+ result = rb_funcall(cResultSet, RB_INTERN_NEW, 2, self, transaction);
558
628
  if(rb_block_given_p()) {
559
- result = yieldResultsRows(result);
629
+ result = rb_iterate(resultSetEach, result, rb_yield, 0);
560
630
  }
561
631
  } else {
562
632
  result = INT2NUM(fb_query_affected(hStatement));
@@ -717,7 +787,7 @@ VALUE getStatementPlan(VALUE self) {
717
787
  case isc_info_sql_get_plan:
718
788
  dataLength = isc_vax_integer(&buffer[1], 2);
719
789
  result = rb_str_new(&buffer[3], dataLength);
720
- rb_funcall(result, rb_intern("strip!"), 0);
790
+ rb_funcall(result, RB_INTERN_STRIP, 0);
721
791
  default:
722
792
  retry = 0;
723
793
  }
@@ -798,7 +868,7 @@ StatementHandle* getPreparedHandle(VALUE self) {
798
868
  rb_ary_push(args, transaction);
799
869
 
800
870
  rb_rescue(prepareFromArray, args, rescueLocalTransaction, transaction);
801
- rb_funcall(transaction, rb_intern("commit"), 0);
871
+ rb_funcall(transaction, RB_INTERN_COMMIT, 0);
802
872
  }
803
873
  return (hStatement);
804
874
  }
@@ -818,6 +888,64 @@ void statementFree(void *handle) {
818
888
  }
819
889
  }
820
890
 
891
+ static VALUE fetch(VALUE self) {
892
+ StatementHandle *hStatement;
893
+ ISC_STATUS status[ISC_STATUS_LENGTH],
894
+ fetch_result;
895
+
896
+ Data_Get_Struct(self, StatementHandle, hStatement);
897
+ if (hStatement->outputs == 0) {
898
+ return Qnil;
899
+ }
900
+
901
+ if (isCursorStatement(hStatement)) {
902
+ fetch_result = isc_dsql_fetch(status, &hStatement->handle, hStatement->dialect,
903
+ hStatement->output);
904
+ if(fetch_result != FETCH_MORE && fetch_result != FETCH_COMPLETED) {
905
+ rb_fireruby_raise(status, "Error fetching query row.");
906
+ }
907
+ } else {
908
+ fetch_result = FETCH_ONE;
909
+ }
910
+
911
+ return INT2FIX(fetch_result);
912
+ }
913
+
914
+ static VALUE closeCursor(VALUE self) {
915
+ StatementHandle *hStatement;
916
+ ISC_STATUS status[ISC_STATUS_LENGTH],
917
+ close_result;
918
+
919
+ Data_Get_Struct(self, StatementHandle, hStatement);
920
+ if (hStatement->outputs == 0) {
921
+ rb_fireruby_raise(status, "Not a cursor statement.");
922
+ }
923
+ if(close_result = isc_dsql_free_statement(status, &hStatement->handle, DSQL_close)) {
924
+ rb_fireruby_raise(status, "Error closing cursor.");
925
+ }
926
+ return INT2FIX(close_result);
927
+ }
928
+
929
+ static VALUE currentRow(VALUE self, VALUE transaction) {
930
+ int i;
931
+ XSQLVAR *entry;
932
+ StatementHandle *hStatement;
933
+ VALUE array, connection;
934
+
935
+ Data_Get_Struct(self, StatementHandle, hStatement);
936
+ if (hStatement->outputs == 0) {
937
+ rb_fireruby_raise(NULL, "Statement has no output.");
938
+ }
939
+
940
+ connection = getStatementConnection(self);
941
+ array = rb_ary_new2(hStatement->output->sqln);
942
+ entry = hStatement->output->sqlvar;
943
+ for(i = 0; i < hStatement->output->sqln; i++, entry++) {
944
+ rb_ary_store(array, i, toValue(entry, connection, transaction));
945
+ }
946
+ return(array);
947
+ }
948
+
821
949
  /**
822
950
  * This function initializes the Statement class within the Ruby environment.
823
951
  * The class is established under the module specified to the function.
@@ -826,7 +954,30 @@ void statementFree(void *handle) {
826
954
  *
827
955
  */
828
956
  void Init_Statement(VALUE module) {
957
+ RB_INTERN_CREATE_COLUMN_METADATA = rb_intern("create_column_metadata");
958
+ RB_INTERN_AT_NAME = rb_intern("@name");
959
+ RB_INTERN_AT_ALIAS = rb_intern("@alias");
960
+ RB_INTERN_AT_KEY = rb_intern("@key");
961
+ RB_INTERN_AT_TYPE = rb_intern("@type");
962
+ RB_INTERN_AT_SCALE = rb_intern("@scale");
963
+ RB_INTERN_AT_RELATION = rb_intern("@relation");
964
+ RB_INTERN_AT_METADATA = rb_intern("@metadata");
965
+ RB_INTERN_AT_MANAGE_STATEMENT = rb_intern("@manage_statement");
966
+ RB_INTERN_AT_MANAGE_TRANSACTION = rb_intern("@manage_transaction");
967
+ RB_INTERN_ACTIVE = rb_intern("active?");
968
+ RB_INTERN_EACH = rb_intern("each");
969
+ RB_INTERN_COMMIT = rb_intern("commit");
970
+ RB_INTERN_ROLLBACK = rb_intern("rollback");
971
+ RB_INTERN_SIZE = rb_intern("size");
972
+ RB_INTERN_CLOSE = rb_intern("close");
973
+ RB_INTERN_NEW = rb_intern("new");
974
+ RB_INTERN_TO_S = rb_intern("to_s");
975
+ RB_INTERN_OPEN = rb_intern("open?");
976
+ RB_INTERN_STRIP = rb_intern("strip!");
977
+
978
+ cResultSet = getClassInModule("ResultSet", module);
829
979
  cStatement = rb_define_class_under(module, "Statement", rb_cObject);
980
+
830
981
  rb_define_alloc_func(cStatement, allocateStatement);
831
982
  rb_define_method(cStatement, "initialize", initializeStatement, 2);
832
983
  rb_define_method(cStatement, "initialize_copy", forbidObjectCopy, 1);
@@ -841,6 +992,9 @@ void Init_Statement(VALUE module) {
841
992
  rb_define_method(cStatement, "prepare", prepareStatement, -1);
842
993
  rb_define_method(cStatement, "prepared?", getStatementPrepared, 0);
843
994
  rb_define_method(cStatement, "plan", getStatementPlan, 0);
995
+ rb_define_method(cStatement, "fetch", fetch, 0);
996
+ rb_define_method(cStatement, "close_cursor", closeCursor, 0);
997
+ rb_define_method(cStatement, "current_row", currentRow, 1);
844
998
 
845
999
  rb_define_const(cStatement, "SELECT_STATEMENT",
846
1000
  INT2FIX(isc_info_sql_stmt_select));
@@ -870,4 +1024,10 @@ void Init_Statement(VALUE module) {
870
1024
  INT2FIX(isc_info_sql_stmt_set_generator));
871
1025
  rb_define_const(cStatement, "SAVE_POINT_STATEMENT",
872
1026
  INT2FIX(isc_info_sql_stmt_savepoint));
1027
+ rb_define_const(cStatement, "FETCH_MORE",
1028
+ INT2FIX(FETCH_MORE));
1029
+ rb_define_const(cStatement, "FETCH_COMPLETED",
1030
+ INT2FIX(FETCH_COMPLETED));
1031
+ rb_define_const(cStatement, "FETCH_ONE",
1032
+ INT2FIX(FETCH_ONE));
873
1033
  }