ruby-informix 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,55 +1,64 @@
1
- /* $Id: informix.ec,v 1.12 2007/10/14 00:18:50 santana Exp $ */
2
- /*
3
- * Copyright (c) 2006-2007, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
4
- * All rights reserved.
5
- *
6
- * Redistribution and use in source and binary forms, with or without
7
- * modification, are permitted provided that the following conditions
8
- * are met:
9
- *
10
- * 1. Redistributions of source code must retain the above copyright
11
- * notice, this list of conditions and the following disclaimer.
12
- * 2. Redistributions in binary form must reproduce the above copyright
13
- * notice, this list of conditions and the following disclaimer in the
14
- * documentation and/or other materials provided with the distribution.
15
- * 3. The name of the author may not be used to endorse or promote products
16
- * derived from this software without specific prior written permission.
17
- *
18
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
- * POSSIBILITY OF SUCH DAMAGE.
29
- */
30
-
31
- static const char rcsid[] = "$Id: informix.ec,v 1.12 2007/10/14 00:18:50 santana Exp $";
1
+ /* $Id: informixc.ec,v 1.26 2008/04/01 05:30:21 santana Exp $ */
2
+ /*
3
+ * Copyright (c) 2006-2008, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions
8
+ * are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright
11
+ * notice, this list of conditions and the following disclaimer.
12
+ * 2. Redistributions in binary form must reproduce the above copyright
13
+ * notice, this list of conditions and the following disclaimer in the
14
+ * documentation and/or other materials provided with the distribution.
15
+ * 3. The name of the author may not be used to endorse or promote products
16
+ * derived from this software without specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ * POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ static const char rcsid[] = "$Id: informixc.ec,v 1.26 2008/04/01 05:30:21 santana Exp $";
32
32
 
33
33
  #include "ruby.h"
34
- #include "ifx_except.h"
35
34
 
36
35
  #include <sqlstype.h>
37
36
  #include <sqltypes.h>
38
37
 
39
- static VALUE rb_cDate, rb_cBigDecimal;
38
+ static VALUE rb_cDate, rb_cBigDecimal, rb_cRational;
40
39
 
40
+ /* Modules */
41
41
  static VALUE rb_mInformix;
42
- static VALUE rb_mSequentialCursor;
43
- static VALUE rb_mScrollCursor;
44
- static VALUE rb_mInsertCursor;
42
+ static VALUE rb_mInterval;
43
+ static VALUE rb_mCursor;
45
44
 
45
+ /* Classes */
46
46
  static VALUE rb_cSlob, rb_cSlobStat;
47
47
  static VALUE rb_cDatabase;
48
- static VALUE rb_cStatement;
49
- static VALUE rb_cCursor;
48
+ static VALUE rb_cStatement, rb_cCursorBase;
49
+ static VALUE rb_cSequentialCursor, rb_cScrollCursor, rb_cInsertCursor;
50
+ static VALUE rb_cIfxVersion;
51
+
52
+ static VALUE rb_cArray;
53
+
54
+ /* Exceptions */
55
+ static VALUE rb_eError, rb_eWarning, rb_eInternalError;
56
+ static VALUE rb_eProgrammingError, rb_eOperationalError, rb_eDatabaseError;
50
57
 
51
58
  static ID s_read, s_new, s_utc, s_day, s_month, s_year;
52
59
  static ID s_hour, s_min, s_sec, s_usec, s_to_s, s_to_i;
60
+ static ID s_add_info, s_from_months, s_from_seconds;
61
+ static ID s_add, s_mul;
53
62
 
54
63
  static VALUE sym_name, sym_type, sym_nullable, sym_stype, sym_length;
55
64
  static VALUE sym_precision, sym_scale, sym_default, sym_xid;
@@ -58,9 +67,6 @@ static VALUE sym_col_info, sym_sbspace, sym_estbytes, sym_extsz;
58
67
  static VALUE sym_createflags, sym_openflags, sym_maxbytes;
59
68
  static VALUE sym_params;
60
69
 
61
- /* Symbols from ifx_except module */
62
- static ifx_except_symbols_t esyms;
63
-
64
70
  #define IDSIZE 30
65
71
 
66
72
  typedef struct {
@@ -94,17 +100,162 @@ do { \
94
100
  char *c_str = StringValueCStr(str); \
95
101
  mint ret = ifx_int8cvasc(c_str, strlen(c_str), (int8addr)); \
96
102
  if (ret < 0) \
97
- rb_raise(esyms.eOperationalError, "Could not convert %s to int8", c_str); \
103
+ rb_raise(rb_eOperationalError, "Could not convert %s to INT8 [Error %d]", c_str, ret); \
98
104
  } while(0)
99
105
 
100
106
  #define INT82NUM(int8addr, num) \
101
107
  do { \
102
108
  char str[21]; \
103
- ifx_int8toasc((int8addr), str, sizeof(str) - 1); \
109
+ mint ret; \
110
+ ret = ifx_int8toasc((int8addr), str, sizeof(str) - 1); \
111
+ if (ret < 0) \
112
+ rb_raise(rb_eOperationalError, \
113
+ "Unable to convert INT8 to Bignum [Error %d]", ret); \
104
114
  str[sizeof(str) - 1] = 0; \
105
115
  num = rb_cstr2inum(str, 10); \
106
116
  } while(0)
107
117
 
118
+ /*
119
+ *****************************************************************************
120
+ * Begins code copyrighted by Edwin M. Fine
121
+ *****************************************************************************
122
+ *
123
+ * Copyright (c) 2006, 2007 Edwin M. Fine <efine@finecomputerconsultants.com>
124
+ * All rights reserved.
125
+ *
126
+ * Redistribution and use in source and binary forms, with or without
127
+ * modification, are permitted provided that the following conditions
128
+ * are met:
129
+ *
130
+ * 1. Redistributions of source code must retain the above copyright
131
+ * notice, this list of conditions and the following disclaimer.
132
+ * 2. Redistributions in binary form must reproduce the above copyright
133
+ * notice, this list of conditions and the following disclaimer in the
134
+ * documentation and/or other materials provided with the distribution.
135
+ * 3. The name of the author may not be used to endorse or promote products
136
+ * derived from this software without specific prior written permission.
137
+ *
138
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
139
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
140
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
141
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
142
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
143
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
144
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
145
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
146
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
147
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
148
+ * POSSIBILITY OF SUCH DAMAGE.
149
+ *****************************************************************************
150
+ */
151
+ #define TRIM_BLANKS(s) ((s)[byleng(s, stleng(s))] = '\0')
152
+ #define NUM_ELEMS(arr) (sizeof(arr) / sizeof(*arr))
153
+
154
+ static VALUE
155
+ rbifx_ext_exception(VALUE exception_class)
156
+ {
157
+ VALUE new_instance;
158
+
159
+ EXEC SQL BEGIN DECLARE SECTION;
160
+ /* All field sizes defined in IBM Informix ESQL/C Programmer's Manual */
161
+ int4 sql_code;
162
+
163
+ char sql_state[5 + 1];
164
+ char class_origin_val[255 + 1];
165
+ char subclass_origin_val[255 + 1];
166
+ char message[8191 + 1];
167
+ char server_name[255 + 1];
168
+ char connection_name[255 + 1];
169
+
170
+ mint sql_exception_number;
171
+ mint exc_count = 0;
172
+ mint message_len;
173
+ mint i;
174
+ EXEC SQL END DECLARE SECTION;
175
+
176
+ new_instance = rb_class_new_instance(0, 0, exception_class);
177
+
178
+ /* Check that instance of exception_class is derived from
179
+ * Informix::Error
180
+ */
181
+ if (!rb_obj_is_kind_of(new_instance, rb_eError) &&
182
+ !rb_obj_is_kind_of(new_instance, rb_eWarning)) {
183
+ rb_raise(rb_eRuntimeError,
184
+ "Can't instantiate exception from %s, only from %s or %s or their children",
185
+ rb_class2name(exception_class),
186
+ rb_class2name(rb_eWarning),
187
+ rb_class2name(rb_eError));
188
+ }
189
+
190
+ EXEC SQL GET DIAGNOSTICS :exc_count = NUMBER;
191
+
192
+ if (exc_count == 0) { /* Something went wrong */
193
+ char message[128];
194
+ snprintf(message,
195
+ sizeof(message),
196
+ "SQL ERROR: SQLCODE %d (sorry, no GET DIAGNOSTICS information available)",
197
+ SQLCODE);
198
+
199
+ {
200
+ VALUE argv[] = { rb_str_new2(message) };
201
+ return rb_class_new_instance(NUM_ELEMS(argv), argv, rb_eOperationalError);
202
+ }
203
+ }
204
+
205
+ for (i = 0; i < exc_count; ++i) {
206
+ sql_exception_number = i + 1;
207
+
208
+ EXEC SQL GET DIAGNOSTICS EXCEPTION :sql_exception_number
209
+ :sql_code = INFORMIX_SQLCODE,
210
+ :sql_state = RETURNED_SQLSTATE,
211
+ :class_origin_val = CLASS_ORIGIN,
212
+ :subclass_origin_val = SUBCLASS_ORIGIN,
213
+ :message = MESSAGE_TEXT,
214
+ :message_len = MESSAGE_LENGTH,
215
+ :server_name = SERVER_NAME,
216
+ :connection_name = CONNECTION_NAME
217
+ ;
218
+
219
+ TRIM_BLANKS(class_origin_val);
220
+ TRIM_BLANKS(subclass_origin_val);
221
+ TRIM_BLANKS(server_name);
222
+ TRIM_BLANKS(connection_name);
223
+ message[message_len - 1] = '\0';
224
+ TRIM_BLANKS(message);
225
+
226
+ {
227
+ VALUE sprintf_args[] = { rb_str_new2(message), rb_str_new2(sqlca.sqlerrm) };
228
+ VALUE argv[] = {
229
+ INT2FIX(sql_code),
230
+ rb_str_new2(sql_state),
231
+ rb_str_new2(class_origin_val),
232
+ rb_str_new2(subclass_origin_val),
233
+ rb_f_sprintf(NUM_ELEMS(sprintf_args), sprintf_args),
234
+ rb_str_new2(server_name),
235
+ rb_str_new2(connection_name)
236
+ };
237
+
238
+ rb_funcall(new_instance, s_add_info, 1, rb_ary_new4(7, argv));
239
+ }
240
+ }
241
+
242
+ return new_instance;
243
+ }
244
+
245
+ /*
246
+ * C helper functions (see ifx_except.h for documentation)
247
+ */
248
+ static void
249
+ raise_ifx_extended(void)
250
+ {
251
+ rb_exc_raise(rbifx_ext_exception(rb_eDatabaseError));
252
+ }
253
+ /*
254
+ *****************************************************************************
255
+ * Ends code copyrighted by Edwin M. Fine
256
+ *****************************************************************************
257
+ */
258
+
108
259
  /* class Slob::Stat ------------------------------------------------------ */
109
260
 
110
261
  static void
@@ -144,7 +295,7 @@ rb_slobstat_initialize(VALUE self, VALUE slob)
144
295
  Data_Get_Struct(self, slobstat_t, stat);
145
296
 
146
297
  if (sb->fd == -1)
147
- rb_raise(esyms.eProgrammingError,
298
+ rb_raise(rb_eProgrammingError,
148
299
  "Open the Slob object before getting its status");
149
300
 
150
301
  did = sb->database_id;
@@ -167,7 +318,7 @@ rb_slobstat_initialize(VALUE self, VALUE slob)
167
318
 
168
319
  if (stat->atime == -1 || stat->ctime == -1 || stat->mtime == -1 ||
169
320
  stat->refcnt == -1 || ret == -1) {
170
- rb_raise(esyms.eOperationalError, "Unable to get status");
321
+ rb_raise(rb_eOperationalError, "Unable to get status");
171
322
  }
172
323
 
173
324
  return self;
@@ -322,6 +473,7 @@ slob_alloc(VALUE klass)
322
473
  return Data_Wrap_Struct(klass, slob_mark, slob_free, slob);
323
474
  }
324
475
 
476
+ /* :nodoc: */
325
477
  static VALUE
326
478
  rb_slob_initialize(int argc, VALUE *argv, VALUE self)
327
479
  {
@@ -347,7 +499,7 @@ rb_slob_initialize(int argc, VALUE *argv, VALUE self)
347
499
  if (!NIL_P(type)) {
348
500
  int t = FIX2INT(type);
349
501
  if (t != XID_CLOB && t != XID_BLOB)
350
- rb_raise(esyms.eInternalError, "Invalid type %d for an SLOB", t);
502
+ rb_raise(rb_eInternalError, "Invalid type %d for an SLOB", t);
351
503
  slob->type = t;
352
504
  }
353
505
 
@@ -378,7 +530,7 @@ rb_slob_initialize(int argc, VALUE *argv, VALUE self)
378
530
  char *c_sbspace = StringValueCStr(sbspace);
379
531
  ret = ifx_lo_specset_sbspace(slob->spec, c_sbspace);
380
532
  if (ret == -1)
381
- rb_raise(esyms.eOperationalError, "Could not set sbspace name to %s", c_sbspace);
533
+ rb_raise(rb_eOperationalError, "Could not set sbspace name to %s", c_sbspace);
382
534
  }
383
535
  if (!NIL_P(estbytes)) {
384
536
  ifx_int8_t estbytes8;
@@ -386,17 +538,17 @@ rb_slob_initialize(int argc, VALUE *argv, VALUE self)
386
538
  NUM2INT8(estbytes, &estbytes8);
387
539
  ret = ifx_lo_specset_estbytes(slob->spec, &estbytes8);
388
540
  if (ret == -1)
389
- rb_raise(esyms.eOperationalError, "Could not set estbytes");
541
+ rb_raise(rb_eOperationalError, "Could not set estbytes");
390
542
  }
391
543
  if (!NIL_P(extsz)) {
392
544
  ret = ifx_lo_specset_extsz(slob->spec, FIX2LONG(extsz));
393
545
  if (ret == -1)
394
- rb_raise(esyms.eOperationalError, "Could not set extsz to %d", FIX2LONG(extsz));
546
+ rb_raise(rb_eOperationalError, "Could not set extsz to %ld", FIX2LONG(extsz));
395
547
  }
396
548
  if (!NIL_P(createflags)) {
397
549
  ret = ifx_lo_specset_flags(slob->spec, FIX2LONG(createflags));
398
550
  if (ret == -1)
399
- rb_raise(esyms.eOperationalError, "Could not set crate-time flags to 0x%X", FIX2LONG(createflags));
551
+ rb_raise(rb_eOperationalError, "Could not set crate-time flags to 0x%X", FIX2LONG(createflags));
400
552
  }
401
553
  if (!NIL_P(maxbytes)) {
402
554
  ifx_int8_t maxbytes8;
@@ -404,7 +556,7 @@ rb_slob_initialize(int argc, VALUE *argv, VALUE self)
404
556
  NUM2INT8(maxbytes, (&maxbytes8));
405
557
  ret = ifx_lo_specset_maxbytes(slob->spec, &maxbytes8);
406
558
  if (ret == -1)
407
- rb_raise(esyms.eOperationalError, "Could not set maxbytes");
559
+ rb_raise(rb_eOperationalError, "Could not set maxbytes");
408
560
  }
409
561
 
410
562
  slob->fd = ifx_lo_create(slob->spec, RTEST(openflags)? FIX2LONG(openflags): LO_RDWR, &slob->lo, &error);
@@ -414,41 +566,6 @@ rb_slob_initialize(int argc, VALUE *argv, VALUE self)
414
566
  return self;
415
567
  }
416
568
 
417
- static VALUE rb_slob_close(VALUE self);
418
- /*
419
- * call-seq:
420
- * Slob.new(database, type = Slob::CLOB, options = nil) => slob
421
- * Slob.new(database, type = Slob::CLOB, options = nil) {|slob| block } => obj
422
- *
423
- * Creates a Smart Large Object of type <i>type</i> in <i>database</i>.
424
- * Returns a <code>Slob</code> object pointing to it.
425
- *
426
- * <i>type</i> can be Slob::BLOB or Slob::CLOB
427
- *
428
- * <i>options</i> can be nil or a Hash object with the following possible keys:
429
- *
430
- * :sbspace => Sbspace name
431
- * :estbytes => Estimated size, in bytes
432
- * :extsz => Allocation extent size
433
- * :createflags => Create-time flags
434
- * :openflags => Access mode
435
- * :maxbytes => Maximum size
436
- * :col_info => Get the previous values from the column-level storage
437
- * characteristics for the specified database column
438
- */
439
- static VALUE
440
- rb_slob_s_new(int argc, VALUE *argv, VALUE klass)
441
- {
442
- VALUE slob;
443
-
444
- slob = rb_class_new_instance(argc, argv, klass);
445
-
446
- if (rb_block_given_p())
447
- return rb_ensure(rb_yield, slob, rb_slob_close, slob);
448
-
449
- return slob;
450
- }
451
-
452
569
  /*
453
570
  * call-seq:
454
571
  * slob.open(access = Slob::RDONLY) => slob
@@ -552,7 +669,7 @@ rb_slob_read(VALUE self, VALUE nbytes)
552
669
  Data_Get_Struct(self, slob_t, slob);
553
670
 
554
671
  if (slob->fd == -1)
555
- rb_raise(esyms.eProgrammingError, "Open the Slob object before reading");
672
+ rb_raise(rb_eProgrammingError, "Open the Slob object before reading");
556
673
 
557
674
  did = slob->database_id;
558
675
  EXEC SQL set connection :did;
@@ -598,7 +715,7 @@ rb_slob_write(VALUE self, VALUE data)
598
715
  Data_Get_Struct(self, slob_t, slob);
599
716
 
600
717
  if (slob->fd == -1)
601
- rb_raise(esyms.eProgrammingError, "Open the Slob object before writing");
718
+ rb_raise(rb_eProgrammingError, "Open the Slob object before writing");
602
719
 
603
720
  did = slob->database_id;
604
721
  EXEC SQL set connection :did;
@@ -606,8 +723,8 @@ rb_slob_write(VALUE self, VALUE data)
606
723
  raise_ifx_extended();
607
724
 
608
725
  str = rb_obj_as_string(data);
609
- buffer = RSTRING(str)->ptr;
610
- nbytes = RSTRING(str)->len;
726
+ buffer = RSTRING_PTR(str);
727
+ nbytes = RSTRING_LEN(str);
611
728
 
612
729
  ret = ifx_lo_write(slob->fd, buffer, nbytes, &error);
613
730
 
@@ -666,7 +783,7 @@ rb_slob_seek(VALUE self, VALUE offset, VALUE whence)
666
783
  Data_Get_Struct(self, slob_t, slob);
667
784
 
668
785
  if (slob->fd == -1)
669
- rb_raise(esyms.eProgrammingError, "Open the Slob object first");
786
+ rb_raise(rb_eProgrammingError, "Open the Slob object first");
670
787
 
671
788
  did = slob->database_id;
672
789
  EXEC SQL set connection :did;
@@ -728,7 +845,7 @@ rb_slob_tell(VALUE self)
728
845
  Data_Get_Struct(self, slob_t, slob);
729
846
 
730
847
  if (slob->fd == -1)
731
- rb_raise(esyms.eProgrammingError, "Open the Slob object first");
848
+ rb_raise(rb_eProgrammingError, "Open the Slob object first");
732
849
 
733
850
  did = slob->database_id;
734
851
  EXEC SQL set connection :did;
@@ -765,7 +882,7 @@ rb_slob_truncate(VALUE self, VALUE offset)
765
882
  Data_Get_Struct(self, slob_t, slob);
766
883
 
767
884
  if (slob->fd == -1)
768
- rb_raise(esyms.eProgrammingError, "Open the Slob object first");
885
+ rb_raise(rb_eProgrammingError, "Open the Slob object first");
769
886
 
770
887
  did = slob->database_id;
771
888
  EXEC SQL set connection :did;
@@ -821,7 +938,7 @@ rb_slob_lock(VALUE self, VALUE offset, VALUE whence, VALUE range, VALUE mode)
821
938
  Data_Get_Struct(self, slob_t, slob);
822
939
 
823
940
  if (slob->fd == -1)
824
- rb_raise(esyms.eProgrammingError, "Open the Slob object first");
941
+ rb_raise(rb_eProgrammingError, "Open the Slob object first");
825
942
 
826
943
  did = slob->database_id;
827
944
  EXEC SQL set connection :did;
@@ -865,7 +982,7 @@ rb_slob_unlock(VALUE self, VALUE offset, VALUE whence, VALUE range)
865
982
  Data_Get_Struct(self, slob_t, slob);
866
983
 
867
984
  if (slob->fd == -1)
868
- rb_raise(esyms.eProgrammingError, "Open the Slob object first");
985
+ rb_raise(rb_eProgrammingError, "Open the Slob object first");
869
986
 
870
987
  did = slob->database_id;
871
988
  EXEC SQL set connection :did;
@@ -906,7 +1023,7 @@ slob_specget(VALUE self, slob_option_t option)
906
1023
  Data_Get_Struct(self, slob_t, slob);
907
1024
 
908
1025
  if (slob->fd == -1)
909
- rb_raise(esyms.eProgrammingError, "Open the Slob object first");
1026
+ rb_raise(rb_eProgrammingError, "Open the Slob object first");
910
1027
 
911
1028
  did = slob->database_id;
912
1029
  EXEC SQL set connection :did;
@@ -920,7 +1037,7 @@ slob_specget(VALUE self, slob_option_t option)
920
1037
  spec = ifx_lo_stat_cspec(stat);
921
1038
  if (spec == NULL) {
922
1039
  ifx_lo_stat_free(stat);
923
- rb_raise(esyms.eOperationalError, "Unable to get storage characteristics");
1040
+ rb_raise(rb_eOperationalError, "Unable to get storage characteristics");
924
1041
  }
925
1042
 
926
1043
  switch(option) {
@@ -942,7 +1059,7 @@ slob_specget(VALUE self, slob_option_t option)
942
1059
 
943
1060
  ifx_lo_stat_free(stat);
944
1061
  if (ret == -1)
945
- rb_raise(esyms.eOperationalError, "Unable to get information for %s", str_slob_options[option]);
1062
+ rb_raise(rb_eOperationalError, "Unable to get information for %s", str_slob_options[option]);
946
1063
 
947
1064
  switch(option) {
948
1065
  case slob_estbytes:
@@ -976,7 +1093,7 @@ slob_specset(VALUE self, slob_option_t option, VALUE value)
976
1093
  Data_Get_Struct(self, slob_t, slob);
977
1094
 
978
1095
  if (slob->fd == -1)
979
- rb_raise(esyms.eProgrammingError, "Open the Slob object first");
1096
+ rb_raise(rb_eProgrammingError, "Open the Slob object first");
980
1097
 
981
1098
  did = slob->database_id;
982
1099
  EXEC SQL set connection :did;
@@ -990,7 +1107,7 @@ slob_specset(VALUE self, slob_option_t option, VALUE value)
990
1107
  spec = ifx_lo_stat_cspec(stat);
991
1108
  if (spec == NULL) {
992
1109
  ifx_lo_stat_free(stat);
993
- rb_raise(esyms.eOperationalError, "Unable to get storage characteristics");
1110
+ rb_raise(rb_eOperationalError, "Unable to get storage characteristics");
994
1111
  }
995
1112
 
996
1113
  switch(option) {
@@ -1006,7 +1123,7 @@ slob_specset(VALUE self, slob_option_t option, VALUE value)
1006
1123
 
1007
1124
  ifx_lo_stat_free(stat);
1008
1125
  if (ret == -1)
1009
- rb_raise(esyms.eOperationalError, "Unable to set information for %s", str_slob_options[option]);
1126
+ rb_raise(rb_eOperationalError, "Unable to set information for %s", str_slob_options[option]);
1010
1127
 
1011
1128
  return value;
1012
1129
  }
@@ -1118,7 +1235,7 @@ slob_stat(VALUE self, slob_stat_t stat)
1118
1235
  Data_Get_Struct(self, slob_t, slob);
1119
1236
 
1120
1237
  if (slob->fd == -1)
1121
- rb_raise(esyms.eProgrammingError,
1238
+ rb_raise(rb_eProgrammingError,
1122
1239
  "Open the Slob object before getting its status");
1123
1240
 
1124
1241
  did = slob->database_id;
@@ -1151,7 +1268,7 @@ slob_stat(VALUE self, slob_stat_t stat)
1151
1268
  ifx_lo_stat_free(st);
1152
1269
 
1153
1270
  if (ret == -1)
1154
- rb_raise(esyms.eOperationalError, "Unable to get value of %s", str_slob_stats[stat]);
1271
+ rb_raise(rb_eOperationalError, "Unable to get value of %s", str_slob_stats[stat]);
1155
1272
 
1156
1273
  switch(stat) {
1157
1274
  case slob_atime:
@@ -1324,7 +1441,7 @@ alloc_output_slots(cursor_t *c)
1324
1441
  p->loc_loctype = LOCMEMORY;
1325
1442
  p->loc_bufsize = -1;
1326
1443
  }
1327
- if (var->sqltype == SQLDTIME) {
1444
+ if (var->sqltype == SQLDTIME || var->sqltype == SQLINTERVAL) {
1328
1445
  var->sqllen = 0;
1329
1446
  }
1330
1447
  }
@@ -1458,26 +1575,11 @@ bind_input_params(cursor_t *c, VALUE *argv)
1458
1575
  break;
1459
1576
  default:
1460
1577
  klass = rb_obj_class(data);
1461
- if (klass == rb_cDate) {
1462
- int2 mdy[3];
1463
- int4 date;
1464
-
1465
- mdy[0] = FIX2INT(rb_funcall(data, s_month, 0));
1466
- mdy[1] = FIX2INT(rb_funcall(data, s_day, 0));
1467
- mdy[2] = FIX2INT(rb_funcall(data, s_year, 0));
1468
- rmdyjul(mdy, &date);
1469
-
1470
- var->sqldata = (char *)ALLOC(int4);
1471
- *((int4 *)var->sqldata) = date;
1472
- var->sqltype = CDATETYPE;
1473
- var->sqllen = sizeof(int4);
1474
- *var->sqlind = 0;
1475
- break;
1476
- }
1477
1578
  if (klass == rb_cTime) {
1478
1579
  char buffer[30];
1479
1580
  short year, month, day, hour, minute, second;
1480
1581
  int usec;
1582
+ mint ret;
1481
1583
  dtime_t *dt;
1482
1584
 
1483
1585
  year = FIX2INT(rb_funcall(data, s_year, 0));
@@ -1493,7 +1595,11 @@ bind_input_params(cursor_t *c, VALUE *argv)
1493
1595
  dt->dt_qual = TU_DTENCODE(TU_YEAR, TU_F5);
1494
1596
  snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d.%d",
1495
1597
  year, month, day, hour, minute, second, usec/10);
1496
- dtcvasc(buffer, dt);
1598
+ ret = dtcvasc(buffer, dt);
1599
+ if (ret < 0)
1600
+ rb_raise(rb_eOperationalError,
1601
+ "Unable to convert '%s' to DATETIME [Error %d]",
1602
+ RSTRING_PTR(data), ret);
1497
1603
 
1498
1604
  var->sqldata = (char *)dt;
1499
1605
  var->sqltype = CDTIMETYPE;
@@ -1514,25 +1620,14 @@ bind_input_params(cursor_t *c, VALUE *argv)
1514
1620
  *var->sqlind = 0;
1515
1621
  break;
1516
1622
  }
1517
- if (klass == rb_cBigDecimal) {
1518
- data = rb_funcall(data, s_to_s, 0);
1519
- var->sqldata = (char *)ALLOC(dec_t);
1520
- deccvasc(RSTRING(data)->ptr, RSTRING(data)->len,
1521
- (dec_t *)var->sqldata);
1522
- var->sqltype = CDECIMALTYPE;
1523
- var->sqllen = sizeof(dec_t);
1524
- *var->sqlind = 0;
1525
- break;
1526
- }
1527
1623
  if (rb_respond_to(data, s_read)) {
1528
1624
  char *str;
1529
1625
  loc_t *loc;
1530
1626
  long len;
1531
1627
 
1532
1628
  data = rb_funcall(data, s_read, 0);
1533
- data = StringValue(data);
1534
- str = RSTRING(data)->ptr;
1535
- len = RSTRING(data)->len;
1629
+ str = RSTRING_PTR(data);
1630
+ len = RSTRING_LEN(data);
1536
1631
 
1537
1632
  loc = (loc_t *)ALLOC(loc_t);
1538
1633
  byfill((char *)loc, sizeof(loc_t), 0);
@@ -1561,8 +1656,8 @@ bind_input_params(cursor_t *c, VALUE *argv)
1561
1656
  char *str;
1562
1657
  long len;
1563
1658
 
1564
- str = RSTRING(data)->ptr;
1565
- len = RSTRING(data)->len;
1659
+ str = RSTRING_PTR(data);
1660
+ len = RSTRING_LEN(data);
1566
1661
  var->sqldata = ALLOC_N(char, len + 1);
1567
1662
  memcpy(var->sqldata, str, len);
1568
1663
  var->sqldata[len] = 0;
@@ -1679,6 +1774,88 @@ make_result(cursor_t *c, VALUE record)
1679
1774
 
1680
1775
  break;
1681
1776
  }
1777
+ case SQLINTERVAL: {
1778
+ VALUE constructor, value;
1779
+ intrvl_t *data, invl;
1780
+ short sign;
1781
+
1782
+ data = (intrvl_t *)var->sqldata;
1783
+ if (TU_START(data->in_qual) <= TU_MONTH) {
1784
+ invl.in_qual = TU_IENCODE(9, TU_YEAR, TU_MONTH);
1785
+ constructor = s_from_months;
1786
+ }
1787
+ else {
1788
+ invl.in_qual = TU_IENCODE(9, TU_DAY, TU_F5);
1789
+ constructor = s_from_seconds;
1790
+ }
1791
+
1792
+ invextend(data, &invl);
1793
+ sign = invl.in_dec.dec_pos == 0? -1 : 1;
1794
+
1795
+ if (TU_START(data->in_qual) <= TU_MONTH) {
1796
+ int i, exp, months;
1797
+ long years;
1798
+ char *dgts;
1799
+
1800
+ exp = invl.in_dec.dec_exp;
1801
+ dgts = invl.in_dec.dec_dgts;
1802
+ months = years = 0;
1803
+
1804
+ for(i = 0; i < invl.in_dec.dec_ndgts; i++, exp--) {
1805
+ if (exp > 5)
1806
+ years = years*100 + dgts[i];
1807
+ else
1808
+ months += dgts[i];
1809
+ }
1810
+ for(i = exp - 5; i > 0; i--)
1811
+ years *= 100;
1812
+ value = LONG2NUM(sign*years);
1813
+ value = rb_funcall(value, s_mul, 1, INT2FIX(12));
1814
+ value = rb_funcall(value, s_add, 1, INT2FIX(sign*months));
1815
+ }
1816
+ else {
1817
+ int i, exp, usec;
1818
+ long days, seconds;
1819
+ char *dgts;
1820
+
1821
+ exp = invl.in_dec.dec_exp;
1822
+ dgts = invl.in_dec.dec_dgts;
1823
+ days = seconds = usec = 0;
1824
+
1825
+ for(i = 0; i < invl.in_dec.dec_ndgts; i++, exp--) {
1826
+ if(exp > 3)
1827
+ days = days*100 + dgts[i];
1828
+ else if (exp == 3)
1829
+ seconds += dgts[i]*60*60;
1830
+ else if (exp == 2)
1831
+ seconds += dgts[i]*60;
1832
+ else if (exp == 1)
1833
+ seconds += dgts[i];
1834
+ else if (exp == 0)
1835
+ usec += dgts[i]*10000;
1836
+ else if (exp == -1)
1837
+ usec += dgts[i]*100;
1838
+ else if (exp == -2)
1839
+ usec += dgts[i];
1840
+ }
1841
+
1842
+ for(i = exp - 3; i > 0; i--)
1843
+ days *= 100;
1844
+
1845
+ value = LONG2FIX(days);
1846
+ value = rb_funcall(value, s_mul, 1, LONG2FIX(sign*24*60*60));
1847
+ value = rb_funcall(value, s_add, 1, LONG2FIX(sign*seconds));
1848
+
1849
+ if (usec != 0) {
1850
+ VALUE argv[2] = { INT2FIX(sign*usec), LONG2FIX(1000000L) };
1851
+ VALUE frac = rb_class_new_instance(2, argv, rb_cRational);
1852
+ value = rb_funcall(frac, s_add, 1, value);
1853
+ }
1854
+ }
1855
+
1856
+ item = rb_funcall(rb_mInterval, constructor, 1, value);
1857
+ break;
1858
+ }
1682
1859
  case SQLDECIMAL:
1683
1860
  case SQLMONEY: {
1684
1861
  char buffer[40];
@@ -1686,9 +1863,9 @@ make_result(cursor_t *c, VALUE record)
1686
1863
 
1687
1864
  ret = dectoasc((dec_t *)var->sqldata, buffer,
1688
1865
  sizeof(buffer) - 1, -1);
1689
- if (ret)
1690
- rb_raise(esyms.eOperationalError,
1691
- "Unable to convert DECIMAL to BigDecimal");
1866
+ if (ret < 0)
1867
+ rb_raise(rb_eOperationalError,
1868
+ "Unable to convert DECIMAL to BigDecimal [Error %d]", ret);
1692
1869
 
1693
1870
  buffer[sizeof(buffer) - 1] = 0;
1694
1871
  item = rb_funcall(rb_cBigDecimal, s_new, 1, rb_str_new2(buffer));
@@ -1744,46 +1921,6 @@ make_result(cursor_t *c, VALUE record)
1744
1921
  return record;
1745
1922
  }
1746
1923
 
1747
- /* module Informix -------------------------------------------------------- */
1748
-
1749
- static VALUE rb_database_s_open(int argc, VALUE *argv, VALUE klass);
1750
- /*
1751
- * call-seq:
1752
- * Informix.connect(dbname, user=nil, password=nil) => database
1753
- * Informix.connect(dbname, user=nil, password=nil) {|database| block } => obj
1754
- *
1755
- * Creates a <code>Database</code> object connected to <i>dbname</i> as
1756
- * <i>user</i> with <i>password</i>. If these are not given, connects to
1757
- * <i>dbname</i> as the current user.
1758
- *
1759
- * The Database object is passed to the block if it's given, and automatically
1760
- * closes the connection when the block terminates, returning the value of
1761
- * the block.
1762
- */
1763
- static VALUE
1764
- rb_informix_connect(int argc, VALUE *argv, VALUE self)
1765
- {
1766
- return rb_database_s_open(argc, argv, rb_cDatabase);
1767
- }
1768
-
1769
- /*
1770
- * call-seq:
1771
- * Informix.version => string
1772
- *
1773
- * Returns the version of this Ruby/Informix driver.
1774
- * Note that this is NOT the Informix database version.
1775
- */
1776
- static VALUE rb_informix_version(void)
1777
- {
1778
- static const char * const ver = "0.6.1";
1779
- static VALUE driver_version;
1780
-
1781
- if (driver_version == 0)
1782
- driver_version = rb_str_freeze(rb_str_new2(ver));
1783
-
1784
- return driver_version;
1785
- }
1786
-
1787
1924
  /* class Database --------------------------------------------------------- */
1788
1925
 
1789
1926
  static void
@@ -1808,19 +1945,25 @@ database_alloc(VALUE klass)
1808
1945
  return Data_Wrap_Struct(klass, 0, database_free, did);
1809
1946
  }
1810
1947
 
1948
+ /* :nodoc: */
1811
1949
  static VALUE
1812
1950
  rb_database_initialize(int argc, VALUE *argv, VALUE self)
1813
1951
  {
1814
- VALUE arg[3];
1952
+ VALUE arg[3], version;
1953
+ VALUE server_type, major, minor, os, level, full;
1815
1954
 
1816
1955
  EXEC SQL begin declare section;
1817
1956
  char *dbname, *user = NULL, *pass = NULL, *did;
1957
+ struct version_t {
1958
+ varchar server_type[41], major[3], minor[3], os[3], level[3];
1959
+ varchar full[61];
1960
+ } c_version;
1818
1961
  EXEC SQL end declare section;
1819
1962
 
1820
1963
  rb_scan_args(argc, argv, "12", &arg[0], &arg[1], &arg[2]);
1821
1964
 
1822
1965
  if (NIL_P(arg[0]))
1823
- rb_raise(esyms.eProgrammingError, "A database name must be specified");
1966
+ rb_raise(rb_eProgrammingError, "A database name must be specified");
1824
1967
 
1825
1968
  Data_Get_Struct(self, char, did);
1826
1969
 
@@ -1842,36 +1985,28 @@ rb_database_initialize(int argc, VALUE *argv, VALUE self)
1842
1985
  if (SQLCODE < 0)
1843
1986
  raise_ifx_extended();
1844
1987
 
1845
- return self;
1846
- }
1988
+ EXEC SQL select dbinfo('version', 'server-type'),
1989
+ dbinfo('version', 'major'),
1990
+ dbinfo('version', 'minor'),
1991
+ dbinfo('version', 'os'),
1992
+ dbinfo('version', 'level'),
1993
+ dbinfo('version', 'full')
1994
+ into :c_version from systables where tabid = 1;
1847
1995
 
1848
- /*
1849
- * call-seq:
1850
- * Database.new(dbname, user = nil, password = nil) => database
1851
- * Database.open(dbname, user = nil, password = nil) => database
1852
- * Database.new(dbname, user = nil, password = nil) {|database| block } => obj
1853
- * Database.open(dbname, user = nil, password = nil) {|database| block } => obj
1854
- *
1855
- * Creates a <code>Database</code> object connected to <i>dbname</i> as
1856
- * <i>user</i> with <i>password</i>. If these are not given, connects to
1857
- * <i>dbname</i> as the current user.
1858
- *
1859
- * The Database object is passed to the block if it's given, and automatically
1860
- * closes the connection when the block terminates, returning the value of
1861
- * the block.
1862
- */
1863
- static VALUE rb_database_close(VALUE self);
1864
- static VALUE
1865
- rb_database_s_open(int argc, VALUE *argv, VALUE klass)
1866
- {
1867
- VALUE database;
1868
1996
 
1869
- database = rb_class_new_instance(argc, argv, klass);
1997
+ OBJ_FREEZE(server_type = rb_str_new2(c_version.server_type));
1998
+ OBJ_FREEZE(major = rb_str_new2(c_version.major));
1999
+ OBJ_FREEZE(minor = rb_str_new2(c_version.minor));
2000
+ OBJ_FREEZE(os = rb_str_new2(c_version.os));
2001
+ OBJ_FREEZE(level = rb_str_new2(c_version.level));
2002
+ OBJ_FREEZE(full = rb_str_new2(c_version.full));
1870
2003
 
1871
- if (rb_block_given_p())
1872
- return rb_ensure(rb_yield, database, rb_database_close, database);
2004
+ version = rb_struct_new(rb_cIfxVersion, server_type, major, minor, os,
2005
+ level, full, NULL);
2006
+ OBJ_FREEZE(version);
2007
+ rb_iv_set(self, "@version", version);
1873
2008
 
1874
- return database;
2009
+ return self;
1875
2010
  }
1876
2011
 
1877
2012
  /*
@@ -1904,7 +2039,17 @@ rb_database_close(VALUE self)
1904
2039
  *
1905
2040
  * Executes <i>query</i> and returns the number of rows affected.
1906
2041
  * <i>query</i> must not return rows. Executes efficiently any
1907
- * non-parameterized or DQL statement.
2042
+ * DDL (CREATE, DROP, ALTER), DCL (GRANT, REVOKE) and non-parameterized
2043
+ * DML (INSERT, UPDATE, DELETE) statements, except SELECT.
2044
+ *
2045
+ * Examples:
2046
+ *
2047
+ * Granting CONNECT to user:
2048
+ * db.immediate "grant connect to #{user}"
2049
+ * Creating a table:
2050
+ * db.immediate 'create table test(id serial, code char(2), desc varchar(30))'
2051
+ * Deleting records:
2052
+ * db.immediate 'delete from test where id = 7'
1908
2053
  */
1909
2054
 
1910
2055
  static VALUE
@@ -1990,6 +2135,20 @@ database_transfail(VALUE self)
1990
2135
  * otherwise.
1991
2136
  *
1992
2137
  * Returns __self__.
2138
+ *
2139
+ * Examples:
2140
+ *
2141
+ * A bulk insert using an insert cursor. Requires a transaction:
2142
+ * db.transaction do |db|
2143
+ * db.cursor('insert into stock values(?, ?, ?, ?, ?, ?)') |cur|
2144
+ * cur.open
2145
+ * # Loading a file separated by '|'
2146
+ * File.open(filename).each do |line|
2147
+ * fields = line.split('|')
2148
+ * cur.put(*fields)
2149
+ * end
2150
+ * end
2151
+ * end
1993
2152
  */
1994
2153
  static VALUE
1995
2154
  rb_database_transaction(VALUE self)
@@ -2010,91 +2169,11 @@ rb_database_transaction(VALUE self)
2010
2169
  EXEC SQL begin work;
2011
2170
  ret = rb_rescue(rb_yield, self, database_transfail, self);
2012
2171
  if (ret == Qundef)
2013
- rb_raise(esyms.eOperationalError, "Transaction rolled back");
2172
+ rb_raise(rb_eOperationalError, "Transaction rolled back");
2014
2173
  EXEC SQL commit;
2015
2174
  return self;
2016
2175
  }
2017
2176
 
2018
- static VALUE statement_s_new(int, VALUE *, VALUE);
2019
- /*
2020
- * call-seq:
2021
- * db.prepare(query) => statement
2022
- * db.prepare(query) {|stmt| block } => obj
2023
- *
2024
- * Creates a <code>Statement</code> object based on <i>query</i>.
2025
- * In the first form the Statement object is returned.
2026
- * In the second form the Statement object is passed to the block and when it
2027
- * terminates, the Statement object is dropped, returning the value of the
2028
- * block.
2029
- *
2030
- * <i>query</i> may contain '?' placeholders for input parameters;
2031
- * it must not be a query returning more than one row
2032
- * (use <code>Database#cursor</code> instead.)
2033
- */
2034
- static VALUE
2035
- rb_database_prepare(VALUE self, VALUE query)
2036
- {
2037
- VALUE argv[2];
2038
-
2039
- argv[0] = self; argv[1] = query;
2040
- return statement_s_new(2, argv, rb_cStatement);
2041
- }
2042
-
2043
- static VALUE rb_cursor_s_new(int argc, VALUE *argv, VALUE klass);
2044
- /*
2045
- * call-seq:
2046
- * db.cursor(query, options = nil) => cursor
2047
- *
2048
- * Returns a <code>Cursor</code> object based on <i>query</i>.
2049
- * <i>query</i> may contain '?' placeholders for input parameters.
2050
- *
2051
- * <i>options</i> must be a hash with the following possible keys:
2052
- *
2053
- * :scroll => true or false
2054
- * :hold => true or false
2055
- *
2056
- */
2057
- static VALUE
2058
- rb_database_cursor(int argc, VALUE *argv, VALUE self)
2059
- {
2060
- VALUE arg[3];
2061
-
2062
- arg[0] = self;
2063
- rb_scan_args(argc, argv, "11", &arg[1], &arg[2]);
2064
- return rb_cursor_s_new(3, arg, rb_cCursor);
2065
- }
2066
-
2067
- /*
2068
- * call-seq:
2069
- * db.slob(type = Slob::CLOB, options = nil) => slob
2070
- * db.slob(type = Slob::CLOB, options = nil) {|slob| block } => obj
2071
- *
2072
- * Creates a Smart Large Object of type <i>type</i>.
2073
- * Returns a <code>Slob</code> object pointing to it.
2074
- *
2075
- * <i>type</i> can be Slob::BLOB or Slob::CLOB
2076
- *
2077
- * <i>options</i> can be nil or a Hash object with the following possible keys:
2078
- *
2079
- * :sbspace => Sbspace name
2080
- * :estbytes => Estimated size, in bytes
2081
- * :extsz => Allocation extent size
2082
- * :createflags => Create-time flags
2083
- * :openflags => Access mode
2084
- * :maxbytes => Maximum size
2085
- * :col_info => Get the previous values from the column-level storage
2086
- * characteristics for the specified database column
2087
- */
2088
- static VALUE
2089
- rb_database_slob(int argc, VALUE *argv, VALUE self)
2090
- {
2091
- VALUE arg[3];
2092
-
2093
- arg[0] = self;
2094
- rb_scan_args(argc, argv, "02", &arg[1], &arg[2]);
2095
- return rb_slob_s_new(3, arg, rb_cSlob);
2096
- }
2097
-
2098
2177
  /*
2099
2178
  * call-seq:
2100
2179
  * db.columns(tablename) => array
@@ -2139,7 +2218,7 @@ rb_database_columns(VALUE self, VALUE tablename)
2139
2218
  EXEC SQL select tabid into :tabid from systables where tabname = :tabname;
2140
2219
 
2141
2220
  if (SQLCODE == SQLNOTFOUND)
2142
- rb_raise(esyms.eProgrammingError, "Table '%s' doesn't exist", tabname);
2221
+ rb_raise(rb_eProgrammingError, "Table '%s' doesn't exist", tabname);
2143
2222
 
2144
2223
  result = rb_ary_new();
2145
2224
 
@@ -2287,22 +2366,28 @@ statement_mark(cursor_t *c)
2287
2366
  }
2288
2367
 
2289
2368
  static void
2290
- statement_free(void *p)
2369
+ st_free(cursor_t *c)
2291
2370
  {
2292
2371
  EXEC SQL begin declare section;
2293
2372
  char *sid, *did;
2294
2373
  EXEC SQL end declare section;
2295
2374
 
2296
- free_input_slots(p);
2297
- free_output_slots(p);
2375
+ free_input_slots(c);
2376
+ free_output_slots(c);
2298
2377
 
2299
- did = ((cursor_t *)p)->database_id;
2378
+ did = c->database_id;
2300
2379
  EXEC SQL set connection :did;
2301
- if (SQLCODE >= 0) {
2302
- sid = ((cursor_t *)p)->stmt_id;
2303
- EXEC SQL free :sid;
2304
- }
2380
+ if (SQLCODE < 0)
2381
+ return;
2305
2382
 
2383
+ sid = c->stmt_id;
2384
+ EXEC SQL free :sid;
2385
+ }
2386
+
2387
+ static void
2388
+ statement_free(void *p)
2389
+ {
2390
+ st_free(p);
2306
2391
  xfree(p);
2307
2392
  }
2308
2393
 
@@ -2316,8 +2401,9 @@ statement_alloc(VALUE klass)
2316
2401
  return Data_Wrap_Struct(klass, statement_mark, statement_free, c);
2317
2402
  }
2318
2403
 
2404
+ /* :nodoc: */
2319
2405
  static VALUE
2320
- statement_initialize(VALUE self, VALUE db, VALUE query)
2406
+ rb_statement_initialize(VALUE self, VALUE db, VALUE query)
2321
2407
  {
2322
2408
  struct sqlda *output;
2323
2409
  cursor_t *c;
@@ -2358,48 +2444,31 @@ statement_initialize(VALUE self, VALUE db, VALUE query)
2358
2444
  return self;
2359
2445
  }
2360
2446
 
2361
- static VALUE statement_drop(VALUE);
2362
- /*
2363
- * call-seq:
2364
- * Statement.new(database, query) => statement
2365
- * Statement.new(database, query) {|stmt| block } => obj
2366
- *
2367
- * Creates a <code>Statement</code> object based on <i>query</i> in the
2368
- * context of <i>database</i>.
2369
- * In the first form the <code>Statement</code> object is returned.
2370
- * In the second form the Statement object is passed to the block and when it
2371
- * terminates, the Statement object is dropped, returning the value of the
2372
- * block.
2373
- *
2374
- * <i>query</i> may contain '?' placeholders for input parameters;
2375
- * it must not be a query returning more than one row
2376
- * (use <code>Cursor</code> instead.)
2377
- */
2378
- static VALUE
2379
- statement_s_new(int argc, VALUE *argv, VALUE klass)
2380
- {
2381
- VALUE stmt;
2382
-
2383
- stmt = rb_class_new_instance(argc, argv, klass);
2384
-
2385
- if (rb_block_given_p())
2386
- return rb_ensure(rb_yield, stmt, statement_drop, stmt);
2387
-
2388
- return stmt;
2389
- }
2390
-
2391
2447
  /*
2392
2448
  * call-seq:
2393
- * stmt[*params] => fixnum or hash
2449
+ * st[*params] => fixnum or hash
2394
2450
  *
2395
2451
  * Executes the previously prepared statement, binding <i>params</i> as
2396
2452
  * input parameters.
2397
2453
  *
2398
2454
  * Returns the record retrieved, in the case of a singleton select, or the
2399
2455
  * number of rows affected, in the case of any other statement.
2456
+ *
2457
+ * Examples:
2458
+ *
2459
+ * Inserting records:
2460
+ * db.prepare('insert into state values(?, ?)') do |st|
2461
+ * st.execute('CA', 'California')
2462
+ * st.call('AZ', 'Arizona')
2463
+ * st['TX', 'Texas')
2464
+ * end
2465
+ * Selecting one record (returns a hash):
2466
+ * cust = db.prepare('select * from customer where num = 101') do |st|
2467
+ * st.execute
2468
+ * end
2400
2469
  */
2401
2470
  static VALUE
2402
- statement_call(int argc, VALUE *argv, VALUE self)
2471
+ rb_statement_call(int argc, VALUE *argv, VALUE self)
2403
2472
  {
2404
2473
  struct sqlda *input, *output;
2405
2474
  cursor_t *c;
@@ -2456,40 +2525,29 @@ statement_call(int argc, VALUE *argv, VALUE self)
2456
2525
 
2457
2526
  /*
2458
2527
  * call-seq:
2459
- * stmt.drop
2528
+ * st.drop
2460
2529
  *
2461
2530
  * Frees the statement and the memory associated with it.
2462
2531
  */
2463
2532
  static VALUE
2464
- statement_drop(VALUE self)
2533
+ rb_statement_drop(VALUE self)
2465
2534
  {
2466
2535
  cursor_t *c;
2467
- EXEC SQL begin declare section;
2468
- char *sid, *did;
2469
- EXEC SQL end declare section;
2470
2536
 
2471
2537
  Data_Get_Struct(self, cursor_t, c);
2472
- free_input_slots(c);
2473
- free_output_slots(c);
2474
-
2475
- did = c->database_id;
2476
- EXEC SQL set connection :did;
2477
- if (SQLCODE < 0)
2478
- return Qnil;
2479
- sid = c->stmt_id;
2480
- EXEC SQL free :sid;
2538
+ st_free(c);
2481
2539
 
2482
2540
  return Qnil;
2483
2541
  }
2484
2542
 
2485
- /* module SequentialCursor ----------------------------------------------- */
2543
+ /* class SequentialCursor ------------------------------------------------ */
2486
2544
 
2487
2545
  /* Decides whether to use an Array or a Hash, and instantiate a new
2488
2546
  * object or reuse an existing one.
2489
2547
  */
2490
2548
  #define RECORD(c, type, bang, record) \
2491
2549
  do {\
2492
- if (type == T_ARRAY) {\
2550
+ if (type == rb_cArray) {\
2493
2551
  if (bang) {\
2494
2552
  if (!c->array)\
2495
2553
  c->array = rb_ary_new2(c->daOutput->sqld);\
@@ -2513,18 +2571,19 @@ do {\
2513
2571
  * Base function for fetch* methods, except *_many
2514
2572
  */
2515
2573
  static VALUE
2516
- fetch(VALUE self, VALUE type, int bang)
2574
+ fetch(VALUE self, VALUE type, VALUE bang)
2517
2575
  {
2518
2576
  EXEC SQL begin declare section;
2519
2577
  char *cid, *did;
2520
2578
  EXEC SQL end declare section;
2579
+ short c_bang;
2521
2580
  cursor_t *c;
2522
2581
  struct sqlda *output;
2523
2582
  VALUE record;
2524
2583
 
2525
2584
  Data_Get_Struct(self, cursor_t, c);
2526
2585
  if (!c->is_open)
2527
- rb_raise(esyms.eProgrammingError, "Open the cursor object first");
2586
+ rb_raise(rb_eProgrammingError, "Open the cursor object first");
2528
2587
 
2529
2588
  did = c->database_id;
2530
2589
  EXEC SQL set connection :did;
@@ -2541,72 +2600,11 @@ fetch(VALUE self, VALUE type, int bang)
2541
2600
  if (SQLCODE == SQLNOTFOUND)
2542
2601
  return Qnil;
2543
2602
 
2544
- RECORD(c, type, bang, record);
2603
+ c_bang = RTEST(bang);
2604
+ RECORD(c, type, c_bang, record);
2545
2605
  return make_result(c, record);
2546
2606
  }
2547
2607
 
2548
- /*
2549
- * call-seq:
2550
- * cursor.fetch => array or nil
2551
- *
2552
- * Fetches the next record.
2553
- *
2554
- * Returns the record fetched as an array, or nil if there are no
2555
- * records left.
2556
- */
2557
- static VALUE
2558
- seqcur_fetch(VALUE self)
2559
- {
2560
- return fetch(self, T_ARRAY, 0);
2561
- }
2562
-
2563
- /*
2564
- * call-seq:
2565
- * cursor.fetch! => array or nil
2566
- *
2567
- * Fetches the next record, storing it in the same Array object every time
2568
- * it is called.
2569
- *
2570
- * Returns the record fetched as an array, or nil if there are no
2571
- * records left.
2572
- */
2573
- static VALUE
2574
- seqcur_fetch_bang(VALUE self)
2575
- {
2576
- return fetch(self, T_ARRAY, 1);
2577
- }
2578
-
2579
- /*
2580
- * call-seq:
2581
- * cursor.fetch_hash => hash or nil
2582
- *
2583
- * Fetches the next record.
2584
- *
2585
- * Returns the record fetched as a hash, or nil if there are no
2586
- * records left.
2587
- */
2588
- static VALUE
2589
- seqcur_fetch_hash(VALUE self)
2590
- {
2591
- return fetch(self, T_HASH, 0);
2592
- }
2593
-
2594
- /*
2595
- * call-seq:
2596
- * cursor.fetch_hash! => hash or nil
2597
- *
2598
- * Fetches the next record, storing it in the same Hash object every time
2599
- * it is called.
2600
- *
2601
- * Returns the record fetched as a hash, or nil if there are no
2602
- * records left.
2603
- */
2604
- static VALUE
2605
- seqcur_fetch_hash_bang(VALUE self)
2606
- {
2607
- return fetch(self, T_HASH, 1);
2608
- }
2609
-
2610
2608
  /*
2611
2609
  * Base function for fetch*_many, fetch*_all and each_by methods
2612
2610
  */
@@ -2624,7 +2622,7 @@ fetch_many(VALUE self, VALUE n, VALUE type)
2624
2622
 
2625
2623
  Data_Get_Struct(self, cursor_t, c);
2626
2624
  if (!c->is_open)
2627
- rb_raise(esyms.eProgrammingError, "Open the cursor object first");
2625
+ rb_raise(rb_eProgrammingError, "Open the cursor object first");
2628
2626
 
2629
2627
  did = c->database_id;
2630
2628
  EXEC SQL set connection :did;
@@ -2650,7 +2648,7 @@ fetch_many(VALUE self, VALUE n, VALUE type)
2650
2648
  if (SQLCODE == SQLNOTFOUND)
2651
2649
  break;
2652
2650
 
2653
- if (type == T_ARRAY)
2651
+ if (type == rb_cArray)
2654
2652
  record = rb_ary_new2(c->daOutput->sqld);
2655
2653
  else
2656
2654
  record = rb_hash_new();
@@ -2660,73 +2658,24 @@ fetch_many(VALUE self, VALUE n, VALUE type)
2660
2658
  return records;
2661
2659
  }
2662
2660
 
2663
- /*
2664
- * call-seq:
2665
- * cursor.fetch_many(n) => array
2666
- *
2667
- * Reads at most <i>n</i> records.
2668
- *
2669
- * Returns the records read as an array of arrays
2670
- */
2671
- static VALUE
2672
- seqcur_fetch_many(VALUE self, VALUE n)
2673
- {
2674
- return fetch_many(self, n, T_ARRAY);
2675
- }
2676
-
2677
- /*
2678
- * call-seq:
2679
- * cursor.fetch_hash_many(n) => array
2680
- *
2681
- * Reads at most <i>n</i> records.
2682
- * Returns the records read as an array of hashes.
2683
- */
2684
- static VALUE
2685
- seqcur_fetch_hash_many(VALUE self, VALUE n)
2686
- {
2687
- return fetch_many(self, n, T_HASH);
2688
- }
2689
-
2690
- /*
2691
- * call-seq:
2692
- * cursor.fetch_all => array
2693
- *
2694
- * Returns all the records left as an array of arrays
2695
- */
2696
- static VALUE
2697
- seqcur_fetch_all(VALUE self)
2698
- {
2699
- return fetch_many(self, Qnil, T_ARRAY);
2700
- }
2701
-
2702
- /*
2703
- * call-seq:
2704
- * cursor.fetch_hash_all => array
2705
- *
2706
- * Returns all the records left as an array of hashes
2707
- */
2708
- static VALUE
2709
- seqcur_fetch_hash_all(VALUE self)
2710
- {
2711
- return fetch_many(self, Qnil, T_HASH);
2712
- }
2713
2661
 
2714
2662
  /*
2715
2663
  * Base function for each* methods, except each*_by
2716
2664
  */
2717
2665
  static VALUE
2718
- each(VALUE self, VALUE type, int bang)
2666
+ each(VALUE self, VALUE type, VALUE bang)
2719
2667
  {
2720
2668
  cursor_t *c;
2721
2669
  EXEC SQL begin declare section;
2722
2670
  char *cid, *did;
2723
2671
  EXEC SQL end declare section;
2672
+ short c_bang;
2724
2673
  struct sqlda *output;
2725
2674
  VALUE record;
2726
2675
 
2727
2676
  Data_Get_Struct(self, cursor_t, c);
2728
2677
  if (!c->is_open)
2729
- rb_raise(esyms.eProgrammingError, "Open the cursor object first");
2678
+ rb_raise(rb_eProgrammingError, "Open the cursor object first");
2730
2679
 
2731
2680
  did = c->database_id;
2732
2681
  EXEC SQL set connection :did;
@@ -2743,7 +2692,8 @@ each(VALUE self, VALUE type, int bang)
2743
2692
 
2744
2693
  if (SQLCODE == SQLNOTFOUND)
2745
2694
  return self;
2746
- RECORD(c, type, bang, record);
2695
+ c_bang = RTEST(bang);
2696
+ RECORD(c, type, c_bang, record);
2747
2697
  rb_yield(make_result(c, record));
2748
2698
  }
2749
2699
  }
@@ -2764,111 +2714,33 @@ each_by(VALUE self, VALUE n, VALUE type)
2764
2714
  }
2765
2715
  }
2766
2716
 
2767
- /*
2768
- * call-seq:
2769
- * cursor.each {|record| block } => cursor
2770
- *
2771
- * Iterates over the remaining records, passing each <i>record</i> to the
2772
- * <i>block</i> as an array.
2773
- *
2774
- * Returns __self__.
2775
- */
2776
- static VALUE
2777
- seqcur_each(VALUE self)
2778
- {
2779
- return each(self, T_ARRAY, 0);
2780
- }
2717
+ /* class InsertCursor ---------------------------------------------------- */
2781
2718
 
2782
2719
  /*
2783
2720
  * call-seq:
2784
- * cursor.each! {|record| block } => cursor
2721
+ * cursor.put(*params)
2722
+ *
2723
+ * Binds +params+ as input parameters and executes the insert statement.
2724
+ * The records are not written immediatly to disk, unless the insert buffer
2725
+ * is full, the +flush+ method is called, the cursor is closed or
2726
+ * the transaction is commited.
2785
2727
  *
2786
- * Iterates over the remaining records, passing each <i>record</i> to the
2787
- * <i>block</i> as an array. No new Array objects are created for each record.
2788
- * The same Array object is reused in each call.
2728
+ * Examples:
2789
2729
  *
2790
- * Returns __self__.
2730
+ * A bulk insert using an insert cursor. Requires a transaction:
2731
+ * db.transaction do |db|
2732
+ * db.cursor('insert into stock values(?, ?, ?, ?, ?, ?)') |cur|
2733
+ * cur.open
2734
+ * # Loading a file separated by '|'
2735
+ * File.open(filename).each do |line|
2736
+ * fields = line.split('|')
2737
+ * cur.put(*fields)
2738
+ * end
2739
+ * end
2740
+ * end
2791
2741
  */
2792
2742
  static VALUE
2793
- seqcur_each_bang(VALUE self)
2794
- {
2795
- return each(self, T_ARRAY, 1);
2796
- }
2797
-
2798
- /*
2799
- * call-seq:
2800
- * cursor.each_hash {|record| block } => cursor
2801
- *
2802
- * Iterates over the remaining records, passing each <i>record</i> to the
2803
- * <i>block</i> as a hash.
2804
- *
2805
- * Returns __self__.
2806
- */
2807
- static VALUE
2808
- seqcur_each_hash(VALUE self)
2809
- {
2810
- return each(self, T_HASH, 0);
2811
- }
2812
-
2813
- /*
2814
- * call-seq:
2815
- * cursor.each_hash! {|record| block } => cursor
2816
- *
2817
- * Iterates over the remaining records, passing each <i>record</i> to the
2818
- * <i>block</i> as a hash. No new Hash objects are created for each record.
2819
- * The same Hash object is reused in each call.
2820
- *
2821
- * Returns __self__.
2822
- */
2823
- static VALUE
2824
- seqcur_each_hash_bang(VALUE self)
2825
- {
2826
- return each(self, T_HASH, 1);
2827
- }
2828
-
2829
- /*
2830
- * call-seq:
2831
- * cursor.each_by(n) {|records| block } => cursor
2832
- *
2833
- * Iterates over the remaining records, passing at most <i>n</i> <i>records</i>
2834
- * to the <i>block</i> as arrays.
2835
- *
2836
- * Returns __self__.
2837
- */
2838
- static VALUE
2839
- seqcur_each_by(VALUE self, VALUE n)
2840
- {
2841
- return each_by(self, n, T_ARRAY);
2842
- }
2843
-
2844
- /*
2845
- * call-seq:
2846
- * cursor.each_hash_by(n) {|records| block } => cursor
2847
- *
2848
- * Iterates over the remaining records, passing at most <i>n</i> <i>records</i>
2849
- * to the <i>block</i> as hashes.
2850
- *
2851
- * Returns __self__.
2852
- */
2853
- static VALUE
2854
- seqcur_each_hash_by(VALUE self, VALUE n)
2855
- {
2856
- return each_by(self, n, T_HASH);
2857
- }
2858
-
2859
- /* module InsertCursor --------------------------------------------------- */
2860
-
2861
- /*
2862
- * call-seq:
2863
- * cursor.put(*params)
2864
- *
2865
- * Binds <i>params</i> as input parameters and executes the insert statement.
2866
- * The records are not written immediatly to disk, unless the insert buffer
2867
- * is full, the <code>flush</code> method is called, the cursor is closed or
2868
- * the transaction is commited.
2869
- */
2870
- static VALUE
2871
- inscur_put(int argc, VALUE *argv, VALUE self)
2743
+ rb_inscur_put(int argc, VALUE *argv, VALUE self)
2872
2744
  {
2873
2745
  struct sqlda *input;
2874
2746
  cursor_t *c;
@@ -2878,7 +2750,7 @@ inscur_put(int argc, VALUE *argv, VALUE self)
2878
2750
 
2879
2751
  Data_Get_Struct(self, cursor_t, c);
2880
2752
  if (!c->is_open)
2881
- rb_raise(esyms.eProgrammingError, "Open the cursor object first");
2753
+ rb_raise(rb_eProgrammingError, "Open the cursor object first");
2882
2754
 
2883
2755
  did = c->database_id;
2884
2756
  EXEC SQL set connection :did;
@@ -2911,7 +2783,7 @@ inscur_put(int argc, VALUE *argv, VALUE self)
2911
2783
  * Returns __self__.
2912
2784
  */
2913
2785
  static VALUE
2914
- inscur_flush(VALUE self)
2786
+ rb_inscur_flush(VALUE self)
2915
2787
  {
2916
2788
  cursor_t *c;
2917
2789
  EXEC SQL begin declare section;
@@ -2920,7 +2792,7 @@ inscur_flush(VALUE self)
2920
2792
 
2921
2793
  Data_Get_Struct(self, cursor_t, c);
2922
2794
  if (!c->is_open)
2923
- rb_raise(esyms.eProgrammingError, "Open the cursor object first");
2795
+ rb_raise(rb_eProgrammingError, "Open the cursor object first");
2924
2796
 
2925
2797
  did = c->database_id;
2926
2798
  EXEC SQL set connection :did;
@@ -2932,18 +2804,19 @@ inscur_flush(VALUE self)
2932
2804
  return self;
2933
2805
  }
2934
2806
 
2935
- /* module ScrollCursor --------------------------------------------------- */
2807
+ /* class ScrollCursor --------------------------------------------------- */
2936
2808
 
2937
2809
  /*
2938
2810
  * Provides the Array-like functionality for scroll cursors when using the
2939
2811
  * cursor[index] syntax
2940
2812
  */
2941
2813
  static VALUE
2942
- scrollcur_entry(VALUE self, VALUE index, VALUE type, int bang)
2814
+ rb_scrollcur_entry(VALUE self, VALUE index, VALUE type, VALUE bang)
2943
2815
  {
2944
2816
  cursor_t *c;
2945
2817
  struct sqlda *output;
2946
2818
  VALUE record;
2819
+ short c_bang;
2947
2820
  EXEC SQL begin declare section;
2948
2821
  char *cid, *did;
2949
2822
  long pos;
@@ -2951,7 +2824,7 @@ scrollcur_entry(VALUE self, VALUE index, VALUE type, int bang)
2951
2824
 
2952
2825
  Data_Get_Struct(self, cursor_t, c);
2953
2826
  if (!c->is_open)
2954
- rb_raise(esyms.eProgrammingError, "Open the cursor object first");
2827
+ rb_raise(rb_eProgrammingError, "Open the cursor object first");
2955
2828
 
2956
2829
  did = c->database_id;
2957
2830
  EXEC SQL set connection :did;
@@ -2976,148 +2849,21 @@ scrollcur_entry(VALUE self, VALUE index, VALUE type, int bang)
2976
2849
  if (SQLCODE < 0)
2977
2850
  raise_ifx_extended();
2978
2851
 
2979
- RECORD(c, type, bang, record);
2852
+ c_bang = RTEST(bang);
2853
+ RECORD(c, type, c_bang, record);
2980
2854
  return make_result(c, record);
2981
2855
  }
2982
2856
 
2983
- /*
2984
- * Provides the Array-like functionality for scroll cursors when using the
2985
- * cursor[start, length] syntax
2986
- */
2987
- static VALUE
2988
- scrollcur_subseq(VALUE self, VALUE start, VALUE length, VALUE type)
2989
- {
2990
- VALUE first, records;
2991
- EXEC SQL begin declare section;
2992
- long pos;
2993
- EXEC SQL end declare section;
2994
-
2995
- first = scrollcur_entry(self, start, type, 0);
2996
- if (NIL_P(first))
2997
- return Qnil;
2998
-
2999
- pos = NUM2LONG(length) - 1;
3000
-
3001
- if (pos > 0) {
3002
- length = LONG2NUM(pos);
3003
- records = fetch_many(self, length, type);
3004
- }
3005
- else
3006
- records = rb_ary_new();
3007
-
3008
- rb_ary_unshift(records, first);
3009
-
3010
- return records;
3011
- }
3012
-
3013
- /*
3014
- * Base function for slice and slice_hash methods
3015
- */
3016
- static VALUE
3017
- slice(int argc, VALUE *argv, VALUE self, VALUE type)
3018
- {
3019
- if (argc == 2) {
3020
- if (NUM2LONG(argv[1]) <= 0)
3021
- rb_raise(rb_eArgError, "length must be positive");
3022
- return scrollcur_subseq(self, argv[0], argv[1], type);
3023
- }
3024
- if (argc != 1)
3025
- rb_scan_args(argc, argv, "11", 0, 0);
3026
-
3027
- return scrollcur_entry(self, argv[0], type, 0);
3028
- }
3029
-
3030
- /*
3031
- * call-seq:
3032
- * cursor[index] => array or nil
3033
- * cursor[start, length] => array or nil
3034
- * cursor.slice(index) => array or nil
3035
- * cursor.slice(start, length) => array or nil
3036
- *
3037
- * Returns the record at _index_, or returns a subarray starting at _start_
3038
- * and continuing for _length_ records. Negative indices count backward from
3039
- * the end of the cursor (-1 is the last element). Returns nil if the
3040
- * (starting) index is out of range.
3041
- *
3042
- * <b>Warning</b>: if the (starting) index is negative and out of range, the
3043
- * position in the cursor is set to the last record. Otherwise the current
3044
- * position in the cursor is preserved.
3045
- */
3046
- static VALUE
3047
- scrollcur_slice(int argc, VALUE *argv, VALUE self)
3048
- {
3049
- return slice(argc, argv, self, T_ARRAY);
3050
- }
3051
-
3052
- /*
3053
- * call-seq:
3054
- * cursor.slice!(index) => array or nil
3055
- *
3056
- * Returns the record at _index_. Negative indices count backward from
3057
- * the end of the cursor (-1 is the last element). Returns nil if the index
3058
- * is out of range.
3059
- *
3060
- * Stores the record fetched always in the same Array object.
3061
- *
3062
- * <b>Warning</b>: if the index is negative and out of range, the
3063
- * position in the cursor is set to the last record. Otherwise the current
3064
- * position in the cursor is preserved.
3065
- */
3066
- static VALUE
3067
- scrollcur_slice_bang(VALUE self, VALUE index)
3068
- {
3069
- return scrollcur_entry(self, index, T_ARRAY, 1);
3070
- }
3071
-
3072
- /*
3073
- * call-seq:
3074
- * cursor.slice_hash(index) => hash or nil
3075
- * cursor.slice_hash(start, length) => array or nil
3076
- *
3077
- * Returns the record at _index_, or returns a subarray starting at _start_
3078
- * and continuing for _length_ records. Negative indices count backward from
3079
- * the end of the cursor (-1 is the last element). Returns nil if the
3080
- * (starting) index is out of range.
3081
- *
3082
- * <b>Warning</b>: if the (starting) index is negative and out of range, the
3083
- * position in the cursor is set to the last record. Otherwise the current
3084
- * position in the cursor is preserved.
3085
- */
3086
- static VALUE
3087
- scrollcur_slice_hash(int argc, VALUE *argv, VALUE self)
3088
- {
3089
- return slice(argc, argv, self, T_HASH);
3090
- }
3091
-
3092
- /*
3093
- * call-seq:
3094
- * cursor.slice_hash!(index) => hash or nil
3095
- *
3096
- * Returns the record at _index_. Negative indices count backward from
3097
- * the end of the cursor (-1 is the last element). Returns nil if the index
3098
- * is out of range.
3099
- *
3100
- * Stores the record fetched always in the same Hash object.
3101
- *
3102
- * <b>Warning</b>: if the index is negative and out of range, the
3103
- * position in the cursor is set to the last record. Otherwise the current
3104
- * position in the cursor is preserved.
3105
- */
3106
- static VALUE
3107
- scrollcur_slice_hash_bang(VALUE self, VALUE index)
3108
- {
3109
- return scrollcur_entry(self, index, T_HASH, 1);
3110
- }
3111
-
3112
2857
  /*
3113
2858
  * Base function for prev* and next* methods
3114
2859
  */
3115
2860
  static VALUE
3116
- scrollcur_rel(int argc, VALUE *argv, VALUE self, int dir, VALUE type, int bang)
2861
+ rb_scrollcur_rel(VALUE self, VALUE offset, VALUE type, VALUE bang)
3117
2862
  {
2863
+ short c_bang;
3118
2864
  cursor_t *c;
3119
2865
  struct sqlda *output;
3120
- VALUE offset, record;
2866
+ VALUE record;
3121
2867
  EXEC SQL begin declare section;
3122
2868
  char *cid, *did;
3123
2869
  long pos;
@@ -3125,15 +2871,14 @@ scrollcur_rel(int argc, VALUE *argv, VALUE self, int dir, VALUE type, int bang)
3125
2871
 
3126
2872
  Data_Get_Struct(self, cursor_t, c);
3127
2873
  if (!c->is_open)
3128
- rb_raise(esyms.eProgrammingError, "Open the cursor object first");
2874
+ rb_raise(rb_eProgrammingError, "Open the cursor object first");
3129
2875
 
3130
2876
  did = c->database_id;
3131
2877
  EXEC SQL set connection :did;
3132
2878
  if (SQLCODE < 0)
3133
2879
  return Qnil;
3134
2880
 
3135
- rb_scan_args(argc, argv, "01", &offset);
3136
- pos = dir*(NIL_P(offset)? 1: NUM2LONG(offset));
2881
+ pos = NUM2LONG(offset);
3137
2882
 
3138
2883
  output = c->daOutput;
3139
2884
  cid = c->cursor_id;
@@ -3145,293 +2890,15 @@ scrollcur_rel(int argc, VALUE *argv, VALUE self, int dir, VALUE type, int bang)
3145
2890
  if (SQLCODE < 0)
3146
2891
  raise_ifx_extended();
3147
2892
 
3148
- RECORD(c, type, bang, record);
2893
+ c_bang = RTEST(bang);
2894
+ RECORD(c, type, c_bang, record);
3149
2895
  return make_result(c, record);
3150
2896
  }
3151
2897
 
3152
- /* call-seq:
3153
- * cursor.prev(offset = 1) => array or nil
3154
- *
3155
- * Returns the previous _offset_ th record. Negative indices count
3156
- * forward from the current position. Returns nil if the _offset_ is out of
3157
- * range.
3158
- */
3159
- static VALUE
3160
- scrollcur_prev(int argc, VALUE *argv, VALUE self)
3161
- {
3162
- return scrollcur_rel(argc, argv, self, -1, T_ARRAY, 0);
3163
- }
3164
-
3165
- /* call-seq:
3166
- * cursor.prev!(offset = 1) => array or nil
3167
- *
3168
- * Returns the previous _offset_ th record. Negative indices count
3169
- * forward from the current position. Returns nil if the _offset_ is out of
3170
- * range.
3171
- *
3172
- * Stores the record fetched always in the same Array object.
3173
- */
3174
- static VALUE
3175
- scrollcur_prev_bang(int argc, VALUE *argv, VALUE self)
3176
- {
3177
- return scrollcur_rel(argc, argv, self, -1, T_ARRAY, 1);
3178
- }
3179
-
3180
- /* call-seq:
3181
- * cursor.prev_hash(offset = 1) => hash or nil
3182
- *
3183
- * Returns the previous _offset_ th record. Negative indices count
3184
- * forward from the current position. Returns nil if the _offset_ is out of
3185
- * range.
3186
- */
3187
- static VALUE
3188
- scrollcur_prev_hash(int argc, VALUE *argv, VALUE self)
3189
- {
3190
- return scrollcur_rel(argc, argv, self, -1, T_HASH, 0);
3191
- }
3192
-
3193
- /* call-seq:
3194
- * cursor.prev_hash!(offset = 1) => hash or nil
3195
- *
3196
- * Returns the previous _offset_ th record. Negative indices count
3197
- * forward from the current position. Returns nil if the _offset_ is out of
3198
- * range.
3199
- *
3200
- * Stores the record fetched always in the same Hash object.
3201
- */
3202
- static VALUE
3203
- scrollcur_prev_hash_bang(int argc, VALUE *argv, VALUE self)
3204
- {
3205
- return scrollcur_rel(argc, argv, self, -1, T_HASH, 1);
3206
- }
3207
-
3208
- /* call-seq:
3209
- * cursor.next(offset = 1) => array or nil
3210
- *
3211
- * Returns the next _offset_ th record. Negative indices count
3212
- * backward from the current position. Returns nil if the _offset_ is out of
3213
- * range.
3214
- */
3215
- static VALUE
3216
- scrollcur_next(int argc, VALUE *argv, VALUE self)
3217
- {
3218
- return scrollcur_rel(argc, argv, self, 1, T_ARRAY, 0);
3219
- }
3220
-
3221
- /* call-seq:
3222
- * cursor.next!(offset = 1) => array or nil
3223
- *
3224
- * Returns the next _offset_ th record. Negative indices count
3225
- * backward from the current position. Returns nil if the _offset_ is out of
3226
- * range.
3227
- *
3228
- * Stores the record fetched always in the same Array object.
3229
- */
3230
- static VALUE
3231
- scrollcur_next_bang(int argc, VALUE *argv, VALUE self)
3232
- {
3233
- return scrollcur_rel(argc, argv, self, 1, T_ARRAY, 1);
3234
- }
3235
-
3236
- /* call-seq:
3237
- * cursor.next_hash(offset = 1) => hash or nil
3238
- *
3239
- * Returns the next _offset_ th record. Negative indices count
3240
- * backward from the current position. Returns nil if the _offset_ is out of
3241
- * range.
3242
- */
3243
- static VALUE
3244
- scrollcur_next_hash(int argc, VALUE *argv, VALUE self)
3245
- {
3246
- return scrollcur_rel(argc, argv, self, 1, T_HASH, 0);
3247
- }
3248
-
3249
- /* call-seq:
3250
- * cursor.next_hash!(offset = 1) => hash or nil
3251
- *
3252
- * Returns the next _offset_ th record. Negative indices count
3253
- * backward from the current position. Returns nil if the _offset_ is out of
3254
- * range.
3255
- *
3256
- * Stores the record fetched always in the same Hash object.
3257
- */
3258
- static VALUE
3259
- scrollcur_next_hash_bang(int argc, VALUE *argv, VALUE self)
3260
- {
3261
- return scrollcur_rel(argc, argv, self, 1, T_HASH, 1);
3262
- }
3263
-
3264
- /*
3265
- * call-seq:
3266
- * cursor.first => array or nil
3267
- *
3268
- * Returns the first record of the cursor. If the cursor is empty,
3269
- * returns nil.
3270
- */
3271
- static VALUE
3272
- scrollcur_first(VALUE self)
3273
- {
3274
- return scrollcur_entry(self, INT2FIX(0), T_ARRAY, 0);
3275
- }
3276
-
3277
- /*
3278
- * call-seq:
3279
- * cursor.first! => array or nil
3280
- *
3281
- * Returns the first record of the cursor. If the cursor is empty,
3282
- * returns nil.
3283
- *
3284
- * Stores the record fetched always in the same Array object.
3285
- */
3286
- static VALUE
3287
- scrollcur_first_bang(VALUE self)
3288
- {
3289
- return scrollcur_entry(self, INT2FIX(0), T_ARRAY, 1);
3290
- }
3291
-
3292
- /*
3293
- * call-seq:
3294
- * cursor.first_hash => hash or nil
3295
- *
3296
- * Returns the first record of the cursor. If the cursor is empty,
3297
- * returns nil.
3298
- */
3299
- static VALUE
3300
- scrollcur_first_hash(VALUE self)
3301
- {
3302
- return scrollcur_entry(self, INT2FIX(0), T_HASH, 0);
3303
- }
3304
-
3305
- /*
3306
- * call-seq:
3307
- * cursor.first_hash! => hash or nil
3308
- *
3309
- * Returns the first record of the cursor. If the cursor is empty,
3310
- * returns nil.
3311
- *
3312
- * Stores the record fetched always in the same Hash object.
3313
- */
3314
- static VALUE
3315
- scrollcur_first_hash_bang(VALUE self)
3316
- {
3317
- return scrollcur_entry(self, INT2FIX(0), T_HASH, 1);
3318
- }
2898
+ /* class CursorBase ------------------------------------------------------ */
3319
2899
 
3320
- /*
3321
- * call-seq:
3322
- * cursor.last => array or nil
3323
- *
3324
- * Returns the last record of the cursor. If the cursor is empty,
3325
- * returns nil.
3326
- */
3327
- static VALUE
3328
- scrollcur_last(VALUE self)
3329
- {
3330
- return scrollcur_entry(self, INT2FIX(-1), T_ARRAY, 0);
3331
- }
3332
-
3333
- /*
3334
- * call-seq:
3335
- * cursor.last! => array or nil
3336
- *
3337
- * Returns the last record of the cursor. If the cursor is empty,
3338
- * returns nil.
3339
- *
3340
- * Stores the record fetched always in the same Array object.
3341
- */
3342
- static VALUE
3343
- scrollcur_last_bang(VALUE self)
3344
- {
3345
- return scrollcur_entry(self, INT2FIX(-1), T_ARRAY, 1);
3346
- }
3347
-
3348
- /*
3349
- * call-seq:
3350
- * cursor.last_hash => hash or nil
3351
- *
3352
- * Returns the last record of the cursor. If the cursor is empty,
3353
- * returns nil.
3354
- */
3355
- static VALUE
3356
- scrollcur_last_hash(VALUE self)
3357
- {
3358
- return scrollcur_entry(self, INT2FIX(-1), T_HASH, 0);
3359
- }
3360
-
3361
- /*
3362
- * call-seq:
3363
- * cursor.last_hash! => hash or nil
3364
- *
3365
- * Returns the last record of the cursor. If the cursor is empty,
3366
- * returns nil.
3367
- *
3368
- * Stores the record fetched always in the same Hash object.
3369
- */
3370
- static VALUE
3371
- scrollcur_last_hash_bang(VALUE self)
3372
- {
3373
- return scrollcur_entry(self, INT2FIX(-1), T_HASH, 1);
3374
- }
3375
-
3376
- /*
3377
- * call-seq:
3378
- * cursor.current => array or nil
3379
- *
3380
- * Returns the current record of the cursor. If the cursor is empty,
3381
- * returns nil.
3382
- */
3383
- static VALUE
3384
- scrollcur_current(VALUE self)
3385
- {
3386
- return scrollcur_entry(self, Qnil, T_ARRAY, 0);
3387
- }
3388
-
3389
- /*
3390
- * call-seq:
3391
- * cursor.current! => array or nil
3392
- *
3393
- * Returns the current record of the cursor. If the cursor is empty,
3394
- * returns nil.
3395
- *
3396
- * Stores the record fetched always in the same Array object.
3397
- */
3398
- static VALUE
3399
- scrollcur_current_bang(VALUE self)
3400
- {
3401
- return scrollcur_entry(self, Qnil, T_ARRAY, 1);
3402
- }
3403
-
3404
- /*
3405
- * call-seq:
3406
- * cursor.current_hash => hash or nil
3407
- *
3408
- * Returns the current record of the cursor. If the cursor is empty,
3409
- * returns nil.
3410
- */
3411
- static VALUE
3412
- scrollcur_current_hash(VALUE self)
3413
- {
3414
- return scrollcur_entry(self, Qnil, T_HASH, 0);
3415
- }
3416
-
3417
- /*
3418
- * call-seq:
3419
- * cursor.current_hash! => hash or nil
3420
- *
3421
- * Returns the current record of the cursor. If the cursor is empty,
3422
- * returns nil.
3423
- *
3424
- * Stores the record fetched always in the same Hash object.
3425
- */
3426
- static VALUE
3427
- scrollcur_current_hash_bang(VALUE self)
3428
- {
3429
- return scrollcur_entry(self, Qnil, T_HASH, 1);
3430
- }
3431
-
3432
- /* class Cursor ---------------------------------------------------------- */
3433
2900
  static void
3434
- cursor_close_or_free(cursor_t *c, short op)
2901
+ cursorbase_close_or_free(cursor_t *c, short op)
3435
2902
  {
3436
2903
  EXEC SQL begin declare section;
3437
2904
  char *cid, *sid, *did;
@@ -3441,29 +2908,27 @@ cursor_close_or_free(cursor_t *c, short op)
3441
2908
  return;
3442
2909
 
3443
2910
  c->is_open = 0;
3444
- if (op == 1)
3445
- clean_input_slots(c);
3446
- else {
3447
- free_input_slots(c);
3448
- free_output_slots(c);
3449
- }
3450
-
3451
- did = c->database_id;
3452
- EXEC SQL set connection :did;
3453
- if (SQLCODE < 0)
3454
- return;
3455
-
3456
- cid = c->cursor_id;
3457
- EXEC SQL close :cid;
3458
2911
 
3459
- if (op == 2) {
3460
- sid = c->stmt_id;
3461
- EXEC SQL free :cid; EXEC SQL free :sid;
2912
+ switch(op) {
2913
+ case 1:
2914
+ clean_input_slots(c);
2915
+ case 2:
2916
+ did = c->database_id;
2917
+ EXEC SQL set connection :did;
2918
+ if (SQLCODE < 0)
2919
+ return;
2920
+ cid = c->cursor_id;
2921
+ EXEC SQL close :cid;
2922
+ if (op == 1)
2923
+ break;
2924
+ EXEC SQL free :cid;
2925
+ st_free(c);
2926
+ break;
3462
2927
  }
3463
2928
  }
3464
2929
 
3465
2930
  static void
3466
- cursor_mark(cursor_t *c)
2931
+ cursorbase_mark(cursor_t *c)
3467
2932
  {
3468
2933
  rb_gc_mark(c->db);
3469
2934
  if (c->array)
@@ -3475,166 +2940,20 @@ cursor_mark(cursor_t *c)
3475
2940
  }
3476
2941
 
3477
2942
  static void
3478
- cursor_free(void *p)
2943
+ cursorbase_free(void *p)
3479
2944
  {
3480
- cursor_close_or_free(p, 2);
2945
+ cursorbase_close_or_free(p, 2);
3481
2946
  xfree(p);
3482
2947
  }
3483
2948
 
3484
2949
  static VALUE
3485
- cursor_alloc(VALUE klass)
2950
+ cursorbase_alloc(VALUE klass)
3486
2951
  {
3487
2952
  cursor_t *c;
3488
2953
 
3489
2954
  c = ALLOC(cursor_t);
3490
2955
  memset(c, 0, sizeof(cursor_t));
3491
- return Data_Wrap_Struct(klass, cursor_mark, cursor_free, c);
3492
- }
3493
-
3494
- static VALUE
3495
- cursor_initialize(int argc, VALUE *argv, VALUE self)
3496
- {
3497
- VALUE db, query, options;
3498
- VALUE scroll, hold;
3499
- struct sqlda *output;
3500
- cursor_t *c;
3501
- EXEC SQL begin declare section;
3502
- char *c_query;
3503
- char *cid, *sid, *did;
3504
- EXEC SQL end declare section;
3505
-
3506
- rb_scan_args(argc, argv, "21", &db, &query, &options);
3507
- Data_Get_Struct(db, char, did);
3508
-
3509
- EXEC SQL set connection :did;
3510
- if (SQLCODE < 0)
3511
- raise_ifx_extended();
3512
-
3513
- Data_Get_Struct(self, cursor_t, c);
3514
- c->db = db;
3515
- c->database_id = did;
3516
- scroll = hold = Qfalse;
3517
- snprintf(c->cursor_id, sizeof(c->cursor_id), "CUR%lX", self);
3518
- snprintf(c->stmt_id, sizeof(c->stmt_id), "STMT%lX", self);
3519
- cid = c->cursor_id; sid = c->stmt_id;
3520
- c_query = StringValueCStr(query);
3521
-
3522
- if (!NIL_P(options)) {
3523
- Check_Type(options, T_HASH);
3524
- scroll = rb_hash_aref(options, sym_scroll);
3525
- hold = rb_hash_aref(options, sym_hold);
3526
- }
3527
-
3528
- EXEC SQL prepare :sid from :c_query;
3529
- if (SQLCODE < 0)
3530
- raise_ifx_extended();
3531
-
3532
- if (RTEST(scroll) && RTEST(hold))
3533
- EXEC SQL declare :cid scroll cursor with hold for :sid;
3534
- else if (RTEST(hold))
3535
- EXEC SQL declare :cid cursor with hold for :sid;
3536
- else if (RTEST(scroll))
3537
- EXEC SQL declare :cid scroll cursor for :sid;
3538
- else
3539
- EXEC SQL declare :cid cursor for :sid;
3540
-
3541
- if (SQLCODE < 0)
3542
- raise_ifx_extended();
3543
-
3544
- alloc_input_slots(c, c_query);
3545
- EXEC SQL describe :sid into output;
3546
- c->daOutput = output;
3547
-
3548
- c->is_select = (SQLCODE == 0 || SQLCODE == SQ_EXECPROC);
3549
-
3550
- if (c->is_select) {
3551
- alloc_output_slots(c);
3552
- rb_extend_object(self, rb_mSequentialCursor);
3553
- if (scroll)
3554
- rb_extend_object(self, rb_mScrollCursor);
3555
- }
3556
- else {
3557
- xfree(c->daOutput);
3558
- c->daOutput = NULL;
3559
- rb_extend_object(self, rb_mInsertCursor);
3560
- }
3561
- return self;
3562
- }
3563
-
3564
- static VALUE cursor_drop(VALUE self);
3565
- /*
3566
- * call-seq:
3567
- * Cursor.new(database, query, options) => cursor
3568
- * Cursor.new(database, query, options) {|cursor| block } => obj
3569
- *
3570
- * Creates a Cursor object based on <i>query</i> using <i>options</i>
3571
- * in the context of <i>database</i> but does not open it.
3572
- * In the first form the Cursor object is returned.
3573
- * In the second form the Cursor object is passed to the block and when it
3574
- * terminates, the Cursor object is dropped, returning the value of the block.
3575
- *
3576
- * <i>options</i> can be nil or a Hash object with the following possible keys:
3577
- *
3578
- * :scroll => true or false
3579
- * :hold => true or false
3580
- */
3581
- static VALUE
3582
- rb_cursor_s_new(int argc, VALUE *argv, VALUE klass)
3583
- {
3584
- VALUE cursor;
3585
-
3586
- cursor = rb_class_new_instance(argc, argv, klass);
3587
-
3588
- if (rb_block_given_p())
3589
- return rb_ensure(rb_yield, cursor, cursor_drop, cursor);
3590
-
3591
- return cursor;
3592
- }
3593
-
3594
- static VALUE cursor_open(int argc, VALUE *argv, VALUE self);
3595
- /*
3596
- * call-seq:
3597
- * Cursor.open(database, query, options) => cursor
3598
- * Cursor.open(database, query, options) {|cursor| block } => obj
3599
- *
3600
- * Creates and opens a Cursor object based on <i>query</i> using <i>options</i>
3601
- * in the context of <i>database</i>.
3602
- * In the first form the Cursor object is returned.
3603
- * In the second form the Cursor object is passed to the block and when it
3604
- * terminates, the Cursor object is dropped, returning the value of the block.
3605
- *
3606
- * <i>options</i> can be nil or a Hash object with the following possible keys:
3607
- *
3608
- * :scroll => true or false
3609
- * :hold => true or false
3610
- * :params => input parameters as an Array or nil
3611
- */
3612
- static VALUE
3613
- cursor_s_open(int argc, VALUE *argv, VALUE klass)
3614
- {
3615
- VALUE cursor, options, params;
3616
- int open_argc;
3617
-
3618
- rb_scan_args(argc, argv, "21", 0, 0, &options);
3619
- open_argc = 0; params = Qnil;
3620
-
3621
- if (!NIL_P(options)) {
3622
- Check_Type(options, T_HASH);
3623
- params = rb_hash_aref(options, sym_params);
3624
-
3625
- if (TYPE(params) == T_ARRAY)
3626
- open_argc = RARRAY(params)->len;
3627
- else if (params != Qnil)
3628
- rb_raise(rb_eArgError, "Parameters must be supplied as an Array");
3629
- }
3630
-
3631
- cursor = rb_class_new_instance(argc, argv, klass);
3632
- cursor_open(open_argc, &params, cursor);
3633
-
3634
- if (rb_block_given_p())
3635
- return rb_ensure(rb_yield, cursor, cursor_drop, cursor);
3636
-
3637
- return cursor;
2956
+ return Data_Wrap_Struct(klass, cursorbase_mark, cursorbase_free, c);
3638
2957
  }
3639
2958
 
3640
2959
  /*
@@ -3644,7 +2963,7 @@ cursor_s_open(int argc, VALUE *argv, VALUE klass)
3644
2963
  * Returns the cursor ID
3645
2964
  */
3646
2965
  static VALUE
3647
- cursor_id(VALUE self)
2966
+ rb_cursorbase_id(VALUE self)
3648
2967
  {
3649
2968
  cursor_t *c;
3650
2969
 
@@ -3662,7 +2981,7 @@ cursor_id(VALUE self)
3662
2981
  * Returns __self__.
3663
2982
  */
3664
2983
  static VALUE
3665
- cursor_open(int argc, VALUE *argv, VALUE self)
2984
+ rb_cursorbase_open(int argc, VALUE *argv, VALUE self)
3666
2985
  {
3667
2986
  struct sqlda *input;
3668
2987
  cursor_t *c;
@@ -3714,12 +3033,12 @@ cursor_open(int argc, VALUE *argv, VALUE self)
3714
3033
  * Closes the cursor and returns __self__.
3715
3034
  */
3716
3035
  static VALUE
3717
- cursor_close(VALUE self)
3036
+ rb_cursorbase_close(VALUE self)
3718
3037
  {
3719
3038
  cursor_t *c;
3720
3039
 
3721
3040
  Data_Get_Struct(self, cursor_t, c);
3722
- cursor_close_or_free(c, 1);
3041
+ cursorbase_close_or_free(c, 1);
3723
3042
  return self;
3724
3043
  }
3725
3044
 
@@ -3731,39 +3050,153 @@ cursor_close(VALUE self)
3731
3050
  * cannot be opened again.
3732
3051
  */
3733
3052
  static VALUE
3734
- cursor_drop(VALUE self)
3053
+ rb_cursorbase_drop(VALUE self)
3735
3054
  {
3736
3055
  cursor_t *c;
3737
3056
 
3738
3057
  Data_Get_Struct(self, cursor_t, c);
3739
- cursor_close_or_free(c, 2);
3058
+ cursorbase_close_or_free(c, 2);
3740
3059
 
3741
3060
  return Qnil;
3742
3061
  }
3743
3062
 
3744
- /* Entry point ------------------------------------------------------------ */
3063
+ /* module Cursor --------------------------------------------------------- */
3745
3064
 
3746
- void Init_informix(void)
3065
+ /*
3066
+ * The underlying class method that prepares a cursor and creates
3067
+ * the respective cursor object.
3068
+ */
3069
+ static VALUE
3070
+ rb_cursor_s_new0(int argc, VALUE *argv, VALUE self)
3747
3071
  {
3748
- /* module Informix ---------------------------------------------------- */
3072
+ VALUE db, query, options, ret;
3073
+ VALUE scroll, hold;
3074
+ struct sqlda *output;
3075
+ cursor_t c, *cur;
3076
+ EXEC SQL begin declare section;
3077
+ char *c_query;
3078
+ char *cid, *sid, *did;
3079
+ EXEC SQL end declare section;
3080
+
3081
+ memset(&c, 0, sizeof(c));
3082
+ rb_scan_args(argc, argv, "21", &db, &query, &options);
3083
+ Data_Get_Struct(db, char, did);
3084
+
3085
+ EXEC SQL set connection :did;
3086
+ if (SQLCODE < 0)
3087
+ raise_ifx_extended();
3088
+
3089
+ c.db = db;
3090
+ c.database_id = did;
3091
+ scroll = hold = Qfalse;
3092
+ snprintf(c.cursor_id, sizeof(c.cursor_id), "CUR%lX", self);
3093
+ snprintf(c.stmt_id, sizeof(c.stmt_id), "STMT%lX", self);
3094
+ cid = c.cursor_id; sid = c.stmt_id;
3095
+ c_query = StringValueCStr(query);
3096
+
3097
+ if (!NIL_P(options)) {
3098
+ Check_Type(options, T_HASH);
3099
+ scroll = rb_hash_aref(options, sym_scroll);
3100
+ hold = rb_hash_aref(options, sym_hold);
3101
+ }
3102
+
3103
+ EXEC SQL prepare :sid from :c_query;
3104
+ if (SQLCODE < 0)
3105
+ raise_ifx_extended();
3106
+
3107
+ if (RTEST(scroll) && RTEST(hold))
3108
+ EXEC SQL declare :cid scroll cursor with hold for :sid;
3109
+ else if (RTEST(hold))
3110
+ EXEC SQL declare :cid cursor with hold for :sid;
3111
+ else if (RTEST(scroll))
3112
+ EXEC SQL declare :cid scroll cursor for :sid;
3113
+ else
3114
+ EXEC SQL declare :cid cursor for :sid;
3115
+
3116
+ if (SQLCODE < 0)
3117
+ raise_ifx_extended();
3118
+
3119
+ alloc_input_slots(&c, c_query);
3120
+ EXEC SQL describe :sid into output;
3121
+ c.daOutput = output;
3122
+
3123
+ c.is_select = (SQLCODE == 0 || SQLCODE == SQ_EXECPROC);
3124
+
3125
+ if (c.is_select) {
3126
+ alloc_output_slots(&c);
3127
+ if (scroll)
3128
+ ret = cursorbase_alloc(rb_cScrollCursor);
3129
+ else
3130
+ ret = cursorbase_alloc(rb_cSequentialCursor);
3131
+ }
3132
+ else {
3133
+ xfree(c.daOutput);
3134
+ c.daOutput = NULL;
3135
+ ret = cursorbase_alloc(rb_cInsertCursor);
3136
+ }
3137
+ Data_Get_Struct(ret, cursor_t, cur);
3138
+ memcpy(cur, &c, sizeof(cursor_t));
3139
+
3140
+ return ret;
3141
+ }
3142
+
3143
+ void Init_informixc(void)
3144
+ {
3145
+ /*
3146
+ * The +Informix+ module contains the mechanisms for connecting to and
3147
+ * taking advantage of an existing Informix database by means of a
3148
+ * simple model, similar to the one used in ESQL/C.
3149
+ *
3150
+ * The interaction with an Informix database is made basically through three
3151
+ * classes: +Database+, +Statement+ and +Cursor+.
3152
+ *
3153
+ * +Cursor+ is actually a module that works as a shortcut for creating three
3154
+ * kinds of cursors: +SequentialCursor+, +ScrollCursor+ and +InsertCursor+.
3155
+ *
3156
+ * There are other classes for supporting some data types not available in
3157
+ * Ruby: +Slob+, +SlobStat+ and +Interval+.
3158
+ *
3159
+ * Again, +Interval+ is actually a module that works as a shortcut for
3160
+ * creating two kinds of intervals: +IntervalYTM+ and +IntervalDTS+.
3161
+ */
3749
3162
  rb_mInformix = rb_define_module("Informix");
3750
- rb_mScrollCursor = rb_define_module_under(rb_mInformix, "ScrollCursor");
3751
- rb_mInsertCursor = rb_define_module_under(rb_mInformix, "InsertCursor");
3752
- rb_define_module_function(rb_mInformix, "connect", rb_informix_connect, -1);
3753
- rb_define_module_function(rb_mInformix, "version", rb_informix_version, 0);
3754
3163
 
3755
- /* class Slob --------------------------------------------------------- */
3164
+ /*
3165
+ * The +Slob+ class is the Ruby interface for handling Smart Large Objects.
3166
+ * It provides methods for every action applicable to an SLOB.
3167
+ *
3168
+ * Examples:
3169
+ *
3170
+ * # Storing BLOBs read from files
3171
+ * Slob = Informix::Slob
3172
+ * db.execute("create table album (filename varchar(30), picture blob)")
3173
+ * st = db.prepare("insert into album values(?, ?)")
3174
+ * Dir.glob("*jpg") do |filename|
3175
+ * slob = db.slob(Slob::BLOB)
3176
+ * slob.write(File.read(filename)) # same as slob <<File.read(filename)
3177
+ * slob.close
3178
+ * st.execute(filename, slob)
3179
+ * end
3180
+ *
3181
+ *
3182
+ * # Retrieving BLOBs and writing them to files
3183
+ * db.each_hash("select filename, picture from album") do |r|
3184
+ * slob = r['picture'].open
3185
+ * File.open(r['filename'], "w") do |f|
3186
+ * f.write r['picture'].read(r['picture'].size)
3187
+ * end
3188
+ * slob.close
3189
+ * end
3190
+ */
3756
3191
  rb_cSlob = rb_define_class_under(rb_mInformix, "Slob", rb_cObject);
3757
3192
  rb_define_alloc_func(rb_cSlob, slob_alloc);
3758
3193
  rb_define_method(rb_cSlob, "initialize", rb_slob_initialize, -1);
3759
- rb_define_singleton_method(rb_cSlob, "new", rb_slob_s_new, -1);
3760
3194
  rb_define_method(rb_cSlob, "open", rb_slob_open, -1);
3761
3195
  rb_define_method(rb_cSlob, "close", rb_slob_close, 0);
3762
3196
  rb_define_method(rb_cSlob, "read", rb_slob_read, 1);
3763
3197
  rb_define_method(rb_cSlob, "write", rb_slob_write, 1);
3764
3198
  rb_define_method(rb_cSlob, "seek", rb_slob_seek, 2);
3765
3199
  rb_define_method(rb_cSlob, "tell", rb_slob_tell, 0);
3766
- rb_define_alias(rb_cSlob, "pos", "tell");
3767
3200
  rb_define_method(rb_cSlob, "pos=", rb_slob_set_pos, 1);
3768
3201
  rb_define_method(rb_cSlob, "truncate", rb_slob_truncate, 1);
3769
3202
  rb_define_method(rb_cSlob, "stat", rb_slob_stat, 0);
@@ -3790,38 +3223,38 @@ void Init_informix(void)
3790
3223
  rb_define_const(rb_cSlob, "CLOB", INT2FIX(XID_CLOB));
3791
3224
  rb_define_const(rb_cSlob, "BLOB", INT2FIX(XID_BLOB));
3792
3225
 
3793
- #define DEF_SLOB_CONST(k) rb_define_const(rb_cSlob, #k, INT2FIX(LO_##k))
3794
-
3795
- /* Access modes */
3796
- DEF_SLOB_CONST(RDONLY);
3797
- DEF_SLOB_CONST(DIRTY_READ);
3798
- DEF_SLOB_CONST(WRONLY);
3799
- DEF_SLOB_CONST(APPEND);
3800
- DEF_SLOB_CONST(RDWR);
3801
- DEF_SLOB_CONST(BUFFER);
3802
- DEF_SLOB_CONST(NOBUFFER);
3803
- DEF_SLOB_CONST(LOCKALL);
3804
- DEF_SLOB_CONST(LOCKRANGE);
3805
- DEF_SLOB_CONST(SEEK_SET);
3806
- DEF_SLOB_CONST(SEEK_CUR);
3807
- DEF_SLOB_CONST(SEEK_END);
3226
+ /* Access modes */
3227
+ rb_define_const(rb_cSlob, "RDONLY", INT2FIX(LO_RDONLY));
3228
+ rb_define_const(rb_cSlob, "DIRTY_READ", INT2FIX(LO_DIRTY_READ));
3229
+ rb_define_const(rb_cSlob, "WRONLY", INT2FIX(LO_WRONLY));
3230
+ rb_define_const(rb_cSlob, "APPEND", INT2FIX(LO_APPEND));
3231
+ rb_define_const(rb_cSlob, "RDWR", INT2FIX(LO_RDWR));
3232
+ rb_define_const(rb_cSlob, "BUFFER", INT2FIX(LO_BUFFER));
3233
+ rb_define_const(rb_cSlob, "NOBUFFER", INT2FIX(LO_NOBUFFER));
3234
+ rb_define_const(rb_cSlob, "LOCKALL", INT2FIX(LO_LOCKALL));
3235
+ rb_define_const(rb_cSlob, "LOCKRANGE", INT2FIX(LO_LOCKRANGE));
3236
+ rb_define_const(rb_cSlob, "SEEK_SET", INT2FIX(LO_SEEK_SET));
3237
+ rb_define_const(rb_cSlob, "SEEK_CUR", INT2FIX(LO_SEEK_CUR));
3238
+ rb_define_const(rb_cSlob, "SEEK_END", INT2FIX(LO_SEEK_END));
3808
3239
 
3809
3240
  /* Creation-time flags */
3810
- DEF_SLOB_CONST(LOG);
3811
- DEF_SLOB_CONST(NOLOG);
3812
- DEF_SLOB_CONST(KEEP_LASTACCESS_TIME);
3813
- DEF_SLOB_CONST(NOKEEP_LASTACCESS_TIME);
3241
+ rb_define_const(rb_cSlob, "LOG", INT2FIX(LO_LOG));
3242
+ rb_define_const(rb_cSlob, "NOLOG", INT2FIX(LO_NOLOG));
3243
+ rb_define_const(rb_cSlob, "KEEP_LASTACCESS_TIME", INT2FIX(LO_KEEP_LASTACCESS_TIME));
3244
+ rb_define_const(rb_cSlob, "NOKEEP_LASTACCESS_TIME", INT2FIX(LO_NOKEEP_LASTACCESS_TIME));
3814
3245
 
3815
3246
  /* Ranges */
3816
- DEF_SLOB_CONST(CURRENT_END);
3817
- DEF_SLOB_CONST(MAX_END);
3247
+ rb_define_const(rb_cSlob, "CURRENT_END", INT2FIX(LO_CURRENT_END));
3248
+ rb_define_const(rb_cSlob, "MAX_END", INT2FIX(LO_MAX_END));
3818
3249
 
3819
3250
  /* Lock modes */
3820
- DEF_SLOB_CONST(SHARED_MODE);
3821
- DEF_SLOB_CONST(EXCLUSIVE_MODE);
3822
-
3823
- /* class Slob::Stat --------------------------------------------------- */
3251
+ rb_define_const(rb_cSlob, "SHARED_MODE", INT2FIX(LO_SHARED_MODE));
3252
+ rb_define_const(rb_cSlob, "EXCLUSIVE_MODE", INT2FIX(LO_EXCLUSIVE_MODE));
3824
3253
 
3254
+ /*
3255
+ * An instance of the <tt>Slob::Stat</tt> class is returned when an Slob
3256
+ * is queried about its status information (<tt>Slob#stat</tt>).
3257
+ */
3825
3258
  rb_cSlobStat = rb_define_class_under(rb_cSlob, "Stat", rb_cObject);
3826
3259
  rb_define_alloc_func(rb_cSlobStat, slobstat_alloc);
3827
3260
  rb_define_method(rb_cSlobStat, "initialize", rb_slobstat_initialize, 1);
@@ -3835,106 +3268,122 @@ void Init_informix(void)
3835
3268
  rb_define_method(rb_cSlobStat, "refcnt", rb_slobstat_refcnt, 0);
3836
3269
  rb_define_method(rb_cSlobStat, "size", rb_slobstat_size, 0);
3837
3270
 
3838
- /* class Database ----------------------------------------------------- */
3271
+ /*
3272
+ * The +Database+ class lets you open a connection to an existing database
3273
+ * (usually done with <tt>Informix.connect</tt>) and provides shortcuts for
3274
+ * creating +Cursor+, +Statement+ and +Slob+ objects, among other database
3275
+ * actions.
3276
+ */
3839
3277
  rb_cDatabase = rb_define_class_under(rb_mInformix, "Database", rb_cObject);
3840
3278
  rb_define_alloc_func(rb_cDatabase, database_alloc);
3841
3279
  rb_define_method(rb_cDatabase, "initialize", rb_database_initialize, -1);
3842
- rb_define_singleton_method(rb_cDatabase, "open", rb_database_s_open, -1);
3843
- rb_define_alias(rb_cDatabase, "new", "open");
3844
3280
  rb_define_method(rb_cDatabase, "close", rb_database_close, 0);
3845
- rb_define_alias(rb_cDatabase, "disconnect", "close");
3846
3281
  rb_define_method(rb_cDatabase, "immediate", rb_database_immediate, 1);
3847
- rb_define_alias(rb_cDatabase, "do", "immediate");
3848
- rb_define_alias(rb_cDatabase, "execute", "immediate");
3849
3282
  rb_define_method(rb_cDatabase, "rollback", rb_database_rollback, 0);
3850
3283
  rb_define_method(rb_cDatabase, "commit", rb_database_commit, 0);
3851
3284
  rb_define_method(rb_cDatabase, "transaction", rb_database_transaction, 0);
3852
- rb_define_method(rb_cDatabase, "prepare", rb_database_prepare, 1);
3853
3285
  rb_define_method(rb_cDatabase, "columns", rb_database_columns, 1);
3854
- rb_define_method(rb_cDatabase, "cursor", rb_database_cursor, -1);
3855
- rb_define_method(rb_cDatabase, "slob", rb_database_slob, -1);
3856
3286
 
3857
- /* class Statement ---------------------------------------------------- */
3858
- rb_cStatement = rb_define_class_under(rb_mInformix, "Statement", rb_cObject);
3287
+ rb_define_const(rb_cDatabase, "IfxVersion",
3288
+ rb_struct_define("IfxVersion", "server_type", "major",
3289
+ "minor", "level", "os", "full", NULL));
3290
+ rb_cIfxVersion = rb_const_get(rb_cDatabase, rb_intern("IfxVersion"));
3291
+
3292
+ /*
3293
+ * The +Statement+ class lets you prepare and execute any SQL statement,
3294
+ * (usually done with <tt>Database#prepare</tt>)
3295
+ * paremeterized or not, that does not return records. This includes
3296
+ * DDL (CREATE, DROP, ALTER), DCL (GRANT, REVOKE) and DML (INSERT, UPDATE,
3297
+ * DELETE) statements, and SELECTs that return <b>only one</b> record at
3298
+ * most.
3299
+ *
3300
+ * To retrieve more than one record, use a +Cursor+ instead.
3301
+ */
3302
+ rb_cStatement = rb_define_class_under(rb_mInformix, "Statement",rb_cObject);
3859
3303
  rb_define_alloc_func(rb_cStatement, statement_alloc);
3860
- rb_define_method(rb_cStatement, "initialize", statement_initialize, 2);
3861
- rb_define_singleton_method(rb_cStatement, "new", statement_s_new, -1);
3862
- rb_define_method(rb_cStatement, "[]", statement_call, -1);
3863
- rb_define_alias(rb_cStatement, "call", "[]");
3864
- rb_define_alias(rb_cStatement, "execute", "[]");
3865
- rb_define_method(rb_cStatement, "drop", statement_drop, 0);
3866
-
3867
- /* module SequentialCursor -------------------------------------------- */
3868
- rb_mSequentialCursor = rb_define_module_under(rb_mInformix, "SequentialCursor");
3869
- rb_define_method(rb_mSequentialCursor, "fetch", seqcur_fetch, 0);
3870
- rb_define_method(rb_mSequentialCursor, "fetch!", seqcur_fetch_bang, 0);
3871
- rb_define_method(rb_mSequentialCursor, "fetch_hash", seqcur_fetch_hash, 0);
3872
- rb_define_method(rb_mSequentialCursor, "fetch_hash!", seqcur_fetch_hash_bang, 0);
3873
- rb_define_method(rb_mSequentialCursor, "fetch_many", seqcur_fetch_many, 1);
3874
- rb_define_method(rb_mSequentialCursor, "fetch_hash_many", seqcur_fetch_hash_many, 1);
3875
- rb_define_method(rb_mSequentialCursor, "fetch_all", seqcur_fetch_all, 0);
3876
- rb_define_method(rb_mSequentialCursor, "fetch_hash_all", seqcur_fetch_hash_all, 0);
3877
- rb_define_method(rb_mSequentialCursor, "each", seqcur_each, 0);
3878
- rb_define_method(rb_mSequentialCursor, "each!", seqcur_each_bang, 0);
3879
- rb_define_method(rb_mSequentialCursor, "each_hash", seqcur_each_hash, 0);
3880
- rb_define_method(rb_mSequentialCursor, "each_hash!", seqcur_each_hash_bang, 0);
3881
- rb_define_method(rb_mSequentialCursor, "each_by", seqcur_each_by, 1);
3882
- rb_define_method(rb_mSequentialCursor, "each_hash_by", seqcur_each_hash_by, 1);
3883
-
3884
- /* InsertCursor ------------------------------------------------------- */
3885
- rb_define_method(rb_mInsertCursor, "put", inscur_put, -1);
3886
- rb_define_method(rb_mInsertCursor, "flush", inscur_flush, 0);
3887
-
3888
- /* ScrollCursor ------------------------------------------------------- */
3889
- rb_define_method(rb_mScrollCursor, "[]", scrollcur_slice, -1);
3890
- rb_define_alias(rb_mScrollCursor, "slice", "[]");
3891
- rb_define_method(rb_mScrollCursor, "slice!", scrollcur_slice_bang, 1);
3892
- rb_define_method(rb_mScrollCursor, "slice_hash", scrollcur_slice_hash, -1);
3893
- rb_define_method(rb_mScrollCursor, "slice_hash!", scrollcur_slice_hash_bang, 1);
3894
- rb_define_method(rb_mScrollCursor, "prev", scrollcur_prev, -1);
3895
- rb_define_method(rb_mScrollCursor, "prev!", scrollcur_prev_bang, -1);
3896
- rb_define_method(rb_mScrollCursor, "prev_hash", scrollcur_prev_hash, -1);
3897
- rb_define_method(rb_mScrollCursor, "prev_hash!", scrollcur_prev_hash_bang, -1);
3898
- rb_define_method(rb_mScrollCursor, "next", scrollcur_next, -1);
3899
- rb_define_method(rb_mScrollCursor, "next!", scrollcur_next_bang, -1);
3900
- rb_define_method(rb_mScrollCursor, "next_hash", scrollcur_next_hash, -1);
3901
- rb_define_method(rb_mScrollCursor, "next_hash!", scrollcur_next_hash_bang, -1);
3902
- rb_define_method(rb_mScrollCursor, "first", scrollcur_first, 0);
3903
- rb_define_method(rb_mScrollCursor, "first!", scrollcur_first_bang, 0);
3904
- rb_define_method(rb_mScrollCursor, "first_hash", scrollcur_first_hash, 0);
3905
- rb_define_method(rb_mScrollCursor, "first_hash!", scrollcur_first_hash_bang, 0);
3906
- rb_define_method(rb_mScrollCursor, "last", scrollcur_last, 0);
3907
- rb_define_method(rb_mScrollCursor, "last!", scrollcur_last_bang, 0);
3908
- rb_define_method(rb_mScrollCursor, "last_hash", scrollcur_last_hash, 0);
3909
- rb_define_method(rb_mScrollCursor, "last_hash!", scrollcur_last_hash_bang, 0);
3910
- rb_define_method(rb_mScrollCursor, "current", scrollcur_current, 0);
3911
- rb_define_method(rb_mScrollCursor, "current!", scrollcur_current_bang, 0);
3912
- rb_define_method(rb_mScrollCursor, "current_hash", scrollcur_current_hash, 0);
3913
- rb_define_method(rb_mScrollCursor, "current_hash!", scrollcur_current_hash_bang, 0);
3914
-
3915
- /* class Cursor ------------------------------------------------------- */
3916
- rb_cCursor = rb_define_class_under(rb_mInformix, "Cursor", rb_cObject);
3917
- rb_define_alloc_func(rb_cCursor, cursor_alloc);
3918
- rb_define_method(rb_cCursor, "initialize", cursor_initialize, -1);
3919
- rb_define_singleton_method(rb_cCursor, "new", rb_cursor_s_new, -1);
3920
- rb_define_singleton_method(rb_cCursor, "open", cursor_s_open, -1);
3921
- rb_define_method(rb_cCursor, "id", cursor_id, 0);
3922
- rb_define_method(rb_cCursor, "open", cursor_open, -1);
3923
- rb_define_method(rb_cCursor, "close", cursor_close, 0);
3924
- rb_define_method(rb_cCursor, "drop", cursor_drop, 0);
3304
+ rb_define_method(rb_cStatement, "initialize", rb_statement_initialize, 2);
3305
+ rb_define_method(rb_cStatement, "[]", rb_statement_call, -1);
3306
+ rb_define_method(rb_cStatement, "drop", rb_statement_drop, 0);
3307
+
3308
+ /*
3309
+ * The +CursorBase+ class provides the basic functionality for any cursor.
3310
+ */
3311
+ rb_cCursorBase=rb_define_class_under(rb_mInformix,"CursorBase",rb_cObject);
3312
+ rb_define_alloc_func(rb_cCursorBase, cursorbase_alloc);
3313
+ rb_define_method(rb_cCursorBase, "id", rb_cursorbase_id, 0);
3314
+ rb_define_method(rb_cCursorBase, "open", rb_cursorbase_open, -1);
3315
+ rb_define_method(rb_cCursorBase, "close", rb_cursorbase_close, 0);
3316
+ rb_define_method(rb_cCursorBase, "drop", rb_cursorbase_drop, 0);
3317
+
3318
+ /*
3319
+ * The +SequentialCursor+ class adds fetching capabilities and iterators
3320
+ * to the +CursorBase+ class.
3321
+ */
3322
+ rb_cSequentialCursor = rb_define_class_under(rb_mInformix, "SequentialCursor", rb_cCursorBase);
3323
+ rb_define_private_method(rb_cSequentialCursor, "fetch0", fetch, 2);
3324
+ rb_define_private_method(rb_cSequentialCursor, "fetch_many0", fetch_many,2);
3325
+ rb_define_private_method(rb_cSequentialCursor, "each0", each, 2);
3326
+ rb_define_private_method(rb_cSequentialCursor, "each_by0", each_by, 2);
3327
+
3328
+ /*
3329
+ * The +InsertCursor+ class adds insertion capabilities to the +CursorBase+
3330
+ * class.
3331
+ */
3332
+ rb_cInsertCursor = rb_define_class_under(rb_mInformix, "InsertCursor", rb_cCursorBase);
3333
+ rb_define_method(rb_cInsertCursor, "put", rb_inscur_put, -1);
3334
+ rb_define_method(rb_cInsertCursor, "flush", rb_inscur_flush, 0);
3335
+
3336
+ /*
3337
+ * The +ScrollCursor+ class adds +Array+-like capabilities to the
3338
+ * +SequentialCursor+ class
3339
+ */
3340
+ rb_cScrollCursor = rb_define_class_under(rb_mInformix, "ScrollCursor", rb_cSequentialCursor);
3341
+ rb_define_private_method(rb_cScrollCursor, "entry", rb_scrollcur_entry, 3);
3342
+ rb_define_private_method(rb_cScrollCursor, "rel", rb_scrollcur_rel, 3);
3343
+
3344
+ /*
3345
+ * The +Cursor+ module provides shortcuts for creating cursor objects that
3346
+ * lets you retrieve, update and insert records.
3347
+ *
3348
+ * Depending on the query and options given, one of three classes of
3349
+ * cursors is returned: +SequentialCursor+, +ScrollCursor+ or
3350
+ * +InsertCursor+.
3351
+ */
3352
+ rb_mCursor = rb_define_module_under(rb_mInformix, "Cursor");
3353
+ rb_define_singleton_method(rb_mCursor, "new0", rb_cursor_s_new0, -1);
3925
3354
 
3926
3355
  /* Global constants --------------------------------------------------- */
3356
+ rb_cArray = rb_const_get(rb_cObject, rb_intern("Array"));
3357
+
3927
3358
  rb_require("date");
3928
3359
  rb_cDate = rb_const_get(rb_cObject, rb_intern("Date"));
3360
+
3929
3361
  rb_require("bigdecimal");
3930
3362
  rb_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
3931
3363
 
3364
+ rb_cRational = rb_const_get(rb_cObject, rb_intern("Rational"));
3365
+
3366
+ rb_require("informix/exceptions");
3367
+ rb_eError = rb_const_get(rb_mInformix, rb_intern("Error"));
3368
+ rb_eWarning = rb_const_get(rb_mInformix, rb_intern("Warning"));
3369
+ rb_eInternalError = rb_const_get(rb_mInformix, rb_intern("InternalError"));
3370
+ rb_eProgrammingError = rb_const_get(rb_mInformix, rb_intern("ProgrammingError"));
3371
+ rb_eOperationalError = rb_const_get(rb_mInformix, rb_intern("OperationalError"));
3372
+ rb_eDatabaseError = rb_const_get(rb_mInformix, rb_intern("DatabaseError"));
3373
+
3374
+ rb_require("informix/interval");
3375
+ rb_mInterval = rb_const_get(rb_mInformix, rb_intern("Interval"));
3376
+
3932
3377
  /* Global symbols ----------------------------------------------------- */
3933
3378
  #define INTERN(sym) s_##sym = rb_intern(#sym)
3934
3379
  INTERN(read); INTERN(new);
3935
3380
  INTERN(utc); INTERN(day); INTERN(month); INTERN(year);
3936
3381
  INTERN(hour); INTERN(min); INTERN(sec); INTERN(usec);
3937
3382
  INTERN(to_s); INTERN(to_i);
3383
+ INTERN(add_info);
3384
+ INTERN(from_months); INTERN(from_seconds);
3385
+ s_add = rb_intern("+");
3386
+ s_mul = rb_intern("*");
3938
3387
 
3939
3388
  sym_name = ID2SYM(rb_intern("name"));
3940
3389
  sym_type = ID2SYM(rb_intern("type"));
@@ -3958,7 +3407,4 @@ void Init_informix(void)
3958
3407
  sym_maxbytes = ID2SYM(rb_intern("maxbytes"));
3959
3408
 
3960
3409
  sym_params = ID2SYM(rb_intern("params"));
3961
-
3962
- /* Initialize ifx_except module */
3963
- rbifx_except_init(rb_mInformix, &esyms);
3964
3410
  }