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.
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,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
@@ -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