activerecord-ingres-adapter 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ee73a4b0345045c687590229b38fd5e25d272111
4
+ data.tar.gz: 683714ea31c1aa78d743b67b3194ebb742a63552
5
+ SHA512:
6
+ metadata.gz: 902d32013ec1c034d404461d40fa255b42dbacd62bef1ae81103596a949d58466b762051a9ae34df4de11aacdbd4c822c0855517fdd1c1756ffe093f08bc0eaf
7
+ data.tar.gz: aa0267a389c5c1a3e5a6f38840f8184694db859b3d02e3549c9250396443446bd21b46052a057931ae69d26c7b267616b483eb846cdee2fb70e504ee5717fc7c
data/CHANGELOG ADDED
@@ -0,0 +1,69 @@
1
+ version 1.4.1
2
+ - Fix #656 - getProcedureName() returns a non-NULL terminated procedure name
3
+ - Fix #653 - Update s.date dynamically for each release
4
+ - Fix #651 - Add support for building a Ruby Gem
5
+ - Fix #555 - SEGV when fetcing LOB data
6
+ - Fix #565 - Compilation errors with Redhat ES 5.4 (x86-64)
7
+
8
+ version 1.4.0
9
+ - Default to "id" for the :primary_key column in ActiveRecord if no
10
+ PRIMARY KEY constraint is defined
11
+ - Update the documentation using RDoc
12
+ - Add Ingres.set_environment()
13
+ - Add the ability to set the date format for ingresdate values at connection
14
+ time
15
+ - Update ingres_adapter.rb for ActiveRecord 2.3.x
16
+ - Fix #489 - librt.so should only be used on Linux
17
+ - Use IIAPI_VCH_TYPE for converting date values to their string form
18
+ - Add support for the SQL SAVEPOINT statement
19
+ - Fix a regression where certain query would return no data
20
+ - Add support for multiple active connections
21
+ - replaced all calls to ii_allocate()/ii_reallocate() with their ruby
22
+ counterparts ALLOC_N and REALLOC_N
23
+ - Except for memory allocation in getColumn()
24
+ - Added a SQL query classifier to eliminate the need to force the query into
25
+ upper case
26
+ - Moved Unicode functionality into Unicode.c and Unicode.h
27
+ - Moved defines/typedefs/function prototypes into Ingres.h
28
+ - Added new unit tests directory, see "Testing Done" for more information
29
+ - Ingres.connect() takes an optional username/password
30
+ - eliminates the need for connect_with_credentials (now an alias pointing to
31
+ connect)
32
+ - Ingres.execute() now accepts a variable number of parameters, requires query
33
+ but parameter values is optional
34
+ - Ingres.pexecute() now an alias for Ingres.execute()
35
+ - Re-formatted the code using astyle (http://astyle.sourceforge.net/)
36
+ - Added the following Ruby constants
37
+ - VERSION - version string, e.g. "1.4.0-dev"
38
+ - API_LEVEL - value for IIAPI_VERSION
39
+ - REVISION - the SVN revision for the driver
40
+ - CM_AttrTab should be defined as an extern
41
+ - Improve Ingres library and header detection _ version 1.3.0
42
+ - Add support for the null clause used in Ingres 9.1.x (and earlier)
43
+ - Change status to Beta
44
+
45
+ version 1.3.0
46
+ - Add quote_column_names() for quoting of table and column names. Required
47
+ for the ActiveRecord base unit tests
48
+ - Fix data truncation for the ActiveRecord :text type
49
+ - Add support for Ingres datatypes float4, float8, money, decimal, bigint,
50
+ and ANSI date/time/timestamp.
51
+ - Add support in ingres_adapter.rb for Rails migrations
52
+ - Restrict tables() to non-system tables
53
+
54
+ version 1.2.2
55
+ - Add an ascii README file for systems without access to a browser
56
+ - Add TODO.txt show show areas that require attention
57
+ - Add missing GPL header text to ingres_adapter.rb
58
+ - Fix quote() in ingres_adapater.rb to use the class of variable rather than
59
+ the equivalent Ingres column type.
60
+ - Fix segvio in Ingres Ruby driver when fetching char/varchar with data
61
+ longer than 4074 bytes.
62
+
63
+ version 1.2.1
64
+ - Initial release
65
+
66
+ /*
67
+ vim: ts=4 sw=4 expandtab textwidth=78
68
+ $Id$
69
+ */
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ #platforms :ruby do
6
+ # gem 'arel', '~> 5.0.0'
7
+ #end
data/LICENSE ADDED
@@ -0,0 +1,258 @@
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
4
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
5
+
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+ The licenses for most software are designed to take away your freedom
11
+ to share and change it. By contrast, the GNU General Public License is
12
+ intended to guarantee your freedom to share and change free software--to
13
+ make sure the software is free for all its users. This General Public
14
+ License applies to most of the Free Software Foundation's software and
15
+ to any other program whose authors commit to using it. (Some other Free
16
+ Software Foundation software is covered by the GNU Lesser General Public
17
+ License instead.) You can apply it to your programs, too.
18
+
19
+ When we speak of free software, we are referring to freedom, not
20
+ price. Our General Public Licenses are designed to make sure that you
21
+ have the freedom to distribute copies of free software (and charge for
22
+ this service if you wish), that you receive source code or can get it
23
+ if you want it, that you can change the software or use pieces of it in
24
+ new free programs; and that you know you can do these things.
25
+
26
+ To protect your rights, we need to make restrictions that forbid anyone
27
+ to deny you these rights or to ask you to surrender the rights. These
28
+ restrictions translate to certain responsibilities for you if you
29
+ distribute copies of the software, or if you modify it.
30
+
31
+ For example, if you distribute copies of such a program, whether gratis or
32
+ for a fee, you must give the recipients all the rights that you have. You
33
+ must make sure that they, too, receive or can get the source code. And
34
+ you must show them these terms so they know their rights.
35
+
36
+ We protect your rights with two steps: (1) copyright the software, and
37
+ (2) offer you this license which gives you legal permission to copy,
38
+ distribute and/or modify the software.
39
+
40
+ Also, for each author's protection and ours, we want to make certain
41
+ that everyone understands that there is no warranty for this free
42
+ software. If the software is modified by someone else and passed on,
43
+ we want its recipients to know that what they have is not the original,
44
+ so that any problems introduced by others will not reflect on the original
45
+ authors' reputations.
46
+
47
+ Finally, any free program is threatened constantly by software
48
+ patents. We wish to avoid the danger that redistributors of a free
49
+ program will individually obtain patent licenses, in effect making the
50
+ program proprietary. To prevent this, we have made it clear that any
51
+ patent must be licensed for everyone's free use or not licensed at all.
52
+
53
+ The precise terms and conditions for copying, distribution and
54
+ modification follow.
55
+
56
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
57
+ 0. This License applies to any program or other work which contains
58
+ a notice placed by the copyright holder saying it may be distributed
59
+ under the terms of this General Public License. The "Program", below,
60
+ refers to any such program or work, and a "work based on the Program"
61
+ means either the Program or any derivative work under copyright law:
62
+ that is to say, a work containing the Program or a portion of it,
63
+ either verbatim or with modifications and/or translated into another
64
+ language. (Hereinafter, translation is included without limitation in
65
+ the term "modification".) Each licensee is addressed as "you".
66
+
67
+ Activities other than copying, distribution and modification are not
68
+ covered by this License; they are outside its scope. The act of running
69
+ the Program is not restricted, and the output from the Program is covered
70
+ only if its contents constitute a work based on the Program (independent
71
+ of having been made by running the Program). Whether that is true depends
72
+ on what the Program does.
73
+
74
+ 1. You may copy and distribute verbatim copies of the Program's source
75
+ code as you receive it, in any medium, provided that you conspicuously
76
+ and appropriately publish on each copy an appropriate copyright notice
77
+ and disclaimer of warranty; keep intact all the notices that refer to
78
+ this License and to the absence of any warranty; and give any other
79
+ recipients of the Program a copy of this License along with the Program.
80
+ You may charge a fee for the physical act of transferring a copy, and
81
+ you may at your option offer warranty protection in exchange for a fee.
82
+
83
+ 2. You may modify your copy or copies of the Program or any portion of
84
+ it, thus forming a work based on the Program, and copy and distribute
85
+ such modifications or work under the terms of Section 1 above, provided
86
+ that you also meet all of these conditions:
87
+
88
+ a) You must cause the modified files to carry prominent notices stating
89
+ that you changed the files and the date of any change.
90
+ b) You must cause any work that you distribute or publish, that in whole
91
+ or in part contains or is derived from the Program or any part thereof,
92
+ to be licensed as a whole at no charge to all third parties under the
93
+ terms of this License.
94
+ c) If the modified program normally reads commands interactively when
95
+ run, you must cause it, when started running for such interactive use in
96
+ the most ordinary way, to print or display an announcement including an
97
+ appropriate copyright notice and a notice that there is no warranty (or
98
+ else, saying that you provide a warranty) and that users may redistribute
99
+ the program under these conditions, and telling the user how to view a
100
+ copy of this License. (Exception: if the Program itself is interactive
101
+ but does not normally print such an announcement, your work based on
102
+ the Program is not required to print an announcement.)
103
+
104
+ These requirements apply to the modified work as a whole. If identifiable
105
+ sections of that work are not derived from the Program, and can be
106
+ reasonably considered independent and separate works in themselves,
107
+ then this License, and its terms, do not apply to those sections when
108
+ you distribute them as separate works. But when you distribute the same
109
+ sections as part of a whole which is a work based on the Program, the
110
+ distribution of the whole must be on the terms of this License, whose
111
+ permissions for other licensees extend to the entire whole, and thus to
112
+ each and every part regardless of who wrote it.
113
+
114
+ Thus, it is not the intent of this section to claim rights or contest your
115
+ rights to work written entirely by you; rather, the intent is to exercise
116
+ the right to control the distribution of derivative or collective works
117
+ based on the Program.
118
+
119
+ In addition, mere aggregation of another work not based on the Program
120
+ with the Program (or with a work based on the Program) on a volume of a
121
+ storage or distribution medium does not bring the other work under the
122
+ scope of this License.
123
+
124
+ 3. You may copy and distribute the Program (or a work based on it,
125
+ under Section 2) in object code or executable form under the terms of
126
+ Sections 1 and 2 above provided that you also do one of the following:
127
+
128
+ a) Accompany it with the complete corresponding machine-readable source
129
+ code, which must be distributed under the terms of Sections 1 and 2
130
+ above on a medium customarily used for software interchange; or,
131
+ b) Accompany it with a written offer, valid for at least three years, to
132
+ give any third party, for a charge no more than your cost of physically
133
+ performing source distribution, a complete machine-readable copy of the
134
+ corresponding source code, to be distributed under the terms of Sections
135
+ 1 and 2 above on a medium customarily used for software interchange; or,
136
+ c) Accompany it with the information you received as to the offer to
137
+ distribute corresponding source code. (This alternative is allowed only
138
+ for noncommercial distribution and only if you received the program
139
+ in object code or executable form with such an offer, in accord with
140
+ Subsection b above.)
141
+
142
+ The source code for a work means the preferred form of the work for making
143
+ modifications to it. For an executable work, complete source code means
144
+ all the source code for all modules it contains, plus any associated
145
+ interface definition files, plus the scripts used to control compilation
146
+ and installation of the executable. However, as a special exception,
147
+ the source code distributed need not include anything that is normally
148
+ distributed (in either source or binary form) with the major components
149
+ (compiler, kernel, and so on) of the operating system on which the
150
+ executable runs, unless that component itself accompanies the executable.
151
+ If distribution of executable or object code is made by offering access
152
+ to copy from a designated place, then offering equivalent access to
153
+ copy the source code from the same place counts as distribution of the
154
+ source code, even though third parties are not compelled to copy the
155
+ source along with the object code.
156
+
157
+ 4. You may not copy, modify, sublicense, or distribute the Program
158
+ except as expressly provided under this License. Any attempt otherwise
159
+ to copy, modify, sublicense or distribute the Program is void, and will
160
+ automatically terminate your rights under this License. However, parties
161
+ who have received copies, or rights, from you under this License will
162
+ not have their licenses terminated so long as such parties remain in
163
+ full compliance.
164
+
165
+ 5. You are not required to accept this License, since you have not signed
166
+ it. However, nothing else grants you permission to modify or distribute
167
+ the Program or its derivative works. These actions are prohibited
168
+ by law if you do not accept this License. Therefore, by modifying or
169
+ distributing the Program (or any work based on the Program), you indicate
170
+ your acceptance of this License to do so, and all its terms and conditions
171
+ for copying, distributing or modifying the Program or works based on it.
172
+
173
+ 6. Each time you redistribute the Program (or any work based on the
174
+ Program), the recipient automatically receives a license from the
175
+ original licensor to copy, distribute or modify the Program subject to
176
+ these terms and conditions. You may not impose any further restrictions
177
+ on the recipients' exercise of the rights granted herein. You are not
178
+ responsible for enforcing compliance by third parties to this License.
179
+
180
+ 7. If, as a consequence of a court judgment or allegation of patent
181
+ infringement or for any other reason (not limited to patent issues),
182
+ conditions are imposed on you (whether by court order, agreement or
183
+ otherwise) that contradict the conditions of this License, they do not
184
+ excuse you from the conditions of this License. If you cannot distribute
185
+ so as to satisfy simultaneously your obligations under this License
186
+ and any other pertinent obligations, then as a consequence you may not
187
+ distribute the Program at all. For example, if a patent license would
188
+ not permit royalty-free redistribution of the Program by all those who
189
+ receive copies directly or indirectly through you, then the only way you
190
+ could satisfy both it and this License would be to refrain entirely from
191
+ distribution of the Program.
192
+
193
+ If any portion of this section is held invalid or unenforceable under any
194
+ particular circumstance, the balance of the section is intended to apply
195
+ and the section as a whole is intended to apply in other circumstances.
196
+ It is not the purpose of this section to induce you to infringe any
197
+ patents or other property right claims or to contest validity of any such
198
+ claims; this section has the sole purpose of protecting the integrity of
199
+ the free software distribution system, which is implemented by public
200
+ license practices. Many people have made generous contributions to the
201
+ wide range of software distributed through that system in reliance on
202
+ consistent application of that system; it is up to the author/donor to
203
+ decide if he or she is willing to distribute software through any other
204
+ system and a licensee cannot impose that choice.
205
+
206
+ This section is intended to make thoroughly clear what is believed to
207
+ be a consequence of the rest of this License.
208
+
209
+ 8. If the distribution and/or use of the Program is restricted in certain
210
+ countries either by patents or by copyrighted interfaces, the original
211
+ copyright holder who places the Program under this License may add an
212
+ explicit geographical distribution limitation excluding those countries,
213
+ so that distribution is permitted only in or among countries not thus
214
+ excluded. In such case, this License incorporates the limitation as if
215
+ written in the body of this License.
216
+
217
+ 9. The Free Software Foundation may publish revised and/or new versions
218
+ of the General Public License from time to time. Such new versions will
219
+ be similar in spirit to the present version, but may differ in detail
220
+ to address new problems or concerns.
221
+
222
+ Each version is given a distinguishing version number. If the Program
223
+ specifies a version number of this License which applies to it and
224
+ "any later version", you have the option of following the terms and
225
+ conditions either of that version or of any later version published by
226
+ the Free Software Foundation. If the Program does not specify a version
227
+ number of this License, you may choose any version ever published by
228
+ the Free Software Foundation.
229
+
230
+ 10. If you wish to incorporate parts of the Program into other free
231
+ programs whose distribution conditions are different, write to the author
232
+ to ask for permission. For software which is copyrighted by the Free
233
+ Software Foundation, write to the Free Software Foundation; we sometimes
234
+ make exceptions for this. Our decision will be guided by the two goals
235
+ of preserving the free status of all derivatives of our free software
236
+ and of promoting the sharing and reuse of software generally.
237
+
238
+ NO WARRANTY
239
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
240
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
241
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
242
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
243
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
244
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
245
+ AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
246
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
247
+ REPAIR OR CORRECTION.
248
+
249
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
250
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
251
+ AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
252
+ FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
253
+ DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING
254
+ BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
255
+ LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
256
+ TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY
257
+ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
258
+ END OF TERMS AND CONDITIONS
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # Ingres Ruby ActiveRecord Adapter/Driver
2
+
3
+ This repository contains code based on the outdated gem provided by Actian support
4
+ for recent Ingres releases and Rails 3/4 compatibility. Bear in mind that not everything
5
+ may be functional. As of today here's a list of what you can do (will update this as I go):
6
+
7
+ * `SELECT` statements are fully functionals.
8
+
9
+ ## Overview
10
+
11
+ Three components provide Ingres support for Ruby:
12
+
13
+ * Ingres Ruby driver - native SQL-level interface
14
+ * Ingres ActiveRecord adapter - object relational adapater for Ruby on Rails
15
+ * Ingres Arel Visitor binding - specific visitor bindings for Arel
16
+
17
+ All components are required for Rails applications using ActiveRecord,
18
+ which is the standard Rails Object-to-Relations Mapping (ORM) interface. The
19
+ adapter implements the ActiveRecord classes for Ingres; internally, it invokes the
20
+ classes and methods in the driver to actually communicate with Ingres.
21
+ The driver, while primarily intended to service the adapter, can also be
22
+ invoked directly from any Ruby program to communicate with Ingres. The driver
23
+ interface does not follow any standard API and may change in the future.
24
+
25
+ ## Installation Considerations
26
+
27
+ To build and install the Ingres Ruby interface, the following components are
28
+ required:
29
+
30
+ * Ingres 9.1 or above. At a minimum, an Ingres client installation is required
31
+ on the same machine as the Ruby installation. For a list of Ingres binary and
32
+ source downloads, see http://esd.ingres.com.
33
+ * Ruby, preferably at version 1.9.3 or later. Additional Ruby components or
34
+ related products (such as ActiveRecord or Rails) may also be required
35
+ depending on how Ruby will be used with Ingres. See below for details.
36
+ * C compiler (for example, GNU/C on Linux and UNIX, or Microsoft Visual Studio
37
+ 6 on Windows). The C compiler is not needed if you are using using a pre-built
38
+ version of the Ingres Ruby driver.
39
+ Note: It is not possible to build Ruby extensions with newer versions of the
40
+ Visual Studio C compiler without making changes to the Ruby header files.
41
+ * The Ingres Ruby ActiveRecord adapter source code and driver binary. The source
42
+ code for the driver also is needed if not using the pre-built binary.
43
+
44
+ ## Installation
45
+
46
+ ### Rails 3.2.x
47
+
48
+ I maintain compatibility for Rails 3.2.x and Arel 3 in the 3-0-stable branch. Using rubygems you can do:
49
+
50
+ $ gem install activerecord-ingres-adapter -v 3.0.2
51
+
52
+ ### Rails 4
53
+
54
+ I maintain compatibility for Rails 4 and Arel 4/5 in the 4-0-stable branch. Using rubygems you can do:
55
+
56
+ $ gem install activerecord-ingres-adapter -v 4.0.0
57
+
58
+ ## TODO
59
+
60
+ * Add support for `INSERT`, `UPDATE`, `DELETE` statements.
61
+ * Add support for table manipulation/migrations.
62
+ * Add support for database creation/deletion.
63
+
64
+ ## Notes
65
+
66
+ I'm not in any part working for Actian, I'm just a third-party developer trying to make do
67
+ with what I can. If some things aren't working I'm willing to help and provide limited support.
68
+
69
+ If you want to help you're more than welcome to.
data/Rakefile ADDED
File without changes
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "activerecord-ingres-adapter"
6
+ s.version = "3.0.2"
7
+ s.summary = "ActiveRecord Ingres Adapter"
8
+ s.email = "felix.bellanger@gmail.com"
9
+ s.homepage = "https://github.com/Keeguon/activerecord-ingres-adapter"
10
+ s.description = "ActiveRecord Ingres Adapter and driver for the Ingres Enterprise Relational Database"
11
+ s.authors = ["Grant Croker","Bruce Lunsford","Jared Richardson","Felix Bellanger"]
12
+
13
+ s.rubyforge_project = "activerecord-ingres-adapter"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- test/*`.split("\n")
17
+ s.require_paths = ["lib"]
18
+ s.extensions = ['ext/extconf.rb']
19
+ end
data/ext/Ingres.c ADDED
@@ -0,0 +1,3889 @@
1
+ /*
2
+ ** Copyright (c) 2007 Ingres Corporation
3
+ **
4
+ ** This program is free software; you can redistribute it and/or modify
5
+ ** it under the terms of the GNU General Public License version 2 as
6
+ ** published by the Free Software Foundation.
7
+ **
8
+ ** This program is distributed in the hope that it will be useful,
9
+ ** but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ ** GNU General Public License for more details.
12
+ **
13
+ ** You should have received a copy of the GNU General Public License along
14
+ ** with this program; if not, write to the Free Software Foundation, Inc.,
15
+ ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ */
17
+
18
+ /* static char Sccsid[] = "$Id$"; */
19
+
20
+ /*
21
+ ** INGRES.C
22
+ **
23
+ ** History
24
+ ** 12/18/06 (Jared Richardson)
25
+ ** Community developer provided original source
26
+ ** for Ingres Corp to use as basis for Ruby driver
27
+ ** 02/21/07 (robert.kent@ingres.com)
28
+ ** General cleanup, removal of unused variables, etc,
29
+ ** replacement of trim function with Ingres version,
30
+ ** creation of debug flag setting function
31
+ ** 11/30/07 (bruce.lunsford@ingres.com)
32
+ ** Fix Segvio when selecting char or varchar with data
33
+ ** longer than 4074 bytes (co_sizeAdvise + 2). Also
34
+ ** improve performance on non-lob colunn fetches by
35
+ ** eliminating alloc/free on every column.
36
+ ** 06/17/08 (bruce.lunsford@ingres.com)
37
+ ** Add support for datatypes float4, float8, money,
38
+ ** decimal, bigint. Removed unref'd processShortField().
39
+ ** Change INT2NUM->INT2FIX where feasible for performance.
40
+ ** Add support for Ingres ANSI date/time datatypes.
41
+ ** 09/30/09 (grant.croker@ingres.com)
42
+ ** Add support for multiple active connections
43
+ ** replaced all calls to ii_allocate()/ii_reallocate()
44
+ ** with their ruby counterparts ALLOC_N and REALLOC_N
45
+ ** Except for memory allocation in getColumn()
46
+ ** Added a SQL query classifier to eliminate the need
47
+ ** to force the query into upper case
48
+ ** Moved Unicode functionality into Unicode.c and Unicode.h
49
+ ** Moved defines/typedefs/function prototypes into Ingres.h
50
+ ** Ingres.connect() takes an optional username/password
51
+ ** eliminates the need for connect_with_credentials
52
+ ** (now an alias pointing to connect)
53
+ ** Ingres.execute() now accepts a variable number of parameters,
54
+ ** requires query but parameter values is optional
55
+ ** Ingres.pexecute() now an alias for Ingres.execute()
56
+ ** Re-formatted the code using astyle (http://astyle.sourceforge.net/)
57
+ ** Added the following Ruby constants
58
+ ** VERSION - version string, e.g. "1.4.0-dev"
59
+ ** API_LEVEL - value for IIAPI_VERSION
60
+ ** REVISION - the SVN revision for the driver
61
+ ** 10/08/09 (grant.croker@ingres.com)
62
+ ** Add support for the SQL SAVEPOINT statement
63
+ ** Fix a regression where certain query would return no data
64
+ ** 10/27/09 (grant.croker@ingres.com)
65
+ ** Convert date values to IIAPI_VCH_TYPE to avoid space padded strings
66
+ ** 11/09/2009 (grant.croker@ingres.com)
67
+ ** Add the ability to set the date format for Ingres date values
68
+ ** from within Ruby.
69
+ ** 07/28/2010 (grant.croker@ingres.com)
70
+ ** Fix bug #555 - SEGV when using memcpy with BLOB data
71
+ ** 10/29/2010 (grant.croker@ingres.com)
72
+ ** Fix bug #656 - getProcedureName() fails to NULL terminate the
73
+ ** parsed procedure name.
74
+ **
75
+ */
76
+
77
+ #include "ruby.h"
78
+ #include <stdio.h>
79
+ #include <stdlib.h>
80
+ #include <ctype.h>
81
+ #include <iiapi.h>
82
+ #include "Ingres.h"
83
+ #include "Unicode.h"
84
+
85
+
86
+ static VALUE cIngres;
87
+
88
+ II_GLOBALS ii_globals;
89
+ II_LONG global_rows_affected = 0;
90
+
91
+ extern u_i2 *CM_AttrTab;
92
+ extern char *CM_CaseTab;
93
+
94
+ /* static int ii_sync(IIAPI_GENPARM *genParm)
95
+ * Waits for completion of the last Ingres api call used because of the asynchronous design of this api
96
+ */
97
+ static int
98
+ ii_sync (IIAPI_GENPARM * genParm)
99
+ {
100
+ static IIAPI_WAITPARM waitParm =
101
+ {
102
+ -1, /* no timeout, we don't want asynchronous queries */
103
+ 0 /* wt_status (output) */
104
+ };
105
+ static char function_name[] = "ii_sync";
106
+ if (ii_globals.debug)
107
+ printf ("Entering %s.\n", function_name);
108
+
109
+ while (genParm->gp_completed == FALSE)
110
+ {
111
+ IIapi_wait (&waitParm);
112
+ }
113
+
114
+ if (waitParm.wt_status != IIAPI_ST_SUCCESS)
115
+ rb_raise (rb_eRuntimeError, "IIapi_wait() failed.");
116
+
117
+ if (ii_globals.debug)
118
+ printf ("Exiting %s.\n", function_name);
119
+ return 0;
120
+ }
121
+
122
+
123
+ void *
124
+ ii_allocate (size_t nitems, size_t size)
125
+ {
126
+ void *ptr = NULL;
127
+ char function_name[] = "ii_allocate";
128
+ if (ii_globals.debug)
129
+ printf ("Entering %s.\n", function_name);
130
+
131
+ ptr = calloc (nitems, size);
132
+
133
+ if (ptr == NULL)
134
+ rb_raise (rb_eRuntimeError, "Error! Failed to allocate memory. ");
135
+
136
+ if (ii_globals.debug)
137
+ printf ("Exiting %s.\n", function_name);
138
+
139
+ return ptr;
140
+ }
141
+
142
+ void *
143
+ ii_reallocate (void *oldPtr, size_t nitems, size_t size)
144
+ {
145
+ void *ptr = NULL;
146
+ char function_name[] = "ii_reallocate";
147
+ if (ii_globals.debug)
148
+ printf ("Entering %s.\n", function_name);
149
+
150
+ if (oldPtr == NULL)
151
+ return ii_allocate (nitems, size);
152
+
153
+ ptr = realloc (oldPtr, nitems * size);
154
+
155
+ if (ptr == NULL)
156
+ rb_raise (rb_eRuntimeError, "Error! Failed to reallocate memory. ");
157
+
158
+ if (ii_globals.debug)
159
+ printf ("Exiting %s.\n", function_name);
160
+
161
+ return ptr;
162
+ }
163
+
164
+ void
165
+ ii_free (void **ptr)
166
+ {
167
+ char function_name[] = "ii_free";
168
+ if (ii_globals.debug)
169
+ printf ("Entering %s.\n", function_name);
170
+
171
+ if (*ptr != NULL)
172
+ {
173
+ free (*ptr);
174
+ *ptr = NULL;
175
+ }
176
+ if (ii_globals.debug)
177
+ printf ("Exiting %s.\n", function_name);
178
+ return;
179
+ }
180
+
181
+ void
182
+ ii_api_init ()
183
+ {
184
+ IIAPI_INITPARM initParm;
185
+ char function_name[] = "ii_api_init";
186
+ if (ii_globals.debug)
187
+ printf ("Entering %s, API Version is %d.\n", function_name, IIAPI_VERSION);
188
+
189
+ initParm.in_version = IIAPI_VERSION;
190
+ initParm.in_timeout = -1;
191
+ IIapi_initialize (&initParm);
192
+ ii_globals.envHandle = initParm.in_envHandle;
193
+
194
+ if (ii_globals.debug)
195
+ printf ("Exiting %s.\n", function_name);
196
+ }
197
+
198
+ /*
199
+ * Document-method: new
200
+ *
201
+ * Initializes a new instance of Ingres.
202
+ *
203
+ * call-seq:
204
+ * Ingres.new() -> Ingres
205
+ *
206
+ * Example usage:
207
+ *
208
+ * conn = Ingres.new()
209
+ *
210
+ */
211
+ VALUE
212
+ ii_init (VALUE param_self)
213
+ {
214
+ char function_name[] = "ii_init";
215
+ if (ii_globals.debug)
216
+ printf ("Entering %s.\n", function_name);
217
+
218
+ ii_globals.debug = FALSE;
219
+ ii_globals.debug_connection = FALSE;
220
+ ii_globals.debug_sql = FALSE;
221
+ ii_globals.debug_termination = FALSE;
222
+ ii_globals.debug_transactions = FALSE;
223
+
224
+ if (ii_globals.debug)
225
+ printf ("%s: About to execute ii_api_init ()\n", function_name);
226
+ ii_api_init ();
227
+
228
+ if (ii_globals.debug)
229
+ printf ("Exiting %s.\n", function_name);
230
+ return param_self;
231
+ }
232
+
233
+
234
+ void
235
+ init_rb_array (VALUE * param_rb_array)
236
+ {
237
+ char function_name[] = "init_rb_array";
238
+ if (ii_globals.debug)
239
+ printf ("Entering %s.\n", function_name);
240
+
241
+ if (!(*param_rb_array))
242
+ {
243
+ *param_rb_array = rb_ary_new ();
244
+ rb_global_variable (param_rb_array);
245
+ }
246
+ rb_ary_clear (*param_rb_array);
247
+
248
+ if (ii_globals.debug)
249
+ printf ("Exiting %s.\n", function_name);
250
+ }
251
+
252
+ char *
253
+ getIngresDataTypeAsString (IIAPI_DT_ID param_dt_id)
254
+ {
255
+ char *dataType = NULL;
256
+ char function_name[] = "getIngresDataTypeAsString";
257
+ if (ii_globals.debug)
258
+ printf ("Entering %s.\n", function_name);
259
+
260
+ switch (param_dt_id)
261
+ {
262
+ case IIAPI_LNVCH_TYPE:
263
+ case IIAPI_LBYTE_TYPE:
264
+ case IIAPI_LVCH_TYPE:
265
+ dataType = RUBY_LOB;
266
+ break;
267
+
268
+ case IIAPI_CHA_TYPE:
269
+ case IIAPI_NCHA_TYPE:
270
+ case IIAPI_CHR_TYPE:
271
+ case IIAPI_DEC_TYPE:
272
+ dataType = RUBY_STRING;
273
+ break;
274
+
275
+ case IIAPI_INT_TYPE:
276
+ dataType = RUBY_INTEGER;
277
+ break;
278
+
279
+ case IIAPI_FLT_TYPE:
280
+ case IIAPI_MNY_TYPE:
281
+ dataType = RUBY_DOUBLE;
282
+ break;
283
+
284
+ case IIAPI_BYTE_TYPE:
285
+ dataType = RUBY_BYTE;
286
+ break;
287
+
288
+ case IIAPI_TXT_TYPE:
289
+ dataType = RUBY_TEXT;
290
+ break;
291
+
292
+ case IIAPI_VCH_TYPE:
293
+ case IIAPI_NVCH_TYPE:
294
+ dataType = RUBY_VARCHAR;
295
+ break;
296
+
297
+ case IIAPI_DTE_TYPE:
298
+ #ifdef IIAPI_DATE_TYPE
299
+ case IIAPI_DATE_TYPE:
300
+ case IIAPI_TIME_TYPE:
301
+ case IIAPI_TMWO_TYPE:
302
+ case IIAPI_TMTZ_TYPE:
303
+ case IIAPI_TS_TYPE:
304
+ case IIAPI_TSWO_TYPE:
305
+ case IIAPI_TSTZ_TYPE:
306
+ case IIAPI_INTYM_TYPE:
307
+ case IIAPI_INTDS_TYPE:
308
+ #endif
309
+ dataType = RUBY_DATE;
310
+ break;
311
+
312
+ default:
313
+ dataType = RUBY_UNMAPPED;
314
+ printf ("\nUnmapped data type is %d\n", param_dt_id);
315
+ }
316
+
317
+ if (ii_globals.debug)
318
+ printf ("Exiting %s.\n", function_name);
319
+ return dataType;
320
+ }
321
+
322
+
323
+ /** check for and print out any errors found */
324
+ /* TODO: we should raise an exception */
325
+ void
326
+ printGPStatus (int param_gp_status)
327
+ {
328
+ char *ptr = NULL;
329
+ char val[33] = "";
330
+ char function_name[] = "printGPStatus";
331
+ if (ii_globals.debug)
332
+ printf ("Entering %s.\n", function_name);
333
+
334
+ switch (param_gp_status)
335
+ {
336
+ case IIAPI_ST_ERROR:
337
+ ptr = "IIAPI_ST_ERROR";
338
+ break;
339
+
340
+ case IIAPI_ST_FAILURE:
341
+ ptr = "IIAPI_ST_FAILURE";
342
+ break;
343
+
344
+ case IIAPI_ST_NOT_INITIALIZED:
345
+ ptr = "IIAPI_ST_NOT_INITIALIZED";
346
+ break;
347
+
348
+ case IIAPI_ST_INVALID_HANDLE:
349
+ ptr = "IIAPI_ST_INVALID_HANDLE";
350
+ break;
351
+
352
+ case IIAPI_ST_OUT_OF_MEMORY:
353
+ ptr = "IIAPI_ST_OUT_OF_MEMORY";
354
+ break;
355
+
356
+ default:
357
+ ptr = val;
358
+ sprintf (val, "%d", param_gp_status);
359
+ break;
360
+ }
361
+ printf ("\n%s: status = %s\n", function_name, ptr);
362
+
363
+ if (ii_globals.debug)
364
+ printf ("Exiting %s.\n", function_name);
365
+ }
366
+
367
+
368
+ char *
369
+ getErrorTypeStr (int param_ge_type)
370
+ {
371
+ char *ptr = NULL;
372
+ char function_name[] = "getErrorTypeStr";
373
+ if (ii_globals.debug)
374
+ printf ("Entering %s.\n", function_name);
375
+
376
+ switch (param_ge_type)
377
+ {
378
+ case IIAPI_GE_ERROR:
379
+ ptr = "ERROR";
380
+ break;
381
+ case IIAPI_GE_WARNING:
382
+ ptr = "WARNING";
383
+ break;
384
+ case IIAPI_GE_MESSAGE:
385
+ ptr = "USER MESSAGE";
386
+ break;
387
+ default:
388
+ ptr = "?";
389
+ }
390
+
391
+ if (ii_globals.debug)
392
+ printf ("Exiting %s.\n", function_name);
393
+ return ptr;
394
+ }
395
+
396
+
397
+ int
398
+ ii_checkError (IIAPI_GENPARM * param_genParm)
399
+ {
400
+ int ret_val = FALSE;
401
+ char function_name[] = "ii_checkError";
402
+ if (ii_globals.debug)
403
+ printf ("Entering %s.\n", function_name);
404
+
405
+ if (param_genParm != NULL && param_genParm->gp_status >= IIAPI_ST_ERROR)
406
+ {
407
+ ret_val = TRUE;
408
+ printGPStatus (param_genParm->gp_status);
409
+ }
410
+
411
+ if (param_genParm != NULL && param_genParm->gp_errorHandle)
412
+ {
413
+ IIAPI_GETEINFOPARM getErrParm;
414
+ char *errorTypeStr = NULL;
415
+ char *message = NULL;
416
+
417
+ ret_val = TRUE;
418
+ printf ("\n%s: %s\n", function_name, ERROR_MESSAGE_HEADER);
419
+
420
+ /* Provide initial error handle. */
421
+ getErrParm.ge_errorHandle = param_genParm->gp_errorHandle;
422
+
423
+ /* Call IIapi_getErrorInfo() in loop until no data. */
424
+ while (IIapi_getErrorInfo (&getErrParm), getErrParm.ge_status == IIAPI_ST_SUCCESS)
425
+ {
426
+ errorTypeStr = getErrorTypeStr (getErrParm.ge_type);
427
+ message = (getErrParm.ge_message ? getErrParm.ge_message : "NULL");
428
+
429
+ /* Print error message info */
430
+ printf ("%s: SQLSTATE: %s, CODE: 0x%x: %s\n",
431
+ errorTypeStr, getErrParm.ge_SQLSTATE,
432
+ getErrParm.ge_errorCode, message);
433
+ }
434
+ }
435
+
436
+ if (ii_globals.debug)
437
+ printf ("Exiting %s.\n", function_name);
438
+ return ret_val;
439
+ }
440
+
441
+ void
442
+ ii_api_set_connect_param (II_CONN *ii_conn, II_LONG paramID, VALUE paramValue)
443
+ {
444
+ IIAPI_SETCONPRMPARM setConPrmParm;
445
+ II_LONG tmp_long = 0;
446
+ char function_name[] = "ii_api_set_connect_param";
447
+
448
+ if (ii_globals.debug)
449
+ printf ("Entering %s.\n", function_name);
450
+
451
+ setConPrmParm.sc_genParm.gp_callback = NULL;
452
+ #if defined(IIAPI_VERSION_2)
453
+ setConPrmParm.sc_connHandle = ii_globals.envHandle;
454
+ #else
455
+ setConPrmParm.sc_connHandle = NULL;
456
+ #endif
457
+ setConPrmParm.sc_paramID = paramID;
458
+
459
+ switch (TYPE(paramValue))
460
+ {
461
+ case T_STRING:
462
+ setConPrmParm.sc_paramValue = RSTRING_PTR(paramValue);
463
+ break;
464
+ case T_FIXNUM:
465
+ tmp_long = FIX2LONG(paramValue);
466
+ setConPrmParm.sc_paramValue = (II_PTR)&tmp_long;
467
+ break;
468
+ default:
469
+ rb_raise(rb_eArgError, "Unable to handle an option value of type %d", TYPE(paramValue));
470
+ }
471
+
472
+ IIapi_setConnectParam(&setConPrmParm);
473
+ ii_sync (&(setConPrmParm.sc_genParm));
474
+ ii_checkError (&setConPrmParm.sc_genParm);
475
+
476
+ ii_conn->connHandle = setConPrmParm.sc_connHandle;
477
+
478
+ if (ii_globals.debug)
479
+ printf ("Exiting %s.\n", function_name);
480
+
481
+ }
482
+
483
+
484
+ void
485
+ ii_api_set_env_param (II_LONG paramID, VALUE paramValue)
486
+ {
487
+ IIAPI_SETENVPRMPARM setEnvPrmParm;
488
+ II_LONG tmp_long = 0;
489
+ char function_name[] = "ii_api_set_env_param";
490
+
491
+ if (ii_globals.debug)
492
+ printf ("Entering %s.\n", function_name);
493
+
494
+ setEnvPrmParm.se_envHandle = ii_globals.envHandle;
495
+ setEnvPrmParm.se_paramID = paramID;
496
+
497
+ switch (TYPE(paramValue))
498
+ {
499
+ case T_STRING:
500
+ setEnvPrmParm.se_paramValue = RSTRING_PTR(paramValue);
501
+ break;
502
+ case T_FIXNUM:
503
+ tmp_long = FIX2LONG(paramValue);
504
+ setEnvPrmParm.se_paramValue = (II_PTR)&tmp_long;
505
+ break;
506
+ default:
507
+ rb_raise(rb_eArgError, "Unable to handle an option value of type %d", TYPE(paramValue));
508
+ }
509
+
510
+ IIapi_setEnvParam (&setEnvPrmParm);
511
+ if (setEnvPrmParm.se_status != 0)
512
+ {
513
+ rb_raise(rb_eRuntimeError, "An error occurred when calling IIapi_setEnvParam, status returned was %d", setEnvPrmParm.se_status);
514
+ }
515
+
516
+ if (ii_globals.debug)
517
+ printf ("Exiting %s.\n", function_name);
518
+
519
+ }
520
+
521
+ void
522
+ ii_api_connect (II_CONN *ii_conn, char *param_targetDB, char *param_username, char *param_password)
523
+ {
524
+ IIAPI_CONNPARM connParm;
525
+ char function_name[] = "ii_api_connect";
526
+ if (ii_globals.debug)
527
+ printf ("Entering %s.\n", function_name);
528
+
529
+ if (ii_globals.debug || ii_globals.debug_connection)
530
+ printf
531
+ ("%s: Attempting to connect to database: %s, as username: %s, password: %s.\n",
532
+ function_name, param_targetDB, param_username, param_password);
533
+
534
+ connParm.co_genParm.gp_callback = NULL;
535
+ connParm.co_genParm.gp_closure = NULL;
536
+ connParm.co_target = param_targetDB;
537
+ connParm.co_connHandle = (ii_conn->connHandle != NULL) ? ii_conn->connHandle : ii_globals.envHandle;
538
+ connParm.co_tranHandle = NULL;
539
+ connParm.co_type = IIAPI_CT_SQL;
540
+ connParm.co_username = param_username;
541
+ connParm.co_password = param_password;
542
+ connParm.co_timeout = -1;
543
+
544
+ if (ii_globals.debug || ii_globals.debug_connection)
545
+ printf ("%s: About to execute IIapi_connect (&connParm)\n", function_name);
546
+
547
+ IIapi_connect (&connParm);
548
+ ii_sync (&(connParm.co_genParm));
549
+
550
+ if (ii_globals.debug || ii_globals.debug_connection)
551
+ printf ("%s: Executed IIapi_connect, status is %i\n", function_name, connParm.co_genParm.gp_status);
552
+ if (connParm.co_genParm.gp_status == IIAPI_ST_SUCCESS)
553
+ {
554
+ ii_conn->connHandle = connParm.co_connHandle;
555
+ ii_conn->lobSegmentSize = connParm.co_sizeAdvise;
556
+ ii_conn->apiLevel = connParm.co_apiLevel;
557
+ }
558
+ else
559
+ {
560
+ ii_checkError (&connParm.co_genParm);
561
+ rb_raise (rb_eRuntimeError, "Error! Failed to connect to database: %s, as username: %s, password: %s. ",
562
+ param_targetDB, param_username, param_password);
563
+ }
564
+
565
+ if (ii_globals.debug)
566
+ printf ("Exiting %s.\n", function_name);
567
+ }
568
+
569
+ /*
570
+ * Document-method: set_environment
571
+ *
572
+ * call-seq:
573
+ * Ingres.set_environment(environment_hash) -> nil
574
+ *
575
+ * Configures the environment settings for a Ruby application.
576
+ *
577
+ * Valid hash keys are:
578
+ *
579
+ * * <tt>:dateformat</tt>
580
+ *
581
+ * Example usage:
582
+ *
583
+ * conn = Ingres.new()
584
+ * conn.connect(:database => "demodb")
585
+ * conn.set_environment(:date_format => Ingres::DATE_FORMAT_FINLAND)
586
+ *
587
+ */
588
+ VALUE
589
+ ii_set_environment (int param_argc, VALUE *param_argv, VALUE param_self)
590
+ {
591
+ char function_name[] = "ii_set_environment";
592
+ VALUE param_value = Qnil;
593
+ VALUE args,arg;
594
+ int param_no = 0;
595
+
596
+ if (ii_globals.debug)
597
+ printf ("Entering %s.\n", function_name);
598
+
599
+ rb_scan_args (param_argc, param_argv, "0*", &args);
600
+
601
+ if (RARRAY_LEN(args) == 1)
602
+ {
603
+ arg = rb_ary_entry(args,0);
604
+ if (TYPE (arg) == T_HASH)
605
+ {
606
+ for (param_no = 0; param_no < INGRES_NO_ENV_PARAMS; param_no++)
607
+ {
608
+ param_value = rb_hash_aref(arg, ID2SYM(rb_intern(ENV_PARAMS[param_no].paramName)));
609
+ if (TYPE(param_value) != T_NIL)
610
+ {
611
+ ii_api_set_env_param (ENV_PARAMS[param_no].paramID, param_value);
612
+ }
613
+ }
614
+ }
615
+ else
616
+ {
617
+ rb_raise(rb_eArgError, "Expected a hash of environment parameters");
618
+ }
619
+ }
620
+ else
621
+ {
622
+ rb_raise(rb_eArgError, "Expected a hash of environment parameters");
623
+ }
624
+
625
+ return param_self;
626
+ }
627
+
628
+ /*
629
+ * Document-method: connect
630
+ *
631
+ * call-seq:
632
+ * Ingres.connect(connection_hash) -> Ingres
633
+ * Ingres.connect(database[, username, password]) -> Ingres
634
+ *
635
+ * Makes a connection to an Ingres database.
636
+ *
637
+ * _connection_hash_ keys:
638
+ * * +database+ - database to connect to in either of the following forms:
639
+ * [vnode::]database[/svrclass]
640
+ * @hostname,tcp_ip,listen_address[username,password]::database
641
+ * * +username+ - username to use for connection.
642
+ * * +password+ - password for the supplied username
643
+ * * +date_format+ - the string format to be used for Ingres date values. See the
644
+ * DATE_FORMAT_* constants for valid values.
645
+ *
646
+ * Usage examples:
647
+ * * Setting the date format to "YYYY-MM-DD HH:MM:SS"
648
+ * Ingres.connect(:database => "demodb", :date_format => Ingres::DATE_FORMAT_SWEDEN)
649
+ * * Passing a username / password
650
+ * Ingres.connect(:database => "demodb", :username => "ruby", password => "s3cr3t")
651
+ * * Passing a hash variable
652
+ * config[:database] = "demodb"
653
+ * config[:username] = "ruby"
654
+ * config[:password] = "s3cr3t"
655
+ * config[:date_format] = Ingres::DATE_FORMAT_ISO4
656
+ * Ingres.connect(config)
657
+ *
658
+ */
659
+
660
+ VALUE
661
+ ii_connect (int param_argc, VALUE *param_argv, VALUE param_self)
662
+ {
663
+ char function_name[] = "ii_connect";
664
+ VALUE param_targetDB;
665
+ VALUE param_username = Qnil;
666
+ VALUE param_password = Qnil;
667
+ VALUE param_value = Qnil;
668
+ VALUE args,arg;
669
+ II_CONN *ii_conn = NULL;
670
+ int db_length = 0;
671
+ int param_no = 0;
672
+ VALUE maxSegmentSize = INT2FIX(LOB_SEGMENT_SIZE);
673
+
674
+ if (ii_globals.debug)
675
+ printf ("Entering %s.\n", function_name);
676
+
677
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
678
+
679
+ rb_scan_args (param_argc, param_argv, "0*", &args);
680
+
681
+ if (RARRAY_LEN(args) == 1)
682
+ {
683
+ arg = rb_ary_entry(args,0);
684
+ if (TYPE (arg) == T_STRING)
685
+ {
686
+ /* Just have a database */
687
+ param_targetDB = arg;
688
+ param_username = rb_str_new2 ("");
689
+ param_password = rb_str_new2 ("");
690
+ }
691
+ else if (TYPE (arg) == T_HASH)
692
+ {
693
+ /* Ingres.connect({:dbname=>xxxx, :username => "xxxx", :password => "xxxx"}) */
694
+ param_targetDB = rb_hash_aref(arg, ID2SYM(rb_intern("database")));
695
+ param_username = rb_hash_aref(arg, ID2SYM(rb_intern("username")));
696
+ param_password = rb_hash_aref(arg, ID2SYM(rb_intern("password")));
697
+
698
+ if (TYPE(param_targetDB) == T_NIL)
699
+ {
700
+ rb_raise(rb_eArgError, "Unable to connect without specifying a database");
701
+ }
702
+ for ( param_no = 0; param_no < INGRES_NO_ENV_PARAMS; param_no++)
703
+ {
704
+ param_value = rb_hash_aref(arg, ID2SYM(rb_intern(CONN_PARAMS[param_no].paramName)));
705
+ if (TYPE(param_value) != T_NIL)
706
+ {
707
+ ii_api_set_connect_param (ii_conn, CONN_PARAMS[param_no].paramID, param_value);
708
+ }
709
+ }
710
+ }
711
+ }
712
+ else if (RARRAY_LEN(args) == 3)
713
+ {
714
+ param_targetDB = rb_ary_entry(args,0);
715
+ param_username = rb_ary_entry(args,1);
716
+ param_password = rb_ary_entry(args,2);
717
+ }
718
+ else
719
+ {
720
+ rb_raise(rb_eArgError, "Expected one of: database, database + username/password or hash");
721
+ }
722
+
723
+ /* If param_username and param_password are not supplied, convert them to an empty T_STRING */
724
+ if ((TYPE (param_username) == T_NIL) && (TYPE (param_password) == T_NIL))
725
+ {
726
+ param_username = rb_str_new2 ("");
727
+ param_password = rb_str_new2 ("");
728
+ }
729
+ else if ((TYPE (param_username) == T_STRING) && (TYPE (param_password) == T_NIL))
730
+ {
731
+ /* Password is required when a username is supplied */
732
+ /* This is a hacky way of aborting but will do until an IngresError Exception has been added */
733
+ rb_raise(rb_eArgError, "A password is required when specifying a username");
734
+ }
735
+
736
+ ii_api_connect (ii_conn, RSTRING_PTR(param_targetDB), RSTRING_PTR(param_username), RSTRING_PTR(param_password));
737
+
738
+ if (RARRAY_LEN(args) == 1)
739
+ {
740
+ arg = rb_ary_entry(args,0);
741
+ if (TYPE (arg) == T_HASH)
742
+ {
743
+ for (param_no = 0; param_no < INGRES_NO_ENV_PARAMS; param_no++)
744
+ {
745
+ param_value = rb_hash_aref(arg, ID2SYM(rb_intern(ENV_PARAMS[param_no].paramName)));
746
+ if (TYPE(param_value) != T_NIL)
747
+ {
748
+ ii_api_set_env_param (ENV_PARAMS[param_no].paramID, param_value);
749
+ }
750
+ }
751
+ }
752
+ }
753
+ db_length = strlen(StringValuePtr(param_targetDB));
754
+
755
+ ii_conn->currentDatabase = ALLOC_N (char, db_length + 1);
756
+ memcpy (ii_conn->currentDatabase, StringValuePtr(param_targetDB), db_length);
757
+ ii_conn->currentDatabase[db_length] = '\0';
758
+
759
+ ii_api_set_env_param (IIAPI_EP_MAX_SEGMENT_LEN, maxSegmentSize);
760
+
761
+ if (ii_globals.debug || ii_globals.debug_connection)
762
+ printf ("%s: Set ii_conn->currentDatabase to %s\n", function_name, ii_conn->currentDatabase);
763
+
764
+ if (ii_globals.debug)
765
+ printf ("Exiting %s.\n", function_name);
766
+
767
+ return param_self;
768
+ }
769
+
770
+ /*
771
+ * Document-method: disconnect
772
+ *
773
+ * Disconnects from the associated database
774
+ *
775
+ * call-seq:
776
+ * Ingres.disconnect ()
777
+ *
778
+ */
779
+ static VALUE
780
+ ii_disconnect (VALUE param_self)
781
+ {
782
+ char function_name[] = "ii_disconnect";
783
+ II_CONN *ii_conn = NULL;
784
+
785
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
786
+
787
+ if (ii_globals.debug)
788
+ printf ("Entering %s.\n", function_name);
789
+ if (ii_globals.debug || ii_globals.debug_termination)
790
+ printf ("%s: Preparing to disconnect\n", function_name);
791
+
792
+ if (ii_conn->keep_me)
793
+ rb_ary_clear (ii_conn->keep_me);
794
+
795
+ /* If there is an active transaction it must be closed before disconnection */
796
+ if (ii_conn->tranHandle)
797
+ {
798
+ ii_api_rollback (ii_conn, NULL);
799
+ }
800
+ if (ii_conn->connHandle)
801
+ {
802
+ ii_api_disconnect(ii_conn);
803
+ }
804
+ else
805
+ {
806
+ if (ii_globals.debug || ii_globals.debug_termination)
807
+ printf ("%s: Not connected\n", function_name);
808
+ }
809
+
810
+ if (ii_globals.debug)
811
+ printf ("Exiting %s.\n", function_name);
812
+ return Qnil;
813
+ }
814
+
815
+ void ii_api_disconnect( II_CONN *ii_conn)
816
+ {
817
+ IIAPI_DISCONNPARM disconnParm;
818
+ IIAPI_TERMPARM termParm;
819
+
820
+ char function_name[] = "ii_disconnect";
821
+
822
+ if (ii_globals.debug)
823
+ printf ("Entering %s.\n", function_name);
824
+
825
+ if (ii_conn->connHandle)
826
+ {
827
+ disconnParm.dc_genParm.gp_callback = NULL;
828
+ disconnParm.dc_genParm.gp_closure = NULL;
829
+ disconnParm.dc_connHandle = ii_conn->connHandle;
830
+
831
+ if (ii_globals.debug || ii_globals.debug_termination)
832
+ printf ("%s: Next, IIapi_disconnect\n", function_name);
833
+
834
+ IIapi_disconnect (&disconnParm);
835
+ ii_sync (&(disconnParm.dc_genParm));
836
+
837
+ if (ii_globals.debug || ii_globals.debug_termination)
838
+ printf ("%s: Disconnect status is >>%d<<\n", function_name, disconnParm.dc_genParm.gp_status);
839
+
840
+ ii_checkError (&disconnParm.dc_genParm);
841
+
842
+ if (ii_globals.debug || ii_globals.debug_termination)
843
+ printf ("%s: Completed IIapi_disconnect and related error checks\n", function_name);
844
+
845
+ if (ii_globals.debug || ii_globals.debug_termination)
846
+ printf ("ii_disconnect: Next, IIapi_terminate( &termParm )\n");
847
+
848
+ IIapi_terminate (&termParm);
849
+ ii_conn->connHandle = NULL;
850
+
851
+ if (ii_globals.debug || ii_globals.debug_termination)
852
+ printf ("%s: Completed IIapi_terminate( &termParm )\n", function_name);
853
+ }
854
+
855
+ if (ii_globals.debug)
856
+ printf ("Exiting %s.\n", function_name);
857
+ }
858
+
859
+ /*
860
+ * Document-method: commit
861
+ *
862
+ * call-seq:
863
+ * Ingres.commit()
864
+ *
865
+ * Commit the current open transaction against the associated database
866
+ * connection. Any active savepoints created by savepoint will be
867
+ * released.
868
+ *
869
+ */
870
+ VALUE
871
+ ii_commit (VALUE param_self)
872
+ {
873
+ char function_name[] = "ii_commit";
874
+ II_CONN *ii_conn = NULL;
875
+
876
+ if (ii_globals.debug)
877
+ printf ("Entering %s.\n", function_name);
878
+
879
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
880
+
881
+ /* We cannot commit a transaction if there is not one is already in place */
882
+ if (ii_conn->tranHandle == NULL)
883
+ {
884
+ rb_raise (rb_eRuntimeError, "Unable to commit a non-existent transaction");
885
+ }
886
+ else
887
+ {
888
+ ii_api_commit (ii_conn);
889
+ }
890
+ if (ii_globals.debug)
891
+ printf ("Exiting %s.\n", function_name);
892
+ return Qnil;
893
+ }
894
+
895
+ /*
896
+ * Document-method: rollback
897
+ *
898
+ * call-seq:
899
+ * Ingres.rollback([savepoint])
900
+ *
901
+ * Rolls back the current transaction against the associated database
902
+ * connection to the named savepoint. If no savepoint is specified, the
903
+ * transaction is rolled back to the last commit point and all savepoints
904
+ * created by savepoint are released.
905
+ *
906
+ * Example usage with savepoints:
907
+ *
908
+ * conn = Ingres.new()
909
+ * conn.connect(:database => "demodb")
910
+ * conn.execute("START TRANSACTION")
911
+ * conn.execute("INSERT INTO user_profile VALUES
912
+ * (1,'Test', 'User 1', 'user1@example.com','VLL', NULL)")
913
+ * conn.savepoint("user1")
914
+ * conn.execute("INSERT INTO user_profile VALUES
915
+ * (2,'Test', 'User 2', 'user2@example.com','MAD', NULL)")
916
+ * conn.execute("INSERT INTO user_profile VALUES
917
+ * (3,'Test', 'User 3', 'user3@example.com','JFK', NULL)")
918
+ * conn.rollback("user1")
919
+ *
920
+ */
921
+ VALUE
922
+ ii_rollback (int param_argc, VALUE * param_argv, VALUE param_self)
923
+ {
924
+ char function_name[] = "ii_rollback";
925
+ II_CONN *ii_conn = NULL;
926
+ VALUE param_savepointName = (VALUE) FALSE;
927
+ II_SAVEPOINT_ENTRY *savePtEntry = NULL;
928
+ II_SAVEPOINT_ENTRY *nextSavePtEntry = NULL;
929
+
930
+ if (ii_globals.debug)
931
+ printf ("Entering %s.\n", function_name);
932
+
933
+ rb_scan_args (param_argc, param_argv, "01", &param_savepointName);
934
+ if (param_argc)
935
+ {
936
+ Check_Type(param_savepointName, T_STRING);
937
+ }
938
+
939
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
940
+
941
+ /* We cannot rollback a transaction if there is not one is already in place */
942
+ if (ii_conn->tranHandle == NULL)
943
+ {
944
+ rb_raise (rb_eRuntimeError, "Unable to rollback a non-existent transaction");
945
+ }
946
+ else
947
+ {
948
+ if (param_argc)
949
+ {
950
+ /* Find the the savepoint entry in the list of savepoints */
951
+ if (ii_conn->savePtList)
952
+ {
953
+ savePtEntry = ii_conn->savePtList;
954
+ while (savePtEntry)
955
+ {
956
+ /* Check to see if the entry's savePtName is the same length else we could
957
+ * have a false postive result */
958
+ if (strlen(savePtEntry->savePtName) == RSTRING_LEN(param_savepointName))
959
+ {
960
+ if (strncasecmp(savePtEntry->savePtName, RSTRING_PTR (param_savepointName), RSTRING_LEN(param_savepointName)) == 0)
961
+ {
962
+ /* Found it */
963
+ break;
964
+ }
965
+ }
966
+ /* Not found move on to the next one (if any) */
967
+ savePtEntry = savePtEntry->nextSavePtEntry;
968
+ }
969
+ }
970
+ else
971
+ {
972
+ rb_raise (rb_eRuntimeError, "Unable to rollback to a non-existent savepoint");
973
+ }
974
+ if (savePtEntry == NULL)
975
+ {
976
+ rb_raise (rb_eRuntimeError, "Savepoint %s does not exist", RSTRING_PTR (param_savepointName));
977
+ }
978
+ }
979
+
980
+ ii_api_rollback (ii_conn, savePtEntry);
981
+
982
+ }
983
+ if (ii_globals.debug)
984
+ printf ("Exiting %s.\n", function_name);
985
+ return Qnil;
986
+ }
987
+
988
+ /* Free up the memory allocated for a savepoint
989
+ * input:
990
+ * pointer to a II_SAVEPOINT_ENTRY structure
991
+ * output:
992
+ * none
993
+ */
994
+ void
995
+ ii_free_savePtEntries (II_SAVEPOINT_ENTRY *savePtEntry)
996
+ {
997
+ char function_name[] = "ii_free_savePtEntries";
998
+ II_PTR nextSavePtEntry = NULL;
999
+
1000
+ if (ii_globals.debug)
1001
+ printf ("Entering %s.\n", function_name);
1002
+
1003
+ nextSavePtEntry = savePtEntry->nextSavePtEntry;
1004
+
1005
+ if (ii_globals.debug || ii_globals.debug_transactions)
1006
+ printf ("Releasing save point %s.\n", savePtEntry->savePtName);
1007
+
1008
+ ii_free((void **) &savePtEntry);
1009
+
1010
+ /* Follow the white rabbit */
1011
+ if (nextSavePtEntry)
1012
+ {
1013
+ ii_free_savePtEntries (nextSavePtEntry);
1014
+ }
1015
+ if (ii_globals.debug)
1016
+ printf ("Exiting %s.\n", function_name);
1017
+ }
1018
+
1019
+ /*
1020
+ * Document-method: savepoint
1021
+ *
1022
+ * call-seq:
1023
+ * Ingres.savepoint(savepoint)
1024
+ *
1025
+ * Create a savepoint using the supplied name. The savepoint can be used
1026
+ * as a marker for performing partial rollbacks with rollback. When
1027
+ * either commit or rollback (without specifying a savepoint name)
1028
+ * is called, all savepoints are released.
1029
+ *
1030
+ * Example usage:
1031
+ *
1032
+ * conn = Ingres.new()
1033
+ * conn.connect(:database => "demodb")
1034
+ * conn.execute("START TRANSACTION")
1035
+ * conn.execute("INSERT INTO user_profile VALUES
1036
+ * (1,'Test', 'User 1', 'user1@example.com','VLL', NULL)")
1037
+ * conn.savepoint("user1")
1038
+ * conn.execute("INSERT INTO user_profile VALUES
1039
+ * (2,'Test', 'User 2', 'user2@example.com','MAD', NULL)")
1040
+ * conn.execute("INSERT INTO user_profile VALUES
1041
+ * (3,'Test', 'User 3', 'user3@example.com','JFK', NULL)")
1042
+ * conn.rollback("user1")
1043
+ *
1044
+ *
1045
+ */
1046
+
1047
+ VALUE
1048
+ ii_savepoint (VALUE param_self, VALUE param_savepointName)
1049
+ {
1050
+ char function_name[] = "ii_savepoint";
1051
+ II_CONN *ii_conn = NULL;
1052
+
1053
+ if (ii_globals.debug)
1054
+ printf ("Entering %s.\n", function_name);
1055
+
1056
+ Check_Type (param_savepointName, T_STRING);
1057
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
1058
+
1059
+ /* We cannot generate a save point if there is no transaction or if auto commit is in effect */
1060
+ if (ii_conn->tranHandle == NULL)
1061
+ {
1062
+ rb_raise (rb_eRuntimeError, "Unable to generate a save point if there is no active transaction");
1063
+ }
1064
+ else
1065
+ {
1066
+ ii_api_savepoint (ii_conn, param_savepointName);
1067
+ }
1068
+ if (ii_globals.debug)
1069
+ printf ("Exiting %s.\n", function_name);
1070
+ return Qnil;
1071
+ }
1072
+
1073
+ void
1074
+ startTransaction (VALUE param_self)
1075
+ {
1076
+ VALUE sql_string;
1077
+ IIAPI_WAITPARM waitParm = { -1 };
1078
+ char function_name[] = "startTransaction";
1079
+ VALUE params;
1080
+ II_CONN *ii_conn = NULL;
1081
+
1082
+ if (ii_globals.debug)
1083
+ printf ("Entering %s.\n", function_name);
1084
+
1085
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
1086
+
1087
+ /* We cannot start a transaction if one is already in place */
1088
+ if (ii_conn->tranHandle)
1089
+ {
1090
+ rb_raise (rb_eRuntimeError, "Unable to start a new transaction. COMMIT or ROLLBACK the existing transaction first");
1091
+ }
1092
+
1093
+ /* turn off autocommit. The calling program is now */
1094
+ /* responsible for transactions */
1095
+ ii_conn->autocommit = FALSE;
1096
+ ii_conn->tranHandle = NULL;
1097
+
1098
+ /* now issue a simple query to get a transaction handle */
1099
+ /* FIXEME: consider adding a small, one entry table to make */
1100
+ /* this a really short, small query */
1101
+ sql_string = rb_str_new2 ("SELECT relid FROM iirelation WHERE relid='iirelation'");
1102
+ ii_execute (1, &sql_string, param_self);
1103
+
1104
+ if (ii_globals.debug)
1105
+ printf ("Exiting %s.\n", function_name);
1106
+ }
1107
+
1108
+
1109
+ void
1110
+ ii_api_commit (II_CONN *ii_conn)
1111
+ {
1112
+ IIAPI_COMMITPARM commitParm;
1113
+ char function_name[] = "commit";
1114
+ II_SAVEPOINT_ENTRY *tmpSavePtEntry; /* pointer to a savePtEntry chain that needs to be free'd up */
1115
+
1116
+ if (ii_globals.debug)
1117
+ printf ("Entering %s.\n", function_name);
1118
+
1119
+ /* ii_api_commit the transaction */
1120
+ commitParm.cm_genParm.gp_callback = NULL;
1121
+ commitParm.cm_genParm.gp_closure = NULL;
1122
+ commitParm.cm_tranHandle = ii_conn->tranHandle;
1123
+
1124
+ IIapi_commit (&commitParm);
1125
+
1126
+ ii_sync (&(commitParm.cm_genParm));
1127
+
1128
+ if (ii_globals.debug)
1129
+ printf ("\nTransaction ii_api_commit status is ++%d++\n",
1130
+ commitParm.cm_genParm.gp_status);
1131
+ ii_checkError (&commitParm.cm_genParm);
1132
+
1133
+ /* Remove all save points */
1134
+ if (ii_conn->savePtList)
1135
+ {
1136
+ tmpSavePtEntry = (II_SAVEPOINT_ENTRY *) ii_conn->savePtList;
1137
+ ii_free_savePtEntries (tmpSavePtEntry);
1138
+ ii_conn->savePtList = NULL;
1139
+ }
1140
+ /* now turn automatic transaction handling back on */
1141
+ ii_conn->tranHandle = NULL;
1142
+ ii_conn->autocommit = TRUE;
1143
+
1144
+ if (ii_globals.debug)
1145
+ printf ("Exiting %s.\n", function_name);
1146
+ }
1147
+
1148
+
1149
+ void
1150
+ ii_api_rollback (II_CONN *ii_conn, II_SAVEPOINT_ENTRY *savePtEntry)
1151
+ {
1152
+ IIAPI_ROLLBACKPARM rollbackParm;
1153
+ II_SAVEPOINT_ENTRY *tmpSavePtEntry; /* pointer to a savePtEntry chain that needs to be free'd up */
1154
+
1155
+ char function_name[] = "ii_api_rollback";
1156
+ if (ii_globals.debug)
1157
+ printf ("Entering %s.\n", function_name);
1158
+
1159
+ if (ii_conn->tranHandle)
1160
+ {
1161
+ rollbackParm.rb_tranHandle = ii_conn->tranHandle;
1162
+ rollbackParm.rb_genParm.gp_callback = NULL;
1163
+ rollbackParm.rb_genParm.gp_closure = NULL;
1164
+ rollbackParm.rb_savePointHandle = savePtEntry ? savePtEntry->savePtHandle : NULL;
1165
+
1166
+ IIapi_rollback (&rollbackParm);
1167
+
1168
+ ii_sync (&(rollbackParm.rb_genParm));
1169
+ ii_checkError (&rollbackParm.rb_genParm);
1170
+
1171
+ /*
1172
+ * Remove successive savePtEntry records as they are no longer valid
1173
+ * If savePtEntry is NULL then we need to remove all savepoint entries
1174
+ *
1175
+ * For a given set of savepoints, created in the following order:
1176
+ * A, B, C, D, E
1177
+ * Rolling back savepoint C causes D and E to become invalid
1178
+ */
1179
+ if (savePtEntry)
1180
+ {
1181
+ /* Remove any later/newer save points */
1182
+ if (savePtEntry->nextSavePtEntry)
1183
+ {
1184
+ tmpSavePtEntry = savePtEntry->nextSavePtEntry;
1185
+ ii_free_savePtEntries (tmpSavePtEntry);
1186
+ savePtEntry->nextSavePtEntry = NULL;
1187
+ ii_conn->lastSavePtEntry = savePtEntry;
1188
+ }
1189
+ }
1190
+ else if (ii_conn->savePtList && savePtEntry == NULL)
1191
+ {
1192
+ /* remove all save points */
1193
+ tmpSavePtEntry = (II_SAVEPOINT_ENTRY *) ii_conn->savePtList;
1194
+ ii_free_savePtEntries (tmpSavePtEntry);
1195
+ ii_conn->savePtList = NULL;
1196
+ }
1197
+
1198
+ /* We can only set tranHandle to NULL if there are no more save points */
1199
+ if (ii_conn->savePtList == NULL)
1200
+ {
1201
+ /* now turn automatic transaction handling back on */
1202
+ ii_conn->tranHandle = NULL;
1203
+ ii_conn->autocommit = TRUE;
1204
+ }
1205
+ }
1206
+
1207
+ if (ii_globals.debug)
1208
+ printf ("Exiting %s.\n", function_name);
1209
+ }
1210
+
1211
+ void
1212
+ ii_api_savepoint (II_CONN *ii_conn, VALUE savePtName)
1213
+ {
1214
+ IIAPI_SAVEPTPARM savePtParm;
1215
+ II_SAVEPOINT_ENTRY *savePtEntry = NULL;
1216
+ char function_name[] = "ii_api_savepoint";
1217
+ if (ii_globals.debug)
1218
+ printf ("Entering %s.\n", function_name);
1219
+
1220
+ savePtParm.sp_genParm.gp_callback = NULL;
1221
+ savePtParm.sp_genParm.gp_closure = NULL;
1222
+ savePtParm.sp_tranHandle = ii_conn->tranHandle;
1223
+ savePtParm.sp_savePoint = RSTRING_PTR(savePtName);
1224
+
1225
+ if (ii_globals.debug || ii_globals.debug_transactions)
1226
+ printf ("Creating savepoint %s\n", RSTRING_PTR(savePtName));
1227
+ IIapi_savePoint( &savePtParm );
1228
+ ii_sync (&(savePtParm.sp_genParm));
1229
+
1230
+ if (ii_globals.debug)
1231
+ printf ("\nTransaction ii_api_savepoint status is ++%d++\n", savePtParm.sp_genParm.gp_status);
1232
+ ii_checkError (&savePtParm.sp_genParm);
1233
+
1234
+ /* store the savepoint name and handle for issuing a rollback later on */
1235
+ savePtEntry = (II_SAVEPOINT_ENTRY *) ii_allocate (1,sizeof(II_SAVEPOINT_ENTRY));
1236
+ savePtEntry->savePtName = (char *) ii_allocate (RSTRING_LEN(savePtName), sizeof(char));
1237
+ savePtEntry->savePtHandle = savePtParm.sp_savePointHandle;
1238
+ memcpy(savePtEntry->savePtName, RSTRING_PTR(savePtName), RSTRING_LEN(savePtName));
1239
+ savePtEntry->nextSavePtEntry = NULL;
1240
+
1241
+ if (ii_conn->savePtList)
1242
+ {
1243
+ (ii_conn->lastSavePtEntry)->nextSavePtEntry = savePtEntry;
1244
+ }
1245
+ else
1246
+ {
1247
+ ii_conn->savePtList = (II_PTR)savePtEntry;
1248
+ }
1249
+ ii_conn->lastSavePtEntry = savePtEntry;
1250
+
1251
+ if (ii_globals.debug)
1252
+ printf ("Exiting %s.\n", function_name);
1253
+ }
1254
+
1255
+
1256
+ II_PTR
1257
+ executeQuery (II_CONN *ii_conn, char *param_sqlText)
1258
+ {
1259
+ IIAPI_QUERYPARM queryParm;
1260
+ char function_name[] = "executeQuery";
1261
+
1262
+
1263
+ if (ii_globals.debug)
1264
+ printf ("Entering %s.\n", function_name);
1265
+
1266
+ /*
1267
+ ** Call IIapi_query to execute statement.
1268
+ */
1269
+ queryParm.qy_connHandle = ii_conn->connHandle;
1270
+ queryParm.qy_genParm.gp_callback = NULL;
1271
+ queryParm.qy_genParm.gp_closure = NULL;
1272
+ queryParm.qy_queryType = IIAPI_QT_QUERY;
1273
+ queryParm.qy_queryText = param_sqlText;
1274
+ queryParm.qy_parameters = FALSE;
1275
+ queryParm.qy_tranHandle = ii_conn->tranHandle;
1276
+ queryParm.qy_stmtHandle = NULL;
1277
+ #if defined(IIAPI_VERSION_6)
1278
+ queryParm.qy_flags = 0;
1279
+ #endif
1280
+
1281
+
1282
+ IIapi_query (&queryParm);
1283
+ ii_sync (&(queryParm.qy_genParm));
1284
+
1285
+ ii_conn->stmtHandle = queryParm.qy_stmtHandle;
1286
+
1287
+ if (ii_globals.debug)
1288
+ printf ("%s: Query status is >>%d<<\n", function_name, queryParm.qy_genParm.gp_status);
1289
+
1290
+ if (ii_conn->tranHandle == NULL)
1291
+ ii_conn->tranHandle = queryParm.qy_tranHandle;
1292
+
1293
+ if (ii_globals.debug)
1294
+ printf ("Exiting %s.\n", function_name);
1295
+ return queryParm.qy_stmtHandle;
1296
+ }
1297
+
1298
+
1299
+ /* char * getProcedureName(char *statement) */
1300
+ /* check to see if the query is for a procedure or not, if it is return the procedure name
1301
+ *
1302
+ * Procedure calls come in two forms either:
1303
+ * execute procedure procname
1304
+ * call procedure
1305
+ *
1306
+ */
1307
+ static char *
1308
+ getProcedureName (char *param_sqlText)
1309
+ {
1310
+ int proc_len = 0;
1311
+ char *start = NULL;
1312
+ char *end_space = NULL;
1313
+ char *end_term = NULL;
1314
+ char *end_bracket = NULL;
1315
+ char *procedureName = NULL;
1316
+ char exec_proc[] = "{execute procedure";
1317
+ char call_proc[] = "{call";
1318
+ char function_name[] = "getProcedureName";
1319
+ if (ii_globals.debug)
1320
+ printf ("Entering %s.\n", function_name);
1321
+
1322
+ if (strncmp (param_sqlText, exec_proc, strlen (exec_proc)) == 0)
1323
+ {
1324
+ start = param_sqlText + strlen (exec_proc);
1325
+ }
1326
+ else if (strncmp (param_sqlText, call_proc, strlen (call_proc)) == 0)
1327
+ {
1328
+ start = param_sqlText + strlen (call_proc);
1329
+ }
1330
+
1331
+ if (start != NULL)
1332
+ {
1333
+ while (*start == ' ') /* skip over spaces after 'call' or 'procedure' */
1334
+ {
1335
+ start++;
1336
+ }
1337
+
1338
+ /* look for a space, bracket or null terminator to determine end of */
1339
+ /* the procedure name, end_term should never be NULL */
1340
+ end_term = strchr (start, '}');
1341
+ end_space = strchr (start, ' ');
1342
+ end_bracket = strchr (start, '(');
1343
+
1344
+ if (end_term == NULL)
1345
+ {
1346
+ rb_raise (rb_eRuntimeError, "%s: Error! Call to procedure not terminated with a '}'. ", function_name);
1347
+ }
1348
+
1349
+ if (end_space == NULL && end_bracket == NULL)
1350
+ {
1351
+ proc_len = end_term - start;
1352
+ }
1353
+ else if (end_space != NULL && end_bracket == NULL)
1354
+ {
1355
+ proc_len = end_space - start;
1356
+ }
1357
+ else if (end_space == NULL && end_bracket != NULL)
1358
+ {
1359
+ proc_len = end_bracket - start;
1360
+ }
1361
+ else if (end_space != NULL && end_bracket != NULL)
1362
+ {
1363
+ if (end_space > end_bracket)
1364
+ {
1365
+ proc_len = end_bracket - start;
1366
+ }
1367
+ else
1368
+ {
1369
+ proc_len = end_space - start;
1370
+ }
1371
+ }
1372
+
1373
+ procedureName = ALLOC_N (char, proc_len + 1);
1374
+ memcpy (procedureName, start, proc_len);
1375
+ procedureName[proc_len] = '\0';
1376
+ }
1377
+
1378
+ if (ii_globals.debug)
1379
+ printf ("Exiting %s, returning %s.\n", function_name, procedureName);
1380
+ return procedureName;
1381
+ }
1382
+
1383
+
1384
+ /* static long ii_paramcount(char *statement) */
1385
+ /* ----------------------------------------------------------------------
1386
+ * int php_ii_paramcount(char *statement TSRMLS_DC)
1387
+ *
1388
+ * Count the placeholders (?) parameters in the statement
1389
+ * return -1 for error. 0 or number of question marks
1390
+ *
1391
+ * Thanks to ext/informix (based on php_intifx_preparse).
1392
+ *
1393
+ * ----------------------------------------------------------------------
1394
+ */
1395
+ static long
1396
+ countParameters (char *statement)
1397
+ {
1398
+ char *src = statement;
1399
+ char *dst = statement;
1400
+ int parameterCount = 0;
1401
+ char ch;
1402
+ char end_quote = '\0';
1403
+ char function_name[] = "ii_paramcount";
1404
+ if (ii_globals.debug)
1405
+ printf ("Entering %s.\n", function_name);
1406
+
1407
+ while ((ch = *src++) != '\0')
1408
+ {
1409
+ if (ch == end_quote)
1410
+ {
1411
+ end_quote = '\0';
1412
+ }
1413
+ else if (end_quote != '\0')
1414
+ {
1415
+ *dst++ = ch;
1416
+ continue;
1417
+ }
1418
+ else if (ch == '\'' || ch == '\"')
1419
+ {
1420
+ end_quote = ch;
1421
+ }
1422
+ if (ch == '?')
1423
+ {
1424
+ /* X/Open standard */
1425
+ *dst++ = '?';
1426
+ parameterCount++;
1427
+ }
1428
+ else
1429
+ {
1430
+ *dst++ = ch;
1431
+ continue;
1432
+ }
1433
+ }
1434
+
1435
+ if (ii_globals.debug)
1436
+ printf ("Exiting %s, returning %i.\n", function_name, parameterCount);
1437
+ return (parameterCount);
1438
+ }
1439
+
1440
+
1441
+ int
1442
+ getIIParameter (RUBY_PARAMETER * parameter, VALUE rubyParams, int iiParam,
1443
+ int isProcedureCall)
1444
+ {
1445
+ int returnValue = 0;
1446
+ char function_name[] = "getIIParameter";
1447
+ if (ii_globals.debug)
1448
+ printf ("Entering %s.\n", function_name);
1449
+
1450
+ parameter->vkey =
1451
+ rb_ary_entry (rubyParams, RubyParamOffset (iiParam, isProcedureCall) + 0);
1452
+ parameter->vtype =
1453
+ rb_ary_entry (rubyParams, RubyParamOffset (iiParam, isProcedureCall) +
1454
+ isProcedureCall);
1455
+ parameter->vvalue =
1456
+ rb_ary_entry (rubyParams, RubyParamOffset (iiParam, isProcedureCall) +
1457
+ isProcedureCall + 1);
1458
+ if (ii_globals.debug)
1459
+ printf
1460
+ ("%s: Completed calls to rb_ary_entry, param = %i, vkey = %s, vtype = %s, vvalue = %s.\n",
1461
+ function_name, iiParam, RSTRING_PTR (parameter->vkey),
1462
+ RSTRING_PTR (parameter->vtype), RSTRING_PTR (parameter->vvalue));
1463
+
1464
+ if (!isProcedureCall)
1465
+ parameter->vkey = Qnil;
1466
+
1467
+ if (ii_globals.debug)
1468
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1469
+ return (returnValue);
1470
+ }
1471
+
1472
+
1473
+ int
1474
+ setDescriptor (IIAPI_DESCRIPTOR * sd_descriptor, RUBY_PARAMETER * parameter,
1475
+ int isProcedureCall, IIAPI_DT_ID ds_dataType,
1476
+ II_UINT2 ds_length, II_INT2 ds_precision, II_INT2 ds_scale)
1477
+ {
1478
+ int returnValue = 0;
1479
+ char function_name[] = "setDescriptorCommon";
1480
+ if (ii_globals.debug)
1481
+ printf ("Entering %s.\n", function_name);
1482
+
1483
+ if (!isProcedureCall)
1484
+ {
1485
+ sd_descriptor->ds_columnName = NULL;
1486
+ sd_descriptor->ds_columnType = IIAPI_COL_QPARM;
1487
+ }
1488
+ else
1489
+ {
1490
+ sd_descriptor->ds_columnType = IIAPI_COL_PROCPARM;
1491
+ Check_Type (parameter->vkey, T_STRING);
1492
+ sd_descriptor->ds_columnName = RSTRING_PTR (parameter->vkey);
1493
+ }
1494
+ sd_descriptor->ds_nullable = FALSE;
1495
+ sd_descriptor->ds_dataType = ds_dataType;
1496
+ sd_descriptor->ds_length = ds_length;
1497
+ sd_descriptor->ds_precision = ds_precision;
1498
+ sd_descriptor->ds_scale = ds_scale;
1499
+
1500
+ if (ii_globals.debug)
1501
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1502
+ return (returnValue);
1503
+ }
1504
+
1505
+
1506
+ int
1507
+ setLongByteDescriptor (IIAPI_DESCRIPTOR * sd_descriptor, RUBY_PARAMETER * parameter, int isProcedureCall, II_LONG lobSegmentSize)
1508
+ {
1509
+ int returnValue = 0;
1510
+ char function_name[] = "setLongByteDescriptor";
1511
+ if (ii_globals.debug)
1512
+ printf ("Entering %s.\n", function_name);
1513
+
1514
+ Check_Type (parameter->vvalue, T_STRING);
1515
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_LBYTE_TYPE, (II_UINT2) lobSegmentSize, 0, 0);
1516
+
1517
+ if (ii_globals.debug)
1518
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1519
+ return (returnValue);
1520
+ }
1521
+
1522
+
1523
+ int
1524
+ setCharDescriptor (IIAPI_DESCRIPTOR * sd_descriptor,
1525
+ RUBY_PARAMETER * parameter, int isProcedureCall)
1526
+ {
1527
+ int returnValue = 0;
1528
+ char function_name[] = "setCharDescriptor";
1529
+ if (ii_globals.debug)
1530
+ printf ("Entering %s.\n", function_name);
1531
+
1532
+ Check_Type (parameter->vvalue, T_STRING);
1533
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_CHA_TYPE,
1534
+ (II_UINT2) RSTRING_LEN (parameter->vvalue), 0, 0);
1535
+
1536
+ if (ii_globals.debug)
1537
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1538
+ return (returnValue);
1539
+ }
1540
+
1541
+
1542
+ int
1543
+ setVarcharDescriptor (IIAPI_DESCRIPTOR * sd_descriptor,
1544
+ RUBY_PARAMETER * parameter, int isProcedureCall)
1545
+ {
1546
+ int returnValue = 0;
1547
+ char function_name[] = "setVarcharDescriptor";
1548
+ if (ii_globals.debug)
1549
+ printf ("Entering %s.\n", function_name);
1550
+
1551
+ Check_Type (parameter->vvalue, T_STRING);
1552
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_VCH_TYPE,
1553
+ (II_UINT2) (RSTRING_LEN (parameter->vvalue) + 2), 0, 0);
1554
+
1555
+ if (ii_globals.debug)
1556
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1557
+ return (returnValue);
1558
+ }
1559
+
1560
+
1561
+ int
1562
+ setDecimalDescriptor (IIAPI_DESCRIPTOR * sd_descriptor,
1563
+ RUBY_PARAMETER * parameter, int isProcedureCall)
1564
+ {
1565
+ int returnValue = 0;
1566
+ char function_name[] = "setDecimalDescriptor";
1567
+ if (ii_globals.debug)
1568
+ printf ("Entering %s.\n", function_name);
1569
+
1570
+ Check_Type (parameter->vvalue, T_STRING);
1571
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_DEC_TYPE,
1572
+ (II_UINT2) DECIMAL_BUFFER_LEN, DECIMAL_PRECISION, DECIMAL_SCALE);
1573
+
1574
+ if (ii_globals.debug)
1575
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1576
+ return (returnValue);
1577
+ }
1578
+
1579
+
1580
+ int
1581
+ setFloatDescriptor (IIAPI_DESCRIPTOR * sd_descriptor,
1582
+ RUBY_PARAMETER * parameter, int isProcedureCall)
1583
+ {
1584
+ int returnValue = 0;
1585
+ char function_name[] = "setFloatDescriptor";
1586
+ if (ii_globals.debug)
1587
+ printf ("Entering %s.\n", function_name);
1588
+
1589
+ Check_Type (parameter->vvalue, T_FLOAT);
1590
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_FLT_TYPE,
1591
+ (II_UINT2) sizeof (double), DOUBLE_PRECISION, DOUBLE_SCALE);
1592
+
1593
+ if (ii_globals.debug)
1594
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1595
+ return (returnValue);
1596
+ }
1597
+
1598
+
1599
+ int
1600
+ setLongVarcharDescriptor (IIAPI_DESCRIPTOR * sd_descriptor, RUBY_PARAMETER * parameter, int isProcedureCall, II_LONG lobSegmentSize)
1601
+ {
1602
+ int returnValue = 0;
1603
+ char function_name[] = "setLongVarcharDescriptor";
1604
+ if (ii_globals.debug)
1605
+ printf ("Entering %s.\n", function_name);
1606
+
1607
+ Check_Type (parameter->vvalue, T_STRING);
1608
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_VCH_TYPE, (II_UINT2) lobSegmentSize, 0, 0);
1609
+
1610
+ if (ii_globals.debug)
1611
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1612
+ return (returnValue);
1613
+ }
1614
+
1615
+
1616
+ int
1617
+ setIntegerDescriptor (IIAPI_DESCRIPTOR * sd_descriptor,
1618
+ RUBY_PARAMETER * parameter, int isProcedureCall)
1619
+ {
1620
+ int returnValue = 0;
1621
+ char function_name[] = "setIntegerDescriptor";
1622
+ if (ii_globals.debug)
1623
+ printf ("Entering %s.\n", function_name);
1624
+
1625
+ Check_Type (parameter->vvalue, T_FIXNUM);
1626
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_INT_TYPE,
1627
+ (II_UINT2) sizeof (long), 0, 0);
1628
+
1629
+ if (ii_globals.debug)
1630
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1631
+ return (returnValue);
1632
+ }
1633
+
1634
+
1635
+ int
1636
+ setNCharDescriptor (IIAPI_DESCRIPTOR * sd_descriptor,
1637
+ RUBY_PARAMETER * parameter, int isProcedureCall)
1638
+ {
1639
+ int returnValue = 0;
1640
+ long valueLen = RSTRING_LEN (parameter->vvalue);
1641
+ char *valuePtr = RSTRING_PTR (parameter->vvalue);
1642
+ long ncharLen = valueLen * sizeof (UCS2);
1643
+ char *nchar = ALLOC_N (char, ncharLen + sizeof (UCS2));
1644
+ char function_name[] = "setNCharDescriptor";
1645
+ if (ii_globals.debug)
1646
+ printf ("Entering %s.\n", function_name);
1647
+
1648
+ Check_Type (parameter->vvalue, T_STRING);
1649
+
1650
+ if (utf8_to_utf16
1651
+ (valuePtr, valuePtr + valueLen, (UCS2 *) nchar,
1652
+ (UCS2 *) (nchar + ncharLen), &ncharLen))
1653
+ rb_raise (rb_eRuntimeError,
1654
+ "Error! Failed to transcode %s (n) to utf16.\n", valuePtr);
1655
+
1656
+ /* Allow a null at the end */
1657
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_NCHA_TYPE,
1658
+ (II_UINT2) (ncharLen * sizeof (UCS2)), 0, 0);
1659
+
1660
+ if (ii_globals.debug)
1661
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1662
+ return (returnValue);
1663
+ }
1664
+
1665
+
1666
+ int
1667
+ setNVarcharDescriptor (IIAPI_DESCRIPTOR * sd_descriptor,
1668
+ RUBY_PARAMETER * parameter, int isProcedureCall)
1669
+ {
1670
+ int returnValue = 0;
1671
+ long valueLen = RSTRING_LEN (parameter->vvalue);
1672
+ char *valuePtr = RSTRING_PTR (parameter->vvalue);
1673
+ long nvarcharlen = valueLen * sizeof (UCS2);
1674
+ char *nvarchar =
1675
+ ALLOC_N (char, 2 + nvarcharlen + sizeof (UCS2));
1676
+ char function_name[] = "setNVarcharDescriptor";
1677
+ if (ii_globals.debug)
1678
+ printf ("Entering %s.\n", function_name);
1679
+
1680
+ Check_Type (parameter->vvalue, T_STRING);
1681
+ nvarcharlen = valueLen * sizeof (UCS2);
1682
+ nvarchar = ALLOC_N (char, 2 + nvarcharlen + sizeof (UCS2));
1683
+ if (utf8_to_utf16 (valuePtr, valuePtr + valueLen, (UCS2 *) nvarchar,
1684
+ (UCS2 *) (nvarchar + nvarcharlen), &nvarcharlen))
1685
+ rb_raise (rb_eRuntimeError,
1686
+ "Error! Failed to transcode %s (N) to utf16.\n", valuePtr);
1687
+
1688
+ /* The first two bytes will contain the length */
1689
+ setDescriptor (sd_descriptor, parameter, isProcedureCall, IIAPI_NVCH_TYPE,
1690
+ (II_UINT2) (2 + (nvarcharlen * sizeof (UCS2))), 0, 0);
1691
+
1692
+ if (ii_globals.debug)
1693
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1694
+ return (returnValue);
1695
+ }
1696
+
1697
+
1698
+ int
1699
+ setParameterDescriptor (IIAPI_DESCRIPTOR * sd_descriptor, RUBY_PARAMETER * parameter, int isProcedureCall, II_LONG lobSegmentSize)
1700
+ {
1701
+ int returnValue = 0;
1702
+ char function_name[] = "setParameterDescriptor";
1703
+ if (ii_globals.debug)
1704
+ printf ("Entering %s.\n", function_name);
1705
+
1706
+ Check_Type (parameter->vtype, T_STRING);
1707
+ if (RSTRING_LEN (parameter->vtype) != 1)
1708
+ {
1709
+ rb_raise (rb_eRuntimeError, "Paramter type (%s) length (%i) != 1.",
1710
+ RSTRING_PTR (parameter->vtype),
1711
+ RSTRING_LEN (parameter->vtype));
1712
+ }
1713
+ if (ii_globals.debug)
1714
+ printf ("%s: Type is %c.\n", function_name,
1715
+ (char) *(RSTRING_PTR (parameter->vtype)));
1716
+
1717
+ switch ((char) *(RSTRING_PTR (parameter->vtype)))
1718
+ {
1719
+ case RUBY_LONG_BYTE_PARAMETER:
1720
+ setLongByteDescriptor (sd_descriptor, parameter, isProcedureCall, lobSegmentSize);
1721
+ break;
1722
+
1723
+ case RUBY_BYTE_PARAMETER:
1724
+ case RUBY_CHAR_PARAMETER:
1725
+ case RUBY_DATE_PARAMETER:
1726
+ case RUBY_TEXT_PARAMETER:
1727
+ setCharDescriptor (sd_descriptor, parameter, isProcedureCall);
1728
+ break;
1729
+
1730
+ case RUBY_DECIMAL_PARAMETER:
1731
+ setDecimalDescriptor (sd_descriptor, parameter, isProcedureCall);
1732
+ break;
1733
+
1734
+ case RUBY_FLOAT_PARAMETER:
1735
+ setFloatDescriptor (sd_descriptor, parameter, isProcedureCall);
1736
+ break;
1737
+
1738
+ case RUBY_LONG_TEXT_PARAMETER:
1739
+ case RUBY_LONG_VARCHAR_PARAMETER:
1740
+ setLongVarcharDescriptor (sd_descriptor, parameter, isProcedureCall, lobSegmentSize);
1741
+ break;
1742
+
1743
+ case RUBY_INTEGER_PARAMETER:
1744
+ setIntegerDescriptor (sd_descriptor, parameter, isProcedureCall);
1745
+ break;
1746
+
1747
+ case RUBY_NCHAR_PARAMETER:
1748
+ setNCharDescriptor (sd_descriptor, parameter, isProcedureCall);
1749
+ break;
1750
+
1751
+ case RUBY_NVARCHAR_PARAMETER:
1752
+ setNVarcharDescriptor (sd_descriptor, parameter, isProcedureCall);
1753
+ break;
1754
+
1755
+ case RUBY_VARCHAR_PARAMETER:
1756
+ setVarcharDescriptor (sd_descriptor, parameter, isProcedureCall);
1757
+ break;
1758
+
1759
+ default:
1760
+ if (ii_globals.debug)
1761
+ printf ("%s: Not set ds_length for type = %c.\n",
1762
+ function_name, (char) *(RSTRING_PTR (parameter->vtype)));
1763
+ break;
1764
+ }
1765
+
1766
+ if (ii_globals.debug)
1767
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1768
+ return (returnValue);
1769
+ }
1770
+
1771
+
1772
+ int
1773
+ setProcedureNameDescriptor (IIAPI_DESCRIPTOR * sd_descriptor,
1774
+ char *procedureName)
1775
+ {
1776
+ int returnValue = 0;
1777
+ char function_name[] = "setProcedureNameDescriptor";
1778
+ if (ii_globals.debug)
1779
+ printf ("Entering %s.\n", function_name);
1780
+
1781
+ /* setup the first parameter as the procedure name */
1782
+ sd_descriptor->ds_dataType = IIAPI_CHA_TYPE;
1783
+ sd_descriptor->ds_length = strlen (procedureName);
1784
+ sd_descriptor->ds_nullable = FALSE;
1785
+ sd_descriptor->ds_precision = 0;
1786
+ sd_descriptor->ds_scale = 0;
1787
+ sd_descriptor->ds_columnType = IIAPI_COL_SVCPARM;
1788
+ sd_descriptor->ds_columnName = NULL;
1789
+
1790
+ if (ii_globals.debug)
1791
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1792
+ return (returnValue);
1793
+ }
1794
+
1795
+
1796
+ int
1797
+ setDescriptorParms (IIAPI_SETDESCRPARM * setDescrParm, int paramCount, int isProcedureCall, II_CONN *ii_conn)
1798
+ {
1799
+ int returnValue = 0;
1800
+ char function_name[] = "setDescriptorParms";
1801
+ if (ii_globals.debug)
1802
+ printf ("Entering %s.\n", function_name);
1803
+
1804
+ /* if we are sending params then we need to describe them into to Ingres */
1805
+ /* if no parameters have been provided to a procedure call there is always 1 */
1806
+ /* parameter, the procedure name */
1807
+ setDescrParm->sd_genParm.gp_callback = NULL;
1808
+ setDescrParm->sd_genParm.gp_closure = NULL;
1809
+ setDescrParm->sd_stmtHandle = ii_conn->stmtHandle;
1810
+ setDescrParm->sd_descriptorCount = paramCount + isProcedureCall;
1811
+ setDescrParm->sd_descriptor =
1812
+ ALLOC_N (IIAPI_DESCRIPTOR, setDescrParm->sd_descriptorCount);
1813
+
1814
+ if (ii_globals.debug)
1815
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1816
+ return (returnValue);
1817
+ }
1818
+
1819
+
1820
+ int
1821
+ ii_putParamter (II_CONN *ii_conn, II_BOOL moreSegments, II_BOOL dv_null, II_UINT2 dv_length, II_PTR dv_value)
1822
+ {
1823
+ IIAPI_PUTPARMPARM putParmParm;
1824
+ IIAPI_DATAVALUE dataValue[1];
1825
+ int returnValue = 0;
1826
+ char function_name[] = "ii_putParamter";
1827
+ if (ii_globals.debug)
1828
+ printf ("Entering %s.\n", function_name);
1829
+
1830
+ dataValue[0].dv_null = dv_null;
1831
+ dataValue[0].dv_length = dv_length;
1832
+ dataValue[0].dv_value = dv_value;
1833
+
1834
+ putParmParm.pp_moreSegments = moreSegments;
1835
+ putParmParm.pp_parmData = dataValue;
1836
+ putParmParm.pp_genParm.gp_callback = NULL;
1837
+ putParmParm.pp_genParm.gp_closure = NULL;
1838
+ putParmParm.pp_stmtHandle = ii_conn->stmtHandle;
1839
+ putParmParm.pp_parmCount = 1;
1840
+ IIapi_putParms (&putParmParm);
1841
+ ii_sync (&(putParmParm.pp_genParm));
1842
+
1843
+ if (ii_checkError (&(putParmParm.pp_genParm)))
1844
+ rb_raise (rb_eRuntimeError, "Error putting a parameter.");
1845
+
1846
+ if (ii_globals.debug)
1847
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1848
+ return (returnValue);
1849
+ }
1850
+
1851
+
1852
+ int
1853
+ putProcedureNameParameter (II_CONN *ii_conn, char *procedureName)
1854
+ {
1855
+ int returnValue = 0;
1856
+ char function_name[] = "putProcedureNameParameter";
1857
+ if (ii_globals.debug)
1858
+ printf ("Entering %s.\n", function_name);
1859
+
1860
+ returnValue =
1861
+ ii_putParamter (ii_conn, 0, FALSE, (II_UINT2) strlen (procedureName), procedureName);
1862
+
1863
+ if (ii_globals.debug)
1864
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1865
+ return (returnValue);
1866
+ }
1867
+
1868
+
1869
+ int
1870
+ putRubyFixNumParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
1871
+ {
1872
+ long number = NUM2INT (parameter->vvalue);
1873
+ int returnValue = 0;
1874
+ char function_name[] = "putRubyFixNumParameter";
1875
+ if (ii_globals.debug)
1876
+ printf ("Entering %s.\n", function_name);
1877
+
1878
+ returnValue = ii_putParamter (ii_conn, 0, FALSE, sizeof (number), &number);
1879
+
1880
+ if (ii_globals.debug)
1881
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1882
+ return (returnValue);
1883
+ }
1884
+
1885
+
1886
+ int
1887
+ putRubyFloatParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
1888
+ {
1889
+ double number = NUM2DBL (parameter->vvalue);
1890
+ int returnValue = 0;
1891
+ char function_name[] = "putRubyFloatParameter";
1892
+ if (ii_globals.debug)
1893
+ printf ("Entering %s.\n", function_name);
1894
+
1895
+ returnValue = ii_putParamter (ii_conn, 0, FALSE, sizeof (number), &number);
1896
+
1897
+ if (ii_globals.debug)
1898
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1899
+ return (returnValue);
1900
+ }
1901
+
1902
+
1903
+ int
1904
+ putNVarcharParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
1905
+ {
1906
+ char *nvarchar = NULL;
1907
+ char *value_ptr = RSTRING_PTR (parameter->vvalue);
1908
+ int value_len = RSTRING_LEN (parameter->vvalue);
1909
+ long ucs2strLen = value_len * sizeof (UCS2);
1910
+ char *ucs2str = ALLOC_N (char, ucs2strLen + 2 + sizeof (UCS2));
1911
+ int returnValue = 0;
1912
+ char function_name[] = "putNVarcharParameter";
1913
+ if (ii_globals.debug)
1914
+ printf ("Entering %s.\n", function_name);
1915
+
1916
+ if (utf8_to_utf16 (value_ptr, value_ptr + value_len, (UCS2 *) ucs2str,
1917
+ (UCS2 *) (ucs2str + ucs2strLen), &ucs2strLen))
1918
+ rb_raise (rb_eRuntimeError,
1919
+ "Error! Failed to transcode %s (N) to utf16.\n", value_ptr);
1920
+ ucs2strLen *= sizeof (UCS2);
1921
+
1922
+ /* copy the data to a new buffer then set the size of the string in
1923
+ * chars at the begining of the buffer
1924
+ * Note: allocate 2 bytes at the start and a null char at the end
1925
+ * of the new buffer
1926
+ */
1927
+ nvarchar = ALLOC_N (char, 2 + ucs2strLen + sizeof (UCS2));
1928
+ memcpy (nvarchar + 2, ucs2str, ucs2strLen);
1929
+ *((II_INT2 *) (nvarchar)) = (II_INT2) ucs2strLen / sizeof (UCS2);
1930
+
1931
+ returnValue = ii_putParamter (ii_conn, 0, FALSE, (II_UINT2) (ucs2strLen + 2), nvarchar);
1932
+
1933
+ if (ii_globals.debug)
1934
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1935
+ return (returnValue);
1936
+ }
1937
+
1938
+
1939
+ int
1940
+ putNCharParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
1941
+ {
1942
+ char *value_ptr = RSTRING_PTR (parameter->vvalue);
1943
+ int value_len = RSTRING_LEN (parameter->vvalue);
1944
+ long ucs2strlen = value_len * sizeof (UCS2);
1945
+ char *nchar = ALLOC_N (char, ucs2strlen + sizeof (UCS2));
1946
+ int returnValue = 0;
1947
+ char function_name[] = "putNCharParameter";
1948
+ if (ii_globals.debug)
1949
+ printf ("Entering %s.\n", function_name);
1950
+
1951
+ if (utf8_to_utf16 (value_ptr, value_ptr + value_len, (UCS2 *) nchar,
1952
+ (UCS2 *) (nchar + ucs2strlen), &ucs2strlen))
1953
+ rb_raise (rb_eRuntimeError,
1954
+ "Error! Failed to transcode %s (n) to utf16.\n", value_ptr);
1955
+ ucs2strlen *= sizeof (UCS2);
1956
+
1957
+ returnValue = ii_putParamter (ii_conn, 0, FALSE, (II_UINT2) ucs2strlen, nchar);
1958
+
1959
+ if (ii_globals.debug)
1960
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1961
+ return (returnValue);
1962
+ }
1963
+
1964
+
1965
+ int
1966
+ putVarcharParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
1967
+ {
1968
+ char *value_ptr = RSTRING_PTR (parameter->vvalue);
1969
+ int value_len = RSTRING_LEN (parameter->vvalue);
1970
+ char *varchar = ALLOC_N (char, value_len + 2 + sizeof (char));
1971
+ int returnValue = 0;
1972
+ char function_name[] = "putVarcharParameter";
1973
+ if (ii_globals.debug)
1974
+ printf ("Entering %s.\n", function_name);
1975
+
1976
+ /* copy the data to a new buffer then set the size
1977
+ * of the string at the begining of the buffer
1978
+ */
1979
+ memcpy (varchar + 2, value_ptr, value_len);
1980
+ /* set the 1st 2 bytes as the length of the string */
1981
+ *((II_INT2 *) (varchar)) = (II_INT2) value_len;
1982
+
1983
+ returnValue = ii_putParamter (ii_conn, 0, FALSE, (II_UINT2) (value_len + 2), varchar);
1984
+
1985
+ if (ii_globals.debug)
1986
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
1987
+ return (returnValue);
1988
+ }
1989
+
1990
+ int
1991
+ putDecimalParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
1992
+ {
1993
+ IIAPI_FORMATPARM formatParm;
1994
+ char *value_ptr = RSTRING_PTR (parameter->vvalue);
1995
+ int value_len = RSTRING_LEN (parameter->vvalue);
1996
+ char decimal[DECIMAL_BUFFER_LEN + 1] = "";
1997
+ int returnValue = 0;
1998
+ char function_name[] = "putDecimalParameter";
1999
+ if (ii_globals.debug)
2000
+ printf ("Entering %s.\n", function_name);
2001
+
2002
+ formatParm.fd_envHandle = ii_globals.envHandle;
2003
+ formatParm.fd_srcDesc.ds_dataType = IIAPI_CHA_TYPE;
2004
+ formatParm.fd_srcDesc.ds_nullable = FALSE;
2005
+ formatParm.fd_srcDesc.ds_length = value_len;
2006
+ formatParm.fd_srcDesc.ds_precision = 0;
2007
+ formatParm.fd_srcDesc.ds_scale = 0;
2008
+ formatParm.fd_srcDesc.ds_columnType = IIAPI_COL_QPARM;
2009
+ formatParm.fd_srcDesc.ds_columnName = NULL;
2010
+ formatParm.fd_srcValue.dv_null = FALSE;
2011
+ formatParm.fd_srcValue.dv_length = value_len;
2012
+ formatParm.fd_srcValue.dv_value = value_ptr;
2013
+ formatParm.fd_dstDesc.ds_dataType = IIAPI_DEC_TYPE;
2014
+ formatParm.fd_dstDesc.ds_nullable = FALSE;
2015
+ formatParm.fd_dstDesc.ds_length = DECIMAL_BUFFER_LEN;
2016
+ formatParm.fd_dstDesc.ds_precision = DECIMAL_PRECISION;
2017
+ formatParm.fd_dstDesc.ds_scale = DECIMAL_SCALE;
2018
+ formatParm.fd_dstDesc.ds_columnType = IIAPI_COL_QPARM;
2019
+ formatParm.fd_dstDesc.ds_columnName = NULL;
2020
+ formatParm.fd_dstValue.dv_null = FALSE;
2021
+ formatParm.fd_dstValue.dv_length = DECIMAL_BUFFER_LEN;
2022
+ formatParm.fd_dstValue.dv_value = decimal;
2023
+ IIapi_formatData (&formatParm);
2024
+ if (formatParm.fd_status != IIAPI_ST_SUCCESS)
2025
+ {
2026
+ rb_raise (rb_eRuntimeError,
2027
+ "Error occured converting to DECIMAL. Value supplied was %s",
2028
+ value_ptr);
2029
+ }
2030
+
2031
+ returnValue = ii_putParamter (ii_conn, 0, FALSE, formatParm.fd_dstValue.dv_length, decimal);
2032
+
2033
+ if (ii_globals.debug)
2034
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
2035
+ return (returnValue);
2036
+ }
2037
+
2038
+
2039
+ int
2040
+ putLOBParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
2041
+ {
2042
+ IIAPI_FORMATPARM formatParm;
2043
+ II_BOOL moreSegments = 0;
2044
+ char *segment = ALLOC_N (char, ii_conn->lobSegmentSize + 2);
2045
+ char *value_ptr = RSTRING_PTR (parameter->vvalue);
2046
+ long value_len = RSTRING_LEN (parameter->vvalue);
2047
+ long segment_length = 0;
2048
+ int returnValue = 0;
2049
+ char function_name[] = "putLOBParameter";
2050
+ if (ii_globals.debug)
2051
+ printf ("Entering %s.\n", function_name);
2052
+
2053
+ do
2054
+ {
2055
+ memset (segment, 0, ii_conn->lobSegmentSize + 2);
2056
+
2057
+ if (value_len <= ii_conn->lobSegmentSize)
2058
+ {
2059
+ moreSegments = 0;
2060
+ segment_length = value_len;
2061
+ }
2062
+ else
2063
+ {
2064
+ moreSegments = 1;
2065
+ segment_length = ii_conn->lobSegmentSize;
2066
+ }
2067
+ /* copy the segment data to a buffer then set the size
2068
+ * of the segment at the begining of the buffer
2069
+ */
2070
+ memcpy (segment + 2, value_ptr, segment_length);
2071
+ /* set the 1st 2 bytes as the length of the segment */
2072
+ *((II_UINT2 *) segment) = (II_UINT2) segment_length;
2073
+
2074
+ returnValue =
2075
+ ii_putParamter (ii_conn, moreSegments, FALSE, (II_UINT2) (segment_length + 2), segment);
2076
+
2077
+ /* bump pointer for data by segment_length */
2078
+ value_ptr += segment_length;
2079
+ value_len -= segment_length;
2080
+ }
2081
+ while (value_len);
2082
+
2083
+ if (ii_globals.debug)
2084
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
2085
+ return (returnValue);
2086
+ }
2087
+
2088
+
2089
+ int
2090
+ putCharParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
2091
+ {
2092
+ int returnValue = 0;
2093
+ char function_name[] = "putCharParameter";
2094
+ if (ii_globals.debug)
2095
+ printf ("Entering %s.\n", function_name);
2096
+
2097
+ returnValue =
2098
+ ii_putParamter (ii_conn, 0, FALSE, (II_UINT2) RSTRING_LEN (parameter->vvalue),
2099
+ RSTRING_PTR (parameter->vvalue));
2100
+
2101
+ if (ii_globals.debug)
2102
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
2103
+ return (returnValue);
2104
+ }
2105
+
2106
+
2107
+ int
2108
+ putNullParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
2109
+ {
2110
+ int returnValue = 0;
2111
+ char function_name[] = "putNullParameter";
2112
+ if (ii_globals.debug)
2113
+ printf ("Entering %s.\n", function_name);
2114
+
2115
+ returnValue =
2116
+ ii_putParamter (ii_conn, 0, TRUE, (II_UINT2) RSTRING_LEN (parameter->vvalue),
2117
+ RSTRING_PTR (parameter->vvalue));
2118
+
2119
+ if (ii_globals.debug)
2120
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
2121
+ return (returnValue);
2122
+ }
2123
+
2124
+
2125
+ int
2126
+ putParameter (II_CONN *ii_conn, RUBY_PARAMETER * parameter)
2127
+ {
2128
+ int returnValue = 0;
2129
+ char function_name[] = "putParameter";
2130
+ if (ii_globals.debug)
2131
+ printf ("Entering %s.\n", function_name);
2132
+
2133
+ switch (TYPE (parameter->vvalue))
2134
+ {
2135
+ case T_FIXNUM:
2136
+ returnValue = putRubyFixNumParameter (ii_conn, parameter);
2137
+ break;
2138
+
2139
+ case T_FLOAT:
2140
+ returnValue = putRubyFloatParameter (ii_conn, parameter);
2141
+ break;
2142
+
2143
+ case T_STRING:
2144
+ switch ((char) *(RSTRING_PTR (parameter->vtype)))
2145
+ {
2146
+ case RUBY_NVARCHAR_PARAMETER:
2147
+ returnValue = putNVarcharParameter (ii_conn, parameter);
2148
+ break;
2149
+
2150
+ case RUBY_NCHAR_PARAMETER:
2151
+ returnValue = putNCharParameter (ii_conn, parameter);
2152
+ break;
2153
+
2154
+ case RUBY_VARCHAR_PARAMETER:
2155
+ returnValue = putVarcharParameter (ii_conn, parameter);
2156
+ break;
2157
+
2158
+ case RUBY_DECIMAL_PARAMETER:
2159
+ returnValue = putDecimalParameter (ii_conn, parameter);
2160
+ break;
2161
+
2162
+ case RUBY_LONG_BYTE_PARAMETER:
2163
+ case RUBY_LONG_TEXT_PARAMETER:
2164
+ case RUBY_LONG_VARCHAR_PARAMETER:
2165
+ returnValue = putLOBParameter (ii_conn, parameter);
2166
+ break;
2167
+
2168
+ case RUBY_INTEGER_PARAMETER:
2169
+ case RUBY_BYTE_PARAMETER:
2170
+ case RUBY_CHAR_PARAMETER:
2171
+ case RUBY_DATE_PARAMETER:
2172
+ case RUBY_TEXT_PARAMETER:
2173
+ case RUBY_FLOAT_PARAMETER:
2174
+ returnValue = putCharParameter (ii_conn, parameter);
2175
+ break;
2176
+
2177
+ default: /* everything else */
2178
+ rb_raise (rb_eRuntimeError,
2179
+ "Error putting a parameter of unknown type");
2180
+ break;
2181
+ }
2182
+ break;
2183
+
2184
+ case T_NIL: /* TODO need to check this */
2185
+ returnValue = putNullParameter (ii_conn, parameter);
2186
+ break;
2187
+
2188
+ default:
2189
+ rb_raise (rb_eRuntimeError,
2190
+ "Error putting a parameter of unknown type");
2191
+ break;
2192
+ }
2193
+ if (ii_globals.debug)
2194
+ printf ("Exiting %s, returning %i.\n", function_name, returnValue);
2195
+ return (returnValue);
2196
+ }
2197
+
2198
+
2199
+
2200
+ /* static short ii_bind_params (VALUE param_params, char *procname, long paramCount,II_LONG lobSegmentSize) */
2201
+ /* Binds and sends data for parameters passed via param_params */
2202
+ /* param_params is expected to be a repeating list of n * [key, type, value] */
2203
+ static short
2204
+ ii_bind_params (int param_argc, VALUE param_params, char *procname, long paramCount, II_CONN *ii_conn)
2205
+ {
2206
+ IIAPI_SETDESCRPARM setDescrParm;
2207
+ IIAPI_PUTPARMPARM putParmParm;
2208
+ int param = 0;
2209
+ short isProcedureCall = 0;
2210
+ char function_name[] = "ii_bind_params";
2211
+ if (ii_globals.debug)
2212
+ printf ("Entering %s.\n", function_name);
2213
+
2214
+ if (ii_globals.debug)
2215
+ printf ("%s: argc = %i, paramCount = %li, procedure name = %s.\n", function_name, param_argc, paramCount, procname);
2216
+
2217
+ isProcedureCall = (procname != NULL) ? 1 : 0;
2218
+ setDescriptorParms (&setDescrParm, paramCount, isProcedureCall, ii_conn);
2219
+
2220
+ if (isProcedureCall)
2221
+ setProcedureNameDescriptor (&(setDescrParm.sd_descriptor[0]), procname);
2222
+
2223
+ /* extract the paramtypes */
2224
+ for (param = isProcedureCall; param < setDescrParm.sd_descriptorCount; param++)
2225
+ {
2226
+ RUBY_PARAMETER parameter;
2227
+
2228
+ if (ii_globals.debug)
2229
+ printf ("%s: At start of loop for param = %i.\n", function_name, param);
2230
+
2231
+ getIIParameter (&parameter, param_params, param, isProcedureCall);
2232
+ setParameterDescriptor (&(setDescrParm.sd_descriptor[param]), &parameter, isProcedureCall, ii_conn->lobSegmentSize);
2233
+ }
2234
+
2235
+ if (ii_globals.debug)
2236
+ printf ("%s: About to set parameter descriptors.\n", function_name);
2237
+
2238
+ IIapi_setDescriptor (&setDescrParm);
2239
+
2240
+ if (ii_checkError (&setDescrParm.sd_genParm))
2241
+ rb_raise (rb_eRuntimeError, "Failed to set parameter descriptors.");
2242
+
2243
+ if (ii_globals.debug)
2244
+ printf ("%s: About to put parameters.\n", function_name);
2245
+
2246
+ if (isProcedureCall)
2247
+ putProcedureNameParameter (ii_conn, procname);
2248
+
2249
+ for (param = isProcedureCall; param < setDescrParm.sd_descriptorCount; param++)
2250
+ {
2251
+ RUBY_PARAMETER parameter;
2252
+ getIIParameter (&parameter, param_params, param, isProcedureCall);
2253
+ putParameter (ii_conn, &parameter);
2254
+ }
2255
+
2256
+ if (ii_globals.debug)
2257
+ printf ("Exiting %s.\n", function_name);
2258
+ return 0;
2259
+ }
2260
+
2261
+
2262
+ char *
2263
+ convertParamMarkers (char *param_sqlText, long param_count)
2264
+ {
2265
+ /* allow for space either side and a null */
2266
+ char *new_statement = (char *) ALLOC_N (char, strlen (param_sqlText) + (param_count * 3) + 1);
2267
+ char function_name[] = "convertParamMarkers";
2268
+ int i = 0, j = 0;
2269
+
2270
+ if (ii_globals.debug)
2271
+ printf ("Entering %s.\n", function_name);
2272
+
2273
+ for (i = 0; i < strlen (param_sqlText); i++)
2274
+ {
2275
+ if (param_sqlText[i] == '?')
2276
+ {
2277
+ /* check for space before '?' */
2278
+ /* if there is no space before the '~V' */
2279
+ /* ingres will error with "Invalid operator '~V'" */
2280
+ if (param_sqlText[i - 1] != ' ')
2281
+ new_statement[j++] = ' ';
2282
+ new_statement[j++] = '~';
2283
+ new_statement[j++] = 'V';
2284
+ /* check for space before '?' */
2285
+ /* if there is no space after the '~V' */
2286
+ /* ingres will error with "Invalid operator '~V'" */
2287
+ if (param_sqlText[i + 1] != ' ')
2288
+ new_statement[j++] = ' ';
2289
+ }
2290
+ else
2291
+ new_statement[j++] = param_sqlText[i];
2292
+ }
2293
+
2294
+ if (ii_globals.debug)
2295
+ printf ("Exiting %s.\n", function_name);
2296
+ return new_statement;
2297
+ }
2298
+
2299
+ II_PTR ii_api_query (II_CONN *ii_conn, char *param_sqlText, int param_argc, VALUE param_params)
2300
+ {
2301
+ IIAPI_QUERYPARM queryParm;
2302
+ char function_name[] = "ii_api_query";
2303
+ char *procedureName = getProcedureName (param_sqlText);
2304
+ char *statement = NULL;
2305
+ long paramCount = countParameters (param_sqlText);
2306
+ if (ii_globals.debug)
2307
+ printf ("Entering %s.\n", function_name);
2308
+
2309
+ /*
2310
+ ** Call IIapi_query to execute statement.
2311
+ */
2312
+
2313
+ if (procedureName == NULL)
2314
+ {
2315
+ statement = ((paramCount == 0) ? (param_sqlText) : (convertParamMarkers (param_sqlText, paramCount)));
2316
+ }
2317
+ queryParm.qy_connHandle = ii_conn->connHandle;
2318
+ queryParm.qy_genParm.gp_callback = NULL;
2319
+ queryParm.qy_genParm.gp_closure = NULL;
2320
+ queryParm.qy_queryType = ((procedureName != NULL) ? IIAPI_QT_EXEC_PROCEDURE : IIAPI_QT_QUERY);
2321
+ queryParm.qy_queryText = ((procedureName == NULL) ? statement : NULL);
2322
+ queryParm.qy_parameters = ((param_argc > 0) ? TRUE : FALSE);
2323
+ queryParm.qy_tranHandle = ii_conn->tranHandle;
2324
+ queryParm.qy_stmtHandle = NULL;
2325
+ #if defined(IIAPI_VERSION_6)
2326
+ queryParm.qy_flags = 0;
2327
+ #endif
2328
+
2329
+ IIapi_query (&queryParm);
2330
+ ii_sync (&(queryParm.qy_genParm));
2331
+ ii_conn->stmtHandle = queryParm.qy_stmtHandle;
2332
+
2333
+ if (param_argc > 0 && ii_bind_params (param_argc, param_params, procedureName, paramCount, ii_conn))
2334
+ {
2335
+ rb_raise (rb_eRuntimeError, "Error binding parameters.");
2336
+ }
2337
+
2338
+ if (ii_globals.debug)
2339
+ printf ("%s: Query status is >>%d<<\n", function_name, queryParm.qy_genParm.gp_status);
2340
+
2341
+ if (ii_conn->tranHandle == NULL)
2342
+ ii_conn->tranHandle = queryParm.qy_tranHandle;
2343
+
2344
+ if (ii_globals.debug)
2345
+ printf ("Exiting %s.\n", function_name);
2346
+ return queryParm.qy_stmtHandle;
2347
+ }
2348
+
2349
+
2350
+ void
2351
+ ii_api_get_metadata (II_CONN * ii_conn, IIAPI_GETDESCRPARM * param_descrParm)
2352
+ {
2353
+ int i;
2354
+ char function_name[] = "ii_api_get_metadata";
2355
+ VALUE data_type = (VALUE) FALSE;
2356
+ VALUE column_name = (VALUE) FALSE;
2357
+ VALUE ret_val = (VALUE) FALSE;
2358
+ if (ii_globals.debug)
2359
+ printf ("Entering %s.\n", function_name);
2360
+
2361
+ /* Iterate through each column loading the name and type in to global arrays */
2362
+ for (i = 0; i < param_descrParm->gd_descriptorCount; i++)
2363
+ {
2364
+ ret_val = rb_ary_push (ii_conn->r_data_types, rb_str_new2 (getIngresDataTypeAsString (param_descrParm->gd_descriptor[i].ds_dataType)));
2365
+ rb_ary_push (ii_conn->r_column_names, rb_str_new2 (param_descrParm->gd_descriptor[i].ds_columnName));
2366
+ }
2367
+ if (ii_globals.debug)
2368
+ printf ("Exiting %s.\n", function_name);
2369
+ }
2370
+
2371
+
2372
+ void
2373
+ ii_api_getDescriptors (II_CONN *ii_conn, IIAPI_GETDESCRPARM * param_descrParm)
2374
+ {
2375
+ char function_name[] = "ii_api_getDescriptors";
2376
+ if (ii_globals.debug)
2377
+ printf ("Entering %s.\n", function_name);
2378
+
2379
+ param_descrParm->gd_genParm.gp_callback = NULL;
2380
+ param_descrParm->gd_genParm.gp_closure = NULL;
2381
+ param_descrParm->gd_stmtHandle = ii_conn->stmtHandle;
2382
+ param_descrParm->gd_descriptorCount = 0;
2383
+ param_descrParm->gd_descriptor = NULL;
2384
+
2385
+ IIapi_getDescriptor (param_descrParm);
2386
+
2387
+ ii_sync (&(param_descrParm->gd_genParm));
2388
+
2389
+ if (ii_globals.debug)
2390
+ printf ("%s: GetDescriptor status is **%d**", function_name, param_descrParm->gd_genParm.gp_status);
2391
+
2392
+ if (ii_checkError (&(param_descrParm->gd_genParm)))
2393
+ {
2394
+ ii_api_query_close (ii_conn);
2395
+ ii_api_rollback (ii_conn, NULL);
2396
+ rb_raise (rb_eRuntimeError, "Error! Failed while getting Descriptors. ");
2397
+ }
2398
+
2399
+ if (ii_globals.debug)
2400
+ printf ("Exiting %s.\n", function_name);
2401
+ }
2402
+
2403
+
2404
+ void
2405
+ ii_api_query_close (II_CONN *ii_conn)
2406
+ {
2407
+ IIAPI_CLOSEPARM closeParm;
2408
+ char function_name[] = "ii_api_query_close";
2409
+ if (ii_globals.debug)
2410
+ printf ("Entering %s.\n", function_name);
2411
+
2412
+ closeParm.cl_genParm.gp_callback = NULL;
2413
+ closeParm.cl_genParm.gp_closure = NULL;
2414
+ closeParm.cl_stmtHandle = ii_conn->stmtHandle;
2415
+
2416
+ IIapi_close (&closeParm);
2417
+
2418
+ ii_sync (&(closeParm.cl_genParm));
2419
+
2420
+ if (ii_globals.debug)
2421
+ printf ("%s: closeParm status is >>%d<<", function_name,
2422
+ closeParm.cl_genParm.gp_status);
2423
+ ii_checkError (&closeParm.cl_genParm);
2424
+
2425
+ ii_conn->stmtHandle = NULL;
2426
+
2427
+ if (ii_globals.debug)
2428
+ printf ("Exiting %s.\n", function_name);
2429
+ }
2430
+
2431
+
2432
+ II_LONG
2433
+ getRowsAffected (II_CONN *ii_conn)
2434
+ {
2435
+ IIAPI_GETQINFOPARM getQInfoParm;
2436
+ char function_name[] = "getRowsAffected";
2437
+ if (ii_globals.debug)
2438
+ printf ("Entering %s.\n", function_name);
2439
+
2440
+ getQInfoParm.gq_genParm.gp_callback = NULL;
2441
+ getQInfoParm.gq_genParm.gp_closure = NULL;
2442
+ getQInfoParm.gq_stmtHandle = ii_conn->stmtHandle;
2443
+
2444
+ IIapi_getQueryInfo (&getQInfoParm);
2445
+
2446
+ ii_sync (&(getQInfoParm.gq_genParm));
2447
+
2448
+ if (ii_globals.debug)
2449
+ printf ("%s: GetQueryInfo status is >>%d<<", function_name,
2450
+ getQInfoParm.gq_genParm.gp_status);
2451
+ ii_checkError (&getQInfoParm.gq_genParm);
2452
+
2453
+ if (ii_globals.debug)
2454
+ printf ("Exiting %s.\n", function_name);
2455
+ return (II_LONG) getQInfoParm.gq_rowCount;
2456
+ }
2457
+
2458
+
2459
+ VALUE
2460
+ processDateField (IIAPI_DATAVALUE * param_columnData, int param_dataType)
2461
+ {
2462
+ VALUE returnValue;
2463
+ IIAPI_CONVERTPARM convertParm;
2464
+ IIAPI_FORMATPARM formatParm;
2465
+ int dateStrLen = 260;
2466
+ char *dateStr = NULL;
2467
+ char function_name[] = "processDateField";
2468
+ if (ii_globals.debug)
2469
+ printf ("Entering %s.\n", function_name);
2470
+
2471
+ dateStr = ALLOC_N (char, dateStrLen + 1);
2472
+
2473
+ if (ii_globals.debug)
2474
+ printf ("%s: Found a DATE or TIME field of type %d >>%s<<\n", function_name,
2475
+ param_dataType, (char *)(param_columnData->dv_value));
2476
+
2477
+ formatParm.fd_envHandle = ii_globals.envHandle;
2478
+ formatParm.fd_srcDesc.ds_dataType = param_dataType;
2479
+ formatParm.fd_srcDesc.ds_nullable = FALSE;
2480
+ formatParm.fd_srcDesc.ds_length = param_columnData->dv_length;
2481
+ formatParm.fd_srcDesc.ds_precision = 0;
2482
+ formatParm.fd_srcDesc.ds_scale = 0;
2483
+ formatParm.fd_srcDesc.ds_columnType = IIAPI_COL_QPARM;
2484
+ formatParm.fd_srcDesc.ds_columnName = NULL;
2485
+
2486
+ formatParm.fd_srcValue.dv_null = FALSE;
2487
+ formatParm.fd_srcValue.dv_length = param_columnData->dv_length;
2488
+ formatParm.fd_srcValue.dv_value = param_columnData->dv_value;
2489
+
2490
+ formatParm.fd_dstDesc.ds_dataType = IIAPI_VCH_TYPE;
2491
+ formatParm.fd_dstDesc.ds_nullable = FALSE;
2492
+ formatParm.fd_dstDesc.ds_length = dateStrLen;
2493
+ formatParm.fd_dstDesc.ds_precision = 0;
2494
+ formatParm.fd_dstDesc.ds_scale = 0;
2495
+ formatParm.fd_dstDesc.ds_columnType = IIAPI_COL_QPARM;
2496
+ formatParm.fd_dstDesc.ds_columnName = NULL;
2497
+
2498
+ formatParm.fd_dstValue.dv_null = FALSE;
2499
+ formatParm.fd_dstValue.dv_length = dateStrLen;
2500
+ formatParm.fd_dstValue.dv_value = dateStr;
2501
+
2502
+ IIapi_formatData (&formatParm);
2503
+
2504
+ dateStr[formatParm.fd_dstValue.dv_length] = '\0';
2505
+ if (ii_globals.debug)
2506
+ printf ("%s: Converted the DATE/TIME field >>%s<< to the string >>%s<<\n",
2507
+ function_name, (char *)param_columnData->dv_value, dateStr + 2);
2508
+
2509
+ returnValue = rb_str_new (dateStr + 2, *(II_INT2 *)dateStr);
2510
+
2511
+ if (ii_globals.debug)
2512
+ printf ("Exiting %s.\n", function_name);
2513
+ return returnValue;
2514
+ }
2515
+
2516
+
2517
+ VALUE
2518
+ processDecimalField (IIAPI_DATAVALUE * param_columnData, IIAPI_DESCRIPTOR * param_descrParm)
2519
+ {
2520
+ VALUE returnValue;
2521
+ IIAPI_CONVERTPARM convertParm;
2522
+ int decimalStrLen = 42;
2523
+ /* FIXME: use Ingres MAX_DECIMAL_LEN or something like that */
2524
+ char decimalStr[42] = {0};
2525
+ char function_name[] = "processDecimalField";
2526
+ if (ii_globals.debug)
2527
+ printf ("Entering %s.\n", function_name);
2528
+
2529
+ convertParm.cv_srcDesc.ds_dataType = IIAPI_DEC_TYPE;
2530
+ convertParm.cv_srcDesc.ds_nullable = FALSE;
2531
+ convertParm.cv_srcDesc.ds_length = param_descrParm->ds_length;
2532
+ convertParm.cv_srcDesc.ds_precision = param_descrParm->ds_precision;
2533
+ convertParm.cv_srcDesc.ds_scale = param_descrParm->ds_scale;
2534
+ convertParm.cv_srcDesc.ds_columnType = IIAPI_COL_QPARM;
2535
+ convertParm.cv_srcDesc.ds_columnName = NULL;
2536
+
2537
+ convertParm.cv_srcValue.dv_null = FALSE;
2538
+ convertParm.cv_srcValue.dv_length = param_columnData->dv_length;
2539
+ convertParm.cv_srcValue.dv_value = param_columnData->dv_value;
2540
+
2541
+ convertParm.cv_dstDesc.ds_dataType = IIAPI_VCH_TYPE;
2542
+ convertParm.cv_dstDesc.ds_nullable = FALSE;
2543
+ convertParm.cv_dstDesc.ds_length = decimalStrLen;
2544
+ convertParm.cv_dstDesc.ds_precision = 0;
2545
+ convertParm.cv_dstDesc.ds_scale = 0;
2546
+ convertParm.cv_dstDesc.ds_columnType = IIAPI_COL_QPARM;
2547
+ convertParm.cv_dstDesc.ds_columnName = NULL;
2548
+
2549
+ convertParm.cv_dstValue.dv_null = FALSE;
2550
+ convertParm.cv_dstValue.dv_length = decimalStrLen;
2551
+ convertParm.cv_dstValue.dv_value = decimalStr;
2552
+
2553
+ IIapi_convertData (&convertParm);
2554
+
2555
+ returnValue = rb_str_new2 (decimalStr + 2);
2556
+
2557
+ if (ii_globals.debug)
2558
+ printf ("Exiting %s.\n", function_name);
2559
+ return returnValue;
2560
+ }
2561
+
2562
+
2563
+ /*
2564
+ ** processIntField() - Convert Ingres integer to Ruby numeric
2565
+ **
2566
+ ** Description -
2567
+ ** Convert Ingres integer (lengths 1, 2, 4 or 8) to Ruby
2568
+ ** numeric (Fixnum or Bignum).
2569
+ **
2570
+ ** Ruby numeric types w/ ranges:
2571
+ ** Fixnum -2**30 -> 2**30-1 #most platforms
2572
+ ** (-1,073,741,824) (1,073,741,823)
2573
+ ** -2**62 -> 2**62-1 #some 64-bit? platforms
2574
+ ** Bignum: unlimited...anything outside range of Fixnum
2575
+ **
2576
+ ** Ingres integer types w/ ranges and mapping to Ruby:
2577
+ ** tinyint(integer1) -128 -> 127 Fixnum
2578
+ ** smallint(integer2) -32768 -> 32767 Fixnum
2579
+ ** integer(integer4) -2**31 -> 2**31-1 Fixnum/Bignum
2580
+ ** (-2,147,483,648) (2,147,483,647)
2581
+ ** bigint(integer8) -2**63 -> 2**63-1 Fixnum/Bignum
2582
+ **
2583
+ ** The Ruby macros xxx2NUM/FIX are used to do the conversion.
2584
+ ** If the Ingres type will always fit within a Ruby Fixnum,
2585
+ ** then use INT2FIX because it is faster. Otherwise, use the
2586
+ ** appropriate xxx2NUM macro which will convert it to either
2587
+ ** Fixnum or Bignum depending on the value.
2588
+ **
2589
+ ** History
2590
+ ** 06/18/08 (lunbr01)
2591
+ ** Added Ingres bigint support and used INT2FIX
2592
+ ** instead of INT2NUM where possible for performance.
2593
+ ** Add function documentation.
2594
+ */
2595
+ VALUE
2596
+ processIntField (IIAPI_DATAVALUE * param_columnData)
2597
+ {
2598
+ VALUE ret_val;
2599
+ char function_name[] = "processIntField";
2600
+ if (ii_globals.debug)
2601
+ printf ("Entering %s.\n", function_name);
2602
+
2603
+ switch (param_columnData->dv_length)
2604
+ {
2605
+ case 1:
2606
+ ret_val = INT2FIX ((char) * ((II_INT1 *) param_columnData->dv_value));
2607
+ break;
2608
+ case 2:
2609
+ ret_val = INT2FIX ((short) * ((II_INT2 *) param_columnData->dv_value));
2610
+ break;
2611
+ case 4:
2612
+ ret_val = LONG2NUM ((long) * ((II_INT4 *) param_columnData->dv_value));
2613
+ break;
2614
+ case 8:
2615
+ ret_val = LL2NUM ((__int64) * ((__int64 *) param_columnData->dv_value));
2616
+ break;
2617
+ default:
2618
+ if (ii_globals.debug)
2619
+ printf
2620
+ ("%s: Bad size for IIAPI_INT_TYPE. The size %d is invalid. Returning NULL.\n",
2621
+ function_name, param_columnData->dv_length);
2622
+ /* if the data size is zero, this is a NULL value. */
2623
+ ret_val = rb_str_new2 ("NULL");
2624
+ break;
2625
+ }
2626
+
2627
+ if (ii_globals.debug)
2628
+ printf ("Exiting %s.\n", function_name);
2629
+ return ret_val;
2630
+ }
2631
+
2632
+
2633
+ VALUE
2634
+ processFloatField (IIAPI_DATAVALUE * param_columnData)
2635
+ {
2636
+ VALUE ret_val;
2637
+ char function_name[] = "processFloatField";
2638
+ if (ii_globals.debug)
2639
+ printf ("Entering %s.\n", function_name);
2640
+
2641
+ switch (param_columnData->dv_length)
2642
+ {
2643
+ case 4:
2644
+ ret_val =
2645
+ rb_float_new ((double) * ((II_FLOAT4 *) param_columnData->dv_value));
2646
+ break;
2647
+
2648
+ case 8:
2649
+ ret_val =
2650
+ rb_float_new ((double) * ((II_FLOAT8 *) param_columnData->dv_value));
2651
+ break;
2652
+
2653
+ default:
2654
+ if (ii_globals.debug)
2655
+ printf
2656
+ ("%s: Bad size for IIAPI_FLT_TYPE. The size %d is invalid. Valid sizes are 4 and 8. Returning NULL.",
2657
+ function_name, param_columnData->dv_length);
2658
+ ret_val = rb_str_new2 ("NULL");;
2659
+ break;
2660
+ }
2661
+
2662
+ if (ii_globals.debug)
2663
+ printf ("Exiting %s.\n", function_name);
2664
+ return ret_val;
2665
+ }
2666
+
2667
+
2668
+ VALUE
2669
+ processMoneyField (IIAPI_DATAVALUE * param_columnData)
2670
+ {
2671
+ VALUE ret_val;
2672
+ char function_name[] = "processMoneyField";
2673
+ if (ii_globals.debug)
2674
+ printf ("Entering %s.\n", function_name);
2675
+
2676
+ ret_val = rb_float_new ((double) * ((II_FLOAT8 *) param_columnData->dv_value) / 100.00);
2677
+
2678
+ if (ii_globals.debug)
2679
+ printf ("Exiting %s.\n", function_name);
2680
+ return ret_val;
2681
+ }
2682
+
2683
+
2684
+
2685
+ VALUE
2686
+ processCharField (char *param_char_field, int param_char_length)
2687
+ {
2688
+ VALUE ret_val = (VALUE)FALSE;
2689
+ int trimmed_len = 0;
2690
+ char *newstring = NULL;
2691
+ char function_name[] = "processCharField";
2692
+ if (ii_globals.debug)
2693
+ printf ("Entering %s.\n", function_name);
2694
+
2695
+ newstring = (char *) ALLOC_N(char, param_char_length + 1);
2696
+ memcpy (newstring, param_char_field, param_char_length);
2697
+ newstring[param_char_length] = '\0';
2698
+
2699
+ /* remove any trailing blanks */
2700
+ trimmed_len = STtrmwhite (newstring);
2701
+ newstring[trimmed_len] = '\0';
2702
+ ret_val = rb_str_new (newstring, trimmed_len);
2703
+
2704
+ if (ii_globals.debug)
2705
+ printf ("oldchar is >>%s<<, newchar is >>%s<<\n", param_char_field, RSTRING_PTR (ret_val));
2706
+
2707
+ if (ii_globals.debug)
2708
+ printf ("Exiting %s.\n", function_name);
2709
+ return ret_val;
2710
+ }
2711
+
2712
+
2713
+ VALUE
2714
+ processStringField (char *param_varchar_field, int param_varchar_length)
2715
+ {
2716
+ VALUE result_value;
2717
+ int i;
2718
+ char *newstring = ALLOC_N (char, param_varchar_length - 1);
2719
+ char function_name[] = "processStringField";
2720
+ if (ii_globals.debug)
2721
+ printf ("Entering %s.\n", function_name);
2722
+
2723
+ /* the first two bytes holds the length. */
2724
+ /* since we already have that, we don't need it, */
2725
+ /* so we just skip over that information. */
2726
+ memcpy (newstring, param_varchar_field + 2, param_varchar_length - 2);
2727
+
2728
+ if (ii_globals.debug)
2729
+ printf ("oldstring is >>%s<<, newstring is >>%s<<\n", param_varchar_field,
2730
+ newstring);
2731
+
2732
+ /* make a Ruby value out of the result */
2733
+ result_value = rb_str_new (newstring, param_varchar_length - 2);
2734
+
2735
+ if (ii_globals.debug)
2736
+ printf ("Exiting %s.\n", function_name);
2737
+
2738
+ return result_value;
2739
+ }
2740
+
2741
+ VALUE
2742
+ processUTF16StringField (char *param_nvarchar_field,
2743
+ int param_nvarchar_length)
2744
+ {
2745
+ VALUE result_value;
2746
+ int i, ret_val;
2747
+ long utf8strlen;
2748
+ unsigned char *utf8str = NULL;
2749
+ char function_name[] = "processUTF16StringField";
2750
+ if (ii_globals.debug)
2751
+ printf ("Entering %s.\n", function_name);
2752
+
2753
+ utf8strlen = param_nvarchar_length * 4;
2754
+ utf8str = ALLOC_N (char, utf8strlen + 3);
2755
+
2756
+ if (utf16_to_utf8
2757
+ ((UCS2 *) (param_nvarchar_field + 2),
2758
+ (UCS2 *) (param_nvarchar_field + param_nvarchar_length),
2759
+ (char *) (utf8str + 2), (char *) (utf8str + utf8strlen + 2),
2760
+ &utf8strlen))
2761
+ rb_raise (rb_eRuntimeError,
2762
+ "Transcode of UTF16 %s, string to UTF failed.",
2763
+ param_nvarchar_field);
2764
+
2765
+ result_value = processStringField (utf8str, utf8strlen + 2);
2766
+
2767
+ if (ii_globals.debug)
2768
+ printf ("Exiting %s.\n", function_name);
2769
+
2770
+ return result_value;
2771
+ }
2772
+
2773
+
2774
+ VALUE
2775
+ processUTF16CharField (char *param_nchar_field, int param_nchar_length)
2776
+ {
2777
+ VALUE result_value;
2778
+ long utf8strlen;
2779
+ unsigned char *utf8str = NULL;
2780
+ char function_name[] = "processUTF16CharField";
2781
+ if (ii_globals.debug)
2782
+ printf ("Entering %s.\n", function_name);
2783
+
2784
+ utf8strlen = param_nchar_length * 4;
2785
+ utf8str = ALLOC_N (char, utf8strlen + 1);
2786
+
2787
+ if (utf16_to_utf8 ((UCS2 *) param_nchar_field, (UCS2 *) (param_nchar_field + param_nchar_length), (char *) utf8str, (char *) (utf8str + utf8strlen), &utf8strlen))
2788
+ rb_raise (rb_eRuntimeError, "Transcode of UTF16 %s, char to UTF failed.", param_nchar_field);
2789
+
2790
+ result_value = processCharField (utf8str, utf8strlen);
2791
+
2792
+ if (ii_globals.debug)
2793
+ printf ("Exiting %s.\n", function_name);
2794
+
2795
+ return result_value;
2796
+ }
2797
+
2798
+
2799
+ VALUE
2800
+ processUTF16LOBField (char *param_nlob_field, int param_nlob_length)
2801
+ {
2802
+ VALUE result_value;
2803
+ long utf8strlen;
2804
+ unsigned char *utf8str = NULL;
2805
+ char function_name[] = "processUTF16LOBField";
2806
+ if (ii_globals.debug)
2807
+ printf ("Entering %s.\n", function_name);
2808
+
2809
+ utf8strlen = param_nlob_length * 4;
2810
+ utf8str = ALLOC_N (char, utf8strlen + 1);
2811
+
2812
+ if (utf16_to_utf8
2813
+ ((UCS2 *) param_nlob_field,
2814
+ (UCS2 *) (param_nlob_field + param_nlob_length), (char *) utf8str,
2815
+ (char *) (utf8str + utf8strlen), &utf8strlen))
2816
+ rb_raise (rb_eRuntimeError, "Transcode of UTF16 %s, char to UTF failed.",
2817
+ param_nlob_field);
2818
+
2819
+ result_value = rb_str_new (utf8str, utf8strlen);
2820
+
2821
+ if (ii_globals.debug)
2822
+ printf ("Exiting %s.\n", function_name);
2823
+
2824
+ return result_value;
2825
+ }
2826
+
2827
+
2828
+ VALUE
2829
+ processLOBField (char *param_nlob_field, int param_nlob_length)
2830
+ {
2831
+ VALUE result_value;
2832
+ char function_name[] = "processLOBField";
2833
+ if (ii_globals.debug)
2834
+ printf ("Entering %s.\n", function_name);
2835
+
2836
+ result_value = rb_str_new (param_nlob_field, param_nlob_length);
2837
+
2838
+ if (ii_globals.debug)
2839
+ printf ("Exiting %s.\n", function_name);
2840
+
2841
+ return result_value;
2842
+ }
2843
+
2844
+
2845
+ VALUE
2846
+ processUnImplementedField ()
2847
+ {
2848
+ char function_name[] = "processUnImplementedField";
2849
+ if (ii_globals.debug)
2850
+ printf ("Entering %s.\n", function_name);
2851
+
2852
+ rb_notimplement ();
2853
+
2854
+ if (ii_globals.debug)
2855
+ printf ("Exiting %s.\n", function_name);
2856
+ return rb_str_new2 ("NULL");
2857
+ }
2858
+
2859
+
2860
+ VALUE
2861
+ processField (II_CONN * ii_conn, RUBY_IIAPI_DATAVALUE * param_columnData, int param_columnNumber, IIAPI_DESCRIPTOR * param_descrParm)
2862
+ {
2863
+ VALUE ret_val;
2864
+ IIAPI_DATAVALUE *dataValue = param_columnData->dataValue;
2865
+ int param_dataType = param_descrParm->ds_dataType;
2866
+ char function_name[] = "processField";
2867
+
2868
+ if (ii_globals.debug)
2869
+ printf ("Entering %s.\n", function_name);
2870
+
2871
+ rb_ary_store (ii_conn->r_data_sizes, param_columnNumber, INT2NUM (param_columnData->dv_length));
2872
+
2873
+ /* fetch the data differently depending on the type of data it is */
2874
+ switch (param_dataType)
2875
+ {
2876
+ /* I followed the Ingres doc for these types */
2877
+ /* anything listed as a char * will be treated as varchar or text */
2878
+ case IIAPI_NVCH_TYPE:
2879
+ ret_val = processUTF16StringField (dataValue->dv_value, param_columnData->dv_length);
2880
+ break;
2881
+
2882
+ case IIAPI_LNVCH_TYPE:
2883
+ ret_val = processUTF16LOBField (dataValue->dv_value, param_columnData->dv_length);
2884
+ break;
2885
+
2886
+ case IIAPI_LBYTE_TYPE:
2887
+ case IIAPI_LVCH_TYPE:
2888
+ ret_val = processLOBField (dataValue->dv_value, param_columnData->dv_length);
2889
+ break;
2890
+
2891
+ case IIAPI_BYTE_TYPE:
2892
+ case IIAPI_LOGKEY_TYPE:
2893
+ case IIAPI_TABKEY_TYPE:
2894
+ case IIAPI_VBYTE_TYPE:
2895
+ /* tested */
2896
+ case IIAPI_TXT_TYPE:
2897
+ case IIAPI_VCH_TYPE:
2898
+ ret_val = processStringField (dataValue->dv_value, param_columnData->dv_length);
2899
+ break;
2900
+
2901
+ case IIAPI_INT_TYPE:
2902
+ ret_val = processIntField (dataValue);
2903
+ break;
2904
+
2905
+ case IIAPI_DEC_TYPE:
2906
+ ret_val = processDecimalField (dataValue, param_descrParm);
2907
+ break;
2908
+
2909
+ case IIAPI_FLT_TYPE:
2910
+ ret_val = processFloatField (dataValue);
2911
+ break;
2912
+
2913
+ case IIAPI_DTE_TYPE:
2914
+ #ifdef IIAPI_DATE_TYPE
2915
+ case IIAPI_DATE_TYPE:
2916
+ case IIAPI_TIME_TYPE:
2917
+ case IIAPI_TMWO_TYPE:
2918
+ case IIAPI_TMTZ_TYPE:
2919
+ case IIAPI_TS_TYPE:
2920
+ case IIAPI_TSWO_TYPE:
2921
+ case IIAPI_TSTZ_TYPE:
2922
+ case IIAPI_INTYM_TYPE:
2923
+ case IIAPI_INTDS_TYPE:
2924
+ #endif
2925
+ ret_val = processDateField (dataValue, param_dataType);
2926
+ break;
2927
+
2928
+ case IIAPI_MNY_TYPE:
2929
+ ret_val = processMoneyField (dataValue);
2930
+ break;
2931
+
2932
+ case IIAPI_NCHA_TYPE:
2933
+ ret_val = processUTF16CharField (dataValue->dv_value, param_columnData->dv_length);
2934
+ break;
2935
+
2936
+ case IIAPI_CHR_TYPE:
2937
+ case IIAPI_CHA_TYPE:
2938
+ default:
2939
+ ret_val = processCharField ((char *)dataValue->dv_value, param_columnData->dv_length);
2940
+ }
2941
+
2942
+ if (ii_globals.debug)
2943
+ printf ("Exiting %s.\n", function_name);
2944
+ return ret_val;
2945
+ }
2946
+
2947
+
2948
+ int getColumn (II_CONN *ii_conn, RUBY_IIAPI_DATAVALUE * param_columnData, II_LONG param_columnType)
2949
+ {
2950
+ IIAPI_GETCOLPARM getColParm;
2951
+ IIAPI_DATAVALUE *dataValue = param_columnData->dataValue;
2952
+ int status = 0;
2953
+ long bufferLen = 0;
2954
+ char *buffer = NULL;
2955
+ char *bufferPtr = NULL;
2956
+ char function_name[] = "getColumn";
2957
+ short int segmentLen = 0;
2958
+ char *lob_data = NULL;
2959
+
2960
+ if (ii_globals.debug)
2961
+ printf ("Entering %s.\n", function_name);
2962
+
2963
+ getColParm.gc_columnData = dataValue;
2964
+
2965
+ do
2966
+ {
2967
+ getColParm.gc_genParm.gp_callback = NULL;
2968
+ getColParm.gc_genParm.gp_closure = NULL;
2969
+ getColParm.gc_rowCount = 1;
2970
+ getColParm.gc_columnCount = 1;
2971
+ getColParm.gc_rowsReturned = 0;
2972
+ getColParm.gc_stmtHandle = ii_conn->stmtHandle;
2973
+ getColParm.gc_moreSegments = 0;
2974
+ dataValue->dv_length = 0;
2975
+
2976
+ IIapi_getColumns (&getColParm);
2977
+ ii_sync (&(getColParm.gc_genParm));
2978
+ if (ii_checkError (&(getColParm.gc_genParm)))
2979
+ {
2980
+ memset (dataValue, 0, sizeof (IIAPI_DATAVALUE));
2981
+ rb_raise (rb_eRuntimeError, "IIapi_getColumns() failed.");
2982
+ break;
2983
+ }
2984
+
2985
+ /* Size of the data being returned is in the first 2 bytes of dataValue->dv_value */
2986
+ if (param_columnType == IIAPI_LVCH_TYPE ||
2987
+ param_columnType == IIAPI_LBYTE_TYPE ||
2988
+ param_columnType == IIAPI_LNVCH_TYPE)
2989
+ {
2990
+ param_columnData->dv_length = *(II_INT2 *)dataValue->dv_value;
2991
+ }
2992
+ else
2993
+ {
2994
+ param_columnData->dv_length = dataValue->dv_length;
2995
+ }
2996
+
2997
+ /* Handle LOB data slightly differently */
2998
+ if (param_columnType == IIAPI_LVCH_TYPE ||
2999
+ param_columnType == IIAPI_LBYTE_TYPE ||
3000
+ param_columnType == IIAPI_LNVCH_TYPE)
3001
+ {
3002
+ /* Copy the first two bytes of dataValue->dv_value to get the length */
3003
+ /* of the data fetched from the server */
3004
+ memcpy ((char *) &segmentLen, dataValue->dv_value, 2);
3005
+
3006
+ if (buffer == NULL)
3007
+ {
3008
+ /* Init buffer to place LOB data */
3009
+ buffer = ii_allocate(LOB_SEGMENT_SIZE, sizeof(char *));
3010
+ bufferPtr = buffer;
3011
+ }
3012
+ else
3013
+ {
3014
+ /*
3015
+ ** TODO Improve performance by not reallocating new larger
3016
+ ** buffer for every lob segment (approx 4K bytes each). See
3017
+ ** Ingres ODBC driver for more efficient algorithm.
3018
+ */
3019
+ buffer = ii_reallocate (buffer, bufferLen + segmentLen + 1, sizeof(char));
3020
+ bufferPtr = buffer + bufferLen;
3021
+ }
3022
+ memcpy (bufferPtr, (char *)dataValue->dv_value + 2, segmentLen);
3023
+ bufferLen += segmentLen;
3024
+ param_columnData->dv_length = bufferLen;
3025
+ }
3026
+ }
3027
+ while (getColParm.gc_moreSegments);
3028
+
3029
+ if (buffer != NULL) /* If blob col, return alloc'd buffer */
3030
+ {
3031
+ if (dataValue->dv_value)
3032
+ {
3033
+ ii_free((void **) &(dataValue->dv_value));
3034
+ }
3035
+ dataValue->dv_value = buffer;
3036
+ }
3037
+
3038
+ if (ii_globals.debug)
3039
+ printf ("Exiting %s.\n", function_name);
3040
+ return getColParm.gc_genParm.gp_status;
3041
+ }
3042
+
3043
+
3044
+ int
3045
+ processColumn (II_CONN *ii_conn, VALUE * param_values, int param_columnNumber, IIAPI_DESCRIPTOR * param_descrParm)
3046
+ {
3047
+ RUBY_IIAPI_DATAVALUE columnData = {FALSE, 0, NULL};
3048
+ int done = FALSE;
3049
+ char *tmp = NULL;
3050
+ char function_name[] = "processColumn";
3051
+
3052
+
3053
+ if (ii_globals.debug)
3054
+ printf ("Entering %s.\n", function_name);
3055
+
3056
+ /* Allocate storage space for incoming data */
3057
+ tmp = (char *) ii_allocate(param_descrParm->ds_length + 1, sizeof(char));
3058
+ memset (tmp, 0, param_descrParm->ds_length + 1);
3059
+ columnData.dataValue[0].dv_value = tmp;
3060
+
3061
+ if (getColumn (ii_conn, &columnData, param_descrParm->ds_dataType ) >= IIAPI_ST_NO_DATA)
3062
+ {
3063
+ /* we've reached the end of the data */
3064
+ done = TRUE;
3065
+ }
3066
+ else
3067
+ {
3068
+ /* let's copy out and convert the data */
3069
+ VALUE nextEntry;
3070
+
3071
+ if (columnData.dataValue[0].dv_null == TRUE)
3072
+ {
3073
+ /* this is a null value. Don't try to convert it. */
3074
+ if (ii_globals.debug)
3075
+ printf ("\nFound a NULL value\n");
3076
+ nextEntry = rb_str_new2 ("NULL");
3077
+ }
3078
+ else
3079
+ {
3080
+ nextEntry = processField (ii_conn, &columnData, param_columnNumber, param_descrParm);
3081
+ }
3082
+
3083
+ rb_ary_push ((*param_values), nextEntry);
3084
+ }
3085
+
3086
+ if (tmp)
3087
+ {
3088
+ ii_free((void **) &(columnData.dataValue[0].dv_value));
3089
+ }
3090
+
3091
+ if (ii_globals.debug)
3092
+ printf ("Exiting %s.\n", function_name);
3093
+ return done;
3094
+ }
3095
+
3096
+
3097
+ void
3098
+ ii_api_get_data (II_CONN *ii_conn, IIAPI_GETDESCRPARM * param_descrParm)
3099
+ {
3100
+ int done = FALSE;
3101
+ char function_name[] = "ii_api_get_data";
3102
+ if (ii_globals.debug)
3103
+ printf ("Entering %s.\n", function_name);
3104
+
3105
+ /* loop until all rows are fetched */
3106
+ while (!done)
3107
+ {
3108
+ VALUE values;
3109
+ int columnCount = 0;
3110
+
3111
+ values = rb_ary_new ();
3112
+
3113
+ while (columnCount < param_descrParm->gd_descriptorCount && !done)
3114
+ {
3115
+ done = processColumn (ii_conn, &values, columnCount, &(param_descrParm->gd_descriptor[columnCount]));
3116
+ columnCount++;
3117
+ }
3118
+
3119
+ if (!done)
3120
+ {
3121
+ rb_ary_push (ii_conn->resultset, values);
3122
+ }
3123
+ }
3124
+
3125
+ if (ii_globals.debug)
3126
+ printf ("Exiting %s.\n", function_name);
3127
+ }
3128
+
3129
+
3130
+ VALUE
3131
+ ii_execute_query (II_CONN *ii_conn, char *param_sqlText, int param_argc, VALUE param_params)
3132
+ {
3133
+ IIAPI_GETDESCRPARM getDescrParm;
3134
+ IIAPI_WAITPARM waitParm = { -1 };
3135
+ VALUE ret_val;
3136
+ char function_name[] = "ii_execute_query";
3137
+ if (ii_globals.debug)
3138
+ printf ("Entering %s.\n", function_name);
3139
+
3140
+ if (ii_globals.debug)
3141
+ printf ("\n AUTOCOMMIT_ON = %d\n", ii_conn->autocommit);
3142
+
3143
+ ii_api_query (ii_conn, param_sqlText, param_argc, param_params);
3144
+ ii_api_getDescriptors (ii_conn, &getDescrParm);
3145
+
3146
+ if (ii_globals.debug)
3147
+ printf ("\nFound %d column(s)\n", getDescrParm.gd_descriptorCount);
3148
+
3149
+ /* fetch the query results */
3150
+ if (getDescrParm.gd_descriptorCount > 0)
3151
+ {
3152
+ init_rb_array (&ii_conn->resultset);
3153
+ init_rb_array (&ii_conn->r_data_sizes);
3154
+ init_rb_array (&ii_conn->r_column_names);
3155
+ init_rb_array (&ii_conn->r_data_types);
3156
+
3157
+ ii_api_get_metadata (ii_conn, &getDescrParm);
3158
+ ii_api_get_data (ii_conn, &getDescrParm);
3159
+ }
3160
+
3161
+ ret_val = ii_conn->resultset;
3162
+ global_rows_affected = getRowsAffected (ii_conn);
3163
+
3164
+ ii_api_query_close (ii_conn);
3165
+
3166
+ if (ii_conn->autocommit)
3167
+ ii_api_commit (ii_conn);
3168
+
3169
+ if (ii_globals.debug)
3170
+ printf ("Exiting %s.\n", function_name);
3171
+ return ret_val;
3172
+ }
3173
+
3174
+
3175
+ /*
3176
+ * Document-method: execute
3177
+ *
3178
+ * call-seq:
3179
+ * Ingres.execute(sql[ param_types, param_values]) -> Array
3180
+ *
3181
+ * Executes the supplied _sql_ statement returning the results as a
3182
+ * two-dimensional Array. The first dimension represents each row, and the
3183
+ * second dimension represents each column within the row. _param_types_ is
3184
+ * a string of letters, with each letter representing the type of each
3185
+ * parameter being passed.
3186
+ *
3187
+ * For SQL queries or database procedure calls that contain parameters, use the
3188
+ * Ingres.execute() method in one of the following formats.
3189
+ * For selects, inserts, deletes, and updates:
3190
+ *
3191
+ * execute(sql [ [, param_type, param_value ] … ] )
3192
+ *
3193
+ * For database procedure calls:
3194
+ *
3195
+ * execute("{ <call> | <execute procedure> procedure_name [ (column_name = ? [
3196
+ * [ , column_name = ? ] … ] ) ] }" [ [ , column_name, param_type, param_value
3197
+ * ] … ] )
3198
+ *
3199
+ * where parameters in the sql text are represented by question marks (?) and
3200
+ * there is one set of param_type/param_value entries for each one.
3201
+ * param_type must be one of the following single characters:
3202
+ *
3203
+ * <table>
3204
+ * <tr><td>*param_type*<td>*Description*
3205
+ * <tr><td>b<td>byte
3206
+ * <tr><td>B<td>long_byte
3207
+ * <tr><td>c<td>char
3208
+ * <tr><td>d<td>date
3209
+ * <tr><td>D<td>decimal
3210
+ * <tr><td>f<td>float
3211
+ * <tr><td>i<td>integer
3212
+ * <tr><td>n<td>nchar
3213
+ * <tr><td>N<td>nvarchar
3214
+ * <tr><td>t<td>text
3215
+ * <tr><td>T<td>long_text
3216
+ * <tr><td>v<td>varchar
3217
+ * <tr><td>V<td>long_varchar
3218
+ * </table>
3219
+ *
3220
+ * param_value should correspond to the expected type being sent.
3221
+ *
3222
+ * Example usage:
3223
+ *
3224
+ * conn = Ingres.new()
3225
+ * conn.connect(:database => "demodb")
3226
+ * results = conn.execute("select up_first, up_last, up_email from user_profile where up_id = ?", "i", 1)
3227
+ *
3228
+ */
3229
+ VALUE
3230
+ ii_execute (int param_argc, VALUE * param_argv, VALUE param_self)
3231
+ {
3232
+ VALUE ret_val = Qnil;
3233
+ VALUE param_queryText;
3234
+ VALUE params;
3235
+ VALUE savePtName;
3236
+ int i;
3237
+ char function_name[] = "ii_execute";
3238
+ II_CONN *ii_conn;
3239
+
3240
+ if (ii_globals.debug)
3241
+ printf ("Entering %s.\n", function_name);
3242
+
3243
+ rb_scan_args (param_argc, param_argv, "1*", &param_queryText, &params);
3244
+
3245
+ Check_Type(param_queryText, T_STRING);
3246
+
3247
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
3248
+
3249
+ /* determine what sort of query is being executed */
3250
+ if (ii_globals.debug)
3251
+ printf ("Classifying query\n");
3252
+ ii_conn->queryType = ii_query_type(RSTRING_PTR (param_queryText));
3253
+ if (ii_globals.debug)
3254
+ printf ("Classified query\n");
3255
+
3256
+ switch (ii_conn->queryType)
3257
+ {
3258
+ case INGRES_SQL_COMMIT:
3259
+ if (ii_conn->tranHandle != NULL)
3260
+ ii_api_commit (ii_conn);
3261
+ else if (ii_globals.debug || ii_globals.debug_transactions)
3262
+ rb_warn ("Attempting to ii_api_commit a non-existent transaction");
3263
+ break;
3264
+ case INGRES_SQL_ROLLBACK:
3265
+ if (ii_conn->tranHandle != NULL)
3266
+ ii_api_rollback (ii_conn, NULL);
3267
+ else if (ii_globals.debug || ii_globals.debug_transactions)
3268
+ rb_warn ("Attempting to ii_api_rollback a non-existent transaction");
3269
+ break;
3270
+ case INGRES_SQL_ROLLBACK_TO:
3271
+ case INGRES_SQL_ROLLBACK_WORK_TO:
3272
+ /* ROLLBACK [WORK] TO SAVEPOINT */
3273
+ if (ii_conn->tranHandle == NULL)
3274
+ {
3275
+ rb_raise (rb_eRuntimeError, "Unable to rollback a non-existent transaction");
3276
+ }
3277
+ else
3278
+ {
3279
+ /* Extract Savepoint name */
3280
+ savePtName = ii_savepoint_name(ii_conn, StringValuePtr(param_queryText));
3281
+ ii_rollback (1, &savePtName, param_self);
3282
+ }
3283
+ break;
3284
+ case INGRES_START_TRANSACTION:
3285
+ startTransaction (param_self);
3286
+ break;
3287
+ case INGRES_SQL_CONNECT:
3288
+ rb_warn ("Use connect() to connect to a database");
3289
+ break;
3290
+ case INGRES_SQL_DISCONNECT:
3291
+ rb_warn ("Use disconnect() to disconnect from a database");
3292
+ break;
3293
+ case INGRES_SQL_GETDBEVENT:
3294
+ rb_warn ("Ingres 'GET DBEVENT' is not supported at the current time");
3295
+ break;
3296
+ case INGRES_SQL_SAVEPOINT:
3297
+ /* We cannot generate a save point if there is no transaction or if auto commit is in effect */
3298
+ if (ii_conn->tranHandle == NULL)
3299
+ {
3300
+ rb_raise (rb_eRuntimeError, "Unable to generate a save point if there is no active transaction");
3301
+ }
3302
+ else
3303
+ {
3304
+ /* Extract Savepoint name */
3305
+ savePtName = ii_savepoint_name(ii_conn, StringValuePtr(param_queryText));
3306
+ ii_api_savepoint (ii_conn, savePtName);
3307
+ }
3308
+ break;
3309
+ case INGRES_SQL_AUTOCOMMIT:
3310
+ rb_warn ("Use autocommit() to set the auto-commit state");
3311
+ break;
3312
+ case INGRES_SQL_COPY:
3313
+ rb_warn ("Ingres 'COPY TABLE() INTO/FROM' is not supported at the current time");
3314
+ break;
3315
+ case INGRES_SQL_SELECT:
3316
+ case INGRES_SQL_INSERT:
3317
+ case INGRES_SQL_UPDATE:
3318
+ case INGRES_SQL_DELETE:
3319
+ case INGRES_SQL_CREATE:
3320
+ case INGRES_SQL_ALTER:
3321
+ case INGRES_SQL_EXECUTE_PROCEDURE:
3322
+ case INGRES_SQL_CALL:
3323
+ default:
3324
+ if (ii_globals.debug || ii_globals.debug_transactions)
3325
+ printf ("Executing %s\n", StringValuePtr (param_queryText));
3326
+ ret_val = ii_execute_query (ii_conn, StringValuePtr (param_queryText), param_argc - 1, params);
3327
+ break;
3328
+ }
3329
+
3330
+ if (ii_globals.debug)
3331
+ printf ("Exiting %s.\n", function_name);
3332
+ return ret_val;
3333
+ }
3334
+
3335
+ /*
3336
+ * Document-method: tables
3337
+ *
3338
+ * call-seq:
3339
+ * Ingres.tables() -> Array
3340
+ *
3341
+ * Returns a list of all the tables in the database associated with this instance.
3342
+ *
3343
+ * Example usage:
3344
+ *
3345
+ * conn = Ingres.new()
3346
+ * conn = Ingres.connect(:database => "demodb")
3347
+ * con.tables
3348
+ *
3349
+ */
3350
+ static VALUE
3351
+ ii_tables (VALUE param_self)
3352
+ {
3353
+ VALUE table_list;
3354
+ VALUE sql_string;
3355
+ VALUE *params;
3356
+ char function_name[] = "ii_tables";
3357
+ II_CONN *ii_conn = NULL;
3358
+
3359
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
3360
+
3361
+ if (ii_globals.debug)
3362
+ printf ("Entering %s.\n", function_name);
3363
+
3364
+ sql_string = rb_str_new2 ("SELECT table_name FROM iitables WHERE table_type = 'T' AND table_name not like 'ii%'");
3365
+ table_list = ii_execute (1, &sql_string, param_self);
3366
+
3367
+ if (ii_globals.debug)
3368
+ printf ("Exiting %s.\n", function_name);
3369
+ return table_list;
3370
+ }
3371
+
3372
+ /*
3373
+ * Document-method: current_database
3374
+ *
3375
+ * call-seq:
3376
+ * Ingres.current_database() -> String
3377
+ *
3378
+ * Returns the name of associated database, if connected.
3379
+ *
3380
+ * Example usage:
3381
+ *
3382
+ * conn = Ingres.new()
3383
+ * conn = Ingres.connect(:database => "demodb")
3384
+ * puts conn.current_database()
3385
+ *
3386
+ */
3387
+ VALUE
3388
+ ii_current_database (VALUE param_self)
3389
+ {
3390
+ VALUE curr_db;
3391
+ char function_name[] = "ii_current_database";
3392
+ II_CONN *ii_conn = NULL;
3393
+
3394
+ if (ii_globals.debug)
3395
+ printf ("Entering %s.\n", function_name);
3396
+
3397
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
3398
+
3399
+ curr_db = rb_str_new2 (ii_conn->currentDatabase);
3400
+
3401
+ if (ii_globals.debug)
3402
+ printf ("Exiting %s.\n", function_name);
3403
+ return curr_db;
3404
+ }
3405
+
3406
+ VALUE
3407
+ ii_crash_it (VALUE param_self) //:nodoc
3408
+ {
3409
+ VALUE a_string;
3410
+ VALUE yet_another_string;
3411
+ char *my_string = NULL;
3412
+ char *another_string = NULL;
3413
+ char function_name[] = "ii_crash_it";
3414
+ if (ii_globals.debug)
3415
+ printf ("Entering %s.\n", function_name);
3416
+
3417
+ printf ("\n\nMalloc some memory\n");
3418
+ my_string = malloc (strlen ("activerecord_unittest") + 1);
3419
+ my_string = "activerecord_unittest";
3420
+
3421
+ printf ("\n Create the Ruby string \n");
3422
+ a_string = rb_str_new2 (my_string);
3423
+
3424
+ printf ("Now convert it to a C string\n");
3425
+ another_string = STR2CSTR (a_string);
3426
+
3427
+ printf ("Now convert it back to a Ruby string\n");
3428
+ yet_another_string = rb_str_new2 (another_string);
3429
+
3430
+ printf ("Done!");
3431
+
3432
+ if (ii_globals.debug)
3433
+ printf ("Exiting %s.\n", function_name);
3434
+ return yet_another_string;
3435
+ }
3436
+
3437
+ /*
3438
+ * Document-method: rows_affected
3439
+ *
3440
+ * call-seq:
3441
+ * Ingres.rows_affected() -> Fixnum
3442
+ *
3443
+ * Returns the number of rows affected by the last SQL statement.
3444
+ *
3445
+ * conn = Ingres.new()
3446
+ * conn = Ingres.connect(:database => "demodb")
3447
+ * users = conn.execute("select * from user_profile")
3448
+ * user_count = conn.rows_affected()
3449
+ *
3450
+ */
3451
+ VALUE
3452
+ ii_rows_affected (VALUE param_self)
3453
+ {
3454
+ VALUE return_value;
3455
+ char function_name[] = "ii_rows_affected";
3456
+ if (ii_globals.debug)
3457
+ printf ("Entering %s.\n", function_name);
3458
+
3459
+ return_value = INT2NUM (global_rows_affected);
3460
+
3461
+ if (ii_globals.debug)
3462
+ printf ("Exiting %s.\n", function_name);
3463
+ return return_value;
3464
+ }
3465
+
3466
+ /*
3467
+ * Document-method: data_types
3468
+ *
3469
+ * call-seq:
3470
+ * Ingres.data_types() -> Array
3471
+ *
3472
+ * Returns an Array of data types names for the last SQL SELECT statement executed.
3473
+ *
3474
+ * conn = Ingres.new()
3475
+ * conn = Ingres.connect(:database => "demodb")
3476
+ * users = conn.execute("select * from user_profile")
3477
+ * types = conn.data_types()
3478
+ *
3479
+ */
3480
+ VALUE
3481
+ ii_return_data_types (VALUE param_self)
3482
+ {
3483
+ char function_name[] = "ii_return_data_types";
3484
+ II_CONN *ii_conn = NULL;
3485
+
3486
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
3487
+
3488
+ if (ii_globals.debug)
3489
+ printf ("Entering %s.\n", function_name);
3490
+
3491
+ return ii_conn->r_data_types;
3492
+ }
3493
+
3494
+
3495
+ /*
3496
+ * Document-method: column_list_of_names
3497
+ *
3498
+ * call-seq:
3499
+ * Ingres.column_list_of_names() -> Array
3500
+ *
3501
+ * Returns an Array of column names for the last SQL _SELECT_ statement executed.
3502
+ *
3503
+ * conn = Ingres.new()
3504
+ * conn = Ingres.connect(:database => "demodb")
3505
+ * users = conn.execute("select * from user_profile")
3506
+ * columns = conn.column_list_of_names()
3507
+ *
3508
+ */
3509
+ VALUE
3510
+ ii_column_names (VALUE param_self)
3511
+ {
3512
+ char function_name[] = "ii_column_names";
3513
+ II_CONN *ii_conn = NULL;
3514
+
3515
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
3516
+
3517
+ if (ii_globals.debug)
3518
+ printf ("Entering %s.\n", function_name);
3519
+
3520
+ return ii_conn->r_column_names;
3521
+ }
3522
+
3523
+
3524
+ /*
3525
+ * Document-method: data_sizes
3526
+ *
3527
+ * call-seq:
3528
+ * Ingres.data_sizes() -> Array
3529
+ *
3530
+ * Returns an Array of Fixnum values representing the width of each column from the last
3531
+ * SQL SELECT statement executed.
3532
+ *
3533
+ * conn = Ingres.new()
3534
+ * conn = Ingres.connect(:database => "demodb")
3535
+ * users = conn.execute("select * from user_profile")
3536
+ * sizes = conn.data_sizes()
3537
+ *
3538
+ */
3539
+ VALUE
3540
+ ii_data_sizes (VALUE param_self)
3541
+ {
3542
+ char function_name[] = "ii_data_sizes";
3543
+ II_CONN *ii_conn = NULL;
3544
+
3545
+ Data_Get_Struct(param_self, II_CONN, ii_conn);
3546
+
3547
+ if (ii_globals.debug)
3548
+ printf ("Entering %s.\n", function_name);
3549
+
3550
+
3551
+ return ii_conn->r_data_sizes;
3552
+ }
3553
+
3554
+
3555
+ /*
3556
+ * Document-method: set_debug_flag
3557
+ *
3558
+ * call-seq:
3559
+ * Ingres.set_debug_flag(flag, flag_value) -> nil
3560
+ *
3561
+ * Turns trace debugging on or off
3562
+ *
3563
+ * Valid values:
3564
+ * * _flag_ can be one of <tt>GLOBAL_DEBUG</tt>, <tt>DEBUG_TRANSACTIONS</tt>, <tt>DEBUG_SQL</tt>, <tt>DEBUG_TERMINATION</tt>
3565
+ * * _flag_value_ is either <tt>TRUE</tt> or <tt>FALSE</tt>
3566
+ *
3567
+ * Example usage:
3568
+ *
3569
+ * conn = Ingres.new()
3570
+ * conn.set_debug_flag("GLOBAL_DEBUG","TRUE")
3571
+ *
3572
+ */
3573
+ VALUE
3574
+ ii_set_debug_flag (VALUE param_self, VALUE param_debug_flag, VALUE param_debug_flag_value)
3575
+ {
3576
+ int new_debug_value = FALSE;
3577
+ char function_name[] = "ii_set_debug_flag";
3578
+ if (ii_globals.debug)
3579
+ printf ("Entering %s.\n", function_name);
3580
+
3581
+ Check_Type (param_debug_flag, T_STRING);
3582
+ Check_Type (param_debug_flag_value, T_STRING);
3583
+
3584
+ if (!strcmp (RSTRING_PTR (param_debug_flag_value), "TRUE"))
3585
+ new_debug_value = TRUE;
3586
+
3587
+ if (!strcmp (RSTRING_PTR (param_debug_flag), "GLOBAL_DEBUG"))
3588
+ ii_globals.debug = new_debug_value;
3589
+ else if (!strcmp (RSTRING_PTR (param_debug_flag), "DEBUG_TRANSACTIONS"))
3590
+ ii_globals.debug_transactions = new_debug_value;
3591
+ else if (!strcmp (RSTRING_PTR (param_debug_flag), "DEBUG_SQL"))
3592
+ ii_globals.debug_sql = new_debug_value;
3593
+ else if (!strcmp (RSTRING_PTR (param_debug_flag), "DEBUG_TERMINATION"))
3594
+ ii_globals.debug_termination = new_debug_value;
3595
+
3596
+ if (ii_globals.debug)
3597
+ printf ("Exiting %s.\n", function_name);
3598
+ return Qnil;
3599
+ }
3600
+
3601
+ size_t STtrmwhite (register char *string)
3602
+ {
3603
+ register size_t len;
3604
+ register char *nw = NULL;
3605
+ register size_t nwl;
3606
+ char function_name[] = "STtrmwhite";
3607
+ if (ii_globals.debug)
3608
+ {
3609
+ printf ("Entering %s.\n", function_name);
3610
+ }
3611
+
3612
+ /*
3613
+ ** after the loop, nw points to the first character beyond
3614
+ ** the last non-white character. Done this way because you
3615
+ ** can't reverse scan a string with CM efficiently
3616
+ */
3617
+ len = 0;
3618
+ nwl = 0;
3619
+ nw = string;
3620
+ while (*string != EOS)
3621
+ {
3622
+ len += CMbytecnt (string);
3623
+ if (!CMwhite (string))
3624
+ {
3625
+ CMnext (string);
3626
+ nw = string;
3627
+ nwl = len;
3628
+ }
3629
+ else
3630
+ {
3631
+ CMnext (string);
3632
+ }
3633
+ }
3634
+
3635
+ if (nw != string)
3636
+ {
3637
+ *nw = EOS;
3638
+ }
3639
+
3640
+ if (ii_globals.debug)
3641
+ printf ("Exiting %s.\n", function_name);
3642
+ return nwl;
3643
+ }
3644
+
3645
+ /********************************************************************
3646
+ *
3647
+ * Document-class: Ingres
3648
+ *
3649
+ * This class accesses the Ingres RDBMS through OpenAPI
3650
+ *
3651
+ * For example, to execute a simple query
3652
+ * require 'Ingres'
3653
+ * ing = Ingres.new()
3654
+ * ing.connect(:database => 'demodb')
3655
+ * result = ing.execute('SELECT * from user_profile')
3656
+ *
3657
+ * See README.rdoc for information about obtaining and installing the
3658
+ * Ingres Ruby Driver.
3659
+ */
3660
+ void
3661
+ Init_Ingres ()
3662
+ {
3663
+ char function_name[] = "Init_Ingres";
3664
+ if (ii_globals.debug)
3665
+ printf ("Entering %s.\n", function_name);
3666
+
3667
+ /* Define Ingres Class */
3668
+ cIngres = rb_define_class ("Ingres", rb_cObject);
3669
+
3670
+ /* Allocation of memory for II_CONN structure */
3671
+ rb_define_alloc_func(cIngres, rb_ingres_alloc);
3672
+
3673
+ /* Constants for the driver */
3674
+
3675
+ /* Driver version */
3676
+ rb_define_const(cIngres, "VERSION", rb_str_new2 (RUBY_INGRES_VERSION));
3677
+ /* Driver OpenAPI level */
3678
+ rb_define_const(cIngres, "API_LEVEL", INT2FIX(RUBY_INGRES_API));
3679
+ /* Source code revision level */
3680
+ rb_define_const(cIngres, "REVISION", rb_str_new2 ("$Rev$"));
3681
+
3682
+ rb_define_method (cIngres, "initialize", ii_init, 0);
3683
+ rb_define_method (cIngres, "connect", ii_connect, -1);
3684
+ rb_define_method (cIngres, "disconnect", ii_disconnect, 0);
3685
+ rb_define_method (cIngres, "execute", ii_execute, -1);
3686
+ rb_define_method (cIngres, "tables", ii_tables, 0);
3687
+ rb_define_method (cIngres, "current_database", ii_current_database, 0);
3688
+ rb_define_method (cIngres, "data_types", ii_return_data_types, 0);
3689
+ rb_define_method (cIngres, "rows_affected", ii_rows_affected, 0);
3690
+ rb_define_method (cIngres, "column_list_of_names", ii_column_names, 0);
3691
+ rb_define_method (cIngres, "data_sizes", ii_data_sizes, 0);
3692
+ rb_define_method (cIngres, "set_environment", ii_set_environment, -1);
3693
+
3694
+ /* Transaction Methods */
3695
+ rb_define_method (cIngres, "commit", ii_commit, 0);
3696
+ rb_define_method (cIngres, "rollback", ii_rollback, -1);
3697
+ rb_define_method (cIngres, "savepoint", ii_savepoint, 1);
3698
+
3699
+ /* Aliases of methods */
3700
+ rb_define_alias (cIngres, "connect_with_credentials", "connect");
3701
+ rb_define_alias (cIngres, "pexecute", "execute"); // Deprecated
3702
+ rb_define_alias (cIngres, "exec", "execute");
3703
+
3704
+ rb_define_method (cIngres, "crash_it", ii_crash_it, 0);
3705
+ rb_define_method (cIngres, "set_debug_flag", ii_set_debug_flag, 2);
3706
+
3707
+ /* :date_format Constants */
3708
+
3709
+ /* DMY Date format */
3710
+ rb_define_const(cIngres,"DATE_FORMAT_DMY", INT2FIX(IIAPI_CPV_DFRMT_DMY));
3711
+ /* FINLAND Date format */
3712
+ rb_define_const(cIngres,"DATE_FORMAT_FINLAND", INT2FIX(IIAPI_CPV_DFRMT_FINNISH));
3713
+ /* GERMAN Date format */
3714
+ rb_define_const(cIngres,"DATE_FORMAT_GERMAN", INT2FIX(IIAPI_CPV_DFRMT_GERMAN));
3715
+ /* ISO Date format */
3716
+ rb_define_const(cIngres,"DATE_FORMAT_ISO", INT2FIX(IIAPI_CPV_DFRMT_ISO));
3717
+ /* ISO4 Date format */
3718
+ rb_define_const(cIngres,"DATE_FORMAT_ISO4", INT2FIX(IIAPI_CPV_DFRMT_ISO4));
3719
+ /* MDY Date format */
3720
+ rb_define_const(cIngres,"DATE_FORMAT_MDY", INT2FIX(IIAPI_CPV_DFRMT_MDY));
3721
+ /* MULTINATIONAL Date format */
3722
+ rb_define_const(cIngres,"DATE_FORMAT_MULTINATIONAL", INT2FIX(IIAPI_CPV_DFRMT_MULTI));
3723
+ /* MULTINATIONAL4 Date format */
3724
+ rb_define_const(cIngres,"DATE_FORMAT_MULTINATIONAL4", INT2FIX(IIAPI_CPV_DFRMT_MLT4));
3725
+ /* SWEDEN Date format */
3726
+ rb_define_const(cIngres,"DATE_FORMAT_SWEDEN", INT2FIX(IIAPI_CPV_DFRMT_FINNISH));
3727
+ /* US Date format */
3728
+ rb_define_const(cIngres,"DATE_FORMAT_US", INT2FIX(IIAPI_CPV_DFRMT_US));
3729
+ /* YMD Date format */
3730
+ rb_define_const(cIngres,"DATE_FORMAT_YMD", INT2FIX(IIAPI_CPV_DFRMT_YMD));
3731
+
3732
+
3733
+ if (ii_globals.debug)
3734
+ printf ("Exiting %s.\n", function_name);
3735
+ }
3736
+
3737
+
3738
+ /* Allocate the II_CONN structure used to store connection state et. al. */
3739
+ static VALUE rb_ingres_alloc(VALUE klass)
3740
+ {
3741
+ II_CONN *ii_conn = NULL;
3742
+
3743
+ char function_name[] = "rb_ingres_alloc";
3744
+ if (ii_globals.debug)
3745
+ printf ("Entering %s.\n", function_name);
3746
+
3747
+ ii_conn = (II_CONN *)ALLOC(II_CONN);
3748
+ ii_conn_init(ii_conn);
3749
+
3750
+ return Data_Wrap_Struct(klass, NULL, free_ii_conn, ii_conn);
3751
+ }
3752
+ static void free_ii_conn (II_CONN *ii_conn)
3753
+ {
3754
+ char function_name[] = "free_ii_conn";
3755
+ if (ii_globals.debug)
3756
+ printf ("Entering %s.\n", function_name);
3757
+
3758
+ if (ii_conn)
3759
+ {
3760
+ /* Clean up the connection */
3761
+ ii_api_rollback (ii_conn, NULL);
3762
+ ii_api_disconnect (ii_conn);
3763
+ }
3764
+ }
3765
+
3766
+ /* Set the defaults for II_CONN internals */
3767
+ static void ii_conn_init(II_CONN *ii_conn)
3768
+ {
3769
+ char function_name[] = "ii_conn_init";
3770
+ if (ii_globals.debug)
3771
+ printf ("Entering %s.\n", function_name);
3772
+
3773
+ ii_conn->autocommit = TRUE;
3774
+ ii_conn->connHandle = NULL;
3775
+ ii_conn->tranHandle = NULL;
3776
+ ii_conn->stmtHandle = NULL;
3777
+ ii_conn->envHandle = NULL;
3778
+ ii_conn->fieldCount = 0;
3779
+ ii_conn->lobSegmentSize = 0;
3780
+ ii_conn->descriptor = NULL;
3781
+ ii_conn->errorText = NULL;
3782
+ ii_conn->sqlstate[0] = '\0';
3783
+ ii_conn->errorCode = 0;
3784
+ ii_conn->apiLevel = IIAPI_VERSION - 1;
3785
+ ii_conn->paramCount = 0;
3786
+ ii_conn->cursor_id = NULL;
3787
+ ii_conn->cursor_mode = INGRES_CURSOR_READONLY;
3788
+ ii_conn->currentDatabase = NULL;
3789
+ ii_conn->keep_me = (VALUE) FALSE;
3790
+ ii_conn->resultset = (VALUE) FALSE;
3791
+ ii_conn->r_column_names = (VALUE) FALSE;
3792
+ ii_conn->r_data_sizes = (VALUE) FALSE;
3793
+ ii_conn->r_data_types = (VALUE) FALSE;
3794
+ ii_conn->savePtList = NULL; /* Linked list of Save point names and their handles */
3795
+ ii_conn->lastSavePtEntry = NULL;
3796
+
3797
+ }
3798
+
3799
+ static int ii_query_type(char *statement)
3800
+ {
3801
+ char function_name[] = "ii_query_type";
3802
+ int count = 0;
3803
+ char *statement_ptr = NULL;
3804
+
3805
+ if (ii_globals.debug)
3806
+ printf ("Entering %s.\n", function_name);
3807
+
3808
+ statement_ptr = statement;
3809
+ /* Look for some white space */
3810
+ while (isspace(*statement_ptr))
3811
+ {
3812
+ statement_ptr++;
3813
+ }
3814
+ for ( count = 0; count < INGRES_NO_OF_COMMANDS; count++ )
3815
+ {
3816
+ if (strncasecmp(SQL_COMMANDS[count].command, statement_ptr, SQL_COMMANDS[count].length) == 0)
3817
+ {
3818
+ if (count == INGRES_SQL_ROLLBACK)
3819
+ {
3820
+ /* Verify this is ROLLBACK and not ROLLBACK [WORK] TO */
3821
+ if (strlen(statement_ptr) != SQL_COMMANDS[count].length)
3822
+ {
3823
+ if (strncasecmp(SQL_COMMANDS[INGRES_SQL_ROLLBACK_TO].command, statement_ptr, SQL_COMMANDS[INGRES_SQL_ROLLBACK_TO].length) == 0)
3824
+ {
3825
+ return SQL_COMMANDS[INGRES_SQL_ROLLBACK_TO].code;
3826
+ }
3827
+ if (strncasecmp(SQL_COMMANDS[INGRES_SQL_ROLLBACK_WORK_TO].command, statement_ptr, SQL_COMMANDS[INGRES_SQL_ROLLBACK_WORK_TO].length) == 0)
3828
+ {
3829
+ return SQL_COMMANDS[INGRES_SQL_ROLLBACK_WORK_TO].code;
3830
+ }
3831
+ }
3832
+ }
3833
+ return SQL_COMMANDS[count].code;
3834
+ }
3835
+ }
3836
+
3837
+ return -1;
3838
+ }
3839
+
3840
+ VALUE
3841
+ ii_savepoint_name(II_CONN *ii_conn, char *statement)
3842
+ {
3843
+ char function_name[] = "ii_savepoint_name";
3844
+ int count = 0;
3845
+ char *statement_ptr = NULL;
3846
+ char *savePtName_start = NULL;
3847
+ char *tmp_savePtName = NULL;
3848
+ char ch;
3849
+ VALUE savePtName = (VALUE) FALSE;
3850
+
3851
+ if (ii_globals.debug)
3852
+ printf ("Entering %s.\n", function_name);
3853
+
3854
+ statement_ptr = statement + SQL_COMMANDS[ii_conn->queryType].length;
3855
+ /* Look for some white space */
3856
+ while (isspace(*statement_ptr))
3857
+ {
3858
+ statement_ptr++;
3859
+ }
3860
+ savePtName_start = statement_ptr;
3861
+
3862
+ while (*statement_ptr != EOS)
3863
+ {
3864
+ ch = *statement_ptr;
3865
+ if ((isalnum (*statement_ptr)) ||
3866
+ (ch == ' ') ||
3867
+ (ch == '_') ||
3868
+ (ch == '"'))
3869
+ {
3870
+ statement_ptr++;
3871
+ }
3872
+ else
3873
+ {
3874
+ rb_raise(rb_eRuntimeError, "%s : found an invalid character %c", function_name, ch);
3875
+ return Qnil;
3876
+ }
3877
+ }
3878
+
3879
+ tmp_savePtName = (char *) ii_allocate (statement_ptr - savePtName_start, sizeof(char *));
3880
+ memcpy (tmp_savePtName, savePtName_start, statement_ptr - savePtName_start);
3881
+ savePtName = rb_str_new2 (tmp_savePtName);
3882
+ ii_free ((void **) &tmp_savePtName);
3883
+
3884
+ return savePtName;
3885
+ }
3886
+
3887
+ /*
3888
+ vim: ts=2 sw=2 expandtab
3889
+ */