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.
- data/COPYRIGHT +1 -1
- data/Changelog +43 -0
- data/README +117 -56
- data/{extconf.rb → ext/extconf.rb} +2 -2
- data/{informix.c → ext/informixc.c} +1242 -1745
- data/{informix.ec → ext/informixc.ec} +722 -1276
- data/lib/informix.rb +380 -0
- data/lib/informix/exceptions.rb +161 -0
- data/lib/informix/interval.rb +280 -0
- data/lib/informix/scrollcursor.rb +306 -0
- data/lib/informix/seqcursor.rb +169 -0
- data/test/ifx_all.rb +31 -0
- data/test/ifx_test_create_table.rb +26 -0
- data/test/ifx_test_errinfo.rb +37 -0
- data/test/ifx_test_exceptions.rb +71 -0
- data/test/ifx_test_fetch_n_each.rb +64 -0
- data/test/ifx_test_insert.rb +27 -0
- data/test/ifx_test_select.rb +87 -0
- data/test/testcase.rb +166 -0
- metadata +32 -14
- data/ifx_assert.h +0 -45
- data/ifx_except.c +0 -522
- data/ifx_except.ec +0 -466
- data/ifx_except.h +0 -82
@@ -1,55 +1,64 @@
|
|
1
|
-
/* $Id:
|
2
|
-
/*
|
3
|
-
* Copyright (c) 2006-
|
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:
|
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
|
43
|
-
static VALUE
|
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
|
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(
|
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
|
-
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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 =
|
610
|
-
nbytes =
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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
|
-
|
1534
|
-
|
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 =
|
1565
|
-
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(
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
1872
|
-
|
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
|
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
|
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(
|
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(
|
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
|
-
|
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(
|
2297
|
-
free_output_slots(
|
2375
|
+
free_input_slots(c);
|
2376
|
+
free_output_slots(c);
|
2298
2377
|
|
2299
|
-
did =
|
2378
|
+
did = c->database_id;
|
2300
2379
|
EXEC SQL set connection :did;
|
2301
|
-
if (SQLCODE
|
2302
|
-
|
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
|
-
|
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
|
-
*
|
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
|
-
|
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
|
-
*
|
2528
|
+
* st.drop
|
2460
2529
|
*
|
2461
2530
|
* Frees the statement and the memory associated with it.
|
2462
2531
|
*/
|
2463
2532
|
static VALUE
|
2464
|
-
|
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
|
-
|
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
|
-
/*
|
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 ==
|
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,
|
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(
|
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
|
-
|
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(
|
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 ==
|
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,
|
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(
|
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
|
-
|
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.
|
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
|
-
*
|
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
|
-
*
|
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
|
-
|
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(
|
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
|
-
|
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(
|
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
|
-
/*
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
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(
|
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
|
-
|
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
|
-
|
2893
|
+
c_bang = RTEST(bang);
|
2894
|
+
RECORD(c, type, c_bang, record);
|
3149
2895
|
return make_result(c, record);
|
3150
2896
|
}
|
3151
2897
|
|
3152
|
-
/*
|
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
|
-
|
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
|
-
|
3460
|
-
|
3461
|
-
|
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
|
-
|
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
|
-
|
2943
|
+
cursorbase_free(void *p)
|
3479
2944
|
{
|
3480
|
-
|
2945
|
+
cursorbase_close_or_free(p, 2);
|
3481
2946
|
xfree(p);
|
3482
2947
|
}
|
3483
2948
|
|
3484
2949
|
static VALUE
|
3485
|
-
|
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,
|
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, ¶ms, 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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
3058
|
+
cursorbase_close_or_free(c, 2);
|
3740
3059
|
|
3741
3060
|
return Qnil;
|
3742
3061
|
}
|
3743
3062
|
|
3744
|
-
/*
|
3063
|
+
/* module Cursor --------------------------------------------------------- */
|
3745
3064
|
|
3746
|
-
|
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
|
-
|
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
|
-
/*
|
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
|
-
|
3794
|
-
|
3795
|
-
|
3796
|
-
|
3797
|
-
|
3798
|
-
|
3799
|
-
|
3800
|
-
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
3804
|
-
|
3805
|
-
|
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
|
-
|
3811
|
-
|
3812
|
-
|
3813
|
-
|
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
|
-
|
3817
|
-
|
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
|
-
|
3821
|
-
|
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
|
-
/*
|
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
|
-
|
3858
|
-
|
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",
|
3861
|
-
|
3862
|
-
rb_define_method(rb_cStatement, "
|
3863
|
-
|
3864
|
-
|
3865
|
-
|
3866
|
-
|
3867
|
-
|
3868
|
-
|
3869
|
-
rb_define_method(
|
3870
|
-
rb_define_method(
|
3871
|
-
rb_define_method(
|
3872
|
-
rb_define_method(
|
3873
|
-
|
3874
|
-
|
3875
|
-
|
3876
|
-
|
3877
|
-
|
3878
|
-
|
3879
|
-
|
3880
|
-
|
3881
|
-
|
3882
|
-
|
3883
|
-
|
3884
|
-
/*
|
3885
|
-
|
3886
|
-
|
3887
|
-
|
3888
|
-
|
3889
|
-
rb_define_method(
|
3890
|
-
|
3891
|
-
|
3892
|
-
|
3893
|
-
|
3894
|
-
|
3895
|
-
|
3896
|
-
|
3897
|
-
|
3898
|
-
|
3899
|
-
|
3900
|
-
|
3901
|
-
|
3902
|
-
|
3903
|
-
|
3904
|
-
|
3905
|
-
|
3906
|
-
|
3907
|
-
|
3908
|
-
|
3909
|
-
|
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
|
}
|