ruby-informix 0.6.2-i386-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYRIGHT +26 -0
- data/Changelog +198 -0
- data/README +85 -0
- data/ifx_except.c +522 -0
- data/informix.c +5021 -0
- data/informix.so +0 -0
- 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"
|