unclebilly-activerecord-oracle_enhanced-adapter 1.2.4

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 (38) hide show
  1. data/History.txt +165 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +32 -0
  4. data/README.rdoc +75 -0
  5. data/Rakefile +49 -0
  6. data/VERSION +1 -0
  7. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  8. data/lib/active_record/connection_adapters/oracle_enhanced.rake +51 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1723 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +121 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +64 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +369 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +396 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +164 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_reserved_words.rb +126 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +177 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +214 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +224 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +11 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_virtual_column.rb +35 -0
  24. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +610 -0
  25. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_structure_dumper_spec.rb +266 -0
  26. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +206 -0
  27. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +40 -0
  28. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +107 -0
  29. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +984 -0
  30. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +67 -0
  31. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +93 -0
  32. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +370 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +268 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_schema_spec.rb +761 -0
  36. data/spec/spec.opts +6 -0
  37. data/spec/spec_helper.rb +130 -0
  38. metadata +149 -0
@@ -0,0 +1,121 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ # interface independent methods
4
+ class OracleEnhancedConnection #:nodoc:
5
+
6
+ def self.create(config)
7
+ case ORACLE_ENHANCED_CONNECTION
8
+ when :oci
9
+ OracleEnhancedOCIConnection.new(config)
10
+ when :jdbc
11
+ OracleEnhancedJDBCConnection.new(config)
12
+ else
13
+ nil
14
+ end
15
+ end
16
+
17
+ attr_reader :raw_connection
18
+
19
+ # Oracle column names by default are case-insensitive, but treated as upcase;
20
+ # for neatness, we'll downcase within Rails. EXCEPT that folks CAN quote
21
+ # their column names when creating Oracle tables, which makes then case-sensitive.
22
+ # I don't know anybody who does this, but we'll handle the theoretical case of a
23
+ # camelCase column name. I imagine other dbs handle this different, since there's a
24
+ # unit test that's currently failing test_oci.
25
+ def oracle_downcase(column_name)
26
+ return nil if column_name.nil?
27
+ column_name =~ /[a-z]/ ? column_name : column_name.downcase
28
+ end
29
+
30
+ # Used always by JDBC connection as well by OCI connection when describing tables over database link
31
+ def describe(name)
32
+ name = name.to_s
33
+ if name.include?('@')
34
+ name, db_link = name.split('@')
35
+ default_owner = select_value("SELECT username FROM all_db_links WHERE db_link = '#{db_link.upcase}'")
36
+ db_link = "@#{db_link}"
37
+ else
38
+ db_link = nil
39
+ default_owner = @owner
40
+ end
41
+ real_name = OracleEnhancedAdapter.valid_table_name?(name) ? name.upcase : name
42
+ if real_name.include?('.')
43
+ table_owner, table_name = real_name.split('.')
44
+ else
45
+ table_owner, table_name = default_owner, real_name
46
+ end
47
+ sql = <<-SQL
48
+ SELECT owner, table_name, 'TABLE' name_type
49
+ FROM all_tables#{db_link}
50
+ WHERE owner = '#{table_owner}'
51
+ AND table_name = '#{table_name}'
52
+ UNION ALL
53
+ SELECT owner, view_name table_name, 'VIEW' name_type
54
+ FROM all_views#{db_link}
55
+ WHERE owner = '#{table_owner}'
56
+ AND view_name = '#{table_name}'
57
+ UNION ALL
58
+ SELECT table_owner, DECODE(db_link, NULL, table_name, table_name||'@'||db_link), 'SYNONYM' name_type
59
+ FROM all_synonyms#{db_link}
60
+ WHERE owner = '#{table_owner}'
61
+ AND synonym_name = '#{table_name}'
62
+ UNION ALL
63
+ SELECT table_owner, DECODE(db_link, NULL, table_name, table_name||'@'||db_link), 'SYNONYM' name_type
64
+ FROM all_synonyms#{db_link}
65
+ WHERE owner = 'PUBLIC'
66
+ AND synonym_name = '#{real_name}'
67
+ SQL
68
+ if result = select_one(sql)
69
+ case result['name_type']
70
+ when 'SYNONYM'
71
+ describe("#{result['owner'] && "#{result['owner']}."}#{result['table_name']}#{db_link}")
72
+ else
73
+ db_link ? [result['owner'], result['table_name'], db_link] : [result['owner'], result['table_name']]
74
+ end
75
+ else
76
+ raise OracleEnhancedConnectionException, %Q{"DESC #{name}" failed; does it exist?}
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ # Returns a record hash with the column names as keys and column values
83
+ # as values.
84
+ def select_one(sql)
85
+ result = select(sql)
86
+ result.first if result
87
+ end
88
+
89
+ # Returns a single value from a record
90
+ def select_value(sql)
91
+ if result = select_one(sql)
92
+ result.values.first
93
+ end
94
+ end
95
+
96
+ # Returns an array of the values of the first column in a select:
97
+ # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
98
+ def select_values(sql)
99
+ result = select(sql)
100
+ result.map { |r| r.values.first }
101
+ end
102
+
103
+ end
104
+
105
+ class OracleEnhancedConnectionException < StandardError #:nodoc:
106
+ end
107
+
108
+ end
109
+ end
110
+
111
+ # if MRI or YARV
112
+ if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
113
+ ORACLE_ENHANCED_CONNECTION = :oci
114
+ require 'active_record/connection_adapters/oracle_enhanced_oci_connection'
115
+ # if JRuby
116
+ elsif RUBY_ENGINE == 'jruby'
117
+ ORACLE_ENHANCED_CONNECTION = :jdbc
118
+ require 'active_record/connection_adapters/oracle_enhanced_jdbc_connection'
119
+ else
120
+ raise "Unsupported Ruby engine #{RUBY_ENGINE}"
121
+ end
@@ -0,0 +1,64 @@
1
+ require "bigdecimal"
2
+ unless BigDecimal.instance_methods.include?("to_d")
3
+ BigDecimal.class_eval do
4
+ def to_d #:nodoc:
5
+ self
6
+ end
7
+ end
8
+ end
9
+
10
+ unless Bignum.instance_methods.include?("to_d")
11
+ Bignum.class_eval do
12
+ def to_d #:nodoc:
13
+ BigDecimal.new(self.to_s)
14
+ end
15
+ end
16
+ end
17
+
18
+ unless Fixnum.instance_methods.include?("to_d")
19
+ Fixnum.class_eval do
20
+ def to_d #:nodoc:
21
+ BigDecimal.new(self.to_s)
22
+ end
23
+ end
24
+ end
25
+
26
+ # Add Unicode aware String#upcase and String#downcase methods when mb_chars method is called
27
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' && RUBY_VERSION >= '1.9'
28
+ begin
29
+ gem "unicode_utils", ">=1.0.0"
30
+ require "unicode_utils/upcase"
31
+ require "unicode_utils/downcase"
32
+
33
+ module ActiveRecord #:nodoc:
34
+ module ConnectionAdapters #:nodoc:
35
+ module OracleEnhancedUnicodeString #:nodoc:
36
+ def upcase #:nodoc:
37
+ UnicodeUtils.upcase(self)
38
+ end
39
+
40
+ def downcase #:nodoc:
41
+ UnicodeUtils.downcase(self)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ class String #:nodoc:
48
+ def mb_chars #:nodoc:
49
+ self.extend(ActiveRecord::ConnectionAdapters::OracleEnhancedUnicodeString)
50
+ self
51
+ end
52
+ end
53
+
54
+ rescue LoadError
55
+ warning_message = "WARNING: Please install unicode_utils gem to support Unicode aware upcase and downcase for String#mb_chars"
56
+ if defined?(RAILS_DEFAULT_LOGGER)
57
+ RAILS_DEFAULT_LOGGER.warn warning_message
58
+ else
59
+ STDERR.puts warning_message
60
+ end
61
+ end
62
+
63
+
64
+ 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 '' or empty text (CLOB) as NULL
18
+ # therefore need to convert empty string value to nil if old value is nil
19
+ elsif (column.type == :string || column.type == :text) && 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.instance_methods.include?('changed?')
36
+ ActiveRecord::Base.class_eval do
37
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedDirty::InstanceMethods
38
+ end
39
+ end
@@ -0,0 +1,369 @@
1
+ begin
2
+ require "java"
3
+ require "jruby"
4
+
5
+ # ojdbc14.jar file should be in JRUBY_HOME/lib or should be in ENV['PATH'] or load path
6
+
7
+ ojdbc_jar = "ojdbc14.jar"
8
+
9
+ unless ENV_JAVA['java.class.path'] =~ Regexp.new(ojdbc_jar)
10
+ # On Unix environment variable should be PATH, on Windows it is sometimes Path
11
+ env_path = ENV["PATH"] || ENV["Path"] || ''
12
+ if ojdbc_jar_path = env_path.split(/[:;]/).concat($LOAD_PATH).find{|d| File.exists?(File.join(d,ojdbc_jar))}
13
+ require File.join(ojdbc_jar_path,ojdbc_jar)
14
+ end
15
+ end
16
+
17
+ java.sql.DriverManager.registerDriver Java::oracle.jdbc.driver.OracleDriver.new
18
+
19
+ # set tns_admin property from TNS_ADMIN environment variable
20
+ if !java.lang.System.get_property("oracle.net.tns_admin") && ENV["TNS_ADMIN"]
21
+ java.lang.System.set_property("oracle.net.tns_admin", ENV["TNS_ADMIN"])
22
+ end
23
+
24
+ rescue LoadError, NameError
25
+ # JDBC driver is unavailable.
26
+ error_message = "ERROR: ActiveRecord oracle_enhanced adapter could not load Oracle JDBC driver. "+
27
+ "Please install ojdbc14.jar library."
28
+ if defined?(RAILS_DEFAULT_LOGGER)
29
+ RAILS_DEFAULT_LOGGER.error error_message
30
+ else
31
+ STDERR.puts error_message
32
+ end
33
+ raise LoadError
34
+ end
35
+
36
+
37
+ module ActiveRecord
38
+ module ConnectionAdapters
39
+
40
+ # JDBC database interface for JRuby
41
+ class OracleEnhancedJDBCConnection < OracleEnhancedConnection #:nodoc:
42
+
43
+ attr_accessor :active
44
+ alias :active? :active
45
+
46
+ attr_accessor :auto_retry
47
+ alias :auto_retry? :auto_retry
48
+ @auto_retry = false
49
+
50
+ def initialize(config)
51
+ @active = true
52
+ @config = config
53
+ new_connection(@config)
54
+ end
55
+
56
+ def new_connection(config)
57
+ username, password, database = config[:username].to_s, config[:password].to_s, config[:database].to_s
58
+ privilege = config[:privilege] && config[:privilege].to_s
59
+ host, port = config[:host], config[:port]
60
+
61
+ # connection using TNS alias
62
+ if database && !host && !config[:url] && ENV['TNS_ADMIN']
63
+ url = "jdbc:oracle:thin:@#{database || 'XE'}"
64
+ else
65
+ url = config[:url] || "jdbc:oracle:thin:@#{host || 'localhost'}:#{port || 1521}:#{database || 'XE'}"
66
+ end
67
+
68
+ prefetch_rows = config[:prefetch_rows] || 100
69
+ cursor_sharing = config[:cursor_sharing] || 'force'
70
+ # by default VARCHAR2 column size will be interpreted as max number of characters (and not bytes)
71
+ nls_length_semantics = config[:nls_length_semantics] || 'CHAR'
72
+ # get session time_zone from configuration or from TZ environment variable
73
+ time_zone = config[:time_zone] || ENV['TZ'] || java.util.TimeZone.default.getID
74
+
75
+ properties = java.util.Properties.new
76
+ properties.put("user", username)
77
+ properties.put("password", password)
78
+ properties.put("defaultRowPrefetch", "#{prefetch_rows}") if prefetch_rows
79
+ properties.put("internal_logon", privilege) if privilege
80
+
81
+ @raw_connection = java.sql.DriverManager.getConnection(url, properties)
82
+ exec %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
83
+ exec %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS:FF6'}
84
+ exec "alter session set cursor_sharing = #{cursor_sharing}"
85
+ exec "alter session set nls_length_semantics = '#{nls_length_semantics}'"
86
+ self.autocommit = true
87
+
88
+ # Set session time zone to current time zone
89
+ @raw_connection.setSessionTimeZone(time_zone)
90
+
91
+ # Set default number of rows to prefetch
92
+ # @raw_connection.setDefaultRowPrefetch(prefetch_rows) if prefetch_rows
93
+
94
+ # default schema owner
95
+ @owner = username.upcase
96
+
97
+ @raw_connection
98
+ end
99
+
100
+
101
+ def logoff
102
+ @active = false
103
+ @raw_connection.close
104
+ true
105
+ rescue
106
+ false
107
+ end
108
+
109
+ def commit
110
+ @raw_connection.commit
111
+ end
112
+
113
+ def rollback
114
+ @raw_connection.rollback
115
+ end
116
+
117
+ def autocommit?
118
+ @raw_connection.getAutoCommit
119
+ end
120
+
121
+ def autocommit=(value)
122
+ @raw_connection.setAutoCommit(value)
123
+ end
124
+
125
+ # Checks connection, returns true if active. Note that ping actively
126
+ # checks the connection, while #active? simply returns the last
127
+ # known state.
128
+ def ping
129
+ exec_no_retry("select 1 from dual")
130
+ @active = true
131
+ rescue NativeException => e
132
+ @active = false
133
+ if e.message =~ /^java\.sql\.SQLException/
134
+ raise OracleEnhancedConnectionException, e.message
135
+ else
136
+ raise
137
+ end
138
+ end
139
+
140
+ # Resets connection, by logging off and creating a new connection.
141
+ def reset!
142
+ logoff rescue nil
143
+ begin
144
+ new_connection(@config)
145
+ @active = true
146
+ rescue NativeException => e
147
+ @active = false
148
+ if e.message =~ /^java\.sql\.SQLException/
149
+ raise OracleEnhancedConnectionException, e.message
150
+ else
151
+ raise
152
+ end
153
+ end
154
+ end
155
+
156
+ # mark connection as dead if connection lost
157
+ def with_retry(&block)
158
+ should_retry = auto_retry? && autocommit?
159
+ begin
160
+ yield if block_given?
161
+ rescue NativeException => e
162
+ raise unless e.message =~ /^java\.sql\.SQLException: (Closed Connection|Io exception:|No more data to read from socket)/
163
+ @active = false
164
+ raise unless should_retry
165
+ should_retry = false
166
+ reset! rescue nil
167
+ retry
168
+ end
169
+ end
170
+
171
+ def exec(sql)
172
+ with_retry do
173
+ exec_no_retry(sql)
174
+ end
175
+ end
176
+
177
+ def exec_no_retry(sql)
178
+ case sql
179
+ when /\A\s*(UPDATE|INSERT|DELETE)/i
180
+ s = @raw_connection.prepareStatement(sql)
181
+ s.executeUpdate
182
+ # it is safer for CREATE and DROP statements not to use PreparedStatement
183
+ # as it does not allow creation of triggers with :NEW in their definition
184
+ when /\A\s*(CREATE|DROP)/i
185
+ s = @raw_connection.createStatement()
186
+ s.execute(sql)
187
+ true
188
+ else
189
+ s = @raw_connection.prepareStatement(sql)
190
+ s.execute
191
+ true
192
+ end
193
+ ensure
194
+ s.close rescue nil
195
+ end
196
+
197
+ def returning_clause(quoted_pk)
198
+ " RETURNING #{quoted_pk} INTO ?"
199
+ end
200
+
201
+ # execute sql with RETURNING ... INTO :insert_id
202
+ # and return :insert_id value
203
+ def exec_with_returning(sql)
204
+ with_retry do
205
+ begin
206
+ # it will always be INSERT statement
207
+
208
+ # TODO: need to investigate why PreparedStatement is giving strange exception "Protocol violation"
209
+ # s = @raw_connection.prepareStatement(sql)
210
+ # s.registerReturnParameter(1, ::Java::oracle.jdbc.OracleTypes::NUMBER)
211
+ # count = s.executeUpdate
212
+ # if count > 0
213
+ # rs = s.getReturnResultSet
214
+ # if rs.next
215
+ # # Assuming that primary key will not be larger as long max value
216
+ # insert_id = rs.getLong(1)
217
+ # rs.wasNull ? nil : insert_id
218
+ # else
219
+ # nil
220
+ # end
221
+ # else
222
+ # nil
223
+ # end
224
+
225
+ # Workaround with CallableStatement
226
+ s = @raw_connection.prepareCall("BEGIN #{sql}; END;")
227
+ s.registerOutParameter(1, java.sql.Types::BIGINT)
228
+ s.execute
229
+ insert_id = s.getLong(1)
230
+ s.wasNull ? nil : insert_id
231
+ ensure
232
+ # rs.close rescue nil
233
+ s.close rescue nil
234
+ end
235
+ end
236
+ end
237
+
238
+ def select(sql, name = nil, return_column_names = false)
239
+ with_retry do
240
+ select_no_retry(sql, name, return_column_names)
241
+ end
242
+ end
243
+
244
+ def select_no_retry(sql, name = nil, return_column_names = false)
245
+ stmt = @raw_connection.prepareStatement(sql)
246
+ rset = stmt.executeQuery
247
+
248
+ # Reuse the same hash for all rows
249
+ column_hash = {}
250
+
251
+ metadata = rset.getMetaData
252
+ column_count = metadata.getColumnCount
253
+
254
+ cols_types_index = (1..column_count).map do |i|
255
+ col_name = oracle_downcase(metadata.getColumnName(i))
256
+ next if col_name == 'raw_rnum_'
257
+ column_hash[col_name] = nil
258
+ [col_name, metadata.getColumnTypeName(i).to_sym, i]
259
+ end
260
+ cols_types_index.delete(nil)
261
+
262
+ rows = []
263
+ get_lob_value = !(name == 'Writable Large Object')
264
+
265
+ while rset.next
266
+ hash = column_hash.dup
267
+ cols_types_index.each do |col, column_type, i|
268
+ hash[col] = get_ruby_value_from_result_set(rset, i, column_type, get_lob_value)
269
+ end
270
+ rows << hash
271
+ end
272
+
273
+ return_column_names ? [rows, cols_types_index.map(&:first)] : rows
274
+ ensure
275
+ rset.close rescue nil
276
+ stmt.close rescue nil
277
+ end
278
+
279
+ def write_lob(lob, value, is_binary = false)
280
+ if is_binary
281
+ lob.setBytes(1, value.to_java_bytes)
282
+ else
283
+ lob.setString(1,value)
284
+ end
285
+ end
286
+
287
+ # Return NativeException / java.sql.SQLException error code
288
+ def error_code(exception)
289
+ exception.cause.getErrorCode
290
+ end
291
+
292
+ private
293
+
294
+ # def prepare_statement(sql)
295
+ # @raw_connection.prepareStatement(sql)
296
+ # end
297
+
298
+ # def prepare_call(sql, *bindvars)
299
+ # @raw_connection.prepareCall(sql)
300
+ # end
301
+
302
+ def get_ruby_value_from_result_set(rset, i, type_name, get_lob_value = true)
303
+ case type_name
304
+ when :NUMBER
305
+ # d = rset.getBigDecimal(i)
306
+ # if d.nil?
307
+ # nil
308
+ # elsif d.scale == 0
309
+ # d.toBigInteger+0
310
+ # else
311
+ # # Is there better way how to convert Java BigDecimal to Ruby BigDecimal?
312
+ # d.toString.to_d
313
+ # end
314
+ d = rset.getNUMBER(i)
315
+ if d.nil?
316
+ nil
317
+ elsif d.isInt
318
+ Integer(d.stringValue)
319
+ else
320
+ BigDecimal.new(d.stringValue)
321
+ end
322
+ when :VARCHAR2, :CHAR, :LONG
323
+ rset.getString(i)
324
+ when :DATE
325
+ if dt = rset.getDATE(i)
326
+ d = dt.dateValue
327
+ t = dt.timeValue
328
+ if OracleEnhancedAdapter.emulate_dates && t.hours == 0 && t.minutes == 0 && t.seconds == 0
329
+ Date.new(d.year + 1900, d.month + 1, d.date)
330
+ else
331
+ Time.send(Base.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
332
+ end
333
+ else
334
+ nil
335
+ end
336
+ when :TIMESTAMP, :TIMESTAMPTZ, :TIMESTAMPLTZ
337
+ ts = rset.getTimestamp(i)
338
+ ts && Time.send(Base.default_timezone, ts.year + 1900, ts.month + 1, ts.date, ts.hours, ts.minutes, ts.seconds,
339
+ ts.nanos / 1000)
340
+ when :CLOB
341
+ get_lob_value ? lob_to_ruby_value(rset.getClob(i)) : rset.getClob(i)
342
+ when :BLOB
343
+ get_lob_value ? lob_to_ruby_value(rset.getBlob(i)) : rset.getBlob(i)
344
+ else
345
+ nil
346
+ end
347
+ end
348
+
349
+ def lob_to_ruby_value(val)
350
+ case val
351
+ when ::Java::OracleSql::CLOB
352
+ if val.isEmptyLob
353
+ nil
354
+ else
355
+ val.getSubString(1, val.length)
356
+ end
357
+ when ::Java::OracleSql::BLOB
358
+ if val.isEmptyLob
359
+ nil
360
+ else
361
+ String.from_java_bytes(val.getBytes(1, val.length))
362
+ end
363
+ end
364
+ end
365
+
366
+ end
367
+
368
+ end
369
+ end