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
data/lib/oci8/compat.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#
|
2
|
+
# add compatible code with old versions.
|
3
|
+
#
|
4
|
+
|
5
|
+
OCI_STMT_SELECT = :select_stmt
|
6
|
+
OCI_STMT_UPDATE = :update_stmt
|
7
|
+
OCI_STMT_DELETE = :delete_stmt
|
8
|
+
OCI_STMT_INSERT = :insert_stmt
|
9
|
+
OCI_STMT_CREATE = :create_stmt
|
10
|
+
OCI_STMT_DROP = :drop_stmt
|
11
|
+
OCI_STMT_ALTER = :alter_stmt
|
12
|
+
OCI_STMT_BEGIN = :begin_stmt
|
13
|
+
OCI_STMT_DECLARE = :declare_stmt
|
14
|
+
|
15
|
+
class OCI8
|
16
|
+
|
17
|
+
STMT_SELECT = :select_stmt
|
18
|
+
STMT_UPDATE = :update_stmt
|
19
|
+
STMT_DELETE = :delete_stmt
|
20
|
+
STMT_INSERT = :insert_stmt
|
21
|
+
STMT_CREATE = :create_stmt
|
22
|
+
STMT_DROP = :drop_stmt
|
23
|
+
STMT_ALTER = :alter_stmt
|
24
|
+
STMT_BEGIN = :begin_stmt
|
25
|
+
STMT_DECLARE = :declare_stmt
|
26
|
+
|
27
|
+
RAW = :raw
|
28
|
+
|
29
|
+
# varchar, varchar2
|
30
|
+
SQLT_CHR = :varchar2
|
31
|
+
# number, double precision, float, real, numeric, int, integer, smallint
|
32
|
+
SQLT_NUM = :number
|
33
|
+
# long
|
34
|
+
SQLT_LNG = :long
|
35
|
+
# date
|
36
|
+
SQLT_DAT = :date
|
37
|
+
# raw
|
38
|
+
SQLT_BIN = :raw
|
39
|
+
# long raw
|
40
|
+
SQLT_LBI = :long_raw
|
41
|
+
# char
|
42
|
+
SQLT_AFC = :char
|
43
|
+
# binary_float
|
44
|
+
SQLT_IBFLOAT = :binary_float
|
45
|
+
# binary_double
|
46
|
+
SQLT_IBDOUBLE = :binary_double
|
47
|
+
# rowid
|
48
|
+
SQLT_RDD = :rowid
|
49
|
+
# clob
|
50
|
+
SQLT_CLOB = :clob
|
51
|
+
# blob
|
52
|
+
SQLT_BLOB = :blob
|
53
|
+
# bfile
|
54
|
+
SQLT_BFILE = :bfile
|
55
|
+
# ref cursor
|
56
|
+
SQLT_RSET = 116
|
57
|
+
# timestamp
|
58
|
+
SQLT_TIMESTAMP = :timestamp
|
59
|
+
# timestamp with time zone
|
60
|
+
SQLT_TIMESTAMP_TZ = :timestamp_tz
|
61
|
+
# interval year to month
|
62
|
+
SQLT_INTERVAL_YM = :interval_ym
|
63
|
+
# interval day to second
|
64
|
+
SQLT_INTERVAL_DS = :interval_ds
|
65
|
+
# timestamp with local time zone
|
66
|
+
SQLT_TIMESTAMP_LTZ = :timestamp_ltz
|
67
|
+
|
68
|
+
# mapping of sql type number to sql type name.
|
69
|
+
SQLT_NAMES = {}
|
70
|
+
constants.each do |name|
|
71
|
+
next if name.to_s.index("SQLT_") != 0
|
72
|
+
val = const_get name.intern
|
73
|
+
if val.is_a? Fixnum
|
74
|
+
SQLT_NAMES[val] = name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# add alias compatible with 'Oracle7 Module for Ruby'.
|
79
|
+
alias autocommit autocommit?
|
80
|
+
|
81
|
+
class Cursor
|
82
|
+
def self.select_number_as=(val)
|
83
|
+
if val == Fixnum
|
84
|
+
@@bind_unknown_number = OCI8::BindType::Fixnum
|
85
|
+
elsif val == Integer
|
86
|
+
@@bind_unknown_number = OCI8::BindType::Integer
|
87
|
+
elsif val == Float
|
88
|
+
@@bind_unknown_number = OCI8::BindType::Float
|
89
|
+
else
|
90
|
+
raise ArgumentError, "must be Fixnum, Integer or Float"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.select_number_as
|
95
|
+
case @@bind_unknown_number
|
96
|
+
when OCI8::BindType::Fixnum
|
97
|
+
return Fixnum
|
98
|
+
when OCI8::BindType::Integer
|
99
|
+
return Integer
|
100
|
+
when OCI8::BindType::Float
|
101
|
+
return Float
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# add alias compatible with 'Oracle7 Module for Ruby'.
|
106
|
+
alias getColNames get_col_names
|
107
|
+
end
|
108
|
+
|
109
|
+
module BindType
|
110
|
+
# alias to Integer for compatibility with ruby-oci8 1.0.
|
111
|
+
Fixnum = Integer
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
#--
|
2
|
+
# connection_pool.rb -- OCI8::ConnectionPool
|
3
|
+
#
|
4
|
+
# Copyright (C) 2010 KUBO Takehiro <kubo@jiubao.org>
|
5
|
+
#++
|
6
|
+
|
7
|
+
#
|
8
|
+
class OCI8
|
9
|
+
|
10
|
+
# Connection pooling is the use of a group (the pool) of reusable
|
11
|
+
# physical connections by several sessions to balance loads.
|
12
|
+
# See: {Oracle Call Interface Manual}[http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/oci09adv.htm#sthref1479]
|
13
|
+
#
|
14
|
+
# This is equivalent to Oracle JDBC Driver {OCI Connection Pooling}[http://docs.oracle.com/cd/E11882_01/java.112/e16548/ociconpl.htm#JJDBC28789].
|
15
|
+
#
|
16
|
+
# Usage:
|
17
|
+
# # Create a connection pool.
|
18
|
+
# # username and password are required to establish an implicit primary session.
|
19
|
+
# cpool = OCI8::ConnectionPool.new(1, 5, 2, username, password, database)
|
20
|
+
#
|
21
|
+
# # Get a session from the pool.
|
22
|
+
# # Pass the connection pool to the third argument.
|
23
|
+
# conn1 = OCI8.new(username, password, cpool)
|
24
|
+
#
|
25
|
+
# # Get another session.
|
26
|
+
# conn2 = OCI8.new(username, password, cpool)
|
27
|
+
#
|
28
|
+
class ConnectionPool
|
29
|
+
|
30
|
+
# Connections idle for more than this time value (in seconds) are
|
31
|
+
# terminated, to maintain an optimum number of open
|
32
|
+
# connections. If it is zero, the connections are never timed out.
|
33
|
+
# The default value is zero.
|
34
|
+
#
|
35
|
+
# <b>Note:</b> Shrinkage of the pool only occurs when there is a network
|
36
|
+
# round trip. If there are no operations, then the connections
|
37
|
+
# stay alive.
|
38
|
+
#
|
39
|
+
# @return [Integer]
|
40
|
+
def timeout
|
41
|
+
attr_get_ub4(OCI_ATTR_CONN_TIMEOUT)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Changes the timeout in seconds to terminate idle connections.
|
45
|
+
#
|
46
|
+
# @param [Integer] val
|
47
|
+
def timeout=(val)
|
48
|
+
attr_set_ub4(OCI_ATTR_CONN_TIMEOUT, val)
|
49
|
+
end
|
50
|
+
|
51
|
+
# If true, an error is thrown when all the connections in the pool
|
52
|
+
# are busy and the number of connections has already reached the
|
53
|
+
# maximum. Otherwise the call waits till it gets a connection.
|
54
|
+
# The default value is false.
|
55
|
+
def nowait?
|
56
|
+
attr_get_ub1(OCI_ATTR_CONN_NOWAIT) != 0
|
57
|
+
end
|
58
|
+
|
59
|
+
# Changes the behavior when all the connections in the pool
|
60
|
+
# are busy and the number of connections has already reached the
|
61
|
+
# maximum.
|
62
|
+
#
|
63
|
+
# @param [Boolean] val
|
64
|
+
def nowait=(val)
|
65
|
+
attr_set_ub1(OCI_ATTR_CONN_NOWAIT, val ? 1 : 0)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the number of busy physical connections.
|
69
|
+
#
|
70
|
+
# @return [Integer]
|
71
|
+
def busy_count
|
72
|
+
attr_get_ub4(OCI_ATTR_CONN_BUSY_COUNT)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns the number of open physical connections.
|
76
|
+
#
|
77
|
+
# @return [Integer]
|
78
|
+
def open_count
|
79
|
+
attr_get_ub4(OCI_ATTR_CONN_OPEN_COUNT)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns the number of minimum physical connections.
|
83
|
+
#
|
84
|
+
# @return [Integer]
|
85
|
+
def min
|
86
|
+
attr_get_ub4(OCI_ATTR_CONN_MIN)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns the number of maximum physical connections.
|
90
|
+
#
|
91
|
+
# @return [Integer]
|
92
|
+
def max
|
93
|
+
attr_get_ub4(OCI_ATTR_CONN_MAX)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns the connection increment parameter.
|
97
|
+
#
|
98
|
+
# @return [Integer]
|
99
|
+
def incr
|
100
|
+
attr_get_ub4(OCI_ATTR_CONN_INCR)
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
def destroy
|
105
|
+
free
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/oci8/cursor.rb
ADDED
@@ -0,0 +1,564 @@
|
|
1
|
+
# oci8.rb -- OCI8::Cursor
|
2
|
+
#
|
3
|
+
# Copyright (C) 2002-2012 KUBO Takehiro <kubo@jiubao.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
#
|
7
|
+
class OCI8
|
8
|
+
|
9
|
+
# The instance of this class corresponds to cursor in the term of
|
10
|
+
# Oracle, which corresponds to java.sql.Statement of JDBC and statement
|
11
|
+
# handle $sth of Perl/DBI.
|
12
|
+
#
|
13
|
+
# Don't create the instance by calling 'new' method. Please create it by
|
14
|
+
# calling OCI8#exec or OCI8#parse.
|
15
|
+
class Cursor
|
16
|
+
|
17
|
+
# @note Don't use this constructor. Use {OCI8#parse} instead.
|
18
|
+
#
|
19
|
+
# @param [OCI8] conn connection
|
20
|
+
# @param [String] sql SQL statement
|
21
|
+
def initialize(conn, sql = nil)
|
22
|
+
@bind_handles = {}
|
23
|
+
@define_handles = []
|
24
|
+
@column_metadata = []
|
25
|
+
@names = nil
|
26
|
+
@con = conn
|
27
|
+
@max_array_size = nil
|
28
|
+
__initialize(conn, sql) # Initialize the internal C structure.
|
29
|
+
end
|
30
|
+
|
31
|
+
# explicitly indicate the date type of fetched value. run this
|
32
|
+
# method within parse and exec. pos starts from 1. lentgh is used
|
33
|
+
# when type is String.
|
34
|
+
#
|
35
|
+
# example:
|
36
|
+
# cursor = conn.parse("SELECT ename, hiredate FROM emp")
|
37
|
+
# cursor.define(1, String, 20) # fetch the first column as String.
|
38
|
+
# cursor.define(2, Time) # fetch the second column as Time.
|
39
|
+
# cursor.exec()
|
40
|
+
def define(pos, type, length = nil)
|
41
|
+
bindobj = make_bind_object(:type => type, :length => length)
|
42
|
+
__define(pos, bindobj)
|
43
|
+
if old = @define_handles[pos - 1]
|
44
|
+
old.send(:free)
|
45
|
+
end
|
46
|
+
@define_handles[pos - 1] = bindobj
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Binds variables explicitly.
|
51
|
+
#
|
52
|
+
# When key is number, it binds by position, which starts from 1.
|
53
|
+
# When key is string, it binds by the name of placeholder.
|
54
|
+
#
|
55
|
+
# example:
|
56
|
+
# cursor = conn.parse("SELECT * FROM emp WHERE ename = :ename")
|
57
|
+
# cursor.bind_param(1, 'SMITH') # bind by position
|
58
|
+
# ...or...
|
59
|
+
# cursor.bind_param(':ename', 'SMITH') # bind by name
|
60
|
+
#
|
61
|
+
# To bind as number, Fixnum and Float are available, but Bignum is
|
62
|
+
# not supported. If its initial value is NULL, please set nil to
|
63
|
+
# +type+ and Fixnum or Float to +val+.
|
64
|
+
#
|
65
|
+
# example:
|
66
|
+
# cursor.bind_param(1, 1234) # bind as Fixnum, Initial value is 1234.
|
67
|
+
# cursor.bind_param(1, 1234.0) # bind as Float, Initial value is 1234.0.
|
68
|
+
# cursor.bind_param(1, nil, Fixnum) # bind as Fixnum, Initial value is NULL.
|
69
|
+
# cursor.bind_param(1, nil, Float) # bind as Float, Initial value is NULL.
|
70
|
+
#
|
71
|
+
# In case of binding a string, set the string itself to
|
72
|
+
# +val+. When the bind variable is used as output, set the
|
73
|
+
# string whose length is enough to store or set the length.
|
74
|
+
#
|
75
|
+
# example:
|
76
|
+
# cursor = conn.parse("BEGIN :out := :in || '_OUT'; END;")
|
77
|
+
# cursor.bind_param(':in', 'DATA') # bind as String with width 4.
|
78
|
+
# cursor.bind_param(':out', nil, String, 7) # bind as String with width 7.
|
79
|
+
# cursor.exec()
|
80
|
+
# p cursor[':out'] # => 'DATA_OU'
|
81
|
+
# # Though the length of :out is 8 bytes in PL/SQL block, it is
|
82
|
+
# # bound as 7 bytes. So result is cut off at 7 byte.
|
83
|
+
#
|
84
|
+
# In case of binding a string as RAW, set OCI::RAW to +type+.
|
85
|
+
#
|
86
|
+
# example:
|
87
|
+
# cursor = conn.parse("INSERT INTO raw_table(raw_column) VALUE (:1)")
|
88
|
+
# cursor.bind_param(1, 'RAW_STRING', OCI8::RAW)
|
89
|
+
# cursor.exec()
|
90
|
+
# cursor.close()
|
91
|
+
def bind_param(key, param, type = nil, length = nil)
|
92
|
+
case param
|
93
|
+
when Hash
|
94
|
+
when Class
|
95
|
+
param = {:value => nil, :type => param, :length => length}
|
96
|
+
else
|
97
|
+
param = {:value => param, :type => type, :length => length}
|
98
|
+
end
|
99
|
+
bindobj = make_bind_object(param)
|
100
|
+
__bind(key, bindobj)
|
101
|
+
if old = @bind_handles[key]
|
102
|
+
old.send(:free)
|
103
|
+
end
|
104
|
+
@bind_handles[key] = bindobj
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
# Executes the SQL statement assigned the cursor. The type of
|
109
|
+
# return value depends on the type of sql statement: select;
|
110
|
+
# insert, update and delete; create, alter, drop and PL/SQL.
|
111
|
+
#
|
112
|
+
# In case of select statement, it returns the number of the
|
113
|
+
# select-list.
|
114
|
+
#
|
115
|
+
# In case of insert, update or delete statement, it returns the
|
116
|
+
# number of processed rows.
|
117
|
+
#
|
118
|
+
# In case of create, alter, drop and PL/SQL statement, it returns
|
119
|
+
# true. In contrast with OCI8#exec, it returns true even
|
120
|
+
# though PL/SQL. Use OCI8::Cursor#[] explicitly to get bind
|
121
|
+
# variables.
|
122
|
+
def exec(*bindvars)
|
123
|
+
bind_params(*bindvars)
|
124
|
+
case type
|
125
|
+
when :select_stmt
|
126
|
+
__execute(0)
|
127
|
+
define_columns()
|
128
|
+
else
|
129
|
+
__execute(1)
|
130
|
+
row_count
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Gets fetched data as array. This is available for select
|
135
|
+
# statement only.
|
136
|
+
#
|
137
|
+
# @example
|
138
|
+
# conn = OCI8.new('scott', 'tiger')
|
139
|
+
# cursor = conn.exec('SELECT * FROM emp')
|
140
|
+
# while r = cursor.fetch()
|
141
|
+
# puts r.join(',')
|
142
|
+
# end
|
143
|
+
# cursor.close
|
144
|
+
# conn.logoff
|
145
|
+
#
|
146
|
+
# @return [Array]
|
147
|
+
def fetch
|
148
|
+
if block_given?
|
149
|
+
while row = fetch_one_row_as_array
|
150
|
+
yield row
|
151
|
+
end
|
152
|
+
self
|
153
|
+
else
|
154
|
+
fetch_one_row_as_array
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Gets fetched data as a Hash. The hash keys are column names.
|
159
|
+
# If a block is given, acts as an iterator.
|
160
|
+
#
|
161
|
+
# @return [Hash] the hash keys are column names and hash values are column values
|
162
|
+
def fetch_hash
|
163
|
+
if block_given?
|
164
|
+
while row = fetch_one_row_as_hash()
|
165
|
+
yield row
|
166
|
+
end
|
167
|
+
else
|
168
|
+
fetch_one_row_as_hash
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Gets the value of the bind variable.
|
173
|
+
#
|
174
|
+
# When bind variables are explicitly bound by {OCI8::Cursor#bind_param},
|
175
|
+
# the subscript +key+ must be same with the parameter +key+ passed to {OCI8::Cursor#bind_param}.
|
176
|
+
#
|
177
|
+
# When they are implicitly bound by {OCI8#exec} or {OCI8::Cursor#exec},
|
178
|
+
# the subscript +key+ is the position which starts from one.
|
179
|
+
#
|
180
|
+
# @example explicitly bind by name
|
181
|
+
# cursor = conn.parse("BEGIN :out := 'BAR'; END;")
|
182
|
+
# cursor.bind_param(:out, 'FOO') # bind by name
|
183
|
+
# p cursor[:out] # => 'FOO' - The subscript must be :out.
|
184
|
+
# cursor.exec()
|
185
|
+
# p cursor[:out] # => 'BAR'
|
186
|
+
#
|
187
|
+
# @example explicitly bind by position
|
188
|
+
# cursor = conn.parse("BEGIN :out := 'BAR'; END;")
|
189
|
+
# cursor.bind_param(1, 'FOO') # bind by position
|
190
|
+
# p cursor[1] # => 'FOO' - The subscript must be 1.
|
191
|
+
# cursor.exec()
|
192
|
+
# p cursor[1] # => 'BAR'
|
193
|
+
#
|
194
|
+
# @example implicitly bind
|
195
|
+
# cursor = conn.exec("BEGIN :out := 'BAR'; END;", 'FOO')
|
196
|
+
# # 1st bind variable is bound as String with width 3. Its initial value is 'FOO'
|
197
|
+
# # After execute, the value become 'BAR'.
|
198
|
+
# p cursor[1] # => 'BAR'
|
199
|
+
#
|
200
|
+
# @param [Object] key bind key
|
201
|
+
# @return [Object] the value of the bind variable
|
202
|
+
#
|
203
|
+
def [](key)
|
204
|
+
handle = @bind_handles[key]
|
205
|
+
handle && handle.send(:get_data)
|
206
|
+
end
|
207
|
+
|
208
|
+
# Changes the bind variable value.
|
209
|
+
#
|
210
|
+
# When bind variables are explicitly bound by {OCI8::Cursor#bind_param},
|
211
|
+
# the subscript +key+ must be same with the parameter +key+ passed to {OCI8::Cursor#bind_param}.
|
212
|
+
#
|
213
|
+
# When they are implicitly bound by {OCI8#exec} or {OCI8::Cursor#exec},
|
214
|
+
# the subscript +key+ is the position which starts from one.
|
215
|
+
#
|
216
|
+
# @example
|
217
|
+
# # Inserts three rows whose values are 'FOO', 'BAR' and 'BAZ.'
|
218
|
+
# cursor = conn.parse("INSERT INTO test(col1) VALUES(:1)")
|
219
|
+
# begin
|
220
|
+
# cursor.bind_params(1, nil, String, 3)
|
221
|
+
# ['FOO', 'BAR', 'BAZ'].each do |column_value|
|
222
|
+
# cursor[1] = column_value # Change the bind value
|
223
|
+
# cursor.exec # and insert it.
|
224
|
+
# end
|
225
|
+
# ensure
|
226
|
+
# cursor.close()
|
227
|
+
# end
|
228
|
+
# # This makes same result with the following but is more efficient.
|
229
|
+
# #
|
230
|
+
# # ['FOO', 'BAR', 'BAZ'].each do |column_value|
|
231
|
+
# # conn.exec("INSERT INTO test(col1) VALUES(:1)", column_value)
|
232
|
+
# # end
|
233
|
+
# #
|
234
|
+
#
|
235
|
+
# @param [Object] key bind key
|
236
|
+
# @param [Object] val bind value
|
237
|
+
#
|
238
|
+
def []=(key, val)
|
239
|
+
handle = @bind_handles[key]
|
240
|
+
return nil if handle.nil?
|
241
|
+
|
242
|
+
if val.is_a? Array
|
243
|
+
if @actual_array_size > 0 && val.length != @actual_array_size
|
244
|
+
raise RuntimeError, "all binding arrays hould be the same size"
|
245
|
+
end
|
246
|
+
if @actual_array_size == 0 && val.length <= @max_array_size
|
247
|
+
@actual_array_size = val.length
|
248
|
+
end
|
249
|
+
end
|
250
|
+
handle.send(:set_data, val)
|
251
|
+
val
|
252
|
+
end
|
253
|
+
|
254
|
+
# Set the maximum array size for bind_param_array
|
255
|
+
#
|
256
|
+
# All the binds will be clean from cursor if instance variable max_array_size is set before
|
257
|
+
#
|
258
|
+
# Instance variable actual_array_size holds the size of the arrays users actually binds through bind_param_array
|
259
|
+
# all the binding arrays are required to be the same size
|
260
|
+
def max_array_size=(size)
|
261
|
+
raise "expect positive number for max_array_size." if size.nil? && size <=0
|
262
|
+
free_bind_handles() if !@max_array_size.nil?
|
263
|
+
@max_array_size = size
|
264
|
+
@actual_array_size = nil
|
265
|
+
end
|
266
|
+
|
267
|
+
# Binds array explicitly
|
268
|
+
#
|
269
|
+
# When key is number, it binds by position, which starts from 1.
|
270
|
+
# When key is string, it binds by the name of placeholder.
|
271
|
+
#
|
272
|
+
# The max_array_size should be set before calling bind_param_array
|
273
|
+
#
|
274
|
+
# @example
|
275
|
+
# cursor = conn.parse("INSERT INTO test_table VALUES (:str)")
|
276
|
+
# cursor.max_array_size = 3
|
277
|
+
# cursor.bind_param_array(1, ['happy', 'new', 'year'], String, 30)
|
278
|
+
# cursor.exec_array
|
279
|
+
def bind_param_array(key, var_array, type = nil, max_item_length = nil)
|
280
|
+
raise "please call max_array_size= first." if @max_array_size.nil?
|
281
|
+
raise "expect array as input param for bind_param_array." if !var_array.nil? && !(var_array.is_a? Array)
|
282
|
+
raise "the size of var_array should not be greater than max_array_size." if !var_array.nil? && var_array.size > @max_array_size
|
283
|
+
|
284
|
+
if var_array.nil?
|
285
|
+
raise "all binding arrays should be the same size." unless @actual_array_size.nil? || @actual_array_size == 0
|
286
|
+
@actual_array_size = 0
|
287
|
+
else
|
288
|
+
raise "all binding arrays should be the same size." unless @actual_array_size.nil? || var_array.size == @actual_array_size
|
289
|
+
@actual_array_size = var_array.size if @actual_array_size.nil?
|
290
|
+
end
|
291
|
+
|
292
|
+
param = {:value => var_array, :type => type, :length => max_item_length, :max_array_size => @max_array_size}
|
293
|
+
first_non_nil_elem = var_array.nil? ? nil : var_array.find{|x| x!= nil}
|
294
|
+
|
295
|
+
if type.nil?
|
296
|
+
if first_non_nil_elem.nil?
|
297
|
+
raise "bind type is not given."
|
298
|
+
else
|
299
|
+
type = first_non_nil_elem.class
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
bindclass = OCI8::BindType::Mapping[type]
|
304
|
+
if bindclass.nil? and type.is_a? Class
|
305
|
+
bindclass = OCI8::BindType::Mapping[type.to_s]
|
306
|
+
OCI8::BindType::Mapping[type] = bindclass if bindclass
|
307
|
+
end
|
308
|
+
raise "unsupported dataType: #{type}" if bindclass.nil?
|
309
|
+
bindobj = bindclass.create(@con, var_array, param, @max_array_size)
|
310
|
+
__bind(key, bindobj)
|
311
|
+
#
|
312
|
+
if old = @bind_handles[key]
|
313
|
+
old.send(:free)
|
314
|
+
end
|
315
|
+
@bind_handles[key] = bindobj
|
316
|
+
self
|
317
|
+
end
|
318
|
+
|
319
|
+
# Executes the SQL statement assigned the cursor with array binding
|
320
|
+
def exec_array
|
321
|
+
raise "please call max_array_size= first." if @max_array_size.nil?
|
322
|
+
|
323
|
+
if !@actual_array_size.nil? && @actual_array_size > 0
|
324
|
+
__execute(@actual_array_size)
|
325
|
+
else
|
326
|
+
raise "please set non-nil values to array binding parameters"
|
327
|
+
end
|
328
|
+
|
329
|
+
case type
|
330
|
+
when :update_stmt, :delete_stmt, :insert_stmt
|
331
|
+
row_count
|
332
|
+
else
|
333
|
+
true
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
# Gets the names of select-list as array. Please use this
|
338
|
+
# method after exec.
|
339
|
+
def get_col_names
|
340
|
+
@names ||= @column_metadata.collect { |md| md.name }
|
341
|
+
end
|
342
|
+
|
343
|
+
# Gets an array of OCI8::Metadata::Column of a select statement.
|
344
|
+
#
|
345
|
+
# @example
|
346
|
+
# cursor = conn.exec('select * from tab')
|
347
|
+
# puts ' Name Type'
|
348
|
+
# puts ' ----------------------------------------- ----------------------------'
|
349
|
+
# cursor.column_metadata.each do |colinfo|
|
350
|
+
# puts format(' %-41s %s',
|
351
|
+
# colinfo.name,
|
352
|
+
# colinfo.type_string)
|
353
|
+
# end
|
354
|
+
#
|
355
|
+
# @return [Array of OCI8::Metadata::Column]
|
356
|
+
#
|
357
|
+
# @since 1.0.0
|
358
|
+
def column_metadata
|
359
|
+
@column_metadata
|
360
|
+
end
|
361
|
+
|
362
|
+
# close the cursor.
|
363
|
+
def close
|
364
|
+
free()
|
365
|
+
@names = nil
|
366
|
+
@column_metadata = nil
|
367
|
+
end
|
368
|
+
|
369
|
+
# Returns the keys of bind variables.
|
370
|
+
#
|
371
|
+
# @return [Array] bind variable keys
|
372
|
+
def keys
|
373
|
+
@bind_handles.keys
|
374
|
+
end
|
375
|
+
|
376
|
+
# Set the number of rows to be prefetched.
|
377
|
+
# This can reduce the number of network round trips when fetching
|
378
|
+
# many rows. The default value is one.
|
379
|
+
#
|
380
|
+
# FYI: Rails oracle adaptor uses 100 by default.
|
381
|
+
#
|
382
|
+
# @param [Fixnum] rows The number of rows to be prefetched
|
383
|
+
def prefetch_rows=(rows)
|
384
|
+
attr_set_ub4(11, rows) # OCI_ATTR_PREFETCH_ROWS(11)
|
385
|
+
end
|
386
|
+
|
387
|
+
# Returns the number of processed rows.
|
388
|
+
#
|
389
|
+
# @return [Integer]
|
390
|
+
def row_count
|
391
|
+
# http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5498
|
392
|
+
attr_get_ub4(9) # OCI_ATTR_ROW_COUNT(9)
|
393
|
+
end
|
394
|
+
|
395
|
+
# Returns the text of the SQL statement prepared in the cursor.
|
396
|
+
#
|
397
|
+
# @note
|
398
|
+
# When {http://docs.oracle.com/cd/E11882_01/server.112/e10729/ch7progrunicode.htm#CACHHIFE
|
399
|
+
# NCHAR String Literal Replacement} is turned on, it returns the modified SQL text,
|
400
|
+
# instead of the original SQL text.
|
401
|
+
#
|
402
|
+
# @example
|
403
|
+
# cursor = conn.parse("select * from country where country_code = 'ja'")
|
404
|
+
# cursor.statement # => "select * from country where country_code = 'ja'"
|
405
|
+
#
|
406
|
+
# @return [String] prepared SQL statement
|
407
|
+
#
|
408
|
+
# @since 2.1.3
|
409
|
+
#
|
410
|
+
def statement
|
411
|
+
# The magic number 144 is OCI_ATTR_STATEMENT.
|
412
|
+
# See http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5503
|
413
|
+
attr_get_string(144)
|
414
|
+
end
|
415
|
+
|
416
|
+
# gets the type of SQL statement as follows.
|
417
|
+
# * OCI8::STMT_SELECT
|
418
|
+
# * OCI8::STMT_UPDATE
|
419
|
+
# * OCI8::STMT_DELETE
|
420
|
+
# * OCI8::STMT_INSERT
|
421
|
+
# * OCI8::STMT_CREATE
|
422
|
+
# * OCI8::STMT_DROP
|
423
|
+
# * OCI8::STMT_ALTER
|
424
|
+
# * OCI8::STMT_BEGIN (PL/SQL block which starts with a BEGIN keyword)
|
425
|
+
# * OCI8::STMT_DECLARE (PL/SQL block which starts with a DECLARE keyword)
|
426
|
+
# * Other Fixnum value undocumented in Oracle manuals.
|
427
|
+
#
|
428
|
+
# <em>Changes between ruby-oci8 1.0 and 2.0.</em>
|
429
|
+
#
|
430
|
+
# [ruby-oci8 2.0] OCI8::STMT_* are Symbols. (:select_stmt, :update_stmt, etc.)
|
431
|
+
# [ruby-oci8 1.0] OCI8::STMT_* are Fixnums. (1, 2, 3, etc.)
|
432
|
+
#
|
433
|
+
def type
|
434
|
+
# http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5506
|
435
|
+
stmt_type = attr_get_ub2(24) # OCI_ATTR_STMT_TYPE(24)
|
436
|
+
case stmt_type
|
437
|
+
when 1 # OCI_STMT_SELECT
|
438
|
+
:select_stmt
|
439
|
+
when 2 # OCI_STMT_UPDATE
|
440
|
+
:update_stmt
|
441
|
+
when 3 # OCI_STMT_DELETE
|
442
|
+
:delete_stmt
|
443
|
+
when 4 # OCI_STMT_INSERT
|
444
|
+
:insert_stmt
|
445
|
+
when 5 # OCI_STMT_CREATE
|
446
|
+
:create_stmt
|
447
|
+
when 6 # OCI_STMT_DROP
|
448
|
+
:drop_stmt
|
449
|
+
when 7 # OCI_STMT_ALTER
|
450
|
+
:alter_stmt
|
451
|
+
when 8 # OCI_STMT_BEGIN
|
452
|
+
:begin_stmt
|
453
|
+
when 9 # OCI_STMT_DECLARE
|
454
|
+
:declare_stmt
|
455
|
+
else
|
456
|
+
stmt_type
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
private
|
461
|
+
|
462
|
+
def make_bind_object(param)
|
463
|
+
case param
|
464
|
+
when Hash
|
465
|
+
key = param[:type]
|
466
|
+
val = param[:value]
|
467
|
+
max_array_size = param[:max_array_size]
|
468
|
+
|
469
|
+
if key.nil?
|
470
|
+
if val.nil?
|
471
|
+
raise "bind type is not given."
|
472
|
+
elsif val.is_a? OCI8::Object::Base
|
473
|
+
key = :named_type
|
474
|
+
param = @con.get_tdo_by_class(val.class)
|
475
|
+
else
|
476
|
+
key = val.class
|
477
|
+
end
|
478
|
+
elsif key.class == Class && key < OCI8::Object::Base
|
479
|
+
param = @con.get_tdo_by_class(key)
|
480
|
+
key = :named_type
|
481
|
+
end
|
482
|
+
when OCI8::Metadata::Base
|
483
|
+
key = param.data_type
|
484
|
+
case key
|
485
|
+
when :named_type
|
486
|
+
if param.type_name == 'XMLTYPE'
|
487
|
+
key = :xmltype
|
488
|
+
else
|
489
|
+
param = @con.get_tdo_by_metadata(param.type_metadata)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
else
|
493
|
+
raise "unknown param #{param.intern}"
|
494
|
+
end
|
495
|
+
|
496
|
+
bindclass = OCI8::BindType::Mapping[key]
|
497
|
+
if bindclass.nil? and key.is_a? Class
|
498
|
+
bindclass = OCI8::BindType::Mapping[key.to_s]
|
499
|
+
OCI8::BindType::Mapping[key] = bindclass if bindclass
|
500
|
+
end
|
501
|
+
raise "unsupported datatype: #{key}" if bindclass.nil?
|
502
|
+
bindclass.create(@con, val, param, max_array_size)
|
503
|
+
end
|
504
|
+
|
505
|
+
def define_columns
|
506
|
+
# http://docs.oracle.com/cd/E11882_01/appdev.112/e10646/ociaahan.htm#sthref5494
|
507
|
+
num_cols = attr_get_ub4(18) # OCI_ATTR_PARAM_COUNT(18)
|
508
|
+
1.upto(num_cols) do |i|
|
509
|
+
parm = __paramGet(i)
|
510
|
+
define_one_column(i, parm) unless @define_handles[i - 1]
|
511
|
+
@column_metadata[i - 1] = parm
|
512
|
+
end
|
513
|
+
num_cols
|
514
|
+
end
|
515
|
+
|
516
|
+
def define_one_column(pos, param)
|
517
|
+
bindobj = make_bind_object(param)
|
518
|
+
__define(pos, bindobj)
|
519
|
+
if old = @define_handles[pos - 1]
|
520
|
+
old.send(:free)
|
521
|
+
end
|
522
|
+
@define_handles[pos - 1] = bindobj
|
523
|
+
end
|
524
|
+
|
525
|
+
def bind_params(*bindvars)
|
526
|
+
bindvars.each_with_index do |val, i|
|
527
|
+
if val.is_a? Array
|
528
|
+
bind_param(i + 1, val[0], val[1], val[2])
|
529
|
+
else
|
530
|
+
bind_param(i + 1, val)
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
def fetch_one_row_as_array
|
536
|
+
if __fetch(@con)
|
537
|
+
@define_handles.collect do |handle|
|
538
|
+
handle.send(:get_data)
|
539
|
+
end
|
540
|
+
else
|
541
|
+
nil
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
def fetch_one_row_as_hash
|
546
|
+
if __fetch(@con)
|
547
|
+
ret = {}
|
548
|
+
get_col_names.each_with_index do |name, idx|
|
549
|
+
ret[name] = @define_handles[idx].send(:get_data)
|
550
|
+
end
|
551
|
+
ret
|
552
|
+
else
|
553
|
+
nil
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
def free_bind_handles
|
558
|
+
@bind_handles.each_value do |val|
|
559
|
+
val.send(:free)
|
560
|
+
end
|
561
|
+
@bind_handles.clear
|
562
|
+
end
|
563
|
+
end
|
564
|
+
end
|