ctreatma-activerecord-oracle_enhanced-adapter 1.4.1.1

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 (47) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +51 -0
  3. data/History.md +269 -0
  4. data/License.txt +20 -0
  5. data/README.md +378 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +46 -0
  8. data/VERSION +1 -0
  9. data/activerecord-oracle_enhanced-adapter.gemspec +130 -0
  10. data/ctreatma-activerecord-oracle_enhanced-adapter.gemspec +129 -0
  11. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1390 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +106 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +136 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +119 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +328 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +553 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +492 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +213 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +252 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +373 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +265 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +290 -0
  30. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  31. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  32. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +749 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +310 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +426 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +19 -0
  37. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +113 -0
  38. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +1330 -0
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +69 -0
  40. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +121 -0
  41. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  42. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +374 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +380 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1112 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +323 -0
  46. data/spec/spec_helper.rb +185 -0
  47. metadata +287 -0
@@ -0,0 +1,25 @@
1
+ require "bigdecimal"
2
+
3
+ unless BigDecimal.method_defined?(:to_d)
4
+ BigDecimal.class_eval do
5
+ def to_d #:nodoc:
6
+ self
7
+ end
8
+ end
9
+ end
10
+
11
+ unless Bignum.method_defined?(:to_d)
12
+ Bignum.class_eval do
13
+ def to_d #:nodoc:
14
+ BigDecimal.new(self.to_s)
15
+ end
16
+ end
17
+ end
18
+
19
+ unless Fixnum.method_defined?(:to_d)
20
+ Fixnum.class_eval do
21
+ def to_d #:nodoc:
22
+ BigDecimal.new(self.to_s)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveRecord #:nodoc:
2
+ module ConnectionAdapters #:nodoc:
3
+ module OracleEnhancedCpk #:nodoc:
4
+
5
+ # This mightn't be in Core, but count(distinct x,y) doesn't work for me.
6
+ # Return that not supported if composite_primary_keys gem is required.
7
+ def supports_count_distinct? #:nodoc:
8
+ @supports_count_distinct ||= ! defined?(CompositePrimaryKeys)
9
+ end
10
+
11
+ def concat(*columns) #:nodoc:
12
+ "(#{columns.join('||')})"
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+
19
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
20
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedCpk
21
+ end
@@ -0,0 +1,39 @@
1
+ module ActiveRecord #:nodoc:
2
+ module ConnectionAdapters #:nodoc:
3
+ module OracleEnhancedDirty #:nodoc:
4
+
5
+ module InstanceMethods #:nodoc:
6
+ private
7
+
8
+ def field_changed?(attr, old, value)
9
+ if column = column_for_attribute(attr)
10
+ # Added also :decimal type
11
+ if (column.type == :integer || column.type == :decimal) && column.null && (old.nil? || old == 0) && value.blank?
12
+ # For nullable integer columns, NULL gets stored in database for blank (i.e. '') values.
13
+ # Hence we don't record it as a change if the value changes from nil to ''.
14
+ # If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
15
+ # be typecast back to 0 (''.to_i => 0)
16
+ value = nil
17
+ # Oracle stores empty string '' as NULL
18
+ # therefore need to convert empty string value to nil if old value is nil
19
+ elsif column.type == :string && column.null && old.nil?
20
+ value = nil if value == ''
21
+ else
22
+ value = column.type_cast(value)
23
+ end
24
+ end
25
+
26
+ old != value
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+
35
+ if ActiveRecord::Base.method_defined?(:changed?)
36
+ ActiveRecord::Base.class_eval do
37
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedDirty::InstanceMethods
38
+ end
39
+ end
@@ -0,0 +1,553 @@
1
+ begin
2
+ require "java"
3
+ require "jruby"
4
+
5
+ # ojdbc6.jar or ojdbc5.jar file should be in JRUBY_HOME/lib or should be in ENV['PATH'] or load path
6
+
7
+ java_version = java.lang.System.getProperty("java.version")
8
+ ojdbc_jar = if java_version =~ /^1.5/
9
+ "ojdbc5.jar"
10
+ elsif java_version >= '1.6'
11
+ "ojdbc6.jar"
12
+ else
13
+ nil
14
+ end
15
+
16
+ unless ojdbc_jar.nil? || ENV_JAVA['java.class.path'] =~ Regexp.new(ojdbc_jar)
17
+ # On Unix environment variable should be PATH, on Windows it is sometimes Path
18
+ env_path = (ENV["PATH"] || ENV["Path"] || '').split(/[:;]/)
19
+ # Look for JDBC driver at first in lib subdirectory (application specific JDBC file version)
20
+ # then in Ruby load path and finally in environment PATH
21
+ if ojdbc_jar_path = ['./lib'].concat($LOAD_PATH).concat(env_path).find{|d| File.exists?(File.join(d,ojdbc_jar))}
22
+ require File.join(ojdbc_jar_path,ojdbc_jar)
23
+ end
24
+ end
25
+
26
+ java.sql.DriverManager.registerDriver Java::oracle.jdbc.OracleDriver.new
27
+
28
+ # set tns_admin property from TNS_ADMIN environment variable
29
+ if !java.lang.System.get_property("oracle.net.tns_admin") && ENV["TNS_ADMIN"]
30
+ java.lang.System.set_property("oracle.net.tns_admin", ENV["TNS_ADMIN"])
31
+ end
32
+
33
+ rescue LoadError, NameError
34
+ # JDBC driver is unavailable.
35
+ raise LoadError, "ERROR: ActiveRecord oracle_enhanced adapter could not load Oracle JDBC driver. Please install #{ojdbc_jar || "Oracle JDBC"} library."
36
+ end
37
+
38
+
39
+ module ActiveRecord
40
+ module ConnectionAdapters
41
+
42
+ # JDBC database interface for JRuby
43
+ class OracleEnhancedJDBCConnection < OracleEnhancedConnection #:nodoc:
44
+
45
+ attr_accessor :active
46
+ alias :active? :active
47
+
48
+ attr_accessor :auto_retry
49
+ alias :auto_retry? :auto_retry
50
+ @auto_retry = false
51
+
52
+ def initialize(config)
53
+ @active = true
54
+ @config = config
55
+ new_connection(@config)
56
+ end
57
+
58
+ # modified method to support JNDI connections
59
+ def new_connection(config)
60
+ username = nil
61
+
62
+ if config[:jndi]
63
+ jndi = config[:jndi].to_s
64
+ ctx = javax.naming.InitialContext.new
65
+ ds = nil
66
+
67
+ # tomcat needs first lookup method, oc4j (and maybe other application servers) need second method
68
+ begin
69
+ env = ctx.lookup('java:/comp/env')
70
+ ds = env.lookup(jndi)
71
+ rescue
72
+ ds = ctx.lookup(jndi)
73
+ end
74
+
75
+ # check if datasource supports pooled connections, otherwise use default
76
+ if ds.respond_to?(:pooled_connection)
77
+ @raw_connection = ds.pooled_connection
78
+ else
79
+ @raw_connection = ds.connection
80
+ end
81
+
82
+ # get Oracle JDBC connection when using DBCP in Tomcat or jBoss
83
+ if @raw_connection.respond_to?(:getInnermostDelegate)
84
+ @pooled_connection = @raw_connection
85
+ @raw_connection = @raw_connection.innermost_delegate
86
+ elsif @raw_connection.respond_to?(:getUnderlyingConnection)
87
+ @pooled_connection = @raw_connection
88
+ @raw_connection = @raw_connection.underlying_connection
89
+ end
90
+
91
+ config[:driver] ||= @raw_connection.meta_data.connection.java_class.name
92
+ username = @raw_connection.meta_data.user_name
93
+ else
94
+ # to_s needed if username, password or database is specified as number in database.yml file
95
+ username = config[:username] && config[:username].to_s
96
+ password = config[:password] && config[:password].to_s
97
+ database = config[:database] && config[:database].to_s
98
+ host, port = config[:host], config[:port]
99
+ privilege = config[:privilege] && config[:privilege].to_s
100
+
101
+ # connection using TNS alias
102
+ if database && !host && !config[:url] && ENV['TNS_ADMIN']
103
+ url = "jdbc:oracle:thin:@#{database || 'XE'}"
104
+ else
105
+ url = config[:url] || "jdbc:oracle:thin:@#{host || 'localhost'}:#{port || 1521}:#{database || 'XE'}"
106
+ end
107
+
108
+ prefetch_rows = config[:prefetch_rows] || 100
109
+ # get session time_zone from configuration or from TZ environment variable
110
+ time_zone = config[:time_zone] || ENV['TZ'] || java.util.TimeZone.default.getID
111
+
112
+ properties = java.util.Properties.new
113
+ properties.put("user", username)
114
+ properties.put("password", password)
115
+ properties.put("defaultRowPrefetch", "#{prefetch_rows}") if prefetch_rows
116
+ properties.put("internal_logon", privilege) if privilege
117
+
118
+ @raw_connection = java.sql.DriverManager.getConnection(url, properties)
119
+
120
+ # Set session time zone to current time zone
121
+ @raw_connection.setSessionTimeZone(time_zone)
122
+
123
+ # Set default number of rows to prefetch
124
+ # @raw_connection.setDefaultRowPrefetch(prefetch_rows) if prefetch_rows
125
+ end
126
+
127
+ cursor_sharing = config[:cursor_sharing] || 'force'
128
+ exec "alter session set cursor_sharing = #{cursor_sharing}"
129
+
130
+ # Initialize NLS parameters
131
+ OracleEnhancedAdapter::DEFAULT_NLS_PARAMETERS.each do |key, default_value|
132
+ value = config[key] || ENV[key.to_s.upcase] || default_value
133
+ if value
134
+ exec "alter session set #{key} = '#{value}'"
135
+ end
136
+ end
137
+
138
+ self.autocommit = true
139
+
140
+ # default schema owner
141
+ @owner = username.upcase unless username.nil?
142
+
143
+ @raw_connection
144
+ end
145
+
146
+ def logoff
147
+ @active = false
148
+ if defined?(@pooled_connection)
149
+ @pooled_connection.close
150
+ else
151
+ @raw_connection.close
152
+ end
153
+ true
154
+ rescue
155
+ false
156
+ end
157
+
158
+ def commit
159
+ @raw_connection.commit
160
+ end
161
+
162
+ def rollback
163
+ @raw_connection.rollback
164
+ end
165
+
166
+ def autocommit?
167
+ @raw_connection.getAutoCommit
168
+ end
169
+
170
+ def autocommit=(value)
171
+ @raw_connection.setAutoCommit(value)
172
+ end
173
+
174
+ # Checks connection, returns true if active. Note that ping actively
175
+ # checks the connection, while #active? simply returns the last
176
+ # known state.
177
+ def ping
178
+ exec_no_retry("select 1 from dual")
179
+ @active = true
180
+ rescue NativeException => e
181
+ @active = false
182
+ if e.message =~ /^java\.sql\.SQL(Recoverable)?Exception/
183
+ raise OracleEnhancedConnectionException, e.message
184
+ else
185
+ raise
186
+ end
187
+ end
188
+
189
+ # Resets connection, by logging off and creating a new connection.
190
+ def reset!
191
+ logoff rescue nil
192
+ begin
193
+ new_connection(@config)
194
+ @active = true
195
+ rescue NativeException => e
196
+ @active = false
197
+ if e.message =~ /^java\.sql\.SQL(Recoverable)?Exception/
198
+ raise OracleEnhancedConnectionException, e.message
199
+ else
200
+ raise
201
+ end
202
+ end
203
+ end
204
+
205
+ # mark connection as dead if connection lost
206
+ def with_retry(&block)
207
+ should_retry = auto_retry? && autocommit?
208
+ begin
209
+ yield if block_given?
210
+ rescue NativeException => e
211
+ raise unless e.message =~ /^java\.sql\.SQL(Recoverable)?Exception: (Closed Connection|Io exception:|No more data to read from socket|IO Error:)/
212
+ @active = false
213
+ raise unless should_retry
214
+ should_retry = false
215
+ reset! rescue nil
216
+ retry
217
+ end
218
+ end
219
+
220
+ def exec(sql)
221
+ with_retry do
222
+ exec_no_retry(sql)
223
+ end
224
+ end
225
+
226
+ def exec_no_retry(sql)
227
+ case sql
228
+ when /\A\s*(UPDATE|INSERT|DELETE)/i
229
+ s = @raw_connection.prepareStatement(sql)
230
+ s.executeUpdate
231
+ # it is safer for CREATE and DROP statements not to use PreparedStatement
232
+ # as it does not allow creation of triggers with :NEW in their definition
233
+ when /\A\s*(CREATE|DROP)/i
234
+ s = @raw_connection.createStatement()
235
+ # this disables SQL92 syntax processing of {...} which can result in statement execution errors
236
+ # if sql contains {...} in strings or comments
237
+ s.setEscapeProcessing(false)
238
+ s.execute(sql)
239
+ true
240
+ else
241
+ s = @raw_connection.prepareStatement(sql)
242
+ s.execute
243
+ true
244
+ end
245
+ ensure
246
+ s.close rescue nil
247
+ end
248
+
249
+ def returning_clause(quoted_pk)
250
+ " RETURNING #{quoted_pk} INTO ?"
251
+ end
252
+
253
+ # execute sql with RETURNING ... INTO :insert_id
254
+ # and return :insert_id value
255
+ def exec_with_returning(sql)
256
+ with_retry do
257
+ begin
258
+ # it will always be INSERT statement
259
+
260
+ # TODO: need to investigate why PreparedStatement is giving strange exception "Protocol violation"
261
+ # s = @raw_connection.prepareStatement(sql)
262
+ # s.registerReturnParameter(1, ::Java::oracle.jdbc.OracleTypes::NUMBER)
263
+ # count = s.executeUpdate
264
+ # if count > 0
265
+ # rs = s.getReturnResultSet
266
+ # if rs.next
267
+ # # Assuming that primary key will not be larger as long max value
268
+ # insert_id = rs.getLong(1)
269
+ # rs.wasNull ? nil : insert_id
270
+ # else
271
+ # nil
272
+ # end
273
+ # else
274
+ # nil
275
+ # end
276
+
277
+ # Workaround with CallableStatement
278
+ s = @raw_connection.prepareCall("BEGIN #{sql}; END;")
279
+ s.registerOutParameter(1, java.sql.Types::BIGINT)
280
+ s.execute
281
+ insert_id = s.getLong(1)
282
+ s.wasNull ? nil : insert_id
283
+ ensure
284
+ # rs.close rescue nil
285
+ s.close rescue nil
286
+ end
287
+ end
288
+ end
289
+
290
+ def prepare(sql)
291
+ Cursor.new(self, @raw_connection.prepareStatement(sql))
292
+ end
293
+
294
+ class Cursor
295
+ def initialize(connection, raw_statement)
296
+ @connection = connection
297
+ @raw_statement = raw_statement
298
+ end
299
+
300
+ def bind_param(position, value, col_type = nil)
301
+ java_value = ruby_to_java_value(value, col_type)
302
+ case value
303
+ when Integer
304
+ @raw_statement.setLong(position, java_value)
305
+ when Float
306
+ @raw_statement.setFloat(position, java_value)
307
+ when BigDecimal
308
+ @raw_statement.setBigDecimal(position, java_value)
309
+ when String
310
+ case col_type
311
+ when :text
312
+ @raw_statement.setClob(position, java_value)
313
+ when :binary
314
+ @raw_statement.setBlob(position, java_value)
315
+ when :raw
316
+ @raw_statement.setString(position, OracleEnhancedAdapter.encode_raw(java_value))
317
+ when :decimal
318
+ @raw_statement.setBigDecimal(position, java_value)
319
+ else
320
+ @raw_statement.setString(position, java_value)
321
+ end
322
+ when Date, DateTime
323
+ @raw_statement.setDATE(position, java_value)
324
+ when Time
325
+ @raw_statement.setTimestamp(position, java_value)
326
+ when NilClass
327
+ # TODO: currently nil is always bound as NULL with VARCHAR type.
328
+ # When nils will actually be used by ActiveRecord as bound parameters
329
+ # then need to pass actual column type.
330
+ @raw_statement.setNull(position, java.sql.Types::VARCHAR)
331
+ else
332
+ raise ArgumentError, "Don't know how to bind variable with type #{value.class}"
333
+ end
334
+ end
335
+
336
+ def bind_returning_param(position, bind_type)
337
+ @returning_positions ||= []
338
+ @returning_positions << position
339
+ if bind_type == Integer
340
+ @raw_statement.registerReturnParameter(position, java.sql.Types::BIGINT)
341
+ end
342
+ end
343
+
344
+ def exec
345
+ @raw_result_set = @raw_statement.executeQuery
346
+ true
347
+ end
348
+
349
+ def exec_update
350
+ @raw_statement.executeUpdate
351
+ end
352
+
353
+ def metadata
354
+ @metadata ||= @raw_result_set.getMetaData
355
+ end
356
+
357
+ def column_types
358
+ @column_types ||= (1..metadata.getColumnCount).map{|i| metadata.getColumnTypeName(i).to_sym}
359
+ end
360
+
361
+ def column_names
362
+ @column_names ||= (1..metadata.getColumnCount).map{|i| metadata.getColumnName(i)}
363
+ end
364
+ alias :get_col_names :column_names
365
+
366
+ def fetch(options={})
367
+ if @raw_result_set.next
368
+ get_lob_value = options[:get_lob_value]
369
+ row_values = []
370
+ column_types.each_with_index do |column_type, i|
371
+ row_values <<
372
+ @connection.get_ruby_value_from_result_set(@raw_result_set, i+1, column_type, get_lob_value)
373
+ end
374
+ row_values
375
+ else
376
+ @raw_result_set.close
377
+ nil
378
+ end
379
+ end
380
+
381
+ def get_returning_param(position, type)
382
+ rs_position = @returning_positions.index(position) + 1
383
+ rs = @raw_statement.getReturnResultSet
384
+ if rs.next
385
+ # Assuming that primary key will not be larger as long max value
386
+ returning_id = rs.getLong(rs_position)
387
+ rs.wasNull ? nil : returning_id
388
+ else
389
+ nil
390
+ end
391
+ end
392
+
393
+ def close
394
+ @raw_statement.close
395
+ end
396
+
397
+ private
398
+
399
+ def ruby_to_java_value(value, col_type = nil)
400
+ case value
401
+ when Fixnum, Float
402
+ value
403
+ when String
404
+ case col_type
405
+ when :text
406
+ clob = Java::OracleSql::CLOB.createTemporary(@connection.raw_connection, false, Java::OracleSql::CLOB::DURATION_SESSION)
407
+ clob.setString(1, value)
408
+ clob
409
+ when :binary
410
+ blob = Java::OracleSql::BLOB.createTemporary(@connection.raw_connection, false, Java::OracleSql::BLOB::DURATION_SESSION)
411
+ blob.setBytes(1, value.to_java_bytes)
412
+ blob
413
+ when :decimal
414
+ java.math.BigDecimal.new(value.to_s)
415
+ else
416
+ value
417
+ end
418
+ when BigDecimal
419
+ java.math.BigDecimal.new(value.to_s)
420
+ when Date, DateTime
421
+ Java::oracle.sql.DATE.new(value.strftime("%Y-%m-%d %H:%M:%S"))
422
+ when Time
423
+ Java::java.sql.Timestamp.new(value.year-1900, value.month-1, value.day, value.hour, value.min, value.sec, value.usec * 1000)
424
+ else
425
+ value
426
+ end
427
+ end
428
+
429
+ end
430
+
431
+ def select(sql, name = nil, return_column_names = false)
432
+ with_retry do
433
+ select_no_retry(sql, name, return_column_names)
434
+ end
435
+ end
436
+
437
+ def select_no_retry(sql, name = nil, return_column_names = false)
438
+ stmt = @raw_connection.prepareStatement(sql)
439
+ rset = stmt.executeQuery
440
+
441
+ # Reuse the same hash for all rows
442
+ column_hash = {}
443
+
444
+ metadata = rset.getMetaData
445
+ column_count = metadata.getColumnCount
446
+
447
+ cols_types_index = (1..column_count).map do |i|
448
+ col_name = oracle_downcase(metadata.getColumnName(i))
449
+ next if col_name == 'raw_rnum_'
450
+ column_hash[col_name] = nil
451
+ [col_name, metadata.getColumnTypeName(i).to_sym, i]
452
+ end
453
+ cols_types_index.delete(nil)
454
+
455
+ rows = []
456
+ get_lob_value = !(name == 'Writable Large Object')
457
+
458
+ while rset.next
459
+ hash = column_hash.dup
460
+ cols_types_index.each do |col, column_type, i|
461
+ hash[col] = get_ruby_value_from_result_set(rset, i, column_type, get_lob_value)
462
+ end
463
+ rows << hash
464
+ end
465
+
466
+ return_column_names ? [rows, cols_types_index.map(&:first)] : rows
467
+ ensure
468
+ rset.close rescue nil
469
+ stmt.close rescue nil
470
+ end
471
+
472
+ def write_lob(lob, value, is_binary = false)
473
+ if is_binary
474
+ lob.setBytes(1, value.to_java_bytes)
475
+ else
476
+ lob.setString(1,value)
477
+ end
478
+ end
479
+
480
+ # Return NativeException / java.sql.SQLException error code
481
+ def error_code(exception)
482
+ case exception
483
+ when NativeException
484
+ exception.cause.getErrorCode
485
+ else
486
+ nil
487
+ end
488
+ end
489
+
490
+ def get_ruby_value_from_result_set(rset, i, type_name, get_lob_value = true)
491
+ case type_name
492
+ when :NUMBER
493
+ d = rset.getNUMBER(i)
494
+ if d.nil?
495
+ nil
496
+ elsif d.isInt
497
+ Integer(d.stringValue)
498
+ else
499
+ BigDecimal.new(d.stringValue)
500
+ end
501
+ when :VARCHAR2, :CHAR, :LONG, :NVARCHAR2, :NCHAR
502
+ rset.getString(i)
503
+ when :DATE
504
+ if dt = rset.getDATE(i)
505
+ d = dt.dateValue
506
+ t = dt.timeValue
507
+ if OracleEnhancedAdapter.emulate_dates && t.hours == 0 && t.minutes == 0 && t.seconds == 0
508
+ Date.new(d.year + 1900, d.month + 1, d.date)
509
+ else
510
+ Time.send(Base.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
511
+ end
512
+ else
513
+ nil
514
+ end
515
+ when :TIMESTAMP, :TIMESTAMPTZ, :TIMESTAMPLTZ, :"TIMESTAMP WITH TIME ZONE", :"TIMESTAMP WITH LOCAL TIME ZONE"
516
+ ts = rset.getTimestamp(i)
517
+ ts && Time.send(Base.default_timezone, ts.year + 1900, ts.month + 1, ts.date, ts.hours, ts.minutes, ts.seconds,
518
+ ts.nanos / 1000)
519
+ when :CLOB
520
+ get_lob_value ? lob_to_ruby_value(rset.getClob(i)) : rset.getClob(i)
521
+ when :BLOB
522
+ get_lob_value ? lob_to_ruby_value(rset.getBlob(i)) : rset.getBlob(i)
523
+ when :RAW
524
+ raw_value = rset.getRAW(i)
525
+ raw_value && raw_value.getBytes.to_a.pack('C*')
526
+ else
527
+ nil
528
+ end
529
+ end
530
+
531
+ private
532
+
533
+ def lob_to_ruby_value(val)
534
+ case val
535
+ when ::Java::OracleSql::CLOB
536
+ if val.isEmptyLob
537
+ nil
538
+ else
539
+ val.getSubString(1, val.length)
540
+ end
541
+ when ::Java::OracleSql::BLOB
542
+ if val.isEmptyLob
543
+ nil
544
+ else
545
+ String.from_java_bytes(val.getBytes(1, val.length))
546
+ end
547
+ end
548
+ end
549
+
550
+ end
551
+
552
+ end
553
+ end