ruby-informix 0.4.0

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