ruby-informix 0.4.0 → 0.5.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 (5) hide show
  1. data/Changelog +37 -1
  2. data/README +4 -2
  3. data/informix.c +1606 -658
  4. data/informix.ec +1176 -323
  5. metadata +4 -3
data/informix.ec CHANGED
@@ -1,4 +1,4 @@
1
- /* $Id: informix.ec,v 1.56 2006/12/13 08:19:52 santana Exp $ */
1
+ /* $Id: informix.ec,v 1.81 2006/12/27 20:57:39 santana Exp $ */
2
2
  /*
3
3
  * Copyright (c) 2006, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
4
4
  * All rights reserved.
@@ -33,30 +33,30 @@
33
33
  #include <sqlstype.h>
34
34
  #include <sqltypes.h>
35
35
 
36
- static VALUE rb_cDate;
36
+ static VALUE rb_cDate, rb_cBigDecimal;
37
37
 
38
38
  static VALUE rb_mInformix;
39
39
  static VALUE rb_mSequentialCursor;
40
40
  static VALUE rb_mScrollCursor;
41
41
  static VALUE rb_mInsertCursor;
42
42
 
43
- static VALUE rb_cSlob;
43
+ static VALUE rb_cSlob, rb_cSlobStat;
44
44
  static VALUE rb_cDatabase;
45
45
  static VALUE rb_cStatement;
46
46
  static VALUE rb_cCursor;
47
47
 
48
48
  static ID s_read, s_new, s_utc, s_day, s_month, s_year;
49
49
  static ID s_hour, s_min, s_sec, s_usec, s_to_s, s_to_i;
50
+
50
51
  static VALUE sym_name, sym_type, sym_nullable, sym_stype, sym_length;
51
52
  static VALUE sym_precision, sym_scale, sym_default, sym_xid;
52
53
  static VALUE sym_scroll, sym_hold;
53
54
  static VALUE sym_col_info, sym_sbspace, sym_estbytes, sym_extsz;
54
- static VALUE sym_createflags, sym_openflags;
55
+ static VALUE sym_createflags, sym_openflags, sym_maxbytes;
56
+ static VALUE sym_params;
55
57
 
56
58
  #define IDSIZE 30
57
59
 
58
- static char *currentdid = NULL;
59
-
60
60
  typedef struct {
61
61
  short is_select, is_open;
62
62
  struct sqlda daInput, *daOutput;
@@ -77,6 +77,11 @@ typedef struct {
77
77
  char *database_id;
78
78
  } slob_t;
79
79
 
80
+ typedef struct {
81
+ mint atime, ctime, mtime, refcnt;
82
+ ifx_int8_t size;
83
+ } slobstat_t;
84
+
80
85
  #define NUM2INT8(num, int8addr) do { \
81
86
  VALUE str = rb_funcall(num, s_to_s, 0); \
82
87
  char *c_str = StringValueCStr(str); \
@@ -87,11 +92,185 @@ typedef struct {
87
92
 
88
93
  #define INT82NUM(int8addr, num) do { \
89
94
  char str[21]; \
90
- mint ret = ifx_int8toasc((int8addr), str, sizeof(str) - 1); \
95
+ ifx_int8toasc((int8addr), str, sizeof(str) - 1); \
91
96
  str[sizeof(str) - 1] = 0; \
92
97
  num = rb_cstr2inum(str, 10); \
93
98
  }while(0)
94
99
 
100
+ /* class Slob::Stat ------------------------------------------------------ */
101
+
102
+ static void
103
+ slobstat_free(slobstat_t *stat)
104
+ {
105
+ xfree(stat);
106
+ }
107
+
108
+ static VALUE
109
+ slobstat_alloc(VALUE klass)
110
+ {
111
+ slobstat_t *stat;
112
+
113
+ stat = ALLOC(slobstat_t);
114
+ return Data_Wrap_Struct(klass, 0, slobstat_free, stat);
115
+ }
116
+
117
+ /*
118
+ * call-seq:
119
+ * Slob::Stat.new(slob) => stat
120
+ *
121
+ * Creates an Slob::Stat object with status information for the given Slob
122
+ * object.
123
+ */
124
+ static VALUE
125
+ rb_slobstat_initialize(VALUE self, VALUE slob)
126
+ {
127
+ mint ret;
128
+ slob_t *sb;
129
+ slobstat_t *stat;
130
+ ifx_lo_stat_t *st;
131
+ EXEC SQL begin declare section;
132
+ char *did;
133
+ EXEC SQL end declare section;
134
+
135
+ Data_Get_Struct(slob, slob_t, sb);
136
+ Data_Get_Struct(self, slobstat_t, stat);
137
+
138
+ if (sb->fd == -1)
139
+ rb_raise(rb_eRuntimeError,
140
+ "Open the Slob object before getting its status");
141
+
142
+ did = sb->database_id;
143
+ EXEC SQL set connection :did;
144
+ if (SQLCODE < 0)
145
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
146
+
147
+ ret = ifx_lo_stat(sb->fd, &st);
148
+
149
+ if (ret < 0)
150
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
151
+
152
+ stat->atime = ifx_lo_stat_atime(st);
153
+ stat->ctime = ifx_lo_stat_ctime(st);
154
+ stat->mtime = ifx_lo_stat_mtime_sec(st);
155
+ stat->refcnt = ifx_lo_stat_refcnt(st);
156
+ ret = ifx_lo_stat_size(st, &stat->size);
157
+
158
+ ifx_lo_stat_free(st);
159
+
160
+ if (stat->atime == -1 || stat->ctime == -1 || stat->mtime == -1 ||
161
+ stat->refcnt == -1 || ret == -1) {
162
+ rb_raise(rb_eRuntimeError, "Unable to get status");
163
+ }
164
+
165
+ return self;
166
+ }
167
+
168
+ /*
169
+ * call-seq:
170
+ * stat <=> other_stat => -1, 0, 1
171
+ *
172
+ * Compares with another <code>Slob::Stat</code> object by comparing their
173
+ * modification times.
174
+ */
175
+ static VALUE
176
+ rb_slobstat_cmp(VALUE self, VALUE other)
177
+ {
178
+ if (rb_obj_is_kind_of(other, rb_obj_class(self))) {
179
+ slobstat_t *stat;
180
+ time_t t1, t2;
181
+
182
+ Data_Get_Struct(self, slobstat_t, stat); t1 = stat->mtime;
183
+ Data_Get_Struct(other, slobstat_t, stat); t2 = stat->mtime;
184
+
185
+ if (t1 == t2)
186
+ return INT2FIX(0);
187
+ else if (t1 < t2)
188
+ return INT2FIX(-1);
189
+ else
190
+ return INT2FIX(1);
191
+ }
192
+
193
+ return Qnil;
194
+ }
195
+
196
+ /*
197
+ * call-seq:
198
+ * stat.atime => time
199
+ *
200
+ * Returns the time of last access as a Time object.
201
+ */
202
+ static VALUE
203
+ rb_slobstat_atime(VALUE self)
204
+ {
205
+ slobstat_t *stat;
206
+
207
+ Data_Get_Struct(self, slobstat_t, stat);
208
+ return rb_time_new(stat->atime, 0);
209
+ }
210
+
211
+ /*
212
+ * call-seq:
213
+ * stat.ctime => time
214
+ *
215
+ * Returns the time of last change in status as a Time object.
216
+ */
217
+ static VALUE
218
+ rb_slobstat_ctime(VALUE self)
219
+ {
220
+ slobstat_t *stat;
221
+
222
+ Data_Get_Struct(self, slobstat_t, stat);
223
+ return rb_time_new(stat->ctime, 0);
224
+ }
225
+
226
+ /*
227
+ * call-seq:
228
+ * stat.mtime => time
229
+ *
230
+ * Returns the time of last modification as a Time object.
231
+ */
232
+ static VALUE
233
+ rb_slobstat_mtime(VALUE self)
234
+ {
235
+ slobstat_t *stat;
236
+
237
+ Data_Get_Struct(self, slobstat_t, stat);
238
+ return rb_time_new(stat->mtime, 0);
239
+ }
240
+
241
+ /*
242
+ * call-seq:
243
+ * stat.refcnt => fixnum
244
+ *
245
+ * Returns the number of references
246
+ */
247
+ static VALUE
248
+ rb_slobstat_refcnt(VALUE self)
249
+ {
250
+ slobstat_t *stat;
251
+
252
+ Data_Get_Struct(self, slobstat_t, stat);
253
+ return INT2FIX(stat->refcnt);
254
+ }
255
+
256
+ /*
257
+ * call-seq:
258
+ * stat.size => fixnum or bignum
259
+ *
260
+ * Returns the size in bytes
261
+ */
262
+ static VALUE
263
+ rb_slobstat_size(VALUE self)
264
+ {
265
+ slobstat_t *stat;
266
+ VALUE size;
267
+
268
+ Data_Get_Struct(self, slobstat_t, stat);
269
+ INT82NUM(&stat->size, size);
270
+
271
+ return size;
272
+ }
273
+
95
274
  /* class Slob ------------------------------------------------------------ */
96
275
 
97
276
  static void
@@ -109,16 +288,11 @@ slob_free(slob_t *slob)
109
288
  EXEC SQL end declare section;
110
289
 
111
290
  did = slob->database_id;
112
- if (currentdid != did) {
113
- EXEC SQL set connection :did;
114
- if (SQLCODE < 0)
115
- goto exit;
116
- currentdid = did;
117
- }
118
- ifx_lo_close(slob->fd);
291
+ EXEC SQL set connection :did;
292
+ if (SQLCODE >= 0)
293
+ ifx_lo_close(slob->fd);
119
294
  }
120
295
 
121
- exit:
122
296
  if (slob->spec)
123
297
  ifx_lo_spec_free(slob->spec);
124
298
 
@@ -133,14 +307,17 @@ slob_alloc(VALUE klass)
133
307
  slob = ALLOC(slob_t);
134
308
  slob->spec = NULL;
135
309
  slob->fd = -1;
310
+ slob->database_id = NULL;
136
311
  slob->type = XID_CLOB;
312
+ slob->db = 0;
137
313
 
138
314
  return Data_Wrap_Struct(klass, slob_mark, slob_free, slob);
139
315
  }
140
316
 
141
317
  /*
142
318
  * call-seq:
143
- * Slob.new(database, type = Slob::CLOB, options = nil) => slob
319
+ * Slob.new(database, type = Slob::CLOB, options = nil) => slob
320
+ * Slob.new(database, type = Slob::CLOB, options = nil) {|slob| block } => obj
144
321
  *
145
322
  * Creates a Smart Large Object of type <i>type</i> in <i>database</i>.
146
323
  * Returns a <code>Slob</code> object pointing to it.
@@ -159,7 +336,7 @@ slob_alloc(VALUE klass)
159
336
  * characteristics for the specified database column
160
337
  */
161
338
  static VALUE
162
- slob_initialize(int argc, VALUE *argv, VALUE self)
339
+ rb_slob_initialize(int argc, VALUE *argv, VALUE self)
163
340
  {
164
341
  mint ret, error;
165
342
  slob_t *slob;
@@ -172,18 +349,15 @@ slob_initialize(int argc, VALUE *argv, VALUE self)
172
349
  rb_scan_args(argc, argv, "12", &db, &type, &options);
173
350
  Data_Get_Struct(db, char, did);
174
351
 
175
- if (currentdid != did) {
176
- EXEC SQL set connection :did;
177
- if (SQLCODE < 0)
178
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
179
- currentdid = did;
180
- }
352
+ EXEC SQL set connection :did;
353
+ if (SQLCODE < 0)
354
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
181
355
 
182
356
  Data_Get_Struct(self, slob_t, slob);
183
357
  slob->db = db;
184
358
  slob->database_id = did;
185
359
 
186
- if (RTEST(type)) {
360
+ if (!NIL_P(type)) {
187
361
  int t = FIX2INT(type);
188
362
  if (t != XID_CLOB && t != XID_BLOB)
189
363
  rb_raise(rb_eRuntimeError, "Invalid type %d for an SLOB", t);
@@ -192,32 +366,34 @@ slob_initialize(int argc, VALUE *argv, VALUE self)
192
366
 
193
367
  col_info = sbspace = estbytes = extsz = createflags = openflags = maxbytes = Qnil;
194
368
 
195
- if (RTEST(options)) {
369
+ if (!NIL_P(options)) {
370
+ Check_Type(options, T_HASH);
196
371
  col_info = rb_hash_aref(options, sym_col_info);
197
372
  sbspace = rb_hash_aref(options, sym_sbspace);
198
373
  estbytes = rb_hash_aref(options, sym_estbytes);
199
374
  extsz = rb_hash_aref(options, sym_extsz);
200
375
  createflags = rb_hash_aref(options, sym_createflags);
201
376
  openflags = rb_hash_aref(options, sym_openflags);
377
+ maxbytes = rb_hash_aref(options, sym_maxbytes);
202
378
  }
203
379
 
204
380
  ret = ifx_lo_def_create_spec(&slob->spec);
205
381
  if (ret < 0)
206
382
  rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
207
383
 
208
- if (RTEST(col_info)) {
384
+ if (!NIL_P(col_info)) {
209
385
  ret = ifx_lo_col_info(StringValueCStr(col_info), slob->spec);
210
386
 
211
387
  if (ret < 0)
212
388
  rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
213
389
  }
214
- if (RTEST(sbspace)) {
390
+ if (!NIL_P(sbspace)) {
215
391
  char *c_sbspace = StringValueCStr(sbspace);
216
392
  ret = ifx_lo_specset_sbspace(slob->spec, c_sbspace);
217
393
  if (ret == -1)
218
394
  rb_raise(rb_eRuntimeError, "Could not set sbspace name to %s", c_sbspace);
219
395
  }
220
- if (RTEST(estbytes)) {
396
+ if (!NIL_P(estbytes)) {
221
397
  ifx_int8_t estbytes8;
222
398
 
223
399
  NUM2INT8(estbytes, &estbytes8);
@@ -225,17 +401,17 @@ slob_initialize(int argc, VALUE *argv, VALUE self)
225
401
  if (ret == -1)
226
402
  rb_raise(rb_eRuntimeError, "Could not set estbytes");
227
403
  }
228
- if (RTEST(extsz)) {
404
+ if (!NIL_P(extsz)) {
229
405
  ret = ifx_lo_specset_extsz(slob->spec, FIX2LONG(extsz));
230
406
  if (ret == -1)
231
407
  rb_raise(rb_eRuntimeError, "Could not set extsz to %d", FIX2LONG(extsz));
232
408
  }
233
- if (RTEST(createflags)) {
409
+ if (!NIL_P(createflags)) {
234
410
  ret = ifx_lo_specset_flags(slob->spec, FIX2LONG(createflags));
235
411
  if (ret == -1)
236
412
  rb_raise(rb_eRuntimeError, "Could not set crate-time flags to 0x%X", FIX2LONG(createflags));
237
413
  }
238
- if (RTEST(maxbytes)) {
414
+ if (!NIL_P(maxbytes)) {
239
415
  ifx_int8_t maxbytes8;
240
416
 
241
417
  NUM2INT8(maxbytes, (&maxbytes8));
@@ -243,26 +419,62 @@ slob_initialize(int argc, VALUE *argv, VALUE self)
243
419
  if (ret == -1)
244
420
  rb_raise(rb_eRuntimeError, "Could not set maxbytes");
245
421
  }
422
+
246
423
  slob->fd = ifx_lo_create(slob->spec, RTEST(openflags)? FIX2LONG(openflags): LO_RDWR, &slob->lo, &error);
247
- if (slob->fd == -1) {
424
+ if (slob->fd == -1)
248
425
  rb_raise(rb_eRuntimeError, "Informix Error: %d\n", error);
249
- }
426
+
250
427
  return self;
251
428
  }
252
429
 
430
+ /*
431
+ * call-seq:
432
+ * Slob.new(database, type = Slob::CLOB, options = nil) => slob
433
+ * Slob.new(database, type = Slob::CLOB, options = nil) {|slob| block } => obj
434
+ *
435
+ * Creates a Smart Large Object of type <i>type</i> in <i>database</i>.
436
+ * Returns a <code>Slob</code> object pointing to it.
437
+ *
438
+ * <i>type</i> can be Slob::BLOB or Slob::CLOB
439
+ *
440
+ * <i>options</i> can be nil or a Hash object with the following possible keys:
441
+ *
442
+ * :sbspace => Sbspace name
443
+ * :estbytes => Estimated size, in bytes
444
+ * :extsz => Allocation extent size
445
+ * :createflags => Create-time flags
446
+ * :openflags => Access mode
447
+ * :maxbytes => Maximum size
448
+ * :col_info => Get the previous values from the column-level storage
449
+ * characteristics for the specified database column
450
+ */
451
+ static VALUE rb_slob_close(VALUE self);
452
+ static VALUE
453
+ rb_slob_s_new(int argc, VALUE *argv, VALUE klass)
454
+ {
455
+ VALUE slob;
456
+
457
+ slob = rb_class_new_instance(argc, argv, klass);
458
+
459
+ if (rb_block_given_p())
460
+ return rb_ensure(rb_yield, slob, rb_slob_close, slob);
461
+
462
+ return slob;
463
+ }
464
+
253
465
  /*
254
466
  * call-seq:
255
467
  * slob.open(access = Slob::RDONLY) => slob
256
468
  *
257
469
  * Opens the Smart Large Object in <i>access</i> mode.
258
470
  *
259
- * access modes:
471
+ * Access modes:
260
472
  *
261
473
  * Slob::RDONLY:: Read only
262
474
  * Slob::DIRTY_READ:: Read uncommitted data
263
475
  * Slob::WRONLY:: Write only
264
- * Slob::APPEND:: Append data to the end, if combined with RDRW or WRONLY; read only otherwise
265
- * Slob::RDRW:: Read/Write
476
+ * Slob::APPEND:: Append data to the end, if combined with RDWR or WRONLY; read only otherwise
477
+ * Slob::RDWR:: Read/Write
266
478
  * Slob::BUFFER:: Use standard database server buffer pool
267
479
  * Slob::NOBUFFER:: Use private buffer from the session pool of the database server
268
480
  * Slob::LOCKALL:: Lock the entire Smart Large Object
@@ -271,7 +483,7 @@ slob_initialize(int argc, VALUE *argv, VALUE self)
271
483
  * Returns __self__.
272
484
  */
273
485
  static VALUE
274
- slob_open(int argc, VALUE *argv, VALUE self)
486
+ rb_slob_open(int argc, VALUE *argv, VALUE self)
275
487
  {
276
488
  VALUE access;
277
489
  slob_t *slob;
@@ -286,12 +498,9 @@ slob_open(int argc, VALUE *argv, VALUE self)
286
498
  return self;
287
499
 
288
500
  did = slob->database_id;
289
- if (currentdid != did) {
290
- EXEC SQL set connection :did;
291
- if (SQLCODE < 0)
292
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
293
- currentdid = did;
294
- }
501
+ EXEC SQL set connection :did;
502
+ if (SQLCODE < 0)
503
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
295
504
 
296
505
  rb_scan_args(argc, argv, "01", &access);
297
506
 
@@ -310,7 +519,7 @@ slob_open(int argc, VALUE *argv, VALUE self)
310
519
  * Closes the Smart Large Object and returns __self__.
311
520
  */
312
521
  static VALUE
313
- slob_close(VALUE self)
522
+ rb_slob_close(VALUE self)
314
523
  {
315
524
  slob_t *slob;
316
525
 
@@ -321,12 +530,9 @@ slob_close(VALUE self)
321
530
  EXEC SQL end declare section;
322
531
 
323
532
  did = slob->database_id;
324
- if (currentdid != did) {
325
- EXEC SQL set connection :did;
326
- if (SQLCODE < 0)
327
- return self;
328
- currentdid = did;
329
- }
533
+ EXEC SQL set connection :did;
534
+ if (SQLCODE < 0)
535
+ return self;
330
536
 
331
537
  ifx_lo_close(slob->fd);
332
538
  slob->fd = -1;
@@ -344,7 +550,7 @@ slob_close(VALUE self)
344
550
  * Returns the bytes read as a String object.
345
551
  */
346
552
  static VALUE
347
- slob_read(VALUE self, VALUE nbytes)
553
+ rb_slob_read(VALUE self, VALUE nbytes)
348
554
  {
349
555
  slob_t *slob;
350
556
  mint error, ret;
@@ -362,19 +568,18 @@ slob_read(VALUE self, VALUE nbytes)
362
568
  rb_raise(rb_eRuntimeError, "Open the Slob object before reading");
363
569
 
364
570
  did = slob->database_id;
365
- if (currentdid != did) {
366
- EXEC SQL set connection :did;
367
- if (SQLCODE < 0)
368
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
369
- currentdid = did;
370
- }
571
+ EXEC SQL set connection :did;
572
+ if (SQLCODE < 0)
573
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
371
574
 
372
575
  c_nbytes = FIX2LONG(nbytes);
373
576
  buffer = ALLOC_N(char, c_nbytes);
374
577
  ret = ifx_lo_read(slob->fd, buffer, c_nbytes, &error);
375
578
 
376
- if (ret == -1)
579
+ if (ret == -1) {
580
+ xfree(buffer);
377
581
  rb_raise(rb_eRuntimeError, "Informix Error: %d\n", error);
582
+ }
378
583
 
379
584
  str = rb_str_new(buffer, ret);
380
585
  xfree(buffer);
@@ -386,12 +591,13 @@ slob_read(VALUE self, VALUE nbytes)
386
591
  * call-seq:
387
592
  * slob.write(data) => fixnum or bignum
388
593
  *
389
- * Writes <i>data</i> to the Smart Large Object.
594
+ * Writes <i>data</i> to the Smart Large Object. If <i>data</i> is not a
595
+ * String object it will be converted to String using <code>to_s</code>.
390
596
  *
391
597
  * Returns the number of bytes written.
392
598
  */
393
599
  static VALUE
394
- slob_write(VALUE self, VALUE data)
600
+ rb_slob_write(VALUE self, VALUE data)
395
601
  {
396
602
  slob_t *slob;
397
603
  mint error, ret;
@@ -408,14 +614,11 @@ slob_write(VALUE self, VALUE data)
408
614
  rb_raise(rb_eRuntimeError, "Open the Slob object before writing");
409
615
 
410
616
  did = slob->database_id;
411
- if (currentdid != did) {
412
- EXEC SQL set connection :did;
413
- if (SQLCODE < 0)
414
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
415
- currentdid = did;
416
- }
617
+ EXEC SQL set connection :did;
618
+ if (SQLCODE < 0)
619
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
417
620
 
418
- str = StringValue(data);
621
+ str = rb_obj_as_string(data);
419
622
  buffer = RSTRING(str)->ptr;
420
623
  nbytes = RSTRING(str)->len;
421
624
 
@@ -427,6 +630,22 @@ slob_write(VALUE self, VALUE data)
427
630
  return LONG2NUM(ret);
428
631
  }
429
632
 
633
+ /*
634
+ * call-seq:
635
+ * slob << data => slob
636
+ *
637
+ * Writes <i>data</i> to the Smart Large Object. If <i>data</i> is not a
638
+ * String object it will be converted to String using <code>to_s</code>.
639
+ *
640
+ * Returns self.
641
+ */
642
+ static VALUE
643
+ rb_slob_addstr(VALUE self, VALUE data)
644
+ {
645
+ rb_slob_write(self, data);
646
+ return self;
647
+ }
648
+
430
649
  /*
431
650
  * call-seq:
432
651
  * slob.seek(offset, whence) => fixnum or bignum
@@ -447,7 +666,7 @@ slob_write(VALUE self, VALUE data)
447
666
  * Returns the new position.
448
667
  */
449
668
  static VALUE
450
- slob_seek(VALUE self, VALUE offset, VALUE whence)
669
+ rb_slob_seek(VALUE self, VALUE offset, VALUE whence)
451
670
  {
452
671
  slob_t *slob;
453
672
  mint ret;
@@ -463,12 +682,9 @@ slob_seek(VALUE self, VALUE offset, VALUE whence)
463
682
  rb_raise(rb_eRuntimeError, "Open the Slob object first");
464
683
 
465
684
  did = slob->database_id;
466
- if (currentdid != did) {
467
- EXEC SQL set connection :did;
468
- if (SQLCODE < 0)
469
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
470
- currentdid = did;
471
- }
685
+ EXEC SQL set connection :did;
686
+ if (SQLCODE < 0)
687
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
472
688
 
473
689
  NUM2INT8(offset, &offset8);
474
690
  ret = ifx_lo_seek(slob->fd, &offset8, FIX2INT(whence), &seek_pos8);
@@ -482,13 +698,37 @@ slob_seek(VALUE self, VALUE offset, VALUE whence)
482
698
 
483
699
  /*
484
700
  * call-seq:
485
- * slob.tell => fixnum or bignum
701
+ * slob.pos = integer => integer
702
+ *
703
+ * Seeks to the given position (in bytes) in _slob_.
704
+ */
705
+ static VALUE
706
+ rb_slob_set_pos(VALUE self, VALUE pos)
707
+ {
708
+ return rb_slob_seek(self, pos, LO_SEEK_SET);
709
+ }
710
+
711
+ /*
712
+ * call-seq:
713
+ * slob.rewind => fixnum
714
+ *
715
+ * Moves the cursor position to the start of the Smart Large Object.
716
+ */
717
+ static VALUE
718
+ rb_slob_rewind(VALUE self)
719
+ {
720
+ return rb_slob_seek(self, INT2FIX(0), LO_SEEK_SET);
721
+ }
722
+
723
+ /*
724
+ * call-seq:
725
+ * slob.tell => integer
726
+ * slob.pos => integer
486
727
  *
487
- * Returns the current file or seek position for an
488
- * open Smart Large Object
728
+ * Returns the current file or seek position for an open Smart Large Object
489
729
  */
490
730
  static VALUE
491
- slob_tell(VALUE self)
731
+ rb_slob_tell(VALUE self)
492
732
  {
493
733
  slob_t *slob;
494
734
  mint ret;
@@ -504,12 +744,9 @@ slob_tell(VALUE self)
504
744
  rb_raise(rb_eRuntimeError, "Open the Slob object first");
505
745
 
506
746
  did = slob->database_id;
507
- if (currentdid != did) {
508
- EXEC SQL set connection :did;
509
- if (SQLCODE < 0)
510
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
511
- currentdid = did;
512
- }
747
+ EXEC SQL set connection :did;
748
+ if (SQLCODE < 0)
749
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
513
750
 
514
751
  ret = ifx_lo_tell(slob->fd, &seek_pos8);
515
752
  if (ret < 0)
@@ -522,41 +759,486 @@ slob_tell(VALUE self)
522
759
 
523
760
  /*
524
761
  * call-seq:
525
- * slob.truncate(offset) => slob
526
- *
527
- * Truncates a Smart Large Object at a specified byte position.
762
+ * slob.truncate(offset) => slob
763
+ *
764
+ * Truncates a Smart Large Object at a specified byte position.
765
+ *
766
+ * Returns __self__.
767
+ */
768
+ static VALUE
769
+ rb_slob_truncate(VALUE self, VALUE offset)
770
+ {
771
+ slob_t *slob;
772
+ mint ret;
773
+ ifx_int8_t offset8;
774
+ EXEC SQL begin declare section;
775
+ char *did;
776
+ EXEC SQL end declare section;
777
+
778
+ Data_Get_Struct(self, slob_t, slob);
779
+
780
+ if (slob->fd == -1)
781
+ rb_raise(rb_eRuntimeError, "Open the Slob object first");
782
+
783
+ did = slob->database_id;
784
+ EXEC SQL set connection :did;
785
+ if (SQLCODE < 0)
786
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
787
+
788
+ NUM2INT8(offset, &offset8);
789
+ ret = ifx_lo_truncate(slob->fd, &offset8);
790
+ if (ret < 0)
791
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
792
+
793
+ return self;
794
+ }
795
+
796
+ /*
797
+ * call-seq:
798
+ * slob.stat => stat
799
+ *
800
+ * Creates and returns an Slob::Stat object with status information for _slob_.
801
+ */
802
+ static VALUE
803
+ rb_slob_stat(VALUE self)
804
+ {
805
+ return rb_class_new_instance(1, &self, rb_cSlobStat);
806
+ }
807
+
808
+ /*
809
+ * call-seq:
810
+ * slob.lock(offset, whence, range, mode) => slob
811
+ *
812
+ * Locks _range_ number of bytes, starting from _offset_ bytes from
813
+ * _whence_, in _mode_ mode.
814
+ *
815
+ * Returns _self_.
816
+ *
817
+ * Possible values:
818
+ *
819
+ * offset => integer
820
+ * whence => Slob::SEEK_SET, Slob::SEEK_CUR, Slob::SEEK_END
821
+ * range => integer, Slob::CURRENT_END, Slob::MAX_END
822
+ * mode => Slob::SHARED_MODE, Slob::EXCLUSIVE_MODE
823
+ */
824
+ static VALUE
825
+ rb_slob_lock(VALUE self, VALUE offset, VALUE whence, VALUE range, VALUE mode)
826
+ {
827
+ slob_t *slob;
828
+ mint ret;
829
+ ifx_int8_t offset8, range8;
830
+ EXEC SQL begin declare section;
831
+ char *did;
832
+ EXEC SQL end declare section;
833
+
834
+ Data_Get_Struct(self, slob_t, slob);
835
+
836
+ if (slob->fd == -1)
837
+ rb_raise(rb_eRuntimeError, "Open the Slob object first");
838
+
839
+ did = slob->database_id;
840
+ EXEC SQL set connection :did;
841
+ if (SQLCODE < 0)
842
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
843
+
844
+ NUM2INT8(offset, &offset8);
845
+ NUM2INT8(range, &range8);
846
+ ret = ifx_lo_lock(slob->fd, &offset8, FIX2INT(whence), &range8, FIX2INT(mode));
847
+ if (ret < 0)
848
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
849
+
850
+ return self;
851
+ }
852
+
853
+ /*
854
+ * call-seq:
855
+ * slob.unlock(offset, whence, range) => slob
856
+ *
857
+ * Unlocks _range_ number of bytes, starting from _offset_ bytes from
858
+ * _whence_.
859
+ *
860
+ * Returns _self_.
861
+ *
862
+ * Possible values:
863
+ *
864
+ * offset => integer
865
+ * whence => Slob::SEEK_SET, Slob::SEEK_CUR, Slob::SEEK_END
866
+ * range => integer
867
+ */
868
+ static VALUE
869
+ rb_slob_unlock(VALUE self, VALUE offset, VALUE whence, VALUE range)
870
+ {
871
+ slob_t *slob;
872
+ mint ret;
873
+ ifx_int8_t offset8, range8;
874
+ EXEC SQL begin declare section;
875
+ char *did;
876
+ EXEC SQL end declare section;
877
+
878
+ Data_Get_Struct(self, slob_t, slob);
879
+
880
+ if (slob->fd == -1)
881
+ rb_raise(rb_eRuntimeError, "Open the Slob object first");
882
+
883
+ did = slob->database_id;
884
+ EXEC SQL set connection :did;
885
+ if (SQLCODE < 0)
886
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
887
+
888
+ NUM2INT8(offset, &offset8);
889
+ NUM2INT8(range, &range8);
890
+ ret = ifx_lo_unlock(slob->fd, &offset8, FIX2INT(whence), &range8);
891
+ if (ret < 0)
892
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
893
+
894
+ return self;
895
+ }
896
+
897
+ typedef enum {
898
+ slob_estbytes, slob_extsz, slob_flags, slob_maxbytes, slob_sbspace
899
+ } slob_option_t;
900
+ static char *str_slob_options[] = {
901
+ "estbytes", "extsz", "flags", "maxbytes", "sbspace"};
902
+ /*
903
+ * Base function for getting storage charasteristics
904
+ */
905
+ static VALUE
906
+ slob_specget(VALUE self, slob_option_t option)
907
+ {
908
+ slob_t *slob;
909
+ mint ret;
910
+ ifx_lo_stat_t *stat;
911
+ ifx_lo_create_spec_t *spec;
912
+ ifx_int8_t int8;
913
+ char buffer[129];
914
+ VALUE item;
915
+ EXEC SQL begin declare section;
916
+ char *did;
917
+ EXEC SQL end declare section;
918
+
919
+ Data_Get_Struct(self, slob_t, slob);
920
+
921
+ if (slob->fd == -1)
922
+ rb_raise(rb_eRuntimeError, "Open the Slob object first");
923
+
924
+ did = slob->database_id;
925
+ EXEC SQL set connection :did;
926
+ if (SQLCODE < 0)
927
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
928
+
929
+ ret = ifx_lo_stat(slob->fd, &stat);
930
+ if (ret < 0)
931
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
932
+
933
+ spec = ifx_lo_stat_cspec(stat);
934
+ if (spec == NULL) {
935
+ ifx_lo_stat_free(stat);
936
+ rb_raise(rb_eRuntimeError, "Unable to get storage characteristics");
937
+ }
938
+
939
+ switch(option) {
940
+ case slob_estbytes:
941
+ ret = ifx_lo_specget_estbytes(spec, &int8);
942
+ break;
943
+ case slob_extsz:
944
+ ret = ifx_lo_specget_extsz(spec);
945
+ break;
946
+ case slob_flags:
947
+ ret = ifx_lo_specget_flags(spec);
948
+ break;
949
+ case slob_maxbytes:
950
+ ret = ifx_lo_specget_maxbytes(spec, &int8);
951
+ break;
952
+ case slob_sbspace:
953
+ ret = ifx_lo_specget_sbspace(spec, buffer, sizeof(buffer));
954
+ }
955
+
956
+ ifx_lo_stat_free(stat);
957
+ if (ret == -1)
958
+ rb_raise(rb_eRuntimeError, "Unable to get information for %s", str_slob_options[option]);
959
+
960
+ switch(option) {
961
+ case slob_estbytes:
962
+ case slob_maxbytes:
963
+ INT82NUM(&int8, item);
964
+ return item;
965
+ case slob_extsz:
966
+ case slob_flags:
967
+ return INT2FIX(ret);
968
+ case slob_sbspace:
969
+ return rb_str_new2(buffer);
970
+ }
971
+
972
+ return Qnil; /* Not reached */
973
+ }
974
+
975
+ /*
976
+ * Base function for setting extsz and flags
977
+ */
978
+ static VALUE
979
+ slob_specset(VALUE self, slob_option_t option, VALUE value)
980
+ {
981
+ slob_t *slob;
982
+ mint ret;
983
+ ifx_lo_stat_t *stat;
984
+ ifx_lo_create_spec_t *spec;
985
+ EXEC SQL begin declare section;
986
+ char *did;
987
+ EXEC SQL end declare section;
988
+
989
+ Data_Get_Struct(self, slob_t, slob);
990
+
991
+ if (slob->fd == -1)
992
+ rb_raise(rb_eRuntimeError, "Open the Slob object first");
993
+
994
+ did = slob->database_id;
995
+ EXEC SQL set connection :did;
996
+ if (SQLCODE < 0)
997
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
998
+
999
+ ret = ifx_lo_stat(slob->fd, &stat);
1000
+ if (ret < 0)
1001
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
1002
+
1003
+ spec = ifx_lo_stat_cspec(stat);
1004
+ if (spec == NULL) {
1005
+ ifx_lo_stat_free(stat);
1006
+ rb_raise(rb_eRuntimeError, "Unable to get storage characteristics");
1007
+ }
1008
+
1009
+ switch(option) {
1010
+ case slob_extsz:
1011
+ ret = ifx_lo_specset_extsz(spec, FIX2INT(value));
1012
+ break;
1013
+ case slob_flags:
1014
+ ret = ifx_lo_specset_flags(spec, FIX2INT(value));
1015
+ break;
1016
+ default:
1017
+ break; /* Not reached */
1018
+ }
1019
+
1020
+ ifx_lo_stat_free(stat);
1021
+ if (ret == -1)
1022
+ rb_raise(rb_eRuntimeError, "Unable to set information for %s", str_slob_options[option]);
1023
+
1024
+ return value;
1025
+ }
1026
+
1027
+ /*
1028
+ * call-seq:
1029
+ * slob.estbytes => fixnum or bignum
1030
+ *
1031
+ * Returns the estimated size of the SLOB
1032
+ */
1033
+ static VALUE
1034
+ rb_slob_estbytes(VALUE self)
1035
+ {
1036
+ return slob_specget(self, slob_estbytes);
1037
+ }
1038
+
1039
+ /*
1040
+ * call-seq:
1041
+ * slob.extsz => fixnum
1042
+ *
1043
+ * Returns the allocation extent size of the SLOB
1044
+ */
1045
+ static VALUE
1046
+ rb_slob_extsz(VALUE self)
1047
+ {
1048
+ return slob_specget(self, slob_extsz);
1049
+ }
1050
+
1051
+ /*
1052
+ * call-seq:
1053
+ * slob.flags => fixnum
1054
+ *
1055
+ * Returns the create-time flags of the SLOB
1056
+ */
1057
+ static VALUE
1058
+ rb_slob_flags(VALUE self)
1059
+ {
1060
+ return slob_specget(self, slob_flags);
1061
+ }
1062
+
1063
+ /*
1064
+ * call-seq:
1065
+ * slob.maxbytes => fixnum or bignum
1066
+ *
1067
+ * Returns the maximum size of the SLOB
1068
+ */
1069
+ static VALUE
1070
+ rb_slob_maxbytes(VALUE self)
1071
+ {
1072
+ return slob_specget(self, slob_maxbytes);
1073
+ }
1074
+
1075
+ /*
1076
+ * call-seq:
1077
+ * slob.sbspace => string
1078
+ *
1079
+ * Returns the name of the sbspace where the SLOB is stored
1080
+ */
1081
+ static VALUE
1082
+ rb_slob_sbspace(VALUE self)
1083
+ {
1084
+ return slob_specget(self, slob_sbspace);
1085
+ }
1086
+
1087
+ /*
1088
+ * call-seq:
1089
+ * slob.extsz = fixnum => fixnum
1090
+ *
1091
+ * Sets the allocation extent size for the SLOB
1092
+ */
1093
+ static VALUE
1094
+ rb_slob_set_extsz(VALUE self, VALUE value)
1095
+ {
1096
+ return slob_specset(self, slob_extsz, value);
1097
+ }
1098
+
1099
+ /*
1100
+ * call-seq:
1101
+ * slob.flags = fixnum => fixnum
1102
+ *
1103
+ * Sets the create-time flags of the SLOB
1104
+ */
1105
+ static VALUE
1106
+ rb_slob_set_flags(VALUE self, VALUE value)
1107
+ {
1108
+ return slob_specset(self, slob_flags, value);
1109
+ }
1110
+
1111
+ typedef enum { slob_atime, slob_ctime, slob_mtime, slob_refcnt, slob_size } slob_stat_t;
1112
+ static char *str_slob_stats[] = {
1113
+ "atime", "ctime", "mtime", "refcnt", "size"
1114
+ };
1115
+
1116
+ /*
1117
+ * Base function for getting status information
1118
+ */
1119
+ static VALUE
1120
+ slob_stat(VALUE self, slob_stat_t stat)
1121
+ {
1122
+ mint ret;
1123
+ slob_t *slob;
1124
+ ifx_lo_stat_t *st;
1125
+ ifx_int8_t int8;
1126
+ VALUE result;
1127
+ EXEC SQL begin declare section;
1128
+ char *did;
1129
+ EXEC SQL end declare section;
1130
+
1131
+ Data_Get_Struct(self, slob_t, slob);
1132
+
1133
+ if (slob->fd == -1)
1134
+ rb_raise(rb_eRuntimeError,
1135
+ "Open the Slob object before getting its status");
1136
+
1137
+ did = slob->database_id;
1138
+ EXEC SQL set connection :did;
1139
+ if (SQLCODE < 0)
1140
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1141
+
1142
+ ret = ifx_lo_stat(slob->fd, &st);
1143
+
1144
+ if (ret < 0)
1145
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
1146
+
1147
+ switch(stat) {
1148
+ case slob_atime:
1149
+ ret = ifx_lo_stat_atime(st);
1150
+ break;
1151
+ case slob_ctime:
1152
+ ret = ifx_lo_stat_ctime(st);
1153
+ break;
1154
+ case slob_mtime:
1155
+ ret = ifx_lo_stat_mtime_sec(st);
1156
+ break;
1157
+ case slob_refcnt:
1158
+ ret = ifx_lo_stat_refcnt(st);
1159
+ break;
1160
+ case slob_size:
1161
+ ret = ifx_lo_stat_size(st, &int8);
1162
+ }
1163
+
1164
+ ifx_lo_stat_free(st);
1165
+
1166
+ if (ret == -1)
1167
+ rb_raise(rb_eRuntimeError, "Unable to get value of %s", str_slob_stats[stat]);
1168
+
1169
+ switch(stat) {
1170
+ case slob_atime:
1171
+ case slob_ctime:
1172
+ case slob_mtime:
1173
+ return rb_time_new(ret, 0);
1174
+ case slob_refcnt:
1175
+ return INT2FIX(ret);
1176
+ case slob_size:
1177
+ INT82NUM(&int8, result);
1178
+ return result;
1179
+ }
1180
+
1181
+ return Qnil; /* Not reached */
1182
+ }
1183
+
1184
+ /*
1185
+ * call-seq:
1186
+ * slob.atime => time
1187
+ *
1188
+ * Returns the time of last access as a Time object.
1189
+ */
1190
+ static VALUE
1191
+ rb_slob_atime(VALUE self)
1192
+ {
1193
+ return slob_stat(self, slob_atime);
1194
+ }
1195
+
1196
+ /*
1197
+ * call-seq:
1198
+ * stat.ctime => time
1199
+ *
1200
+ * Returns the time of last change in status as a Time object.
1201
+ */
1202
+ static VALUE
1203
+ rb_slob_ctime(VALUE self)
1204
+ {
1205
+ return slob_stat(self, slob_ctime);
1206
+ }
1207
+
1208
+ /*
1209
+ * call-seq:
1210
+ * stat.mtime => time
1211
+ *
1212
+ * Returns the time of last modification as a Time object.
1213
+ */
1214
+ static VALUE
1215
+ rb_slob_mtime(VALUE self)
1216
+ {
1217
+ return slob_stat(self, slob_mtime);
1218
+ }
1219
+
1220
+ /*
1221
+ * call-seq:
1222
+ * stat.refcnt => fixnum
528
1223
  *
529
- * Returns __self__.
1224
+ * Returns the number of references
530
1225
  */
531
1226
  static VALUE
532
- slob_truncate(VALUE self, VALUE offset)
1227
+ rb_slob_refcnt(VALUE self)
533
1228
  {
534
- slob_t *slob;
535
- mint ret;
536
- ifx_int8_t offset8;
537
- EXEC SQL begin declare section;
538
- char *did;
539
- EXEC SQL end declare section;
540
-
541
- Data_Get_Struct(self, slob_t, slob);
542
-
543
- if (slob->fd == -1)
544
- rb_raise(rb_eRuntimeError, "Open the Slob object first");
545
-
546
- did = slob->database_id;
547
- if (currentdid != did) {
548
- EXEC SQL set connection :did;
549
- if (SQLCODE < 0)
550
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
551
- currentdid = did;
552
- }
553
-
554
- NUM2INT8(offset, &offset8);
555
- ret = ifx_lo_truncate(slob->fd, &offset8);
556
- if (ret < 0)
557
- rb_raise(rb_eRuntimeError, "Informix Error: %d", ret);
1229
+ return slob_stat(self, slob_refcnt);
1230
+ }
558
1231
 
559
- return self;
1232
+ /*
1233
+ * call-seq:
1234
+ * stat.size => fixnum or bignum
1235
+ *
1236
+ * Returns the size in bytes
1237
+ */
1238
+ static VALUE
1239
+ rb_slob_size(VALUE self)
1240
+ {
1241
+ return slob_stat(self, slob_size);
560
1242
  }
561
1243
 
562
1244
  /* Helper functions ------------------------------------------------------- */
@@ -564,7 +1246,8 @@ slob_truncate(VALUE self, VALUE offset)
564
1246
  /*
565
1247
  * Counts the number of markers '?' in the query
566
1248
  */
567
- static int count_markers(const char *query)
1249
+ static int
1250
+ count_markers(const char *query)
568
1251
  {
569
1252
  register char c, quote = 0;
570
1253
  register int count = 0;
@@ -844,6 +1527,16 @@ bind_input_params(cursor_t *c, VALUE *argv)
844
1527
  *var->sqlind = 0;
845
1528
  break;
846
1529
  }
1530
+ if (klass == rb_cBigDecimal) {
1531
+ data = rb_funcall(data, s_to_s, 0);
1532
+ var->sqldata = (char *)ALLOC(dec_t);
1533
+ deccvasc(RSTRING(data)->ptr, RSTRING(data)->len,
1534
+ (dec_t *)var->sqldata);
1535
+ var->sqltype = CDECIMALTYPE;
1536
+ var->sqllen = sizeof(dec_t);
1537
+ *var->sqlind = 0;
1538
+ break;
1539
+ }
847
1540
  if (rb_respond_to(data, s_read)) {
848
1541
  char *str;
849
1542
  loc_t *loc;
@@ -1005,9 +1698,17 @@ make_result(cursor_t *c, VALUE record)
1005
1698
  }
1006
1699
  case SQLDECIMAL:
1007
1700
  case SQLMONEY: {
1008
- double dblValue;
1009
- dectodbl((dec_t *)var->sqldata, &dblValue);
1010
- item = rb_float_new(dblValue);
1701
+ char buffer[40];
1702
+ mint ret;
1703
+
1704
+ ret = dectoasc((dec_t *)var->sqldata, buffer,
1705
+ sizeof(buffer) - 1, -1);
1706
+ if (ret)
1707
+ rb_raise(rb_eRuntimeError,
1708
+ "Unable to convert DECIMAL to BigDecimal");
1709
+
1710
+ buffer[sizeof(buffer) - 1] = 0;
1711
+ item = rb_funcall(rb_cBigDecimal, s_new, 1, rb_str_new2(buffer));
1011
1712
  break;
1012
1713
  }
1013
1714
  case SQLBOOL:
@@ -1028,6 +1729,8 @@ make_result(cursor_t *c, VALUE record)
1028
1729
  Data_Get_Struct(item, slob_t, slob);
1029
1730
  memcpy(&slob->lo, var->sqldata, sizeof(ifx_lo_t));
1030
1731
  slob->type = var->sqlxid;
1732
+ slob->database_id = c->database_id;
1733
+ slob->db = c->db;
1031
1734
  break;
1032
1735
  }
1033
1736
  case SQLSET:
@@ -1062,16 +1765,22 @@ make_result(cursor_t *c, VALUE record)
1062
1765
 
1063
1766
  /*
1064
1767
  * call-seq:
1065
- * Informix.connect(dbname, user = nil, password = nil) => database
1768
+ * Informix.connect(dbname, user=nil, password=nil) => database
1769
+ * Informix.connect(dbname, user=nil, password=nil) {|database| block } => obj
1066
1770
  *
1067
- * Returns a <code>Database</code> object connected to <i>dbname</i> as
1771
+ * Creates a <code>Database</code> object connected to <i>dbname</i> as
1068
1772
  * <i>user</i> with <i>password</i>. If these are not given, connects to
1069
1773
  * <i>dbname</i> as the current user.
1774
+ *
1775
+ * The Database object is passed to the block if it's given, and automatically
1776
+ * closes the connection when the block terminates, returning the value of
1777
+ * the block.
1070
1778
  */
1779
+ static VALUE rb_database_s_open(int argc, VALUE *argv, VALUE klass);
1071
1780
  static VALUE
1072
1781
  informix_connect(int argc, VALUE *argv, VALUE self)
1073
1782
  {
1074
- return rb_class_new_instance(argc, argv, rb_cDatabase);
1783
+ return rb_database_s_open(argc, argv, rb_cDatabase);
1075
1784
  }
1076
1785
 
1077
1786
 
@@ -1086,8 +1795,6 @@ database_free(void *p)
1086
1795
 
1087
1796
  did = p;
1088
1797
  EXEC SQL disconnect :did;
1089
- if (currentdid == did)
1090
- currentdid = NULL;
1091
1798
  xfree(p);
1092
1799
  }
1093
1800
 
@@ -1096,21 +1803,13 @@ database_alloc(VALUE klass)
1096
1803
  {
1097
1804
  char *did;
1098
1805
 
1099
- did = ALLOC_N(char, IDSIZE);
1100
- did[0] = 0;
1806
+ did = ALLOC_N(char, IDSIZE<<1);
1807
+ did[0] = did[IDSIZE] = 0;
1101
1808
  return Data_Wrap_Struct(klass, 0, database_free, did);
1102
1809
  }
1103
1810
 
1104
- /*
1105
- * call-seq:
1106
- * Database.new(dbname, user = nil, password = nil) => database
1107
- *
1108
- * Returns a <code>Database</code> object connected to <i>dbname</i> as
1109
- * <i>user</i> with <i>password</i>. If these are not given, connects to
1110
- * <i>dbname</i> as the current user.
1111
- */
1112
1811
  static VALUE
1113
- database_initialize(int argc, VALUE *argv, VALUE self)
1812
+ rb_database_initialize(int argc, VALUE *argv, VALUE self)
1114
1813
  {
1115
1814
  VALUE arg[3];
1116
1815
 
@@ -1143,11 +1842,38 @@ database_initialize(int argc, VALUE *argv, VALUE self)
1143
1842
  if (SQLCODE < 0)
1144
1843
  rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1145
1844
 
1146
- currentdid = did;
1147
-
1148
1845
  return self;
1149
1846
  }
1150
1847
 
1848
+ /*
1849
+ * call-seq:
1850
+ * Database.new(dbname, user = nil, password = nil) => database
1851
+ * Database.open(dbname, user = nil, password = nil) => database
1852
+ * Database.new(dbname, user = nil, password = nil) {|database| block } => obj
1853
+ * Database.open(dbname, user = nil, password = nil) {|database| block } => obj
1854
+ *
1855
+ * Creates a <code>Database</code> object connected to <i>dbname</i> as
1856
+ * <i>user</i> with <i>password</i>. If these are not given, connects to
1857
+ * <i>dbname</i> as the current user.
1858
+ *
1859
+ * The Database object is passed to the block if it's given, and automatically
1860
+ * closes the connection when the block terminates, returning the value of
1861
+ * the block.
1862
+ */
1863
+ static VALUE rb_database_close(VALUE self);
1864
+ static VALUE
1865
+ rb_database_s_open(int argc, VALUE *argv, VALUE klass)
1866
+ {
1867
+ VALUE database;
1868
+
1869
+ database = rb_class_new_instance(argc, argv, klass);
1870
+
1871
+ if (rb_block_given_p())
1872
+ return rb_ensure(rb_yield, database, rb_database_close, database);
1873
+
1874
+ return database;
1875
+ }
1876
+
1151
1877
  /*
1152
1878
  * call-seq:
1153
1879
  * db.close => db
@@ -1155,16 +1881,18 @@ database_initialize(int argc, VALUE *argv, VALUE self)
1155
1881
  * Disconnects <i>db</i> and returns __self__
1156
1882
  */
1157
1883
  static VALUE
1158
- database_close(VALUE self)
1884
+ rb_database_close(VALUE self)
1159
1885
  {
1160
1886
  EXEC SQL begin declare section;
1161
1887
  char *did;
1162
1888
  EXEC SQL end declare section;
1163
1889
 
1164
1890
  Data_Get_Struct(self, char, did);
1891
+ did += IDSIZE;
1892
+ if (*did)
1893
+ EXEC SQL free :did;
1894
+ did -= IDSIZE;
1165
1895
  EXEC SQL disconnect :did;
1166
- if (did == currentdid)
1167
- currentdid = NULL;
1168
1896
 
1169
1897
  return self;
1170
1898
  }
@@ -1179,7 +1907,7 @@ database_close(VALUE self)
1179
1907
  */
1180
1908
 
1181
1909
  static VALUE
1182
- database_immediate(VALUE self, VALUE arg)
1910
+ rb_database_immediate(VALUE self, VALUE arg)
1183
1911
  {
1184
1912
  EXEC SQL begin declare section;
1185
1913
  char *query, *did;
@@ -1187,12 +1915,9 @@ database_immediate(VALUE self, VALUE arg)
1187
1915
 
1188
1916
  Data_Get_Struct(self, char, did);
1189
1917
 
1190
- if (currentdid != did) {
1191
- EXEC SQL set connection :did;
1192
- if (SQLCODE < 0)
1193
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1194
- currentdid = did;
1195
- }
1918
+ EXEC SQL set connection :did;
1919
+ if (SQLCODE < 0)
1920
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1196
1921
 
1197
1922
  query = StringValueCStr(arg);
1198
1923
  EXEC SQL execute immediate :query;
@@ -1209,7 +1934,7 @@ database_immediate(VALUE self, VALUE arg)
1209
1934
  * Rolls back a transaction and returns __self__.
1210
1935
  */
1211
1936
  static VALUE
1212
- database_rollback(VALUE self)
1937
+ rb_database_rollback(VALUE self)
1213
1938
  {
1214
1939
  EXEC SQL begin declare section;
1215
1940
  char *did;
@@ -1217,12 +1942,9 @@ database_rollback(VALUE self)
1217
1942
 
1218
1943
  Data_Get_Struct(self, char, did);
1219
1944
 
1220
- if (currentdid != did) {
1221
- EXEC SQL set connection :did;
1222
- if (SQLCODE < 0)
1223
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1224
- currentdid = did;
1225
- }
1945
+ EXEC SQL set connection :did;
1946
+ if (SQLCODE < 0)
1947
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1226
1948
 
1227
1949
  EXEC SQL rollback;
1228
1950
  return self;
@@ -1235,7 +1957,7 @@ database_rollback(VALUE self)
1235
1957
  * Commits a transaction and returns __self__.
1236
1958
  */
1237
1959
  static VALUE
1238
- database_commit(VALUE self)
1960
+ rb_database_commit(VALUE self)
1239
1961
  {
1240
1962
  EXEC SQL begin declare section;
1241
1963
  char *did;
@@ -1243,12 +1965,9 @@ database_commit(VALUE self)
1243
1965
 
1244
1966
  Data_Get_Struct(self, char, did);
1245
1967
 
1246
- if (currentdid != did) {
1247
- EXEC SQL set connection :did;
1248
- if (SQLCODE < 0)
1249
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1250
- currentdid = did;
1251
- }
1968
+ EXEC SQL set connection :did;
1969
+ if (SQLCODE < 0)
1970
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1252
1971
 
1253
1972
  EXEC SQL commit;
1254
1973
  return self;
@@ -1257,7 +1976,7 @@ database_commit(VALUE self)
1257
1976
  static VALUE
1258
1977
  database_transfail(VALUE self)
1259
1978
  {
1260
- database_rollback(self);
1979
+ rb_database_rollback(self);
1261
1980
  return Qundef;
1262
1981
  }
1263
1982
 
@@ -1272,7 +1991,7 @@ database_transfail(VALUE self)
1272
1991
  * Returns __self__.
1273
1992
  */
1274
1993
  static VALUE
1275
- database_transaction(VALUE self)
1994
+ rb_database_transaction(VALUE self)
1276
1995
  {
1277
1996
  VALUE ret;
1278
1997
  EXEC SQL begin declare section;
@@ -1281,12 +2000,9 @@ database_transaction(VALUE self)
1281
2000
 
1282
2001
  Data_Get_Struct(self, char, did);
1283
2002
 
1284
- if (currentdid != did) {
1285
- EXEC SQL set connection :did;
1286
- if (SQLCODE < 0)
1287
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1288
- currentdid = did;
1289
- }
2003
+ EXEC SQL set connection :did;
2004
+ if (SQLCODE < 0)
2005
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1290
2006
 
1291
2007
  EXEC SQL commit;
1292
2008
 
@@ -1300,20 +2016,27 @@ database_transaction(VALUE self)
1300
2016
 
1301
2017
  /*
1302
2018
  * call-seq:
1303
- * db.prepare(query) => statement
2019
+ * db.prepare(query) => statement
2020
+ * db.prepare(query) {|stmt| block } => obj
2021
+ *
2022
+ * Creates a <code>Statement</code> object based on <i>query</i>.
2023
+ * In the first form the Statement object is returned.
2024
+ * In the second form the Statement object is passed to the block and when it
2025
+ * terminates, the Statement object is dropped, returning the value of the
2026
+ * block.
1304
2027
  *
1305
- * Returns a <code>Statement</code> object based on <i>query</i>.
1306
2028
  * <i>query</i> may contain '?' placeholders for input parameters;
1307
2029
  * it must not be a query returning more than one row
1308
2030
  * (use <code>Database#cursor</code> instead.)
1309
2031
  */
2032
+ static VALUE statement_s_new(int, VALUE *, VALUE);
1310
2033
  static VALUE
1311
- database_prepare(VALUE self, VALUE query)
2034
+ rb_database_prepare(VALUE self, VALUE query)
1312
2035
  {
1313
2036
  VALUE argv[2];
1314
2037
 
1315
2038
  argv[0] = self; argv[1] = query;
1316
- return rb_class_new_instance(2, argv, rb_cStatement);
2039
+ return statement_s_new(2, argv, rb_cStatement);
1317
2040
  }
1318
2041
 
1319
2042
  /*
@@ -1330,7 +2053,7 @@ database_prepare(VALUE self, VALUE query)
1330
2053
  *
1331
2054
  */
1332
2055
  static VALUE
1333
- database_cursor(int argc, VALUE *argv, VALUE self)
2056
+ rb_database_cursor(int argc, VALUE *argv, VALUE self)
1334
2057
  {
1335
2058
  VALUE arg[3];
1336
2059
 
@@ -1339,6 +2062,37 @@ database_cursor(int argc, VALUE *argv, VALUE self)
1339
2062
  return rb_class_new_instance(3, arg, rb_cCursor);
1340
2063
  }
1341
2064
 
2065
+ /*
2066
+ * call-seq:
2067
+ * db.slob(type = Slob::CLOB, options = nil) => slob
2068
+ * db.slob(type = Slob::CLOB, options = nil) {|slob| block } => obj
2069
+ *
2070
+ * Creates a Smart Large Object of type <i>type</i>.
2071
+ * Returns a <code>Slob</code> object pointing to it.
2072
+ *
2073
+ * <i>type</i> can be Slob::BLOB or Slob::CLOB
2074
+ *
2075
+ * <i>options</i> can be nil or a Hash object with the following possible keys:
2076
+ *
2077
+ * :sbspace => Sbspace name
2078
+ * :estbytes => Estimated size, in bytes
2079
+ * :extsz => Allocation extent size
2080
+ * :createflags => Create-time flags
2081
+ * :openflags => Access mode
2082
+ * :maxbytes => Maximum size
2083
+ * :col_info => Get the previous values from the column-level storage
2084
+ * characteristics for the specified database column
2085
+ */
2086
+ static VALUE
2087
+ rb_database_slob(int argc, VALUE *argv, VALUE self)
2088
+ {
2089
+ VALUE arg[3];
2090
+
2091
+ arg[0] = self;
2092
+ rb_scan_args(argc, argv, "02", &arg[1], &arg[2]);
2093
+ return rb_slob_s_new(3, arg, rb_cSlob);
2094
+ }
2095
+
1342
2096
  /*
1343
2097
  * call-seq:
1344
2098
  * db.columns(tablename) => array
@@ -1346,7 +2100,7 @@ database_cursor(int argc, VALUE *argv, VALUE self)
1346
2100
  * Returns an array with information for every column of the given table.
1347
2101
  */
1348
2102
  static VALUE
1349
- database_columns(VALUE self, VALUE tablename)
2103
+ rb_database_columns(VALUE self, VALUE tablename)
1350
2104
  {
1351
2105
  VALUE v, column, result;
1352
2106
  char *stype;
@@ -1363,7 +2117,7 @@ database_columns(VALUE self, VALUE tablename)
1363
2117
  };
1364
2118
 
1365
2119
  EXEC SQL begin declare section;
1366
- char *did;
2120
+ char *did, *cid;
1367
2121
  char *tabname;
1368
2122
  int tabid, xid;
1369
2123
  varchar colname[129];
@@ -1374,12 +2128,9 @@ database_columns(VALUE self, VALUE tablename)
1374
2128
 
1375
2129
  Data_Get_Struct(self, char, did);
1376
2130
 
1377
- if (currentdid != did) {
1378
- EXEC SQL set connection :did;
1379
- if (SQLCODE < 0)
1380
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1381
- currentdid = did;
1382
- }
2131
+ EXEC SQL set connection :did;
2132
+ if (SQLCODE < 0)
2133
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1383
2134
 
1384
2135
  tabname = StringValueCStr(tablename);
1385
2136
 
@@ -1390,21 +2141,28 @@ database_columns(VALUE self, VALUE tablename)
1390
2141
 
1391
2142
  result = rb_ary_new();
1392
2143
 
1393
- EXEC SQL declare cur cursor for
1394
- select colname, coltype, collength, extended_id, type, default, c.colno
1395
- from syscolumns c, outer sysdefaults d
1396
- where c.tabid = :tabid and c.tabid = d.tabid and c.colno = d.colno
1397
- order by c.colno;
1398
-
1399
- if (SQLCODE < 0)
1400
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2144
+ cid = did + IDSIZE;
2145
+ if (!*cid) {
2146
+ snprintf(cid, IDSIZE, "COLS%lX", self);
2147
+ EXEC SQL declare :cid cursor for
2148
+ select colname, coltype, collength, extended_id,
2149
+ type, default, c.colno
2150
+ from syscolumns c, outer sysdefaults d
2151
+ where c.tabid = :tabid and c.tabid = d.tabid
2152
+ and c.colno = d.colno
2153
+ order by c.colno;
2154
+ if (SQLCODE < 0) {
2155
+ cid[0] = 0;
2156
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2157
+ }
2158
+ }
1401
2159
 
1402
- EXEC SQL open cur;
2160
+ EXEC SQL open :cid;
1403
2161
  if (SQLCODE < 0)
1404
2162
  rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1405
2163
 
1406
2164
  for(;;) {
1407
- EXEC SQL fetch cur into :colname, :coltype, :collength, :xid,
2165
+ EXEC SQL fetch :cid into :colname, :coltype, :collength, :xid,
1408
2166
  :deftype, :defvalue;
1409
2167
  if (SQLCODE < 0)
1410
2168
  rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
@@ -1499,8 +2257,7 @@ database_columns(VALUE self, VALUE tablename)
1499
2257
  rb_ary_push(result, column);
1500
2258
  }
1501
2259
 
1502
- EXEC SQL close cur;
1503
- EXEC SQL free cur;
2260
+ EXEC SQL close :cid;
1504
2261
 
1505
2262
  return result;
1506
2263
  }
@@ -1530,17 +2287,12 @@ statement_free(void *p)
1530
2287
  free_output_slots(p);
1531
2288
 
1532
2289
  did = ((cursor_t *)p)->database_id;
1533
- if (currentdid != did) {
1534
- EXEC SQL set connection :did;
1535
- if (SQLCODE < 0)
1536
- goto exit;
1537
- currentdid = did;
2290
+ EXEC SQL set connection :did;
2291
+ if (SQLCODE >= 0) {
2292
+ sid = ((cursor_t *)p)->stmt_id;
2293
+ EXEC SQL free :sid;
1538
2294
  }
1539
2295
 
1540
- sid = ((cursor_t *)p)->stmt_id;
1541
- EXEC SQL free :sid;
1542
-
1543
- exit:
1544
2296
  xfree(p);
1545
2297
  }
1546
2298
 
@@ -1556,10 +2308,19 @@ statement_alloc(VALUE klass)
1556
2308
 
1557
2309
  /*
1558
2310
  * call-seq:
1559
- * Statement.new(database, query) => statement
2311
+ * Statement.new(database, query) => statement
2312
+ * Statement.new(database, query) {|stmt| block } => obj
1560
2313
  *
1561
- * Prepares <i>query</i> in the context of <i>database</i> and returns
1562
- * a <code>Statement</code> object.
2314
+ * Creates a <code>Statement</code> object based on <i>query</i> in the
2315
+ * context of <i>database</i>.
2316
+ * In the first form the <code>Statement</code> object is returned.
2317
+ * In the second form the Statement object is passed to the block and when it
2318
+ * terminates, the Statement object is dropped, returning the value of the
2319
+ * block.
2320
+ *
2321
+ * <i>query</i> may contain '?' placeholders for input parameters;
2322
+ * it must not be a query returning more than one row
2323
+ * (use <code>Cursor</code> instead.)
1563
2324
  */
1564
2325
  static VALUE
1565
2326
  statement_initialize(VALUE self, VALUE db, VALUE query)
@@ -1571,12 +2332,9 @@ statement_initialize(VALUE self, VALUE db, VALUE query)
1571
2332
  EXEC SQL end declare section;
1572
2333
 
1573
2334
  Data_Get_Struct(db, char, did);
1574
- if (currentdid != did) {
1575
- EXEC SQL set connection :did;
1576
- if (SQLCODE < 0)
1577
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1578
- currentdid = did;
1579
- }
2335
+ EXEC SQL set connection :did;
2336
+ if (SQLCODE < 0)
2337
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1580
2338
 
1581
2339
  Data_Get_Struct(self, cursor_t, c);
1582
2340
  c->db = db;
@@ -1606,6 +2364,35 @@ statement_initialize(VALUE self, VALUE db, VALUE query)
1606
2364
  return self;
1607
2365
  }
1608
2366
 
2367
+ /*
2368
+ * call-seq:
2369
+ * Statement.new(database, query) => statement
2370
+ * Statement.new(database, query) {|stmt| block } => obj
2371
+ *
2372
+ * Creates a <code>Statement</code> object based on <i>query</i> in the
2373
+ * context of <i>database</i>.
2374
+ * In the first form the <code>Statement</code> object is returned.
2375
+ * In the second form the Statement object is passed to the block and when it
2376
+ * terminates, the Statement object is dropped, returning the value of the
2377
+ * block.
2378
+ *
2379
+ * <i>query</i> may contain '?' placeholders for input parameters;
2380
+ * it must not be a query returning more than one row
2381
+ * (use <code>Cursor</code> instead.)
2382
+ */
2383
+ static VALUE statement_drop(VALUE);
2384
+ static VALUE
2385
+ statement_s_new(int argc, VALUE *argv, VALUE klass)
2386
+ {
2387
+ VALUE stmt;
2388
+
2389
+ stmt = rb_class_new_instance(argc, argv, klass);
2390
+
2391
+ if (rb_block_given_p())
2392
+ return rb_ensure(rb_yield, stmt, statement_drop, stmt);
2393
+
2394
+ return stmt;
2395
+ }
1609
2396
 
1610
2397
  /*
1611
2398
  * call-seq:
@@ -1629,12 +2416,9 @@ statement_call(int argc, VALUE *argv, VALUE self)
1629
2416
  Data_Get_Struct(self, cursor_t, c);
1630
2417
 
1631
2418
  did = c->database_id;
1632
- if (currentdid != did) {
1633
- EXEC SQL set connection :did;
1634
- if (SQLCODE < 0)
1635
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1636
- currentdid = did;
1637
- }
2419
+ EXEC SQL set connection :did;
2420
+ if (SQLCODE < 0)
2421
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1638
2422
 
1639
2423
  output = c->daOutput;
1640
2424
  input = &c->daInput;
@@ -1695,19 +2479,15 @@ statement_drop(VALUE self)
1695
2479
  free_output_slots(c);
1696
2480
 
1697
2481
  did = c->database_id;
1698
- if (currentdid != did) {
1699
- EXEC SQL set connection :did;
1700
- if (SQLCODE < 0)
1701
- return Qnil;
1702
- currentdid = did;
1703
- }
2482
+ EXEC SQL set connection :did;
2483
+ if (SQLCODE < 0)
2484
+ return Qnil;
1704
2485
  sid = c->stmt_id;
1705
2486
  EXEC SQL free :sid;
1706
2487
 
1707
2488
  return Qnil;
1708
2489
  }
1709
2490
 
1710
-
1711
2491
  /* module SequentialCursor ----------------------------------------------- */
1712
2492
 
1713
2493
  /* Decides whether to use an Array or a Hash, and instantiate a new
@@ -1752,12 +2532,9 @@ fetch(VALUE self, VALUE type, int bang)
1752
2532
  rb_raise(rb_eRuntimeError, "Open the cursor object first");
1753
2533
 
1754
2534
  did = c->database_id;
1755
- if (currentdid != did) {
1756
- EXEC SQL set connection :did;
1757
- if (SQLCODE < 0)
1758
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1759
- currentdid = did;
1760
- }
2535
+ EXEC SQL set connection :did;
2536
+ if (SQLCODE < 0)
2537
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1761
2538
 
1762
2539
  output = c->daOutput;
1763
2540
  cid = c->cursor_id;
@@ -1855,12 +2632,9 @@ fetch_many(VALUE self, VALUE n, VALUE type)
1855
2632
  rb_raise(rb_eRuntimeError, "Open the cursor object first");
1856
2633
 
1857
2634
  did = c->database_id;
1858
- if (currentdid != did) {
1859
- EXEC SQL set connection :did;
1860
- if (SQLCODE < 0)
1861
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1862
- currentdid = did;
1863
- }
2635
+ EXEC SQL set connection :did;
2636
+ if (SQLCODE < 0)
2637
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1864
2638
 
1865
2639
  output = c->daOutput;
1866
2640
  cid = c->cursor_id;
@@ -1960,12 +2734,9 @@ each(VALUE self, VALUE type, int bang)
1960
2734
  rb_raise(rb_eRuntimeError, "Open the cursor object first");
1961
2735
 
1962
2736
  did = c->database_id;
1963
- if (currentdid != did) {
1964
- EXEC SQL set connection :did;
1965
- if (SQLCODE < 0)
1966
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1967
- currentdid = did;
1968
- }
2737
+ EXEC SQL set connection :did;
2738
+ if (SQLCODE < 0)
2739
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
1969
2740
 
1970
2741
  output = c->daOutput;
1971
2742
  cid = c->cursor_id;
@@ -2115,12 +2886,9 @@ inscur_put(int argc, VALUE *argv, VALUE self)
2115
2886
  rb_raise(rb_eRuntimeError, "Open the cursor object first");
2116
2887
 
2117
2888
  did = c->database_id;
2118
- if (currentdid != did) {
2119
- EXEC SQL set connection :did;
2120
- if (SQLCODE < 0)
2121
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2122
- currentdid = did;
2123
- }
2889
+ EXEC SQL set connection :did;
2890
+ if (SQLCODE < 0)
2891
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2124
2892
 
2125
2893
  input = &c->daInput;
2126
2894
  cid = c->cursor_id;
@@ -2160,12 +2928,9 @@ inscur_flush(VALUE self)
2160
2928
  rb_raise(rb_eRuntimeError, "Open the cursor object first");
2161
2929
 
2162
2930
  did = c->database_id;
2163
- if (currentdid != did) {
2164
- EXEC SQL set connection :did;
2165
- if (SQLCODE < 0)
2166
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2167
- currentdid = did;
2168
- }
2931
+ EXEC SQL set connection :did;
2932
+ if (SQLCODE < 0)
2933
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2169
2934
 
2170
2935
  cid = c->cursor_id;
2171
2936
  EXEC SQL flush :cid;
@@ -2194,12 +2959,9 @@ scrollcur_entry(VALUE self, VALUE index, VALUE type, int bang)
2194
2959
  rb_raise(rb_eRuntimeError, "Open the cursor object first");
2195
2960
 
2196
2961
  did = c->database_id;
2197
- if (currentdid != did) {
2198
- EXEC SQL set connection :did;
2199
- if (SQLCODE < 0)
2200
- return Qnil;
2201
- currentdid = did;
2202
- }
2962
+ EXEC SQL set connection :did;
2963
+ if (SQLCODE < 0)
2964
+ return Qnil;
2203
2965
 
2204
2966
  output = c->daOutput;
2205
2967
  cid = c->cursor_id;
@@ -2230,11 +2992,8 @@ scrollcur_entry(VALUE self, VALUE index, VALUE type, int bang)
2230
2992
  static VALUE
2231
2993
  scrollcur_subseq(VALUE self, VALUE start, VALUE length, VALUE type)
2232
2994
  {
2233
- cursor_t *c;
2234
- struct sqlda *output;
2235
2995
  VALUE first, records;
2236
2996
  EXEC SQL begin declare section;
2237
- char *cid, *did;
2238
2997
  long pos;
2239
2998
  EXEC SQL end declare section;
2240
2999
 
@@ -2374,12 +3133,9 @@ scrollcur_rel(int argc, VALUE *argv, VALUE self, int dir, VALUE type, int bang)
2374
3133
  rb_raise(rb_eRuntimeError, "Open the cursor object first");
2375
3134
 
2376
3135
  did = c->database_id;
2377
- if (currentdid != did) {
2378
- EXEC SQL set connection :did;
2379
- if (SQLCODE < 0)
2380
- return Qnil;
2381
- currentdid = did;
2382
- }
3136
+ EXEC SQL set connection :did;
3137
+ if (SQLCODE < 0)
3138
+ return Qnil;
2383
3139
 
2384
3140
  rb_scan_args(argc, argv, "01", &offset);
2385
3141
  pos = dir*(NIL_P(offset)? 1: NUM2LONG(offset));
@@ -2698,12 +3454,9 @@ cursor_close_or_free(cursor_t *c, short op)
2698
3454
  }
2699
3455
 
2700
3456
  did = c->database_id;
2701
- if (currentdid != did) {
2702
- EXEC SQL set connection :did;
2703
- if (SQLCODE < 0)
2704
- return;
2705
- currentdid = did;
2706
- }
3457
+ EXEC SQL set connection :did;
3458
+ if (SQLCODE < 0)
3459
+ return;
2707
3460
 
2708
3461
  cid = c->cursor_id;
2709
3462
  EXEC SQL close :cid;
@@ -2745,19 +3498,20 @@ cursor_alloc(VALUE klass)
2745
3498
 
2746
3499
  /*
2747
3500
  * call-seq:
2748
- * Cursor.new(database, query, options) => cursor
3501
+ * Cursor.new(database, query, options = nil) => cursor
2749
3502
  *
2750
3503
  * Prepares <i>query</i> in the context of <i>database</i> with <i>options</i>
2751
3504
  * and returns a <code>Cursor</code> object.
2752
3505
  *
2753
- * <i>options</i> can be nil or a hash with the following possible keys:
3506
+ * <i>options</i> can be nil or a Hash object with the following possible keys:
2754
3507
  *
2755
3508
  * :scroll => true or false
2756
- * :hold => true or false
3509
+ * :hold => true or false
2757
3510
  */
2758
3511
  static VALUE
2759
- cursor_initialize(VALUE self, VALUE db, VALUE query, VALUE options)
3512
+ cursor_initialize(int argc, VALUE *argv, VALUE self)
2760
3513
  {
3514
+ VALUE db, query, options;
2761
3515
  VALUE scroll, hold;
2762
3516
  struct sqlda *output;
2763
3517
  cursor_t *c;
@@ -2766,14 +3520,12 @@ cursor_initialize(VALUE self, VALUE db, VALUE query, VALUE options)
2766
3520
  char *cid, *sid, *did;
2767
3521
  EXEC SQL end declare section;
2768
3522
 
3523
+ rb_scan_args(argc, argv, "21", &db, &query, &options);
2769
3524
  Data_Get_Struct(db, char, did);
2770
3525
 
2771
- if (currentdid != did) {
2772
- EXEC SQL set connection :did;
2773
- if (SQLCODE < 0)
2774
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2775
- currentdid = did;
2776
- }
3526
+ EXEC SQL set connection :did;
3527
+ if (SQLCODE < 0)
3528
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2777
3529
 
2778
3530
  Data_Get_Struct(self, cursor_t, c);
2779
3531
  c->db = db;
@@ -2784,7 +3536,8 @@ cursor_initialize(VALUE self, VALUE db, VALUE query, VALUE options)
2784
3536
  cid = c->cursor_id; sid = c->stmt_id;
2785
3537
  c_query = StringValueCStr(query);
2786
3538
 
2787
- if (RTEST(options)) {
3539
+ if (!NIL_P(options)) {
3540
+ Check_Type(options, T_HASH);
2788
3541
  scroll = rb_hash_aref(options, sym_scroll);
2789
3542
  hold = rb_hash_aref(options, sym_hold);
2790
3543
  }
@@ -2825,6 +3578,53 @@ cursor_initialize(VALUE self, VALUE db, VALUE query, VALUE options)
2825
3578
  return self;
2826
3579
  }
2827
3580
 
3581
+ /*
3582
+ * call-seq:
3583
+ * Cursor.open(database, query, options) => cursor
3584
+ * Cursor.open(database, query, options) {|cursor| block } => obj
3585
+ *
3586
+ * Creates and opens a Cursor object based on <i>query</i> using <i>options</i>
3587
+ * in the context of <i>database</i>.
3588
+ * In the first form the Cursor object is returned.
3589
+ * In the second form the Cursor object is passed to the block and when it
3590
+ * terminates, the Cursor object is dropped, returning the value of the block.
3591
+ *
3592
+ * <i>options</i> can be nil or a Hash object with the following possible keys:
3593
+ *
3594
+ * :scroll => true or false
3595
+ * :hold => true or false
3596
+ * :params => input parameters as an Array or nil
3597
+ */
3598
+ static VALUE cursor_open(int argc, VALUE *argv, VALUE self);
3599
+ static VALUE cursor_drop(VALUE self);
3600
+ static VALUE
3601
+ cursor_s_open(int argc, VALUE *argv, VALUE klass)
3602
+ {
3603
+ VALUE cursor, options, params;
3604
+ int open_argc;
3605
+
3606
+ rb_scan_args(argc, argv, "21", 0, 0, &options);
3607
+ open_argc = 0; params = Qnil;
3608
+
3609
+ if (!NIL_P(options)) {
3610
+ Check_Type(options, T_HASH);
3611
+ params = rb_hash_aref(options, sym_params);
3612
+
3613
+ if (TYPE(params) == T_ARRAY)
3614
+ open_argc = RARRAY(params)->len;
3615
+ else if (params != Qnil)
3616
+ rb_raise(rb_eRuntimeError, "Parameters must be supplied as an Array");
3617
+ }
3618
+
3619
+ cursor = rb_class_new_instance(argc, argv, klass);
3620
+ cursor_open(open_argc, &params, cursor);
3621
+
3622
+ if (rb_block_given_p())
3623
+ return rb_ensure(rb_yield, cursor, cursor_drop, cursor);
3624
+
3625
+ return cursor;
3626
+ }
3627
+
2828
3628
  /*
2829
3629
  * call-seq:
2830
3630
  * cursor.id => string
@@ -2864,12 +3664,9 @@ cursor_open(int argc, VALUE *argv, VALUE self)
2864
3664
  return self;
2865
3665
 
2866
3666
  did = c->database_id;
2867
- if (currentdid != did) {
2868
- EXEC SQL set connection :did;
2869
- if (SQLCODE < 0)
2870
- rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2871
- currentdid = did;
2872
- }
3667
+ EXEC SQL set connection :did;
3668
+ if (SQLCODE < 0)
3669
+ rb_raise(rb_eRuntimeError, "Informix Error: %d", SQLCODE);
2873
3670
 
2874
3671
  input = &c->daInput;
2875
3672
  cid = c->cursor_id;
@@ -2945,20 +3742,44 @@ void Init_informix(void)
2945
3742
  /* class Slob --------------------------------------------------------- */
2946
3743
  rb_cSlob = rb_define_class_under(rb_mInformix, "Slob", rb_cObject);
2947
3744
  rb_define_alloc_func(rb_cSlob, slob_alloc);
2948
- rb_define_method(rb_cSlob, "initialize", slob_initialize, -1);
2949
- rb_define_method(rb_cSlob, "open", slob_open, -1);
2950
- rb_define_method(rb_cSlob, "close", slob_close, 0);
2951
- rb_define_method(rb_cSlob, "read", slob_read, 1);
2952
- rb_define_method(rb_cSlob, "write", slob_write, 1);
2953
- rb_define_method(rb_cSlob, "seek", slob_seek, 2);
2954
- rb_define_method(rb_cSlob, "tell", slob_tell, 0);
2955
- rb_define_method(rb_cSlob, "truncate", slob_truncate, 1);
3745
+ rb_define_method(rb_cSlob, "initialize", rb_slob_initialize, -1);
3746
+ rb_define_singleton_method(rb_cSlob, "new", rb_slob_s_new, -1);
3747
+ rb_define_method(rb_cSlob, "open", rb_slob_open, -1);
3748
+ rb_define_method(rb_cSlob, "close", rb_slob_close, 0);
3749
+ rb_define_method(rb_cSlob, "read", rb_slob_read, 1);
3750
+ rb_define_method(rb_cSlob, "write", rb_slob_write, 1);
3751
+ rb_define_method(rb_cSlob, "seek", rb_slob_seek, 2);
3752
+ rb_define_method(rb_cSlob, "tell", rb_slob_tell, 0);
3753
+ rb_define_alias(rb_cSlob, "pos", "tell");
3754
+ rb_define_method(rb_cSlob, "pos=", rb_slob_set_pos, 1);
3755
+ rb_define_method(rb_cSlob, "truncate", rb_slob_truncate, 1);
3756
+ rb_define_method(rb_cSlob, "stat", rb_slob_stat, 0);
3757
+ rb_define_method(rb_cSlob, "<<", rb_slob_addstr, 1);
3758
+ rb_define_method(rb_cSlob, "rewind", rb_slob_rewind, 0);
3759
+ rb_define_method(rb_cSlob, "lock", rb_slob_lock, 4);
3760
+ rb_define_method(rb_cSlob, "unlock", rb_slob_unlock, 3);
3761
+
3762
+ rb_define_method(rb_cSlob, "atime", rb_slob_atime, 0);
3763
+ rb_define_method(rb_cSlob, "ctime", rb_slob_ctime, 0);
3764
+ rb_define_method(rb_cSlob, "mtime", rb_slob_mtime, 0);
3765
+ rb_define_method(rb_cSlob, "refcnt", rb_slob_refcnt, 0);
3766
+ rb_define_method(rb_cSlob, "size", rb_slob_size, 0);
3767
+
3768
+ rb_define_method(rb_cSlob, "estbytes", rb_slob_estbytes, 0);
3769
+ rb_define_method(rb_cSlob, "extsz", rb_slob_extsz, 0);
3770
+ rb_define_method(rb_cSlob, "flags", rb_slob_flags, 0);
3771
+ rb_define_method(rb_cSlob, "maxbytes", rb_slob_maxbytes, 0);
3772
+ rb_define_method(rb_cSlob, "sbspace", rb_slob_sbspace, 0);
3773
+
3774
+ rb_define_method(rb_cSlob, "extsz=", rb_slob_set_extsz, 1);
3775
+ rb_define_method(rb_cSlob, "flags=", rb_slob_set_flags, 1);
2956
3776
 
2957
3777
  rb_define_const(rb_cSlob, "CLOB", INT2FIX(XID_CLOB));
2958
3778
  rb_define_const(rb_cSlob, "BLOB", INT2FIX(XID_BLOB));
2959
3779
 
2960
3780
  #define DEF_SLOB_CONST(k) rb_define_const(rb_cSlob, #k, INT2FIX(LO_##k))
2961
3781
 
3782
+ /* Access modes */
2962
3783
  DEF_SLOB_CONST(RDONLY);
2963
3784
  DEF_SLOB_CONST(DIRTY_READ);
2964
3785
  DEF_SLOB_CONST(WRONLY);
@@ -2972,25 +3793,58 @@ void Init_informix(void)
2972
3793
  DEF_SLOB_CONST(SEEK_CUR);
2973
3794
  DEF_SLOB_CONST(SEEK_END);
2974
3795
 
3796
+ /* Creation-time flags */
3797
+ DEF_SLOB_CONST(LOG);
3798
+ DEF_SLOB_CONST(NOLOG);
3799
+ DEF_SLOB_CONST(KEEP_LASTACCESS_TIME);
3800
+ DEF_SLOB_CONST(NOKEEP_LASTACCESS_TIME);
3801
+
3802
+ /* Ranges */
3803
+ DEF_SLOB_CONST(CURRENT_END);
3804
+ DEF_SLOB_CONST(MAX_END);
3805
+
3806
+ /* Lock modes */
3807
+ DEF_SLOB_CONST(SHARED_MODE);
3808
+ DEF_SLOB_CONST(EXCLUSIVE_MODE);
3809
+
3810
+ /* class Slob::Stat --------------------------------------------------- */
3811
+
3812
+ rb_cSlobStat = rb_define_class_under(rb_cSlob, "Stat", rb_cObject);
3813
+ rb_define_alloc_func(rb_cSlobStat, slobstat_alloc);
3814
+ rb_define_method(rb_cSlobStat, "initialize", rb_slobstat_initialize, 1);
3815
+
3816
+ rb_include_module(rb_cSlobStat, rb_mComparable);
3817
+ rb_define_method(rb_cSlobStat, "<=>", rb_slobstat_cmp, 1);
3818
+
3819
+ rb_define_method(rb_cSlobStat, "atime", rb_slobstat_atime, 0);
3820
+ rb_define_method(rb_cSlobStat, "ctime", rb_slobstat_ctime, 0);
3821
+ rb_define_method(rb_cSlobStat, "mtime", rb_slobstat_mtime, 0);
3822
+ rb_define_method(rb_cSlobStat, "refcnt", rb_slobstat_refcnt, 0);
3823
+ rb_define_method(rb_cSlobStat, "size", rb_slobstat_size, 0);
3824
+
2975
3825
  /* class Database ----------------------------------------------------- */
2976
3826
  rb_cDatabase = rb_define_class_under(rb_mInformix, "Database", rb_cObject);
2977
3827
  rb_define_alloc_func(rb_cDatabase, database_alloc);
2978
- rb_define_method(rb_cDatabase, "initialize", database_initialize, -1);
2979
- rb_define_alias(rb_cDatabase, "open", "initialize");
2980
- rb_define_method(rb_cDatabase, "close", database_close, 0);
2981
- rb_define_method(rb_cDatabase, "immediate", database_immediate, 1);
3828
+ rb_define_method(rb_cDatabase, "initialize", rb_database_initialize, -1);
3829
+ rb_define_singleton_method(rb_cDatabase, "open", rb_database_s_open, -1);
3830
+ rb_define_alias(rb_cDatabase, "new", "open");
3831
+ rb_define_method(rb_cDatabase, "close", rb_database_close, 0);
3832
+ rb_define_alias(rb_cDatabase, "disconnect", "close");
3833
+ rb_define_method(rb_cDatabase, "immediate", rb_database_immediate, 1);
2982
3834
  rb_define_alias(rb_cDatabase, "do", "immediate");
2983
- rb_define_method(rb_cDatabase, "rollback", database_rollback, 0);
2984
- rb_define_method(rb_cDatabase, "commit", database_commit, 0);
2985
- rb_define_method(rb_cDatabase, "transaction", database_transaction, 0);
2986
- rb_define_method(rb_cDatabase, "prepare", database_prepare, 1);
2987
- rb_define_method(rb_cDatabase, "columns", database_columns, 1);
2988
- rb_define_method(rb_cDatabase, "cursor", database_cursor, -1);
3835
+ rb_define_method(rb_cDatabase, "rollback", rb_database_rollback, 0);
3836
+ rb_define_method(rb_cDatabase, "commit", rb_database_commit, 0);
3837
+ rb_define_method(rb_cDatabase, "transaction", rb_database_transaction, 0);
3838
+ rb_define_method(rb_cDatabase, "prepare", rb_database_prepare, 1);
3839
+ rb_define_method(rb_cDatabase, "columns", rb_database_columns, 1);
3840
+ rb_define_method(rb_cDatabase, "cursor", rb_database_cursor, -1);
3841
+ rb_define_method(rb_cDatabase, "slob", rb_database_slob, -1);
2989
3842
 
2990
3843
  /* class Statement ---------------------------------------------------- */
2991
3844
  rb_cStatement = rb_define_class_under(rb_mInformix, "Statement", rb_cObject);
2992
3845
  rb_define_alloc_func(rb_cStatement, statement_alloc);
2993
3846
  rb_define_method(rb_cStatement, "initialize", statement_initialize, 2);
3847
+ rb_define_singleton_method(rb_cStatement, "new", statement_s_new, -1);
2994
3848
  rb_define_method(rb_cStatement, "[]", statement_call, -1);
2995
3849
  rb_define_alias(rb_cStatement, "call", "[]");
2996
3850
  rb_define_alias(rb_cStatement, "execute", "[]");
@@ -3047,7 +3901,8 @@ void Init_informix(void)
3047
3901
  /* class Cursor ------------------------------------------------------- */
3048
3902
  rb_cCursor = rb_define_class_under(rb_mInformix, "Cursor", rb_cObject);
3049
3903
  rb_define_alloc_func(rb_cCursor, cursor_alloc);
3050
- rb_define_method(rb_cCursor, "initialize", cursor_initialize, 3);
3904
+ rb_define_method(rb_cCursor, "initialize", cursor_initialize, -1);
3905
+ rb_define_singleton_method(rb_cCursor, "open", cursor_s_open, -1);
3051
3906
  rb_define_method(rb_cCursor, "id", cursor_id, 0);
3052
3907
  rb_define_method(rb_cCursor, "open", cursor_open, -1);
3053
3908
  rb_define_method(rb_cCursor, "close", cursor_close, 0);
@@ -3056,20 +3911,15 @@ void Init_informix(void)
3056
3911
  /* Global constants --------------------------------------------------- */
3057
3912
  rb_require("date");
3058
3913
  rb_cDate = rb_const_get(rb_cObject, rb_intern("Date"));
3914
+ rb_require("bigdecimal");
3915
+ rb_cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
3059
3916
 
3060
3917
  /* Global symbols ----------------------------------------------------- */
3061
- s_read = rb_intern("read");
3062
- s_new = rb_intern("new");
3063
- s_utc = rb_intern("utc");
3064
- s_day = rb_intern("day");
3065
- s_month = rb_intern("month");
3066
- s_year = rb_intern("year");
3067
- s_hour = rb_intern("hour");
3068
- s_min = rb_intern("min");
3069
- s_sec = rb_intern("sec");
3070
- s_usec = rb_intern("usec");
3071
- s_to_s = rb_intern("to_s");
3072
- s_to_i = rb_intern("to_i");
3918
+ #define INTERN(sym) s_##sym = rb_intern(#sym)
3919
+ INTERN(read); INTERN(new);
3920
+ INTERN(utc); INTERN(day); INTERN(month); INTERN(year);
3921
+ INTERN(hour); INTERN(min); INTERN(sec); INTERN(usec);
3922
+ INTERN(to_s); INTERN(to_i);
3073
3923
 
3074
3924
  sym_name = ID2SYM(rb_intern("name"));
3075
3925
  sym_type = ID2SYM(rb_intern("type"));
@@ -3090,4 +3940,7 @@ void Init_informix(void)
3090
3940
  sym_extsz = ID2SYM(rb_intern("extsz"));
3091
3941
  sym_createflags = ID2SYM(rb_intern("createflags"));
3092
3942
  sym_openflags = ID2SYM(rb_intern("openflags"));
3943
+ sym_maxbytes = ID2SYM(rb_intern("maxbytes"));
3944
+
3945
+ sym_params = ID2SYM(rb_intern("params"));
3093
3946
  }