ruby-informix 0.4.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 +26 -0
- data/Changelog +84 -0
- data/README +80 -0
- data/extconf.rb +36 -0
- data/informix.c +4048 -0
- data/informix.ec +3093 -0
- metadata +50 -0
data/informix.ec
ADDED
@@ -0,0 +1,3093 @@
|
|
1
|
+
/* $Id: informix.ec,v 1.56 2006/12/13 08:19:52 santana Exp $ */
|
2
|
+
/*
|
3
|
+
* Copyright (c) 2006, 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
|
+
#include "ruby.h"
|
32
|
+
|
33
|
+
#include <sqlstype.h>
|
34
|
+
#include <sqltypes.h>
|
35
|
+
|
36
|
+
static VALUE rb_cDate;
|
37
|
+
|
38
|
+
static VALUE rb_mInformix;
|
39
|
+
static VALUE rb_mSequentialCursor;
|
40
|
+
static VALUE rb_mScrollCursor;
|
41
|
+
static VALUE rb_mInsertCursor;
|
42
|
+
|
43
|
+
static VALUE rb_cSlob;
|
44
|
+
static VALUE rb_cDatabase;
|
45
|
+
static VALUE rb_cStatement;
|
46
|
+
static VALUE rb_cCursor;
|
47
|
+
|
48
|
+
static ID s_read, s_new, s_utc, s_day, s_month, s_year;
|
49
|
+
static ID s_hour, s_min, s_sec, s_usec, s_to_s, s_to_i;
|
50
|
+
static VALUE sym_name, sym_type, sym_nullable, sym_stype, sym_length;
|
51
|
+
static VALUE sym_precision, sym_scale, sym_default, sym_xid;
|
52
|
+
static VALUE sym_scroll, sym_hold;
|
53
|
+
static VALUE sym_col_info, sym_sbspace, sym_estbytes, sym_extsz;
|
54
|
+
static VALUE sym_createflags, sym_openflags;
|
55
|
+
|
56
|
+
#define IDSIZE 30
|
57
|
+
|
58
|
+
static char *currentdid = NULL;
|
59
|
+
|
60
|
+
typedef struct {
|
61
|
+
short is_select, is_open;
|
62
|
+
struct sqlda daInput, *daOutput;
|
63
|
+
short *indInput, *indOutput;
|
64
|
+
char *bfOutput;
|
65
|
+
char cursor_id[IDSIZE];
|
66
|
+
char stmt_id[IDSIZE];
|
67
|
+
VALUE db, array, hash, field_names;
|
68
|
+
char *database_id;
|
69
|
+
} cursor_t;
|
70
|
+
|
71
|
+
typedef struct {
|
72
|
+
mint fd;
|
73
|
+
ifx_lo_t lo;
|
74
|
+
ifx_lo_create_spec_t *spec;
|
75
|
+
short type; /* XID_CLOB/XID_BLOB */
|
76
|
+
VALUE db;
|
77
|
+
char *database_id;
|
78
|
+
} slob_t;
|
79
|
+
|
80
|
+
#define NUM2INT8(num, int8addr) do { \
|
81
|
+
VALUE str = rb_funcall(num, s_to_s, 0); \
|
82
|
+
char *c_str = StringValueCStr(str); \
|
83
|
+
mint ret = ifx_int8cvasc(c_str, strlen(c_str), (int8addr)); \
|
84
|
+
if (ret < 0) \
|
85
|
+
rb_raise(rb_eRuntimeError, "Could not convert %s to int8", c_str); \
|
86
|
+
}while(0)
|
87
|
+
|
88
|
+
#define INT82NUM(int8addr, num) do { \
|
89
|
+
char str[21]; \
|
90
|
+
mint ret = ifx_int8toasc((int8addr), str, sizeof(str) - 1); \
|
91
|
+
str[sizeof(str) - 1] = 0; \
|
92
|
+
num = rb_cstr2inum(str, 10); \
|
93
|
+
}while(0)
|
94
|
+
|
95
|
+
/* class Slob ------------------------------------------------------------ */
|
96
|
+
|
97
|
+
static void
|
98
|
+
slob_mark(slob_t *slob)
|
99
|
+
{
|
100
|
+
rb_gc_mark(slob->db);
|
101
|
+
}
|
102
|
+
|
103
|
+
static void
|
104
|
+
slob_free(slob_t *slob)
|
105
|
+
{
|
106
|
+
if (slob->fd != -1) {
|
107
|
+
EXEC SQL begin declare section;
|
108
|
+
char *did;
|
109
|
+
EXEC SQL end declare section;
|
110
|
+
|
111
|
+
did = slob->database_id;
|
112
|
+
if (currentdid != did) {
|
113
|
+
EXEC SQL set connection :did;
|
114
|
+
if (SQLCODE < 0)
|
115
|
+
goto exit;
|
116
|
+
currentdid = did;
|
117
|
+
}
|
118
|
+
ifx_lo_close(slob->fd);
|
119
|
+
}
|
120
|
+
|
121
|
+
exit:
|
122
|
+
if (slob->spec)
|
123
|
+
ifx_lo_spec_free(slob->spec);
|
124
|
+
|
125
|
+
xfree(slob);
|
126
|
+
}
|
127
|
+
|
128
|
+
static VALUE
|
129
|
+
slob_alloc(VALUE klass)
|
130
|
+
{
|
131
|
+
slob_t *slob;
|
132
|
+
|
133
|
+
slob = ALLOC(slob_t);
|
134
|
+
slob->spec = NULL;
|
135
|
+
slob->fd = -1;
|
136
|
+
slob->type = XID_CLOB;
|
137
|
+
|
138
|
+
return Data_Wrap_Struct(klass, slob_mark, slob_free, slob);
|
139
|
+
}
|
140
|
+
|
141
|
+
/*
|
142
|
+
* call-seq:
|
143
|
+
* Slob.new(database, type = Slob::CLOB, options = nil) => slob
|
144
|
+
*
|
145
|
+
* Creates a Smart Large Object of type <i>type</i> in <i>database</i>.
|
146
|
+
* Returns a <code>Slob</code> object pointing to it.
|
147
|
+
*
|
148
|
+
* <i>type</i> can be Slob::BLOB or Slob::CLOB
|
149
|
+
*
|
150
|
+
* <i>options</i> must be a hash with the following possible keys:
|
151
|
+
*
|
152
|
+
* :sbspace => Sbspace name
|
153
|
+
* :estbytes => Estimated size, in bytes
|
154
|
+
* :extsz => Allocation extent size
|
155
|
+
* :createflags => Create-time flags
|
156
|
+
* :openflags => Access mode
|
157
|
+
* :maxbytes => Maximum size
|
158
|
+
* :col_info => Get the previous values from the column-level storage
|
159
|
+
* characteristics for the specified database column
|
160
|
+
*/
|
161
|
+
static VALUE
|
162
|
+
slob_initialize(int argc, VALUE *argv, VALUE self)
|
163
|
+
{
|
164
|
+
mint ret, error;
|
165
|
+
slob_t *slob;
|
166
|
+
VALUE db, type, options;
|
167
|
+
VALUE col_info, sbspace, estbytes, extsz, createflags, openflags, maxbytes;
|
168
|
+
EXEC SQL begin declare section;
|
169
|
+
char *did;
|
170
|
+
EXEC SQL end declare section;
|
171
|
+
|
172
|
+
rb_scan_args(argc, argv, "12", &db, &type, &options);
|
173
|
+
Data_Get_Struct(db, char, did);
|
174
|
+
|
175
|
+
if (currentdid != did) {
|
176
|
+
EXEC SQL set connection :did;
|
177
|
+
if (SQLCODE < 0)
|
178
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
179
|
+
currentdid = did;
|
180
|
+
}
|
181
|
+
|
182
|
+
Data_Get_Struct(self, slob_t, slob);
|
183
|
+
slob->db = db;
|
184
|
+
slob->database_id = did;
|
185
|
+
|
186
|
+
if (RTEST(type)) {
|
187
|
+
int t = FIX2INT(type);
|
188
|
+
if (t != XID_CLOB && t != XID_BLOB)
|
189
|
+
rb_raise(rb_eRuntimeError, "Invalid type %d for an SLOB", t);
|
190
|
+
slob->type = t;
|
191
|
+
}
|
192
|
+
|
193
|
+
col_info = sbspace = estbytes = extsz = createflags = openflags = maxbytes = Qnil;
|
194
|
+
|
195
|
+
if (RTEST(options)) {
|
196
|
+
col_info = rb_hash_aref(options, sym_col_info);
|
197
|
+
sbspace = rb_hash_aref(options, sym_sbspace);
|
198
|
+
estbytes = rb_hash_aref(options, sym_estbytes);
|
199
|
+
extsz = rb_hash_aref(options, sym_extsz);
|
200
|
+
createflags = rb_hash_aref(options, sym_createflags);
|
201
|
+
openflags = rb_hash_aref(options, sym_openflags);
|
202
|
+
}
|
203
|
+
|
204
|
+
ret = ifx_lo_def_create_spec(&slob->spec);
|
205
|
+
if (ret < 0)
|
206
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
|
207
|
+
|
208
|
+
if (RTEST(col_info)) {
|
209
|
+
ret = ifx_lo_col_info(StringValueCStr(col_info), slob->spec);
|
210
|
+
|
211
|
+
if (ret < 0)
|
212
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
|
213
|
+
}
|
214
|
+
if (RTEST(sbspace)) {
|
215
|
+
char *c_sbspace = StringValueCStr(sbspace);
|
216
|
+
ret = ifx_lo_specset_sbspace(slob->spec, c_sbspace);
|
217
|
+
if (ret == -1)
|
218
|
+
rb_raise(rb_eRuntimeError, "Could not set sbspace name to %s", c_sbspace);
|
219
|
+
}
|
220
|
+
if (RTEST(estbytes)) {
|
221
|
+
ifx_int8_t estbytes8;
|
222
|
+
|
223
|
+
NUM2INT8(estbytes, &estbytes8);
|
224
|
+
ret = ifx_lo_specset_estbytes(slob->spec, &estbytes8);
|
225
|
+
if (ret == -1)
|
226
|
+
rb_raise(rb_eRuntimeError, "Could not set estbytes");
|
227
|
+
}
|
228
|
+
if (RTEST(extsz)) {
|
229
|
+
ret = ifx_lo_specset_extsz(slob->spec, FIX2LONG(extsz));
|
230
|
+
if (ret == -1)
|
231
|
+
rb_raise(rb_eRuntimeError, "Could not set extsz to %d", FIX2LONG(extsz));
|
232
|
+
}
|
233
|
+
if (RTEST(createflags)) {
|
234
|
+
ret = ifx_lo_specset_flags(slob->spec, FIX2LONG(createflags));
|
235
|
+
if (ret == -1)
|
236
|
+
rb_raise(rb_eRuntimeError, "Could not set crate-time flags to 0x%X", FIX2LONG(createflags));
|
237
|
+
}
|
238
|
+
if (RTEST(maxbytes)) {
|
239
|
+
ifx_int8_t maxbytes8;
|
240
|
+
|
241
|
+
NUM2INT8(maxbytes, (&maxbytes8));
|
242
|
+
ret = ifx_lo_specset_maxbytes(slob->spec, &maxbytes8);
|
243
|
+
if (ret == -1)
|
244
|
+
rb_raise(rb_eRuntimeError, "Could not set maxbytes");
|
245
|
+
}
|
246
|
+
slob->fd = ifx_lo_create(slob->spec, RTEST(openflags)? FIX2LONG(openflags): LO_RDWR, &slob->lo, &error);
|
247
|
+
if (slob->fd == -1) {
|
248
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d\n", error);
|
249
|
+
}
|
250
|
+
return self;
|
251
|
+
}
|
252
|
+
|
253
|
+
/*
|
254
|
+
* call-seq:
|
255
|
+
* slob.open(access = Slob::RDONLY) => slob
|
256
|
+
*
|
257
|
+
* Opens the Smart Large Object in <i>access</i> mode.
|
258
|
+
*
|
259
|
+
* access modes:
|
260
|
+
*
|
261
|
+
* Slob::RDONLY:: Read only
|
262
|
+
* Slob::DIRTY_READ:: Read uncommitted data
|
263
|
+
* Slob::WRONLY:: Write only
|
264
|
+
* Slob::APPEND:: Append data to the end, if combined with RDRW or WRONLY; read only otherwise
|
265
|
+
* Slob::RDRW:: Read/Write
|
266
|
+
* Slob::BUFFER:: Use standard database server buffer pool
|
267
|
+
* Slob::NOBUFFER:: Use private buffer from the session pool of the database server
|
268
|
+
* Slob::LOCKALL:: Lock the entire Smart Large Object
|
269
|
+
* Slob::LOCKRANGE:: Lock a range of bytes
|
270
|
+
*
|
271
|
+
* Returns __self__.
|
272
|
+
*/
|
273
|
+
static VALUE
|
274
|
+
slob_open(int argc, VALUE *argv, VALUE self)
|
275
|
+
{
|
276
|
+
VALUE access;
|
277
|
+
slob_t *slob;
|
278
|
+
mint error;
|
279
|
+
EXEC SQL begin declare section;
|
280
|
+
char *did;
|
281
|
+
EXEC SQL end declare section;
|
282
|
+
|
283
|
+
Data_Get_Struct(self, slob_t, slob);
|
284
|
+
|
285
|
+
if (slob->fd != -1) /* Already open */
|
286
|
+
return self;
|
287
|
+
|
288
|
+
did = slob->database_id;
|
289
|
+
if (currentdid != did) {
|
290
|
+
EXEC SQL set connection :did;
|
291
|
+
if (SQLCODE < 0)
|
292
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
293
|
+
currentdid = did;
|
294
|
+
}
|
295
|
+
|
296
|
+
rb_scan_args(argc, argv, "01", &access);
|
297
|
+
|
298
|
+
slob->fd = ifx_lo_open(&slob->lo, NIL_P(access)? LO_RDONLY: FIX2INT(access), &error);
|
299
|
+
|
300
|
+
if (slob->fd == -1)
|
301
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", error);
|
302
|
+
|
303
|
+
return self;
|
304
|
+
}
|
305
|
+
|
306
|
+
/*
|
307
|
+
* call-seq:
|
308
|
+
* slob.close => slob
|
309
|
+
*
|
310
|
+
* Closes the Smart Large Object and returns __self__.
|
311
|
+
*/
|
312
|
+
static VALUE
|
313
|
+
slob_close(VALUE self)
|
314
|
+
{
|
315
|
+
slob_t *slob;
|
316
|
+
|
317
|
+
Data_Get_Struct(self, slob_t, slob);
|
318
|
+
if (slob->fd != -1) {
|
319
|
+
EXEC SQL begin declare section;
|
320
|
+
char *did;
|
321
|
+
EXEC SQL end declare section;
|
322
|
+
|
323
|
+
did = slob->database_id;
|
324
|
+
if (currentdid != did) {
|
325
|
+
EXEC SQL set connection :did;
|
326
|
+
if (SQLCODE < 0)
|
327
|
+
return self;
|
328
|
+
currentdid = did;
|
329
|
+
}
|
330
|
+
|
331
|
+
ifx_lo_close(slob->fd);
|
332
|
+
slob->fd = -1;
|
333
|
+
}
|
334
|
+
|
335
|
+
return self;
|
336
|
+
}
|
337
|
+
|
338
|
+
/*
|
339
|
+
* call-seq:
|
340
|
+
* slob.read(nbytes) => string
|
341
|
+
*
|
342
|
+
* Reads at most <i>nbytes</i> bytes from the Smart Large Object.
|
343
|
+
*
|
344
|
+
* Returns the bytes read as a String object.
|
345
|
+
*/
|
346
|
+
static VALUE
|
347
|
+
slob_read(VALUE self, VALUE nbytes)
|
348
|
+
{
|
349
|
+
slob_t *slob;
|
350
|
+
mint error, ret;
|
351
|
+
char *buffer;
|
352
|
+
long c_nbytes;
|
353
|
+
VALUE str;
|
354
|
+
EXEC SQL begin declare section;
|
355
|
+
char *did;
|
356
|
+
EXEC SQL end declare section;
|
357
|
+
|
358
|
+
|
359
|
+
Data_Get_Struct(self, slob_t, slob);
|
360
|
+
|
361
|
+
if (slob->fd == -1)
|
362
|
+
rb_raise(rb_eRuntimeError, "Open the Slob object before reading");
|
363
|
+
|
364
|
+
did = slob->database_id;
|
365
|
+
if (currentdid != did) {
|
366
|
+
EXEC SQL set connection :did;
|
367
|
+
if (SQLCODE < 0)
|
368
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
369
|
+
currentdid = did;
|
370
|
+
}
|
371
|
+
|
372
|
+
c_nbytes = FIX2LONG(nbytes);
|
373
|
+
buffer = ALLOC_N(char, c_nbytes);
|
374
|
+
ret = ifx_lo_read(slob->fd, buffer, c_nbytes, &error);
|
375
|
+
|
376
|
+
if (ret == -1)
|
377
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d\n", error);
|
378
|
+
|
379
|
+
str = rb_str_new(buffer, ret);
|
380
|
+
xfree(buffer);
|
381
|
+
|
382
|
+
return str;
|
383
|
+
}
|
384
|
+
|
385
|
+
/*
|
386
|
+
* call-seq:
|
387
|
+
* slob.write(data) => fixnum or bignum
|
388
|
+
*
|
389
|
+
* Writes <i>data</i> to the Smart Large Object.
|
390
|
+
*
|
391
|
+
* Returns the number of bytes written.
|
392
|
+
*/
|
393
|
+
static VALUE
|
394
|
+
slob_write(VALUE self, VALUE data)
|
395
|
+
{
|
396
|
+
slob_t *slob;
|
397
|
+
mint error, ret;
|
398
|
+
char *buffer;
|
399
|
+
long nbytes;
|
400
|
+
VALUE str;
|
401
|
+
EXEC SQL begin declare section;
|
402
|
+
char *did;
|
403
|
+
EXEC SQL end declare section;
|
404
|
+
|
405
|
+
Data_Get_Struct(self, slob_t, slob);
|
406
|
+
|
407
|
+
if (slob->fd == -1)
|
408
|
+
rb_raise(rb_eRuntimeError, "Open the Slob object before writing");
|
409
|
+
|
410
|
+
did = slob->database_id;
|
411
|
+
if (currentdid != did) {
|
412
|
+
EXEC SQL set connection :did;
|
413
|
+
if (SQLCODE < 0)
|
414
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
415
|
+
currentdid = did;
|
416
|
+
}
|
417
|
+
|
418
|
+
str = StringValue(data);
|
419
|
+
buffer = RSTRING(str)->ptr;
|
420
|
+
nbytes = RSTRING(str)->len;
|
421
|
+
|
422
|
+
ret = ifx_lo_write(slob->fd, buffer, nbytes, &error);
|
423
|
+
|
424
|
+
if (ret == -1)
|
425
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", error);
|
426
|
+
|
427
|
+
return LONG2NUM(ret);
|
428
|
+
}
|
429
|
+
|
430
|
+
/*
|
431
|
+
* call-seq:
|
432
|
+
* slob.seek(offset, whence) => fixnum or bignum
|
433
|
+
*
|
434
|
+
* Sets the file position for the next read or write
|
435
|
+
* operation on the open Smart Large Object.
|
436
|
+
*
|
437
|
+
*
|
438
|
+
* <i>offset</i> offset from the starting seek position
|
439
|
+
* <i>whence</i> identifies the starting seek position
|
440
|
+
*
|
441
|
+
* Values for <i>whence</i>:
|
442
|
+
*
|
443
|
+
* Slob::SEEK_SET:: The start of the Smart Large Object
|
444
|
+
* Slob::SEEK_CUR:: The current seek position in the Smart Large Object
|
445
|
+
* Slob::SEEK_END:: The end of the Smart Large Object
|
446
|
+
*
|
447
|
+
* Returns the new position.
|
448
|
+
*/
|
449
|
+
static VALUE
|
450
|
+
slob_seek(VALUE self, VALUE offset, VALUE whence)
|
451
|
+
{
|
452
|
+
slob_t *slob;
|
453
|
+
mint ret;
|
454
|
+
VALUE seek_pos;
|
455
|
+
ifx_int8_t offset8, seek_pos8;
|
456
|
+
EXEC SQL begin declare section;
|
457
|
+
char *did;
|
458
|
+
EXEC SQL end declare section;
|
459
|
+
|
460
|
+
Data_Get_Struct(self, slob_t, slob);
|
461
|
+
|
462
|
+
if (slob->fd == -1)
|
463
|
+
rb_raise(rb_eRuntimeError, "Open the Slob object first");
|
464
|
+
|
465
|
+
did = slob->database_id;
|
466
|
+
if (currentdid != did) {
|
467
|
+
EXEC SQL set connection :did;
|
468
|
+
if (SQLCODE < 0)
|
469
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
470
|
+
currentdid = did;
|
471
|
+
}
|
472
|
+
|
473
|
+
NUM2INT8(offset, &offset8);
|
474
|
+
ret = ifx_lo_seek(slob->fd, &offset8, FIX2INT(whence), &seek_pos8);
|
475
|
+
if (ret < 0)
|
476
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
|
477
|
+
|
478
|
+
INT82NUM(&seek_pos8, seek_pos);
|
479
|
+
|
480
|
+
return seek_pos;
|
481
|
+
}
|
482
|
+
|
483
|
+
/*
|
484
|
+
* call-seq:
|
485
|
+
* slob.tell => fixnum or bignum
|
486
|
+
*
|
487
|
+
* Returns the current file or seek position for an
|
488
|
+
* open Smart Large Object
|
489
|
+
*/
|
490
|
+
static VALUE
|
491
|
+
slob_tell(VALUE self)
|
492
|
+
{
|
493
|
+
slob_t *slob;
|
494
|
+
mint ret;
|
495
|
+
VALUE seek_pos;
|
496
|
+
ifx_int8_t seek_pos8;
|
497
|
+
EXEC SQL begin declare section;
|
498
|
+
char *did;
|
499
|
+
EXEC SQL end declare section;
|
500
|
+
|
501
|
+
Data_Get_Struct(self, slob_t, slob);
|
502
|
+
|
503
|
+
if (slob->fd == -1)
|
504
|
+
rb_raise(rb_eRuntimeError, "Open the Slob object first");
|
505
|
+
|
506
|
+
did = slob->database_id;
|
507
|
+
if (currentdid != did) {
|
508
|
+
EXEC SQL set connection :did;
|
509
|
+
if (SQLCODE < 0)
|
510
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
511
|
+
currentdid = did;
|
512
|
+
}
|
513
|
+
|
514
|
+
ret = ifx_lo_tell(slob->fd, &seek_pos8);
|
515
|
+
if (ret < 0)
|
516
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
|
517
|
+
|
518
|
+
INT82NUM(&seek_pos8, seek_pos);
|
519
|
+
|
520
|
+
return seek_pos;
|
521
|
+
}
|
522
|
+
|
523
|
+
/*
|
524
|
+
* call-seq:
|
525
|
+
* slob.truncate(offset) => slob
|
526
|
+
*
|
527
|
+
* Truncates a Smart Large Object at a specified byte position.
|
528
|
+
*
|
529
|
+
* Returns __self__.
|
530
|
+
*/
|
531
|
+
static VALUE
|
532
|
+
slob_truncate(VALUE self, VALUE offset)
|
533
|
+
{
|
534
|
+
slob_t *slob;
|
535
|
+
mint ret;
|
536
|
+
ifx_int8_t offset8;
|
537
|
+
EXEC SQL begin declare section;
|
538
|
+
char *did;
|
539
|
+
EXEC SQL end declare section;
|
540
|
+
|
541
|
+
Data_Get_Struct(self, slob_t, slob);
|
542
|
+
|
543
|
+
if (slob->fd == -1)
|
544
|
+
rb_raise(rb_eRuntimeError, "Open the Slob object first");
|
545
|
+
|
546
|
+
did = slob->database_id;
|
547
|
+
if (currentdid != did) {
|
548
|
+
EXEC SQL set connection :did;
|
549
|
+
if (SQLCODE < 0)
|
550
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
551
|
+
currentdid = did;
|
552
|
+
}
|
553
|
+
|
554
|
+
NUM2INT8(offset, &offset8);
|
555
|
+
ret = ifx_lo_truncate(slob->fd, &offset8);
|
556
|
+
if (ret < 0)
|
557
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
|
558
|
+
|
559
|
+
return self;
|
560
|
+
}
|
561
|
+
|
562
|
+
/* Helper functions ------------------------------------------------------- */
|
563
|
+
|
564
|
+
/*
|
565
|
+
* Counts the number of markers '?' in the query
|
566
|
+
*/
|
567
|
+
static int count_markers(const char *query)
|
568
|
+
{
|
569
|
+
register char c, quote = 0;
|
570
|
+
register int count = 0;
|
571
|
+
|
572
|
+
while((c = *query++)) {
|
573
|
+
if (quote && c != quote)
|
574
|
+
;
|
575
|
+
else if (quote == c) {
|
576
|
+
quote = 0;
|
577
|
+
}
|
578
|
+
else if (c == '\'' || c == '"') {
|
579
|
+
quote = c;
|
580
|
+
}
|
581
|
+
else if (c == '?') {
|
582
|
+
++count;
|
583
|
+
}
|
584
|
+
}
|
585
|
+
return count;
|
586
|
+
}
|
587
|
+
|
588
|
+
/*
|
589
|
+
* Allocates memory for the indicators array and slots for the input
|
590
|
+
* parameters, if any. Freed by free_input_slots.
|
591
|
+
*/
|
592
|
+
static void
|
593
|
+
alloc_input_slots(cursor_t *c, const char *query)
|
594
|
+
{
|
595
|
+
register int n;
|
596
|
+
|
597
|
+
n = count_markers(query);
|
598
|
+
c->daInput.sqld = n;
|
599
|
+
if (n) {
|
600
|
+
c->daInput.sqlvar = ALLOC_N(struct sqlvar_struct, n);
|
601
|
+
memset(c->daInput.sqlvar, 0, n*sizeof(struct sqlvar_struct));
|
602
|
+
c->indInput = ALLOC_N(short, n);
|
603
|
+
while(n--)
|
604
|
+
c->daInput.sqlvar[n].sqlind = &c->indInput[n];
|
605
|
+
}
|
606
|
+
else {
|
607
|
+
c->daInput.sqlvar = NULL;
|
608
|
+
c->indInput = NULL;
|
609
|
+
}
|
610
|
+
}
|
611
|
+
|
612
|
+
/*
|
613
|
+
* Allocates memory for the output data slots and its indicators array.
|
614
|
+
* Freed by free_output_slots.
|
615
|
+
*/
|
616
|
+
static void
|
617
|
+
alloc_output_slots(cursor_t *c)
|
618
|
+
{
|
619
|
+
register int i, count;
|
620
|
+
register short *ind;
|
621
|
+
struct sqlvar_struct *var;
|
622
|
+
register char *buffer;
|
623
|
+
|
624
|
+
c->field_names = rb_ary_new2(c->daOutput->sqld);
|
625
|
+
|
626
|
+
ind = c->indOutput = ALLOC_N(short, c->daOutput->sqld);
|
627
|
+
|
628
|
+
var = c->daOutput->sqlvar;
|
629
|
+
for (i = count = 0; i < c->daOutput->sqld; i++, ind++, var++) {
|
630
|
+
var->sqlind = ind;
|
631
|
+
rb_ary_store(c->field_names, i, rb_str_new2(var->sqlname));
|
632
|
+
if (ISSMARTBLOB(var->sqltype, var->sqlxid)) {
|
633
|
+
var->sqldata = (char *)ALLOC(ifx_lo_t);
|
634
|
+
continue;
|
635
|
+
}
|
636
|
+
var->sqllen = rtypmsize(var->sqltype, var->sqllen);
|
637
|
+
count = rtypalign(count, var->sqltype) + var->sqllen;
|
638
|
+
}
|
639
|
+
|
640
|
+
buffer = c->bfOutput = ALLOC_N(char, count);
|
641
|
+
memset(buffer, 0, count);
|
642
|
+
|
643
|
+
var = c->daOutput->sqlvar;
|
644
|
+
for (i = count = 0; i < c->daOutput->sqld; i++, var++) {
|
645
|
+
if (var->sqldata)
|
646
|
+
continue;
|
647
|
+
count = rtypalign(count, var->sqltype);
|
648
|
+
var->sqldata = buffer + count;
|
649
|
+
count += var->sqllen;
|
650
|
+
if (ISBYTESTYPE(var->sqltype) || ISTEXTTYPE(var->sqltype)) {
|
651
|
+
loc_t *p;
|
652
|
+
p = (loc_t *)var->sqldata;
|
653
|
+
byfill((char *)p, sizeof(loc_t), 0);
|
654
|
+
p->loc_loctype = LOCMEMORY;
|
655
|
+
p->loc_bufsize = -1;
|
656
|
+
}
|
657
|
+
if (var->sqltype == SQLDTIME) {
|
658
|
+
var->sqllen = 0;
|
659
|
+
}
|
660
|
+
}
|
661
|
+
}
|
662
|
+
|
663
|
+
/*
|
664
|
+
* Frees the allocated memory of the input parameters, but not the slots
|
665
|
+
* nor the indicators array. Allocated by bind_input_params.
|
666
|
+
*/
|
667
|
+
static void
|
668
|
+
clean_input_slots(cursor_t *c)
|
669
|
+
{
|
670
|
+
register int count;
|
671
|
+
register struct sqlvar_struct *var;
|
672
|
+
|
673
|
+
if (c->daInput.sqlvar == NULL)
|
674
|
+
return;
|
675
|
+
var = c->daInput.sqlvar;
|
676
|
+
count = c->daInput.sqld;
|
677
|
+
while(count--) {
|
678
|
+
if (var->sqldata != NULL) {
|
679
|
+
if (var->sqltype == CLOCATORTYPE) {
|
680
|
+
loc_t *p = (loc_t *)var->sqldata;
|
681
|
+
if (p->loc_buffer != NULL) {
|
682
|
+
xfree(p->loc_buffer);
|
683
|
+
}
|
684
|
+
}
|
685
|
+
xfree(var->sqldata);
|
686
|
+
var->sqldata = NULL;
|
687
|
+
var++;
|
688
|
+
}
|
689
|
+
}
|
690
|
+
}
|
691
|
+
|
692
|
+
/*
|
693
|
+
* Frees the memory for the input parameters, their slots, and the indicators
|
694
|
+
* array. Allocated by alloc_input_slots and bind_input_params.
|
695
|
+
*/
|
696
|
+
static void
|
697
|
+
free_input_slots(cursor_t *c)
|
698
|
+
{
|
699
|
+
clean_input_slots(c);
|
700
|
+
if (c->daInput.sqlvar) {
|
701
|
+
xfree(c->daInput.sqlvar);
|
702
|
+
c->daInput.sqlvar = NULL;
|
703
|
+
c->daInput.sqld = 0;
|
704
|
+
}
|
705
|
+
if (c->indInput) {
|
706
|
+
xfree(c->indInput);
|
707
|
+
c->indInput = NULL;
|
708
|
+
}
|
709
|
+
}
|
710
|
+
|
711
|
+
/*
|
712
|
+
* Frees the memory for the output parameters, their slots, and the indicators
|
713
|
+
* array. Allocated by alloc_output_slots.
|
714
|
+
*/
|
715
|
+
static void
|
716
|
+
free_output_slots(cursor_t *c)
|
717
|
+
{
|
718
|
+
if (c->daOutput != NULL) {
|
719
|
+
struct sqlvar_struct *var = c->daOutput->sqlvar;
|
720
|
+
if (var) {
|
721
|
+
register int i;
|
722
|
+
for (i = 0; i < c->daOutput->sqld; i++, var++) {
|
723
|
+
if (ISBLOBTYPE(var->sqltype)) {
|
724
|
+
loc_t *p = (loc_t *) var->sqldata;
|
725
|
+
if(p -> loc_buffer)
|
726
|
+
xfree(p->loc_buffer);
|
727
|
+
}
|
728
|
+
if (ISSMARTBLOB(var->sqltype, var->sqlxid))
|
729
|
+
xfree(var->sqldata);
|
730
|
+
}
|
731
|
+
}
|
732
|
+
xfree(c->daOutput);
|
733
|
+
c->daOutput = NULL;
|
734
|
+
}
|
735
|
+
if (c->indOutput != NULL) {
|
736
|
+
xfree(c->indOutput);
|
737
|
+
c->indOutput = NULL;
|
738
|
+
}
|
739
|
+
if (c->bfOutput != NULL) {
|
740
|
+
xfree(c->bfOutput);
|
741
|
+
c->bfOutput = NULL;
|
742
|
+
}
|
743
|
+
}
|
744
|
+
|
745
|
+
/*
|
746
|
+
* Gets an array of Ruby objects as input parameters and place them in input
|
747
|
+
* slots, converting data types and allocating memory as needed.
|
748
|
+
*/
|
749
|
+
static void
|
750
|
+
bind_input_params(cursor_t *c, VALUE *argv)
|
751
|
+
{
|
752
|
+
VALUE data, klass;
|
753
|
+
register int i;
|
754
|
+
register struct sqlvar_struct *var;
|
755
|
+
|
756
|
+
var = c->daInput.sqlvar;
|
757
|
+
for (i = 0; i < c->daInput.sqld; i++, var++) {
|
758
|
+
data = argv[i];
|
759
|
+
|
760
|
+
switch(TYPE(data)) {
|
761
|
+
case T_NIL:
|
762
|
+
var->sqltype = CSTRINGTYPE;
|
763
|
+
var->sqldata = NULL;
|
764
|
+
var->sqllen = 0;
|
765
|
+
*var->sqlind = -1;
|
766
|
+
break;
|
767
|
+
case T_FIXNUM:
|
768
|
+
var->sqldata = (char *)ALLOC(long);
|
769
|
+
*((long *)var->sqldata) = FIX2LONG(data);
|
770
|
+
var->sqltype = CLONGTYPE;
|
771
|
+
var->sqllen = sizeof(long);
|
772
|
+
*var->sqlind = 0;
|
773
|
+
break;
|
774
|
+
case T_FLOAT:
|
775
|
+
var->sqldata = (char *)ALLOC(double);
|
776
|
+
*((double *)var->sqldata) = NUM2DBL(data);
|
777
|
+
var->sqltype = CDOUBLETYPE;
|
778
|
+
var->sqllen = sizeof(double);
|
779
|
+
*var->sqlind = 0;
|
780
|
+
break;
|
781
|
+
case T_TRUE:
|
782
|
+
case T_FALSE:
|
783
|
+
var->sqldata = ALLOC(char);
|
784
|
+
*var->sqldata = TYPE(data) == T_TRUE? 't': 'f';
|
785
|
+
var->sqltype = CCHARTYPE;
|
786
|
+
var->sqllen = sizeof(char);
|
787
|
+
*var->sqlind = 0;
|
788
|
+
break;
|
789
|
+
default:
|
790
|
+
klass = rb_obj_class(data);
|
791
|
+
if (klass == rb_cDate) {
|
792
|
+
int2 mdy[3];
|
793
|
+
int4 date;
|
794
|
+
|
795
|
+
mdy[0] = FIX2INT(rb_funcall(data, s_month, 0));
|
796
|
+
mdy[1] = FIX2INT(rb_funcall(data, s_day, 0));
|
797
|
+
mdy[2] = FIX2INT(rb_funcall(data, s_year, 0));
|
798
|
+
rmdyjul(mdy, &date);
|
799
|
+
|
800
|
+
var->sqldata = (char *)ALLOC(int4);
|
801
|
+
*((int4 *)var->sqldata) = date;
|
802
|
+
var->sqltype = CDATETYPE;
|
803
|
+
var->sqllen = sizeof(int4);
|
804
|
+
*var->sqlind = 0;
|
805
|
+
break;
|
806
|
+
}
|
807
|
+
if (klass == rb_cTime) {
|
808
|
+
char buffer[30];
|
809
|
+
short year, month, day, hour, minute, second;
|
810
|
+
int usec;
|
811
|
+
dtime_t *dt;
|
812
|
+
|
813
|
+
year = FIX2INT(rb_funcall(data, s_year, 0));
|
814
|
+
month = FIX2INT(rb_funcall(data, s_month, 0));
|
815
|
+
day = FIX2INT(rb_funcall(data, s_day, 0));
|
816
|
+
hour = FIX2INT(rb_funcall(data, s_hour, 0));
|
817
|
+
minute = FIX2INT(rb_funcall(data, s_min, 0));
|
818
|
+
second = FIX2INT(rb_funcall(data, s_sec, 0));
|
819
|
+
usec = FIX2INT(rb_funcall(data, s_usec, 0));
|
820
|
+
|
821
|
+
dt = ALLOC(dtime_t);
|
822
|
+
|
823
|
+
dt->dt_qual = TU_DTENCODE(TU_YEAR, TU_F5);
|
824
|
+
snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d.%d",
|
825
|
+
year, month, day, hour, minute, second, usec/10);
|
826
|
+
dtcvasc(buffer, dt);
|
827
|
+
|
828
|
+
var->sqldata = (char *)dt;
|
829
|
+
var->sqltype = CDTIMETYPE;
|
830
|
+
var->sqllen = sizeof(dtime_t);
|
831
|
+
*var->sqlind = 0;
|
832
|
+
break;
|
833
|
+
}
|
834
|
+
if (klass == rb_cSlob) {
|
835
|
+
slob_t *slob;
|
836
|
+
|
837
|
+
Data_Get_Struct(data, slob_t, slob);
|
838
|
+
|
839
|
+
var->sqldata = (char *)ALLOC(ifx_lo_t);
|
840
|
+
memcpy(var->sqldata, &slob->lo, sizeof(slob->lo));
|
841
|
+
var->sqltype = SQLUDTFIXED;
|
842
|
+
var->sqlxid = slob->type;
|
843
|
+
var->sqllen = sizeof(ifx_lo_t);
|
844
|
+
*var->sqlind = 0;
|
845
|
+
break;
|
846
|
+
}
|
847
|
+
if (rb_respond_to(data, s_read)) {
|
848
|
+
char *str;
|
849
|
+
loc_t *loc;
|
850
|
+
long len;
|
851
|
+
|
852
|
+
data = rb_funcall(data, s_read, 0);
|
853
|
+
data = StringValue(data);
|
854
|
+
str = RSTRING(data)->ptr;
|
855
|
+
len = RSTRING(data)->len;
|
856
|
+
|
857
|
+
loc = (loc_t *)ALLOC(loc_t);
|
858
|
+
byfill((char *)loc, sizeof(loc_t), 0);
|
859
|
+
loc->loc_loctype = LOCMEMORY;
|
860
|
+
loc->loc_buffer = (char *)ALLOC_N(char, len);
|
861
|
+
memcpy(loc->loc_buffer, str, len);
|
862
|
+
loc->loc_bufsize = loc->loc_size = len;
|
863
|
+
|
864
|
+
var->sqldata = (char *)loc;
|
865
|
+
var->sqltype = CLOCATORTYPE;
|
866
|
+
var->sqllen = sizeof(loc_t);
|
867
|
+
*var->sqlind = 0;
|
868
|
+
break;
|
869
|
+
}
|
870
|
+
{
|
871
|
+
VALUE str;
|
872
|
+
str = rb_check_string_type(data);
|
873
|
+
if (NIL_P(str)) {
|
874
|
+
data = rb_obj_as_string(data);
|
875
|
+
}
|
876
|
+
else {
|
877
|
+
data = str;
|
878
|
+
}
|
879
|
+
}
|
880
|
+
case T_STRING: {
|
881
|
+
char *str;
|
882
|
+
long len;
|
883
|
+
|
884
|
+
str = RSTRING(data)->ptr;
|
885
|
+
len = RSTRING(data)->len;
|
886
|
+
var->sqldata = ALLOC_N(char, len + 1);
|
887
|
+
memcpy(var->sqldata, str, len);
|
888
|
+
var->sqldata[len] = 0;
|
889
|
+
var->sqltype = CSTRINGTYPE;
|
890
|
+
var->sqllen = len;
|
891
|
+
*var->sqlind = 0;
|
892
|
+
break;
|
893
|
+
}
|
894
|
+
}
|
895
|
+
}
|
896
|
+
}
|
897
|
+
|
898
|
+
/*
|
899
|
+
* Returns an array or a hash of Ruby objects containing the record fetched.
|
900
|
+
*/
|
901
|
+
static VALUE
|
902
|
+
make_result(cursor_t *c, VALUE record)
|
903
|
+
{
|
904
|
+
VALUE item;
|
905
|
+
register int i;
|
906
|
+
register struct sqlvar_struct *var;
|
907
|
+
|
908
|
+
var = c->daOutput->sqlvar;
|
909
|
+
for (i = 0; i < c->daOutput->sqld; i++, var++) {
|
910
|
+
if (*var->sqlind == -1) {
|
911
|
+
item = Qnil;
|
912
|
+
} else {
|
913
|
+
switch(var->sqltype) {
|
914
|
+
case SQLCHAR:
|
915
|
+
case SQLVCHAR:
|
916
|
+
case SQLNCHAR:
|
917
|
+
case SQLNVCHAR:
|
918
|
+
item = rb_str_new2(var->sqldata);
|
919
|
+
break;
|
920
|
+
case SQLSMINT:
|
921
|
+
item = INT2FIX(*(int2 *)var->sqldata);
|
922
|
+
break;
|
923
|
+
case SQLINT:
|
924
|
+
case SQLSERIAL:
|
925
|
+
item = INT2NUM(*(int4 *)var->sqldata);
|
926
|
+
break;
|
927
|
+
case SQLINT8:
|
928
|
+
case SQLSERIAL8:
|
929
|
+
INT82NUM((ifx_int8_t *)var->sqldata, item);
|
930
|
+
break;
|
931
|
+
case SQLSMFLOAT:
|
932
|
+
item = rb_float_new(*(float *)var->sqldata);
|
933
|
+
break;
|
934
|
+
case SQLFLOAT:
|
935
|
+
item = rb_float_new(*(double *)var->sqldata);
|
936
|
+
break;
|
937
|
+
case SQLDATE: {
|
938
|
+
VALUE year, month, day;
|
939
|
+
int2 mdy[3];
|
940
|
+
|
941
|
+
rjulmdy(*(int4 *)var->sqldata, mdy);
|
942
|
+
year = INT2FIX(mdy[2]);
|
943
|
+
month = INT2FIX(mdy[0]);
|
944
|
+
day = INT2FIX(mdy[1]);
|
945
|
+
item = rb_funcall(rb_cDate, s_new, 3, year, month, day);
|
946
|
+
break;
|
947
|
+
}
|
948
|
+
case SQLDTIME: {
|
949
|
+
register short qual;
|
950
|
+
short year, month, day, hour, minute, second;
|
951
|
+
int usec;
|
952
|
+
dtime_t *dt;
|
953
|
+
register char *dgts;
|
954
|
+
|
955
|
+
month = day = 1;
|
956
|
+
year = hour = minute = second = usec = 0;
|
957
|
+
dt = (dtime_t *)var->sqldata;
|
958
|
+
dgts = dt->dt_dec.dec_dgts;
|
959
|
+
|
960
|
+
qual = TU_START(dt->dt_qual);
|
961
|
+
for (; qual <= TU_END(dt->dt_qual); qual++) {
|
962
|
+
switch(qual) {
|
963
|
+
case TU_YEAR:
|
964
|
+
year = 100**dgts++;
|
965
|
+
year += *dgts++;
|
966
|
+
break;
|
967
|
+
case TU_MONTH:
|
968
|
+
month = *dgts++;
|
969
|
+
break;
|
970
|
+
case TU_DAY:
|
971
|
+
day = *dgts++;
|
972
|
+
break;
|
973
|
+
case TU_HOUR:
|
974
|
+
hour = *dgts++;
|
975
|
+
break;
|
976
|
+
case TU_MINUTE:
|
977
|
+
minute = *dgts++;
|
978
|
+
break;
|
979
|
+
case TU_SECOND:
|
980
|
+
second = *dgts++;
|
981
|
+
break;
|
982
|
+
case TU_F1:
|
983
|
+
usec = 10000**dgts++;
|
984
|
+
break;
|
985
|
+
case TU_F3:
|
986
|
+
usec += 100**dgts++;
|
987
|
+
break;
|
988
|
+
case TU_F5:
|
989
|
+
usec += *dgts++;
|
990
|
+
break;
|
991
|
+
}
|
992
|
+
}
|
993
|
+
|
994
|
+
item = rb_funcall(rb_cTime, s_utc, 7,
|
995
|
+
INT2FIX(year), INT2FIX(month), INT2FIX(day),
|
996
|
+
INT2FIX(hour), INT2FIX(minute), INT2FIX(second),
|
997
|
+
INT2FIX(usec));
|
998
|
+
|
999
|
+
/* Clean the buffer for DATETIME columns because
|
1000
|
+
* ESQL/C leaves the previous content when a
|
1001
|
+
* a time field is zero.
|
1002
|
+
*/
|
1003
|
+
memset(dt, 0, sizeof(dtime_t));
|
1004
|
+
break;
|
1005
|
+
}
|
1006
|
+
case SQLDECIMAL:
|
1007
|
+
case SQLMONEY: {
|
1008
|
+
double dblValue;
|
1009
|
+
dectodbl((dec_t *)var->sqldata, &dblValue);
|
1010
|
+
item = rb_float_new(dblValue);
|
1011
|
+
break;
|
1012
|
+
}
|
1013
|
+
case SQLBOOL:
|
1014
|
+
item = var->sqldata[0]? Qtrue: Qfalse;
|
1015
|
+
break;
|
1016
|
+
case SQLBYTES:
|
1017
|
+
case SQLTEXT: {
|
1018
|
+
loc_t *loc;
|
1019
|
+
loc = (loc_t *)var->sqldata;
|
1020
|
+
item = rb_str_new(loc->loc_buffer, loc->loc_size);
|
1021
|
+
break;
|
1022
|
+
}
|
1023
|
+
case SQLUDTFIXED:
|
1024
|
+
if (ISSMARTBLOB(var->sqltype, var->sqlxid)) {
|
1025
|
+
slob_t *slob;
|
1026
|
+
|
1027
|
+
item = slob_alloc(rb_cSlob);
|
1028
|
+
Data_Get_Struct(item, slob_t, slob);
|
1029
|
+
memcpy(&slob->lo, var->sqldata, sizeof(ifx_lo_t));
|
1030
|
+
slob->type = var->sqlxid;
|
1031
|
+
break;
|
1032
|
+
}
|
1033
|
+
case SQLSET:
|
1034
|
+
case SQLMULTISET:
|
1035
|
+
case SQLLIST:
|
1036
|
+
case SQLROW:
|
1037
|
+
case SQLCOLLECTION:
|
1038
|
+
case SQLROWREF:
|
1039
|
+
case SQLUDTVAR:
|
1040
|
+
case SQLREFSER8:
|
1041
|
+
case SQLLVARCHAR:
|
1042
|
+
case SQLSENDRECV:
|
1043
|
+
case SQLIMPEXP:
|
1044
|
+
case SQLIMPEXPBIN:
|
1045
|
+
case SQLUNKNOWN:
|
1046
|
+
default:
|
1047
|
+
item = Qnil;
|
1048
|
+
break;
|
1049
|
+
}
|
1050
|
+
}
|
1051
|
+
if (BUILTIN_TYPE(record) == T_ARRAY) {
|
1052
|
+
rb_ary_store(record, i, item);
|
1053
|
+
}
|
1054
|
+
else {
|
1055
|
+
rb_hash_aset(record, RARRAY(c->field_names)->ptr[i], item);
|
1056
|
+
}
|
1057
|
+
}
|
1058
|
+
return record;
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
/* module Informix -------------------------------------------------------- */
|
1062
|
+
|
1063
|
+
/*
|
1064
|
+
* call-seq:
|
1065
|
+
* Informix.connect(dbname, user = nil, password = nil) => database
|
1066
|
+
*
|
1067
|
+
* Returns a <code>Database</code> object connected to <i>dbname</i> as
|
1068
|
+
* <i>user</i> with <i>password</i>. If these are not given, connects to
|
1069
|
+
* <i>dbname</i> as the current user.
|
1070
|
+
*/
|
1071
|
+
static VALUE
|
1072
|
+
informix_connect(int argc, VALUE *argv, VALUE self)
|
1073
|
+
{
|
1074
|
+
return rb_class_new_instance(argc, argv, rb_cDatabase);
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
|
1078
|
+
/* class Database --------------------------------------------------------- */
|
1079
|
+
|
1080
|
+
static void
|
1081
|
+
database_free(void *p)
|
1082
|
+
{
|
1083
|
+
EXEC SQL begin declare section;
|
1084
|
+
char *did;
|
1085
|
+
EXEC SQL end declare section;
|
1086
|
+
|
1087
|
+
did = p;
|
1088
|
+
EXEC SQL disconnect :did;
|
1089
|
+
if (currentdid == did)
|
1090
|
+
currentdid = NULL;
|
1091
|
+
xfree(p);
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
static VALUE
|
1095
|
+
database_alloc(VALUE klass)
|
1096
|
+
{
|
1097
|
+
char *did;
|
1098
|
+
|
1099
|
+
did = ALLOC_N(char, IDSIZE);
|
1100
|
+
did[0] = 0;
|
1101
|
+
return Data_Wrap_Struct(klass, 0, database_free, did);
|
1102
|
+
}
|
1103
|
+
|
1104
|
+
/*
|
1105
|
+
* call-seq:
|
1106
|
+
* Database.new(dbname, user = nil, password = nil) => database
|
1107
|
+
*
|
1108
|
+
* Returns a <code>Database</code> object connected to <i>dbname</i> as
|
1109
|
+
* <i>user</i> with <i>password</i>. If these are not given, connects to
|
1110
|
+
* <i>dbname</i> as the current user.
|
1111
|
+
*/
|
1112
|
+
static VALUE
|
1113
|
+
database_initialize(int argc, VALUE *argv, VALUE self)
|
1114
|
+
{
|
1115
|
+
VALUE arg[3];
|
1116
|
+
|
1117
|
+
EXEC SQL begin declare section;
|
1118
|
+
char *dbname, *user = NULL, *pass = NULL, *did;
|
1119
|
+
EXEC SQL end declare section;
|
1120
|
+
|
1121
|
+
rb_scan_args(argc, argv, "12", &arg[0], &arg[1], &arg[2]);
|
1122
|
+
|
1123
|
+
if (NIL_P(arg[0]))
|
1124
|
+
rb_raise(rb_eRuntimeError, "A database name must be specified");
|
1125
|
+
|
1126
|
+
Data_Get_Struct(self, char, did);
|
1127
|
+
|
1128
|
+
dbname = StringValueCStr(arg[0]);
|
1129
|
+
snprintf(did, IDSIZE, "DB%lX", self);
|
1130
|
+
|
1131
|
+
if (!NIL_P(arg[1]))
|
1132
|
+
user = StringValueCStr(arg[1]);
|
1133
|
+
|
1134
|
+
if (!NIL_P(arg[2]))
|
1135
|
+
pass = StringValueCStr(arg[2]);
|
1136
|
+
|
1137
|
+
if (user && pass)
|
1138
|
+
EXEC SQL connect to :dbname as :did user :user
|
1139
|
+
using :pass with concurrent transaction;
|
1140
|
+
else
|
1141
|
+
EXEC SQL connect to :dbname as :did with concurrent transaction;
|
1142
|
+
|
1143
|
+
if (SQLCODE < 0)
|
1144
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1145
|
+
|
1146
|
+
currentdid = did;
|
1147
|
+
|
1148
|
+
return self;
|
1149
|
+
}
|
1150
|
+
|
1151
|
+
/*
|
1152
|
+
* call-seq:
|
1153
|
+
* db.close => db
|
1154
|
+
*
|
1155
|
+
* Disconnects <i>db</i> and returns __self__
|
1156
|
+
*/
|
1157
|
+
static VALUE
|
1158
|
+
database_close(VALUE self)
|
1159
|
+
{
|
1160
|
+
EXEC SQL begin declare section;
|
1161
|
+
char *did;
|
1162
|
+
EXEC SQL end declare section;
|
1163
|
+
|
1164
|
+
Data_Get_Struct(self, char, did);
|
1165
|
+
EXEC SQL disconnect :did;
|
1166
|
+
if (did == currentdid)
|
1167
|
+
currentdid = NULL;
|
1168
|
+
|
1169
|
+
return self;
|
1170
|
+
}
|
1171
|
+
|
1172
|
+
/*
|
1173
|
+
* call-seq:
|
1174
|
+
* db.immediate(query) => fixnum
|
1175
|
+
*
|
1176
|
+
* Executes <i>query</i> and returns the number of rows affected.
|
1177
|
+
* <i>query</i> must not return rows. Executes efficiently any
|
1178
|
+
* non-parameterized or DQL statement.
|
1179
|
+
*/
|
1180
|
+
|
1181
|
+
static VALUE
|
1182
|
+
database_immediate(VALUE self, VALUE arg)
|
1183
|
+
{
|
1184
|
+
EXEC SQL begin declare section;
|
1185
|
+
char *query, *did;
|
1186
|
+
EXEC SQL end declare section;
|
1187
|
+
|
1188
|
+
Data_Get_Struct(self, char, did);
|
1189
|
+
|
1190
|
+
if (currentdid != did) {
|
1191
|
+
EXEC SQL set connection :did;
|
1192
|
+
if (SQLCODE < 0)
|
1193
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1194
|
+
currentdid = did;
|
1195
|
+
}
|
1196
|
+
|
1197
|
+
query = StringValueCStr(arg);
|
1198
|
+
EXEC SQL execute immediate :query;
|
1199
|
+
if (SQLCODE < 0)
|
1200
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1201
|
+
|
1202
|
+
return INT2FIX(sqlca.sqlerrd[2]);
|
1203
|
+
}
|
1204
|
+
|
1205
|
+
/*
|
1206
|
+
* call-seq:
|
1207
|
+
* db.rollback => db
|
1208
|
+
*
|
1209
|
+
* Rolls back a transaction and returns __self__.
|
1210
|
+
*/
|
1211
|
+
static VALUE
|
1212
|
+
database_rollback(VALUE self)
|
1213
|
+
{
|
1214
|
+
EXEC SQL begin declare section;
|
1215
|
+
char *did;
|
1216
|
+
EXEC SQL end declare section;
|
1217
|
+
|
1218
|
+
Data_Get_Struct(self, char, did);
|
1219
|
+
|
1220
|
+
if (currentdid != did) {
|
1221
|
+
EXEC SQL set connection :did;
|
1222
|
+
if (SQLCODE < 0)
|
1223
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1224
|
+
currentdid = did;
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
EXEC SQL rollback;
|
1228
|
+
return self;
|
1229
|
+
}
|
1230
|
+
|
1231
|
+
/*
|
1232
|
+
* call-seq:
|
1233
|
+
* db.commit => db
|
1234
|
+
*
|
1235
|
+
* Commits a transaction and returns __self__.
|
1236
|
+
*/
|
1237
|
+
static VALUE
|
1238
|
+
database_commit(VALUE self)
|
1239
|
+
{
|
1240
|
+
EXEC SQL begin declare section;
|
1241
|
+
char *did;
|
1242
|
+
EXEC SQL end declare section;
|
1243
|
+
|
1244
|
+
Data_Get_Struct(self, char, did);
|
1245
|
+
|
1246
|
+
if (currentdid != did) {
|
1247
|
+
EXEC SQL set connection :did;
|
1248
|
+
if (SQLCODE < 0)
|
1249
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1250
|
+
currentdid = did;
|
1251
|
+
}
|
1252
|
+
|
1253
|
+
EXEC SQL commit;
|
1254
|
+
return self;
|
1255
|
+
}
|
1256
|
+
|
1257
|
+
static VALUE
|
1258
|
+
database_transfail(VALUE self)
|
1259
|
+
{
|
1260
|
+
database_rollback(self);
|
1261
|
+
return Qundef;
|
1262
|
+
}
|
1263
|
+
|
1264
|
+
/*
|
1265
|
+
* call-seq:
|
1266
|
+
* db.transaction {|db| block } => db
|
1267
|
+
*
|
1268
|
+
* Opens a transaction and executes <i>block</i>, passing __self__ as parameter.
|
1269
|
+
* If an exception is raised, the transaction is rolled back. It is commited
|
1270
|
+
* otherwise.
|
1271
|
+
*
|
1272
|
+
* Returns __self__.
|
1273
|
+
*/
|
1274
|
+
static VALUE
|
1275
|
+
database_transaction(VALUE self)
|
1276
|
+
{
|
1277
|
+
VALUE ret;
|
1278
|
+
EXEC SQL begin declare section;
|
1279
|
+
char *did;
|
1280
|
+
EXEC SQL end declare section;
|
1281
|
+
|
1282
|
+
Data_Get_Struct(self, char, did);
|
1283
|
+
|
1284
|
+
if (currentdid != did) {
|
1285
|
+
EXEC SQL set connection :did;
|
1286
|
+
if (SQLCODE < 0)
|
1287
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1288
|
+
currentdid = did;
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
EXEC SQL commit;
|
1292
|
+
|
1293
|
+
EXEC SQL begin work;
|
1294
|
+
ret = rb_rescue(rb_yield, self, database_transfail, self);
|
1295
|
+
if (ret == Qundef)
|
1296
|
+
rb_raise(rb_eRuntimeError, "Transaction rolled back");
|
1297
|
+
EXEC SQL commit;
|
1298
|
+
return self;
|
1299
|
+
}
|
1300
|
+
|
1301
|
+
/*
|
1302
|
+
* call-seq:
|
1303
|
+
* db.prepare(query) => statement
|
1304
|
+
*
|
1305
|
+
* Returns a <code>Statement</code> object based on <i>query</i>.
|
1306
|
+
* <i>query</i> may contain '?' placeholders for input parameters;
|
1307
|
+
* it must not be a query returning more than one row
|
1308
|
+
* (use <code>Database#cursor</code> instead.)
|
1309
|
+
*/
|
1310
|
+
static VALUE
|
1311
|
+
database_prepare(VALUE self, VALUE query)
|
1312
|
+
{
|
1313
|
+
VALUE argv[2];
|
1314
|
+
|
1315
|
+
argv[0] = self; argv[1] = query;
|
1316
|
+
return rb_class_new_instance(2, argv, rb_cStatement);
|
1317
|
+
}
|
1318
|
+
|
1319
|
+
/*
|
1320
|
+
* call-seq:
|
1321
|
+
* db.cursor(query, options = nil) => cursor
|
1322
|
+
*
|
1323
|
+
* Returns a <code>Cursor</code> object based on <i>query</i>.
|
1324
|
+
* <i>query</i> may contain '?' placeholders for input parameters.
|
1325
|
+
*
|
1326
|
+
* <i>options</i> must be a hash with the following possible keys:
|
1327
|
+
*
|
1328
|
+
* :scroll => true or false
|
1329
|
+
* :hold => true or false
|
1330
|
+
*
|
1331
|
+
*/
|
1332
|
+
static VALUE
|
1333
|
+
database_cursor(int argc, VALUE *argv, VALUE self)
|
1334
|
+
{
|
1335
|
+
VALUE arg[3];
|
1336
|
+
|
1337
|
+
arg[0] = self;
|
1338
|
+
rb_scan_args(argc, argv, "11", &arg[1], &arg[2]);
|
1339
|
+
return rb_class_new_instance(3, arg, rb_cCursor);
|
1340
|
+
}
|
1341
|
+
|
1342
|
+
/*
|
1343
|
+
* call-seq:
|
1344
|
+
* db.columns(tablename) => array
|
1345
|
+
*
|
1346
|
+
* Returns an array with information for every column of the given table.
|
1347
|
+
*/
|
1348
|
+
static VALUE
|
1349
|
+
database_columns(VALUE self, VALUE tablename)
|
1350
|
+
{
|
1351
|
+
VALUE v, column, result;
|
1352
|
+
char *stype;
|
1353
|
+
static char *stypes[] = {
|
1354
|
+
"CHAR", "SMALLINT", "INTEGER", "FLOAT", "SMALLFLOAT", "DECIMAL",
|
1355
|
+
"SERIAL", "DATE", "MONEY", "NULL", "DATETIME", "BYTE",
|
1356
|
+
"TEXT", "VARCHAR", "INTERVAL", "NCHAR", "NVARCHAR", "INT8",
|
1357
|
+
"SERIAL8", "SET", "MULTISET", "LIST", "UNNAMED ROW", "NAMED ROW",
|
1358
|
+
"VARIABLE-LENGTH OPAQUE TYPE"
|
1359
|
+
};
|
1360
|
+
|
1361
|
+
static char *qualifiers[] = {
|
1362
|
+
"YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND"
|
1363
|
+
};
|
1364
|
+
|
1365
|
+
EXEC SQL begin declare section;
|
1366
|
+
char *did;
|
1367
|
+
char *tabname;
|
1368
|
+
int tabid, xid;
|
1369
|
+
varchar colname[129];
|
1370
|
+
short coltype, collength;
|
1371
|
+
char deftype[2];
|
1372
|
+
varchar defvalue[257];
|
1373
|
+
EXEC SQL end declare section;
|
1374
|
+
|
1375
|
+
Data_Get_Struct(self, char, did);
|
1376
|
+
|
1377
|
+
if (currentdid != did) {
|
1378
|
+
EXEC SQL set connection :did;
|
1379
|
+
if (SQLCODE < 0)
|
1380
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1381
|
+
currentdid = did;
|
1382
|
+
}
|
1383
|
+
|
1384
|
+
tabname = StringValueCStr(tablename);
|
1385
|
+
|
1386
|
+
EXEC SQL select tabid into :tabid from systables where tabname = :tabname;
|
1387
|
+
|
1388
|
+
if (SQLCODE == SQLNOTFOUND)
|
1389
|
+
rb_raise(rb_eRuntimeError, "Table '%s' doesn't exist", tabname);
|
1390
|
+
|
1391
|
+
result = rb_ary_new();
|
1392
|
+
|
1393
|
+
EXEC SQL declare cur cursor for
|
1394
|
+
select colname, coltype, collength, extended_id, type, default, c.colno
|
1395
|
+
from syscolumns c, outer sysdefaults d
|
1396
|
+
where c.tabid = :tabid and c.tabid = d.tabid and c.colno = d.colno
|
1397
|
+
order by c.colno;
|
1398
|
+
|
1399
|
+
if (SQLCODE < 0)
|
1400
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1401
|
+
|
1402
|
+
EXEC SQL open cur;
|
1403
|
+
if (SQLCODE < 0)
|
1404
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1405
|
+
|
1406
|
+
for(;;) {
|
1407
|
+
EXEC SQL fetch cur into :colname, :coltype, :collength, :xid,
|
1408
|
+
:deftype, :defvalue;
|
1409
|
+
if (SQLCODE < 0)
|
1410
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1411
|
+
|
1412
|
+
if (SQLCODE == SQLNOTFOUND)
|
1413
|
+
break;
|
1414
|
+
|
1415
|
+
column = rb_hash_new();
|
1416
|
+
rb_hash_aset(column, sym_name, rb_str_new2(colname));
|
1417
|
+
rb_hash_aset(column, sym_type, INT2FIX(coltype));
|
1418
|
+
rb_hash_aset(column, sym_nullable, coltype&0x100? Qfalse: Qtrue);
|
1419
|
+
rb_hash_aset(column, sym_xid, INT2FIX(xid));
|
1420
|
+
|
1421
|
+
if ((coltype&0xFF) < 23) {
|
1422
|
+
stype = coltype == 4118? stypes[23]: stypes[coltype&0xFF];
|
1423
|
+
}
|
1424
|
+
else {
|
1425
|
+
stype = stypes[24];
|
1426
|
+
}
|
1427
|
+
rb_hash_aset(column, sym_stype, rb_str_new2(stype));
|
1428
|
+
rb_hash_aset(column, sym_length, INT2FIX(collength));
|
1429
|
+
|
1430
|
+
switch(coltype&0xFF) {
|
1431
|
+
case SQLVCHAR:
|
1432
|
+
case SQLNVCHAR:
|
1433
|
+
case SQLMONEY:
|
1434
|
+
case SQLDECIMAL:
|
1435
|
+
rb_hash_aset(column, sym_precision, INT2FIX(collength >> 8));
|
1436
|
+
rb_hash_aset(column, sym_scale, INT2FIX(collength&0xFF));
|
1437
|
+
break;
|
1438
|
+
case SQLDATE:
|
1439
|
+
case SQLDTIME:
|
1440
|
+
case SQLINTERVAL:
|
1441
|
+
rb_hash_aset(column, sym_length, INT2FIX(collength >> 8));
|
1442
|
+
rb_hash_aset(column, sym_precision, INT2FIX((collength&0xF0) >> 4));
|
1443
|
+
rb_hash_aset(column, sym_scale, INT2FIX(collength&0xF));
|
1444
|
+
break;
|
1445
|
+
default:
|
1446
|
+
rb_hash_aset(column, sym_precision, INT2FIX(0));
|
1447
|
+
rb_hash_aset(column, sym_scale, INT2FIX(0));
|
1448
|
+
}
|
1449
|
+
|
1450
|
+
if (!deftype[0]) {
|
1451
|
+
v = Qnil;
|
1452
|
+
}
|
1453
|
+
else {
|
1454
|
+
switch(deftype[0]) {
|
1455
|
+
case 'C': {
|
1456
|
+
char current[28];
|
1457
|
+
snprintf(current, sizeof(current), "CURRENT %s TO %s",
|
1458
|
+
qualifiers[(collength&0xF0) >> 5],
|
1459
|
+
qualifiers[(collength&0xF)>>1]);
|
1460
|
+
v = rb_str_new2(current);
|
1461
|
+
break;
|
1462
|
+
}
|
1463
|
+
case 'L':
|
1464
|
+
switch (coltype & 0xFF) {
|
1465
|
+
case SQLCHAR:
|
1466
|
+
case SQLNCHAR:
|
1467
|
+
case SQLVCHAR:
|
1468
|
+
case SQLNVCHAR:
|
1469
|
+
v = rb_str_new2(defvalue);
|
1470
|
+
break;
|
1471
|
+
default: {
|
1472
|
+
char *s = defvalue;
|
1473
|
+
while(*s++ != ' ');
|
1474
|
+
if ((coltype&0xFF) == SQLFLOAT ||
|
1475
|
+
(coltype&0xFF) == SQLSMFLOAT ||
|
1476
|
+
(coltype&0xFF) == SQLMONEY ||
|
1477
|
+
(coltype&0xFF) == SQLDECIMAL)
|
1478
|
+
v = rb_float_new(atof(s));
|
1479
|
+
else
|
1480
|
+
v = LONG2FIX(atol(s));
|
1481
|
+
}
|
1482
|
+
}
|
1483
|
+
break;
|
1484
|
+
case 'N':
|
1485
|
+
v = rb_str_new2("NULL");
|
1486
|
+
break;
|
1487
|
+
case 'T':
|
1488
|
+
v = rb_str_new2("today");
|
1489
|
+
break;
|
1490
|
+
case 'U':
|
1491
|
+
v = rb_str_new2("user");
|
1492
|
+
break;
|
1493
|
+
case 'S':
|
1494
|
+
default: /* XXX */
|
1495
|
+
v = Qnil;
|
1496
|
+
}
|
1497
|
+
}
|
1498
|
+
rb_hash_aset(column, sym_default, v);
|
1499
|
+
rb_ary_push(result, column);
|
1500
|
+
}
|
1501
|
+
|
1502
|
+
EXEC SQL close cur;
|
1503
|
+
EXEC SQL free cur;
|
1504
|
+
|
1505
|
+
return result;
|
1506
|
+
}
|
1507
|
+
|
1508
|
+
/* class Statement ------------------------------------------------------- */
|
1509
|
+
|
1510
|
+
static void
|
1511
|
+
statement_mark(cursor_t *c)
|
1512
|
+
{
|
1513
|
+
rb_gc_mark(c->db);
|
1514
|
+
if (c->array)
|
1515
|
+
rb_gc_mark(c->array);
|
1516
|
+
if (c->hash)
|
1517
|
+
rb_gc_mark(c->hash);
|
1518
|
+
if (c->field_names)
|
1519
|
+
rb_gc_mark(c->field_names);
|
1520
|
+
}
|
1521
|
+
|
1522
|
+
static void
|
1523
|
+
statement_free(void *p)
|
1524
|
+
{
|
1525
|
+
EXEC SQL begin declare section;
|
1526
|
+
char *sid, *did;
|
1527
|
+
EXEC SQL end declare section;
|
1528
|
+
|
1529
|
+
free_input_slots(p);
|
1530
|
+
free_output_slots(p);
|
1531
|
+
|
1532
|
+
did = ((cursor_t *)p)->database_id;
|
1533
|
+
if (currentdid != did) {
|
1534
|
+
EXEC SQL set connection :did;
|
1535
|
+
if (SQLCODE < 0)
|
1536
|
+
goto exit;
|
1537
|
+
currentdid = did;
|
1538
|
+
}
|
1539
|
+
|
1540
|
+
sid = ((cursor_t *)p)->stmt_id;
|
1541
|
+
EXEC SQL free :sid;
|
1542
|
+
|
1543
|
+
exit:
|
1544
|
+
xfree(p);
|
1545
|
+
}
|
1546
|
+
|
1547
|
+
static VALUE
|
1548
|
+
statement_alloc(VALUE klass)
|
1549
|
+
{
|
1550
|
+
cursor_t *c;
|
1551
|
+
|
1552
|
+
c = ALLOC(cursor_t);
|
1553
|
+
memset(c, 0, sizeof(cursor_t));
|
1554
|
+
return Data_Wrap_Struct(klass, statement_mark, statement_free, c);
|
1555
|
+
}
|
1556
|
+
|
1557
|
+
/*
|
1558
|
+
* call-seq:
|
1559
|
+
* Statement.new(database, query) => statement
|
1560
|
+
*
|
1561
|
+
* Prepares <i>query</i> in the context of <i>database</i> and returns
|
1562
|
+
* a <code>Statement</code> object.
|
1563
|
+
*/
|
1564
|
+
static VALUE
|
1565
|
+
statement_initialize(VALUE self, VALUE db, VALUE query)
|
1566
|
+
{
|
1567
|
+
struct sqlda *output;
|
1568
|
+
cursor_t *c;
|
1569
|
+
EXEC SQL begin declare section;
|
1570
|
+
char *c_query, *sid, *did;
|
1571
|
+
EXEC SQL end declare section;
|
1572
|
+
|
1573
|
+
Data_Get_Struct(db, char, did);
|
1574
|
+
if (currentdid != did) {
|
1575
|
+
EXEC SQL set connection :did;
|
1576
|
+
if (SQLCODE < 0)
|
1577
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1578
|
+
currentdid = did;
|
1579
|
+
}
|
1580
|
+
|
1581
|
+
Data_Get_Struct(self, cursor_t, c);
|
1582
|
+
c->db = db;
|
1583
|
+
c->database_id = did;
|
1584
|
+
output = c->daOutput;
|
1585
|
+
snprintf(c->stmt_id, sizeof(c->stmt_id), "STMT%lX", self);
|
1586
|
+
sid = c->stmt_id;
|
1587
|
+
c_query = StringValueCStr(query);
|
1588
|
+
|
1589
|
+
EXEC SQL prepare :sid from :c_query;
|
1590
|
+
if (SQLCODE < 0)
|
1591
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1592
|
+
|
1593
|
+
alloc_input_slots(c, c_query);
|
1594
|
+
EXEC SQL describe :sid into output;
|
1595
|
+
c->daOutput = output;
|
1596
|
+
|
1597
|
+
c->is_select = (SQLCODE == 0 || SQLCODE == SQ_EXECPROC);
|
1598
|
+
|
1599
|
+
if (c->is_select)
|
1600
|
+
alloc_output_slots(c);
|
1601
|
+
else {
|
1602
|
+
xfree(c->daOutput);
|
1603
|
+
c->daOutput = NULL;
|
1604
|
+
}
|
1605
|
+
|
1606
|
+
return self;
|
1607
|
+
}
|
1608
|
+
|
1609
|
+
|
1610
|
+
/*
|
1611
|
+
* call-seq:
|
1612
|
+
* stmt[*params] => fixnum or hash
|
1613
|
+
*
|
1614
|
+
* Executes the previously prepared statement, binding <i>params</i> as
|
1615
|
+
* input parameters.
|
1616
|
+
*
|
1617
|
+
* Returns the record retrieved, in the case of a singleton select, or the
|
1618
|
+
* number of rows affected, in the case of any other statement.
|
1619
|
+
*/
|
1620
|
+
static VALUE
|
1621
|
+
statement_call(int argc, VALUE *argv, VALUE self)
|
1622
|
+
{
|
1623
|
+
struct sqlda *input, *output;
|
1624
|
+
cursor_t *c;
|
1625
|
+
EXEC SQL begin declare section;
|
1626
|
+
char *sid, *did;
|
1627
|
+
EXEC SQL end declare section;
|
1628
|
+
|
1629
|
+
Data_Get_Struct(self, cursor_t, c);
|
1630
|
+
|
1631
|
+
did = c->database_id;
|
1632
|
+
if (currentdid != did) {
|
1633
|
+
EXEC SQL set connection :did;
|
1634
|
+
if (SQLCODE < 0)
|
1635
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1636
|
+
currentdid = did;
|
1637
|
+
}
|
1638
|
+
|
1639
|
+
output = c->daOutput;
|
1640
|
+
input = &c->daInput;
|
1641
|
+
sid = c->stmt_id;
|
1642
|
+
|
1643
|
+
if (argc != input->sqld)
|
1644
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
|
1645
|
+
argc, input->sqld);
|
1646
|
+
|
1647
|
+
if (c->is_select) {
|
1648
|
+
if (argc) {
|
1649
|
+
bind_input_params(c, argv);
|
1650
|
+
EXEC SQL execute :sid into descriptor output
|
1651
|
+
using descriptor input;
|
1652
|
+
clean_input_slots(c);
|
1653
|
+
}
|
1654
|
+
else
|
1655
|
+
EXEC SQL execute :sid into descriptor output;
|
1656
|
+
|
1657
|
+
if (SQLCODE < 0)
|
1658
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1659
|
+
|
1660
|
+
if (SQLCODE == SQLNOTFOUND)
|
1661
|
+
return Qnil;
|
1662
|
+
return make_result(c, rb_hash_new());
|
1663
|
+
}
|
1664
|
+
else {
|
1665
|
+
if (argc) {
|
1666
|
+
bind_input_params(c, argv);
|
1667
|
+
EXEC SQL execute :sid using descriptor input;
|
1668
|
+
clean_input_slots(c);
|
1669
|
+
}
|
1670
|
+
else
|
1671
|
+
EXEC SQL execute :sid;
|
1672
|
+
}
|
1673
|
+
if (SQLCODE < 0)
|
1674
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1675
|
+
|
1676
|
+
return INT2FIX(sqlca.sqlerrd[2]);
|
1677
|
+
}
|
1678
|
+
|
1679
|
+
/*
|
1680
|
+
* call-seq:
|
1681
|
+
* stmt.drop
|
1682
|
+
*
|
1683
|
+
* Frees the statement and the memory associated with it.
|
1684
|
+
*/
|
1685
|
+
static VALUE
|
1686
|
+
statement_drop(VALUE self)
|
1687
|
+
{
|
1688
|
+
cursor_t *c;
|
1689
|
+
EXEC SQL begin declare section;
|
1690
|
+
char *sid, *did;
|
1691
|
+
EXEC SQL end declare section;
|
1692
|
+
|
1693
|
+
Data_Get_Struct(self, cursor_t, c);
|
1694
|
+
free_input_slots(c);
|
1695
|
+
free_output_slots(c);
|
1696
|
+
|
1697
|
+
did = c->database_id;
|
1698
|
+
if (currentdid != did) {
|
1699
|
+
EXEC SQL set connection :did;
|
1700
|
+
if (SQLCODE < 0)
|
1701
|
+
return Qnil;
|
1702
|
+
currentdid = did;
|
1703
|
+
}
|
1704
|
+
sid = c->stmt_id;
|
1705
|
+
EXEC SQL free :sid;
|
1706
|
+
|
1707
|
+
return Qnil;
|
1708
|
+
}
|
1709
|
+
|
1710
|
+
|
1711
|
+
/* module SequentialCursor ----------------------------------------------- */
|
1712
|
+
|
1713
|
+
/* Decides whether to use an Array or a Hash, and instantiate a new
|
1714
|
+
* object or reuse an existing one.
|
1715
|
+
*/
|
1716
|
+
#define RECORD(c, type, bang, record) do {\
|
1717
|
+
if (type == T_ARRAY) {\
|
1718
|
+
if (bang) {\
|
1719
|
+
if (!c->array)\
|
1720
|
+
c->array = rb_ary_new2(c->daOutput->sqld);\
|
1721
|
+
record = c->array;\
|
1722
|
+
}\
|
1723
|
+
else\
|
1724
|
+
record = rb_ary_new2(c->daOutput->sqld);\
|
1725
|
+
}\
|
1726
|
+
else {\
|
1727
|
+
if (bang) {\
|
1728
|
+
if (!c->hash)\
|
1729
|
+
c->hash = rb_hash_new();\
|
1730
|
+
record = c->hash;\
|
1731
|
+
}\
|
1732
|
+
else\
|
1733
|
+
record = rb_hash_new();\
|
1734
|
+
}\
|
1735
|
+
}while(0)
|
1736
|
+
|
1737
|
+
/*
|
1738
|
+
* Base function for fetch* methods, except *_many
|
1739
|
+
*/
|
1740
|
+
static VALUE
|
1741
|
+
fetch(VALUE self, VALUE type, int bang)
|
1742
|
+
{
|
1743
|
+
EXEC SQL begin declare section;
|
1744
|
+
char *cid, *did;
|
1745
|
+
EXEC SQL end declare section;
|
1746
|
+
cursor_t *c;
|
1747
|
+
struct sqlda *output;
|
1748
|
+
VALUE record;
|
1749
|
+
|
1750
|
+
Data_Get_Struct(self, cursor_t, c);
|
1751
|
+
if (!c->is_open)
|
1752
|
+
rb_raise(rb_eRuntimeError, "Open the cursor object first");
|
1753
|
+
|
1754
|
+
did = c->database_id;
|
1755
|
+
if (currentdid != did) {
|
1756
|
+
EXEC SQL set connection :did;
|
1757
|
+
if (SQLCODE < 0)
|
1758
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1759
|
+
currentdid = did;
|
1760
|
+
}
|
1761
|
+
|
1762
|
+
output = c->daOutput;
|
1763
|
+
cid = c->cursor_id;
|
1764
|
+
|
1765
|
+
EXEC SQL fetch :cid using descriptor output;
|
1766
|
+
if (SQLCODE < 0)
|
1767
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1768
|
+
|
1769
|
+
if (SQLCODE == SQLNOTFOUND)
|
1770
|
+
return Qnil;
|
1771
|
+
|
1772
|
+
RECORD(c, type, bang, record);
|
1773
|
+
return make_result(c, record);
|
1774
|
+
}
|
1775
|
+
|
1776
|
+
/*
|
1777
|
+
* call-seq:
|
1778
|
+
* cursor.fetch => array or nil
|
1779
|
+
*
|
1780
|
+
* Fetches the next record.
|
1781
|
+
*
|
1782
|
+
* Returns the record fetched as an array, or nil if there are no
|
1783
|
+
* records left.
|
1784
|
+
*/
|
1785
|
+
static VALUE
|
1786
|
+
seqcur_fetch(VALUE self)
|
1787
|
+
{
|
1788
|
+
return fetch(self, T_ARRAY, 0);
|
1789
|
+
}
|
1790
|
+
|
1791
|
+
/*
|
1792
|
+
* call-seq:
|
1793
|
+
* cursor.fetch! => array or nil
|
1794
|
+
*
|
1795
|
+
* Fetches the next record, storing it in the same Array object every time
|
1796
|
+
* it is called.
|
1797
|
+
*
|
1798
|
+
* Returns the record fetched as an array, or nil if there are no
|
1799
|
+
* records left.
|
1800
|
+
*/
|
1801
|
+
static VALUE
|
1802
|
+
seqcur_fetch_bang(VALUE self)
|
1803
|
+
{
|
1804
|
+
return fetch(self, T_ARRAY, 1);
|
1805
|
+
}
|
1806
|
+
|
1807
|
+
/*
|
1808
|
+
* call-seq:
|
1809
|
+
* cursor.fetch_hash => hash or nil
|
1810
|
+
*
|
1811
|
+
* Fetches the next record.
|
1812
|
+
*
|
1813
|
+
* Returns the record fetched as a hash, or nil if there are no
|
1814
|
+
* records left.
|
1815
|
+
*/
|
1816
|
+
static VALUE
|
1817
|
+
seqcur_fetch_hash(VALUE self)
|
1818
|
+
{
|
1819
|
+
return fetch(self, T_HASH, 0);
|
1820
|
+
}
|
1821
|
+
|
1822
|
+
/*
|
1823
|
+
* call-seq:
|
1824
|
+
* cursor.fetch_hash! => hash or nil
|
1825
|
+
*
|
1826
|
+
* Fetches the next record, storing it in the same Hash object every time
|
1827
|
+
* it is called.
|
1828
|
+
*
|
1829
|
+
* Returns the record fetched as a hash, or nil if there are no
|
1830
|
+
* records left.
|
1831
|
+
*/
|
1832
|
+
static VALUE
|
1833
|
+
seqcur_fetch_hash_bang(VALUE self)
|
1834
|
+
{
|
1835
|
+
return fetch(self, T_HASH, 1);
|
1836
|
+
}
|
1837
|
+
|
1838
|
+
/*
|
1839
|
+
* Base function for fetch*_many, fetch*_all and each_by methods
|
1840
|
+
*/
|
1841
|
+
static VALUE
|
1842
|
+
fetch_many(VALUE self, VALUE n, VALUE type)
|
1843
|
+
{
|
1844
|
+
EXEC SQL begin declare section;
|
1845
|
+
char *cid, *did;
|
1846
|
+
EXEC SQL end declare section;
|
1847
|
+
cursor_t *c;
|
1848
|
+
struct sqlda *output;
|
1849
|
+
VALUE record, records;
|
1850
|
+
register long i, max;
|
1851
|
+
register int all = n == Qnil;
|
1852
|
+
|
1853
|
+
Data_Get_Struct(self, cursor_t, c);
|
1854
|
+
if (!c->is_open)
|
1855
|
+
rb_raise(rb_eRuntimeError, "Open the cursor object first");
|
1856
|
+
|
1857
|
+
did = c->database_id;
|
1858
|
+
if (currentdid != did) {
|
1859
|
+
EXEC SQL set connection :did;
|
1860
|
+
if (SQLCODE < 0)
|
1861
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1862
|
+
currentdid = did;
|
1863
|
+
}
|
1864
|
+
|
1865
|
+
output = c->daOutput;
|
1866
|
+
cid = c->cursor_id;
|
1867
|
+
|
1868
|
+
if (!all) {
|
1869
|
+
max = FIX2LONG(n);
|
1870
|
+
records = rb_ary_new2(max);
|
1871
|
+
}
|
1872
|
+
else {
|
1873
|
+
records = rb_ary_new();
|
1874
|
+
}
|
1875
|
+
|
1876
|
+
for(i = 0; all || i < max; i++) {
|
1877
|
+
EXEC SQL fetch :cid using descriptor output;
|
1878
|
+
if (SQLCODE < 0)
|
1879
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1880
|
+
|
1881
|
+
if (SQLCODE == SQLNOTFOUND)
|
1882
|
+
break;
|
1883
|
+
|
1884
|
+
if (type == T_ARRAY)
|
1885
|
+
record = rb_ary_new2(c->daOutput->sqld);
|
1886
|
+
else
|
1887
|
+
record = rb_hash_new();
|
1888
|
+
rb_ary_store(records, i, make_result(c, record));
|
1889
|
+
}
|
1890
|
+
|
1891
|
+
return records;
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
/*
|
1895
|
+
* call-seq:
|
1896
|
+
* cursor.fetch_many(n) => array
|
1897
|
+
*
|
1898
|
+
* Reads at most <i>n</i> records.
|
1899
|
+
*
|
1900
|
+
* Returns the records read as an array of arrays
|
1901
|
+
*/
|
1902
|
+
static VALUE
|
1903
|
+
seqcur_fetch_many(VALUE self, VALUE n)
|
1904
|
+
{
|
1905
|
+
return fetch_many(self, n, T_ARRAY);
|
1906
|
+
}
|
1907
|
+
|
1908
|
+
/*
|
1909
|
+
* call-seq:
|
1910
|
+
* cursor.fetch_hash_many(n) => array
|
1911
|
+
*
|
1912
|
+
* Reads at most <i>n</i> records.
|
1913
|
+
* Returns the records read as an array of hashes.
|
1914
|
+
*/
|
1915
|
+
static VALUE
|
1916
|
+
seqcur_fetch_hash_many(VALUE self, VALUE n)
|
1917
|
+
{
|
1918
|
+
return fetch_many(self, n, T_HASH);
|
1919
|
+
}
|
1920
|
+
|
1921
|
+
/*
|
1922
|
+
* call-seq:
|
1923
|
+
* cursor.fetch_all => array
|
1924
|
+
*
|
1925
|
+
* Returns all the records left as an array of arrays
|
1926
|
+
*/
|
1927
|
+
static VALUE
|
1928
|
+
seqcur_fetch_all(VALUE self)
|
1929
|
+
{
|
1930
|
+
return fetch_many(self, Qnil, T_ARRAY);
|
1931
|
+
}
|
1932
|
+
|
1933
|
+
/*
|
1934
|
+
* call-seq:
|
1935
|
+
* cursor.fetch_hash_all => array
|
1936
|
+
*
|
1937
|
+
* Returns all the records left as an array of hashes
|
1938
|
+
*/
|
1939
|
+
static VALUE
|
1940
|
+
seqcur_fetch_hash_all(VALUE self)
|
1941
|
+
{
|
1942
|
+
return fetch_many(self, Qnil, T_HASH);
|
1943
|
+
}
|
1944
|
+
|
1945
|
+
/*
|
1946
|
+
* Base function for each* methods, except each*_by
|
1947
|
+
*/
|
1948
|
+
static VALUE
|
1949
|
+
each(VALUE self, VALUE type, int bang)
|
1950
|
+
{
|
1951
|
+
cursor_t *c;
|
1952
|
+
EXEC SQL begin declare section;
|
1953
|
+
char *cid, *did;
|
1954
|
+
EXEC SQL end declare section;
|
1955
|
+
struct sqlda *output;
|
1956
|
+
VALUE record;
|
1957
|
+
|
1958
|
+
Data_Get_Struct(self, cursor_t, c);
|
1959
|
+
if (!c->is_open)
|
1960
|
+
rb_raise(rb_eRuntimeError, "Open the cursor object first");
|
1961
|
+
|
1962
|
+
did = c->database_id;
|
1963
|
+
if (currentdid != did) {
|
1964
|
+
EXEC SQL set connection :did;
|
1965
|
+
if (SQLCODE < 0)
|
1966
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1967
|
+
currentdid = did;
|
1968
|
+
}
|
1969
|
+
|
1970
|
+
output = c->daOutput;
|
1971
|
+
cid = c->cursor_id;
|
1972
|
+
|
1973
|
+
for(;;) {
|
1974
|
+
EXEC SQL fetch :cid using descriptor output;
|
1975
|
+
if (SQLCODE < 0)
|
1976
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
1977
|
+
|
1978
|
+
if (SQLCODE == SQLNOTFOUND)
|
1979
|
+
return self;
|
1980
|
+
RECORD(c, type, bang, record);
|
1981
|
+
rb_yield(make_result(c, record));
|
1982
|
+
}
|
1983
|
+
}
|
1984
|
+
|
1985
|
+
/*
|
1986
|
+
* Base function for each*_by methods
|
1987
|
+
*/
|
1988
|
+
static VALUE
|
1989
|
+
each_by(VALUE self, VALUE n, VALUE type)
|
1990
|
+
{
|
1991
|
+
VALUE records;
|
1992
|
+
|
1993
|
+
for(;;) {
|
1994
|
+
records = fetch_many(self, n, type);
|
1995
|
+
if (RARRAY(records)->len == 0)
|
1996
|
+
return self;
|
1997
|
+
rb_yield(records);
|
1998
|
+
}
|
1999
|
+
}
|
2000
|
+
|
2001
|
+
/*
|
2002
|
+
* call-seq:
|
2003
|
+
* cursor.each {|record| block } => cursor
|
2004
|
+
*
|
2005
|
+
* Iterates over the remaining records, passing each <i>record</i> to the
|
2006
|
+
* <i>block</i> as an array.
|
2007
|
+
*
|
2008
|
+
* Returns __self__.
|
2009
|
+
*/
|
2010
|
+
static VALUE
|
2011
|
+
seqcur_each(VALUE self)
|
2012
|
+
{
|
2013
|
+
return each(self, T_ARRAY, 0);
|
2014
|
+
}
|
2015
|
+
|
2016
|
+
/*
|
2017
|
+
* call-seq:
|
2018
|
+
* cursor.each! {|record| block } => cursor
|
2019
|
+
*
|
2020
|
+
* Iterates over the remaining records, passing each <i>record</i> to the
|
2021
|
+
* <i>block</i> as an array. No new Array objects are created for each record.
|
2022
|
+
* The same Array object is reused in each call.
|
2023
|
+
*
|
2024
|
+
* Returns __self__.
|
2025
|
+
*/
|
2026
|
+
static VALUE
|
2027
|
+
seqcur_each_bang(VALUE self)
|
2028
|
+
{
|
2029
|
+
return each(self, T_ARRAY, 1);
|
2030
|
+
}
|
2031
|
+
|
2032
|
+
/*
|
2033
|
+
* call-seq:
|
2034
|
+
* cursor.each_hash {|record| block } => cursor
|
2035
|
+
*
|
2036
|
+
* Iterates over the remaining records, passing each <i>record</i> to the
|
2037
|
+
* <i>block</i> as a hash.
|
2038
|
+
*
|
2039
|
+
* Returns __self__.
|
2040
|
+
*/
|
2041
|
+
static VALUE
|
2042
|
+
seqcur_each_hash(VALUE self)
|
2043
|
+
{
|
2044
|
+
return each(self, T_HASH, 0);
|
2045
|
+
}
|
2046
|
+
|
2047
|
+
/*
|
2048
|
+
* call-seq:
|
2049
|
+
* cursor.each_hash! {|record| block } => cursor
|
2050
|
+
*
|
2051
|
+
* Iterates over the remaining records, passing each <i>record</i> to the
|
2052
|
+
* <i>block</i> as a hash. No new Hash objects are created for each record.
|
2053
|
+
* The same Hash object is reused in each call.
|
2054
|
+
*
|
2055
|
+
* Returns __self__.
|
2056
|
+
*/
|
2057
|
+
static VALUE
|
2058
|
+
seqcur_each_hash_bang(VALUE self)
|
2059
|
+
{
|
2060
|
+
return each(self, T_HASH, 1);
|
2061
|
+
}
|
2062
|
+
|
2063
|
+
/*
|
2064
|
+
* call-seq:
|
2065
|
+
* cursor.each_by(n) {|records| block } => cursor
|
2066
|
+
*
|
2067
|
+
* Iterates over the remaining records, passing at most <i>n</i> <i>records</i>
|
2068
|
+
* to the <i>block</i> as arrays.
|
2069
|
+
*
|
2070
|
+
* Returns __self__.
|
2071
|
+
*/
|
2072
|
+
static VALUE
|
2073
|
+
seqcur_each_by(VALUE self, VALUE n)
|
2074
|
+
{
|
2075
|
+
return each_by(self, n, T_ARRAY);
|
2076
|
+
}
|
2077
|
+
|
2078
|
+
/*
|
2079
|
+
* call-seq:
|
2080
|
+
* cursor.each_hash_by(n) {|records| block } => cursor
|
2081
|
+
*
|
2082
|
+
* Iterates over the remaining records, passing at most <i>n</i> <i>records</i>
|
2083
|
+
* to the <i>block</i> as hashes.
|
2084
|
+
*
|
2085
|
+
* Returns __self__.
|
2086
|
+
*/
|
2087
|
+
static VALUE
|
2088
|
+
seqcur_each_hash_by(VALUE self, VALUE n)
|
2089
|
+
{
|
2090
|
+
return each_by(self, n, T_HASH);
|
2091
|
+
}
|
2092
|
+
|
2093
|
+
/* module InsertCursor --------------------------------------------------- */
|
2094
|
+
|
2095
|
+
/*
|
2096
|
+
* call-seq:
|
2097
|
+
* cursor.put(*params)
|
2098
|
+
*
|
2099
|
+
* Binds <i>params</i> as input parameters and executes the insert statement.
|
2100
|
+
* The records are not written immediatly to disk, unless the insert buffer
|
2101
|
+
* is full, the <code>flush</code> method is called, the cursor is closed or
|
2102
|
+
* the transaction is commited.
|
2103
|
+
*/
|
2104
|
+
static VALUE
|
2105
|
+
inscur_put(int argc, VALUE *argv, VALUE self)
|
2106
|
+
{
|
2107
|
+
struct sqlda *input;
|
2108
|
+
cursor_t *c;
|
2109
|
+
EXEC SQL begin declare section;
|
2110
|
+
char *cid, *did;
|
2111
|
+
EXEC SQL end declare section;
|
2112
|
+
|
2113
|
+
Data_Get_Struct(self, cursor_t, c);
|
2114
|
+
if (!c->is_open)
|
2115
|
+
rb_raise(rb_eRuntimeError, "Open the cursor object first");
|
2116
|
+
|
2117
|
+
did = c->database_id;
|
2118
|
+
if (currentdid != did) {
|
2119
|
+
EXEC SQL set connection :did;
|
2120
|
+
if (SQLCODE < 0)
|
2121
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2122
|
+
currentdid = did;
|
2123
|
+
}
|
2124
|
+
|
2125
|
+
input = &c->daInput;
|
2126
|
+
cid = c->cursor_id;
|
2127
|
+
|
2128
|
+
bind_input_params(c, argv);
|
2129
|
+
if (argc != input->sqld)
|
2130
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
|
2131
|
+
argc, input->sqld);
|
2132
|
+
|
2133
|
+
EXEC SQL put :cid using descriptor input;
|
2134
|
+
clean_input_slots(c);
|
2135
|
+
if (SQLCODE < 0)
|
2136
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2137
|
+
|
2138
|
+
/* XXX 2-448, Guide to SQL: Sytax*/
|
2139
|
+
return INT2FIX(sqlca.sqlerrd[2]);
|
2140
|
+
}
|
2141
|
+
|
2142
|
+
/*
|
2143
|
+
* call-seq:
|
2144
|
+
* cursor.flush => cursor
|
2145
|
+
*
|
2146
|
+
* Flushes the insert buffer, writing data to disk.
|
2147
|
+
*
|
2148
|
+
* Returns __self__.
|
2149
|
+
*/
|
2150
|
+
static VALUE
|
2151
|
+
inscur_flush(VALUE self)
|
2152
|
+
{
|
2153
|
+
cursor_t *c;
|
2154
|
+
EXEC SQL begin declare section;
|
2155
|
+
char *cid, *did;
|
2156
|
+
EXEC SQL end declare section;
|
2157
|
+
|
2158
|
+
Data_Get_Struct(self, cursor_t, c);
|
2159
|
+
if (!c->is_open)
|
2160
|
+
rb_raise(rb_eRuntimeError, "Open the cursor object first");
|
2161
|
+
|
2162
|
+
did = c->database_id;
|
2163
|
+
if (currentdid != did) {
|
2164
|
+
EXEC SQL set connection :did;
|
2165
|
+
if (SQLCODE < 0)
|
2166
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2167
|
+
currentdid = did;
|
2168
|
+
}
|
2169
|
+
|
2170
|
+
cid = c->cursor_id;
|
2171
|
+
EXEC SQL flush :cid;
|
2172
|
+
return self;
|
2173
|
+
}
|
2174
|
+
|
2175
|
+
/* module ScrollCursor --------------------------------------------------- */
|
2176
|
+
|
2177
|
+
/*
|
2178
|
+
* Provides the Array-like functionality for scroll cursors when using the
|
2179
|
+
* cursor[index] syntax
|
2180
|
+
*/
|
2181
|
+
static VALUE
|
2182
|
+
scrollcur_entry(VALUE self, VALUE index, VALUE type, int bang)
|
2183
|
+
{
|
2184
|
+
cursor_t *c;
|
2185
|
+
struct sqlda *output;
|
2186
|
+
VALUE record;
|
2187
|
+
EXEC SQL begin declare section;
|
2188
|
+
char *cid, *did;
|
2189
|
+
long pos;
|
2190
|
+
EXEC SQL end declare section;
|
2191
|
+
|
2192
|
+
Data_Get_Struct(self, cursor_t, c);
|
2193
|
+
if (!c->is_open)
|
2194
|
+
rb_raise(rb_eRuntimeError, "Open the cursor object first");
|
2195
|
+
|
2196
|
+
did = c->database_id;
|
2197
|
+
if (currentdid != did) {
|
2198
|
+
EXEC SQL set connection :did;
|
2199
|
+
if (SQLCODE < 0)
|
2200
|
+
return Qnil;
|
2201
|
+
currentdid = did;
|
2202
|
+
}
|
2203
|
+
|
2204
|
+
output = c->daOutput;
|
2205
|
+
cid = c->cursor_id;
|
2206
|
+
|
2207
|
+
if (NIL_P(index))
|
2208
|
+
EXEC SQL fetch current :cid using descriptor output;
|
2209
|
+
else if ((pos = NUM2LONG(index) + 1) > 0)
|
2210
|
+
EXEC SQL fetch absolute :pos :cid using descriptor output;
|
2211
|
+
else {
|
2212
|
+
EXEC SQL fetch last :cid;
|
2213
|
+
EXEC SQL fetch relative :pos :cid using descriptor output;
|
2214
|
+
}
|
2215
|
+
|
2216
|
+
if (SQLCODE == SQLNOTFOUND)
|
2217
|
+
return Qnil;
|
2218
|
+
|
2219
|
+
if (SQLCODE < 0)
|
2220
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2221
|
+
|
2222
|
+
RECORD(c, type, bang, record);
|
2223
|
+
return make_result(c, record);
|
2224
|
+
}
|
2225
|
+
|
2226
|
+
/*
|
2227
|
+
* Provides the Array-like functionality for scroll cursors when using the
|
2228
|
+
* cursor[start, length] syntax
|
2229
|
+
*/
|
2230
|
+
static VALUE
|
2231
|
+
scrollcur_subseq(VALUE self, VALUE start, VALUE length, VALUE type)
|
2232
|
+
{
|
2233
|
+
cursor_t *c;
|
2234
|
+
struct sqlda *output;
|
2235
|
+
VALUE first, records;
|
2236
|
+
EXEC SQL begin declare section;
|
2237
|
+
char *cid, *did;
|
2238
|
+
long pos;
|
2239
|
+
EXEC SQL end declare section;
|
2240
|
+
|
2241
|
+
first = scrollcur_entry(self, start, type, 0);
|
2242
|
+
if (NIL_P(first))
|
2243
|
+
return Qnil;
|
2244
|
+
|
2245
|
+
pos = NUM2LONG(length) - 1;
|
2246
|
+
|
2247
|
+
if (pos > 0) {
|
2248
|
+
length = LONG2NUM(pos);
|
2249
|
+
records = fetch_many(self, length, type);
|
2250
|
+
}
|
2251
|
+
else
|
2252
|
+
records = rb_ary_new();
|
2253
|
+
|
2254
|
+
rb_ary_unshift(records, first);
|
2255
|
+
|
2256
|
+
return records;
|
2257
|
+
}
|
2258
|
+
|
2259
|
+
/*
|
2260
|
+
* Base function for slice and slice_hash methods
|
2261
|
+
*/
|
2262
|
+
static VALUE
|
2263
|
+
slice(int argc, VALUE *argv, VALUE self, VALUE type)
|
2264
|
+
{
|
2265
|
+
if (argc == 2) {
|
2266
|
+
if (NUM2LONG(argv[1]) <= 0)
|
2267
|
+
rb_raise(rb_eArgError, "length must be positive");
|
2268
|
+
return scrollcur_subseq(self, argv[0], argv[1], type);
|
2269
|
+
}
|
2270
|
+
if (argc != 1)
|
2271
|
+
rb_scan_args(argc, argv, "11", 0, 0);
|
2272
|
+
|
2273
|
+
return scrollcur_entry(self, argv[0], type, 0);
|
2274
|
+
}
|
2275
|
+
|
2276
|
+
/*
|
2277
|
+
* call-seq:
|
2278
|
+
* cursor[index] => array or nil
|
2279
|
+
* cursor[start, length] => array or nil
|
2280
|
+
* cursor.slice(index) => array or nil
|
2281
|
+
* cursor.slice(start, length) => array or nil
|
2282
|
+
*
|
2283
|
+
* Returns the record at _index_, or returns a subarray starting at _start_
|
2284
|
+
* and continuing for _length_ records. Negative indices count backward from
|
2285
|
+
* the end of the cursor (-1 is the last element). Returns nil if the
|
2286
|
+
* (starting) index is out of range.
|
2287
|
+
*
|
2288
|
+
* <b>Warning</b>: if the (starting) index is negative and out of range, the
|
2289
|
+
* position in the cursor is set to the last record. Otherwise the current
|
2290
|
+
* position in the cursor is preserved.
|
2291
|
+
*/
|
2292
|
+
static VALUE
|
2293
|
+
scrollcur_slice(int argc, VALUE *argv, VALUE self)
|
2294
|
+
{
|
2295
|
+
return slice(argc, argv, self, T_ARRAY);
|
2296
|
+
}
|
2297
|
+
|
2298
|
+
/*
|
2299
|
+
* call-seq:
|
2300
|
+
* cursor.slice!(index) => array or nil
|
2301
|
+
*
|
2302
|
+
* Returns the record at _index_. Negative indices count backward from
|
2303
|
+
* the end of the cursor (-1 is the last element). Returns nil if the index
|
2304
|
+
* is out of range.
|
2305
|
+
*
|
2306
|
+
* Stores the record fetched always in the same Array object.
|
2307
|
+
*
|
2308
|
+
* <b>Warning</b>: if the index is negative and out of range, the
|
2309
|
+
* position in the cursor is set to the last record. Otherwise the current
|
2310
|
+
* position in the cursor is preserved.
|
2311
|
+
*/
|
2312
|
+
static VALUE
|
2313
|
+
scrollcur_slice_bang(VALUE self, VALUE index)
|
2314
|
+
{
|
2315
|
+
return scrollcur_entry(self, index, T_ARRAY, 1);
|
2316
|
+
}
|
2317
|
+
|
2318
|
+
/*
|
2319
|
+
* call-seq:
|
2320
|
+
* cursor.slice_hash(index) => hash or nil
|
2321
|
+
* cursor.slice_hash(start, length) => array or nil
|
2322
|
+
*
|
2323
|
+
* Returns the record at _index_, or returns a subarray starting at _start_
|
2324
|
+
* and continuing for _length_ records. Negative indices count backward from
|
2325
|
+
* the end of the cursor (-1 is the last element). Returns nil if the
|
2326
|
+
* (starting) index is out of range.
|
2327
|
+
*
|
2328
|
+
* <b>Warning</b>: if the (starting) index is negative and out of range, the
|
2329
|
+
* position in the cursor is set to the last record. Otherwise the current
|
2330
|
+
* position in the cursor is preserved.
|
2331
|
+
*/
|
2332
|
+
static VALUE
|
2333
|
+
scrollcur_slice_hash(int argc, VALUE *argv, VALUE self)
|
2334
|
+
{
|
2335
|
+
return slice(argc, argv, self, T_HASH);
|
2336
|
+
}
|
2337
|
+
|
2338
|
+
/*
|
2339
|
+
* call-seq:
|
2340
|
+
* cursor.slice_hash!(index) => hash or nil
|
2341
|
+
*
|
2342
|
+
* Returns the record at _index_. Negative indices count backward from
|
2343
|
+
* the end of the cursor (-1 is the last element). Returns nil if the index
|
2344
|
+
* is out of range.
|
2345
|
+
*
|
2346
|
+
* Stores the record fetched always in the same Hash object.
|
2347
|
+
*
|
2348
|
+
* <b>Warning</b>: if the index is negative and out of range, the
|
2349
|
+
* position in the cursor is set to the last record. Otherwise the current
|
2350
|
+
* position in the cursor is preserved.
|
2351
|
+
*/
|
2352
|
+
static VALUE
|
2353
|
+
scrollcur_slice_hash_bang(VALUE self, VALUE index)
|
2354
|
+
{
|
2355
|
+
return scrollcur_entry(self, index, T_HASH, 1);
|
2356
|
+
}
|
2357
|
+
|
2358
|
+
/*
|
2359
|
+
* Base function for prev* and next* methods
|
2360
|
+
*/
|
2361
|
+
static VALUE
|
2362
|
+
scrollcur_rel(int argc, VALUE *argv, VALUE self, int dir, VALUE type, int bang)
|
2363
|
+
{
|
2364
|
+
cursor_t *c;
|
2365
|
+
struct sqlda *output;
|
2366
|
+
VALUE offset, record;
|
2367
|
+
EXEC SQL begin declare section;
|
2368
|
+
char *cid, *did;
|
2369
|
+
long pos;
|
2370
|
+
EXEC SQL end declare section;
|
2371
|
+
|
2372
|
+
Data_Get_Struct(self, cursor_t, c);
|
2373
|
+
if (!c->is_open)
|
2374
|
+
rb_raise(rb_eRuntimeError, "Open the cursor object first");
|
2375
|
+
|
2376
|
+
did = c->database_id;
|
2377
|
+
if (currentdid != did) {
|
2378
|
+
EXEC SQL set connection :did;
|
2379
|
+
if (SQLCODE < 0)
|
2380
|
+
return Qnil;
|
2381
|
+
currentdid = did;
|
2382
|
+
}
|
2383
|
+
|
2384
|
+
rb_scan_args(argc, argv, "01", &offset);
|
2385
|
+
pos = dir*(NIL_P(offset)? 1: NUM2LONG(offset));
|
2386
|
+
|
2387
|
+
output = c->daOutput;
|
2388
|
+
cid = c->cursor_id;
|
2389
|
+
EXEC SQL fetch relative :pos :cid using descriptor output;
|
2390
|
+
|
2391
|
+
if (SQLCODE == SQLNOTFOUND)
|
2392
|
+
return Qnil;
|
2393
|
+
|
2394
|
+
if (SQLCODE < 0)
|
2395
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2396
|
+
|
2397
|
+
RECORD(c, type, bang, record);
|
2398
|
+
return make_result(c, record);
|
2399
|
+
}
|
2400
|
+
|
2401
|
+
/* call-seq:
|
2402
|
+
* cursor.prev(offset = 1) => array or nil
|
2403
|
+
*
|
2404
|
+
* Returns the previous _offset_ th record. Negative indices count
|
2405
|
+
* forward from the current position. Returns nil if the _offset_ is out of
|
2406
|
+
* range.
|
2407
|
+
*/
|
2408
|
+
static VALUE
|
2409
|
+
scrollcur_prev(int argc, VALUE *argv, VALUE self)
|
2410
|
+
{
|
2411
|
+
return scrollcur_rel(argc, argv, self, -1, T_ARRAY, 0);
|
2412
|
+
}
|
2413
|
+
|
2414
|
+
/* call-seq:
|
2415
|
+
* cursor.prev!(offset = 1) => array or nil
|
2416
|
+
*
|
2417
|
+
* Returns the previous _offset_ th record. Negative indices count
|
2418
|
+
* forward from the current position. Returns nil if the _offset_ is out of
|
2419
|
+
* range.
|
2420
|
+
*
|
2421
|
+
* Stores the record fetched always in the same Array object.
|
2422
|
+
*/
|
2423
|
+
static VALUE
|
2424
|
+
scrollcur_prev_bang(int argc, VALUE *argv, VALUE self)
|
2425
|
+
{
|
2426
|
+
return scrollcur_rel(argc, argv, self, -1, T_ARRAY, 1);
|
2427
|
+
}
|
2428
|
+
|
2429
|
+
/* call-seq:
|
2430
|
+
* cursor.prev_hash(offset = 1) => hash or nil
|
2431
|
+
*
|
2432
|
+
* Returns the previous _offset_ th record. Negative indices count
|
2433
|
+
* forward from the current position. Returns nil if the _offset_ is out of
|
2434
|
+
* range.
|
2435
|
+
*/
|
2436
|
+
static VALUE
|
2437
|
+
scrollcur_prev_hash(int argc, VALUE *argv, VALUE self)
|
2438
|
+
{
|
2439
|
+
return scrollcur_rel(argc, argv, self, -1, T_HASH, 0);
|
2440
|
+
}
|
2441
|
+
|
2442
|
+
/* call-seq:
|
2443
|
+
* cursor.prev_hash!(offset = 1) => hash or nil
|
2444
|
+
*
|
2445
|
+
* Returns the previous _offset_ th record. Negative indices count
|
2446
|
+
* forward from the current position. Returns nil if the _offset_ is out of
|
2447
|
+
* range.
|
2448
|
+
*
|
2449
|
+
* Stores the record fetched always in the same Hash object.
|
2450
|
+
*/
|
2451
|
+
static VALUE
|
2452
|
+
scrollcur_prev_hash_bang(int argc, VALUE *argv, VALUE self)
|
2453
|
+
{
|
2454
|
+
return scrollcur_rel(argc, argv, self, -1, T_HASH, 1);
|
2455
|
+
}
|
2456
|
+
|
2457
|
+
/* call-seq:
|
2458
|
+
* cursor.next(offset = 1) => array or nil
|
2459
|
+
*
|
2460
|
+
* Returns the next _offset_ th record. Negative indices count
|
2461
|
+
* backward from the current position. Returns nil if the _offset_ is out of
|
2462
|
+
* range.
|
2463
|
+
*/
|
2464
|
+
static VALUE
|
2465
|
+
scrollcur_next(int argc, VALUE *argv, VALUE self)
|
2466
|
+
{
|
2467
|
+
return scrollcur_rel(argc, argv, self, 1, T_ARRAY, 0);
|
2468
|
+
}
|
2469
|
+
|
2470
|
+
/* call-seq:
|
2471
|
+
* cursor.next!(offset = 1) => array or nil
|
2472
|
+
*
|
2473
|
+
* Returns the next _offset_ th record. Negative indices count
|
2474
|
+
* backward from the current position. Returns nil if the _offset_ is out of
|
2475
|
+
* range.
|
2476
|
+
*
|
2477
|
+
* Stores the record fetched always in the same Array object.
|
2478
|
+
*/
|
2479
|
+
static VALUE
|
2480
|
+
scrollcur_next_bang(int argc, VALUE *argv, VALUE self)
|
2481
|
+
{
|
2482
|
+
return scrollcur_rel(argc, argv, self, 1, T_ARRAY, 1);
|
2483
|
+
}
|
2484
|
+
|
2485
|
+
/* call-seq:
|
2486
|
+
* cursor.next_hash(offset = 1) => hash or nil
|
2487
|
+
*
|
2488
|
+
* Returns the next _offset_ th record. Negative indices count
|
2489
|
+
* backward from the current position. Returns nil if the _offset_ is out of
|
2490
|
+
* range.
|
2491
|
+
*/
|
2492
|
+
static VALUE
|
2493
|
+
scrollcur_next_hash(int argc, VALUE *argv, VALUE self)
|
2494
|
+
{
|
2495
|
+
return scrollcur_rel(argc, argv, self, 1, T_HASH, 0);
|
2496
|
+
}
|
2497
|
+
|
2498
|
+
/* call-seq:
|
2499
|
+
* cursor.next_hash!(offset = 1) => hash or nil
|
2500
|
+
*
|
2501
|
+
* Returns the next _offset_ th record. Negative indices count
|
2502
|
+
* backward from the current position. Returns nil if the _offset_ is out of
|
2503
|
+
* range.
|
2504
|
+
*
|
2505
|
+
* Stores the record fetched always in the same Hash object.
|
2506
|
+
*/
|
2507
|
+
static VALUE
|
2508
|
+
scrollcur_next_hash_bang(int argc, VALUE *argv, VALUE self)
|
2509
|
+
{
|
2510
|
+
return scrollcur_rel(argc, argv, self, 1, T_HASH, 1);
|
2511
|
+
}
|
2512
|
+
|
2513
|
+
/*
|
2514
|
+
* call-seq:
|
2515
|
+
* cursor.first => array or nil
|
2516
|
+
*
|
2517
|
+
* Returns the first record of the cursor. If the cursor is empty,
|
2518
|
+
* returns nil.
|
2519
|
+
*/
|
2520
|
+
static VALUE
|
2521
|
+
scrollcur_first(VALUE self)
|
2522
|
+
{
|
2523
|
+
return scrollcur_entry(self, INT2FIX(0), T_ARRAY, 0);
|
2524
|
+
}
|
2525
|
+
|
2526
|
+
/*
|
2527
|
+
* call-seq:
|
2528
|
+
* cursor.first! => array or nil
|
2529
|
+
*
|
2530
|
+
* Returns the first record of the cursor. If the cursor is empty,
|
2531
|
+
* returns nil.
|
2532
|
+
*
|
2533
|
+
* Stores the record fetched always in the same Array object.
|
2534
|
+
*/
|
2535
|
+
static VALUE
|
2536
|
+
scrollcur_first_bang(VALUE self)
|
2537
|
+
{
|
2538
|
+
return scrollcur_entry(self, INT2FIX(0), T_ARRAY, 1);
|
2539
|
+
}
|
2540
|
+
|
2541
|
+
/*
|
2542
|
+
* call-seq:
|
2543
|
+
* cursor.first_hash => hash or nil
|
2544
|
+
*
|
2545
|
+
* Returns the first record of the cursor. If the cursor is empty,
|
2546
|
+
* returns nil.
|
2547
|
+
*/
|
2548
|
+
static VALUE
|
2549
|
+
scrollcur_first_hash(VALUE self)
|
2550
|
+
{
|
2551
|
+
return scrollcur_entry(self, INT2FIX(0), T_HASH, 0);
|
2552
|
+
}
|
2553
|
+
|
2554
|
+
/*
|
2555
|
+
* call-seq:
|
2556
|
+
* cursor.first_hash! => hash or nil
|
2557
|
+
*
|
2558
|
+
* Returns the first record of the cursor. If the cursor is empty,
|
2559
|
+
* returns nil.
|
2560
|
+
*
|
2561
|
+
* Stores the record fetched always in the same Hash object.
|
2562
|
+
*/
|
2563
|
+
static VALUE
|
2564
|
+
scrollcur_first_hash_bang(VALUE self)
|
2565
|
+
{
|
2566
|
+
return scrollcur_entry(self, INT2FIX(0), T_HASH, 1);
|
2567
|
+
}
|
2568
|
+
|
2569
|
+
/*
|
2570
|
+
* call-seq:
|
2571
|
+
* cursor.last => array or nil
|
2572
|
+
*
|
2573
|
+
* Returns the last record of the cursor. If the cursor is empty,
|
2574
|
+
* returns nil.
|
2575
|
+
*/
|
2576
|
+
static VALUE
|
2577
|
+
scrollcur_last(VALUE self)
|
2578
|
+
{
|
2579
|
+
return scrollcur_entry(self, INT2FIX(-1), T_ARRAY, 0);
|
2580
|
+
}
|
2581
|
+
|
2582
|
+
/*
|
2583
|
+
* call-seq:
|
2584
|
+
* cursor.last! => array or nil
|
2585
|
+
*
|
2586
|
+
* Returns the last record of the cursor. If the cursor is empty,
|
2587
|
+
* returns nil.
|
2588
|
+
*
|
2589
|
+
* Stores the record fetched always in the same Array object.
|
2590
|
+
*/
|
2591
|
+
static VALUE
|
2592
|
+
scrollcur_last_bang(VALUE self)
|
2593
|
+
{
|
2594
|
+
return scrollcur_entry(self, INT2FIX(-1), T_ARRAY, 1);
|
2595
|
+
}
|
2596
|
+
|
2597
|
+
/*
|
2598
|
+
* call-seq:
|
2599
|
+
* cursor.last_hash => hash or nil
|
2600
|
+
*
|
2601
|
+
* Returns the last record of the cursor. If the cursor is empty,
|
2602
|
+
* returns nil.
|
2603
|
+
*/
|
2604
|
+
static VALUE
|
2605
|
+
scrollcur_last_hash(VALUE self)
|
2606
|
+
{
|
2607
|
+
return scrollcur_entry(self, INT2FIX(-1), T_HASH, 0);
|
2608
|
+
}
|
2609
|
+
|
2610
|
+
/*
|
2611
|
+
* call-seq:
|
2612
|
+
* cursor.last_hash! => hash or nil
|
2613
|
+
*
|
2614
|
+
* Returns the last record of the cursor. If the cursor is empty,
|
2615
|
+
* returns nil.
|
2616
|
+
*
|
2617
|
+
* Stores the record fetched always in the same Hash object.
|
2618
|
+
*/
|
2619
|
+
static VALUE
|
2620
|
+
scrollcur_last_hash_bang(VALUE self)
|
2621
|
+
{
|
2622
|
+
return scrollcur_entry(self, INT2FIX(-1), T_HASH, 1);
|
2623
|
+
}
|
2624
|
+
|
2625
|
+
/*
|
2626
|
+
* call-seq:
|
2627
|
+
* cursor.current => array or nil
|
2628
|
+
*
|
2629
|
+
* Returns the current record of the cursor. If the cursor is empty,
|
2630
|
+
* returns nil.
|
2631
|
+
*/
|
2632
|
+
static VALUE
|
2633
|
+
scrollcur_current(VALUE self)
|
2634
|
+
{
|
2635
|
+
return scrollcur_entry(self, Qnil, T_ARRAY, 0);
|
2636
|
+
}
|
2637
|
+
|
2638
|
+
/*
|
2639
|
+
* call-seq:
|
2640
|
+
* cursor.current! => array or nil
|
2641
|
+
*
|
2642
|
+
* Returns the current record of the cursor. If the cursor is empty,
|
2643
|
+
* returns nil.
|
2644
|
+
*
|
2645
|
+
* Stores the record fetched always in the same Array object.
|
2646
|
+
*/
|
2647
|
+
static VALUE
|
2648
|
+
scrollcur_current_bang(VALUE self)
|
2649
|
+
{
|
2650
|
+
return scrollcur_entry(self, Qnil, T_ARRAY, 1);
|
2651
|
+
}
|
2652
|
+
|
2653
|
+
/*
|
2654
|
+
* call-seq:
|
2655
|
+
* cursor.current_hash => hash or nil
|
2656
|
+
*
|
2657
|
+
* Returns the current record of the cursor. If the cursor is empty,
|
2658
|
+
* returns nil.
|
2659
|
+
*/
|
2660
|
+
static VALUE
|
2661
|
+
scrollcur_current_hash(VALUE self)
|
2662
|
+
{
|
2663
|
+
return scrollcur_entry(self, Qnil, T_HASH, 0);
|
2664
|
+
}
|
2665
|
+
|
2666
|
+
/*
|
2667
|
+
* call-seq:
|
2668
|
+
* cursor.current_hash! => hash or nil
|
2669
|
+
*
|
2670
|
+
* Returns the current record of the cursor. If the cursor is empty,
|
2671
|
+
* returns nil.
|
2672
|
+
*
|
2673
|
+
* Stores the record fetched always in the same Hash object.
|
2674
|
+
*/
|
2675
|
+
static VALUE
|
2676
|
+
scrollcur_current_hash_bang(VALUE self)
|
2677
|
+
{
|
2678
|
+
return scrollcur_entry(self, Qnil, T_HASH, 1);
|
2679
|
+
}
|
2680
|
+
|
2681
|
+
/* class Cursor ---------------------------------------------------------- */
|
2682
|
+
static void
|
2683
|
+
cursor_close_or_free(cursor_t *c, short op)
|
2684
|
+
{
|
2685
|
+
EXEC SQL begin declare section;
|
2686
|
+
char *cid, *sid, *did;
|
2687
|
+
EXEC SQL end declare section;
|
2688
|
+
|
2689
|
+
if (op == 1 && !c->is_open)
|
2690
|
+
return;
|
2691
|
+
|
2692
|
+
c->is_open = 0;
|
2693
|
+
if (op == 1)
|
2694
|
+
clean_input_slots(c);
|
2695
|
+
else {
|
2696
|
+
free_input_slots(c);
|
2697
|
+
free_output_slots(c);
|
2698
|
+
}
|
2699
|
+
|
2700
|
+
did = c->database_id;
|
2701
|
+
if (currentdid != did) {
|
2702
|
+
EXEC SQL set connection :did;
|
2703
|
+
if (SQLCODE < 0)
|
2704
|
+
return;
|
2705
|
+
currentdid = did;
|
2706
|
+
}
|
2707
|
+
|
2708
|
+
cid = c->cursor_id;
|
2709
|
+
EXEC SQL close :cid;
|
2710
|
+
|
2711
|
+
if (op == 2) {
|
2712
|
+
sid = c->stmt_id;
|
2713
|
+
EXEC SQL free :cid; EXEC SQL free :sid;
|
2714
|
+
}
|
2715
|
+
}
|
2716
|
+
|
2717
|
+
static void
|
2718
|
+
cursor_mark(cursor_t *c)
|
2719
|
+
{
|
2720
|
+
rb_gc_mark(c->db);
|
2721
|
+
if (c->array)
|
2722
|
+
rb_gc_mark(c->array);
|
2723
|
+
if (c->hash)
|
2724
|
+
rb_gc_mark(c->hash);
|
2725
|
+
if (c->field_names)
|
2726
|
+
rb_gc_mark(c->field_names);
|
2727
|
+
}
|
2728
|
+
|
2729
|
+
static void
|
2730
|
+
cursor_free(void *p)
|
2731
|
+
{
|
2732
|
+
cursor_close_or_free(p, 2);
|
2733
|
+
xfree(p);
|
2734
|
+
}
|
2735
|
+
|
2736
|
+
static VALUE
|
2737
|
+
cursor_alloc(VALUE klass)
|
2738
|
+
{
|
2739
|
+
cursor_t *c;
|
2740
|
+
|
2741
|
+
c = ALLOC(cursor_t);
|
2742
|
+
memset(c, 0, sizeof(cursor_t));
|
2743
|
+
return Data_Wrap_Struct(klass, cursor_mark, cursor_free, c);
|
2744
|
+
}
|
2745
|
+
|
2746
|
+
/*
|
2747
|
+
* call-seq:
|
2748
|
+
* Cursor.new(database, query, options) => cursor
|
2749
|
+
*
|
2750
|
+
* Prepares <i>query</i> in the context of <i>database</i> with <i>options</i>
|
2751
|
+
* and returns a <code>Cursor</code> object.
|
2752
|
+
*
|
2753
|
+
* <i>options</i> can be nil or a hash with the following possible keys:
|
2754
|
+
*
|
2755
|
+
* :scroll => true or false
|
2756
|
+
* :hold => true or false
|
2757
|
+
*/
|
2758
|
+
static VALUE
|
2759
|
+
cursor_initialize(VALUE self, VALUE db, VALUE query, VALUE options)
|
2760
|
+
{
|
2761
|
+
VALUE scroll, hold;
|
2762
|
+
struct sqlda *output;
|
2763
|
+
cursor_t *c;
|
2764
|
+
EXEC SQL begin declare section;
|
2765
|
+
char *c_query;
|
2766
|
+
char *cid, *sid, *did;
|
2767
|
+
EXEC SQL end declare section;
|
2768
|
+
|
2769
|
+
Data_Get_Struct(db, char, did);
|
2770
|
+
|
2771
|
+
if (currentdid != did) {
|
2772
|
+
EXEC SQL set connection :did;
|
2773
|
+
if (SQLCODE < 0)
|
2774
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2775
|
+
currentdid = did;
|
2776
|
+
}
|
2777
|
+
|
2778
|
+
Data_Get_Struct(self, cursor_t, c);
|
2779
|
+
c->db = db;
|
2780
|
+
c->database_id = did;
|
2781
|
+
scroll = hold = Qfalse;
|
2782
|
+
snprintf(c->cursor_id, sizeof(c->cursor_id), "CUR%lX", self);
|
2783
|
+
snprintf(c->stmt_id, sizeof(c->stmt_id), "STMT%lX", self);
|
2784
|
+
cid = c->cursor_id; sid = c->stmt_id;
|
2785
|
+
c_query = StringValueCStr(query);
|
2786
|
+
|
2787
|
+
if (RTEST(options)) {
|
2788
|
+
scroll = rb_hash_aref(options, sym_scroll);
|
2789
|
+
hold = rb_hash_aref(options, sym_hold);
|
2790
|
+
}
|
2791
|
+
|
2792
|
+
EXEC SQL prepare :sid from :c_query;
|
2793
|
+
if (SQLCODE < 0)
|
2794
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2795
|
+
|
2796
|
+
if (RTEST(scroll) && RTEST(hold))
|
2797
|
+
EXEC SQL declare :cid scroll cursor with hold for :sid;
|
2798
|
+
else if (RTEST(hold))
|
2799
|
+
EXEC SQL declare :cid cursor with hold for :sid;
|
2800
|
+
else if (RTEST(scroll))
|
2801
|
+
EXEC SQL declare :cid scroll cursor for :sid;
|
2802
|
+
else
|
2803
|
+
EXEC SQL declare :cid cursor for :sid;
|
2804
|
+
|
2805
|
+
if (SQLCODE < 0)
|
2806
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2807
|
+
|
2808
|
+
alloc_input_slots(c, c_query);
|
2809
|
+
EXEC SQL describe :sid into output;
|
2810
|
+
c->daOutput = output;
|
2811
|
+
|
2812
|
+
c->is_select = (SQLCODE == 0 || SQLCODE == SQ_EXECPROC);
|
2813
|
+
|
2814
|
+
if (c->is_select) {
|
2815
|
+
alloc_output_slots(c);
|
2816
|
+
rb_extend_object(self, rb_mSequentialCursor);
|
2817
|
+
if (scroll)
|
2818
|
+
rb_extend_object(self, rb_mScrollCursor);
|
2819
|
+
}
|
2820
|
+
else {
|
2821
|
+
xfree(c->daOutput);
|
2822
|
+
c->daOutput = NULL;
|
2823
|
+
rb_extend_object(self, rb_mInsertCursor);
|
2824
|
+
}
|
2825
|
+
return self;
|
2826
|
+
}
|
2827
|
+
|
2828
|
+
/*
|
2829
|
+
* call-seq:
|
2830
|
+
* cursor.id => string
|
2831
|
+
*
|
2832
|
+
* Returns the cursor ID
|
2833
|
+
*/
|
2834
|
+
static VALUE
|
2835
|
+
cursor_id(VALUE self)
|
2836
|
+
{
|
2837
|
+
cursor_t *c;
|
2838
|
+
|
2839
|
+
Data_Get_Struct(self, cursor_t, c);
|
2840
|
+
return rb_str_new2(c->cursor_id);
|
2841
|
+
}
|
2842
|
+
|
2843
|
+
/*
|
2844
|
+
* call-seq:
|
2845
|
+
* cursor.open(*params) => cursor
|
2846
|
+
*
|
2847
|
+
* Executes the previously prepared select statement, binding <i>params</i> as
|
2848
|
+
* input parameters.
|
2849
|
+
*
|
2850
|
+
* Returns __self__.
|
2851
|
+
*/
|
2852
|
+
static VALUE
|
2853
|
+
cursor_open(int argc, VALUE *argv, VALUE self)
|
2854
|
+
{
|
2855
|
+
struct sqlda *input;
|
2856
|
+
cursor_t *c;
|
2857
|
+
EXEC SQL begin declare section;
|
2858
|
+
char *cid, *did;
|
2859
|
+
EXEC SQL end declare section;
|
2860
|
+
|
2861
|
+
Data_Get_Struct(self, cursor_t, c);
|
2862
|
+
|
2863
|
+
if (c->is_open)
|
2864
|
+
return self;
|
2865
|
+
|
2866
|
+
did = c->database_id;
|
2867
|
+
if (currentdid != did) {
|
2868
|
+
EXEC SQL set connection :did;
|
2869
|
+
if (SQLCODE < 0)
|
2870
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2871
|
+
currentdid = did;
|
2872
|
+
}
|
2873
|
+
|
2874
|
+
input = &c->daInput;
|
2875
|
+
cid = c->cursor_id;
|
2876
|
+
|
2877
|
+
if (c->is_select) {
|
2878
|
+
if (argc != input->sqld) {
|
2879
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
|
2880
|
+
argc, input->sqld);
|
2881
|
+
}
|
2882
|
+
if (argc) {
|
2883
|
+
bind_input_params(c, argv);
|
2884
|
+
EXEC SQL open :cid using descriptor input
|
2885
|
+
with reoptimization;
|
2886
|
+
clean_input_slots(c);
|
2887
|
+
}
|
2888
|
+
else
|
2889
|
+
EXEC SQL open :cid with reoptimization;
|
2890
|
+
}
|
2891
|
+
else
|
2892
|
+
EXEC SQL open :cid;
|
2893
|
+
|
2894
|
+
if (SQLCODE < 0)
|
2895
|
+
rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
|
2896
|
+
|
2897
|
+
c->is_open = 1;
|
2898
|
+
return self;
|
2899
|
+
}
|
2900
|
+
|
2901
|
+
/*
|
2902
|
+
* call-seq:
|
2903
|
+
* cursor.close => cursor
|
2904
|
+
*
|
2905
|
+
* Closes the cursor and returns __self__.
|
2906
|
+
*/
|
2907
|
+
static VALUE
|
2908
|
+
cursor_close(VALUE self)
|
2909
|
+
{
|
2910
|
+
cursor_t *c;
|
2911
|
+
|
2912
|
+
Data_Get_Struct(self, cursor_t, c);
|
2913
|
+
cursor_close_or_free(c, 1);
|
2914
|
+
return self;
|
2915
|
+
}
|
2916
|
+
|
2917
|
+
/*
|
2918
|
+
* call-seq:
|
2919
|
+
* cursor.drop => nil
|
2920
|
+
*
|
2921
|
+
* Closes the cursor and frees the memory associated with it. The cursor
|
2922
|
+
* cannot be opened again.
|
2923
|
+
*/
|
2924
|
+
static VALUE
|
2925
|
+
cursor_drop(VALUE self)
|
2926
|
+
{
|
2927
|
+
cursor_t *c;
|
2928
|
+
|
2929
|
+
Data_Get_Struct(self, cursor_t, c);
|
2930
|
+
cursor_close_or_free(c, 2);
|
2931
|
+
|
2932
|
+
return Qnil;
|
2933
|
+
}
|
2934
|
+
|
2935
|
+
/* Entry point ------------------------------------------------------------ */
|
2936
|
+
|
2937
|
+
void Init_informix(void)
|
2938
|
+
{
|
2939
|
+
/* module Informix ---------------------------------------------------- */
|
2940
|
+
rb_mInformix = rb_define_module("Informix");
|
2941
|
+
rb_mScrollCursor = rb_define_module_under(rb_mInformix, "ScrollCursor");
|
2942
|
+
rb_mInsertCursor = rb_define_module_under(rb_mInformix, "InsertCursor");
|
2943
|
+
rb_define_module_function(rb_mInformix, "connect", informix_connect, -1);
|
2944
|
+
|
2945
|
+
/* class Slob --------------------------------------------------------- */
|
2946
|
+
rb_cSlob = rb_define_class_under(rb_mInformix, "Slob", rb_cObject);
|
2947
|
+
rb_define_alloc_func(rb_cSlob, slob_alloc);
|
2948
|
+
rb_define_method(rb_cSlob, "initialize", slob_initialize, -1);
|
2949
|
+
rb_define_method(rb_cSlob, "open", slob_open, -1);
|
2950
|
+
rb_define_method(rb_cSlob, "close", slob_close, 0);
|
2951
|
+
rb_define_method(rb_cSlob, "read", slob_read, 1);
|
2952
|
+
rb_define_method(rb_cSlob, "write", slob_write, 1);
|
2953
|
+
rb_define_method(rb_cSlob, "seek", slob_seek, 2);
|
2954
|
+
rb_define_method(rb_cSlob, "tell", slob_tell, 0);
|
2955
|
+
rb_define_method(rb_cSlob, "truncate", slob_truncate, 1);
|
2956
|
+
|
2957
|
+
rb_define_const(rb_cSlob, "CLOB", INT2FIX(XID_CLOB));
|
2958
|
+
rb_define_const(rb_cSlob, "BLOB", INT2FIX(XID_BLOB));
|
2959
|
+
|
2960
|
+
#define DEF_SLOB_CONST(k) rb_define_const(rb_cSlob, #k, INT2FIX(LO_##k))
|
2961
|
+
|
2962
|
+
DEF_SLOB_CONST(RDONLY);
|
2963
|
+
DEF_SLOB_CONST(DIRTY_READ);
|
2964
|
+
DEF_SLOB_CONST(WRONLY);
|
2965
|
+
DEF_SLOB_CONST(APPEND);
|
2966
|
+
DEF_SLOB_CONST(RDWR);
|
2967
|
+
DEF_SLOB_CONST(BUFFER);
|
2968
|
+
DEF_SLOB_CONST(NOBUFFER);
|
2969
|
+
DEF_SLOB_CONST(LOCKALL);
|
2970
|
+
DEF_SLOB_CONST(LOCKRANGE);
|
2971
|
+
DEF_SLOB_CONST(SEEK_SET);
|
2972
|
+
DEF_SLOB_CONST(SEEK_CUR);
|
2973
|
+
DEF_SLOB_CONST(SEEK_END);
|
2974
|
+
|
2975
|
+
/* class Database ----------------------------------------------------- */
|
2976
|
+
rb_cDatabase = rb_define_class_under(rb_mInformix, "Database", rb_cObject);
|
2977
|
+
rb_define_alloc_func(rb_cDatabase, database_alloc);
|
2978
|
+
rb_define_method(rb_cDatabase, "initialize", database_initialize, -1);
|
2979
|
+
rb_define_alias(rb_cDatabase, "open", "initialize");
|
2980
|
+
rb_define_method(rb_cDatabase, "close", database_close, 0);
|
2981
|
+
rb_define_method(rb_cDatabase, "immediate", database_immediate, 1);
|
2982
|
+
rb_define_alias(rb_cDatabase, "do", "immediate");
|
2983
|
+
rb_define_method(rb_cDatabase, "rollback", database_rollback, 0);
|
2984
|
+
rb_define_method(rb_cDatabase, "commit", database_commit, 0);
|
2985
|
+
rb_define_method(rb_cDatabase, "transaction", database_transaction, 0);
|
2986
|
+
rb_define_method(rb_cDatabase, "prepare", database_prepare, 1);
|
2987
|
+
rb_define_method(rb_cDatabase, "columns", database_columns, 1);
|
2988
|
+
rb_define_method(rb_cDatabase, "cursor", database_cursor, -1);
|
2989
|
+
|
2990
|
+
/* class Statement ---------------------------------------------------- */
|
2991
|
+
rb_cStatement = rb_define_class_under(rb_mInformix, "Statement", rb_cObject);
|
2992
|
+
rb_define_alloc_func(rb_cStatement, statement_alloc);
|
2993
|
+
rb_define_method(rb_cStatement, "initialize", statement_initialize, 2);
|
2994
|
+
rb_define_method(rb_cStatement, "[]", statement_call, -1);
|
2995
|
+
rb_define_alias(rb_cStatement, "call", "[]");
|
2996
|
+
rb_define_alias(rb_cStatement, "execute", "[]");
|
2997
|
+
rb_define_method(rb_cStatement, "drop", statement_drop, 0);
|
2998
|
+
|
2999
|
+
/* module SequentialCursor -------------------------------------------- */
|
3000
|
+
rb_mSequentialCursor = rb_define_module_under(rb_mInformix, "SequentialCursor");
|
3001
|
+
rb_define_method(rb_mSequentialCursor, "fetch", seqcur_fetch, 0);
|
3002
|
+
rb_define_method(rb_mSequentialCursor, "fetch!", seqcur_fetch_bang, 0);
|
3003
|
+
rb_define_method(rb_mSequentialCursor, "fetch_hash", seqcur_fetch_hash, 0);
|
3004
|
+
rb_define_method(rb_mSequentialCursor, "fetch_hash!", seqcur_fetch_hash_bang, 0);
|
3005
|
+
rb_define_method(rb_mSequentialCursor, "fetch_many", seqcur_fetch_many, 1);
|
3006
|
+
rb_define_method(rb_mSequentialCursor, "fetch_hash_many", seqcur_fetch_hash_many, 1);
|
3007
|
+
rb_define_method(rb_mSequentialCursor, "fetch_all", seqcur_fetch_all, 0);
|
3008
|
+
rb_define_method(rb_mSequentialCursor, "fetch_hash_all", seqcur_fetch_hash_all, 0);
|
3009
|
+
rb_define_method(rb_mSequentialCursor, "each", seqcur_each, 0);
|
3010
|
+
rb_define_method(rb_mSequentialCursor, "each!", seqcur_each_bang, 0);
|
3011
|
+
rb_define_method(rb_mSequentialCursor, "each_hash", seqcur_each_hash, 0);
|
3012
|
+
rb_define_method(rb_mSequentialCursor, "each_hash!", seqcur_each_hash_bang, 0);
|
3013
|
+
rb_define_method(rb_mSequentialCursor, "each_by", seqcur_each_by, 1);
|
3014
|
+
rb_define_method(rb_mSequentialCursor, "each_hash_by", seqcur_each_hash_by, 1);
|
3015
|
+
|
3016
|
+
/* InsertCursor ------------------------------------------------------- */
|
3017
|
+
rb_define_method(rb_mInsertCursor, "put", inscur_put, -1);
|
3018
|
+
rb_define_method(rb_mInsertCursor, "flush", inscur_flush, 0);
|
3019
|
+
|
3020
|
+
/* ScrollCursor ------------------------------------------------------- */
|
3021
|
+
rb_define_method(rb_mScrollCursor, "[]", scrollcur_slice, -1);
|
3022
|
+
rb_define_alias(rb_mScrollCursor, "slice", "[]");
|
3023
|
+
rb_define_method(rb_mScrollCursor, "slice!", scrollcur_slice_bang, 1);
|
3024
|
+
rb_define_method(rb_mScrollCursor, "slice_hash", scrollcur_slice_hash, -1);
|
3025
|
+
rb_define_method(rb_mScrollCursor, "slice_hash!", scrollcur_slice_hash_bang, 1);
|
3026
|
+
rb_define_method(rb_mScrollCursor, "prev", scrollcur_prev, -1);
|
3027
|
+
rb_define_method(rb_mScrollCursor, "prev!", scrollcur_prev_bang, -1);
|
3028
|
+
rb_define_method(rb_mScrollCursor, "prev_hash", scrollcur_prev_hash, -1);
|
3029
|
+
rb_define_method(rb_mScrollCursor, "prev_hash!", scrollcur_prev_hash_bang, -1);
|
3030
|
+
rb_define_method(rb_mScrollCursor, "next", scrollcur_next, -1);
|
3031
|
+
rb_define_method(rb_mScrollCursor, "next!", scrollcur_next_bang, -1);
|
3032
|
+
rb_define_method(rb_mScrollCursor, "next_hash", scrollcur_next_hash, -1);
|
3033
|
+
rb_define_method(rb_mScrollCursor, "next_hash!", scrollcur_next_hash_bang, -1);
|
3034
|
+
rb_define_method(rb_mScrollCursor, "first", scrollcur_first, 0);
|
3035
|
+
rb_define_method(rb_mScrollCursor, "first!", scrollcur_first_bang, 0);
|
3036
|
+
rb_define_method(rb_mScrollCursor, "first_hash", scrollcur_first_hash, 0);
|
3037
|
+
rb_define_method(rb_mScrollCursor, "first_hash!", scrollcur_first_hash_bang, 0);
|
3038
|
+
rb_define_method(rb_mScrollCursor, "last", scrollcur_last, 0);
|
3039
|
+
rb_define_method(rb_mScrollCursor, "last!", scrollcur_last_bang, 0);
|
3040
|
+
rb_define_method(rb_mScrollCursor, "last_hash", scrollcur_last_hash, 0);
|
3041
|
+
rb_define_method(rb_mScrollCursor, "last_hash!", scrollcur_last_hash_bang, 0);
|
3042
|
+
rb_define_method(rb_mScrollCursor, "current", scrollcur_current, 0);
|
3043
|
+
rb_define_method(rb_mScrollCursor, "current!", scrollcur_current_bang, 0);
|
3044
|
+
rb_define_method(rb_mScrollCursor, "current_hash", scrollcur_current_hash, 0);
|
3045
|
+
rb_define_method(rb_mScrollCursor, "current_hash!", scrollcur_current_hash_bang, 0);
|
3046
|
+
|
3047
|
+
/* class Cursor ------------------------------------------------------- */
|
3048
|
+
rb_cCursor = rb_define_class_under(rb_mInformix, "Cursor", rb_cObject);
|
3049
|
+
rb_define_alloc_func(rb_cCursor, cursor_alloc);
|
3050
|
+
rb_define_method(rb_cCursor, "initialize", cursor_initialize, 3);
|
3051
|
+
rb_define_method(rb_cCursor, "id", cursor_id, 0);
|
3052
|
+
rb_define_method(rb_cCursor, "open", cursor_open, -1);
|
3053
|
+
rb_define_method(rb_cCursor, "close", cursor_close, 0);
|
3054
|
+
rb_define_method(rb_cCursor, "drop", cursor_drop, 0);
|
3055
|
+
|
3056
|
+
/* Global constants --------------------------------------------------- */
|
3057
|
+
rb_require("date");
|
3058
|
+
rb_cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
3059
|
+
|
3060
|
+
/* Global symbols ----------------------------------------------------- */
|
3061
|
+
s_read = rb_intern("read");
|
3062
|
+
s_new = rb_intern("new");
|
3063
|
+
s_utc = rb_intern("utc");
|
3064
|
+
s_day = rb_intern("day");
|
3065
|
+
s_month = rb_intern("month");
|
3066
|
+
s_year = rb_intern("year");
|
3067
|
+
s_hour = rb_intern("hour");
|
3068
|
+
s_min = rb_intern("min");
|
3069
|
+
s_sec = rb_intern("sec");
|
3070
|
+
s_usec = rb_intern("usec");
|
3071
|
+
s_to_s = rb_intern("to_s");
|
3072
|
+
s_to_i = rb_intern("to_i");
|
3073
|
+
|
3074
|
+
sym_name = ID2SYM(rb_intern("name"));
|
3075
|
+
sym_type = ID2SYM(rb_intern("type"));
|
3076
|
+
sym_nullable = ID2SYM(rb_intern("nullable"));
|
3077
|
+
sym_stype = ID2SYM(rb_intern("stype"));
|
3078
|
+
sym_length = ID2SYM(rb_intern("length"));
|
3079
|
+
sym_precision = ID2SYM(rb_intern("precision"));
|
3080
|
+
sym_scale = ID2SYM(rb_intern("scale"));
|
3081
|
+
sym_default = ID2SYM(rb_intern("default"));
|
3082
|
+
sym_xid = ID2SYM(rb_intern("xid"));
|
3083
|
+
|
3084
|
+
sym_scroll = ID2SYM(rb_intern("scroll"));
|
3085
|
+
sym_hold = ID2SYM(rb_intern("hold"));
|
3086
|
+
|
3087
|
+
sym_col_info = ID2SYM(rb_intern("col_info"));
|
3088
|
+
sym_sbspace = ID2SYM(rb_intern("sbspace"));
|
3089
|
+
sym_estbytes = ID2SYM(rb_intern("estbytes"));
|
3090
|
+
sym_extsz = ID2SYM(rb_intern("extsz"));
|
3091
|
+
sym_createflags = ID2SYM(rb_intern("createflags"));
|
3092
|
+
sym_openflags = ID2SYM(rb_intern("openflags"));
|
3093
|
+
}
|