ruby-informix 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/COPYRIGHT +26 -0
  2. data/Changelog +84 -0
  3. data/README +80 -0
  4. data/extconf.rb +36 -0
  5. data/informix.c +4048 -0
  6. data/informix.ec +3093 -0
  7. metadata +50 -0
data/COPYRIGHT ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2006-2007, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ 3. The name of the author may not be used to endorse or promote products
14
+ derived from this software without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ POSSIBILITY OF SUCH DAMAGE.
data/Changelog ADDED
@@ -0,0 +1,84 @@
1
+ 0.4.0 12/13/2006
2
+ ------------------
3
+ New features:
4
+ * Support for multiple connections to databases
5
+ * Support for scroll cursors. Methods available:
6
+ - [], slice
7
+ - prev, next, first, last, current
8
+ - prev_hash, next_hash, first_hash, last_hash, current_hash
9
+ - slice!, prev!, next!, first!, last!, current!
10
+ - slice_hash, prev_hash, next_hash, first_hash, last_hash,
11
+ current_hash!
12
+ - slice_hash!, prev_hash!, next_hash!, first_hash!, last_hash!,
13
+ current_hash!
14
+ * New Cursor#id method that returns the cursor name for use in
15
+ update cursors
16
+
17
+ Bugs fixed:
18
+ * Memory for input parameters was allocated before statement/cursor
19
+ preparation but not freed if preparation failed.
20
+
21
+
22
+ 0.3.0 11/26/2006
23
+ ------------------
24
+ New features:
25
+ * Initial support for Smart Large Objects (BLOB/CLOB).
26
+ Operations supported:
27
+ - new
28
+ - open, close
29
+ - read, write
30
+ - seek, tell
31
+ - truncate
32
+ * Database#columns now also returns the extended id (xid)
33
+ * small documentation improvements and fixes
34
+
35
+
36
+ 0.2.1 11/11/2006
37
+ ------------------
38
+ Bugs fixed:
39
+ * changing free() for xfree() avoids crashes on Windows XP SP1. Noticed
40
+ by Dinko <dsrkoc at helix hr>
41
+
42
+
43
+ 0.2.0 04/24/2006
44
+ ------------------
45
+ New features:
46
+ * Methods added to SequentialCursor:
47
+
48
+ - fetch_hash_many(n), fetch_hash_all
49
+ - each_by(n), each_hash_by(n)
50
+ - fetch!, fetch_hash!, each!, each_hash!
51
+
52
+ where !-methods reduce object creation by reusing the same result
53
+ object in each call
54
+
55
+ Remarks:
56
+ * fetch*many and fetch*all methods now return [] instead of nil when
57
+ no records are found
58
+
59
+ Bugs fixed:
60
+ * When freeing a cursor that was opened but never used, a segmentation
61
+ fault occurred
62
+
63
+
64
+ 0.1.0 04/10/2006
65
+ -------------------
66
+ Features:
67
+ * Support for all built-in data types, except INTERVAL
68
+ * immediate statements
69
+ * prepared statements
70
+ * select cursors and bulk inserts (insert cursors)
71
+ * transactions
72
+ * #columns method for retrieving column information
73
+ * rows retrieved as arrays or hashes
74
+ * IO-based and IO-like (StringIO) objects for storing a BYTE/TEXT
75
+ column, and retrieved as a String object
76
+ * NULL, DATE and DATETIME mapped to nil, Date and Time objects and
77
+ viceversa
78
+ * #drop method for freeing Informix resources immediatly
79
+ * source code documented with RDoc
80
+
81
+ Caveats:
82
+ * INTERVAL not supported
83
+ * cursors must be closed before reopening them
84
+ * only one open connection at a time is supported
data/README ADDED
@@ -0,0 +1,80 @@
1
+ Ruby/Informix
2
+ ---------------
3
+ Ruby extension for connecting to IBM Informix Dynamic Server, written in ESQL/C.
4
+
5
+ For installation instructions please read INSTALL.
6
+
7
+ 1. Supported platforms
8
+ 2. Documentation
9
+ 3. Data types
10
+ 4. Recommendations
11
+ 5. Caveats
12
+ 6. Support
13
+
14
+
15
+ 1. Supported platforms
16
+
17
+ Ruby/Informix has been tested succesfully on the following platforms:
18
+
19
+ Operating System Architecture Informix CSDK
20
+ -------------------------------------------------------------
21
+ Solaris 9 SPARC 9.40FC6 2.90UC3
22
+ Linux Fedora Core 4 i386 10.00.UC3R1 2.90UC4
23
+ Linux Fedora Core 5 i386 10.00.UC3R1 2.90UC4
24
+ SuSE Linux 9.3 i386 9.30TC1 2.90UC4
25
+ Windows XP Pro SP i386 9.40TC3 2.90TC1
26
+ Windows XP i386 9.30TC1 2.90TC4
27
+ HP-UX 11.11 PA-RISC 2.0 10.00.FC3R1TL 2.81
28
+ 64-bit
29
+
30
+ Send me an e-mail if you have [un]succesfully tested Ruby/Informix on another
31
+ platform.
32
+
33
+
34
+ 2. Documentation
35
+
36
+ Documentation generated by RDoc for each class, module and method can be found
37
+ under the doc/ directory in this distribution and at the following web address:
38
+
39
+ http://ruby-informix.rubyforge.org/doc/
40
+
41
+ Examples of use can be found at:
42
+
43
+ http://ruby-informix.rubyforge.org
44
+
45
+
46
+ 3. Data types
47
+
48
+ All built-in data types are supported, except interval. As you would expect,
49
+ numeric, string and boolean data types are mapped to their respective objects
50
+ in Ruby; DATE, DATETIME and NULL are mapped to Date, Time and nil respectively.
51
+
52
+ The notable exception is TEXT/BYTE columns, where Ruby/Informix expects an
53
+ IO-based (File) or IO-like (StringIO) object as input, and returns an String
54
+ object as output.
55
+
56
+ An Slob class exists in the Informix module for working with Smart Large
57
+ Objects (CLOB/BLOB).
58
+
59
+
60
+ 4. Recommendations
61
+
62
+ * use #drop for prepared statements and cursors to release Informix resources
63
+ * you can optimize cursor execution by changing the fetch and insert buffers,
64
+ setting the environment variable FET_BUF_SIZE to up to 32767 for Informix 9.x,
65
+ or BIG_FET_BUF_SIZE for Informix 10.x
66
+
67
+
68
+ 5. Caveats
69
+
70
+ * INTERVAL not implemented yet
71
+
72
+ 6. Support
73
+
74
+ Feel free to send me bug reports, feature requests, comments, patches or
75
+ questions to my mailbox or Ruby/Informix's forums at Rubyforge.
76
+
77
+
78
+ -----------------------------------------
79
+ Gerardo Santana <gerardo.santana gmail>
80
+ http://santanatechnotes.blogspot.com
data/extconf.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'mkmf'
2
+
3
+ env = nil
4
+ informixdir = ENV["INFORMIXDIR"]
5
+
6
+ if informixdir.nil?
7
+ informixdir = RUBY_PLATFORM =~ /mswin/ ? "C:\\informix" : "/usr/informix"
8
+ end
9
+
10
+ esql = File.join(informixdir, "bin", "esql")
11
+ idefault = File.join(informixdir, "incl", "esql")
12
+ ldefault = [ File.join(informixdir, "lib") ]
13
+ ldefault << File.join(informixdir, "lib", "esql") if RUBY_PLATFORM !~ /mswin/
14
+
15
+ dir_config("informix", idefault, ldefault)
16
+
17
+ if RUBY_PLATFORM =~ /mswin/
18
+ $libs += " isqlt09a.lib"
19
+ else
20
+ env = "/usr/bin/env"
21
+
22
+ %w(ifsql ifasf ifgen ifos ifgls).each do |lib|
23
+ $libs += " " + format(LIBARG, lib)
24
+ end
25
+ $LIBPATH.each {|path|
26
+ checkapi = path + "/checkapi.o"
27
+ if File.exist?(checkapi)
28
+ $libs += " " + checkapi
29
+ break
30
+ end
31
+ }
32
+ end
33
+
34
+
35
+ `#{env} #{esql} -e informix.ec`
36
+ create_makefile("informix")
data/informix.c ADDED
@@ -0,0 +1,4048 @@
1
+ #include <sqlhdr.h>
2
+ #include <sqliapi.h>
3
+ static const char _Cn1[] = "cur";
4
+ #line 1 "informix.ec"
5
+ /* $Id: informix.ec,v 1.56 2006/12/13 08:19:52 santana Exp $ */
6
+ /*
7
+ * Copyright (c) 2006, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
8
+ * All rights reserved.
9
+ *
10
+ * Redistribution and use in source and binary forms, with or without
11
+ * modification, are permitted provided that the following conditions
12
+ * are met:
13
+ *
14
+ * 1. Redistributions of source code must retain the above copyright
15
+ * notice, this list of conditions and the following disclaimer.
16
+ * 2. Redistributions in binary form must reproduce the above copyright
17
+ * notice, this list of conditions and the following disclaimer in the
18
+ * documentation and/or other materials provided with the distribution.
19
+ * 3. The name of the author may not be used to endorse or promote products
20
+ * derived from this software without specific prior written permission.
21
+ *
22
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
26
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ * POSSIBILITY OF SUCH DAMAGE.
33
+ */
34
+
35
+ #include "ruby.h"
36
+
37
+ #include <sqlstype.h>
38
+ #include <sqltypes.h>
39
+
40
+ static VALUE rb_cDate;
41
+
42
+ static VALUE rb_mInformix;
43
+ static VALUE rb_mSequentialCursor;
44
+ static VALUE rb_mScrollCursor;
45
+ static VALUE rb_mInsertCursor;
46
+
47
+ static VALUE rb_cSlob;
48
+ static VALUE rb_cDatabase;
49
+ static VALUE rb_cStatement;
50
+ static VALUE rb_cCursor;
51
+
52
+ static ID s_read, s_new, s_utc, s_day, s_month, s_year;
53
+ static ID s_hour, s_min, s_sec, s_usec, s_to_s, s_to_i;
54
+ static VALUE sym_name, sym_type, sym_nullable, sym_stype, sym_length;
55
+ static VALUE sym_precision, sym_scale, sym_default, sym_xid;
56
+ static VALUE sym_scroll, sym_hold;
57
+ static VALUE sym_col_info, sym_sbspace, sym_estbytes, sym_extsz;
58
+ static VALUE sym_createflags, sym_openflags;
59
+
60
+ #define IDSIZE 30
61
+
62
+ static char *currentdid = NULL;
63
+
64
+ typedef struct {
65
+ short is_select, is_open;
66
+ struct sqlda daInput, *daOutput;
67
+ short *indInput, *indOutput;
68
+ char *bfOutput;
69
+ char cursor_id[IDSIZE];
70
+ char stmt_id[IDSIZE];
71
+ VALUE db, array, hash, field_names;
72
+ char *database_id;
73
+ } cursor_t;
74
+
75
+ typedef struct {
76
+ mint fd;
77
+ ifx_lo_t lo;
78
+ ifx_lo_create_spec_t *spec;
79
+ short type; /* XID_CLOB/XID_BLOB */
80
+ VALUE db;
81
+ char *database_id;
82
+ } slob_t;
83
+
84
+ #define NUM2INT8(num, int8addr) do { \
85
+ VALUE str = rb_funcall(num, s_to_s, 0); \
86
+ char *c_str = StringValueCStr(str); \
87
+ mint ret = ifx_int8cvasc(c_str, strlen(c_str), (int8addr)); \
88
+ if (ret < 0) \
89
+ rb_raise(rb_eRuntimeError, "Could not convert %s to int8", c_str); \
90
+ }while(0)
91
+
92
+ #define INT82NUM(int8addr, num) do { \
93
+ char str[21]; \
94
+ mint ret = ifx_int8toasc((int8addr), str, sizeof(str) - 1); \
95
+ str[sizeof(str) - 1] = 0; \
96
+ num = rb_cstr2inum(str, 10); \
97
+ }while(0)
98
+
99
+ /* class Slob ------------------------------------------------------------ */
100
+
101
+ static void
102
+ slob_mark(slob_t *slob)
103
+ {
104
+ rb_gc_mark(slob->db);
105
+ }
106
+
107
+ static void
108
+ slob_free(slob_t *slob)
109
+ {
110
+ if (slob->fd != -1) {
111
+ /*
112
+ * EXEC SQL begin declare section;
113
+ */
114
+ #line 107 "informix.ec"
115
+ #line 108 "informix.ec"
116
+ char *did;
117
+ /*
118
+ * EXEC SQL end declare section;
119
+ */
120
+ #line 109 "informix.ec"
121
+
122
+
123
+ did = slob->database_id;
124
+ if (currentdid != did) {
125
+ /*
126
+ * EXEC SQL set connection :did;
127
+ */
128
+ #line 113 "informix.ec"
129
+ {
130
+ #line 113 "informix.ec"
131
+ sqli_connect_set(0, did, 0);
132
+ #line 113 "informix.ec"
133
+ }
134
+ if (SQLCODE < 0)
135
+ goto exit;
136
+ currentdid = did;
137
+ }
138
+ ifx_lo_close(slob->fd);
139
+ }
140
+
141
+ exit:
142
+ if (slob->spec)
143
+ ifx_lo_spec_free(slob->spec);
144
+
145
+ xfree(slob);
146
+ }
147
+
148
+ static VALUE
149
+ slob_alloc(VALUE klass)
150
+ {
151
+ slob_t *slob;
152
+
153
+ slob = ALLOC(slob_t);
154
+ slob->spec = NULL;
155
+ slob->fd = -1;
156
+ slob->type = XID_CLOB;
157
+
158
+ return Data_Wrap_Struct(klass, slob_mark, slob_free, slob);
159
+ }
160
+
161
+ /*
162
+ * call-seq:
163
+ * Slob.new(database, type = Slob::CLOB, options = nil) => slob
164
+ *
165
+ * Creates a Smart Large Object of type <i>type</i> in <i>database</i>.
166
+ * Returns a <code>Slob</code> object pointing to it.
167
+ *
168
+ * <i>type</i> can be Slob::BLOB or Slob::CLOB
169
+ *
170
+ * <i>options</i> must be a hash with the following possible keys:
171
+ *
172
+ * :sbspace => Sbspace name
173
+ * :estbytes => Estimated size, in bytes
174
+ * :extsz => Allocation extent size
175
+ * :createflags => Create-time flags
176
+ * :openflags => Access mode
177
+ * :maxbytes => Maximum size
178
+ * :col_info => Get the previous values from the column-level storage
179
+ * characteristics for the specified database column
180
+ */
181
+ static VALUE
182
+ slob_initialize(int argc, VALUE *argv, VALUE self)
183
+ {
184
+ mint ret, error;
185
+ slob_t *slob;
186
+ VALUE db, type, options;
187
+ VALUE col_info, sbspace, estbytes, extsz, createflags, openflags, maxbytes;
188
+ /*
189
+ * EXEC SQL begin declare section;
190
+ */
191
+ #line 168 "informix.ec"
192
+ #line 169 "informix.ec"
193
+ char *did;
194
+ /*
195
+ * EXEC SQL end declare section;
196
+ */
197
+ #line 170 "informix.ec"
198
+
199
+
200
+ rb_scan_args(argc, argv, "12", &db, &type, &options);
201
+ Data_Get_Struct(db, char, did);
202
+
203
+ if (currentdid != did) {
204
+ /*
205
+ * EXEC SQL set connection :did;
206
+ */
207
+ #line 176 "informix.ec"
208
+ {
209
+ #line 176 "informix.ec"
210
+ sqli_connect_set(0, did, 0);
211
+ #line 176 "informix.ec"
212
+ }
213
+ if (SQLCODE < 0)
214
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
215
+ currentdid = did;
216
+ }
217
+
218
+ Data_Get_Struct(self, slob_t, slob);
219
+ slob->db = db;
220
+ slob->database_id = did;
221
+
222
+ if (RTEST(type)) {
223
+ int t = FIX2INT(type);
224
+ if (t != XID_CLOB && t != XID_BLOB)
225
+ rb_raise(rb_eRuntimeError, "Invalid type %d for an SLOB", t);
226
+ slob->type = t;
227
+ }
228
+
229
+ col_info = sbspace = estbytes = extsz = createflags = openflags = maxbytes = Qnil;
230
+
231
+ if (RTEST(options)) {
232
+ col_info = rb_hash_aref(options, sym_col_info);
233
+ sbspace = rb_hash_aref(options, sym_sbspace);
234
+ estbytes = rb_hash_aref(options, sym_estbytes);
235
+ extsz = rb_hash_aref(options, sym_extsz);
236
+ createflags = rb_hash_aref(options, sym_createflags);
237
+ openflags = rb_hash_aref(options, sym_openflags);
238
+ }
239
+
240
+ ret = ifx_lo_def_create_spec(&slob->spec);
241
+ if (ret < 0)
242
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
243
+
244
+ if (RTEST(col_info)) {
245
+ ret = ifx_lo_col_info(StringValueCStr(col_info), slob->spec);
246
+
247
+ if (ret < 0)
248
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
249
+ }
250
+ if (RTEST(sbspace)) {
251
+ char *c_sbspace = StringValueCStr(sbspace);
252
+ ret = ifx_lo_specset_sbspace(slob->spec, c_sbspace);
253
+ if (ret == -1)
254
+ rb_raise(rb_eRuntimeError, "Could not set sbspace name to %s", c_sbspace);
255
+ }
256
+ if (RTEST(estbytes)) {
257
+ ifx_int8_t estbytes8;
258
+
259
+ NUM2INT8(estbytes, &estbytes8);
260
+ ret = ifx_lo_specset_estbytes(slob->spec, &estbytes8);
261
+ if (ret == -1)
262
+ rb_raise(rb_eRuntimeError, "Could not set estbytes");
263
+ }
264
+ if (RTEST(extsz)) {
265
+ ret = ifx_lo_specset_extsz(slob->spec, FIX2LONG(extsz));
266
+ if (ret == -1)
267
+ rb_raise(rb_eRuntimeError, "Could not set extsz to %d", FIX2LONG(extsz));
268
+ }
269
+ if (RTEST(createflags)) {
270
+ ret = ifx_lo_specset_flags(slob->spec, FIX2LONG(createflags));
271
+ if (ret == -1)
272
+ rb_raise(rb_eRuntimeError, "Could not set crate-time flags to 0x%X", FIX2LONG(createflags));
273
+ }
274
+ if (RTEST(maxbytes)) {
275
+ ifx_int8_t maxbytes8;
276
+
277
+ NUM2INT8(maxbytes, (&maxbytes8));
278
+ ret = ifx_lo_specset_maxbytes(slob->spec, &maxbytes8);
279
+ if (ret == -1)
280
+ rb_raise(rb_eRuntimeError, "Could not set maxbytes");
281
+ }
282
+ slob->fd = ifx_lo_create(slob->spec, RTEST(openflags)? FIX2LONG(openflags): LO_RDWR, &slob->lo, &error);
283
+ if (slob->fd == -1) {
284
+ rb_raise(rb_eRuntimeError, "Informix Error: %d\n", error);
285
+ }
286
+ return self;
287
+ }
288
+
289
+ /*
290
+ * call-seq:
291
+ * slob.open(access = Slob::RDONLY) => slob
292
+ *
293
+ * Opens the Smart Large Object in <i>access</i> mode.
294
+ *
295
+ * access modes:
296
+ *
297
+ * Slob::RDONLY:: Read only
298
+ * Slob::DIRTY_READ:: Read uncommitted data
299
+ * Slob::WRONLY:: Write only
300
+ * Slob::APPEND:: Append data to the end, if combined with RDRW or WRONLY; read only otherwise
301
+ * Slob::RDRW:: Read/Write
302
+ * Slob::BUFFER:: Use standard database server buffer pool
303
+ * Slob::NOBUFFER:: Use private buffer from the session pool of the database server
304
+ * Slob::LOCKALL:: Lock the entire Smart Large Object
305
+ * Slob::LOCKRANGE:: Lock a range of bytes
306
+ *
307
+ * Returns __self__.
308
+ */
309
+ static VALUE
310
+ slob_open(int argc, VALUE *argv, VALUE self)
311
+ {
312
+ VALUE access;
313
+ slob_t *slob;
314
+ mint error;
315
+ /*
316
+ * EXEC SQL begin declare section;
317
+ */
318
+ #line 279 "informix.ec"
319
+ #line 280 "informix.ec"
320
+ char *did;
321
+ /*
322
+ * EXEC SQL end declare section;
323
+ */
324
+ #line 281 "informix.ec"
325
+
326
+
327
+ Data_Get_Struct(self, slob_t, slob);
328
+
329
+ if (slob->fd != -1) /* Already open */
330
+ return self;
331
+
332
+ did = slob->database_id;
333
+ if (currentdid != did) {
334
+ /*
335
+ * EXEC SQL set connection :did;
336
+ */
337
+ #line 290 "informix.ec"
338
+ {
339
+ #line 290 "informix.ec"
340
+ sqli_connect_set(0, did, 0);
341
+ #line 290 "informix.ec"
342
+ }
343
+ if (SQLCODE < 0)
344
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
345
+ currentdid = did;
346
+ }
347
+
348
+ rb_scan_args(argc, argv, "01", &access);
349
+
350
+ slob->fd = ifx_lo_open(&slob->lo, NIL_P(access)? LO_RDONLY: FIX2INT(access), &error);
351
+
352
+ if (slob->fd == -1)
353
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", error);
354
+
355
+ return self;
356
+ }
357
+
358
+ /*
359
+ * call-seq:
360
+ * slob.close => slob
361
+ *
362
+ * Closes the Smart Large Object and returns __self__.
363
+ */
364
+ static VALUE
365
+ slob_close(VALUE self)
366
+ {
367
+ slob_t *slob;
368
+
369
+ Data_Get_Struct(self, slob_t, slob);
370
+ if (slob->fd != -1) {
371
+ /*
372
+ * EXEC SQL begin declare section;
373
+ */
374
+ #line 319 "informix.ec"
375
+ #line 320 "informix.ec"
376
+ char *did;
377
+ /*
378
+ * EXEC SQL end declare section;
379
+ */
380
+ #line 321 "informix.ec"
381
+
382
+
383
+ did = slob->database_id;
384
+ if (currentdid != did) {
385
+ /*
386
+ * EXEC SQL set connection :did;
387
+ */
388
+ #line 325 "informix.ec"
389
+ {
390
+ #line 325 "informix.ec"
391
+ sqli_connect_set(0, did, 0);
392
+ #line 325 "informix.ec"
393
+ }
394
+ if (SQLCODE < 0)
395
+ return self;
396
+ currentdid = did;
397
+ }
398
+
399
+ ifx_lo_close(slob->fd);
400
+ slob->fd = -1;
401
+ }
402
+
403
+ return self;
404
+ }
405
+
406
+ /*
407
+ * call-seq:
408
+ * slob.read(nbytes) => string
409
+ *
410
+ * Reads at most <i>nbytes</i> bytes from the Smart Large Object.
411
+ *
412
+ * Returns the bytes read as a String object.
413
+ */
414
+ static VALUE
415
+ slob_read(VALUE self, VALUE nbytes)
416
+ {
417
+ slob_t *slob;
418
+ mint error, ret;
419
+ char *buffer;
420
+ long c_nbytes;
421
+ VALUE str;
422
+ /*
423
+ * EXEC SQL begin declare section;
424
+ */
425
+ #line 354 "informix.ec"
426
+ #line 355 "informix.ec"
427
+ char *did;
428
+ /*
429
+ * EXEC SQL end declare section;
430
+ */
431
+ #line 356 "informix.ec"
432
+
433
+
434
+
435
+ Data_Get_Struct(self, slob_t, slob);
436
+
437
+ if (slob->fd == -1)
438
+ rb_raise(rb_eRuntimeError, "Open the Slob object before reading");
439
+
440
+ did = slob->database_id;
441
+ if (currentdid != did) {
442
+ /*
443
+ * EXEC SQL set connection :did;
444
+ */
445
+ #line 366 "informix.ec"
446
+ {
447
+ #line 366 "informix.ec"
448
+ sqli_connect_set(0, did, 0);
449
+ #line 366 "informix.ec"
450
+ }
451
+ if (SQLCODE < 0)
452
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
453
+ currentdid = did;
454
+ }
455
+
456
+ c_nbytes = FIX2LONG(nbytes);
457
+ buffer = ALLOC_N(char, c_nbytes);
458
+ ret = ifx_lo_read(slob->fd, buffer, c_nbytes, &error);
459
+
460
+ if (ret == -1)
461
+ rb_raise(rb_eRuntimeError, "Informix Error: %d\n", error);
462
+
463
+ str = rb_str_new(buffer, ret);
464
+ xfree(buffer);
465
+
466
+ return str;
467
+ }
468
+
469
+ /*
470
+ * call-seq:
471
+ * slob.write(data) => fixnum or bignum
472
+ *
473
+ * Writes <i>data</i> to the Smart Large Object.
474
+ *
475
+ * Returns the number of bytes written.
476
+ */
477
+ static VALUE
478
+ slob_write(VALUE self, VALUE data)
479
+ {
480
+ slob_t *slob;
481
+ mint error, ret;
482
+ char *buffer;
483
+ long nbytes;
484
+ VALUE str;
485
+ /*
486
+ * EXEC SQL begin declare section;
487
+ */
488
+ #line 401 "informix.ec"
489
+ #line 402 "informix.ec"
490
+ char *did;
491
+ /*
492
+ * EXEC SQL end declare section;
493
+ */
494
+ #line 403 "informix.ec"
495
+
496
+
497
+ Data_Get_Struct(self, slob_t, slob);
498
+
499
+ if (slob->fd == -1)
500
+ rb_raise(rb_eRuntimeError, "Open the Slob object before writing");
501
+
502
+ did = slob->database_id;
503
+ if (currentdid != did) {
504
+ /*
505
+ * EXEC SQL set connection :did;
506
+ */
507
+ #line 412 "informix.ec"
508
+ {
509
+ #line 412 "informix.ec"
510
+ sqli_connect_set(0, did, 0);
511
+ #line 412 "informix.ec"
512
+ }
513
+ if (SQLCODE < 0)
514
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
515
+ currentdid = did;
516
+ }
517
+
518
+ str = StringValue(data);
519
+ buffer = RSTRING(str)->ptr;
520
+ nbytes = RSTRING(str)->len;
521
+
522
+ ret = ifx_lo_write(slob->fd, buffer, nbytes, &error);
523
+
524
+ if (ret == -1)
525
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", error);
526
+
527
+ return LONG2NUM(ret);
528
+ }
529
+
530
+ /*
531
+ * call-seq:
532
+ * slob.seek(offset, whence) => fixnum or bignum
533
+ *
534
+ * Sets the file position for the next read or write
535
+ * operation on the open Smart Large Object.
536
+ *
537
+ *
538
+ * <i>offset</i> offset from the starting seek position
539
+ * <i>whence</i> identifies the starting seek position
540
+ *
541
+ * Values for <i>whence</i>:
542
+ *
543
+ * Slob::SEEK_SET:: The start of the Smart Large Object
544
+ * Slob::SEEK_CUR:: The current seek position in the Smart Large Object
545
+ * Slob::SEEK_END:: The end of the Smart Large Object
546
+ *
547
+ * Returns the new position.
548
+ */
549
+ static VALUE
550
+ slob_seek(VALUE self, VALUE offset, VALUE whence)
551
+ {
552
+ slob_t *slob;
553
+ mint ret;
554
+ VALUE seek_pos;
555
+ ifx_int8_t offset8, seek_pos8;
556
+ /*
557
+ * EXEC SQL begin declare section;
558
+ */
559
+ #line 456 "informix.ec"
560
+ #line 457 "informix.ec"
561
+ char *did;
562
+ /*
563
+ * EXEC SQL end declare section;
564
+ */
565
+ #line 458 "informix.ec"
566
+
567
+
568
+ Data_Get_Struct(self, slob_t, slob);
569
+
570
+ if (slob->fd == -1)
571
+ rb_raise(rb_eRuntimeError, "Open the Slob object first");
572
+
573
+ did = slob->database_id;
574
+ if (currentdid != did) {
575
+ /*
576
+ * EXEC SQL set connection :did;
577
+ */
578
+ #line 467 "informix.ec"
579
+ {
580
+ #line 467 "informix.ec"
581
+ sqli_connect_set(0, did, 0);
582
+ #line 467 "informix.ec"
583
+ }
584
+ if (SQLCODE < 0)
585
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
586
+ currentdid = did;
587
+ }
588
+
589
+ NUM2INT8(offset, &offset8);
590
+ ret = ifx_lo_seek(slob->fd, &offset8, FIX2INT(whence), &seek_pos8);
591
+ if (ret < 0)
592
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
593
+
594
+ INT82NUM(&seek_pos8, seek_pos);
595
+
596
+ return seek_pos;
597
+ }
598
+
599
+ /*
600
+ * call-seq:
601
+ * slob.tell => fixnum or bignum
602
+ *
603
+ * Returns the current file or seek position for an
604
+ * open Smart Large Object
605
+ */
606
+ static VALUE
607
+ slob_tell(VALUE self)
608
+ {
609
+ slob_t *slob;
610
+ mint ret;
611
+ VALUE seek_pos;
612
+ ifx_int8_t seek_pos8;
613
+ /*
614
+ * EXEC SQL begin declare section;
615
+ */
616
+ #line 497 "informix.ec"
617
+ #line 498 "informix.ec"
618
+ char *did;
619
+ /*
620
+ * EXEC SQL end declare section;
621
+ */
622
+ #line 499 "informix.ec"
623
+
624
+
625
+ Data_Get_Struct(self, slob_t, slob);
626
+
627
+ if (slob->fd == -1)
628
+ rb_raise(rb_eRuntimeError, "Open the Slob object first");
629
+
630
+ did = slob->database_id;
631
+ if (currentdid != did) {
632
+ /*
633
+ * EXEC SQL set connection :did;
634
+ */
635
+ #line 508 "informix.ec"
636
+ {
637
+ #line 508 "informix.ec"
638
+ sqli_connect_set(0, did, 0);
639
+ #line 508 "informix.ec"
640
+ }
641
+ if (SQLCODE < 0)
642
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
643
+ currentdid = did;
644
+ }
645
+
646
+ ret = ifx_lo_tell(slob->fd, &seek_pos8);
647
+ if (ret < 0)
648
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
649
+
650
+ INT82NUM(&seek_pos8, seek_pos);
651
+
652
+ return seek_pos;
653
+ }
654
+
655
+ /*
656
+ * call-seq:
657
+ * slob.truncate(offset) => slob
658
+ *
659
+ * Truncates a Smart Large Object at a specified byte position.
660
+ *
661
+ * Returns __self__.
662
+ */
663
+ static VALUE
664
+ slob_truncate(VALUE self, VALUE offset)
665
+ {
666
+ slob_t *slob;
667
+ mint ret;
668
+ ifx_int8_t offset8;
669
+ /*
670
+ * EXEC SQL begin declare section;
671
+ */
672
+ #line 537 "informix.ec"
673
+ #line 538 "informix.ec"
674
+ char *did;
675
+ /*
676
+ * EXEC SQL end declare section;
677
+ */
678
+ #line 539 "informix.ec"
679
+
680
+
681
+ Data_Get_Struct(self, slob_t, slob);
682
+
683
+ if (slob->fd == -1)
684
+ rb_raise(rb_eRuntimeError, "Open the Slob object first");
685
+
686
+ did = slob->database_id;
687
+ if (currentdid != did) {
688
+ /*
689
+ * EXEC SQL set connection :did;
690
+ */
691
+ #line 548 "informix.ec"
692
+ {
693
+ #line 548 "informix.ec"
694
+ sqli_connect_set(0, did, 0);
695
+ #line 548 "informix.ec"
696
+ }
697
+ if (SQLCODE < 0)
698
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
699
+ currentdid = did;
700
+ }
701
+
702
+ NUM2INT8(offset, &offset8);
703
+ ret = ifx_lo_truncate(slob->fd, &offset8);
704
+ if (ret < 0)
705
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
706
+
707
+ return self;
708
+ }
709
+
710
+ /* Helper functions ------------------------------------------------------- */
711
+
712
+ /*
713
+ * Counts the number of markers '?' in the query
714
+ */
715
+ static int count_markers(const char *query)
716
+ {
717
+ register char c, quote = 0;
718
+ register int count = 0;
719
+
720
+ while((c = *query++)) {
721
+ if (quote && c != quote)
722
+ ;
723
+ else if (quote == c) {
724
+ quote = 0;
725
+ }
726
+ else if (c == '\'' || c == '"') {
727
+ quote = c;
728
+ }
729
+ else if (c == '?') {
730
+ ++count;
731
+ }
732
+ }
733
+ return count;
734
+ }
735
+
736
+ /*
737
+ * Allocates memory for the indicators array and slots for the input
738
+ * parameters, if any. Freed by free_input_slots.
739
+ */
740
+ static void
741
+ alloc_input_slots(cursor_t *c, const char *query)
742
+ {
743
+ register int n;
744
+
745
+ n = count_markers(query);
746
+ c->daInput.sqld = n;
747
+ if (n) {
748
+ c->daInput.sqlvar = ALLOC_N(struct sqlvar_struct, n);
749
+ memset(c->daInput.sqlvar, 0, n*sizeof(struct sqlvar_struct));
750
+ c->indInput = ALLOC_N(short, n);
751
+ while(n--)
752
+ c->daInput.sqlvar[n].sqlind = &c->indInput[n];
753
+ }
754
+ else {
755
+ c->daInput.sqlvar = NULL;
756
+ c->indInput = NULL;
757
+ }
758
+ }
759
+
760
+ /*
761
+ * Allocates memory for the output data slots and its indicators array.
762
+ * Freed by free_output_slots.
763
+ */
764
+ static void
765
+ alloc_output_slots(cursor_t *c)
766
+ {
767
+ register int i, count;
768
+ register short *ind;
769
+ struct sqlvar_struct *var;
770
+ register char *buffer;
771
+
772
+ c->field_names = rb_ary_new2(c->daOutput->sqld);
773
+
774
+ ind = c->indOutput = ALLOC_N(short, c->daOutput->sqld);
775
+
776
+ var = c->daOutput->sqlvar;
777
+ for (i = count = 0; i < c->daOutput->sqld; i++, ind++, var++) {
778
+ var->sqlind = ind;
779
+ rb_ary_store(c->field_names, i, rb_str_new2(var->sqlname));
780
+ if (ISSMARTBLOB(var->sqltype, var->sqlxid)) {
781
+ var->sqldata = (char *)ALLOC(ifx_lo_t);
782
+ continue;
783
+ }
784
+ var->sqllen = rtypmsize(var->sqltype, var->sqllen);
785
+ count = rtypalign(count, var->sqltype) + var->sqllen;
786
+ }
787
+
788
+ buffer = c->bfOutput = ALLOC_N(char, count);
789
+ memset(buffer, 0, count);
790
+
791
+ var = c->daOutput->sqlvar;
792
+ for (i = count = 0; i < c->daOutput->sqld; i++, var++) {
793
+ if (var->sqldata)
794
+ continue;
795
+ count = rtypalign(count, var->sqltype);
796
+ var->sqldata = buffer + count;
797
+ count += var->sqllen;
798
+ if (ISBYTESTYPE(var->sqltype) || ISTEXTTYPE(var->sqltype)) {
799
+ loc_t *p;
800
+ p = (loc_t *)var->sqldata;
801
+ byfill((char *)p, sizeof(loc_t), 0);
802
+ p->loc_loctype = LOCMEMORY;
803
+ p->loc_bufsize = -1;
804
+ }
805
+ if (var->sqltype == SQLDTIME) {
806
+ var->sqllen = 0;
807
+ }
808
+ }
809
+ }
810
+
811
+ /*
812
+ * Frees the allocated memory of the input parameters, but not the slots
813
+ * nor the indicators array. Allocated by bind_input_params.
814
+ */
815
+ static void
816
+ clean_input_slots(cursor_t *c)
817
+ {
818
+ register int count;
819
+ register struct sqlvar_struct *var;
820
+
821
+ if (c->daInput.sqlvar == NULL)
822
+ return;
823
+ var = c->daInput.sqlvar;
824
+ count = c->daInput.sqld;
825
+ while(count--) {
826
+ if (var->sqldata != NULL) {
827
+ if (var->sqltype == CLOCATORTYPE) {
828
+ loc_t *p = (loc_t *)var->sqldata;
829
+ if (p->loc_buffer != NULL) {
830
+ xfree(p->loc_buffer);
831
+ }
832
+ }
833
+ xfree(var->sqldata);
834
+ var->sqldata = NULL;
835
+ var++;
836
+ }
837
+ }
838
+ }
839
+
840
+ /*
841
+ * Frees the memory for the input parameters, their slots, and the indicators
842
+ * array. Allocated by alloc_input_slots and bind_input_params.
843
+ */
844
+ static void
845
+ free_input_slots(cursor_t *c)
846
+ {
847
+ clean_input_slots(c);
848
+ if (c->daInput.sqlvar) {
849
+ xfree(c->daInput.sqlvar);
850
+ c->daInput.sqlvar = NULL;
851
+ c->daInput.sqld = 0;
852
+ }
853
+ if (c->indInput) {
854
+ xfree(c->indInput);
855
+ c->indInput = NULL;
856
+ }
857
+ }
858
+
859
+ /*
860
+ * Frees the memory for the output parameters, their slots, and the indicators
861
+ * array. Allocated by alloc_output_slots.
862
+ */
863
+ static void
864
+ free_output_slots(cursor_t *c)
865
+ {
866
+ if (c->daOutput != NULL) {
867
+ struct sqlvar_struct *var = c->daOutput->sqlvar;
868
+ if (var) {
869
+ register int i;
870
+ for (i = 0; i < c->daOutput->sqld; i++, var++) {
871
+ if (ISBLOBTYPE(var->sqltype)) {
872
+ loc_t *p = (loc_t *) var->sqldata;
873
+ if(p -> loc_buffer)
874
+ xfree(p->loc_buffer);
875
+ }
876
+ if (ISSMARTBLOB(var->sqltype, var->sqlxid))
877
+ xfree(var->sqldata);
878
+ }
879
+ }
880
+ xfree(c->daOutput);
881
+ c->daOutput = NULL;
882
+ }
883
+ if (c->indOutput != NULL) {
884
+ xfree(c->indOutput);
885
+ c->indOutput = NULL;
886
+ }
887
+ if (c->bfOutput != NULL) {
888
+ xfree(c->bfOutput);
889
+ c->bfOutput = NULL;
890
+ }
891
+ }
892
+
893
+ /*
894
+ * Gets an array of Ruby objects as input parameters and place them in input
895
+ * slots, converting data types and allocating memory as needed.
896
+ */
897
+ static void
898
+ bind_input_params(cursor_t *c, VALUE *argv)
899
+ {
900
+ VALUE data, klass;
901
+ register int i;
902
+ register struct sqlvar_struct *var;
903
+
904
+ var = c->daInput.sqlvar;
905
+ for (i = 0; i < c->daInput.sqld; i++, var++) {
906
+ data = argv[i];
907
+
908
+ switch(TYPE(data)) {
909
+ case T_NIL:
910
+ var->sqltype = CSTRINGTYPE;
911
+ var->sqldata = NULL;
912
+ var->sqllen = 0;
913
+ *var->sqlind = -1;
914
+ break;
915
+ case T_FIXNUM:
916
+ var->sqldata = (char *)ALLOC(long);
917
+ *((long *)var->sqldata) = FIX2LONG(data);
918
+ var->sqltype = CLONGTYPE;
919
+ var->sqllen = sizeof(long);
920
+ *var->sqlind = 0;
921
+ break;
922
+ case T_FLOAT:
923
+ var->sqldata = (char *)ALLOC(double);
924
+ *((double *)var->sqldata) = NUM2DBL(data);
925
+ var->sqltype = CDOUBLETYPE;
926
+ var->sqllen = sizeof(double);
927
+ *var->sqlind = 0;
928
+ break;
929
+ case T_TRUE:
930
+ case T_FALSE:
931
+ var->sqldata = ALLOC(char);
932
+ *var->sqldata = TYPE(data) == T_TRUE? 't': 'f';
933
+ var->sqltype = CCHARTYPE;
934
+ var->sqllen = sizeof(char);
935
+ *var->sqlind = 0;
936
+ break;
937
+ default:
938
+ klass = rb_obj_class(data);
939
+ if (klass == rb_cDate) {
940
+ int2 mdy[3];
941
+ int4 date;
942
+
943
+ mdy[0] = FIX2INT(rb_funcall(data, s_month, 0));
944
+ mdy[1] = FIX2INT(rb_funcall(data, s_day, 0));
945
+ mdy[2] = FIX2INT(rb_funcall(data, s_year, 0));
946
+ rmdyjul(mdy, &date);
947
+
948
+ var->sqldata = (char *)ALLOC(int4);
949
+ *((int4 *)var->sqldata) = date;
950
+ var->sqltype = CDATETYPE;
951
+ var->sqllen = sizeof(int4);
952
+ *var->sqlind = 0;
953
+ break;
954
+ }
955
+ if (klass == rb_cTime) {
956
+ char buffer[30];
957
+ short year, month, day, hour, minute, second;
958
+ int usec;
959
+ dtime_t *dt;
960
+
961
+ year = FIX2INT(rb_funcall(data, s_year, 0));
962
+ month = FIX2INT(rb_funcall(data, s_month, 0));
963
+ day = FIX2INT(rb_funcall(data, s_day, 0));
964
+ hour = FIX2INT(rb_funcall(data, s_hour, 0));
965
+ minute = FIX2INT(rb_funcall(data, s_min, 0));
966
+ second = FIX2INT(rb_funcall(data, s_sec, 0));
967
+ usec = FIX2INT(rb_funcall(data, s_usec, 0));
968
+
969
+ dt = ALLOC(dtime_t);
970
+
971
+ dt->dt_qual = TU_DTENCODE(TU_YEAR, TU_F5);
972
+ snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d.%d",
973
+ year, month, day, hour, minute, second, usec/10);
974
+ dtcvasc(buffer, dt);
975
+
976
+ var->sqldata = (char *)dt;
977
+ var->sqltype = CDTIMETYPE;
978
+ var->sqllen = sizeof(dtime_t);
979
+ *var->sqlind = 0;
980
+ break;
981
+ }
982
+ if (klass == rb_cSlob) {
983
+ slob_t *slob;
984
+
985
+ Data_Get_Struct(data, slob_t, slob);
986
+
987
+ var->sqldata = (char *)ALLOC(ifx_lo_t);
988
+ memcpy(var->sqldata, &slob->lo, sizeof(slob->lo));
989
+ var->sqltype = SQLUDTFIXED;
990
+ var->sqlxid = slob->type;
991
+ var->sqllen = sizeof(ifx_lo_t);
992
+ *var->sqlind = 0;
993
+ break;
994
+ }
995
+ if (rb_respond_to(data, s_read)) {
996
+ char *str;
997
+ loc_t *loc;
998
+ long len;
999
+
1000
+ data = rb_funcall(data, s_read, 0);
1001
+ data = StringValue(data);
1002
+ str = RSTRING(data)->ptr;
1003
+ len = RSTRING(data)->len;
1004
+
1005
+ loc = (loc_t *)ALLOC(loc_t);
1006
+ byfill((char *)loc, sizeof(loc_t), 0);
1007
+ loc->loc_loctype = LOCMEMORY;
1008
+ loc->loc_buffer = (char *)ALLOC_N(char, len);
1009
+ memcpy(loc->loc_buffer, str, len);
1010
+ loc->loc_bufsize = loc->loc_size = len;
1011
+
1012
+ var->sqldata = (char *)loc;
1013
+ var->sqltype = CLOCATORTYPE;
1014
+ var->sqllen = sizeof(loc_t);
1015
+ *var->sqlind = 0;
1016
+ break;
1017
+ }
1018
+ {
1019
+ VALUE str;
1020
+ str = rb_check_string_type(data);
1021
+ if (NIL_P(str)) {
1022
+ data = rb_obj_as_string(data);
1023
+ }
1024
+ else {
1025
+ data = str;
1026
+ }
1027
+ }
1028
+ case T_STRING: {
1029
+ char *str;
1030
+ long len;
1031
+
1032
+ str = RSTRING(data)->ptr;
1033
+ len = RSTRING(data)->len;
1034
+ var->sqldata = ALLOC_N(char, len + 1);
1035
+ memcpy(var->sqldata, str, len);
1036
+ var->sqldata[len] = 0;
1037
+ var->sqltype = CSTRINGTYPE;
1038
+ var->sqllen = len;
1039
+ *var->sqlind = 0;
1040
+ break;
1041
+ }
1042
+ }
1043
+ }
1044
+ }
1045
+
1046
+ /*
1047
+ * Returns an array or a hash of Ruby objects containing the record fetched.
1048
+ */
1049
+ static VALUE
1050
+ make_result(cursor_t *c, VALUE record)
1051
+ {
1052
+ VALUE item;
1053
+ register int i;
1054
+ register struct sqlvar_struct *var;
1055
+
1056
+ var = c->daOutput->sqlvar;
1057
+ for (i = 0; i < c->daOutput->sqld; i++, var++) {
1058
+ if (*var->sqlind == -1) {
1059
+ item = Qnil;
1060
+ } else {
1061
+ switch(var->sqltype) {
1062
+ case SQLCHAR:
1063
+ case SQLVCHAR:
1064
+ case SQLNCHAR:
1065
+ case SQLNVCHAR:
1066
+ item = rb_str_new2(var->sqldata);
1067
+ break;
1068
+ case SQLSMINT:
1069
+ item = INT2FIX(*(int2 *)var->sqldata);
1070
+ break;
1071
+ case SQLINT:
1072
+ case SQLSERIAL:
1073
+ item = INT2NUM(*(int4 *)var->sqldata);
1074
+ break;
1075
+ case SQLINT8:
1076
+ case SQLSERIAL8:
1077
+ INT82NUM((ifx_int8_t *)var->sqldata, item);
1078
+ break;
1079
+ case SQLSMFLOAT:
1080
+ item = rb_float_new(*(float *)var->sqldata);
1081
+ break;
1082
+ case SQLFLOAT:
1083
+ item = rb_float_new(*(double *)var->sqldata);
1084
+ break;
1085
+ case SQLDATE: {
1086
+ VALUE year, month, day;
1087
+ int2 mdy[3];
1088
+
1089
+ rjulmdy(*(int4 *)var->sqldata, mdy);
1090
+ year = INT2FIX(mdy[2]);
1091
+ month = INT2FIX(mdy[0]);
1092
+ day = INT2FIX(mdy[1]);
1093
+ item = rb_funcall(rb_cDate, s_new, 3, year, month, day);
1094
+ break;
1095
+ }
1096
+ case SQLDTIME: {
1097
+ register short qual;
1098
+ short year, month, day, hour, minute, second;
1099
+ int usec;
1100
+ dtime_t *dt;
1101
+ register char *dgts;
1102
+
1103
+ month = day = 1;
1104
+ year = hour = minute = second = usec = 0;
1105
+ dt = (dtime_t *)var->sqldata;
1106
+ dgts = dt->dt_dec.dec_dgts;
1107
+
1108
+ qual = TU_START(dt->dt_qual);
1109
+ for (; qual <= TU_END(dt->dt_qual); qual++) {
1110
+ switch(qual) {
1111
+ case TU_YEAR:
1112
+ year = 100**dgts++;
1113
+ year += *dgts++;
1114
+ break;
1115
+ case TU_MONTH:
1116
+ month = *dgts++;
1117
+ break;
1118
+ case TU_DAY:
1119
+ day = *dgts++;
1120
+ break;
1121
+ case TU_HOUR:
1122
+ hour = *dgts++;
1123
+ break;
1124
+ case TU_MINUTE:
1125
+ minute = *dgts++;
1126
+ break;
1127
+ case TU_SECOND:
1128
+ second = *dgts++;
1129
+ break;
1130
+ case TU_F1:
1131
+ usec = 10000**dgts++;
1132
+ break;
1133
+ case TU_F3:
1134
+ usec += 100**dgts++;
1135
+ break;
1136
+ case TU_F5:
1137
+ usec += *dgts++;
1138
+ break;
1139
+ }
1140
+ }
1141
+
1142
+ item = rb_funcall(rb_cTime, s_utc, 7,
1143
+ INT2FIX(year), INT2FIX(month), INT2FIX(day),
1144
+ INT2FIX(hour), INT2FIX(minute), INT2FIX(second),
1145
+ INT2FIX(usec));
1146
+
1147
+ /* Clean the buffer for DATETIME columns because
1148
+ * ESQL/C leaves the previous content when a
1149
+ * a time field is zero.
1150
+ */
1151
+ memset(dt, 0, sizeof(dtime_t));
1152
+ break;
1153
+ }
1154
+ case SQLDECIMAL:
1155
+ case SQLMONEY: {
1156
+ double dblValue;
1157
+ dectodbl((dec_t *)var->sqldata, &dblValue);
1158
+ item = rb_float_new(dblValue);
1159
+ break;
1160
+ }
1161
+ case SQLBOOL:
1162
+ item = var->sqldata[0]? Qtrue: Qfalse;
1163
+ break;
1164
+ case SQLBYTES:
1165
+ case SQLTEXT: {
1166
+ loc_t *loc;
1167
+ loc = (loc_t *)var->sqldata;
1168
+ item = rb_str_new(loc->loc_buffer, loc->loc_size);
1169
+ break;
1170
+ }
1171
+ case SQLUDTFIXED:
1172
+ if (ISSMARTBLOB(var->sqltype, var->sqlxid)) {
1173
+ slob_t *slob;
1174
+
1175
+ item = slob_alloc(rb_cSlob);
1176
+ Data_Get_Struct(item, slob_t, slob);
1177
+ memcpy(&slob->lo, var->sqldata, sizeof(ifx_lo_t));
1178
+ slob->type = var->sqlxid;
1179
+ break;
1180
+ }
1181
+ case SQLSET:
1182
+ case SQLMULTISET:
1183
+ case SQLLIST:
1184
+ case SQLROW:
1185
+ case SQLCOLLECTION:
1186
+ case SQLROWREF:
1187
+ case SQLUDTVAR:
1188
+ case SQLREFSER8:
1189
+ case SQLLVARCHAR:
1190
+ case SQLSENDRECV:
1191
+ case SQLIMPEXP:
1192
+ case SQLIMPEXPBIN:
1193
+ case SQLUNKNOWN:
1194
+ default:
1195
+ item = Qnil;
1196
+ break;
1197
+ }
1198
+ }
1199
+ if (BUILTIN_TYPE(record) == T_ARRAY) {
1200
+ rb_ary_store(record, i, item);
1201
+ }
1202
+ else {
1203
+ rb_hash_aset(record, RARRAY(c->field_names)->ptr[i], item);
1204
+ }
1205
+ }
1206
+ return record;
1207
+ }
1208
+
1209
+ /* module Informix -------------------------------------------------------- */
1210
+
1211
+ /*
1212
+ * call-seq:
1213
+ * Informix.connect(dbname, user = nil, password = nil) => database
1214
+ *
1215
+ * Returns a <code>Database</code> object connected to <i>dbname</i> as
1216
+ * <i>user</i> with <i>password</i>. If these are not given, connects to
1217
+ * <i>dbname</i> as the current user.
1218
+ */
1219
+ static VALUE
1220
+ informix_connect(int argc, VALUE *argv, VALUE self)
1221
+ {
1222
+ return rb_class_new_instance(argc, argv, rb_cDatabase);
1223
+ }
1224
+
1225
+
1226
+ /* class Database --------------------------------------------------------- */
1227
+
1228
+ static void
1229
+ database_free(void *p)
1230
+ {
1231
+ /*
1232
+ * EXEC SQL begin declare section;
1233
+ */
1234
+ #line 1083 "informix.ec"
1235
+ #line 1084 "informix.ec"
1236
+ char *did;
1237
+ /*
1238
+ * EXEC SQL end declare section;
1239
+ */
1240
+ #line 1085 "informix.ec"
1241
+
1242
+
1243
+ did = p;
1244
+ /*
1245
+ * EXEC SQL disconnect :did;
1246
+ */
1247
+ #line 1088 "informix.ec"
1248
+ {
1249
+ #line 1088 "informix.ec"
1250
+ sqli_connect_close(0, did, 0, 0);
1251
+ #line 1088 "informix.ec"
1252
+ }
1253
+ if (currentdid == did)
1254
+ currentdid = NULL;
1255
+ xfree(p);
1256
+ }
1257
+
1258
+ static VALUE
1259
+ database_alloc(VALUE klass)
1260
+ {
1261
+ char *did;
1262
+
1263
+ did = ALLOC_N(char, IDSIZE);
1264
+ did[0] = 0;
1265
+ return Data_Wrap_Struct(klass, 0, database_free, did);
1266
+ }
1267
+
1268
+ /*
1269
+ * call-seq:
1270
+ * Database.new(dbname, user = nil, password = nil) => database
1271
+ *
1272
+ * Returns a <code>Database</code> object connected to <i>dbname</i> as
1273
+ * <i>user</i> with <i>password</i>. If these are not given, connects to
1274
+ * <i>dbname</i> as the current user.
1275
+ */
1276
+ static VALUE
1277
+ database_initialize(int argc, VALUE *argv, VALUE self)
1278
+ {
1279
+ VALUE arg[3];
1280
+
1281
+ /*
1282
+ * EXEC SQL begin declare section;
1283
+ */
1284
+ #line 1117 "informix.ec"
1285
+ #line 1118 "informix.ec"
1286
+ char *dbname, *user = NULL, *pass = NULL, *did;
1287
+ /*
1288
+ * EXEC SQL end declare section;
1289
+ */
1290
+ #line 1119 "informix.ec"
1291
+
1292
+
1293
+ rb_scan_args(argc, argv, "12", &arg[0], &arg[1], &arg[2]);
1294
+
1295
+ if (NIL_P(arg[0]))
1296
+ rb_raise(rb_eRuntimeError, "A database name must be specified");
1297
+
1298
+ Data_Get_Struct(self, char, did);
1299
+
1300
+ dbname = StringValueCStr(arg[0]);
1301
+ snprintf(did, IDSIZE, "DB%lX", self);
1302
+
1303
+ if (!NIL_P(arg[1]))
1304
+ user = StringValueCStr(arg[1]);
1305
+
1306
+ if (!NIL_P(arg[2]))
1307
+ pass = StringValueCStr(arg[2]);
1308
+
1309
+ if (user && pass)
1310
+ /*
1311
+ * EXEC SQL connect to :dbname as :did user :user
1312
+ * using :pass with concurrent transaction;
1313
+ */
1314
+ #line 1138 "informix.ec"
1315
+ {
1316
+ #line 1139 "informix.ec"
1317
+ ifx_conn_t *_sqiconn;
1318
+ _sqiconn = (ifx_conn_t *)ifx_alloc_conn_user(user, pass);
1319
+ sqli_connect_open(ESQLINTVERSION, 0, dbname, did, _sqiconn, 1);
1320
+ ifx_free_conn_user(&_sqiconn);
1321
+ #line 1139 "informix.ec"
1322
+ }
1323
+ else
1324
+ /*
1325
+ * EXEC SQL connect to :dbname as :did with concurrent transaction;
1326
+ */
1327
+ #line 1141 "informix.ec"
1328
+ {
1329
+ #line 1141 "informix.ec"
1330
+ sqli_connect_open(ESQLINTVERSION, 0, dbname, did, (ifx_conn_t *)0, 1);
1331
+ #line 1141 "informix.ec"
1332
+ }
1333
+
1334
+ if (SQLCODE < 0)
1335
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1336
+
1337
+ currentdid = did;
1338
+
1339
+ return self;
1340
+ }
1341
+
1342
+ /*
1343
+ * call-seq:
1344
+ * db.close => db
1345
+ *
1346
+ * Disconnects <i>db</i> and returns __self__
1347
+ */
1348
+ static VALUE
1349
+ database_close(VALUE self)
1350
+ {
1351
+ /*
1352
+ * EXEC SQL begin declare section;
1353
+ */
1354
+ #line 1160 "informix.ec"
1355
+ #line 1161 "informix.ec"
1356
+ char *did;
1357
+ /*
1358
+ * EXEC SQL end declare section;
1359
+ */
1360
+ #line 1162 "informix.ec"
1361
+
1362
+
1363
+ Data_Get_Struct(self, char, did);
1364
+ /*
1365
+ * EXEC SQL disconnect :did;
1366
+ */
1367
+ #line 1165 "informix.ec"
1368
+ {
1369
+ #line 1165 "informix.ec"
1370
+ sqli_connect_close(0, did, 0, 0);
1371
+ #line 1165 "informix.ec"
1372
+ }
1373
+ if (did == currentdid)
1374
+ currentdid = NULL;
1375
+
1376
+ return self;
1377
+ }
1378
+
1379
+ /*
1380
+ * call-seq:
1381
+ * db.immediate(query) => fixnum
1382
+ *
1383
+ * Executes <i>query</i> and returns the number of rows affected.
1384
+ * <i>query</i> must not return rows. Executes efficiently any
1385
+ * non-parameterized or DQL statement.
1386
+ */
1387
+
1388
+ static VALUE
1389
+ database_immediate(VALUE self, VALUE arg)
1390
+ {
1391
+ /*
1392
+ * EXEC SQL begin declare section;
1393
+ */
1394
+ #line 1184 "informix.ec"
1395
+ #line 1185 "informix.ec"
1396
+ char *query, *did;
1397
+ /*
1398
+ * EXEC SQL end declare section;
1399
+ */
1400
+ #line 1186 "informix.ec"
1401
+
1402
+
1403
+ Data_Get_Struct(self, char, did);
1404
+
1405
+ if (currentdid != did) {
1406
+ /*
1407
+ * EXEC SQL set connection :did;
1408
+ */
1409
+ #line 1191 "informix.ec"
1410
+ {
1411
+ #line 1191 "informix.ec"
1412
+ sqli_connect_set(0, did, 0);
1413
+ #line 1191 "informix.ec"
1414
+ }
1415
+ if (SQLCODE < 0)
1416
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1417
+ currentdid = did;
1418
+ }
1419
+
1420
+ query = StringValueCStr(arg);
1421
+ /*
1422
+ * EXEC SQL execute immediate :query;
1423
+ */
1424
+ #line 1198 "informix.ec"
1425
+ {
1426
+ #line 1198 "informix.ec"
1427
+ sqli_exec_immed(query);
1428
+ #line 1198 "informix.ec"
1429
+ }
1430
+ if (SQLCODE < 0)
1431
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1432
+
1433
+ return INT2FIX(sqlca.sqlerrd[2]);
1434
+ }
1435
+
1436
+ /*
1437
+ * call-seq:
1438
+ * db.rollback => db
1439
+ *
1440
+ * Rolls back a transaction and returns __self__.
1441
+ */
1442
+ static VALUE
1443
+ database_rollback(VALUE self)
1444
+ {
1445
+ /*
1446
+ * EXEC SQL begin declare section;
1447
+ */
1448
+ #line 1214 "informix.ec"
1449
+ #line 1215 "informix.ec"
1450
+ char *did;
1451
+ /*
1452
+ * EXEC SQL end declare section;
1453
+ */
1454
+ #line 1216 "informix.ec"
1455
+
1456
+
1457
+ Data_Get_Struct(self, char, did);
1458
+
1459
+ if (currentdid != did) {
1460
+ /*
1461
+ * EXEC SQL set connection :did;
1462
+ */
1463
+ #line 1221 "informix.ec"
1464
+ {
1465
+ #line 1221 "informix.ec"
1466
+ sqli_connect_set(0, did, 0);
1467
+ #line 1221 "informix.ec"
1468
+ }
1469
+ if (SQLCODE < 0)
1470
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1471
+ currentdid = did;
1472
+ }
1473
+
1474
+ /*
1475
+ * EXEC SQL rollback;
1476
+ */
1477
+ #line 1227 "informix.ec"
1478
+ {
1479
+ #line 1227 "informix.ec"
1480
+ sqli_trans_rollback();
1481
+ #line 1227 "informix.ec"
1482
+ }
1483
+ return self;
1484
+ }
1485
+
1486
+ /*
1487
+ * call-seq:
1488
+ * db.commit => db
1489
+ *
1490
+ * Commits a transaction and returns __self__.
1491
+ */
1492
+ static VALUE
1493
+ database_commit(VALUE self)
1494
+ {
1495
+ /*
1496
+ * EXEC SQL begin declare section;
1497
+ */
1498
+ #line 1240 "informix.ec"
1499
+ #line 1241 "informix.ec"
1500
+ char *did;
1501
+ /*
1502
+ * EXEC SQL end declare section;
1503
+ */
1504
+ #line 1242 "informix.ec"
1505
+
1506
+
1507
+ Data_Get_Struct(self, char, did);
1508
+
1509
+ if (currentdid != did) {
1510
+ /*
1511
+ * EXEC SQL set connection :did;
1512
+ */
1513
+ #line 1247 "informix.ec"
1514
+ {
1515
+ #line 1247 "informix.ec"
1516
+ sqli_connect_set(0, did, 0);
1517
+ #line 1247 "informix.ec"
1518
+ }
1519
+ if (SQLCODE < 0)
1520
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1521
+ currentdid = did;
1522
+ }
1523
+
1524
+ /*
1525
+ * EXEC SQL commit;
1526
+ */
1527
+ #line 1253 "informix.ec"
1528
+ {
1529
+ #line 1253 "informix.ec"
1530
+ sqli_trans_commit();
1531
+ #line 1253 "informix.ec"
1532
+ }
1533
+ return self;
1534
+ }
1535
+
1536
+ static VALUE
1537
+ database_transfail(VALUE self)
1538
+ {
1539
+ database_rollback(self);
1540
+ return Qundef;
1541
+ }
1542
+
1543
+ /*
1544
+ * call-seq:
1545
+ * db.transaction {|db| block } => db
1546
+ *
1547
+ * Opens a transaction and executes <i>block</i>, passing __self__ as parameter.
1548
+ * If an exception is raised, the transaction is rolled back. It is commited
1549
+ * otherwise.
1550
+ *
1551
+ * Returns __self__.
1552
+ */
1553
+ static VALUE
1554
+ database_transaction(VALUE self)
1555
+ {
1556
+ VALUE ret;
1557
+ /*
1558
+ * EXEC SQL begin declare section;
1559
+ */
1560
+ #line 1278 "informix.ec"
1561
+ #line 1279 "informix.ec"
1562
+ char *did;
1563
+ /*
1564
+ * EXEC SQL end declare section;
1565
+ */
1566
+ #line 1280 "informix.ec"
1567
+
1568
+
1569
+ Data_Get_Struct(self, char, did);
1570
+
1571
+ if (currentdid != did) {
1572
+ /*
1573
+ * EXEC SQL set connection :did;
1574
+ */
1575
+ #line 1285 "informix.ec"
1576
+ {
1577
+ #line 1285 "informix.ec"
1578
+ sqli_connect_set(0, did, 0);
1579
+ #line 1285 "informix.ec"
1580
+ }
1581
+ if (SQLCODE < 0)
1582
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1583
+ currentdid = did;
1584
+ }
1585
+
1586
+ /*
1587
+ * EXEC SQL commit;
1588
+ */
1589
+ #line 1291 "informix.ec"
1590
+ {
1591
+ #line 1291 "informix.ec"
1592
+ sqli_trans_commit();
1593
+ #line 1291 "informix.ec"
1594
+ }
1595
+
1596
+ /*
1597
+ * EXEC SQL begin work;
1598
+ */
1599
+ #line 1293 "informix.ec"
1600
+ {
1601
+ #line 1293 "informix.ec"
1602
+ sqli_trans_begin2((mint)1);
1603
+ #line 1293 "informix.ec"
1604
+ }
1605
+ ret = rb_rescue(rb_yield, self, database_transfail, self);
1606
+ if (ret == Qundef)
1607
+ rb_raise(rb_eRuntimeError, "Transaction rolled back");
1608
+ /*
1609
+ * EXEC SQL commit;
1610
+ */
1611
+ #line 1297 "informix.ec"
1612
+ {
1613
+ #line 1297 "informix.ec"
1614
+ sqli_trans_commit();
1615
+ #line 1297 "informix.ec"
1616
+ }
1617
+ return self;
1618
+ }
1619
+
1620
+ /*
1621
+ * call-seq:
1622
+ * db.prepare(query) => statement
1623
+ *
1624
+ * Returns a <code>Statement</code> object based on <i>query</i>.
1625
+ * <i>query</i> may contain '?' placeholders for input parameters;
1626
+ * it must not be a query returning more than one row
1627
+ * (use <code>Database#cursor</code> instead.)
1628
+ */
1629
+ static VALUE
1630
+ database_prepare(VALUE self, VALUE query)
1631
+ {
1632
+ VALUE argv[2];
1633
+
1634
+ argv[0] = self; argv[1] = query;
1635
+ return rb_class_new_instance(2, argv, rb_cStatement);
1636
+ }
1637
+
1638
+ /*
1639
+ * call-seq:
1640
+ * db.cursor(query, options = nil) => cursor
1641
+ *
1642
+ * Returns a <code>Cursor</code> object based on <i>query</i>.
1643
+ * <i>query</i> may contain '?' placeholders for input parameters.
1644
+ *
1645
+ * <i>options</i> must be a hash with the following possible keys:
1646
+ *
1647
+ * :scroll => true or false
1648
+ * :hold => true or false
1649
+ *
1650
+ */
1651
+ static VALUE
1652
+ database_cursor(int argc, VALUE *argv, VALUE self)
1653
+ {
1654
+ VALUE arg[3];
1655
+
1656
+ arg[0] = self;
1657
+ rb_scan_args(argc, argv, "11", &arg[1], &arg[2]);
1658
+ return rb_class_new_instance(3, arg, rb_cCursor);
1659
+ }
1660
+
1661
+ /*
1662
+ * call-seq:
1663
+ * db.columns(tablename) => array
1664
+ *
1665
+ * Returns an array with information for every column of the given table.
1666
+ */
1667
+ static VALUE
1668
+ database_columns(VALUE self, VALUE tablename)
1669
+ {
1670
+ VALUE v, column, result;
1671
+ char *stype;
1672
+ static char *stypes[] = {
1673
+ "CHAR", "SMALLINT", "INTEGER", "FLOAT", "SMALLFLOAT", "DECIMAL",
1674
+ "SERIAL", "DATE", "MONEY", "NULL", "DATETIME", "BYTE",
1675
+ "TEXT", "VARCHAR", "INTERVAL", "NCHAR", "NVARCHAR", "INT8",
1676
+ "SERIAL8", "SET", "MULTISET", "LIST", "UNNAMED ROW", "NAMED ROW",
1677
+ "VARIABLE-LENGTH OPAQUE TYPE"
1678
+ };
1679
+
1680
+ static char *qualifiers[] = {
1681
+ "YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND"
1682
+ };
1683
+
1684
+ /*
1685
+ * EXEC SQL begin declare section;
1686
+ */
1687
+ #line 1365 "informix.ec"
1688
+ #line 1366 "informix.ec"
1689
+ char *did;
1690
+ char *tabname;
1691
+ int tabid, xid;
1692
+ char colname[129];
1693
+ short coltype, collength;
1694
+ char deftype[2];
1695
+ char defvalue[257];
1696
+ /*
1697
+ * EXEC SQL end declare section;
1698
+ */
1699
+ #line 1373 "informix.ec"
1700
+
1701
+
1702
+ Data_Get_Struct(self, char, did);
1703
+
1704
+ if (currentdid != did) {
1705
+ /*
1706
+ * EXEC SQL set connection :did;
1707
+ */
1708
+ #line 1378 "informix.ec"
1709
+ {
1710
+ #line 1378 "informix.ec"
1711
+ sqli_connect_set(0, did, 0);
1712
+ #line 1378 "informix.ec"
1713
+ }
1714
+ if (SQLCODE < 0)
1715
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1716
+ currentdid = did;
1717
+ }
1718
+
1719
+ tabname = StringValueCStr(tablename);
1720
+
1721
+ /*
1722
+ * EXEC SQL select tabid into :tabid from systables where tabname = :tabname;
1723
+ */
1724
+ #line 1386 "informix.ec"
1725
+ {
1726
+ #line 1386 "informix.ec"
1727
+ static const char *sqlcmdtxt[] =
1728
+ #line 1386 "informix.ec"
1729
+ {
1730
+ #line 1386 "informix.ec"
1731
+ "select tabid from systables where tabname = ?",
1732
+ 0
1733
+ };
1734
+ #line 1386 "informix.ec"
1735
+ static ifx_cursor_t _SQ0 = {0};
1736
+ static ifx_sqlvar_t _sqibind[] =
1737
+ {
1738
+ { 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1739
+ #line 1386 "informix.ec"
1740
+ };
1741
+ static ifx_sqlvar_t _sqobind[] =
1742
+ {
1743
+ { 102, sizeof(tabid), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1744
+ #line 1386 "informix.ec"
1745
+ };
1746
+ #line 1386 "informix.ec"
1747
+ _sqibind[0].sqldata = tabname;
1748
+ #line 1386 "informix.ec"
1749
+ _sqobind[0].sqldata = (char *) &tabid;
1750
+ #line 1386 "informix.ec"
1751
+ sqli_slct(ESQLINTVERSION, &_SQ0,sqlcmdtxt,1,_sqibind,1,_sqobind,0,(ifx_literal_t *)0,(ifx_namelist_t *)0,0);
1752
+ #line 1386 "informix.ec"
1753
+ }
1754
+
1755
+ if (SQLCODE == SQLNOTFOUND)
1756
+ rb_raise(rb_eRuntimeError, "Table '%s' doesn't exist", tabname);
1757
+
1758
+ result = rb_ary_new();
1759
+
1760
+ /*
1761
+ * EXEC SQL declare cur cursor for
1762
+ * select colname, coltype, collength, extended_id, type, default, c.colno
1763
+ * from syscolumns c, outer sysdefaults d
1764
+ * where c.tabid = :tabid and c.tabid = d.tabid and c.colno = d.colno
1765
+ * order by c.colno;
1766
+ */
1767
+ #line 1393 "informix.ec"
1768
+ {
1769
+ #line 1397 "informix.ec"
1770
+ static const char *sqlcmdtxt[] =
1771
+ #line 1397 "informix.ec"
1772
+ {
1773
+ #line 1397 "informix.ec"
1774
+ "select colname , coltype , collength , extended_id , type , default , c . colno from syscolumns c , outer sysdefaults d where c . tabid = ? and c . tabid = d . tabid and c . colno = d . colno order by c . colno",
1775
+ 0
1776
+ };
1777
+ #line 1397 "informix.ec"
1778
+ static ifx_sqlvar_t _sqibind[] =
1779
+ {
1780
+ { 102, sizeof(tabid), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1781
+ #line 1397 "informix.ec"
1782
+ };
1783
+ static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
1784
+ #line 1397 "informix.ec"
1785
+ _sqibind[0].sqldata = (char *) &tabid;
1786
+ #line 1397 "informix.ec"
1787
+ sqli_curs_decl_stat(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, _Cn1, 512), _Cn1, sqlcmdtxt, &_SD0, (ifx_sqlda_t *)0, 0, (ifx_literal_t *)0, (ifx_namelist_t *)0, 2, 0, 0);
1788
+ #line 1397 "informix.ec"
1789
+ }
1790
+
1791
+ if (SQLCODE < 0)
1792
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1793
+
1794
+ /*
1795
+ * EXEC SQL open cur;
1796
+ */
1797
+ #line 1402 "informix.ec"
1798
+ {
1799
+ #line 1402 "informix.ec"
1800
+ sqli_curs_open(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, _Cn1, 768), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0, 0);
1801
+ #line 1402 "informix.ec"
1802
+ }
1803
+ if (SQLCODE < 0)
1804
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1805
+
1806
+ for(;;) {
1807
+ /*
1808
+ * EXEC SQL fetch cur into :colname, :coltype, :collength, :xid,
1809
+ * :deftype, :defvalue;
1810
+ */
1811
+ #line 1407 "informix.ec"
1812
+ {
1813
+ #line 1408 "informix.ec"
1814
+ static ifx_sqlvar_t _sqobind[] =
1815
+ {
1816
+ { 114, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1817
+ { 101, sizeof(coltype), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1818
+ { 101, sizeof(collength), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1819
+ { 102, sizeof(xid), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1820
+ { 100, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1821
+ { 114, 257, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1822
+ #line 1408 "informix.ec"
1823
+ };
1824
+ static ifx_sqlda_t _SD0 = { 6, _sqobind, {0}, 6, 0 };
1825
+ static _FetchSpec _FS1 = { 0, 1, 0 };
1826
+ #line 1408 "informix.ec"
1827
+ _sqobind[0].sqldata = colname;
1828
+ #line 1408 "informix.ec"
1829
+ _sqobind[1].sqldata = (char *) &coltype;
1830
+ #line 1408 "informix.ec"
1831
+ _sqobind[2].sqldata = (char *) &collength;
1832
+ #line 1408 "informix.ec"
1833
+ _sqobind[3].sqldata = (char *) &xid;
1834
+ #line 1408 "informix.ec"
1835
+ _sqobind[4].sqldata = deftype;
1836
+ #line 1408 "informix.ec"
1837
+ _sqobind[5].sqldata = defvalue;
1838
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, _Cn1, 768), (ifx_sqlda_t *)0, &_SD0, (char *)0, &_FS1);
1839
+ #line 1408 "informix.ec"
1840
+ }
1841
+ if (SQLCODE < 0)
1842
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1843
+
1844
+ if (SQLCODE == SQLNOTFOUND)
1845
+ break;
1846
+
1847
+ column = rb_hash_new();
1848
+ rb_hash_aset(column, sym_name, rb_str_new2(colname));
1849
+ rb_hash_aset(column, sym_type, INT2FIX(coltype));
1850
+ rb_hash_aset(column, sym_nullable, coltype&0x100? Qfalse: Qtrue);
1851
+ rb_hash_aset(column, sym_xid, INT2FIX(xid));
1852
+
1853
+ if ((coltype&0xFF) < 23) {
1854
+ stype = coltype == 4118? stypes[23]: stypes[coltype&0xFF];
1855
+ }
1856
+ else {
1857
+ stype = stypes[24];
1858
+ }
1859
+ rb_hash_aset(column, sym_stype, rb_str_new2(stype));
1860
+ rb_hash_aset(column, sym_length, INT2FIX(collength));
1861
+
1862
+ switch(coltype&0xFF) {
1863
+ case SQLVCHAR:
1864
+ case SQLNVCHAR:
1865
+ case SQLMONEY:
1866
+ case SQLDECIMAL:
1867
+ rb_hash_aset(column, sym_precision, INT2FIX(collength >> 8));
1868
+ rb_hash_aset(column, sym_scale, INT2FIX(collength&0xFF));
1869
+ break;
1870
+ case SQLDATE:
1871
+ case SQLDTIME:
1872
+ case SQLINTERVAL:
1873
+ rb_hash_aset(column, sym_length, INT2FIX(collength >> 8));
1874
+ rb_hash_aset(column, sym_precision, INT2FIX((collength&0xF0) >> 4));
1875
+ rb_hash_aset(column, sym_scale, INT2FIX(collength&0xF));
1876
+ break;
1877
+ default:
1878
+ rb_hash_aset(column, sym_precision, INT2FIX(0));
1879
+ rb_hash_aset(column, sym_scale, INT2FIX(0));
1880
+ }
1881
+
1882
+ if (!deftype[0]) {
1883
+ v = Qnil;
1884
+ }
1885
+ else {
1886
+ switch(deftype[0]) {
1887
+ case 'C': {
1888
+ char current[28];
1889
+ snprintf(current, sizeof(current), "CURRENT %s TO %s",
1890
+ qualifiers[(collength&0xF0) >> 5],
1891
+ qualifiers[(collength&0xF)>>1]);
1892
+ v = rb_str_new2(current);
1893
+ break;
1894
+ }
1895
+ case 'L':
1896
+ switch (coltype & 0xFF) {
1897
+ case SQLCHAR:
1898
+ case SQLNCHAR:
1899
+ case SQLVCHAR:
1900
+ case SQLNVCHAR:
1901
+ v = rb_str_new2(defvalue);
1902
+ break;
1903
+ default: {
1904
+ char *s = defvalue;
1905
+ while(*s++ != ' ');
1906
+ if ((coltype&0xFF) == SQLFLOAT ||
1907
+ (coltype&0xFF) == SQLSMFLOAT ||
1908
+ (coltype&0xFF) == SQLMONEY ||
1909
+ (coltype&0xFF) == SQLDECIMAL)
1910
+ v = rb_float_new(atof(s));
1911
+ else
1912
+ v = LONG2FIX(atol(s));
1913
+ }
1914
+ }
1915
+ break;
1916
+ case 'N':
1917
+ v = rb_str_new2("NULL");
1918
+ break;
1919
+ case 'T':
1920
+ v = rb_str_new2("today");
1921
+ break;
1922
+ case 'U':
1923
+ v = rb_str_new2("user");
1924
+ break;
1925
+ case 'S':
1926
+ default: /* XXX */
1927
+ v = Qnil;
1928
+ }
1929
+ }
1930
+ rb_hash_aset(column, sym_default, v);
1931
+ rb_ary_push(result, column);
1932
+ }
1933
+
1934
+ /*
1935
+ * EXEC SQL close cur;
1936
+ */
1937
+ #line 1502 "informix.ec"
1938
+ {
1939
+ #line 1502 "informix.ec"
1940
+ sqli_curs_close(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, _Cn1, 768));
1941
+ #line 1502 "informix.ec"
1942
+ }
1943
+ /*
1944
+ * EXEC SQL free cur;
1945
+ */
1946
+ #line 1503 "informix.ec"
1947
+ {
1948
+ #line 1503 "informix.ec"
1949
+ sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, _Cn1, 770));
1950
+ #line 1503 "informix.ec"
1951
+ }
1952
+
1953
+ return result;
1954
+ }
1955
+
1956
+ /* class Statement ------------------------------------------------------- */
1957
+
1958
+ static void
1959
+ statement_mark(cursor_t *c)
1960
+ {
1961
+ rb_gc_mark(c->db);
1962
+ if (c->array)
1963
+ rb_gc_mark(c->array);
1964
+ if (c->hash)
1965
+ rb_gc_mark(c->hash);
1966
+ if (c->field_names)
1967
+ rb_gc_mark(c->field_names);
1968
+ }
1969
+
1970
+ static void
1971
+ statement_free(void *p)
1972
+ {
1973
+ /*
1974
+ * EXEC SQL begin declare section;
1975
+ */
1976
+ #line 1525 "informix.ec"
1977
+ #line 1526 "informix.ec"
1978
+ char *sid, *did;
1979
+ /*
1980
+ * EXEC SQL end declare section;
1981
+ */
1982
+ #line 1527 "informix.ec"
1983
+
1984
+
1985
+ free_input_slots(p);
1986
+ free_output_slots(p);
1987
+
1988
+ did = ((cursor_t *)p)->database_id;
1989
+ if (currentdid != did) {
1990
+ /*
1991
+ * EXEC SQL set connection :did;
1992
+ */
1993
+ #line 1534 "informix.ec"
1994
+ {
1995
+ #line 1534 "informix.ec"
1996
+ sqli_connect_set(0, did, 0);
1997
+ #line 1534 "informix.ec"
1998
+ }
1999
+ if (SQLCODE < 0)
2000
+ goto exit;
2001
+ currentdid = did;
2002
+ }
2003
+
2004
+ sid = ((cursor_t *)p)->stmt_id;
2005
+ /*
2006
+ * EXEC SQL free :sid;
2007
+ */
2008
+ #line 1541 "informix.ec"
2009
+ {
2010
+ #line 1541 "informix.ec"
2011
+ sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 258));
2012
+ #line 1541 "informix.ec"
2013
+ }
2014
+
2015
+ exit:
2016
+ xfree(p);
2017
+ }
2018
+
2019
+ static VALUE
2020
+ statement_alloc(VALUE klass)
2021
+ {
2022
+ cursor_t *c;
2023
+
2024
+ c = ALLOC(cursor_t);
2025
+ memset(c, 0, sizeof(cursor_t));
2026
+ return Data_Wrap_Struct(klass, statement_mark, statement_free, c);
2027
+ }
2028
+
2029
+ /*
2030
+ * call-seq:
2031
+ * Statement.new(database, query) => statement
2032
+ *
2033
+ * Prepares <i>query</i> in the context of <i>database</i> and returns
2034
+ * a <code>Statement</code> object.
2035
+ */
2036
+ static VALUE
2037
+ statement_initialize(VALUE self, VALUE db, VALUE query)
2038
+ {
2039
+ struct sqlda *output;
2040
+ cursor_t *c;
2041
+ /*
2042
+ * EXEC SQL begin declare section;
2043
+ */
2044
+ #line 1569 "informix.ec"
2045
+ #line 1570 "informix.ec"
2046
+ char *c_query, *sid, *did;
2047
+ /*
2048
+ * EXEC SQL end declare section;
2049
+ */
2050
+ #line 1571 "informix.ec"
2051
+
2052
+
2053
+ Data_Get_Struct(db, char, did);
2054
+ if (currentdid != did) {
2055
+ /*
2056
+ * EXEC SQL set connection :did;
2057
+ */
2058
+ #line 1575 "informix.ec"
2059
+ {
2060
+ #line 1575 "informix.ec"
2061
+ sqli_connect_set(0, did, 0);
2062
+ #line 1575 "informix.ec"
2063
+ }
2064
+ if (SQLCODE < 0)
2065
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2066
+ currentdid = did;
2067
+ }
2068
+
2069
+ Data_Get_Struct(self, cursor_t, c);
2070
+ c->db = db;
2071
+ c->database_id = did;
2072
+ output = c->daOutput;
2073
+ snprintf(c->stmt_id, sizeof(c->stmt_id), "STMT%lX", self);
2074
+ sid = c->stmt_id;
2075
+ c_query = StringValueCStr(query);
2076
+
2077
+ /*
2078
+ * EXEC SQL prepare :sid from :c_query;
2079
+ */
2080
+ #line 1589 "informix.ec"
2081
+ {
2082
+ #line 1589 "informix.ec"
2083
+ sqli_prep(ESQLINTVERSION, sid, c_query,(ifx_literal_t *)0, (ifx_namelist_t *)0, -1, 0, 0 );
2084
+ #line 1589 "informix.ec"
2085
+ }
2086
+ if (SQLCODE < 0)
2087
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2088
+
2089
+ alloc_input_slots(c, c_query);
2090
+ /*
2091
+ * EXEC SQL describe :sid into output;
2092
+ */
2093
+ #line 1594 "informix.ec"
2094
+ {
2095
+ #line 1594 "informix.ec"
2096
+ sqli_describe_stmt(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 257), &output, 0);
2097
+ #line 1594 "informix.ec"
2098
+ }
2099
+ c->daOutput = output;
2100
+
2101
+ c->is_select = (SQLCODE == 0 || SQLCODE == SQ_EXECPROC);
2102
+
2103
+ if (c->is_select)
2104
+ alloc_output_slots(c);
2105
+ else {
2106
+ xfree(c->daOutput);
2107
+ c->daOutput = NULL;
2108
+ }
2109
+
2110
+ return self;
2111
+ }
2112
+
2113
+
2114
+ /*
2115
+ * call-seq:
2116
+ * stmt[*params] => fixnum or hash
2117
+ *
2118
+ * Executes the previously prepared statement, binding <i>params</i> as
2119
+ * input parameters.
2120
+ *
2121
+ * Returns the record retrieved, in the case of a singleton select, or the
2122
+ * number of rows affected, in the case of any other statement.
2123
+ */
2124
+ static VALUE
2125
+ statement_call(int argc, VALUE *argv, VALUE self)
2126
+ {
2127
+ struct sqlda *input, *output;
2128
+ cursor_t *c;
2129
+ /*
2130
+ * EXEC SQL begin declare section;
2131
+ */
2132
+ #line 1625 "informix.ec"
2133
+ #line 1626 "informix.ec"
2134
+ char *sid, *did;
2135
+ /*
2136
+ * EXEC SQL end declare section;
2137
+ */
2138
+ #line 1627 "informix.ec"
2139
+
2140
+
2141
+ Data_Get_Struct(self, cursor_t, c);
2142
+
2143
+ did = c->database_id;
2144
+ if (currentdid != did) {
2145
+ /*
2146
+ * EXEC SQL set connection :did;
2147
+ */
2148
+ #line 1633 "informix.ec"
2149
+ {
2150
+ #line 1633 "informix.ec"
2151
+ sqli_connect_set(0, did, 0);
2152
+ #line 1633 "informix.ec"
2153
+ }
2154
+ if (SQLCODE < 0)
2155
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2156
+ currentdid = did;
2157
+ }
2158
+
2159
+ output = c->daOutput;
2160
+ input = &c->daInput;
2161
+ sid = c->stmt_id;
2162
+
2163
+ if (argc != input->sqld)
2164
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
2165
+ argc, input->sqld);
2166
+
2167
+ if (c->is_select) {
2168
+ if (argc) {
2169
+ bind_input_params(c, argv);
2170
+ /*
2171
+ * EXEC SQL execute :sid into descriptor output
2172
+ * using descriptor input;
2173
+ */
2174
+ #line 1650 "informix.ec"
2175
+ {
2176
+ #line 1651 "informix.ec"
2177
+ sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 257), input, (char *)0, (struct value *)0, output, (char *)0, (struct value *)0, 0);
2178
+ #line 1651 "informix.ec"
2179
+ }
2180
+ clean_input_slots(c);
2181
+ }
2182
+ else
2183
+ /*
2184
+ * EXEC SQL execute :sid into descriptor output;
2185
+ */
2186
+ #line 1655 "informix.ec"
2187
+ {
2188
+ #line 1655 "informix.ec"
2189
+ sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 257), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, output, (char *)0, (struct value *)0, 0);
2190
+ #line 1655 "informix.ec"
2191
+ }
2192
+
2193
+ if (SQLCODE < 0)
2194
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2195
+
2196
+ if (SQLCODE == SQLNOTFOUND)
2197
+ return Qnil;
2198
+ return make_result(c, rb_hash_new());
2199
+ }
2200
+ else {
2201
+ if (argc) {
2202
+ bind_input_params(c, argv);
2203
+ /*
2204
+ * EXEC SQL execute :sid using descriptor input;
2205
+ */
2206
+ #line 1667 "informix.ec"
2207
+ {
2208
+ #line 1667 "informix.ec"
2209
+ sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 257), input, (char *)0, (struct value *)0, (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0);
2210
+ #line 1667 "informix.ec"
2211
+ }
2212
+ clean_input_slots(c);
2213
+ }
2214
+ else
2215
+ /*
2216
+ * EXEC SQL execute :sid;
2217
+ */
2218
+ #line 1671 "informix.ec"
2219
+ {
2220
+ #line 1671 "informix.ec"
2221
+ sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 257), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0);
2222
+ #line 1671 "informix.ec"
2223
+ }
2224
+ }
2225
+ if (SQLCODE < 0)
2226
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2227
+
2228
+ return INT2FIX(sqlca.sqlerrd[2]);
2229
+ }
2230
+
2231
+ /*
2232
+ * call-seq:
2233
+ * stmt.drop
2234
+ *
2235
+ * Frees the statement and the memory associated with it.
2236
+ */
2237
+ static VALUE
2238
+ statement_drop(VALUE self)
2239
+ {
2240
+ cursor_t *c;
2241
+ /*
2242
+ * EXEC SQL begin declare section;
2243
+ */
2244
+ #line 1689 "informix.ec"
2245
+ #line 1690 "informix.ec"
2246
+ char *sid, *did;
2247
+ /*
2248
+ * EXEC SQL end declare section;
2249
+ */
2250
+ #line 1691 "informix.ec"
2251
+
2252
+
2253
+ Data_Get_Struct(self, cursor_t, c);
2254
+ free_input_slots(c);
2255
+ free_output_slots(c);
2256
+
2257
+ did = c->database_id;
2258
+ if (currentdid != did) {
2259
+ /*
2260
+ * EXEC SQL set connection :did;
2261
+ */
2262
+ #line 1699 "informix.ec"
2263
+ {
2264
+ #line 1699 "informix.ec"
2265
+ sqli_connect_set(0, did, 0);
2266
+ #line 1699 "informix.ec"
2267
+ }
2268
+ if (SQLCODE < 0)
2269
+ return Qnil;
2270
+ currentdid = did;
2271
+ }
2272
+ sid = c->stmt_id;
2273
+ /*
2274
+ * EXEC SQL free :sid;
2275
+ */
2276
+ #line 1705 "informix.ec"
2277
+ {
2278
+ #line 1705 "informix.ec"
2279
+ sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 258));
2280
+ #line 1705 "informix.ec"
2281
+ }
2282
+
2283
+ return Qnil;
2284
+ }
2285
+
2286
+
2287
+ /* module SequentialCursor ----------------------------------------------- */
2288
+
2289
+ /* Decides whether to use an Array or a Hash, and instantiate a new
2290
+ * object or reuse an existing one.
2291
+ */
2292
+ #define RECORD(c, type, bang, record) do {\
2293
+ if (type == T_ARRAY) {\
2294
+ if (bang) {\
2295
+ if (!c->array)\
2296
+ c->array = rb_ary_new2(c->daOutput->sqld);\
2297
+ record = c->array;\
2298
+ }\
2299
+ else\
2300
+ record = rb_ary_new2(c->daOutput->sqld);\
2301
+ }\
2302
+ else {\
2303
+ if (bang) {\
2304
+ if (!c->hash)\
2305
+ c->hash = rb_hash_new();\
2306
+ record = c->hash;\
2307
+ }\
2308
+ else\
2309
+ record = rb_hash_new();\
2310
+ }\
2311
+ }while(0)
2312
+
2313
+ /*
2314
+ * Base function for fetch* methods, except *_many
2315
+ */
2316
+ static VALUE
2317
+ fetch(VALUE self, VALUE type, int bang)
2318
+ {
2319
+ /*
2320
+ * EXEC SQL begin declare section;
2321
+ */
2322
+ #line 1743 "informix.ec"
2323
+ #line 1744 "informix.ec"
2324
+ char *cid, *did;
2325
+ /*
2326
+ * EXEC SQL end declare section;
2327
+ */
2328
+ #line 1745 "informix.ec"
2329
+
2330
+ cursor_t *c;
2331
+ struct sqlda *output;
2332
+ VALUE record;
2333
+
2334
+ Data_Get_Struct(self, cursor_t, c);
2335
+ if (!c->is_open)
2336
+ rb_raise(rb_eRuntimeError, "Open the cursor object first");
2337
+
2338
+ did = c->database_id;
2339
+ if (currentdid != did) {
2340
+ /*
2341
+ * EXEC SQL set connection :did;
2342
+ */
2343
+ #line 1756 "informix.ec"
2344
+ {
2345
+ #line 1756 "informix.ec"
2346
+ sqli_connect_set(0, did, 0);
2347
+ #line 1756 "informix.ec"
2348
+ }
2349
+ if (SQLCODE < 0)
2350
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2351
+ currentdid = did;
2352
+ }
2353
+
2354
+ output = c->daOutput;
2355
+ cid = c->cursor_id;
2356
+
2357
+ /*
2358
+ * EXEC SQL fetch :cid using descriptor output;
2359
+ */
2360
+ #line 1765 "informix.ec"
2361
+ {
2362
+ #line 1765 "informix.ec"
2363
+ static _FetchSpec _FS0 = { 0, 1, 0 };
2364
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), (ifx_sqlda_t *)0, output, (char *)0, &_FS0);
2365
+ #line 1765 "informix.ec"
2366
+ }
2367
+ if (SQLCODE < 0)
2368
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2369
+
2370
+ if (SQLCODE == SQLNOTFOUND)
2371
+ return Qnil;
2372
+
2373
+ RECORD(c, type, bang, record);
2374
+ return make_result(c, record);
2375
+ }
2376
+
2377
+ /*
2378
+ * call-seq:
2379
+ * cursor.fetch => array or nil
2380
+ *
2381
+ * Fetches the next record.
2382
+ *
2383
+ * Returns the record fetched as an array, or nil if there are no
2384
+ * records left.
2385
+ */
2386
+ static VALUE
2387
+ seqcur_fetch(VALUE self)
2388
+ {
2389
+ return fetch(self, T_ARRAY, 0);
2390
+ }
2391
+
2392
+ /*
2393
+ * call-seq:
2394
+ * cursor.fetch! => array or nil
2395
+ *
2396
+ * Fetches the next record, storing it in the same Array object every time
2397
+ * it is called.
2398
+ *
2399
+ * Returns the record fetched as an array, or nil if there are no
2400
+ * records left.
2401
+ */
2402
+ static VALUE
2403
+ seqcur_fetch_bang(VALUE self)
2404
+ {
2405
+ return fetch(self, T_ARRAY, 1);
2406
+ }
2407
+
2408
+ /*
2409
+ * call-seq:
2410
+ * cursor.fetch_hash => hash or nil
2411
+ *
2412
+ * Fetches the next record.
2413
+ *
2414
+ * Returns the record fetched as a hash, or nil if there are no
2415
+ * records left.
2416
+ */
2417
+ static VALUE
2418
+ seqcur_fetch_hash(VALUE self)
2419
+ {
2420
+ return fetch(self, T_HASH, 0);
2421
+ }
2422
+
2423
+ /*
2424
+ * call-seq:
2425
+ * cursor.fetch_hash! => hash or nil
2426
+ *
2427
+ * Fetches the next record, storing it in the same Hash object every time
2428
+ * it is called.
2429
+ *
2430
+ * Returns the record fetched as a hash, or nil if there are no
2431
+ * records left.
2432
+ */
2433
+ static VALUE
2434
+ seqcur_fetch_hash_bang(VALUE self)
2435
+ {
2436
+ return fetch(self, T_HASH, 1);
2437
+ }
2438
+
2439
+ /*
2440
+ * Base function for fetch*_many, fetch*_all and each_by methods
2441
+ */
2442
+ static VALUE
2443
+ fetch_many(VALUE self, VALUE n, VALUE type)
2444
+ {
2445
+ /*
2446
+ * EXEC SQL begin declare section;
2447
+ */
2448
+ #line 1844 "informix.ec"
2449
+ #line 1845 "informix.ec"
2450
+ char *cid, *did;
2451
+ /*
2452
+ * EXEC SQL end declare section;
2453
+ */
2454
+ #line 1846 "informix.ec"
2455
+
2456
+ cursor_t *c;
2457
+ struct sqlda *output;
2458
+ VALUE record, records;
2459
+ register long i, max;
2460
+ register int all = n == Qnil;
2461
+
2462
+ Data_Get_Struct(self, cursor_t, c);
2463
+ if (!c->is_open)
2464
+ rb_raise(rb_eRuntimeError, "Open the cursor object first");
2465
+
2466
+ did = c->database_id;
2467
+ if (currentdid != did) {
2468
+ /*
2469
+ * EXEC SQL set connection :did;
2470
+ */
2471
+ #line 1859 "informix.ec"
2472
+ {
2473
+ #line 1859 "informix.ec"
2474
+ sqli_connect_set(0, did, 0);
2475
+ #line 1859 "informix.ec"
2476
+ }
2477
+ if (SQLCODE < 0)
2478
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2479
+ currentdid = did;
2480
+ }
2481
+
2482
+ output = c->daOutput;
2483
+ cid = c->cursor_id;
2484
+
2485
+ if (!all) {
2486
+ max = FIX2LONG(n);
2487
+ records = rb_ary_new2(max);
2488
+ }
2489
+ else {
2490
+ records = rb_ary_new();
2491
+ }
2492
+
2493
+ for(i = 0; all || i < max; i++) {
2494
+ /*
2495
+ * EXEC SQL fetch :cid using descriptor output;
2496
+ */
2497
+ #line 1877 "informix.ec"
2498
+ {
2499
+ #line 1877 "informix.ec"
2500
+ static _FetchSpec _FS0 = { 0, 1, 0 };
2501
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), (ifx_sqlda_t *)0, output, (char *)0, &_FS0);
2502
+ #line 1877 "informix.ec"
2503
+ }
2504
+ if (SQLCODE < 0)
2505
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2506
+
2507
+ if (SQLCODE == SQLNOTFOUND)
2508
+ break;
2509
+
2510
+ if (type == T_ARRAY)
2511
+ record = rb_ary_new2(c->daOutput->sqld);
2512
+ else
2513
+ record = rb_hash_new();
2514
+ rb_ary_store(records, i, make_result(c, record));
2515
+ }
2516
+
2517
+ return records;
2518
+ }
2519
+
2520
+ /*
2521
+ * call-seq:
2522
+ * cursor.fetch_many(n) => array
2523
+ *
2524
+ * Reads at most <i>n</i> records.
2525
+ *
2526
+ * Returns the records read as an array of arrays
2527
+ */
2528
+ static VALUE
2529
+ seqcur_fetch_many(VALUE self, VALUE n)
2530
+ {
2531
+ return fetch_many(self, n, T_ARRAY);
2532
+ }
2533
+
2534
+ /*
2535
+ * call-seq:
2536
+ * cursor.fetch_hash_many(n) => array
2537
+ *
2538
+ * Reads at most <i>n</i> records.
2539
+ * Returns the records read as an array of hashes.
2540
+ */
2541
+ static VALUE
2542
+ seqcur_fetch_hash_many(VALUE self, VALUE n)
2543
+ {
2544
+ return fetch_many(self, n, T_HASH);
2545
+ }
2546
+
2547
+ /*
2548
+ * call-seq:
2549
+ * cursor.fetch_all => array
2550
+ *
2551
+ * Returns all the records left as an array of arrays
2552
+ */
2553
+ static VALUE
2554
+ seqcur_fetch_all(VALUE self)
2555
+ {
2556
+ return fetch_many(self, Qnil, T_ARRAY);
2557
+ }
2558
+
2559
+ /*
2560
+ * call-seq:
2561
+ * cursor.fetch_hash_all => array
2562
+ *
2563
+ * Returns all the records left as an array of hashes
2564
+ */
2565
+ static VALUE
2566
+ seqcur_fetch_hash_all(VALUE self)
2567
+ {
2568
+ return fetch_many(self, Qnil, T_HASH);
2569
+ }
2570
+
2571
+ /*
2572
+ * Base function for each* methods, except each*_by
2573
+ */
2574
+ static VALUE
2575
+ each(VALUE self, VALUE type, int bang)
2576
+ {
2577
+ cursor_t *c;
2578
+ /*
2579
+ * EXEC SQL begin declare section;
2580
+ */
2581
+ #line 1952 "informix.ec"
2582
+ #line 1953 "informix.ec"
2583
+ char *cid, *did;
2584
+ /*
2585
+ * EXEC SQL end declare section;
2586
+ */
2587
+ #line 1954 "informix.ec"
2588
+
2589
+ struct sqlda *output;
2590
+ VALUE record;
2591
+
2592
+ Data_Get_Struct(self, cursor_t, c);
2593
+ if (!c->is_open)
2594
+ rb_raise(rb_eRuntimeError, "Open the cursor object first");
2595
+
2596
+ did = c->database_id;
2597
+ if (currentdid != did) {
2598
+ /*
2599
+ * EXEC SQL set connection :did;
2600
+ */
2601
+ #line 1964 "informix.ec"
2602
+ {
2603
+ #line 1964 "informix.ec"
2604
+ sqli_connect_set(0, did, 0);
2605
+ #line 1964 "informix.ec"
2606
+ }
2607
+ if (SQLCODE < 0)
2608
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2609
+ currentdid = did;
2610
+ }
2611
+
2612
+ output = c->daOutput;
2613
+ cid = c->cursor_id;
2614
+
2615
+ for(;;) {
2616
+ /*
2617
+ * EXEC SQL fetch :cid using descriptor output;
2618
+ */
2619
+ #line 1974 "informix.ec"
2620
+ {
2621
+ #line 1974 "informix.ec"
2622
+ static _FetchSpec _FS0 = { 0, 1, 0 };
2623
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), (ifx_sqlda_t *)0, output, (char *)0, &_FS0);
2624
+ #line 1974 "informix.ec"
2625
+ }
2626
+ if (SQLCODE < 0)
2627
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2628
+
2629
+ if (SQLCODE == SQLNOTFOUND)
2630
+ return self;
2631
+ RECORD(c, type, bang, record);
2632
+ rb_yield(make_result(c, record));
2633
+ }
2634
+ }
2635
+
2636
+ /*
2637
+ * Base function for each*_by methods
2638
+ */
2639
+ static VALUE
2640
+ each_by(VALUE self, VALUE n, VALUE type)
2641
+ {
2642
+ VALUE records;
2643
+
2644
+ for(;;) {
2645
+ records = fetch_many(self, n, type);
2646
+ if (RARRAY(records)->len == 0)
2647
+ return self;
2648
+ rb_yield(records);
2649
+ }
2650
+ }
2651
+
2652
+ /*
2653
+ * call-seq:
2654
+ * cursor.each {|record| block } => cursor
2655
+ *
2656
+ * Iterates over the remaining records, passing each <i>record</i> to the
2657
+ * <i>block</i> as an array.
2658
+ *
2659
+ * Returns __self__.
2660
+ */
2661
+ static VALUE
2662
+ seqcur_each(VALUE self)
2663
+ {
2664
+ return each(self, T_ARRAY, 0);
2665
+ }
2666
+
2667
+ /*
2668
+ * call-seq:
2669
+ * cursor.each! {|record| block } => cursor
2670
+ *
2671
+ * Iterates over the remaining records, passing each <i>record</i> to the
2672
+ * <i>block</i> as an array. No new Array objects are created for each record.
2673
+ * The same Array object is reused in each call.
2674
+ *
2675
+ * Returns __self__.
2676
+ */
2677
+ static VALUE
2678
+ seqcur_each_bang(VALUE self)
2679
+ {
2680
+ return each(self, T_ARRAY, 1);
2681
+ }
2682
+
2683
+ /*
2684
+ * call-seq:
2685
+ * cursor.each_hash {|record| block } => cursor
2686
+ *
2687
+ * Iterates over the remaining records, passing each <i>record</i> to the
2688
+ * <i>block</i> as a hash.
2689
+ *
2690
+ * Returns __self__.
2691
+ */
2692
+ static VALUE
2693
+ seqcur_each_hash(VALUE self)
2694
+ {
2695
+ return each(self, T_HASH, 0);
2696
+ }
2697
+
2698
+ /*
2699
+ * call-seq:
2700
+ * cursor.each_hash! {|record| block } => cursor
2701
+ *
2702
+ * Iterates over the remaining records, passing each <i>record</i> to the
2703
+ * <i>block</i> as a hash. No new Hash objects are created for each record.
2704
+ * The same Hash object is reused in each call.
2705
+ *
2706
+ * Returns __self__.
2707
+ */
2708
+ static VALUE
2709
+ seqcur_each_hash_bang(VALUE self)
2710
+ {
2711
+ return each(self, T_HASH, 1);
2712
+ }
2713
+
2714
+ /*
2715
+ * call-seq:
2716
+ * cursor.each_by(n) {|records| block } => cursor
2717
+ *
2718
+ * Iterates over the remaining records, passing at most <i>n</i> <i>records</i>
2719
+ * to the <i>block</i> as arrays.
2720
+ *
2721
+ * Returns __self__.
2722
+ */
2723
+ static VALUE
2724
+ seqcur_each_by(VALUE self, VALUE n)
2725
+ {
2726
+ return each_by(self, n, T_ARRAY);
2727
+ }
2728
+
2729
+ /*
2730
+ * call-seq:
2731
+ * cursor.each_hash_by(n) {|records| block } => cursor
2732
+ *
2733
+ * Iterates over the remaining records, passing at most <i>n</i> <i>records</i>
2734
+ * to the <i>block</i> as hashes.
2735
+ *
2736
+ * Returns __self__.
2737
+ */
2738
+ static VALUE
2739
+ seqcur_each_hash_by(VALUE self, VALUE n)
2740
+ {
2741
+ return each_by(self, n, T_HASH);
2742
+ }
2743
+
2744
+ /* module InsertCursor --------------------------------------------------- */
2745
+
2746
+ /*
2747
+ * call-seq:
2748
+ * cursor.put(*params)
2749
+ *
2750
+ * Binds <i>params</i> as input parameters and executes the insert statement.
2751
+ * The records are not written immediatly to disk, unless the insert buffer
2752
+ * is full, the <code>flush</code> method is called, the cursor is closed or
2753
+ * the transaction is commited.
2754
+ */
2755
+ static VALUE
2756
+ inscur_put(int argc, VALUE *argv, VALUE self)
2757
+ {
2758
+ struct sqlda *input;
2759
+ cursor_t *c;
2760
+ /*
2761
+ * EXEC SQL begin declare section;
2762
+ */
2763
+ #line 2109 "informix.ec"
2764
+ #line 2110 "informix.ec"
2765
+ char *cid, *did;
2766
+ /*
2767
+ * EXEC SQL end declare section;
2768
+ */
2769
+ #line 2111 "informix.ec"
2770
+
2771
+
2772
+ Data_Get_Struct(self, cursor_t, c);
2773
+ if (!c->is_open)
2774
+ rb_raise(rb_eRuntimeError, "Open the cursor object first");
2775
+
2776
+ did = c->database_id;
2777
+ if (currentdid != did) {
2778
+ /*
2779
+ * EXEC SQL set connection :did;
2780
+ */
2781
+ #line 2119 "informix.ec"
2782
+ {
2783
+ #line 2119 "informix.ec"
2784
+ sqli_connect_set(0, did, 0);
2785
+ #line 2119 "informix.ec"
2786
+ }
2787
+ if (SQLCODE < 0)
2788
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2789
+ currentdid = did;
2790
+ }
2791
+
2792
+ input = &c->daInput;
2793
+ cid = c->cursor_id;
2794
+
2795
+ bind_input_params(c, argv);
2796
+ if (argc != input->sqld)
2797
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
2798
+ argc, input->sqld);
2799
+
2800
+ /*
2801
+ * EXEC SQL put :cid using descriptor input;
2802
+ */
2803
+ #line 2133 "informix.ec"
2804
+ {
2805
+ #line 2133 "informix.ec"
2806
+ sqli_curs_put(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), input, (char *)0);
2807
+ #line 2133 "informix.ec"
2808
+ }
2809
+ clean_input_slots(c);
2810
+ if (SQLCODE < 0)
2811
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2812
+
2813
+ /* XXX 2-448, Guide to SQL: Sytax*/
2814
+ return INT2FIX(sqlca.sqlerrd[2]);
2815
+ }
2816
+
2817
+ /*
2818
+ * call-seq:
2819
+ * cursor.flush => cursor
2820
+ *
2821
+ * Flushes the insert buffer, writing data to disk.
2822
+ *
2823
+ * Returns __self__.
2824
+ */
2825
+ static VALUE
2826
+ inscur_flush(VALUE self)
2827
+ {
2828
+ cursor_t *c;
2829
+ /*
2830
+ * EXEC SQL begin declare section;
2831
+ */
2832
+ #line 2154 "informix.ec"
2833
+ #line 2155 "informix.ec"
2834
+ char *cid, *did;
2835
+ /*
2836
+ * EXEC SQL end declare section;
2837
+ */
2838
+ #line 2156 "informix.ec"
2839
+
2840
+
2841
+ Data_Get_Struct(self, cursor_t, c);
2842
+ if (!c->is_open)
2843
+ rb_raise(rb_eRuntimeError, "Open the cursor object first");
2844
+
2845
+ did = c->database_id;
2846
+ if (currentdid != did) {
2847
+ /*
2848
+ * EXEC SQL set connection :did;
2849
+ */
2850
+ #line 2164 "informix.ec"
2851
+ {
2852
+ #line 2164 "informix.ec"
2853
+ sqli_connect_set(0, did, 0);
2854
+ #line 2164 "informix.ec"
2855
+ }
2856
+ if (SQLCODE < 0)
2857
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2858
+ currentdid = did;
2859
+ }
2860
+
2861
+ cid = c->cursor_id;
2862
+ /*
2863
+ * EXEC SQL flush :cid;
2864
+ */
2865
+ #line 2171 "informix.ec"
2866
+ {
2867
+ #line 2171 "informix.ec"
2868
+ sqli_curs_flush(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256));
2869
+ #line 2171 "informix.ec"
2870
+ }
2871
+ return self;
2872
+ }
2873
+
2874
+ /* module ScrollCursor --------------------------------------------------- */
2875
+
2876
+ /*
2877
+ * Provides the Array-like functionality for scroll cursors when using the
2878
+ * cursor[index] syntax
2879
+ */
2880
+ static VALUE
2881
+ scrollcur_entry(VALUE self, VALUE index, VALUE type, int bang)
2882
+ {
2883
+ cursor_t *c;
2884
+ struct sqlda *output;
2885
+ VALUE record;
2886
+ /*
2887
+ * EXEC SQL begin declare section;
2888
+ */
2889
+ #line 2187 "informix.ec"
2890
+ #line 2188 "informix.ec"
2891
+ char *cid, *did;
2892
+ long pos;
2893
+ /*
2894
+ * EXEC SQL end declare section;
2895
+ */
2896
+ #line 2190 "informix.ec"
2897
+
2898
+
2899
+ Data_Get_Struct(self, cursor_t, c);
2900
+ if (!c->is_open)
2901
+ rb_raise(rb_eRuntimeError, "Open the cursor object first");
2902
+
2903
+ did = c->database_id;
2904
+ if (currentdid != did) {
2905
+ /*
2906
+ * EXEC SQL set connection :did;
2907
+ */
2908
+ #line 2198 "informix.ec"
2909
+ {
2910
+ #line 2198 "informix.ec"
2911
+ sqli_connect_set(0, did, 0);
2912
+ #line 2198 "informix.ec"
2913
+ }
2914
+ if (SQLCODE < 0)
2915
+ return Qnil;
2916
+ currentdid = did;
2917
+ }
2918
+
2919
+ output = c->daOutput;
2920
+ cid = c->cursor_id;
2921
+
2922
+ if (NIL_P(index))
2923
+ /*
2924
+ * EXEC SQL fetch current :cid using descriptor output;
2925
+ */
2926
+ #line 2208 "informix.ec"
2927
+ {
2928
+ #line 2208 "informix.ec"
2929
+ static _FetchSpec _FS0 = { 0, 5, 0 };
2930
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), (ifx_sqlda_t *)0, output, (char *)0, &_FS0);
2931
+ #line 2208 "informix.ec"
2932
+ }
2933
+ else if ((pos = NUM2LONG(index) + 1) > 0)
2934
+ /*
2935
+ * EXEC SQL fetch absolute :pos :cid using descriptor output;
2936
+ */
2937
+ #line 2210 "informix.ec"
2938
+ {
2939
+ #line 2210 "informix.ec"
2940
+ static ifx_sqlvar_t _sqibind[] =
2941
+ {
2942
+ { 103, sizeof(pos), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
2943
+ #line 2210 "informix.ec"
2944
+ };
2945
+ static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
2946
+ static _FetchSpec _FS1 = { 0, 6, 0 };
2947
+ #line 2210 "informix.ec"
2948
+ _sqibind[0].sqldata = (char *) &pos;
2949
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), &_SD0, output, (char *)0, &_FS1);
2950
+ #line 2210 "informix.ec"
2951
+ }
2952
+ else {
2953
+ /*
2954
+ * EXEC SQL fetch last :cid;
2955
+ */
2956
+ #line 2212 "informix.ec"
2957
+ {
2958
+ #line 2212 "informix.ec"
2959
+ static _FetchSpec _FS0 = { 0, 4, 0 };
2960
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), (ifx_sqlda_t *)0, (ifx_sqlda_t *)0, (char *)0, &_FS0);
2961
+ #line 2212 "informix.ec"
2962
+ }
2963
+ /*
2964
+ * EXEC SQL fetch relative :pos :cid using descriptor output;
2965
+ */
2966
+ #line 2213 "informix.ec"
2967
+ {
2968
+ #line 2213 "informix.ec"
2969
+ static ifx_sqlvar_t _sqibind[] =
2970
+ {
2971
+ { 103, sizeof(pos), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
2972
+ #line 2213 "informix.ec"
2973
+ };
2974
+ static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
2975
+ static _FetchSpec _FS1 = { 0, 7, 0 };
2976
+ #line 2213 "informix.ec"
2977
+ _sqibind[0].sqldata = (char *) &pos;
2978
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), &_SD0, output, (char *)0, &_FS1);
2979
+ #line 2213 "informix.ec"
2980
+ }
2981
+ }
2982
+
2983
+ if (SQLCODE == SQLNOTFOUND)
2984
+ return Qnil;
2985
+
2986
+ if (SQLCODE < 0)
2987
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2988
+
2989
+ RECORD(c, type, bang, record);
2990
+ return make_result(c, record);
2991
+ }
2992
+
2993
+ /*
2994
+ * Provides the Array-like functionality for scroll cursors when using the
2995
+ * cursor[start, length] syntax
2996
+ */
2997
+ static VALUE
2998
+ scrollcur_subseq(VALUE self, VALUE start, VALUE length, VALUE type)
2999
+ {
3000
+ cursor_t *c;
3001
+ struct sqlda *output;
3002
+ VALUE first, records;
3003
+ /*
3004
+ * EXEC SQL begin declare section;
3005
+ */
3006
+ #line 2236 "informix.ec"
3007
+ #line 2237 "informix.ec"
3008
+ char *cid, *did;
3009
+ long pos;
3010
+ /*
3011
+ * EXEC SQL end declare section;
3012
+ */
3013
+ #line 2239 "informix.ec"
3014
+
3015
+
3016
+ first = scrollcur_entry(self, start, type, 0);
3017
+ if (NIL_P(first))
3018
+ return Qnil;
3019
+
3020
+ pos = NUM2LONG(length) - 1;
3021
+
3022
+ if (pos > 0) {
3023
+ length = LONG2NUM(pos);
3024
+ records = fetch_many(self, length, type);
3025
+ }
3026
+ else
3027
+ records = rb_ary_new();
3028
+
3029
+ rb_ary_unshift(records, first);
3030
+
3031
+ return records;
3032
+ }
3033
+
3034
+ /*
3035
+ * Base function for slice and slice_hash methods
3036
+ */
3037
+ static VALUE
3038
+ slice(int argc, VALUE *argv, VALUE self, VALUE type)
3039
+ {
3040
+ if (argc == 2) {
3041
+ if (NUM2LONG(argv[1]) <= 0)
3042
+ rb_raise(rb_eArgError, "length must be positive");
3043
+ return scrollcur_subseq(self, argv[0], argv[1], type);
3044
+ }
3045
+ if (argc != 1)
3046
+ rb_scan_args(argc, argv, "11", 0, 0);
3047
+
3048
+ return scrollcur_entry(self, argv[0], type, 0);
3049
+ }
3050
+
3051
+ /*
3052
+ * call-seq:
3053
+ * cursor[index] => array or nil
3054
+ * cursor[start, length] => array or nil
3055
+ * cursor.slice(index) => array or nil
3056
+ * cursor.slice(start, length) => array or nil
3057
+ *
3058
+ * Returns the record at _index_, or returns a subarray starting at _start_
3059
+ * and continuing for _length_ records. Negative indices count backward from
3060
+ * the end of the cursor (-1 is the last element). Returns nil if the
3061
+ * (starting) index is out of range.
3062
+ *
3063
+ * <b>Warning</b>: if the (starting) index is negative and out of range, the
3064
+ * position in the cursor is set to the last record. Otherwise the current
3065
+ * position in the cursor is preserved.
3066
+ */
3067
+ static VALUE
3068
+ scrollcur_slice(int argc, VALUE *argv, VALUE self)
3069
+ {
3070
+ return slice(argc, argv, self, T_ARRAY);
3071
+ }
3072
+
3073
+ /*
3074
+ * call-seq:
3075
+ * cursor.slice!(index) => array or nil
3076
+ *
3077
+ * Returns the record at _index_. Negative indices count backward from
3078
+ * the end of the cursor (-1 is the last element). Returns nil if the index
3079
+ * is out of range.
3080
+ *
3081
+ * Stores the record fetched always in the same Array object.
3082
+ *
3083
+ * <b>Warning</b>: if the index is negative and out of range, the
3084
+ * position in the cursor is set to the last record. Otherwise the current
3085
+ * position in the cursor is preserved.
3086
+ */
3087
+ static VALUE
3088
+ scrollcur_slice_bang(VALUE self, VALUE index)
3089
+ {
3090
+ return scrollcur_entry(self, index, T_ARRAY, 1);
3091
+ }
3092
+
3093
+ /*
3094
+ * call-seq:
3095
+ * cursor.slice_hash(index) => hash or nil
3096
+ * cursor.slice_hash(start, length) => array or nil
3097
+ *
3098
+ * Returns the record at _index_, or returns a subarray starting at _start_
3099
+ * and continuing for _length_ records. Negative indices count backward from
3100
+ * the end of the cursor (-1 is the last element). Returns nil if the
3101
+ * (starting) index is out of range.
3102
+ *
3103
+ * <b>Warning</b>: if the (starting) index is negative and out of range, the
3104
+ * position in the cursor is set to the last record. Otherwise the current
3105
+ * position in the cursor is preserved.
3106
+ */
3107
+ static VALUE
3108
+ scrollcur_slice_hash(int argc, VALUE *argv, VALUE self)
3109
+ {
3110
+ return slice(argc, argv, self, T_HASH);
3111
+ }
3112
+
3113
+ /*
3114
+ * call-seq:
3115
+ * cursor.slice_hash!(index) => hash or nil
3116
+ *
3117
+ * Returns the record at _index_. Negative indices count backward from
3118
+ * the end of the cursor (-1 is the last element). Returns nil if the index
3119
+ * is out of range.
3120
+ *
3121
+ * Stores the record fetched always in the same Hash object.
3122
+ *
3123
+ * <b>Warning</b>: if the index is negative and out of range, the
3124
+ * position in the cursor is set to the last record. Otherwise the current
3125
+ * position in the cursor is preserved.
3126
+ */
3127
+ static VALUE
3128
+ scrollcur_slice_hash_bang(VALUE self, VALUE index)
3129
+ {
3130
+ return scrollcur_entry(self, index, T_HASH, 1);
3131
+ }
3132
+
3133
+ /*
3134
+ * Base function for prev* and next* methods
3135
+ */
3136
+ static VALUE
3137
+ scrollcur_rel(int argc, VALUE *argv, VALUE self, int dir, VALUE type, int bang)
3138
+ {
3139
+ cursor_t *c;
3140
+ struct sqlda *output;
3141
+ VALUE offset, record;
3142
+ /*
3143
+ * EXEC SQL begin declare section;
3144
+ */
3145
+ #line 2367 "informix.ec"
3146
+ #line 2368 "informix.ec"
3147
+ char *cid, *did;
3148
+ long pos;
3149
+ /*
3150
+ * EXEC SQL end declare section;
3151
+ */
3152
+ #line 2370 "informix.ec"
3153
+
3154
+
3155
+ Data_Get_Struct(self, cursor_t, c);
3156
+ if (!c->is_open)
3157
+ rb_raise(rb_eRuntimeError, "Open the cursor object first");
3158
+
3159
+ did = c->database_id;
3160
+ if (currentdid != did) {
3161
+ /*
3162
+ * EXEC SQL set connection :did;
3163
+ */
3164
+ #line 2378 "informix.ec"
3165
+ {
3166
+ #line 2378 "informix.ec"
3167
+ sqli_connect_set(0, did, 0);
3168
+ #line 2378 "informix.ec"
3169
+ }
3170
+ if (SQLCODE < 0)
3171
+ return Qnil;
3172
+ currentdid = did;
3173
+ }
3174
+
3175
+ rb_scan_args(argc, argv, "01", &offset);
3176
+ pos = dir*(NIL_P(offset)? 1: NUM2LONG(offset));
3177
+
3178
+ output = c->daOutput;
3179
+ cid = c->cursor_id;
3180
+ /*
3181
+ * EXEC SQL fetch relative :pos :cid using descriptor output;
3182
+ */
3183
+ #line 2389 "informix.ec"
3184
+ {
3185
+ #line 2389 "informix.ec"
3186
+ static ifx_sqlvar_t _sqibind[] =
3187
+ {
3188
+ { 103, sizeof(pos), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
3189
+ #line 2389 "informix.ec"
3190
+ };
3191
+ static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
3192
+ static _FetchSpec _FS1 = { 0, 7, 0 };
3193
+ #line 2389 "informix.ec"
3194
+ _sqibind[0].sqldata = (char *) &pos;
3195
+ sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), &_SD0, output, (char *)0, &_FS1);
3196
+ #line 2389 "informix.ec"
3197
+ }
3198
+
3199
+ if (SQLCODE == SQLNOTFOUND)
3200
+ return Qnil;
3201
+
3202
+ if (SQLCODE < 0)
3203
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
3204
+
3205
+ RECORD(c, type, bang, record);
3206
+ return make_result(c, record);
3207
+ }
3208
+
3209
+ /* call-seq:
3210
+ * cursor.prev(offset = 1) => array or nil
3211
+ *
3212
+ * Returns the previous _offset_ th record. Negative indices count
3213
+ * forward from the current position. Returns nil if the _offset_ is out of
3214
+ * range.
3215
+ */
3216
+ static VALUE
3217
+ scrollcur_prev(int argc, VALUE *argv, VALUE self)
3218
+ {
3219
+ return scrollcur_rel(argc, argv, self, -1, T_ARRAY, 0);
3220
+ }
3221
+
3222
+ /* call-seq:
3223
+ * cursor.prev!(offset = 1) => array or nil
3224
+ *
3225
+ * Returns the previous _offset_ th record. Negative indices count
3226
+ * forward from the current position. Returns nil if the _offset_ is out of
3227
+ * range.
3228
+ *
3229
+ * Stores the record fetched always in the same Array object.
3230
+ */
3231
+ static VALUE
3232
+ scrollcur_prev_bang(int argc, VALUE *argv, VALUE self)
3233
+ {
3234
+ return scrollcur_rel(argc, argv, self, -1, T_ARRAY, 1);
3235
+ }
3236
+
3237
+ /* call-seq:
3238
+ * cursor.prev_hash(offset = 1) => hash or nil
3239
+ *
3240
+ * Returns the previous _offset_ th record. Negative indices count
3241
+ * forward from the current position. Returns nil if the _offset_ is out of
3242
+ * range.
3243
+ */
3244
+ static VALUE
3245
+ scrollcur_prev_hash(int argc, VALUE *argv, VALUE self)
3246
+ {
3247
+ return scrollcur_rel(argc, argv, self, -1, T_HASH, 0);
3248
+ }
3249
+
3250
+ /* call-seq:
3251
+ * cursor.prev_hash!(offset = 1) => hash or nil
3252
+ *
3253
+ * Returns the previous _offset_ th record. Negative indices count
3254
+ * forward from the current position. Returns nil if the _offset_ is out of
3255
+ * range.
3256
+ *
3257
+ * Stores the record fetched always in the same Hash object.
3258
+ */
3259
+ static VALUE
3260
+ scrollcur_prev_hash_bang(int argc, VALUE *argv, VALUE self)
3261
+ {
3262
+ return scrollcur_rel(argc, argv, self, -1, T_HASH, 1);
3263
+ }
3264
+
3265
+ /* call-seq:
3266
+ * cursor.next(offset = 1) => array or nil
3267
+ *
3268
+ * Returns the next _offset_ th record. Negative indices count
3269
+ * backward from the current position. Returns nil if the _offset_ is out of
3270
+ * range.
3271
+ */
3272
+ static VALUE
3273
+ scrollcur_next(int argc, VALUE *argv, VALUE self)
3274
+ {
3275
+ return scrollcur_rel(argc, argv, self, 1, T_ARRAY, 0);
3276
+ }
3277
+
3278
+ /* call-seq:
3279
+ * cursor.next!(offset = 1) => array or nil
3280
+ *
3281
+ * Returns the next _offset_ th record. Negative indices count
3282
+ * backward from the current position. Returns nil if the _offset_ is out of
3283
+ * range.
3284
+ *
3285
+ * Stores the record fetched always in the same Array object.
3286
+ */
3287
+ static VALUE
3288
+ scrollcur_next_bang(int argc, VALUE *argv, VALUE self)
3289
+ {
3290
+ return scrollcur_rel(argc, argv, self, 1, T_ARRAY, 1);
3291
+ }
3292
+
3293
+ /* call-seq:
3294
+ * cursor.next_hash(offset = 1) => hash or nil
3295
+ *
3296
+ * Returns the next _offset_ th record. Negative indices count
3297
+ * backward from the current position. Returns nil if the _offset_ is out of
3298
+ * range.
3299
+ */
3300
+ static VALUE
3301
+ scrollcur_next_hash(int argc, VALUE *argv, VALUE self)
3302
+ {
3303
+ return scrollcur_rel(argc, argv, self, 1, T_HASH, 0);
3304
+ }
3305
+
3306
+ /* call-seq:
3307
+ * cursor.next_hash!(offset = 1) => hash or nil
3308
+ *
3309
+ * Returns the next _offset_ th record. Negative indices count
3310
+ * backward from the current position. Returns nil if the _offset_ is out of
3311
+ * range.
3312
+ *
3313
+ * Stores the record fetched always in the same Hash object.
3314
+ */
3315
+ static VALUE
3316
+ scrollcur_next_hash_bang(int argc, VALUE *argv, VALUE self)
3317
+ {
3318
+ return scrollcur_rel(argc, argv, self, 1, T_HASH, 1);
3319
+ }
3320
+
3321
+ /*
3322
+ * call-seq:
3323
+ * cursor.first => array or nil
3324
+ *
3325
+ * Returns the first record of the cursor. If the cursor is empty,
3326
+ * returns nil.
3327
+ */
3328
+ static VALUE
3329
+ scrollcur_first(VALUE self)
3330
+ {
3331
+ return scrollcur_entry(self, INT2FIX(0), T_ARRAY, 0);
3332
+ }
3333
+
3334
+ /*
3335
+ * call-seq:
3336
+ * cursor.first! => array or nil
3337
+ *
3338
+ * Returns the first record of the cursor. If the cursor is empty,
3339
+ * returns nil.
3340
+ *
3341
+ * Stores the record fetched always in the same Array object.
3342
+ */
3343
+ static VALUE
3344
+ scrollcur_first_bang(VALUE self)
3345
+ {
3346
+ return scrollcur_entry(self, INT2FIX(0), T_ARRAY, 1);
3347
+ }
3348
+
3349
+ /*
3350
+ * call-seq:
3351
+ * cursor.first_hash => hash or nil
3352
+ *
3353
+ * Returns the first record of the cursor. If the cursor is empty,
3354
+ * returns nil.
3355
+ */
3356
+ static VALUE
3357
+ scrollcur_first_hash(VALUE self)
3358
+ {
3359
+ return scrollcur_entry(self, INT2FIX(0), T_HASH, 0);
3360
+ }
3361
+
3362
+ /*
3363
+ * call-seq:
3364
+ * cursor.first_hash! => hash or nil
3365
+ *
3366
+ * Returns the first record of the cursor. If the cursor is empty,
3367
+ * returns nil.
3368
+ *
3369
+ * Stores the record fetched always in the same Hash object.
3370
+ */
3371
+ static VALUE
3372
+ scrollcur_first_hash_bang(VALUE self)
3373
+ {
3374
+ return scrollcur_entry(self, INT2FIX(0), T_HASH, 1);
3375
+ }
3376
+
3377
+ /*
3378
+ * call-seq:
3379
+ * cursor.last => array or nil
3380
+ *
3381
+ * Returns the last record of the cursor. If the cursor is empty,
3382
+ * returns nil.
3383
+ */
3384
+ static VALUE
3385
+ scrollcur_last(VALUE self)
3386
+ {
3387
+ return scrollcur_entry(self, INT2FIX(-1), T_ARRAY, 0);
3388
+ }
3389
+
3390
+ /*
3391
+ * call-seq:
3392
+ * cursor.last! => array or nil
3393
+ *
3394
+ * Returns the last record of the cursor. If the cursor is empty,
3395
+ * returns nil.
3396
+ *
3397
+ * Stores the record fetched always in the same Array object.
3398
+ */
3399
+ static VALUE
3400
+ scrollcur_last_bang(VALUE self)
3401
+ {
3402
+ return scrollcur_entry(self, INT2FIX(-1), T_ARRAY, 1);
3403
+ }
3404
+
3405
+ /*
3406
+ * call-seq:
3407
+ * cursor.last_hash => hash or nil
3408
+ *
3409
+ * Returns the last record of the cursor. If the cursor is empty,
3410
+ * returns nil.
3411
+ */
3412
+ static VALUE
3413
+ scrollcur_last_hash(VALUE self)
3414
+ {
3415
+ return scrollcur_entry(self, INT2FIX(-1), T_HASH, 0);
3416
+ }
3417
+
3418
+ /*
3419
+ * call-seq:
3420
+ * cursor.last_hash! => hash or nil
3421
+ *
3422
+ * Returns the last record of the cursor. If the cursor is empty,
3423
+ * returns nil.
3424
+ *
3425
+ * Stores the record fetched always in the same Hash object.
3426
+ */
3427
+ static VALUE
3428
+ scrollcur_last_hash_bang(VALUE self)
3429
+ {
3430
+ return scrollcur_entry(self, INT2FIX(-1), T_HASH, 1);
3431
+ }
3432
+
3433
+ /*
3434
+ * call-seq:
3435
+ * cursor.current => array or nil
3436
+ *
3437
+ * Returns the current record of the cursor. If the cursor is empty,
3438
+ * returns nil.
3439
+ */
3440
+ static VALUE
3441
+ scrollcur_current(VALUE self)
3442
+ {
3443
+ return scrollcur_entry(self, Qnil, T_ARRAY, 0);
3444
+ }
3445
+
3446
+ /*
3447
+ * call-seq:
3448
+ * cursor.current! => array or nil
3449
+ *
3450
+ * Returns the current record of the cursor. If the cursor is empty,
3451
+ * returns nil.
3452
+ *
3453
+ * Stores the record fetched always in the same Array object.
3454
+ */
3455
+ static VALUE
3456
+ scrollcur_current_bang(VALUE self)
3457
+ {
3458
+ return scrollcur_entry(self, Qnil, T_ARRAY, 1);
3459
+ }
3460
+
3461
+ /*
3462
+ * call-seq:
3463
+ * cursor.current_hash => hash or nil
3464
+ *
3465
+ * Returns the current record of the cursor. If the cursor is empty,
3466
+ * returns nil.
3467
+ */
3468
+ static VALUE
3469
+ scrollcur_current_hash(VALUE self)
3470
+ {
3471
+ return scrollcur_entry(self, Qnil, T_HASH, 0);
3472
+ }
3473
+
3474
+ /*
3475
+ * call-seq:
3476
+ * cursor.current_hash! => hash or nil
3477
+ *
3478
+ * Returns the current record of the cursor. If the cursor is empty,
3479
+ * returns nil.
3480
+ *
3481
+ * Stores the record fetched always in the same Hash object.
3482
+ */
3483
+ static VALUE
3484
+ scrollcur_current_hash_bang(VALUE self)
3485
+ {
3486
+ return scrollcur_entry(self, Qnil, T_HASH, 1);
3487
+ }
3488
+
3489
+ /* class Cursor ---------------------------------------------------------- */
3490
+ static void
3491
+ cursor_close_or_free(cursor_t *c, short op)
3492
+ {
3493
+ /*
3494
+ * EXEC SQL begin declare section;
3495
+ */
3496
+ #line 2685 "informix.ec"
3497
+ #line 2686 "informix.ec"
3498
+ char *cid, *sid, *did;
3499
+ /*
3500
+ * EXEC SQL end declare section;
3501
+ */
3502
+ #line 2687 "informix.ec"
3503
+
3504
+
3505
+ if (op == 1 && !c->is_open)
3506
+ return;
3507
+
3508
+ c->is_open = 0;
3509
+ if (op == 1)
3510
+ clean_input_slots(c);
3511
+ else {
3512
+ free_input_slots(c);
3513
+ free_output_slots(c);
3514
+ }
3515
+
3516
+ did = c->database_id;
3517
+ if (currentdid != did) {
3518
+ /*
3519
+ * EXEC SQL set connection :did;
3520
+ */
3521
+ #line 2702 "informix.ec"
3522
+ {
3523
+ #line 2702 "informix.ec"
3524
+ sqli_connect_set(0, did, 0);
3525
+ #line 2702 "informix.ec"
3526
+ }
3527
+ if (SQLCODE < 0)
3528
+ return;
3529
+ currentdid = did;
3530
+ }
3531
+
3532
+ cid = c->cursor_id;
3533
+ /*
3534
+ * EXEC SQL close :cid;
3535
+ */
3536
+ #line 2709 "informix.ec"
3537
+ {
3538
+ #line 2709 "informix.ec"
3539
+ sqli_curs_close(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256));
3540
+ #line 2709 "informix.ec"
3541
+ }
3542
+
3543
+ if (op == 2) {
3544
+ sid = c->stmt_id;
3545
+ /*
3546
+ * EXEC SQL free :cid;
3547
+ */
3548
+ #line 2713 "informix.ec"
3549
+ {
3550
+ #line 2713 "informix.ec"
3551
+ sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 258));
3552
+ #line 2713 "informix.ec"
3553
+ }
3554
+ /*
3555
+ * EXEC SQL free :sid;
3556
+ */
3557
+ #line 2713 "informix.ec"
3558
+ {
3559
+ #line 2713 "informix.ec"
3560
+ sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 258));
3561
+ #line 2713 "informix.ec"
3562
+ }
3563
+ }
3564
+ }
3565
+
3566
+ static void
3567
+ cursor_mark(cursor_t *c)
3568
+ {
3569
+ rb_gc_mark(c->db);
3570
+ if (c->array)
3571
+ rb_gc_mark(c->array);
3572
+ if (c->hash)
3573
+ rb_gc_mark(c->hash);
3574
+ if (c->field_names)
3575
+ rb_gc_mark(c->field_names);
3576
+ }
3577
+
3578
+ static void
3579
+ cursor_free(void *p)
3580
+ {
3581
+ cursor_close_or_free(p, 2);
3582
+ xfree(p);
3583
+ }
3584
+
3585
+ static VALUE
3586
+ cursor_alloc(VALUE klass)
3587
+ {
3588
+ cursor_t *c;
3589
+
3590
+ c = ALLOC(cursor_t);
3591
+ memset(c, 0, sizeof(cursor_t));
3592
+ return Data_Wrap_Struct(klass, cursor_mark, cursor_free, c);
3593
+ }
3594
+
3595
+ /*
3596
+ * call-seq:
3597
+ * Cursor.new(database, query, options) => cursor
3598
+ *
3599
+ * Prepares <i>query</i> in the context of <i>database</i> with <i>options</i>
3600
+ * and returns a <code>Cursor</code> object.
3601
+ *
3602
+ * <i>options</i> can be nil or a hash with the following possible keys:
3603
+ *
3604
+ * :scroll => true or false
3605
+ * :hold => true or false
3606
+ */
3607
+ static VALUE
3608
+ cursor_initialize(VALUE self, VALUE db, VALUE query, VALUE options)
3609
+ {
3610
+ VALUE scroll, hold;
3611
+ struct sqlda *output;
3612
+ cursor_t *c;
3613
+ /*
3614
+ * EXEC SQL begin declare section;
3615
+ */
3616
+ #line 2764 "informix.ec"
3617
+ #line 2765 "informix.ec"
3618
+ char *c_query;
3619
+ char *cid, *sid, *did;
3620
+ /*
3621
+ * EXEC SQL end declare section;
3622
+ */
3623
+ #line 2767 "informix.ec"
3624
+
3625
+
3626
+ Data_Get_Struct(db, char, did);
3627
+
3628
+ if (currentdid != did) {
3629
+ /*
3630
+ * EXEC SQL set connection :did;
3631
+ */
3632
+ #line 2772 "informix.ec"
3633
+ {
3634
+ #line 2772 "informix.ec"
3635
+ sqli_connect_set(0, did, 0);
3636
+ #line 2772 "informix.ec"
3637
+ }
3638
+ if (SQLCODE < 0)
3639
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
3640
+ currentdid = did;
3641
+ }
3642
+
3643
+ Data_Get_Struct(self, cursor_t, c);
3644
+ c->db = db;
3645
+ c->database_id = did;
3646
+ scroll = hold = Qfalse;
3647
+ snprintf(c->cursor_id, sizeof(c->cursor_id), "CUR%lX", self);
3648
+ snprintf(c->stmt_id, sizeof(c->stmt_id), "STMT%lX", self);
3649
+ cid = c->cursor_id; sid = c->stmt_id;
3650
+ c_query = StringValueCStr(query);
3651
+
3652
+ if (RTEST(options)) {
3653
+ scroll = rb_hash_aref(options, sym_scroll);
3654
+ hold = rb_hash_aref(options, sym_hold);
3655
+ }
3656
+
3657
+ /*
3658
+ * EXEC SQL prepare :sid from :c_query;
3659
+ */
3660
+ #line 2792 "informix.ec"
3661
+ {
3662
+ #line 2792 "informix.ec"
3663
+ sqli_prep(ESQLINTVERSION, sid, c_query,(ifx_literal_t *)0, (ifx_namelist_t *)0, -1, 0, 0 );
3664
+ #line 2792 "informix.ec"
3665
+ }
3666
+ if (SQLCODE < 0)
3667
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
3668
+
3669
+ if (RTEST(scroll) && RTEST(hold))
3670
+ /*
3671
+ * EXEC SQL declare :cid scroll cursor with hold for :sid;
3672
+ */
3673
+ #line 2797 "informix.ec"
3674
+ {
3675
+ #line 2797 "informix.ec"
3676
+ sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 0), cid, sqli_curs_locate(ESQLINTVERSION, sid, 1), 4128, 0);
3677
+ #line 2797 "informix.ec"
3678
+ }
3679
+ else if (RTEST(hold))
3680
+ /*
3681
+ * EXEC SQL declare :cid cursor with hold for :sid;
3682
+ */
3683
+ #line 2799 "informix.ec"
3684
+ {
3685
+ #line 2799 "informix.ec"
3686
+ sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 0), cid, sqli_curs_locate(ESQLINTVERSION, sid, 1), 4096, 0);
3687
+ #line 2799 "informix.ec"
3688
+ }
3689
+ else if (RTEST(scroll))
3690
+ /*
3691
+ * EXEC SQL declare :cid scroll cursor for :sid;
3692
+ */
3693
+ #line 2801 "informix.ec"
3694
+ {
3695
+ #line 2801 "informix.ec"
3696
+ sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 0), cid, sqli_curs_locate(ESQLINTVERSION, sid, 1), 32, 0);
3697
+ #line 2801 "informix.ec"
3698
+ }
3699
+ else
3700
+ /*
3701
+ * EXEC SQL declare :cid cursor for :sid;
3702
+ */
3703
+ #line 2803 "informix.ec"
3704
+ {
3705
+ #line 2803 "informix.ec"
3706
+ sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 0), cid, sqli_curs_locate(ESQLINTVERSION, sid, 1), 0, 0);
3707
+ #line 2803 "informix.ec"
3708
+ }
3709
+
3710
+ if (SQLCODE < 0)
3711
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
3712
+
3713
+ alloc_input_slots(c, c_query);
3714
+ /*
3715
+ * EXEC SQL describe :sid into output;
3716
+ */
3717
+ #line 2809 "informix.ec"
3718
+ {
3719
+ #line 2809 "informix.ec"
3720
+ sqli_describe_stmt(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sid, 257), &output, 0);
3721
+ #line 2809 "informix.ec"
3722
+ }
3723
+ c->daOutput = output;
3724
+
3725
+ c->is_select = (SQLCODE == 0 || SQLCODE == SQ_EXECPROC);
3726
+
3727
+ if (c->is_select) {
3728
+ alloc_output_slots(c);
3729
+ rb_extend_object(self, rb_mSequentialCursor);
3730
+ if (scroll)
3731
+ rb_extend_object(self, rb_mScrollCursor);
3732
+ }
3733
+ else {
3734
+ xfree(c->daOutput);
3735
+ c->daOutput = NULL;
3736
+ rb_extend_object(self, rb_mInsertCursor);
3737
+ }
3738
+ return self;
3739
+ }
3740
+
3741
+ /*
3742
+ * call-seq:
3743
+ * cursor.id => string
3744
+ *
3745
+ * Returns the cursor ID
3746
+ */
3747
+ static VALUE
3748
+ cursor_id(VALUE self)
3749
+ {
3750
+ cursor_t *c;
3751
+
3752
+ Data_Get_Struct(self, cursor_t, c);
3753
+ return rb_str_new2(c->cursor_id);
3754
+ }
3755
+
3756
+ /*
3757
+ * call-seq:
3758
+ * cursor.open(*params) => cursor
3759
+ *
3760
+ * Executes the previously prepared select statement, binding <i>params</i> as
3761
+ * input parameters.
3762
+ *
3763
+ * Returns __self__.
3764
+ */
3765
+ static VALUE
3766
+ cursor_open(int argc, VALUE *argv, VALUE self)
3767
+ {
3768
+ struct sqlda *input;
3769
+ cursor_t *c;
3770
+ /*
3771
+ * EXEC SQL begin declare section;
3772
+ */
3773
+ #line 2857 "informix.ec"
3774
+ #line 2858 "informix.ec"
3775
+ char *cid, *did;
3776
+ /*
3777
+ * EXEC SQL end declare section;
3778
+ */
3779
+ #line 2859 "informix.ec"
3780
+
3781
+
3782
+ Data_Get_Struct(self, cursor_t, c);
3783
+
3784
+ if (c->is_open)
3785
+ return self;
3786
+
3787
+ did = c->database_id;
3788
+ if (currentdid != did) {
3789
+ /*
3790
+ * EXEC SQL set connection :did;
3791
+ */
3792
+ #line 2868 "informix.ec"
3793
+ {
3794
+ #line 2868 "informix.ec"
3795
+ sqli_connect_set(0, did, 0);
3796
+ #line 2868 "informix.ec"
3797
+ }
3798
+ if (SQLCODE < 0)
3799
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
3800
+ currentdid = did;
3801
+ }
3802
+
3803
+ input = &c->daInput;
3804
+ cid = c->cursor_id;
3805
+
3806
+ if (c->is_select) {
3807
+ if (argc != input->sqld) {
3808
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
3809
+ argc, input->sqld);
3810
+ }
3811
+ if (argc) {
3812
+ bind_input_params(c, argv);
3813
+ /*
3814
+ * EXEC SQL open :cid using descriptor input
3815
+ * with reoptimization;
3816
+ */
3817
+ #line 2884 "informix.ec"
3818
+ {
3819
+ #line 2885 "informix.ec"
3820
+ sqli_curs_open(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), input, (char *)0, (struct value *)0, 1, 1);
3821
+ #line 2885 "informix.ec"
3822
+ }
3823
+ clean_input_slots(c);
3824
+ }
3825
+ else
3826
+ /*
3827
+ * EXEC SQL open :cid with reoptimization;
3828
+ */
3829
+ #line 2889 "informix.ec"
3830
+ {
3831
+ #line 2889 "informix.ec"
3832
+ sqli_curs_open(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0, 1);
3833
+ #line 2889 "informix.ec"
3834
+ }
3835
+ }
3836
+ else
3837
+ /*
3838
+ * EXEC SQL open :cid;
3839
+ */
3840
+ #line 2892 "informix.ec"
3841
+ {
3842
+ #line 2892 "informix.ec"
3843
+ sqli_curs_open(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, cid, 256), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0, 0);
3844
+ #line 2892 "informix.ec"
3845
+ }
3846
+
3847
+ if (SQLCODE < 0)
3848
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
3849
+
3850
+ c->is_open = 1;
3851
+ return self;
3852
+ }
3853
+
3854
+ /*
3855
+ * call-seq:
3856
+ * cursor.close => cursor
3857
+ *
3858
+ * Closes the cursor and returns __self__.
3859
+ */
3860
+ static VALUE
3861
+ cursor_close(VALUE self)
3862
+ {
3863
+ cursor_t *c;
3864
+
3865
+ Data_Get_Struct(self, cursor_t, c);
3866
+ cursor_close_or_free(c, 1);
3867
+ return self;
3868
+ }
3869
+
3870
+ /*
3871
+ * call-seq:
3872
+ * cursor.drop => nil
3873
+ *
3874
+ * Closes the cursor and frees the memory associated with it. The cursor
3875
+ * cannot be opened again.
3876
+ */
3877
+ static VALUE
3878
+ cursor_drop(VALUE self)
3879
+ {
3880
+ cursor_t *c;
3881
+
3882
+ Data_Get_Struct(self, cursor_t, c);
3883
+ cursor_close_or_free(c, 2);
3884
+
3885
+ return Qnil;
3886
+ }
3887
+
3888
+ /* Entry point ------------------------------------------------------------ */
3889
+
3890
+ void Init_informix(void)
3891
+ {
3892
+ /* module Informix ---------------------------------------------------- */
3893
+ rb_mInformix = rb_define_module("Informix");
3894
+ rb_mScrollCursor = rb_define_module_under(rb_mInformix, "ScrollCursor");
3895
+ rb_mInsertCursor = rb_define_module_under(rb_mInformix, "InsertCursor");
3896
+ rb_define_module_function(rb_mInformix, "connect", informix_connect, -1);
3897
+
3898
+ /* class Slob --------------------------------------------------------- */
3899
+ rb_cSlob = rb_define_class_under(rb_mInformix, "Slob", rb_cObject);
3900
+ rb_define_alloc_func(rb_cSlob, slob_alloc);
3901
+ rb_define_method(rb_cSlob, "initialize", slob_initialize, -1);
3902
+ rb_define_method(rb_cSlob, "open", slob_open, -1);
3903
+ rb_define_method(rb_cSlob, "close", slob_close, 0);
3904
+ rb_define_method(rb_cSlob, "read", slob_read, 1);
3905
+ rb_define_method(rb_cSlob, "write", slob_write, 1);
3906
+ rb_define_method(rb_cSlob, "seek", slob_seek, 2);
3907
+ rb_define_method(rb_cSlob, "tell", slob_tell, 0);
3908
+ rb_define_method(rb_cSlob, "truncate", slob_truncate, 1);
3909
+
3910
+ rb_define_const(rb_cSlob, "CLOB", INT2FIX(XID_CLOB));
3911
+ rb_define_const(rb_cSlob, "BLOB", INT2FIX(XID_BLOB));
3912
+
3913
+ #define DEF_SLOB_CONST(k) rb_define_const(rb_cSlob, #k, INT2FIX(LO_##k))
3914
+
3915
+ DEF_SLOB_CONST(RDONLY);
3916
+ DEF_SLOB_CONST(DIRTY_READ);
3917
+ DEF_SLOB_CONST(WRONLY);
3918
+ DEF_SLOB_CONST(APPEND);
3919
+ DEF_SLOB_CONST(RDWR);
3920
+ DEF_SLOB_CONST(BUFFER);
3921
+ DEF_SLOB_CONST(NOBUFFER);
3922
+ DEF_SLOB_CONST(LOCKALL);
3923
+ DEF_SLOB_CONST(LOCKRANGE);
3924
+ DEF_SLOB_CONST(SEEK_SET);
3925
+ DEF_SLOB_CONST(SEEK_CUR);
3926
+ DEF_SLOB_CONST(SEEK_END);
3927
+
3928
+ /* class Database ----------------------------------------------------- */
3929
+ rb_cDatabase = rb_define_class_under(rb_mInformix, "Database", rb_cObject);
3930
+ rb_define_alloc_func(rb_cDatabase, database_alloc);
3931
+ rb_define_method(rb_cDatabase, "initialize", database_initialize, -1);
3932
+ rb_define_alias(rb_cDatabase, "open", "initialize");
3933
+ rb_define_method(rb_cDatabase, "close", database_close, 0);
3934
+ rb_define_method(rb_cDatabase, "immediate", database_immediate, 1);
3935
+ rb_define_alias(rb_cDatabase, "do", "immediate");
3936
+ rb_define_method(rb_cDatabase, "rollback", database_rollback, 0);
3937
+ rb_define_method(rb_cDatabase, "commit", database_commit, 0);
3938
+ rb_define_method(rb_cDatabase, "transaction", database_transaction, 0);
3939
+ rb_define_method(rb_cDatabase, "prepare", database_prepare, 1);
3940
+ rb_define_method(rb_cDatabase, "columns", database_columns, 1);
3941
+ rb_define_method(rb_cDatabase, "cursor", database_cursor, -1);
3942
+
3943
+ /* class Statement ---------------------------------------------------- */
3944
+ rb_cStatement = rb_define_class_under(rb_mInformix, "Statement", rb_cObject);
3945
+ rb_define_alloc_func(rb_cStatement, statement_alloc);
3946
+ rb_define_method(rb_cStatement, "initialize", statement_initialize, 2);
3947
+ rb_define_method(rb_cStatement, "[]", statement_call, -1);
3948
+ rb_define_alias(rb_cStatement, "call", "[]");
3949
+ rb_define_alias(rb_cStatement, "execute", "[]");
3950
+ rb_define_method(rb_cStatement, "drop", statement_drop, 0);
3951
+
3952
+ /* module SequentialCursor -------------------------------------------- */
3953
+ rb_mSequentialCursor = rb_define_module_under(rb_mInformix, "SequentialCursor");
3954
+ rb_define_method(rb_mSequentialCursor, "fetch", seqcur_fetch, 0);
3955
+ rb_define_method(rb_mSequentialCursor, "fetch!", seqcur_fetch_bang, 0);
3956
+ rb_define_method(rb_mSequentialCursor, "fetch_hash", seqcur_fetch_hash, 0);
3957
+ rb_define_method(rb_mSequentialCursor, "fetch_hash!", seqcur_fetch_hash_bang, 0);
3958
+ rb_define_method(rb_mSequentialCursor, "fetch_many", seqcur_fetch_many, 1);
3959
+ rb_define_method(rb_mSequentialCursor, "fetch_hash_many", seqcur_fetch_hash_many, 1);
3960
+ rb_define_method(rb_mSequentialCursor, "fetch_all", seqcur_fetch_all, 0);
3961
+ rb_define_method(rb_mSequentialCursor, "fetch_hash_all", seqcur_fetch_hash_all, 0);
3962
+ rb_define_method(rb_mSequentialCursor, "each", seqcur_each, 0);
3963
+ rb_define_method(rb_mSequentialCursor, "each!", seqcur_each_bang, 0);
3964
+ rb_define_method(rb_mSequentialCursor, "each_hash", seqcur_each_hash, 0);
3965
+ rb_define_method(rb_mSequentialCursor, "each_hash!", seqcur_each_hash_bang, 0);
3966
+ rb_define_method(rb_mSequentialCursor, "each_by", seqcur_each_by, 1);
3967
+ rb_define_method(rb_mSequentialCursor, "each_hash_by", seqcur_each_hash_by, 1);
3968
+
3969
+ /* InsertCursor ------------------------------------------------------- */
3970
+ rb_define_method(rb_mInsertCursor, "put", inscur_put, -1);
3971
+ rb_define_method(rb_mInsertCursor, "flush", inscur_flush, 0);
3972
+
3973
+ /* ScrollCursor ------------------------------------------------------- */
3974
+ rb_define_method(rb_mScrollCursor, "[]", scrollcur_slice, -1);
3975
+ rb_define_alias(rb_mScrollCursor, "slice", "[]");
3976
+ rb_define_method(rb_mScrollCursor, "slice!", scrollcur_slice_bang, 1);
3977
+ rb_define_method(rb_mScrollCursor, "slice_hash", scrollcur_slice_hash, -1);
3978
+ rb_define_method(rb_mScrollCursor, "slice_hash!", scrollcur_slice_hash_bang, 1);
3979
+ rb_define_method(rb_mScrollCursor, "prev", scrollcur_prev, -1);
3980
+ rb_define_method(rb_mScrollCursor, "prev!", scrollcur_prev_bang, -1);
3981
+ rb_define_method(rb_mScrollCursor, "prev_hash", scrollcur_prev_hash, -1);
3982
+ rb_define_method(rb_mScrollCursor, "prev_hash!", scrollcur_prev_hash_bang, -1);
3983
+ rb_define_method(rb_mScrollCursor, "next", scrollcur_next, -1);
3984
+ rb_define_method(rb_mScrollCursor, "next!", scrollcur_next_bang, -1);
3985
+ rb_define_method(rb_mScrollCursor, "next_hash", scrollcur_next_hash, -1);
3986
+ rb_define_method(rb_mScrollCursor, "next_hash!", scrollcur_next_hash_bang, -1);
3987
+ rb_define_method(rb_mScrollCursor, "first", scrollcur_first, 0);
3988
+ rb_define_method(rb_mScrollCursor, "first!", scrollcur_first_bang, 0);
3989
+ rb_define_method(rb_mScrollCursor, "first_hash", scrollcur_first_hash, 0);
3990
+ rb_define_method(rb_mScrollCursor, "first_hash!", scrollcur_first_hash_bang, 0);
3991
+ rb_define_method(rb_mScrollCursor, "last", scrollcur_last, 0);
3992
+ rb_define_method(rb_mScrollCursor, "last!", scrollcur_last_bang, 0);
3993
+ rb_define_method(rb_mScrollCursor, "last_hash", scrollcur_last_hash, 0);
3994
+ rb_define_method(rb_mScrollCursor, "last_hash!", scrollcur_last_hash_bang, 0);
3995
+ rb_define_method(rb_mScrollCursor, "current", scrollcur_current, 0);
3996
+ rb_define_method(rb_mScrollCursor, "current!", scrollcur_current_bang, 0);
3997
+ rb_define_method(rb_mScrollCursor, "current_hash", scrollcur_current_hash, 0);
3998
+ rb_define_method(rb_mScrollCursor, "current_hash!", scrollcur_current_hash_bang, 0);
3999
+
4000
+ /* class Cursor ------------------------------------------------------- */
4001
+ rb_cCursor = rb_define_class_under(rb_mInformix, "Cursor", rb_cObject);
4002
+ rb_define_alloc_func(rb_cCursor, cursor_alloc);
4003
+ rb_define_method(rb_cCursor, "initialize", cursor_initialize, 3);
4004
+ rb_define_method(rb_cCursor, "id", cursor_id, 0);
4005
+ rb_define_method(rb_cCursor, "open", cursor_open, -1);
4006
+ rb_define_method(rb_cCursor, "close", cursor_close, 0);
4007
+ rb_define_method(rb_cCursor, "drop", cursor_drop, 0);
4008
+
4009
+ /* Global constants --------------------------------------------------- */
4010
+ rb_require("date");
4011
+ rb_cDate = rb_const_get(rb_cObject, rb_intern("Date"));
4012
+
4013
+ /* Global symbols ----------------------------------------------------- */
4014
+ s_read = rb_intern("read");
4015
+ s_new = rb_intern("new");
4016
+ s_utc = rb_intern("utc");
4017
+ s_day = rb_intern("day");
4018
+ s_month = rb_intern("month");
4019
+ s_year = rb_intern("year");
4020
+ s_hour = rb_intern("hour");
4021
+ s_min = rb_intern("min");
4022
+ s_sec = rb_intern("sec");
4023
+ s_usec = rb_intern("usec");
4024
+ s_to_s = rb_intern("to_s");
4025
+ s_to_i = rb_intern("to_i");
4026
+
4027
+ sym_name = ID2SYM(rb_intern("name"));
4028
+ sym_type = ID2SYM(rb_intern("type"));
4029
+ sym_nullable = ID2SYM(rb_intern("nullable"));
4030
+ sym_stype = ID2SYM(rb_intern("stype"));
4031
+ sym_length = ID2SYM(rb_intern("length"));
4032
+ sym_precision = ID2SYM(rb_intern("precision"));
4033
+ sym_scale = ID2SYM(rb_intern("scale"));
4034
+ sym_default = ID2SYM(rb_intern("default"));
4035
+ sym_xid = ID2SYM(rb_intern("xid"));
4036
+
4037
+ sym_scroll = ID2SYM(rb_intern("scroll"));
4038
+ sym_hold = ID2SYM(rb_intern("hold"));
4039
+
4040
+ sym_col_info = ID2SYM(rb_intern("col_info"));
4041
+ sym_sbspace = ID2SYM(rb_intern("sbspace"));
4042
+ sym_estbytes = ID2SYM(rb_intern("estbytes"));
4043
+ sym_extsz = ID2SYM(rb_intern("extsz"));
4044
+ sym_createflags = ID2SYM(rb_intern("createflags"));
4045
+ sym_openflags = ID2SYM(rb_intern("openflags"));
4046
+ }
4047
+
4048
+ #line 3093 "informix.ec"