ruby-oci8 2.1.5.1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +17 -0
  3. data/COPYING +30 -0
  4. data/COPYING_old +64 -0
  5. data/ChangeLog +2779 -0
  6. data/Makefile +92 -0
  7. data/NEWS +660 -0
  8. data/README.md +43 -0
  9. data/VERSION +1 -0
  10. data/dist-files +91 -0
  11. data/docs/install-binary-package.md +40 -0
  12. data/docs/install-full-client.md +116 -0
  13. data/docs/install-instant-client.md +167 -0
  14. data/docs/platform-specific-issues.md +197 -0
  15. data/docs/report-installation-issue.md +50 -0
  16. data/lib/.document +1 -0
  17. data/lib/dbd/OCI8.rb +591 -0
  18. data/lib/oci8.rb +147 -0
  19. data/lib/oci8.rb.in +147 -0
  20. data/lib/oci8/.document +8 -0
  21. data/lib/oci8/bindtype.rb +350 -0
  22. data/lib/oci8/compat.rb +113 -0
  23. data/lib/oci8/connection_pool.rb +108 -0
  24. data/lib/oci8/cursor.rb +564 -0
  25. data/lib/oci8/datetime.rb +605 -0
  26. data/lib/oci8/encoding-init.rb +79 -0
  27. data/lib/oci8/encoding.yml +537 -0
  28. data/lib/oci8/metadata.rb +2092 -0
  29. data/lib/oci8/object.rb +605 -0
  30. data/lib/oci8/oci8.rb +560 -0
  31. data/lib/oci8/ocihandle.rb +607 -0
  32. data/lib/oci8/oracle_version.rb +143 -0
  33. data/lib/oci8/properties.rb +134 -0
  34. data/lib/oci8lib_200.so +0 -0
  35. data/metaconfig +142 -0
  36. data/pre-distclean.rb +7 -0
  37. data/ruby-oci8.gemspec +80 -0
  38. data/setup.rb +1333 -0
  39. data/test/README +42 -0
  40. data/test/config.rb +184 -0
  41. data/test/setup_test_object.sql +171 -0
  42. data/test/test_all.rb +54 -0
  43. data/test/test_appinfo.rb +63 -0
  44. data/test/test_array_dml.rb +333 -0
  45. data/test/test_bind_raw.rb +46 -0
  46. data/test/test_bind_string.rb +106 -0
  47. data/test/test_bind_time.rb +178 -0
  48. data/test/test_break.rb +124 -0
  49. data/test/test_clob.rb +98 -0
  50. data/test/test_connection_pool.rb +125 -0
  51. data/test/test_connstr.rb +81 -0
  52. data/test/test_datetime.rb +581 -0
  53. data/test/test_dbi.rb +366 -0
  54. data/test/test_dbi_clob.rb +53 -0
  55. data/test/test_encoding.rb +104 -0
  56. data/test/test_error.rb +88 -0
  57. data/test/test_metadata.rb +1485 -0
  58. data/test/test_object.rb +462 -0
  59. data/test/test_oci8.rb +489 -0
  60. data/test/test_oracle_version.rb +70 -0
  61. data/test/test_oradate.rb +256 -0
  62. data/test/test_oranumber.rb +787 -0
  63. data/test/test_rowid.rb +33 -0
  64. metadata +109 -0
@@ -0,0 +1,197 @@
1
+ # @title Platform Specific Issues
2
+
3
+ Linux
4
+ =====
5
+
6
+ Ubuntu 11.10 (Oneiric Ocelot)
7
+ -----------------------------
8
+
9
+ If the following error occurs even though libc6-dev is installed,
10
+
11
+ Do you install glibc-devel(redhat) or libc6-dev(debian)?
12
+ You need /usr/include/sys/types.h to compile ruby-oci8.
13
+
14
+ You need to use ruby-oci8 2.1.0 or upper. Otherwise, run the following command and re-install ruby-oci8.
15
+
16
+ $ sudo ln -s /usr/include/linux/ /usr/include/sys
17
+
18
+ General Linux
19
+ -------------
20
+
21
+ Use the same bit-width of libraries with ruby. For example, x86\_64
22
+ instant client for x86\_64 ruby and 32-bit instant client for 32-bit
23
+ ruby. It depends on the ruby but not on the OS. As for full client,
24
+ x86\_64 ruby cannot use with 32-bit full client, but 32-bit ruby can
25
+ use with 64-bit full client because 32-bit libraries are in
26
+ $ORACLE\_HOME/lib32.
27
+
28
+ To check which type of ruby do you use:
29
+
30
+ file `which ruby`
31
+
32
+ Note: "`" is a back quote.
33
+
34
+ Mac OS X
35
+ ========
36
+
37
+ OS X 10.7+
38
+ ----------
39
+
40
+ Use the latest 64-bit instant client. The older 64-bit (10.2.0.4) instant client [doesn't work](https://forums.oracle.com/forums/thread.jspa?threadID=2187558). The older 32-bit instant client will work but only with 32-bit ruby or jruby (using JDBC).
41
+
42
+ Intel Mac (64-bit)
43
+ ------------------
44
+
45
+ See [How to setup Ruby and Oracle Instant Client on Snow Leopard](http://blog.rayapps.com/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard/).
46
+ Note that setting the environment variable RC\_ARCHS=x86\_64 instead of ARCHFLAGS="-arch x86\_64" will work fine also.
47
+
48
+ Intel Mac (32-bit)
49
+ ------------------
50
+
51
+ See [How to setup Ruby and Oracle Instant Client on Snow Leopard](http://blog.rayapps.com/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard/). Note that you need to replace x86\_64 with i386 in the blog.
52
+
53
+ The Intel Instant client is for Mac OS X 10.5 Leopard. If you are using 10.4 Tiger,
54
+ use one of the following workarounds.
55
+
56
+ * compile ruby as ppc. (look at [How to setup Ruby and Oracle client on Intel Mac](http://blog.rayapps.com/2007/08/27/how-to-setup-ruby-and-oracle-client-on-intel-mac/))
57
+ * use [ruby-odbc](http://www.ch-werner.de/rubyodbc/) and a third party ODBC driver ([Actual Technologies](http://www.actualtechnologies.com) or [OpenLink Software](http://uda.openlinksw.com/)).
58
+ * use JRuby and Oracle JDBC driver.
59
+
60
+ PowerPC Mac
61
+ -----------
62
+
63
+ See [How to setup Ruby and Oracle Instant Client on Snow Leopard](http://blog.rayapps.com/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard/). Note that you need to replace x86\_64 with ppc in the blog.
64
+
65
+ Solaris
66
+ =======
67
+
68
+ You need a same compiler which is used to make ruby itself.
69
+ For example, if the ruby is compiled by gcc, you need gcc. If it is compiled by Oracle Solaris Studio
70
+ (formerly called as Sun Studio), you need Oracle Solaris Studio.
71
+
72
+ If you use Blastwave.org's ruby and want not to install Sun Studio,
73
+ you can edit rbconfig.rb by your self. [(look at here)](http://forum.textdrive.com/viewtopic.php?id=12630)
74
+
75
+ If you use Sunfreeware.com's ruby and
76
+
77
+ $ ruby -r rbconfig -e "p Config::CONFIG['GNU_LD']"
78
+
79
+ prints "yes", you may need to edit rbconfig.rb distributed with the ruby
80
+ as follows:
81
+
82
+ from: CONFIG["LDFLAGS"] = "-L. -Wl,-E"
83
+ to: CONFIG["LDFLAGS"] = "-L. "
84
+
85
+ FreeBSD
86
+ =======
87
+
88
+ There are two ways.
89
+
90
+ * use ruby and instant client on linux emulator
91
+ * use oracle8-client port
92
+
93
+ linux emulator
94
+ --------------
95
+
96
+ I have not run ruby-oci8 on linux emulator, but I guess it will
97
+ run as follows. If it works, please tell me.
98
+
99
+ If FreeBSD has a cross-compiler which can generate linux binaries,
100
+ use it to compile ruby and ruby-oci8.
101
+
102
+ If FreeBSD doesn't have such a compiler, install a linux distribution
103
+ which FreeBSD can emulate to a PC machine, make ruby and ruby-oci8 in
104
+ the linux box and copy them to the FreeBSD box as follows.
105
+
106
+ On linux:
107
+
108
+ # make ruby
109
+ tar xvfz ruby-1.8.x.tar.gz
110
+ cd ruby-1.8.x
111
+ ./configure --prefix=/usr/local/ruby-1.8.x --enable-pthread
112
+ make
113
+ make install
114
+ # setup instant client
115
+ ....
116
+ # make ruby-oci8
117
+ PATH=/usr/local/ruby-1.8.x/bin:$PATH
118
+ tar xvfz ruby-oci8-1.0.x.tar.gz
119
+ cd ruby-oci8-1.0.x
120
+ make
121
+ make install
122
+ cd /usr/local/
123
+ tar cvfz ruby-1.8.x-linux.tar.gz ruby-1.8.x
124
+
125
+ Copy ruby-1.8.x-linux.tar.gz to the FreeBSD box.
126
+
127
+ On freebsd:
128
+
129
+ cd /compat/linux/usr/local
130
+ tar xvfz ruby-1.8.x-linux.tar.gz
131
+
132
+ oracle8-client port
133
+ -------------------
134
+
135
+ I don't recommend this because of the following two reasons.
136
+
137
+ * The oracle8-client port is made from Oracle 8.1.7.1 static library for Linux. Oracle have not supported the connectivity between 8.1.7.1 and Oracle 10g.
138
+ * It is very unstable. When it fails to connect to an Oracle server, it is down by segmentation fault on FreeBSD 7.0 not only when using ruby-oci8, but also by a very simple test code written by C.
139
+
140
+ If you try to use oracle8-client port, compile and install as follows.
141
+
142
+ * install oracle8-client
143
+
144
+ cd /usr/ports/databases/oracle8-client
145
+ make
146
+ make install
147
+
148
+ * set an environment variable ORACLE\_HOME
149
+
150
+ export ORACLE_HOME=/usr/local/oracle8-client
151
+
152
+ The rest steps are described at {file:docs/install-full-client.md}.
153
+
154
+ note: You have no need to set LD\_LIBRARY\_PATH because
155
+ Oracle libraries in oracle8-client port are static ones.
156
+
157
+ HP-UX
158
+ =====
159
+
160
+ You need a ruby which is linked with ''libpthread'' and ''libcl''.
161
+
162
+ Run `configure`.
163
+
164
+ tar xvfz ruby-1.9.x.tar.gz
165
+ cd ruby-1.9.x
166
+ ./configure
167
+
168
+ Then open `Makefile` to add '-lpthread -lcl' to `LIBS` and run `make`
169
+ and `make install`.
170
+
171
+ make
172
+ make install
173
+
174
+ The rest steps are described at {file:docs/install-full-client.md}.
175
+
176
+ Windows
177
+ =======
178
+
179
+ On some machines using a slow disk, you may get the following error.
180
+
181
+ Permission denied - conftest.exe
182
+
183
+ Edit mkmf.rb for a workaround.
184
+
185
+ def try_run(src, opt="")
186
+ if try_link0(src, opt)
187
+ xsystem("./conftest")
188
+ else
189
+ nil
190
+ end
191
+ ensure
192
+ # add the following one line.
193
+ sleep 1 if /mswin32|cygwin|mingw32|bccwin32/ =~ RUBY_PLATFORM
194
+ rm_f "conftest*"
195
+ end
196
+
197
+ See also: {http://abstractplain.net/blog/?p=788}.
@@ -0,0 +1,50 @@
1
+ # @title Report Installation Issues
2
+
3
+ Look at {file:docs/platform-specific-issues.md},
4
+ [the issues page on github][github] and [the ruby-oci8 help forum on rubyforge][rubyforge]
5
+ to check whether your issue is fixed or not.
6
+
7
+ If it is a new one, post the following information to [github][] or [rubyforge][].
8
+
9
+ [github]: https://github.com/kubo/ruby-oci8/issues
10
+ [rubyforge]: http://rubyforge.org/forum/forum.php?forum_id=1078
11
+
12
+ * Messages printed out to the console
13
+
14
+ * `gem_make.out` if you install a gem
15
+
16
+ * Last 100 lines of 'ext/oci8/mkmf.log'
17
+
18
+ Get them as follows.
19
+
20
+ tail -100 ext/oci8/mkmf.log
21
+
22
+ * The results of the following commands:
23
+
24
+ file `which ruby`
25
+ ruby --version
26
+ ruby -r rbconfig -e "p Config::CONFIG['host']"
27
+ ruby -r rbconfig -e "p Config::CONFIG['CC']"
28
+ ruby -r rbconfig -e "p Config::CONFIG['CFLAGS']"
29
+ ruby -r rbconfig -e "p Config::CONFIG['LDSHARED']"
30
+ ruby -r rbconfig -e "p Config::CONFIG['LDFLAGS']"
31
+ ruby -r rbconfig -e "p Config::CONFIG['DLDLAGS']"
32
+ ruby -r rbconfig -e "p Config::CONFIG['LIBS']"
33
+ ruby -r rbconfig -e "p Config::CONFIG['GNU_LD']"
34
+
35
+ # if you use gcc,
36
+ gcc --print-prog-name=ld
37
+ gcc --print-prog-name=as
38
+
39
+ # Oracle full client
40
+ file $ORACLE_HOME/bin/oracle
41
+
42
+ # Oracle Instant client. You need to change INSTANT_CLIENT_DIRECTORY.
43
+ file INSTANT_CLIENT_DIRECTORY/libclntsh.*
44
+
45
+ echo $LD_LIBRARY_PATH
46
+ echo $LIBPATH # AIX
47
+ echo $SHLIB_PATH # HP-UX PA-RISC 32-bit ruby
48
+ echo $DYLD_LIBRARY_PATH # Mac OS X
49
+ echo $LD_LIBRARY_PATH_32 # Solaris 32-bit ruby
50
+ echo $LD_LIBRARY_PATH_64 # Solaris 64-bit ruby
data/lib/.document ADDED
@@ -0,0 +1 @@
1
+ oci8
data/lib/dbd/OCI8.rb ADDED
@@ -0,0 +1,591 @@
1
+ #
2
+ # DBD::OCI8
3
+ #
4
+ # Copyright (c) 2002-2007 KUBO Takehiro <kubo@jiubao.org>
5
+ #
6
+ # copied some code from DBD::Oracle.
7
+ # DBD::Oracle's copyright is as follows:
8
+ # --------------------- begin -------------------
9
+ #
10
+ # Copyright (c) 2001, 2002, 2003, 2004 Michael Neumann <mneumann@ntecs.de>
11
+ #
12
+ # All rights reserved.
13
+ #
14
+ # Redistribution and use in source and binary forms, with or without
15
+ # modification, are permitted provided that the following conditions
16
+ # are met:
17
+ # 1. Redistributions of source code must retain the above copyright
18
+ # notice, this list of conditions and the following disclaimer.
19
+ # 2. Redistributions in binary form must reproduce the above copyright
20
+ # notice, this list of conditions and the following disclaimer in the
21
+ # documentation and/or other materials provided with the distribution.
22
+ # 3. The name of the author may not be used to endorse or promote products
23
+ # derived from this software without specific prior written permission.
24
+ #
25
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
26
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28
+ # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
31
+ # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
33
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+ #
36
+ # --------------------- end -------------------
37
+
38
+ require 'oci8'
39
+
40
+ module DBI # :nodoc:
41
+ module DBD # :nodoc:
42
+ module OCI8
43
+
44
+ VERSION = "0.1"
45
+ USED_DBD_VERSION = "0.4"
46
+
47
+ def self.driver_name
48
+ "OCI8"
49
+ end
50
+
51
+ # type converstion handler to bind values. (ruby-dbi 0.4)
52
+ if DBI.const_defined?(:TypeUtil)
53
+ DBI::TypeUtil.register_conversion("OCI8") do |obj|
54
+ case obj
55
+ when ::TrueClass
56
+ ['1', false]
57
+ when ::FalseClass
58
+ ['0', false]
59
+ else
60
+ [obj, false]
61
+ end
62
+ end
63
+ end
64
+
65
+ # no type converstion is required for result set. (ruby-dbi 0.4)
66
+ class NoTypeConversion
67
+ def self.parse(obj)
68
+ obj
69
+ end
70
+ end
71
+
72
+ module Util
73
+
74
+ ERROR_MAP = {
75
+ 1 => DBI::IntegrityError, # unique constraint violated
76
+ 900 => DBI::ProgrammingError, # invalid SQL statement
77
+ 904 => DBI::ProgrammingError, # invalid identifier
78
+ 905 => DBI::ProgrammingError, # missing keyword
79
+ 923 => DBI::ProgrammingError, # FROM keyword not found where expected
80
+ 936 => DBI::ProgrammingError, # missing expression
81
+ 942 => DBI::ProgrammingError, # table or view does not exist
82
+ 2290 => DBI::IntegrityError, # check constraint violated
83
+ 2291 => DBI::IntegrityError, # parent key not found
84
+ 2292 => DBI::IntegrityError, # child record found
85
+ 2293 => DBI::IntegrityError, # check constraint violated
86
+ }
87
+
88
+ def raise_dbierror(err) # :nodoc:
89
+ if err.is_a? OCIError
90
+ exc = ERROR_MAP[err.code] || DBI::DatabaseError
91
+ raise exc.new(err.message, err.code)
92
+ else
93
+ raise DBI::DatabaseError.new(err.message, -1)
94
+ end
95
+ rescue DBI::DatabaseError => exc
96
+ exc.set_backtrace(err.backtrace)
97
+ raise
98
+ end
99
+
100
+ def column_metadata_to_column_info(col)
101
+ sql_type, type_name, precision, scale =
102
+ case col.data_type
103
+ when :char
104
+ [SQL_CHAR, col.charset_form == :nchar ? "NCHAR" : "CHAR", col.data_size, nil]
105
+ when :varchar2
106
+ [SQL_VARCHAR, col.charset_form == :nchar ? "NVARCHAR2" : "VARCHAR2", col.data_size, nil]
107
+ when :raw
108
+ [SQL_VARBINARY, "RAW", col.data_size, nil]
109
+ when :long
110
+ [SQL_LONGVARCHAR, "LONG", 4000, nil]
111
+ when :long_raw
112
+ [SQL_LONGVARBINARY, "LONG RAW", 4000, nil]
113
+ when :clob
114
+ [SQL_CLOB, col.charset_form == :nchar ? "NCLOB" : "CLOB", 4000, nil]
115
+ when :blob
116
+ [SQL_BLOB, "BLOB", 4000, nil]
117
+ when :bfile
118
+ [SQL_BLOB, "BFILE", 4000, nil]
119
+ when :number
120
+ if col.scale == -127 && col.precision != 0
121
+ # To convert from binary to decimal precision, multiply n by 0.30103.
122
+ [SQL_FLOAT, "FLOAT", (col.precision * 0.30103).ceil , nil]
123
+ elsif col.precision == 0
124
+ # NUMBER or calculated value (eg. col * 1.2).
125
+ [SQL_NUMERIC, "NUMBER", 38, nil]
126
+ else
127
+ [SQL_NUMERIC, "NUMBER", col.precision, col.scale]
128
+ end
129
+ when :binary_float
130
+ # (23 * 0.30103).ceil => 7
131
+ [SQL_FLOAT, "BINARY_FLOAT", 7, nil]
132
+ when :binary_double
133
+ # (52 * 0.30103).ceil => 16
134
+ [SQL_DOUBLE, "BINARY_DOUBLE", 16, nil]
135
+ when :date
136
+ # yyyy-mm-dd hh:mi:ss
137
+ [SQL_DATE, "DATE", 19, nil]
138
+ when :timestamp
139
+ # yyyy-mm-dd hh:mi:ss.SSSS
140
+ [SQL_TIMESTAMP, "TIMESTAMP", 20 + col.fsprecision, nil]
141
+ when :timestamp_tz
142
+ # yyyy-mm-dd hh:mi:ss.SSSS +HH:MM
143
+ [SQL_TIMESTAMP, "TIMESTAMP WITH TIME ZONE", 27 + col.fsprecision, nil]
144
+ when :timestamp_ltz
145
+ # yyyy-mm-dd hh:mi:ss.SSSS
146
+ [SQL_TIMESTAMP, "TIMESTAMP WITH LOCAL TIME ZONE", 20 + col.fsprecision, nil]
147
+ when :interval_ym
148
+ # yyyy-mm
149
+ [SQL_OTHER, 'INTERVAL YEAR TO MONTH', col.lfprecision + 3, nil]
150
+ when :interval_ds
151
+ # dd hh:mi:ss.SSSSS
152
+ [SQL_OTHER, 'INTERVAL DAY TO SECOND', col.lfprecision + 10 + col.fsprecision, nil]
153
+ else
154
+ [SQL_OTHER, col.data_type.to_s, nil, nil]
155
+ end
156
+ {'name' => col.name,
157
+ 'sql_type' => sql_type,
158
+ 'type_name' => type_name,
159
+ 'nullable' => col.nullable?,
160
+ 'precision' => precision,
161
+ 'scale' => scale,
162
+ 'dbi_type' => NoTypeConversion,
163
+ }
164
+ end
165
+ private :column_metadata_to_column_info
166
+ end
167
+
168
+ class Driver < DBI::BaseDriver # :nodoc:
169
+ include Util
170
+
171
+ def initialize
172
+ super(USED_DBD_VERSION)
173
+ end
174
+
175
+ # external OS authentication
176
+ # (contributed by Dan Fitch)
177
+ def default_user
178
+ [nil, nil]
179
+ end
180
+
181
+ def connect( dbname, user, auth, attr )
182
+ handle = ::OCI8.new(user, auth, dbname, attr['Privilege'])
183
+ handle.non_blocking = true if attr['NonBlocking']
184
+ return Database.new(handle, attr)
185
+ rescue OCIException => err
186
+ raise_dbierror(err)
187
+ end
188
+ end
189
+
190
+ class Database < DBI::BaseDatabase
191
+ include Util
192
+
193
+ def disconnect
194
+ @handle.logoff
195
+ rescue OCIException => err
196
+ raise_dbierror(err)
197
+ end
198
+
199
+ def prepare( statement )
200
+ # convert ?-style parameters to :1, :2 etc.
201
+ prep_statement = DBI::SQL::PreparedStatement.new(DummyQuoter.new, statement)
202
+ if prep_statement.unbound.size > 0
203
+ arr = (1..(prep_statement.unbound.size)).collect{|i| ":#{i}"}
204
+ statement = prep_statement.bind( arr )
205
+ end
206
+ cursor = @handle.parse(statement)
207
+ Statement.new(cursor)
208
+ rescue OCIException => err
209
+ raise_dbierror(err)
210
+ end
211
+
212
+ def ping
213
+ @handle.exec("BEGIN NULL; END;")
214
+ true
215
+ rescue
216
+ false
217
+ end
218
+
219
+ def commit
220
+ @handle.commit()
221
+ rescue OCIException => err
222
+ raise_dbierror(err)
223
+ end
224
+
225
+ def rollback
226
+ @handle.rollback()
227
+ rescue OCIException => err
228
+ raise_dbierror(err)
229
+ end
230
+
231
+ def tables
232
+ stmt = execute("SELECT object_name FROM user_objects where object_type in ('TABLE', 'VIEW')")
233
+ rows = stmt.fetch_all || []
234
+ stmt.finish
235
+ rows.collect {|row| row[0]}
236
+ end
237
+
238
+ # SQLs are copied from DBD::Oracle.
239
+ def columns(table)
240
+ tab = @handle.describe_table(table)
241
+ cols = tab.columns
242
+ cols.collect! do |col|
243
+ column_metadata_to_column_info(col)
244
+ end
245
+
246
+ dbh = DBI::DatabaseHandle.new(self)
247
+
248
+ primaries = {}
249
+ dbh.select_all(<<EOS, tab.obj_schema, tab.obj_name) do |row|
250
+ select column_name
251
+ from all_cons_columns a, all_constraints b
252
+ where a.owner = b.owner
253
+ and a.constraint_name = b.constraint_name
254
+ and a.table_name = b.table_name
255
+ and b.constraint_type = 'P'
256
+ and b.owner = :1
257
+ and b.table_name = :2
258
+ EOS
259
+ primaries[row[0]] = true
260
+ end
261
+
262
+ indices = {}
263
+ uniques = {}
264
+ dbh.select_all(<<EOS, tab.obj_schema, tab.obj_name) do |row|
265
+ select a.column_name, a.index_name, b.uniqueness
266
+ from all_ind_columns a, all_indexes b
267
+ where a.index_name = b.index_name
268
+ and a.index_owner = b.owner
269
+ and a.table_owner = :1
270
+ and a.table_name = :2
271
+ EOS
272
+ col_name, index_name, uniqueness = row
273
+ indices[col_name] = true
274
+ uniques[col_name] = true if uniqueness == 'UNIQUE'
275
+ end
276
+
277
+ dbh.select_all(<<EOS, tab.obj_schema, tab.obj_name).collect do |row|
278
+ select column_id, column_name, data_default
279
+ from all_tab_columns
280
+ where owner = :1
281
+ and table_name = :2
282
+ EOS
283
+ col_id, col_name, default = row
284
+
285
+ col = cols[col_id.to_i - 1]
286
+ col_name = col['name']
287
+
288
+ if default && default[0] == ?'
289
+ default = default[1..-2].gsub(/''/, "'")
290
+ end
291
+
292
+ col['indexed'] = indices[col_name] || false
293
+ col['primary'] = primaries[col_name] || false
294
+ col['unique'] = uniques[col_name] || false
295
+ col['default'] = default
296
+ col
297
+ end
298
+ rescue OCIException => err
299
+ raise_dbierror(err)
300
+ end
301
+
302
+ def [](attr)
303
+ case attr
304
+ when 'AutoCommit'
305
+ @handle.autocommit?
306
+ end
307
+ end
308
+
309
+ def []=(attr, value)
310
+ case attr
311
+ when 'AutoCommit'
312
+ @handle.autocommit = value
313
+ end
314
+ end
315
+
316
+ private
317
+
318
+ class DummyQuoter # :nodoc:
319
+ # dummy to substitute ?-style parameter markers by :1 :2 etc.
320
+ def quote(str)
321
+ str
322
+ end
323
+ end
324
+ end
325
+
326
+ class Statement < DBI::BaseStatement
327
+ include Util
328
+
329
+ def initialize(cursor)
330
+ @cursor = cursor
331
+ end
332
+
333
+ def bind_param( param, value, attribs)
334
+ if attribs.nil? || attribs['type'].nil?
335
+ if value.nil?
336
+ @cursor.bind_param(param, nil, String, 1)
337
+ else
338
+ @cursor.bind_param(param, value)
339
+ end
340
+ else
341
+ case attribs['type']
342
+ when SQL_BINARY
343
+ type = OCI_TYPECODE_RAW
344
+ else
345
+ type = attribs['type']
346
+ end
347
+ @cursor.bind_param(param, value, type)
348
+ end
349
+ rescue OCIException => err
350
+ raise_dbierror(err)
351
+ end
352
+
353
+ def execute
354
+ @cursor.exec
355
+ rescue OCIException => err
356
+ raise_dbierror(err)
357
+ end
358
+
359
+ def finish
360
+ @cursor.close
361
+ rescue OCIException => err
362
+ raise_dbierror(err)
363
+ end
364
+
365
+ def fetch
366
+ @cursor.fetch
367
+ rescue OCIException => err
368
+ raise_dbierror(err)
369
+ end
370
+
371
+ def column_info
372
+ # minimum implementation.
373
+ @cursor.column_metadata.collect do |md|
374
+ col = column_metadata_to_column_info(md)
375
+ col['indexed'] = nil
376
+ col['primary'] = nil
377
+ col['unique'] = nil
378
+ col['default'] = nil
379
+ col
380
+ end
381
+ rescue OCIException => err
382
+ raise_dbierror(err)
383
+ end
384
+
385
+ def rows
386
+ @cursor.row_count
387
+ rescue OCIException => err
388
+ raise_dbierror(err)
389
+ end
390
+
391
+ def __rowid
392
+ @cursor.rowid
393
+ end
394
+
395
+ def __define(pos, type, length = nil)
396
+ @cursor.define(pos, type, length)
397
+ self
398
+ end
399
+
400
+ def __bind_value(param)
401
+ @cursor[param]
402
+ end
403
+ end
404
+
405
+ # DBI_STMT_NEW_ARGS is DBI::StatementHandle.new's arguments except +handle+.
406
+ #
407
+ # FYI: DBI::StatementHandle.new method signatures are follows:
408
+ # 0.2.2: handle, fetchable=false, prepared=true
409
+ # 0.4.0: handle, fetchable=false, prepared=true, convert_types=true
410
+ # 0.4.1: handle, fetchable=false, prepared=true, convert_types=true, executed=false
411
+ begin
412
+ DBI::StatementHandle.new(nil, false, true, true, true)
413
+ # dbi 0.4.1
414
+ DBI_STMT_NEW_ARGS = [true, true, true, true] # :nodoc:
415
+ rescue ArgumentError
416
+ # dbi 0.4.0 or lower
417
+ DBI_STMT_NEW_ARGS = [true] # :nodoc:
418
+ end
419
+
420
+ if defined? ::OCI8::BindType::Base
421
+ ##
422
+ ## ruby-oci8 2.0 bind classes.
423
+ ##
424
+
425
+ module BindType # :nodoc:
426
+
427
+ # helper class to define/bind DBI::Date.
428
+ class DBIDate < ::OCI8::BindType::OraDate
429
+ def set(val)
430
+ # convert val to an OraDate,
431
+ # then set it to the bind handle.
432
+ super(val && OraDate.new(val.year, val.month, val.day))
433
+ end
434
+ def get()
435
+ # get an Oradate from the bind handle,
436
+ # then convert it to a DBI::Date.
437
+ val = super()
438
+ return nil if val.nil?
439
+ DBI::Date.new(val.year, val.month, val.day)
440
+ end
441
+ end
442
+
443
+ # helper class to define/bind DBI::Timestamp.
444
+ #
445
+ # To fetch all Oracle's DATE columns as DBI::Timestamp:
446
+ # ::OCI8::BindType::Mapping[OCI8::SQLT_DAT] = ::DBI::DBD::OCI8::BindType::DBITimestamp
447
+ #
448
+ class DBITimestamp < ::OCI8::BindType::OraDate
449
+ def set(val)
450
+ # convert val to an OraDate,
451
+ # then set it to the bind handle.
452
+ super(val && OraDate.new(val.year, val.month, val.day,
453
+ val.respond_to?(:hour) ? val.hour : 0,
454
+ val.respond_to?(:min) ? val.min : 0,
455
+ val.respond_to?(:sec) ? val.sec : 0))
456
+ end
457
+ def get()
458
+ # get an Oradate from the bind handle,
459
+ # then convert it to a DBI::Timestamp.
460
+ val = super()
461
+ return nil if val.nil?
462
+ DBI::Timestamp.new(val.year, val.month, val.day, val.hour, val.minute, val.second)
463
+ end
464
+ end
465
+
466
+ # helper class to bind ref cursor as DBI::StatementHandle.
467
+ #
468
+ # # Create package
469
+ # dbh.execute(<<EOS)
470
+ # create or replace package test_pkg is
471
+ # type ref_cursor is ref cursor;
472
+ # procedure tab_table(csr out ref_cursor);
473
+ # end;
474
+ # EOS
475
+ #
476
+ # # Create package body
477
+ # dbh.execute(<<EOS)
478
+ # create or replace package body test_pkg is
479
+ # procedure tab_table(csr out ref_cursor) is
480
+ # begin
481
+ # open csr for select * from tab;
482
+ # end;
483
+ # end;
484
+ # EOS
485
+ #
486
+ # # Execute test_pkg.tab_table.
487
+ # # The first parameter is bound as DBI::StatementHandle.
488
+ # plsql = dbh.execute("begin test_pkg.tab_table(?); end;", DBI::StatementHandle)
489
+ #
490
+ # # Get the first parameter, which is a DBI::StatementHandle.
491
+ # sth = plsql.func(:bind_value, 1)
492
+ #
493
+ # # fetch column data.
494
+ # sth.fetch_all
495
+ #
496
+ class DBIStatementHandle < ::OCI8::BindType::Cursor
497
+ def set(val)
498
+ if val.is_a? DBI::StatementHandle
499
+ # get OCI8::Cursor
500
+ val = val.instance_eval do @handle end
501
+ val = val.instance_eval do @cursor end
502
+ end
503
+ super(val)
504
+ end
505
+ def get()
506
+ val = super
507
+ return nil if val.nil?
508
+ stmt = DBI::DBD::OCI8::Statement.new(val)
509
+ DBI::StatementHandle.new(stmt, *DBI_STMT_NEW_ARGS)
510
+ end
511
+ end
512
+ end # BindType
513
+
514
+ else
515
+ ##
516
+ ## ruby-oci8 1.0 bind classes.
517
+ ##
518
+
519
+ module BindType # :nodoc:
520
+ DBIDate = Object.new
521
+ class << DBIDate
522
+ def fix_type(env, val, length, precision, scale)
523
+ # bind as an OraDate
524
+ [::OCI8::SQLT_DAT, val, nil]
525
+ end
526
+ def decorate(b)
527
+ def b.set(val)
528
+ # convert val to an OraDate,
529
+ # then set it to the bind handle.
530
+ super(val && OraDate.new(val.year, val.month, val.day))
531
+ end
532
+ def b.get()
533
+ # get an Oradate from the bind handle,
534
+ # then convert it to a DBI::Date.
535
+ (val = super()) && DBI::Date.new(val.year, val.month, val.day)
536
+ end
537
+ end
538
+ end
539
+
540
+ DBITimestamp = Object.new
541
+ class << DBITimestamp
542
+ def fix_type(env, val, length, precision, scale)
543
+ # bind as an OraDate
544
+ [::OCI8::SQLT_DAT, val, nil]
545
+ end
546
+ def decorate(b)
547
+ def b.set(val)
548
+ # convert val to an OraDate,
549
+ # then set it to the bind handle.
550
+ super(val && OraDate.new(val.year, val.month, val.day,
551
+ val.respond_to?(:hour) ? val.hour : 0,
552
+ val.respond_to?(:min) ? val.min : 0,
553
+ val.respond_to?(:sec) ? val.sec : 0))
554
+ end
555
+ def b.get()
556
+ # get an Oradate from the bind handle,
557
+ # then convert it to a DBI::Timestamp.
558
+ (val = super()) && DBI::Timestamp.new(val.year, val.month, val.day, val.hour, val.minute, val.second)
559
+ end
560
+ end
561
+ end
562
+
563
+ DBIStatementHandle = Object.new
564
+ class << DBIStatementHandle
565
+ def fix_type(env, val, length, precision, scale)
566
+ raise NotImplementedError unless val.nil?
567
+ [::OCI8::SQLT_RSET, nil, env.alloc(OCIStmt)]
568
+ end
569
+ def decorate(b)
570
+ def b.set(val)
571
+ raise NotImplementedError
572
+ end
573
+ def b.get()
574
+ val = super
575
+ return val if val.nil?
576
+ cur = ::OCI8::Cursor.new(@env, @svc, @ctx, val)
577
+ stmt = DBI::DBD::OCI8::Statement.new(cur)
578
+ DBI::StatementHandle.new(stmt, *DBI_STMT_NEW_ARGS)
579
+ end
580
+ end
581
+ end
582
+ end # BindType
583
+ end
584
+
585
+ ::OCI8::BindType::Mapping[DBI::Date] = BindType::DBIDate
586
+ ::OCI8::BindType::Mapping[DBI::Timestamp] = BindType::DBITimestamp
587
+ ::OCI8::BindType::Mapping[DBI::StatementHandle] = BindType::DBIStatementHandle
588
+
589
+ end # module OCI8
590
+ end # module DBD
591
+ end # module DBI