ruby-oci8 2.1.5.1-x64-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.
- checksums.yaml +7 -0
- data/.yardopts +17 -0
- data/COPYING +30 -0
- data/COPYING_old +64 -0
- data/ChangeLog +2779 -0
- data/Makefile +92 -0
- data/NEWS +660 -0
- data/README.md +43 -0
- data/VERSION +1 -0
- data/dist-files +91 -0
- data/docs/install-binary-package.md +40 -0
- data/docs/install-full-client.md +116 -0
- data/docs/install-instant-client.md +167 -0
- data/docs/platform-specific-issues.md +197 -0
- data/docs/report-installation-issue.md +50 -0
- data/lib/.document +1 -0
- data/lib/dbd/OCI8.rb +591 -0
- data/lib/oci8.rb +147 -0
- data/lib/oci8.rb.in +147 -0
- data/lib/oci8/.document +8 -0
- data/lib/oci8/bindtype.rb +350 -0
- data/lib/oci8/compat.rb +113 -0
- data/lib/oci8/connection_pool.rb +108 -0
- data/lib/oci8/cursor.rb +564 -0
- data/lib/oci8/datetime.rb +605 -0
- data/lib/oci8/encoding-init.rb +79 -0
- data/lib/oci8/encoding.yml +537 -0
- data/lib/oci8/metadata.rb +2092 -0
- data/lib/oci8/object.rb +605 -0
- data/lib/oci8/oci8.rb +560 -0
- data/lib/oci8/ocihandle.rb +607 -0
- data/lib/oci8/oracle_version.rb +143 -0
- data/lib/oci8/properties.rb +134 -0
- data/lib/oci8lib_200.so +0 -0
- data/metaconfig +142 -0
- data/pre-distclean.rb +7 -0
- data/ruby-oci8.gemspec +80 -0
- data/setup.rb +1333 -0
- data/test/README +42 -0
- data/test/config.rb +184 -0
- data/test/setup_test_object.sql +171 -0
- data/test/test_all.rb +54 -0
- data/test/test_appinfo.rb +63 -0
- data/test/test_array_dml.rb +333 -0
- data/test/test_bind_raw.rb +46 -0
- data/test/test_bind_string.rb +106 -0
- data/test/test_bind_time.rb +178 -0
- data/test/test_break.rb +124 -0
- data/test/test_clob.rb +98 -0
- data/test/test_connection_pool.rb +125 -0
- data/test/test_connstr.rb +81 -0
- data/test/test_datetime.rb +581 -0
- data/test/test_dbi.rb +366 -0
- data/test/test_dbi_clob.rb +53 -0
- data/test/test_encoding.rb +104 -0
- data/test/test_error.rb +88 -0
- data/test/test_metadata.rb +1485 -0
- data/test/test_object.rb +462 -0
- data/test/test_oci8.rb +489 -0
- data/test/test_oracle_version.rb +70 -0
- data/test/test_oradate.rb +256 -0
- data/test/test_oranumber.rb +787 -0
- data/test/test_rowid.rb +33 -0
- 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
|