rubyfb 0.6.4 → 0.6.7

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