oracle_enhanced 1.2.5

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/.gitignore +10 -0
  2. data/History.txt +182 -0
  3. data/License.txt +20 -0
  4. data/Manifest.txt +32 -0
  5. data/README.rdoc +77 -0
  6. data/Rakefile +49 -0
  7. data/VERSION +1 -0
  8. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced.rake +51 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1661 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +121 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +64 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +393 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +389 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +163 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_reserved_words.rb +126 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +168 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +213 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +224 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +11 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  24. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +477 -0
  25. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_structure_dumper_spec.rb +267 -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 +203 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_schema_spec.rb +784 -0
  36. data/spec/spec.opts +6 -0
  37. data/spec/spec_helper.rb +114 -0
  38. metadata +140 -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,393 @@
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
+ raise LoadError, "ERROR: ActiveRecord oracle_enhanced adapter could not load Oracle JDBC driver. Please install ojdbc14.jar library."
27
+ end
28
+
29
+
30
+ module ActiveRecord
31
+ module ConnectionAdapters
32
+
33
+ # JDBC database interface for JRuby
34
+ class OracleEnhancedJDBCConnection < OracleEnhancedConnection #:nodoc:
35
+
36
+ attr_accessor :active
37
+ alias :active? :active
38
+
39
+ attr_accessor :auto_retry
40
+ alias :auto_retry? :auto_retry
41
+ @auto_retry = false
42
+
43
+ def initialize(config)
44
+ @active = true
45
+ @config = config
46
+ new_connection(@config)
47
+ end
48
+
49
+ # modified method to support JNDI connections
50
+ def new_connection(config)
51
+ username = nil
52
+
53
+ if config[:jndi]
54
+ jndi = config[:jndi].to_s
55
+ ctx = javax.naming.InitialContext.new
56
+ ds = nil
57
+
58
+ # tomcat needs first lookup method, oc4j (and maybe other application servers) need second method
59
+ begin
60
+ env = ctx.lookup('java:/comp/env')
61
+ ds = env.lookup(jndi)
62
+ rescue
63
+ ds = ctx.lookup(jndi)
64
+ end
65
+
66
+ # check if datasource supports pooled connections, otherwise use default
67
+ if ds.respond_to?(:pooled_connection)
68
+ @raw_connection = ds.pooled_connection
69
+ else
70
+ @raw_connection = ds.connection
71
+ end
72
+
73
+ config[:driver] ||= @raw_connection.meta_data.connection.java_class.name
74
+ username = @raw_connection.meta_data.user_name
75
+ else
76
+ username = config[:username].to_s
77
+ password, database = config[:password].to_s, config[:database].to_s
78
+ privilege = config[:privilege] && config[:privilege].to_s
79
+ host, port = config[:host], config[:port]
80
+
81
+ # connection using TNS alias
82
+ if database && !host && !config[:url] && ENV['TNS_ADMIN']
83
+ url = "jdbc:oracle:thin:@#{database || 'XE'}"
84
+ else
85
+ url = config[:url] || "jdbc:oracle:thin:@#{host || 'localhost'}:#{port || 1521}:#{database || 'XE'}"
86
+ end
87
+
88
+ prefetch_rows = config[:prefetch_rows] || 100
89
+ # get session time_zone from configuration or from TZ environment variable
90
+ time_zone = config[:time_zone] || ENV['TZ'] || java.util.TimeZone.default.getID
91
+
92
+ properties = java.util.Properties.new
93
+ properties.put("user", username)
94
+ properties.put("password", password)
95
+ properties.put("defaultRowPrefetch", "#{prefetch_rows}") if prefetch_rows
96
+ properties.put("internal_logon", privilege) if privilege
97
+
98
+ @raw_connection = java.sql.DriverManager.getConnection(url, properties)
99
+
100
+ # Set session time zone to current time zone
101
+ @raw_connection.setSessionTimeZone(time_zone)
102
+
103
+ # Set default number of rows to prefetch
104
+ # @raw_connection.setDefaultRowPrefetch(prefetch_rows) if prefetch_rows
105
+ end
106
+
107
+ # by default VARCHAR2 column size will be interpreted as max number of characters (and not bytes)
108
+ nls_length_semantics = config[:nls_length_semantics] || 'CHAR'
109
+ cursor_sharing = config[:cursor_sharing] || 'force'
110
+
111
+ # from here it remaings common for both connections types
112
+ exec %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
113
+ exec %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS:FF6'}
114
+ exec "alter session set cursor_sharing = #{cursor_sharing}"
115
+ exec "alter session set nls_length_semantics = '#{nls_length_semantics}'"
116
+ self.autocommit = true
117
+
118
+ # default schema owner
119
+ @owner = username.upcase unless username.nil?
120
+
121
+ @raw_connection
122
+ end
123
+
124
+
125
+ def logoff
126
+ @active = false
127
+ @raw_connection.close
128
+ true
129
+ rescue
130
+ false
131
+ end
132
+
133
+ def commit
134
+ @raw_connection.commit
135
+ end
136
+
137
+ def rollback
138
+ @raw_connection.rollback
139
+ end
140
+
141
+ def autocommit?
142
+ @raw_connection.getAutoCommit
143
+ end
144
+
145
+ def autocommit=(value)
146
+ @raw_connection.setAutoCommit(value)
147
+ end
148
+
149
+ # Checks connection, returns true if active. Note that ping actively
150
+ # checks the connection, while #active? simply returns the last
151
+ # known state.
152
+ def ping
153
+ exec_no_retry("select 1 from dual")
154
+ @active = true
155
+ rescue NativeException => e
156
+ @active = false
157
+ if e.message =~ /^java\.sql\.SQLException/
158
+ raise OracleEnhancedConnectionException, e.message
159
+ else
160
+ raise
161
+ end
162
+ end
163
+
164
+ # Resets connection, by logging off and creating a new connection.
165
+ def reset!
166
+ logoff rescue nil
167
+ begin
168
+ new_connection(@config)
169
+ @active = true
170
+ rescue NativeException => e
171
+ @active = false
172
+ if e.message =~ /^java\.sql\.SQLException/
173
+ raise OracleEnhancedConnectionException, e.message
174
+ else
175
+ raise
176
+ end
177
+ end
178
+ end
179
+
180
+ # mark connection as dead if connection lost
181
+ def with_retry(&block)
182
+ should_retry = auto_retry? && autocommit?
183
+ begin
184
+ yield if block_given?
185
+ rescue NativeException => e
186
+ raise unless e.message =~ /^java\.sql\.SQLException: (Closed Connection|Io exception:|No more data to read from socket)/
187
+ @active = false
188
+ raise unless should_retry
189
+ should_retry = false
190
+ reset! rescue nil
191
+ retry
192
+ end
193
+ end
194
+
195
+ def exec(sql)
196
+ with_retry do
197
+ exec_no_retry(sql)
198
+ end
199
+ end
200
+
201
+ def exec_no_retry(sql)
202
+ case sql
203
+ when /\A\s*(UPDATE|INSERT|DELETE)/i
204
+ s = @raw_connection.prepareStatement(sql)
205
+ s.executeUpdate
206
+ # it is safer for CREATE and DROP statements not to use PreparedStatement
207
+ # as it does not allow creation of triggers with :NEW in their definition
208
+ when /\A\s*(CREATE|DROP)/i
209
+ s = @raw_connection.createStatement()
210
+ s.execute(sql)
211
+ true
212
+ else
213
+ s = @raw_connection.prepareStatement(sql)
214
+ s.execute
215
+ true
216
+ end
217
+ ensure
218
+ s.close rescue nil
219
+ end
220
+
221
+ def returning_clause(quoted_pk)
222
+ " RETURNING #{quoted_pk} INTO ?"
223
+ end
224
+
225
+ # execute sql with RETURNING ... INTO :insert_id
226
+ # and return :insert_id value
227
+ def exec_with_returning(sql)
228
+ with_retry do
229
+ begin
230
+ # it will always be INSERT statement
231
+
232
+ # TODO: need to investigate why PreparedStatement is giving strange exception "Protocol violation"
233
+ # s = @raw_connection.prepareStatement(sql)
234
+ # s.registerReturnParameter(1, ::Java::oracle.jdbc.OracleTypes::NUMBER)
235
+ # count = s.executeUpdate
236
+ # if count > 0
237
+ # rs = s.getReturnResultSet
238
+ # if rs.next
239
+ # # Assuming that primary key will not be larger as long max value
240
+ # insert_id = rs.getLong(1)
241
+ # rs.wasNull ? nil : insert_id
242
+ # else
243
+ # nil
244
+ # end
245
+ # else
246
+ # nil
247
+ # end
248
+
249
+ # Workaround with CallableStatement
250
+ s = @raw_connection.prepareCall("BEGIN #{sql}; END;")
251
+ s.registerOutParameter(1, java.sql.Types::BIGINT)
252
+ s.execute
253
+ insert_id = s.getLong(1)
254
+ s.wasNull ? nil : insert_id
255
+ ensure
256
+ # rs.close rescue nil
257
+ s.close rescue nil
258
+ end
259
+ end
260
+ end
261
+
262
+ def select(sql, name = nil, return_column_names = false)
263
+ with_retry do
264
+ select_no_retry(sql, name, return_column_names)
265
+ end
266
+ end
267
+
268
+ def select_no_retry(sql, name = nil, return_column_names = false)
269
+ stmt = @raw_connection.prepareStatement(sql)
270
+ rset = stmt.executeQuery
271
+
272
+ # Reuse the same hash for all rows
273
+ column_hash = {}
274
+
275
+ metadata = rset.getMetaData
276
+ column_count = metadata.getColumnCount
277
+
278
+ cols_types_index = (1..column_count).map do |i|
279
+ col_name = oracle_downcase(metadata.getColumnName(i))
280
+ next if col_name == 'raw_rnum_'
281
+ column_hash[col_name] = nil
282
+ [col_name, metadata.getColumnTypeName(i).to_sym, i]
283
+ end
284
+ cols_types_index.delete(nil)
285
+
286
+ rows = []
287
+ get_lob_value = !(name == 'Writable Large Object')
288
+
289
+ while rset.next
290
+ hash = column_hash.dup
291
+ cols_types_index.each do |col, column_type, i|
292
+ hash[col] = get_ruby_value_from_result_set(rset, i, column_type, get_lob_value)
293
+ end
294
+ rows << hash
295
+ end
296
+
297
+ return_column_names ? [rows, cols_types_index.map(&:first)] : rows
298
+ ensure
299
+ rset.close rescue nil
300
+ stmt.close rescue nil
301
+ end
302
+
303
+ def write_lob(lob, value, is_binary = false)
304
+ if is_binary
305
+ lob.setBytes(1, value.to_java_bytes)
306
+ else
307
+ lob.setString(1,value)
308
+ end
309
+ end
310
+
311
+ # Return NativeException / java.sql.SQLException error code
312
+ def error_code(exception)
313
+ exception.cause.getErrorCode
314
+ end
315
+
316
+ private
317
+
318
+ # def prepare_statement(sql)
319
+ # @raw_connection.prepareStatement(sql)
320
+ # end
321
+
322
+ # def prepare_call(sql, *bindvars)
323
+ # @raw_connection.prepareCall(sql)
324
+ # end
325
+
326
+ def get_ruby_value_from_result_set(rset, i, type_name, get_lob_value = true)
327
+ case type_name
328
+ when :NUMBER
329
+ # d = rset.getBigDecimal(i)
330
+ # if d.nil?
331
+ # nil
332
+ # elsif d.scale == 0
333
+ # d.toBigInteger+0
334
+ # else
335
+ # # Is there better way how to convert Java BigDecimal to Ruby BigDecimal?
336
+ # d.toString.to_d
337
+ # end
338
+ d = rset.getNUMBER(i)
339
+ if d.nil?
340
+ nil
341
+ elsif d.isInt
342
+ Integer(d.stringValue)
343
+ else
344
+ BigDecimal.new(d.stringValue)
345
+ end
346
+ when :VARCHAR2, :CHAR, :LONG
347
+ rset.getString(i)
348
+ when :DATE
349
+ if dt = rset.getDATE(i)
350
+ d = dt.dateValue
351
+ t = dt.timeValue
352
+ if OracleEnhancedAdapter.emulate_dates && t.hours == 0 && t.minutes == 0 && t.seconds == 0
353
+ Date.new(d.year + 1900, d.month + 1, d.date)
354
+ else
355
+ Time.send(Base.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
356
+ end
357
+ else
358
+ nil
359
+ end
360
+ when :TIMESTAMP, :TIMESTAMPTZ, :TIMESTAMPLTZ
361
+ ts = rset.getTimestamp(i)
362
+ ts && Time.send(Base.default_timezone, ts.year + 1900, ts.month + 1, ts.date, ts.hours, ts.minutes, ts.seconds,
363
+ ts.nanos / 1000)
364
+ when :CLOB
365
+ get_lob_value ? lob_to_ruby_value(rset.getClob(i)) : rset.getClob(i)
366
+ when :BLOB
367
+ get_lob_value ? lob_to_ruby_value(rset.getBlob(i)) : rset.getBlob(i)
368
+ else
369
+ nil
370
+ end
371
+ end
372
+
373
+ def lob_to_ruby_value(val)
374
+ case val
375
+ when ::Java::OracleSql::CLOB
376
+ if val.isEmptyLob
377
+ nil
378
+ else
379
+ val.getSubString(1, val.length)
380
+ end
381
+ when ::Java::OracleSql::BLOB
382
+ if val.isEmptyLob
383
+ nil
384
+ else
385
+ String.from_java_bytes(val.getBytes(1, val.length))
386
+ end
387
+ end
388
+ end
389
+
390
+ end
391
+
392
+ end
393
+ end