ruby-informix 0.6.2-i386-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/COPYRIGHT +26 -0
  2. data/Changelog +198 -0
  3. data/README +85 -0
  4. data/ifx_except.c +522 -0
  5. data/informix.c +5021 -0
  6. data/informix.so +0 -0
  7. metadata +53 -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,198 @@
1
+ 0.6.2 10/20/2007
2
+ ------------------
3
+ Bugs fixed:
4
+ * Microsoft's cl compiler was failing due to a variable declaration
5
+ where it is not allowed.
6
+
7
+ Noticed by Joe Lanotte <joe.lanotte at comcast dot net>
8
+
9
+
10
+ 0.6.1 10/13/2007
11
+ ------------------
12
+ Bugs fixed:
13
+ * Database#columns was returning an empty array from within the
14
+ Informix ActiveRecord adapter
15
+ (ActiveRecord::ConnectionAdapters::InformixAdapter#columns) if
16
+ called for different tables. This bug was raising the following
17
+ error in Ruby on Rails:
18
+
19
+ undefined method columname=
20
+
21
+ Noticed by Andr�s Rafael <aandresrafael at gmail dot com>
22
+
23
+
24
+ 0.6.0 08/28/2007
25
+ ------------------
26
+ New features:
27
+ * Test suite
28
+ * Error, Warning, and AssertionFailure classes replace RuntimeError when
29
+ raising exceptions.
30
+
31
+ Error class methods:
32
+ - message
33
+ - sql_code
34
+ - add_info
35
+ - []
36
+ - each
37
+ - to_s
38
+ - size, length
39
+
40
+ message and sql_code reference the first error message. Following
41
+ errors can be accessed through Error#[] as ExcInfo objects.
42
+
43
+ ExcInfo is a Struct with the following members:
44
+ - sql_code
45
+ - sql_state
46
+ - class_origin_val
47
+ - subclass_origin_val
48
+ - message
49
+ - server_name
50
+ - connection_name
51
+
52
+ See test/testcase.rb for a simple example of exception handling.
53
+
54
+ * Informix.version returns the version of this extension
55
+ * Database#do aliased as Database#execute
56
+ * More documentation
57
+
58
+ Remarks:
59
+ * Database#do is deprecated and will be removed in next versions. Use
60
+ Database#execute or Database#immediate instead.
61
+
62
+ * In case of Informix errors, RuntimeError objects are no longer raised.
63
+ Error, Warning and AssertionFailure objects are raised instead.
64
+
65
+
66
+ Acknowledgments:
67
+ I want to thank Edwin Fine <emofine at finecomputerconsultants dot com>
68
+ who contributed all the functionality of this release.
69
+
70
+
71
+ 0.5.1 08/10/2007
72
+ ------------------
73
+ Bugs fixed:
74
+ * When a DATETIME HOUR TO SECOND column had a value with leading zeroes
75
+ it was incorrectly interpreted.
76
+ Reported by Daniel Bush <dlb.id.au at gmail>
77
+
78
+
79
+ 0.5.0 12/27/2006
80
+ ------------------
81
+ New features:
82
+ * Easier to install
83
+ * BigDecimal accepted for input parameters
84
+ * BigDecimal used for instantiating DECIMAL and MONEY values
85
+ * Cursor, Statement, Slob and Database accept an optional block that
86
+ automatically frees resources after execution.
87
+ Based on ideas and pseudo-code by
88
+ Edwin Fine <emofine at finecomputerconsultants dot com> and me.
89
+ * Database#slob shortcut for creating Slob objects.
90
+ * Slob::Stat class implemented. Returned by Slob#stat, represents the
91
+ SLOB status. Methods: atime, ctime, mtime, refcnt and size. Includes
92
+ Comparable.
93
+ * Slob new methods: <<, rewind, stat, pos, pos=, lock, unlock,
94
+ estbytes, extsz, flags, maxbytes, sbspace,
95
+ extsz=, flags=,
96
+ atime, ctime, mtime, refcnt and size
97
+ * Thread safe
98
+
99
+ Remarks:
100
+ * DECIMAL and MONEY columns are no longer returned as Float. BigDecimal
101
+ is used instead.
102
+
103
+ Bugs fixed:
104
+ * If there was an error reading (ifx_lo_read) an SLOB, memory
105
+ allocated for the read buffer was not freed. Noticed by
106
+ Edwin Fine <emofine at finecomputerconsultants dot com>
107
+ * maxbytes option was ignored when creating an Slob object
108
+ * Documentation for Slob mentioned an RDRW constant, but it actually
109
+ is RDWR.
110
+
111
+ Special thanks to Guy Bowerman, Jonathan Leffler and Logan Capaldo for their
112
+ feedback and help.
113
+
114
+
115
+ 0.4.0 12/13/2006
116
+ ------------------
117
+ New features:
118
+ * Support for multiple connections to databases
119
+ * Support for scroll cursors. Methods available:
120
+ - [], slice
121
+ - prev, next, first, last, current
122
+ - prev_hash, next_hash, first_hash, last_hash, current_hash
123
+ - slice!, prev!, next!, first!, last!, current!
124
+ - slice_hash, prev_hash, next_hash, first_hash, last_hash,
125
+ current_hash!
126
+ - slice_hash!, prev_hash!, next_hash!, first_hash!, last_hash!,
127
+ current_hash!
128
+ * New Cursor#id method that returns the cursor name for use in
129
+ update cursors
130
+
131
+ Bugs fixed:
132
+ * Memory for input parameters was allocated before statement/cursor
133
+ preparation but not freed if preparation failed.
134
+
135
+
136
+ 0.3.0 11/26/2006
137
+ ------------------
138
+ New features:
139
+ * Initial support for Smart Large Objects (BLOB/CLOB).
140
+ Operations supported:
141
+ - new
142
+ - open, close
143
+ - read, write
144
+ - seek, tell
145
+ - truncate
146
+ * Database#columns now also returns the extended id (xid)
147
+ * small documentation improvements and fixes
148
+
149
+
150
+ 0.2.1 11/11/2006
151
+ ------------------
152
+ Bugs fixed:
153
+ * changing free() for xfree() avoids crashes on Windows XP SP1. Noticed
154
+ by Dinko <dsrkoc at helix dot hr>
155
+
156
+
157
+ 0.2.0 04/24/2006
158
+ ------------------
159
+ New features:
160
+ * Methods added to SequentialCursor:
161
+
162
+ - fetch_hash_many(n), fetch_hash_all
163
+ - each_by(n), each_hash_by(n)
164
+ - fetch!, fetch_hash!, each!, each_hash!
165
+
166
+ where !-methods reduce object creation by reusing the same result
167
+ object in each call
168
+
169
+ Remarks:
170
+ * fetch*many and fetch*all methods now return [] instead of nil when
171
+ no records are found
172
+
173
+ Bugs fixed:
174
+ * When freeing a cursor that was opened but never used, a segmentation
175
+ fault occurred
176
+
177
+
178
+ 0.1.0 04/10/2006
179
+ -------------------
180
+ Features:
181
+ * Support for all built-in data types, except INTERVAL
182
+ * immediate statements
183
+ * prepared statements
184
+ * select cursors and bulk inserts (insert cursors)
185
+ * transactions
186
+ * #columns method for retrieving column information
187
+ * rows retrieved as arrays or hashes
188
+ * IO-based and IO-like (StringIO) objects for storing a BYTE/TEXT
189
+ column, and retrieved as a String object
190
+ * NULL, DATE and DATETIME mapped to nil, Date and Time objects and
191
+ viceversa
192
+ * #drop method for freeing Informix resources immediatly
193
+ * source code documented with RDoc
194
+
195
+ Caveats:
196
+ * INTERVAL not supported
197
+ * cursors must be closed before reopening them
198
+ * only one open connection at a time is supported
data/README ADDED
@@ -0,0 +1,85 @@
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 10 SPARC64 11.10.UC1 3.00UC2
22
+ Solaris 10 SPARC64 9.40FC6 3.00UC2
23
+ Solaris 9 SPARC64 9.40FC6 2.90UC3
24
+ Fedora Core 5 x86 10.00.UC3R1 2.90UC4
25
+ Fedora Core 4 x86 10.00.UC3R1 2.90UC4
26
+ SuSE Linux 9.3 x86 9.30TC1 2.90UC4
27
+ Gentoo Linux x86-64 7.32.HC1 2.90UC4
28
+ Windows XP Pro SP x86 9.40TC3 2.90TC1
29
+ Windows XP x86 9.30TC1 2.90TC4
30
+ HP-UX 11.11 PA-RISC 2.0 10.00.FC3R1TL 2.81
31
+ 64-bit
32
+
33
+ Send me an e-mail if you have [un]succesfully tested Ruby/Informix on another
34
+ platform.
35
+
36
+
37
+ 2. Documentation
38
+
39
+ Documentation generated by RDoc for each class, module and method can be found
40
+ under the doc/ directory in this distribution and at the following web address:
41
+
42
+ http://ruby-informix.rubyforge.org/doc/
43
+
44
+ Examples of use can be found at:
45
+
46
+ http://ruby-informix.rubyforge.org
47
+
48
+
49
+ 3. Data types
50
+
51
+ All built-in data types are supported, except interval. As you would expect,
52
+ numeric, string and boolean data types are mapped to their respective objects
53
+ in Ruby; DECIMAL/MONEY, DATE, DATETIME and NULL are mapped to BigDecimal, Date,
54
+ Time and nil respectively.
55
+
56
+ The notable exception is TEXT/BYTE columns, where Ruby/Informix expects an
57
+ IO-based (File) or IO-like (StringIO) object as input, and returns an String
58
+ object as output.
59
+
60
+ An Slob class exists in the Informix module for working with Smart Large
61
+ Objects (CLOB/BLOB).
62
+
63
+
64
+ 4. Recommendations
65
+
66
+ * use #drop for prepared statements and cursors or use them with blocks,
67
+ to release Informix resources.
68
+ * you can optimize cursor execution by changing the size of fetch and insert
69
+ buffers, setting the environment variable FET_BUF_SIZE to up to 32767.
70
+
71
+
72
+ 5. Caveats
73
+
74
+ * INTERVAL not implemented yet
75
+
76
+ 6. Support
77
+
78
+ Feel free to send me bug reports, feature requests, comments, patches or
79
+ questions to my mailbox or Ruby/Informix's forums and mailing list at
80
+ Rubyforge (http://rubyforge.org/projects/ruby-informix/)
81
+
82
+
83
+ -----------------------------------------
84
+ Gerardo Santana <gerardo.santana gmail>
85
+ http://santanatechnotes.blogspot.com
data/ifx_except.c ADDED
@@ -0,0 +1,522 @@
1
+ #include <sqlhdr.h>
2
+ #include <sqliapi.h>
3
+ #line 1 "ifx_except.ec"
4
+ /* $Id: ifx_except.ec,v 1.2 2007/10/20 10:17:35 santana Exp $ */
5
+ /*
6
+ * Copyright (c) 2006, 2007 Edwin M. Fine <efine@finecomputerconsultants.com>
7
+ * All rights reserved.
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted provided that the following conditions
11
+ * are met:
12
+ *
13
+ * 1. Redistributions of source code must retain the above copyright
14
+ * notice, this list of conditions and the following disclaimer.
15
+ * 2. Redistributions in binary form must reproduce the above copyright
16
+ * notice, this list of conditions and the following disclaimer in the
17
+ * documentation and/or other materials provided with the distribution.
18
+ * 3. The name of the author may not be used to endorse or promote products
19
+ * derived from this software without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ * POSSIBILITY OF SUCH DAMAGE.
32
+ */
33
+
34
+ #include "ifx_except.h"
35
+ #include "ifx_assert.h"
36
+
37
+ #include <ruby.h>
38
+ #include <stdlib.h>
39
+ #include <stdio.h>
40
+ #include <sqlstype.h>
41
+ #include <sqltypes.h>
42
+
43
+ /* Convenience macros */
44
+ #define TRIM_BLANKS(s) ((s)[byleng(s, stleng(s))] = '\0')
45
+ #define NUM_ELEMS(arr) (sizeof(arr) / sizeof(*arr))
46
+
47
+ /* Future use: definition of interpretation of sql_state */
48
+ #define IS_SQL_SUCCESS(sql_state) ((sql_state)[0] == '0' && (sql_state)[1] == '0')
49
+ #define IS_SQL_WARNING(sql_state) ((sql_state)[0] == '0' && (sql_state)[1] == '1')
50
+ #define IS_SQL_NO_DATA_FOUND(sql_state) ((sql_state)[0] == '0' && (sql_state)[1] == '2')
51
+ #define IS_SQL_ERROR(sql_state) ((sql_state)[0] > '0' || (sql_state)[1] > '2')
52
+
53
+ /* Constants */
54
+ #define NUM_SQL_EXCEPTION_ARGS 7 /* Number of things we get from GET EXCEPTION */
55
+
56
+ static const char * const vcs_id = "$Id: ifx_except.ec,v 1.2 2007/10/20 10:17:35 santana Exp $";
57
+
58
+ /*
59
+ * Ruby object/class/module handles
60
+ */
61
+ static ifx_except_symbols_t sym;
62
+
63
+ /**
64
+ * Implementation
65
+ */
66
+
67
+ /* class Informix::Error ------------------------------------------------ */
68
+
69
+ /**
70
+ * call-seq:
71
+ * Informix::Error.new([string|array]) => obj
72
+ *
73
+ * Optional string is the exception message.
74
+ * Optional array must contain only instances of Informix::ExcInfo structs.
75
+ *
76
+ * Examples:
77
+ * exc = Informix::Error.new
78
+ * arr = [ExcInfo.new(x,y,z...), ExcInfo.new(a,b,c...)]
79
+ * exc = Informix::Error.new(arr)
80
+ */
81
+ static VALUE ifx_exc_init(int argc, VALUE *argv, VALUE self)
82
+ {
83
+ VALUE arr;
84
+ VALUE arg;
85
+
86
+ if (rb_scan_args(argc, argv, "01", &arg) == 0) {
87
+ arr = rb_ary_new();
88
+ }
89
+ else if (TYPE(arg) == T_STRING) {
90
+ arr = rb_ary_new();
91
+ rb_call_super(argc, argv);
92
+ }
93
+ else if (TYPE(arg) == T_ARRAY) {
94
+ arr = arg;
95
+ if (RARRAY(arg)->len > 0) {
96
+ long i;
97
+ for (i = 0; i < RARRAY(arg)->len; ++i)
98
+ if (!rb_obj_is_instance_of(rb_ary_entry(arg, i), sym.sExcInfo))
99
+ rb_raise(rb_eTypeError, "Array may contain only Informix::ExcInfo structs");
100
+ }
101
+ }
102
+ else {
103
+ rb_raise(rb_eTypeError,
104
+ "Expected string, or array of Informix::ExcInfo, as argument");
105
+ }
106
+
107
+ rb_iv_set(self, "@info", arr);
108
+
109
+ return self;
110
+ }
111
+
112
+ /* Implementation note:
113
+ * argv must contain the following values in the order given:
114
+ * sql_code FIXNUM
115
+ * sql_state STRING
116
+ * class_origin STRING
117
+ * subclass_origin STRING
118
+ * message STRING
119
+ * server_name STRING
120
+ * connection_name STRING
121
+ */
122
+
123
+ /**
124
+ * call-seq:
125
+ * exc.add_info(sql_code, sql_state, class_origin, subclass_origin, message, server_name, connection_name) => self
126
+ *
127
+ * Appends the given information to the exception.
128
+ */
129
+ static VALUE ifx_exc_add_info(int argc, VALUE *argv, VALUE self)
130
+ {
131
+ VALUE info_arr = rb_iv_get(self, "@info");
132
+ VALUE sInfo;
133
+
134
+ #if defined(DEBUG)
135
+ printf("%s:%d argc = %d\n", "ifx_exc_add_info", __LINE__, argc);
136
+ #endif
137
+
138
+ if (argc != NUM_SQL_EXCEPTION_ARGS)
139
+ rb_raise(rb_eArgError, "Invalid number of arguments (got %d, need %d)", argc, NUM_SQL_EXCEPTION_ARGS);
140
+ if (info_arr == Qnil) { /* Add the array if missing */
141
+ info_arr = rb_ary_new();
142
+ rb_iv_set(self, "@info", info_arr);
143
+ }
144
+
145
+ sInfo =
146
+ rb_struct_new(sym.sExcInfo,
147
+ argv[0], argv[1], argv[2], argv[3],
148
+ argv[4], argv[5], argv[6], NULL);
149
+
150
+ /* Add the new struct instance to end of our array */
151
+ rb_ary_push(info_arr, sInfo);
152
+
153
+ return self;
154
+ }
155
+
156
+ /**
157
+ * call-seq:
158
+ * exc.size => num
159
+ *
160
+ * Returns the number of Informix exception messages in the exception.
161
+ */
162
+ static VALUE ifx_exc_size(VALUE self)
163
+ {
164
+ VALUE info_arr = rb_iv_get(self, "@info");
165
+ return info_arr != Qnil ? LONG2NUM(RARRAY(info_arr)->len) : Qnil;
166
+ }
167
+
168
+ /**
169
+ * call-seq:
170
+ * exc.each {|exc_info| block } => exc_info
171
+ *
172
+ * Calls block once for each Informix::ExcInfo object in the exception.
173
+ */
174
+ static VALUE ifx_exc_each(VALUE self)
175
+ {
176
+ VALUE info_arr = rb_iv_get(self, "@info");
177
+ return info_arr != Qnil ? rb_iterate(rb_each, info_arr, rb_yield, 0) : Qnil;
178
+ }
179
+
180
+ /**
181
+ * call-seq:
182
+ * exc.at(index) => info
183
+ *
184
+ * Returns the ExcInfo object at index.
185
+ */
186
+ static VALUE ifx_exc_at(VALUE self, VALUE index)
187
+ {
188
+ VALUE info_arr = rb_iv_get(self, "@info");
189
+ long n = NUM2LONG(rb_Integer(index));
190
+
191
+ #if defined(DEBUG)
192
+ printf("Getting value at %ld\n", n);
193
+ #endif
194
+
195
+ return info_arr != Qnil ? rb_ary_entry(info_arr, n) : Qnil;
196
+ }
197
+
198
+ /**
199
+ * call-seq:
200
+ * exc.to_s => string
201
+ *
202
+ * Returns a string representation of self.
203
+ */
204
+ static VALUE ifx_exc_to_s(VALUE self)
205
+ {
206
+ const VALUE nl = rb_str_new2("\n");
207
+ VALUE s;
208
+ VALUE info_arr = rb_iv_get(self, "@info");
209
+ long info_arr_len;
210
+ VALUE sInfo;
211
+ long i;
212
+ size_t j;
213
+
214
+ info_arr_len = info_arr == Qnil ? 0 : RARRAY(info_arr)->len;
215
+
216
+ if (info_arr_len > 0) {
217
+ VALUE fmt_str = rb_str_new2("%-15s: %s\n");
218
+
219
+ ID fields[] = { /* Fields will be displayed in this order */
220
+ sym.id_message,
221
+ sym.id_sql_code,
222
+ sym.id_sql_state,
223
+ sym.id_class_origin,
224
+ sym.id_subclass_origin,
225
+ sym.id_server_name,
226
+ sym.id_connection_name
227
+ };
228
+
229
+ s = rb_str_new2("\n");
230
+
231
+ for (i = 0; i < info_arr_len; ++i) {
232
+ sInfo = RARRAY(info_arr)->ptr[i];
233
+
234
+ for (j = 0; j < NUM_ELEMS(fields); ++j) {
235
+ ID field = fields[j];
236
+ VALUE struct_ref = rb_struct_getmember(sInfo, field);
237
+ VALUE item_value = rb_String(struct_ref);
238
+ VALUE args[] = { fmt_str, rb_String(ID2SYM(field)), item_value };
239
+
240
+ if (RSTRING(item_value)->len != 0) { /* Skip empty fields */
241
+ rb_str_concat(s, rb_f_sprintf(NUM_ELEMS(args), args));
242
+ }
243
+ }
244
+
245
+ rb_str_concat(s, nl);
246
+ }
247
+ }
248
+ else { /* Call super's to_s */
249
+ s = rb_call_super(0, 0);
250
+ }
251
+
252
+ return s;
253
+ }
254
+
255
+ /**
256
+ * Overrides Exception#message. Returns first message in ExcInfo array,
257
+ * or if the array is empty, delegates back to the parent class.
258
+ */
259
+ static VALUE ifx_exc_message(VALUE self)
260
+ {
261
+ VALUE info_arr = rb_iv_get(self, "@info");
262
+
263
+ return (info_arr != Qnil && RARRAY(info_arr)->len > 0)
264
+ ? rb_struct_getmember(RARRAY(info_arr)->ptr[0], sym.id_message)
265
+ : rb_call_super(0, 0);
266
+ }
267
+
268
+ /**
269
+ * call-seq:
270
+ * exc.sqlcode => fixnum
271
+ *
272
+ * Returns the SQLCODE for the first stored ExcInfo struct, or 0
273
+ * if none are stored.
274
+ */
275
+ static VALUE ifx_exc_sql_code(VALUE self)
276
+ {
277
+ VALUE info_arr = rb_iv_get(self, "@info");
278
+
279
+ return (info_arr != Qnil && RARRAY(info_arr)->len > 0)
280
+ ? rb_struct_getmember(RARRAY(info_arr)->ptr[0], sym.id_sql_code)
281
+ : INT2FIX(0);
282
+ }
283
+
284
+ /*
285
+ * C helper functions (see ifx_except.h for documentation)
286
+ */
287
+ void raise_ifx_extended(void)
288
+ {
289
+ rb_exc_raise(rbifx_ext_exception(sym.eDatabaseError));
290
+ }
291
+
292
+ VALUE rbifx_ext_exception(VALUE exception_class)
293
+ {
294
+ VALUE new_instance;
295
+
296
+ /*
297
+ * EXEC SQL BEGIN DECLARE SECTION;
298
+ */
299
+ #line 293 "ifx_except.ec"
300
+ #line 294 "ifx_except.ec"
301
+ int4 sql_code;
302
+ char sql_state[6];
303
+ char class_origin_val[256];
304
+ char subclass_origin_val[256];
305
+ char message[8192];
306
+ char server_name[256];
307
+ char connection_name[256];
308
+ mint sql_exception_number;
309
+ mint exc_count = 0;
310
+ mint message_len;
311
+ mint i;
312
+ /*
313
+ * EXEC SQL END DECLARE SECTION;
314
+ */
315
+ #line 308 "ifx_except.ec"
316
+
317
+
318
+ new_instance = rb_class_new_instance(0, 0, exception_class);
319
+
320
+ /* Check that instance of exception_class is derived from
321
+ * Informix::Error
322
+ */
323
+ if (!rb_obj_is_kind_of(new_instance, sym.eError) &&
324
+ !rb_obj_is_kind_of(new_instance, sym.eWarning)) {
325
+ rb_raise(rb_eRuntimeError,
326
+ "Can't instantiate exception from %s, only from %s or %s or their children",
327
+ rb_class2name(exception_class),
328
+ rb_class2name(sym.eWarning),
329
+ rb_class2name(sym.eError));
330
+ }
331
+
332
+ /*
333
+ * EXEC SQL GET DIAGNOSTICS :exc_count = NUMBER;
334
+ */
335
+ #line 324 "ifx_except.ec"
336
+ {
337
+ #line 324 "ifx_except.ec"
338
+ static ifx_hostvar_t _SQhtab[] =
339
+ {
340
+ { 0, 1, 102, sizeof(exc_count), 0, 0, 0, 0 },
341
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
342
+ #line 324 "ifx_except.ec"
343
+ };
344
+ _SQhtab[0].hostaddr = (char *)&exc_count;
345
+ #line 324 "ifx_except.ec"
346
+ sqli_diag_get(ESQLINTVERSION, _SQhtab, -1);
347
+ #line 324 "ifx_except.ec"
348
+ }
349
+
350
+ if (exc_count == 0) { /* Something went wrong */
351
+ char message[128];
352
+ snprintf(message,
353
+ sizeof(message),
354
+ "SQL ERROR: SQLCODE %d (sorry, no GET DIAGNOSTICS information available)",
355
+ SQLCODE);
356
+
357
+ {
358
+ VALUE argv[] = { rb_str_new2(message) };
359
+ return rb_class_new_instance(NUM_ELEMS(argv), argv, sym.eOperationalError);
360
+ }
361
+ }
362
+
363
+ for (i = 0; i < exc_count; ++i) {
364
+ sql_exception_number = i + 1;
365
+
366
+ /*
367
+ * EXEC SQL GET DIAGNOSTICS EXCEPTION :sql_exception_number
368
+ * :sql_code = INFORMIX_SQLCODE,
369
+ * :sql_state = RETURNED_SQLSTATE,
370
+ * :class_origin_val = CLASS_ORIGIN,
371
+ * :subclass_origin_val = SUBCLASS_ORIGIN,
372
+ * :message = MESSAGE_TEXT,
373
+ * :message_len = MESSAGE_LENGTH,
374
+ * :server_name = SERVER_NAME,
375
+ * :connection_name = CONNECTION_NAME
376
+ * ;
377
+ */
378
+ #line 342 "ifx_except.ec"
379
+ {
380
+ #line 351 "ifx_except.ec"
381
+ static ifx_hostvar_t _SQhtab[] =
382
+ {
383
+ { 0, 11, 103, sizeof(sql_code), 0, 0, 0, 0 },
384
+ { 0, 3, 100, 6, 0, 0, 0, 0 },
385
+ { 0, 4, 100, 256, 0, 0, 0, 0 },
386
+ { 0, 5, 100, 256, 0, 0, 0, 0 },
387
+ { 0, 6, 100, 8192, 0, 0, 0, 0 },
388
+ { 0, 7, 102, sizeof(message_len), 0, 0, 0, 0 },
389
+ { 0, 9, 100, 256, 0, 0, 0, 0 },
390
+ { 0, 10, 100, 256, 0, 0, 0, 0 },
391
+ { 0, 0, 0, 0, 0, 0, 0, 0 }
392
+ #line 351 "ifx_except.ec"
393
+ };
394
+ _SQhtab[0].hostaddr = (char *)&sql_code;
395
+ _SQhtab[1].hostaddr = (sql_state);
396
+ _SQhtab[2].hostaddr = (class_origin_val);
397
+ _SQhtab[3].hostaddr = (subclass_origin_val);
398
+ _SQhtab[4].hostaddr = (message);
399
+ _SQhtab[5].hostaddr = (char *)&message_len;
400
+ _SQhtab[6].hostaddr = (server_name);
401
+ _SQhtab[7].hostaddr = (connection_name);
402
+ #line 351 "ifx_except.ec"
403
+ sqli_diag_get(ESQLINTVERSION, _SQhtab, sql_exception_number);
404
+ #line 351 "ifx_except.ec"
405
+ }
406
+
407
+ TRIM_BLANKS(class_origin_val);
408
+ TRIM_BLANKS(subclass_origin_val);
409
+ TRIM_BLANKS(server_name);
410
+ TRIM_BLANKS(connection_name);
411
+ message[message_len - 1] = '\0';
412
+ TRIM_BLANKS(message);
413
+
414
+ {
415
+ VALUE sprintf_args[] = { rb_str_new2(message), rb_str_new2(sqlca.sqlerrm) };
416
+ VALUE argv[] = {
417
+ INT2FIX(sql_code),
418
+ rb_str_new2(sql_state),
419
+ rb_str_new2(class_origin_val),
420
+ rb_str_new2(subclass_origin_val),
421
+ rb_f_sprintf(NUM_ELEMS(sprintf_args), sprintf_args),
422
+ rb_str_new2(server_name),
423
+ rb_str_new2(connection_name)
424
+ };
425
+
426
+ ifx_exc_add_info(NUM_ELEMS(argv), argv, new_instance);
427
+ }
428
+ }
429
+
430
+ return new_instance;
431
+ }
432
+
433
+ /**
434
+ * Raises Informix::AssertionFailure exception
435
+ */
436
+ void ifx_assertion_exception(const char *failure_type,
437
+ const char *what_failed,
438
+ const char *file,
439
+ int line)
440
+ {
441
+ VALUE sprintf_args[] = {
442
+ rb_str_new2("%s failed on line %d of file %s: %s"),
443
+ rb_str_new2(failure_type),
444
+ INT2FIX(line),
445
+ rb_str_new2(file),
446
+ rb_str_new2(what_failed)
447
+ };
448
+
449
+ VALUE args[] = { rb_f_sprintf(NUM_ELEMS(sprintf_args), sprintf_args) };
450
+
451
+ rb_exc_raise(rb_class_new_instance(NUM_ELEMS(args), args, sym.lib_eAssertion));
452
+ }
453
+
454
+ /* Init module with shared value(s) from main informix classes */
455
+ void rbifx_except_init(VALUE mInformix, ifx_except_symbols_t *syms)
456
+ {
457
+ VALUE sym_ExcInfo;
458
+
459
+ sym.mInformix = mInformix; // Informix module object handle
460
+
461
+ /* class Error --------------------------------------------------------- */
462
+ sym.eError = rb_define_class_under(mInformix, "Error", rb_eStandardError);
463
+ sym.eWarning = rb_define_class_under(mInformix, "Warning", rb_eStandardError);
464
+
465
+ sym.eInterfaceError = rb_define_class_under(mInformix, "InterfaceError", sym.eError);
466
+ sym.eDatabaseError = rb_define_class_under(mInformix, "DatabaseError", sym.eError);
467
+ sym.eDataError = rb_define_class_under(mInformix, "DataError", sym.eError);
468
+ sym.eOperationalError = rb_define_class_under(mInformix, "OperationalError", sym.eError);
469
+ sym.eIntegrityError = rb_define_class_under(mInformix, "IntegrityError", sym.eError);
470
+ sym.eInternalError = rb_define_class_under(mInformix, "InternalError", sym.eError);
471
+ sym.eProgrammingError = rb_define_class_under(mInformix, "ProgrammingError", sym.eError);
472
+ sym.eNotSupportedError = rb_define_class_under(mInformix, "NotSupportedError", sym.eError);
473
+
474
+ /* Make base class enumerable */
475
+ rb_include_module(sym.eError, rb_mEnumerable);
476
+
477
+ /* Precondition exception class */
478
+ sym.lib_eAssertion = rb_define_class_under(mInformix, "AssertionFailure", rb_eStandardError);
479
+
480
+ rb_define_method(sym.eError, "initialize", ifx_exc_init, -1);
481
+ rb_define_method(sym.eError, "message", ifx_exc_message, 0);
482
+ rb_define_method(sym.eError, "sql_code", ifx_exc_sql_code, 0);
483
+ rb_define_method(sym.eError, "add_info", ifx_exc_add_info, -1);
484
+ rb_define_method(sym.eError, "[]", ifx_exc_at, 1);
485
+ rb_define_method(sym.eError, "each", ifx_exc_each, 0);
486
+ rb_define_method(sym.eError, "to_s", ifx_exc_to_s, 0);
487
+ rb_define_method(sym.eError, "size", ifx_exc_size, 0);
488
+ rb_define_alias(sym.eError, "length", "size");
489
+
490
+ sym_ExcInfo = rb_intern("ExcInfo");
491
+
492
+ sym.id_sql_code = rb_intern("sql_code");
493
+ sym.id_sql_state = rb_intern("sql_state");
494
+ sym.id_class_origin = rb_intern("class_origin");
495
+ sym.id_subclass_origin = rb_intern("subclass_origin");
496
+ sym.id_message = rb_intern("message");
497
+ sym.id_server_name = rb_intern("server_name");
498
+ sym.id_connection_name = rb_intern("connection_name");
499
+
500
+ /* Define ExcInfo as a struct in the Informix module */
501
+ rb_define_const(mInformix,
502
+ "ExcInfo",
503
+ rb_struct_define(NULL,
504
+ rb_id2name(sym.id_sql_code),
505
+ rb_id2name(sym.id_sql_state),
506
+ rb_id2name(sym.id_class_origin),
507
+ rb_id2name(sym.id_subclass_origin),
508
+ rb_id2name(sym.id_message),
509
+ rb_id2name(sym.id_server_name),
510
+ rb_id2name(sym.id_connection_name),
511
+ NULL));
512
+
513
+ sym.sExcInfo = rb_const_get(mInformix, sym_ExcInfo);
514
+
515
+ if (syms)
516
+ {
517
+ *syms = sym;
518
+ }
519
+ }
520
+
521
+
522
+ #line 466 "ifx_except.ec"