ruby-informix 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  }