do_oracle 0.10.1-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ ## 0.10.1 (unreleased, in git)
2
+
3
+ Initial release.
data/INSTALL.markdown ADDED
@@ -0,0 +1,5 @@
1
+ INSTALLATION
2
+ ============
3
+
4
+
5
+ <http://blog.rayapps.com/2009/09/14/how-to-install-oracle-database-10g-on-mac-os-x-snow-leopard/>
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 - 2010 Yehuda Katz, Dirkjan Bussink, Raimonds Simanovskis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,106 @@
1
+ # do_oracle
2
+
3
+ * <http://dataobjects.info>
4
+
5
+ ## Description
6
+
7
+ An Oracle driver for DataObjects.
8
+
9
+ ## Features/Problems
10
+
11
+ This driver implements the DataObjects API for the Oracle relational database.
12
+
13
+ ## Synopsis
14
+
15
+ An example of usage:
16
+
17
+ @connection = DataObjects::Connection.new("oracle://employees")
18
+ @reader = @connection.create_command('SELECT * FROM users').execute_reader
19
+ @reader.next!
20
+
21
+ In the future, the `Connection` constructor will be able to be passed either a
22
+ DataObjects-style URL or JDBC style URL, when using do\_oracle on JRuby. However,
23
+ this feature is not currently working reliably and is a known issue.
24
+
25
+ ## Requirements
26
+
27
+ This driver is provided for the following platforms:
28
+ * Ruby MRI (1.8.6/7), 1.9: tested on Linux, Mac OS X and Windows platforms.
29
+ * JRuby 1.3.1 + (1.4+ recommended).
30
+ * Rubinius (experimental).
31
+
32
+ Additionally you should have the following prerequisites:
33
+ * `data_objects` gem
34
+ * `do_jdbc` gem (shared library), if running on JRuby.
35
+
36
+ ## Install
37
+
38
+ To install the gem:
39
+
40
+ gem install do_oracle
41
+
42
+ To compile and install from source:
43
+
44
+ * For MRI/Rubinius extensions:
45
+ * Install the `gcc` compiler. On OS X, you should install XCode tools. On
46
+ Ubuntu, run `apt-get install build-essential`.
47
+ * THESE INSTRUCTIONS ARE CURRENTLY INCOMPLETE!
48
+
49
+ * For JRuby extensions:
50
+ * Install the Java Development Kit (provided if you are
51
+ on a recent version of Mac OS X) from <http://java.sun.com>.
52
+ * Install a recent version of JRuby. Ensure `jruby` is in your `PATH` and/or
53
+ you have configured the `JRUBY_HOME` environment variable to point to your
54
+ JRuby installation.
55
+ * Install `data_objects` and `do_jdbc` with `jruby -S rake install`.
56
+
57
+ * Then, install this driver with `(jruby -S) rake install`.
58
+
59
+ For more information, see the Oracle driver wiki page:
60
+ <http://wiki.github.com/datamapper/do/oracle>.
61
+
62
+ ## Developers
63
+
64
+ Follow the above installation instructions. Additionally, you'll need:
65
+ * `bacon` gem for running specs.
66
+ * `YARD` gem for generating documentation.
67
+
68
+ See the DataObjects wiki for more comprehensive information on installing and
69
+ contributing to the JRuby-variant of this driver:
70
+ <http://wiki.github.com/datamapper/do/jruby>.
71
+
72
+ ### install oracle jdbc driver in maven
73
+
74
+ $ mvn install
75
+ will produce an error and give you message like (maybe with a different version). please follow these instructions to install the
76
+
77
+ Try downloading the file manually from:
78
+ http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html
79
+
80
+ Then, install it using the command:
81
+ mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc14 -Dversion=10.2.0.3.0 -Dpackaging=jar -Dfile=/path/to/file
82
+
83
+ Alternatively, if you host your own repository you can deploy the file there:
84
+ mvn deploy:deploy-file -DgroupId=com.oracle -DartifactId=ojdbc14 -Dversion=10.2.0.3.0 -Dpackaging=jar -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]
85
+
86
+ ### Specs
87
+
88
+ To run specs:
89
+
90
+ rake spec
91
+
92
+ To run specs without compiling extensions first:
93
+
94
+ rake spec_no_compile
95
+
96
+ To run individual specs:
97
+
98
+ rake spec TEST=spec/connection_spec.rb
99
+
100
+ (Note that the `rake` task uses a `TEST` parameter, not `SPEC`. This is because
101
+ the `Rake::TestTask` is used for executing the Bacon specs).
102
+
103
+ ## License
104
+
105
+ This code is licensed under an **MIT (X11) License**. Please see the
106
+ accompanying `LICENSE` file.
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/clean'
5
+
6
+ ROOT = Pathname(__FILE__).dirname.expand_path
7
+
8
+ require ROOT + 'lib/do_oracle/version'
9
+
10
+ JRUBY = RUBY_PLATFORM =~ /java/
11
+ IRONRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ironruby'
12
+ WINDOWS = Gem.win_platform? || (JRUBY && ENV_JAVA['os.name'] =~ /windows/i)
13
+ SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
14
+ BINARY_VERSION = '10.2.0.4.0'
15
+
16
+ CLEAN.include(%w[ {tmp,pkg}/ **/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,exp,DS_Store,rbc,db} ext/do_oracle/Makefile ext-java/target ])
17
+
18
+ begin
19
+ gem 'jeweler', '~> 1.4'
20
+ require 'jeweler'
21
+
22
+ Jeweler::Tasks.new do |gem|
23
+ gem.name = 'do_oracle'
24
+ gem.version = DataObjects::Oracle::VERSION
25
+ gem.summary = 'DataObjects Oracle Driver'
26
+ gem.description = 'Implements the DataObjects API for Oracle'
27
+ gem.platform = Gem::Platform::RUBY
28
+ gem.files = Dir['lib/**/*.rb', 'spec/**/*.rb', 'tasks/**/*.rake',
29
+ 'ext/**/*.{rb,c,h}', 'LICENSE', 'Rakefile',
30
+ '*.{markdown,rdoc,txt,yml}']
31
+ gem.extra_rdoc_files = FileList['README*', 'ChangeLog*', 'INSTALL.markdown',
32
+ 'LICENSE']
33
+ gem.test_files = FileList['spec/**/*.rb']
34
+
35
+ # rake-compiler should generate gemspecs for other platforms (e.g. 'java')
36
+ # and modify dependencies and extensions appropriately
37
+ gem.extensions << 'ext/do_oracle/extconf.rb'
38
+
39
+ gem.add_dependency 'data_objects', DataObjects::Oracle::VERSION
40
+ gem.add_dependency 'ruby-oci8', '~>2.0'
41
+
42
+ gem.add_development_dependency 'bacon', '~>1.1'
43
+ gem.add_development_dependency 'rake-compiler', '~>0.7'
44
+
45
+ gem.has_rdoc = false
46
+ gem.rubyforge_project = 'dorb'
47
+ gem.authors = [ 'Raimonds Simanovskis' ]
48
+ gem.email = 'raimonds.simanovskis@gmail.com'
49
+ end
50
+
51
+ if JRUBY
52
+ Rake::Task['build'].clear_actions if Rake::Task.task_defined?('build')
53
+ Rake::Task['install'].clear_actions if Rake::Task.task_defined?('install')
54
+ task :build => [ :java, :gem ]
55
+ task :install do
56
+ sh "#{Config::CONFIG['RUBY_INSTALL_NAME']} -S gem install pkg/do_oracle-#{DataObjects::Oracle::VERSION}-java.gem"
57
+ end
58
+ end
59
+
60
+ Jeweler::GemcutterTasks.new
61
+
62
+ FileList['tasks/**/*.rake'].each { |task| import task }
63
+ rescue LoadError
64
+ puts 'Jeweler (or a dependency) not available. Install it with: gem install jeweler'
65
+ end
@@ -0,0 +1,903 @@
1
+ #ifdef _WIN32
2
+ #define do_int64 signed __int64
3
+ #else
4
+ #define do_int64 signed long long int
5
+ #endif
6
+
7
+ #include <ruby.h>
8
+ #include <string.h>
9
+ #include <math.h>
10
+ #include <ctype.h>
11
+ #include <time.h>
12
+
13
+ #define ID_CONST_GET rb_intern("const_get")
14
+
15
+ #define RUBY_STRING(char_ptr) rb_str_new2(char_ptr)
16
+ #define TAINTED_STRING(name, length) rb_tainted_str_new(name, length)
17
+ #define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
18
+ #define ORACLE_CLASS(klass, parent) (rb_define_class_under(mOracle, klass, parent))
19
+ #define DEBUG(value) data_objects_debug(value)
20
+ #define RUBY_CLASS(name) rb_const_get(rb_cObject, rb_intern(name))
21
+
22
+ #ifndef RSTRING_PTR
23
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
24
+ #endif
25
+
26
+ #ifndef RSTRING_LEN
27
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
28
+ #endif
29
+
30
+ #ifndef RARRAY_LEN
31
+ #define RARRAY_LEN(a) RARRAY(a)->len
32
+ #endif
33
+
34
+
35
+ // To store rb_intern values
36
+ static ID ID_NEW;
37
+ static ID ID_NEW_DATE;
38
+ static ID ID_LOGGER;
39
+ static ID ID_DEBUG;
40
+ static ID ID_LEVEL;
41
+ static ID ID_TO_S;
42
+ static ID ID_RATIONAL;
43
+
44
+ static ID ID_NAME;
45
+
46
+ static ID ID_NUMBER;
47
+ static ID ID_VARCHAR2;
48
+ static ID ID_CHAR;
49
+ static ID ID_DATE;
50
+ static ID ID_TIMESTAMP;
51
+ static ID ID_TIMESTAMP_TZ;
52
+ static ID ID_TIMESTAMP_LTZ;
53
+ static ID ID_CLOB;
54
+ static ID ID_BLOB;
55
+ static ID ID_LONG;
56
+ static ID ID_RAW;
57
+ static ID ID_LONG_RAW;
58
+ static ID ID_BFILE;
59
+ static ID ID_BINARY_FLOAT;
60
+ static ID ID_BINARY_DOUBLE;
61
+
62
+ static ID ID_TO_A;
63
+ static ID ID_TO_I;
64
+ static ID ID_TO_S;
65
+ static ID ID_TO_F;
66
+
67
+ static ID ID_UTC_OFFSET;
68
+ static ID ID_FULL_CONST_GET;
69
+
70
+ static ID ID_PARSE;
71
+ static ID ID_FETCH;
72
+ static ID ID_TYPE;
73
+ static ID ID_EXECUTE;
74
+ static ID ID_EXEC;
75
+
76
+ static ID ID_SELECT_STMT;
77
+ static ID ID_COLUMN_METADATA;
78
+ static ID ID_PRECISION;
79
+ static ID ID_SCALE;
80
+ static ID ID_BIND_PARAM;
81
+ static ID ID_ELEM;
82
+ static ID ID_READ;
83
+
84
+ static ID ID_CLOSE;
85
+ static ID ID_LOGOFF;
86
+
87
+ static VALUE mExtlib;
88
+ static VALUE mDO;
89
+ static VALUE cDO_Quoting;
90
+ static VALUE cDO_Connection;
91
+ static VALUE cDO_Command;
92
+ static VALUE cDO_Result;
93
+ static VALUE cDO_Reader;
94
+
95
+ static VALUE rb_cDate;
96
+ static VALUE rb_cDateTime;
97
+ static VALUE rb_cBigDecimal;
98
+ static VALUE rb_cByteArray;
99
+
100
+ static VALUE cOCI8;
101
+ static VALUE cOCI8_Cursor;
102
+ static VALUE cOCI8_BLOB;
103
+ static VALUE cOCI8_CLOB;
104
+
105
+ static VALUE mOracle;
106
+ static VALUE cConnection;
107
+ static VALUE cCommand;
108
+ static VALUE cResult;
109
+ static VALUE cReader;
110
+
111
+ static VALUE eArgumentError;
112
+ static VALUE eSQLError;
113
+ static VALUE eConnectionError;
114
+ static VALUE eDataError;
115
+
116
+ static void data_objects_debug(VALUE string, struct timeval* start) {
117
+ struct timeval stop;
118
+ char *message;
119
+
120
+ char *query = RSTRING_PTR(string);
121
+ int length = RSTRING_LEN(string);
122
+ char total_time[32];
123
+ do_int64 duration = 0;
124
+
125
+ VALUE logger = rb_funcall(mOracle, ID_LOGGER, 0);
126
+ int log_level = NUM2INT(rb_funcall(logger, ID_LEVEL, 0));
127
+
128
+ if (0 == log_level) {
129
+ gettimeofday(&stop, NULL);
130
+
131
+ duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec;
132
+
133
+ snprintf(total_time, 32, "%.6f", duration / 1000000.0);
134
+ message = (char *)calloc(length + strlen(total_time) + 4, sizeof(char));
135
+ snprintf(message, length + strlen(total_time) + 4, "(%s) %s", total_time, query);
136
+ rb_funcall(logger, ID_DEBUG, 1, rb_str_new(message, length + strlen(total_time) + 3));
137
+ free(message);
138
+ }
139
+ }
140
+
141
+ static char * get_uri_option(VALUE query_hash, char * key) {
142
+ VALUE query_value;
143
+ char * value = NULL;
144
+
145
+ if(!rb_obj_is_kind_of(query_hash, rb_cHash)) { return NULL; }
146
+
147
+ query_value = rb_hash_aref(query_hash, RUBY_STRING(key));
148
+
149
+ if (Qnil != query_value) {
150
+ value = StringValuePtr(query_value);
151
+ }
152
+
153
+ return value;
154
+ }
155
+
156
+ /* ====== Time/Date Parsing Helper Functions ====== */
157
+ static void reduce( do_int64 *numerator, do_int64 *denominator ) {
158
+ do_int64 a, b, c;
159
+ a = *numerator;
160
+ b = *denominator;
161
+ while ( a != 0 ) {
162
+ c = a; a = b % a; b = c;
163
+ }
164
+ *numerator = *numerator / b;
165
+ *denominator = *denominator / b;
166
+ }
167
+
168
+ // Generate the date integer which Date.civil_to_jd returns
169
+ static int jd_from_date(int year, int month, int day) {
170
+ int a, b;
171
+ if ( month <= 2 ) {
172
+ year -= 1;
173
+ month += 12;
174
+ }
175
+ a = year / 100;
176
+ b = 2 - a + (a / 4);
177
+ return floor(365.25 * (year + 4716)) + floor(30.6001 * (month + 1)) + day + b - 1524;
178
+ }
179
+
180
+ // Creates a Rational for use as a Timezone offset to be passed to DateTime.new!
181
+ static VALUE seconds_to_offset(do_int64 num) {
182
+ do_int64 den = 86400;
183
+ reduce(&num, &den);
184
+ return rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ll2inum(num), rb_ll2inum(den));
185
+ }
186
+
187
+ static VALUE timezone_to_offset(int hour_offset, int minute_offset) {
188
+ do_int64 seconds = 0;
189
+
190
+ seconds += hour_offset * 3600;
191
+ seconds += minute_offset * 60;
192
+
193
+ return seconds_to_offset(seconds);
194
+ }
195
+
196
+ // Implementation using C functions
197
+
198
+ static VALUE parse_date(VALUE r_value) {
199
+ VALUE time_array;
200
+ int year, month, day;
201
+ int jd, ajd;
202
+ VALUE rational;
203
+
204
+ if (rb_obj_class(r_value) == rb_cTime) {
205
+ time_array = rb_funcall(r_value, ID_TO_A, 0);
206
+ year = NUM2INT(rb_ary_entry(time_array, 5));
207
+ month = NUM2INT(rb_ary_entry(time_array, 4));
208
+ day = NUM2INT(rb_ary_entry(time_array, 3));
209
+
210
+ jd = jd_from_date(year, month, day);
211
+
212
+ // Math from Date.jd_to_ajd
213
+ ajd = jd * 2 - 1;
214
+ rational = rb_funcall(rb_mKernel, ID_RATIONAL, 2, INT2NUM(ajd), INT2NUM(2));
215
+
216
+ return rb_funcall(rb_cDate, ID_NEW_DATE, 3, rational, INT2NUM(0), INT2NUM(2299161));
217
+
218
+ } else if (rb_obj_class(r_value) == rb_cDate) {
219
+ return r_value;
220
+
221
+ } else if (rb_obj_class(r_value) == rb_cDateTime) {
222
+ rational = rb_iv_get(r_value, "@ajd");
223
+ return rb_funcall(rb_cDate, ID_NEW_DATE, 3, rational, INT2NUM(0), INT2NUM(2299161));
224
+
225
+ } else {
226
+ // Something went terribly wrong
227
+ rb_raise(eDataError, "Couldn't parse date from class %s object", rb_obj_classname(r_value));
228
+ }
229
+ }
230
+
231
+ // Implementation using C functions
232
+
233
+ static VALUE parse_date_time(VALUE r_value) {
234
+ VALUE ajd, offset;
235
+
236
+ VALUE time_array;
237
+ int year, month, day, hour, min, sec, hour_offset, minute_offset;
238
+ // int usec;
239
+ int jd;
240
+ do_int64 num, den;
241
+
242
+ long int gmt_offset;
243
+ int is_dst;
244
+
245
+ // time_t rawtime;
246
+ // struct tm * timeinfo;
247
+
248
+ // int tokens_read, max_tokens;
249
+
250
+ if (rb_obj_class(r_value) == rb_cDateTime) {
251
+ return r_value;
252
+ } else if (rb_obj_class(r_value) == rb_cTime) {
253
+ time_array = rb_funcall(r_value, ID_TO_A, 0);
254
+ year = NUM2INT(rb_ary_entry(time_array, 5));
255
+ month = NUM2INT(rb_ary_entry(time_array, 4));
256
+ day = NUM2INT(rb_ary_entry(time_array, 3));
257
+ hour = NUM2INT(rb_ary_entry(time_array, 2));
258
+ min = NUM2INT(rb_ary_entry(time_array, 1));
259
+ sec = NUM2INT(rb_ary_entry(time_array, 0));
260
+
261
+ is_dst = rb_ary_entry(time_array, 8) == Qtrue ? 3600 : 0;
262
+ gmt_offset = NUM2INT(rb_funcall(r_value, ID_UTC_OFFSET, 0 ));
263
+
264
+ if ( is_dst > 0 )
265
+ gmt_offset -= is_dst;
266
+
267
+ hour_offset = -(gmt_offset / 3600);
268
+ minute_offset = -(gmt_offset % 3600 / 60);
269
+
270
+ jd = jd_from_date(year, month, day);
271
+
272
+ // Generate ajd with fractional days for the time
273
+ // Extracted from Date#jd_to_ajd, Date#day_fraction_to_time, and Rational#+ and #-
274
+ num = (hour * 1440) + (min * 24);
275
+
276
+ // Modify the numerator so when we apply the timezone everything works out
277
+ num -= (hour_offset * 1440) + (minute_offset * 24);
278
+
279
+ den = (24 * 1440);
280
+ reduce(&num, &den);
281
+
282
+ num = (num * 86400) + (sec * den);
283
+ den = den * 86400;
284
+ reduce(&num, &den);
285
+
286
+ num = (jd * den) + num;
287
+
288
+ num = num * 2;
289
+ num = num - den;
290
+ den = den * 2;
291
+
292
+ reduce(&num, &den);
293
+
294
+ ajd = rb_funcall(rb_mKernel, ID_RATIONAL, 2, rb_ull2inum(num), rb_ull2inum(den));
295
+ offset = timezone_to_offset(hour_offset, minute_offset);
296
+
297
+ return rb_funcall(rb_cDateTime, ID_NEW_DATE, 3, ajd, offset, INT2NUM(2299161));
298
+ } else {
299
+ // Something went terribly wrong
300
+ rb_raise(eDataError, "Couldn't parse datetime from class %s object", rb_obj_classname(r_value));
301
+ }
302
+
303
+ }
304
+
305
+ static VALUE parse_time(VALUE r_value) {
306
+ if (rb_obj_class(r_value) == rb_cTime) {
307
+ return r_value;
308
+ } else {
309
+ // Something went terribly wrong
310
+ rb_raise(eDataError, "Couldn't parse time from class %s object", rb_obj_classname(r_value));
311
+ }
312
+ }
313
+
314
+ static VALUE parse_boolean(VALUE r_value) {
315
+ if (TYPE(r_value) == T_FIXNUM || TYPE(r_value) == T_BIGNUM) {
316
+ return NUM2INT(r_value) >= 1 ? Qtrue : Qfalse;
317
+ } else if (TYPE(r_value) == T_STRING) {
318
+ char value = NIL_P(r_value) || RSTRING_LEN(r_value) == 0 ? '\0' : *(RSTRING_PTR(r_value));
319
+ return value == 'Y' || value == 'y' || value == 'T' || value == 't' ? Qtrue : Qfalse;
320
+ } else {
321
+ // Something went terribly wrong
322
+ rb_raise(eDataError, "Couldn't parse boolean from class %s object", rb_obj_classname(r_value));
323
+ }
324
+ }
325
+
326
+ /* ===== Typecasting Functions ===== */
327
+
328
+ static VALUE infer_ruby_type(VALUE type, VALUE precision, VALUE scale) {
329
+ ID type_id = SYM2ID(type);
330
+
331
+ if (type_id == ID_NUMBER)
332
+ return scale != Qnil && NUM2INT(scale) == 0 ?
333
+ (NUM2INT(precision) == 1 ? rb_cTrueClass : rb_cInteger) : rb_cBigDecimal;
334
+ else if (type_id == ID_VARCHAR2 || type_id == ID_CHAR || type_id == ID_CLOB || type_id == ID_LONG)
335
+ return rb_cString;
336
+ else if (type_id == ID_DATE)
337
+ // return rb_cDateTime;
338
+ // by default map DATE type to Time class as it is much faster than DateTime class
339
+ return rb_cTime;
340
+ else if (type_id == ID_TIMESTAMP || type_id == ID_TIMESTAMP_TZ || type_id == ID_TIMESTAMP_LTZ)
341
+ // return rb_cDateTime;
342
+ // by default map TIMESTAMP type to Time class as it is much faster than DateTime class
343
+ return rb_cTime;
344
+ else if (type_id == ID_BLOB || type_id == ID_RAW || type_id == ID_LONG_RAW || type_id == ID_BFILE)
345
+ return rb_cByteArray;
346
+ else if (type_id == ID_BINARY_FLOAT || type_id == ID_BINARY_DOUBLE)
347
+ return rb_cFloat;
348
+ else
349
+ return rb_cString;
350
+ }
351
+
352
+ static VALUE typecast(VALUE r_value, const VALUE type) {
353
+ VALUE r_data;
354
+
355
+ if (type == rb_cInteger) {
356
+ return TYPE(r_value) == T_FIXNUM || TYPE(r_value) == T_BIGNUM ? r_value : rb_funcall(r_value, ID_TO_I, 0);
357
+
358
+ } else if (type == rb_cString) {
359
+ if (TYPE(r_value) == T_STRING)
360
+ return r_value;
361
+ else if (rb_obj_class(r_value) == cOCI8_CLOB)
362
+ return rb_funcall(r_value, ID_READ, 0);
363
+ else
364
+ return rb_funcall(r_value, ID_TO_S, 0);
365
+
366
+ } else if (type == rb_cFloat) {
367
+ return TYPE(r_value) == T_FLOAT ? r_value : rb_funcall(r_value, ID_TO_F, 0);
368
+
369
+ } else if (type == rb_cBigDecimal) {
370
+ VALUE r_string = TYPE(r_value) == T_STRING ? r_value : rb_funcall(r_value, ID_TO_S, 0);
371
+ return rb_funcall(rb_cBigDecimal, ID_NEW, 1, r_string);
372
+
373
+ } else if (type == rb_cDate) {
374
+ return parse_date(r_value);
375
+
376
+ } else if (type == rb_cDateTime) {
377
+ return parse_date_time(r_value);
378
+
379
+ } else if (type == rb_cTime) {
380
+ return parse_time(r_value);
381
+
382
+ } else if (type == rb_cTrueClass) {
383
+ return parse_boolean(r_value);
384
+
385
+ } else if (type == rb_cByteArray) {
386
+ if (rb_obj_class(r_value) == cOCI8_BLOB)
387
+ r_data = rb_funcall(r_value, ID_READ, 0);
388
+ else
389
+ r_data = r_value;
390
+ return rb_funcall(rb_cByteArray, ID_NEW, 1, r_data);
391
+
392
+ } else if (type == rb_cClass) {
393
+ return rb_funcall(mDO, ID_FULL_CONST_GET, 1, r_value);
394
+
395
+ // TODO: where are tests for this mapping?
396
+ } else if (type == rb_cObject) {
397
+ if (rb_obj_class(r_value) == cOCI8_CLOB)
398
+ return rb_marshal_load(rb_funcall(r_value, ID_READ, 0));
399
+ else
400
+ return rb_marshal_load(r_value);
401
+
402
+ } else if (type == rb_cNilClass) {
403
+ return Qnil;
404
+
405
+ } else {
406
+ if (rb_obj_class(r_value) == cOCI8_CLOB)
407
+ return rb_funcall(r_value, ID_READ, 0);
408
+ else
409
+ return r_value;
410
+ }
411
+
412
+ }
413
+
414
+ static VALUE typecast_bind_value(VALUE oci8_conn, VALUE r_value) {
415
+ VALUE r_class = rb_obj_class(r_value);
416
+ // replace nil value with '' as otherwise OCI8 cannot get bind variable type
417
+ // '' will be inserted as NULL by Oracle
418
+ if (NIL_P(r_value))
419
+ return RUBY_STRING("");
420
+ else if (r_class == rb_cString)
421
+ // if string is longer than 4000 characters then convert to CLOB
422
+ return RSTRING_LEN(r_value) <= 4000 ? r_value : rb_funcall(cOCI8_CLOB, ID_NEW, 2, oci8_conn, r_value);
423
+ else if (r_class == rb_cBigDecimal)
424
+ return rb_funcall(r_value, ID_TO_S, 1, RUBY_STRING("F"));
425
+ else if (r_class == rb_cTrueClass)
426
+ return INT2NUM(1);
427
+ else if (r_class == rb_cFalseClass)
428
+ return INT2NUM(0);
429
+ else if (r_class == rb_cByteArray)
430
+ return rb_funcall(cOCI8_BLOB, ID_NEW, 2, oci8_conn, r_value);
431
+ else if (r_class == rb_cClass)
432
+ return rb_funcall(r_value, ID_TO_S, 0);
433
+ else
434
+ return r_value;
435
+ }
436
+
437
+ /* ====== Public API ======= */
438
+ static VALUE cConnection_dispose(VALUE self) {
439
+ VALUE oci8_conn = rb_iv_get(self, "@connection");
440
+
441
+ if (Qnil == oci8_conn)
442
+ return Qfalse;
443
+
444
+ rb_funcall(oci8_conn, ID_LOGOFF, 0);
445
+
446
+ rb_iv_set(self, "@connection", Qnil);
447
+
448
+ return Qtrue;
449
+ }
450
+
451
+ static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
452
+ VALUE type_strings = rb_ary_new();
453
+ VALUE array = rb_ary_new();
454
+
455
+ int i, j;
456
+
457
+ for ( i = 0; i < argc; i++) {
458
+ rb_ary_push(array, argv[i]);
459
+ }
460
+
461
+ for (i = 0; i < RARRAY_LEN(array); i++) {
462
+ VALUE entry = rb_ary_entry(array, i);
463
+ if(TYPE(entry) == T_CLASS) {
464
+ rb_ary_push(type_strings, entry);
465
+ } else if (TYPE(entry) == T_ARRAY) {
466
+ for (j = 0; j < RARRAY_LEN(entry); j++) {
467
+ VALUE sub_entry = rb_ary_entry(entry, j);
468
+ if(TYPE(sub_entry) == T_CLASS) {
469
+ rb_ary_push(type_strings, sub_entry);
470
+ } else {
471
+ rb_raise(eArgumentError, "Invalid type given");
472
+ }
473
+ }
474
+ } else {
475
+ rb_raise(eArgumentError, "Invalid type given");
476
+ }
477
+ }
478
+
479
+ rb_iv_set(self, "@field_types", type_strings);
480
+
481
+ return array;
482
+ }
483
+
484
+ typedef struct {
485
+ VALUE self;
486
+ VALUE oci8_conn;
487
+ VALUE cursor;
488
+ VALUE statement_type;
489
+ VALUE args;
490
+ VALUE sql;
491
+ struct timeval start;
492
+ } cCommand_execute_try_t;
493
+
494
+ static VALUE cCommand_execute_try(cCommand_execute_try_t *arg);
495
+ static VALUE cCommand_execute_ensure(cCommand_execute_try_t *arg);
496
+
497
+ // called by Command#execute that is written in Ruby
498
+ static VALUE cCommand_execute_internal(VALUE self, VALUE oci8_conn, VALUE sql, VALUE args) {
499
+ cCommand_execute_try_t arg;
500
+ arg.self = self;
501
+ arg.oci8_conn = oci8_conn;
502
+ arg.sql = sql;
503
+ // store start time before SQL parsing
504
+ gettimeofday(&arg.start, NULL);
505
+ arg.cursor = rb_funcall(oci8_conn, ID_PARSE, 1, sql);
506
+ arg.statement_type = rb_funcall(arg.cursor, ID_TYPE, 0);
507
+ arg.args = args;
508
+
509
+ return rb_ensure(cCommand_execute_try, (VALUE)&arg, cCommand_execute_ensure, (VALUE)&arg);
510
+ }
511
+
512
+ // wrapper for simple SQL calls without arguments
513
+ static VALUE execute_sql(VALUE oci8_conn, VALUE sql) {
514
+ return cCommand_execute_internal(Qnil, oci8_conn, sql, Qnil);
515
+ }
516
+
517
+ static VALUE cCommand_execute_try(cCommand_execute_try_t *arg) {
518
+ VALUE result = Qnil;
519
+ int insert_id_present;
520
+
521
+ // no arguments given
522
+ if NIL_P(arg->args) {
523
+ result = rb_funcall(arg->cursor, ID_EXEC, 0);
524
+ // arguments given - need to typecast
525
+ } else {
526
+ insert_id_present = (!NIL_P(arg->self) && rb_iv_get(arg->self, "@insert_id_present") == Qtrue);
527
+
528
+ if (insert_id_present)
529
+ rb_funcall(arg->cursor, ID_BIND_PARAM, 2, RUBY_STRING(":insert_id"), INT2NUM(0));
530
+
531
+ int i;
532
+ VALUE r_orig_value, r_new_value;
533
+ for (i = 0; i < RARRAY_LEN(arg->args); i++) {
534
+ r_orig_value = rb_ary_entry(arg->args, i);
535
+ r_new_value = typecast_bind_value(arg->oci8_conn, r_orig_value);
536
+ if (r_orig_value != r_new_value)
537
+ rb_ary_store(arg->args, i, r_new_value);
538
+ }
539
+
540
+ result = rb_apply(arg->cursor, ID_EXEC, arg->args);
541
+
542
+ if (insert_id_present) {
543
+ VALUE insert_id = rb_funcall(arg->cursor, ID_ELEM, 1, RUBY_STRING(":insert_id"));
544
+ rb_iv_set(arg->self, "@insert_id", insert_id);
545
+ }
546
+ }
547
+
548
+ if (SYM2ID(arg->statement_type) == ID_SELECT_STMT)
549
+ return arg->cursor;
550
+ else {
551
+ return result;
552
+ }
553
+
554
+ }
555
+
556
+ static VALUE cCommand_execute_ensure(cCommand_execute_try_t *arg) {
557
+ if (SYM2ID(arg->statement_type) != ID_SELECT_STMT)
558
+ rb_funcall(arg->cursor, ID_CLOSE, 0);
559
+ // Log SQL and execution time
560
+ data_objects_debug(arg->sql, &(arg->start));
561
+ return Qnil;
562
+ }
563
+
564
+ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
565
+ VALUE r_host, r_port, r_path, r_user, r_password;
566
+ VALUE r_query, r_time_zone;
567
+ char *non_blocking = NULL;
568
+ char *time_zone = NULL;
569
+ char set_time_zone_command[80];
570
+
571
+ char *host = "localhost", *port = "1521", *path = NULL;
572
+ char *connect_string;
573
+ int connect_string_length;
574
+ VALUE oci8_conn;
575
+
576
+ r_user = rb_funcall(uri, rb_intern("user"), 0);
577
+ r_password = rb_funcall(uri, rb_intern("password"), 0);
578
+
579
+ r_host = rb_funcall(uri, rb_intern("host"), 0);
580
+ if ( Qnil != r_host && RSTRING_LEN(r_host) > 0) {
581
+ host = StringValuePtr(r_host);
582
+ }
583
+
584
+ r_port = rb_funcall(uri, rb_intern("port"), 0);
585
+ if ( Qnil != r_port ) {
586
+ r_port = rb_funcall(r_port, ID_TO_S, 0);
587
+ port = StringValuePtr(r_port);
588
+ }
589
+
590
+ r_path = rb_funcall(uri, rb_intern("path"), 0);
591
+ path = StringValuePtr(r_path);
592
+
593
+ // If just host name is specified then use it as TNS names alias
594
+ if ((r_host != Qnil && RSTRING_LEN(r_host) > 0) &&
595
+ (r_port == Qnil) &&
596
+ (r_path == Qnil || RSTRING_LEN(r_path) == 0)) {
597
+ connect_string = host;
598
+ // If database name is specified in path (in format "/database")
599
+ } else if (strlen(path) > 1) {
600
+ connect_string_length = strlen(host) + strlen(port) + strlen(path) + 4;
601
+ connect_string = (char *)calloc(connect_string_length, sizeof(char));
602
+ snprintf(connect_string, connect_string_length, "//%s:%s%s", host, port, path);
603
+ } else {
604
+ rb_raise(eConnectionError, "Database must be specified");
605
+ }
606
+
607
+ // oci8_conn = rb_funcall(cOCI8, ID_NEW, 3, r_user, r_password, RUBY_STRING(connect_string));
608
+ oci8_conn = rb_funcall(cConnection, rb_intern("oci8_new"), 3, r_user, r_password, RUBY_STRING(connect_string));
609
+
610
+ // Pull the querystring off the URI
611
+ r_query = rb_funcall(uri, rb_intern("query"), 0);
612
+
613
+ non_blocking = get_uri_option(r_query, "non_blocking");
614
+ // Enable non-blocking mode
615
+ if (non_blocking != NULL && strcmp(non_blocking, "true") == 0)
616
+ rb_funcall(oci8_conn, rb_intern("non_blocking="), 1, Qtrue);
617
+ // By default enable auto-commit mode
618
+ rb_funcall(oci8_conn, rb_intern("autocommit="), 1, Qtrue);
619
+ // Set prefetch rows to 100 to increase fetching performance SELECTs with many rows
620
+ rb_funcall(oci8_conn, rb_intern("prefetch_rows="), 1, INT2NUM(100));
621
+
622
+ // Set session time zone
623
+ // at first look for option in connection string
624
+ time_zone = get_uri_option(r_query, "time_zone");
625
+ // if no option specified then look in ENV['TZ']
626
+ if (time_zone == NULL) {
627
+ r_time_zone = rb_funcall(cConnection, rb_intern("ruby_time_zone"), 0);
628
+ if (!NIL_P(r_time_zone))
629
+ time_zone = StringValuePtr(r_time_zone);
630
+ }
631
+ if (time_zone) {
632
+ snprintf(set_time_zone_command, 80, "alter session set time_zone = '%s'", time_zone);
633
+ execute_sql(oci8_conn, RUBY_STRING(set_time_zone_command));
634
+ }
635
+
636
+ execute_sql(oci8_conn, RUBY_STRING("alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'"));
637
+ execute_sql(oci8_conn, RUBY_STRING("alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF'"));
638
+ execute_sql(oci8_conn, RUBY_STRING("alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM'"));
639
+
640
+ rb_iv_set(self, "@uri", uri);
641
+ rb_iv_set(self, "@connection", oci8_conn);
642
+
643
+ return Qtrue;
644
+ }
645
+
646
+ static VALUE cCommand_execute_non_query(int argc, VALUE *argv[], VALUE self) {
647
+ VALUE affected_rows = rb_funcall2(self, ID_EXECUTE, argc, (VALUE *)argv);
648
+ if (affected_rows == Qtrue)
649
+ affected_rows = INT2NUM(0);
650
+
651
+ VALUE insert_id = rb_iv_get(self, "@insert_id");
652
+
653
+ return rb_funcall(cResult, ID_NEW, 3, self, affected_rows, insert_id);
654
+ }
655
+
656
+ static VALUE cCommand_execute_reader(int argc, VALUE *argv[], VALUE self) {
657
+ VALUE reader, query;
658
+ VALUE field_names, field_types;
659
+ VALUE column_metadata, column, column_name;
660
+
661
+ int i;
662
+ int field_count;
663
+ int infer_types = 0;
664
+
665
+ VALUE cursor = rb_funcall2(self, ID_EXECUTE, argc, (VALUE *)argv);
666
+
667
+ if (rb_obj_class(cursor) != cOCI8_Cursor) {
668
+ rb_raise(eArgumentError, "\"%s\" is invalid SELECT query", StringValuePtr(query));
669
+ }
670
+
671
+ column_metadata = rb_funcall(cursor, ID_COLUMN_METADATA, 0);
672
+ field_count = RARRAY_LEN(column_metadata);
673
+ // reduce field_count by 1 if RAW_RNUM_ is present as last column
674
+ // (generated by DataMapper to simulate LIMIT and OFFSET)
675
+ column = rb_ary_entry(column_metadata, field_count-1);
676
+ column_name = rb_funcall(column, ID_NAME, 0);
677
+ if (strncmp(RSTRING_PTR(column_name), "RAW_RNUM_", RSTRING_LEN(column_name)) == 0)
678
+ field_count--;
679
+
680
+ reader = rb_funcall(cReader, ID_NEW, 0);
681
+ rb_iv_set(reader, "@reader", cursor);
682
+ rb_iv_set(reader, "@field_count", INT2NUM(field_count));
683
+
684
+ field_names = rb_ary_new();
685
+ field_types = rb_iv_get(self, "@field_types");
686
+
687
+ if ( field_types == Qnil || 0 == RARRAY_LEN(field_types) ) {
688
+ field_types = rb_ary_new();
689
+ infer_types = 1;
690
+ } else if (RARRAY_LEN(field_types) != field_count) {
691
+ // Whoops... wrong number of types passed to set_types. Close the reader and raise
692
+ // and error
693
+ rb_funcall(reader, ID_CLOSE, 0);
694
+ rb_raise(eArgumentError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
695
+ }
696
+
697
+ for ( i = 0; i < field_count; i++ ) {
698
+ column = rb_ary_entry(column_metadata, i);
699
+ column_name = rb_funcall(column, ID_NAME, 0);
700
+ rb_ary_push(field_names, column_name);
701
+ if ( infer_types == 1 ) {
702
+ rb_ary_push(field_types,
703
+ infer_ruby_type(rb_iv_get(column, "@data_type"),
704
+ rb_funcall(column, ID_PRECISION, 0),
705
+ rb_funcall(column, ID_SCALE, 0))
706
+ );
707
+ }
708
+ }
709
+
710
+ rb_iv_set(reader, "@position", INT2NUM(0));
711
+ rb_iv_set(reader, "@fields", field_names);
712
+ rb_iv_set(reader, "@field_types", field_types);
713
+
714
+ rb_iv_set(reader, "@last_row", Qfalse);
715
+
716
+ return reader;
717
+ }
718
+
719
+ static VALUE cReader_close(VALUE self) {
720
+ VALUE cursor = rb_iv_get(self, "@reader");
721
+
722
+ if (Qnil == cursor)
723
+ return Qfalse;
724
+
725
+ rb_funcall(cursor, ID_CLOSE, 0);
726
+
727
+ rb_iv_set(self, "@reader", Qnil);
728
+ return Qtrue;
729
+ }
730
+
731
+ static VALUE cReader_next(VALUE self) {
732
+ VALUE cursor = rb_iv_get(self, "@reader");
733
+
734
+ int field_count;
735
+ int i;
736
+
737
+ if (Qnil == cursor || Qtrue == rb_iv_get(self, "@last_row"))
738
+ return Qfalse;
739
+
740
+ VALUE row = rb_ary_new();
741
+ VALUE field_types, field_type;
742
+ VALUE value;
743
+
744
+ VALUE fetch_result = rb_funcall(cursor, ID_FETCH, 0);
745
+
746
+ if (Qnil == fetch_result) {
747
+ rb_iv_set(self, "@values", Qnil);
748
+ rb_iv_set(self, "@last_row", Qtrue);
749
+ return Qfalse;
750
+ }
751
+
752
+ field_count = NUM2INT(rb_iv_get(self, "@field_count"));
753
+ field_types = rb_iv_get(self, "@field_types");
754
+
755
+ for ( i = 0; i < field_count; i++ ) {
756
+ field_type = rb_ary_entry(field_types, i);
757
+ value = rb_ary_entry(fetch_result, i);
758
+ // Always return nil if the value returned from Oracle is null
759
+ if (Qnil != value) {
760
+ value = typecast(value, field_type);
761
+ }
762
+
763
+ rb_ary_push(row, value);
764
+ }
765
+
766
+ rb_iv_set(self, "@values", row);
767
+ return Qtrue;
768
+ }
769
+
770
+ static VALUE cReader_values(VALUE self) {
771
+
772
+ VALUE values = rb_iv_get(self, "@values");
773
+ if(values == Qnil) {
774
+ rb_raise(eDataError, "Reader not initialized");
775
+ return Qnil;
776
+ } else {
777
+ return values;
778
+ }
779
+ }
780
+
781
+ static VALUE cReader_fields(VALUE self) {
782
+ return rb_iv_get(self, "@fields");
783
+ }
784
+
785
+ static VALUE cReader_field_count(VALUE self) {
786
+ return rb_iv_get(self, "@field_count");
787
+ }
788
+
789
+
790
+ void Init_do_oracle() {
791
+ // rb_require("oci8");
792
+ rb_require("date");
793
+ rb_require("bigdecimal");
794
+
795
+ // Get references classes needed for Date/Time parsing
796
+ rb_cDate = CONST_GET(rb_mKernel, "Date");
797
+ rb_cDateTime = CONST_GET(rb_mKernel, "DateTime");
798
+ rb_cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
799
+
800
+ rb_funcall(rb_mKernel, rb_intern("require"), 1, rb_str_new2("data_objects"));
801
+
802
+ ID_NEW = rb_intern("new");
803
+ #ifdef RUBY_LESS_THAN_186
804
+ ID_NEW_DATE = rb_intern("new0");
805
+ #else
806
+ ID_NEW_DATE = rb_intern("new!");
807
+ #endif
808
+ ID_LOGGER = rb_intern("logger");
809
+ ID_DEBUG = rb_intern("debug");
810
+ ID_LEVEL = rb_intern("level");
811
+ ID_TO_S = rb_intern("to_s");
812
+ ID_RATIONAL = rb_intern("Rational");
813
+
814
+ ID_NAME = rb_intern("name");
815
+
816
+ ID_NUMBER = rb_intern("number");
817
+ ID_VARCHAR2 = rb_intern("varchar2");
818
+ ID_CHAR = rb_intern("char");
819
+ ID_DATE = rb_intern("date");
820
+ ID_TIMESTAMP = rb_intern("timestamp");
821
+ ID_TIMESTAMP_TZ = rb_intern("timestamp_tz");
822
+ ID_TIMESTAMP_LTZ = rb_intern("timestamp_ltz");
823
+ ID_CLOB = rb_intern("clob");
824
+ ID_BLOB = rb_intern("blob");
825
+ ID_LONG = rb_intern("long");
826
+ ID_RAW = rb_intern("raw");
827
+ ID_LONG_RAW = rb_intern("long_raw");
828
+ ID_BFILE = rb_intern("bfile");
829
+ ID_BINARY_FLOAT = rb_intern("binary_float");
830
+ ID_BINARY_DOUBLE = rb_intern("binary_double");
831
+
832
+ ID_TO_A = rb_intern("to_a");
833
+ ID_TO_I = rb_intern("to_i");
834
+ ID_TO_S = rb_intern("to_s");
835
+ ID_TO_F = rb_intern("to_f");
836
+
837
+ ID_UTC_OFFSET = rb_intern("utc_offset");
838
+ ID_FULL_CONST_GET = rb_intern("full_const_get");
839
+
840
+ ID_PARSE = rb_intern("parse");
841
+ ID_FETCH = rb_intern("fetch");
842
+ ID_TYPE = rb_intern("type");
843
+ ID_EXECUTE = rb_intern("execute");
844
+ ID_EXEC = rb_intern("exec");
845
+
846
+ ID_SELECT_STMT = rb_intern("select_stmt");
847
+ ID_COLUMN_METADATA = rb_intern("column_metadata");
848
+ ID_PRECISION = rb_intern("precision");
849
+ ID_SCALE = rb_intern("scale");
850
+ ID_BIND_PARAM = rb_intern("bind_param");
851
+ ID_ELEM = rb_intern("[]");
852
+ ID_READ = rb_intern("read");
853
+
854
+ ID_CLOSE = rb_intern("close");
855
+ ID_LOGOFF = rb_intern("logoff");
856
+
857
+ // Get references to the Extlib module
858
+ mExtlib = CONST_GET(rb_mKernel, "Extlib");
859
+ rb_cByteArray = CONST_GET(mExtlib, "ByteArray");
860
+
861
+ // Get reference to OCI8 class
862
+ cOCI8 = CONST_GET(rb_mKernel, "OCI8");
863
+ cOCI8_Cursor = CONST_GET(cOCI8, "Cursor");
864
+ cOCI8_BLOB = CONST_GET(cOCI8, "BLOB");
865
+ cOCI8_CLOB = CONST_GET(cOCI8, "CLOB");
866
+
867
+ // Get references to the DataObjects module and its classes
868
+ mDO = CONST_GET(rb_mKernel, "DataObjects");
869
+ cDO_Quoting = CONST_GET(mDO, "Quoting");
870
+ cDO_Connection = CONST_GET(mDO, "Connection");
871
+ cDO_Command = CONST_GET(mDO, "Command");
872
+ cDO_Result = CONST_GET(mDO, "Result");
873
+ cDO_Reader = CONST_GET(mDO, "Reader");
874
+
875
+ // Top Level Module that all the classes live under
876
+ mOracle = rb_define_module_under(mDO, "Oracle");
877
+
878
+ eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
879
+ eSQLError = CONST_GET(mDO, "SQLError");
880
+ eConnectionError = CONST_GET(mDO, "ConnectionError");
881
+ eDataError = CONST_GET(mDO, "DataError");
882
+ // eOracleError = rb_define_class("OracleError", rb_eStandardError);
883
+
884
+ cConnection = ORACLE_CLASS("Connection", cDO_Connection);
885
+ rb_define_method(cConnection, "initialize", cConnection_initialize, 1);
886
+ rb_define_method(cConnection, "dispose", cConnection_dispose, 0);
887
+
888
+ cCommand = ORACLE_CLASS("Command", cDO_Command);
889
+ rb_define_method(cCommand, "set_types", cCommand_set_types, -1);
890
+ rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
891
+ rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
892
+ rb_define_method(cCommand, "execute_internal", cCommand_execute_internal, 3);
893
+
894
+ cResult = ORACLE_CLASS("Result", cDO_Result);
895
+
896
+ cReader = ORACLE_CLASS("Reader", cDO_Reader);
897
+ rb_define_method(cReader, "close", cReader_close, 0);
898
+ rb_define_method(cReader, "next!", cReader_next, 0);
899
+ rb_define_method(cReader, "values", cReader_values, 0);
900
+ rb_define_method(cReader, "fields", cReader_fields, 0);
901
+ rb_define_method(cReader, "field_count", cReader_field_count, 0);
902
+
903
+ }