activerecord-oracle_enhanced-adapter 5.2.8 → 7.0.3

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +390 -21
  3. data/README.md +35 -8
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
  6. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +3 -3
  7. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +42 -37
  8. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +59 -60
  9. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +5 -10
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +86 -81
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +9 -10
  12. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +1 -2
  13. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +37 -16
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -1
  15. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +5 -6
  16. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +58 -49
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +1 -1
  18. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +6 -7
  19. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +75 -51
  20. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +13 -14
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +14 -4
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +27 -24
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +156 -155
  24. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +103 -90
  25. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +3 -2
  26. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +261 -161
  27. data/lib/active_record/type/oracle_enhanced/boolean.rb +0 -1
  28. data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
  29. data/lib/active_record/type/oracle_enhanced/integer.rb +0 -1
  30. data/lib/arel/visitors/oracle.rb +221 -0
  31. data/lib/arel/visitors/oracle12.rb +128 -0
  32. data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +0 -2
  33. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +78 -26
  34. data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +7 -15
  35. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +5 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +17 -17
  37. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +7 -10
  38. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +0 -15
  39. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +33 -36
  40. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +77 -258
  41. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +38 -39
  42. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +273 -85
  43. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +7 -8
  44. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +2 -4
  45. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +43 -0
  46. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  47. data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
  48. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +1 -1
  49. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +2 -2
  50. data/spec/active_record/oracle_enhanced/type/json_spec.rb +0 -1
  51. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +6 -5
  52. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +2 -4
  53. data/spec/spec_config.yaml.template +2 -2
  54. data/spec/spec_helper.rb +13 -2
  55. metadata +52 -30
  56. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +0 -28
@@ -17,21 +17,20 @@ module ActiveRecord
17
17
  print "Please provide the SYSTEM password for your Oracle installation (set ORACLE_SYSTEM_PASSWORD to avoid this prompt)\n>"
18
18
  $stdin.gets.strip
19
19
  }
20
- establish_connection(@config.merge("username" => "SYSTEM", "password" => system_password))
20
+ establish_connection(@config.merge(username: "SYSTEM", password: system_password))
21
21
  begin
22
- connection.execute "CREATE USER #{@config['username']} IDENTIFIED BY #{@config['password']}"
22
+ connection.execute "CREATE USER #{@config[:username]} IDENTIFIED BY #{@config[:password]}"
23
23
  rescue => e
24
- if e.message =~ /ORA-01920/ # user name conflicts with another user or role name
25
- connection.execute "ALTER USER #{@config['username']} IDENTIFIED BY #{@config['password']}"
24
+ if /ORA-01920/.match?(e.message) # user name conflicts with another user or role name
25
+ connection.execute "ALTER USER #{@config[:username]} IDENTIFIED BY #{@config[:password]}"
26
26
  else
27
27
  raise e
28
28
  end
29
29
  end
30
- connection.execute "GRANT unlimited tablespace TO #{@config['username']}"
31
- connection.execute "GRANT create session TO #{@config['username']}"
32
- connection.execute "GRANT create table TO #{@config['username']}"
33
- connection.execute "GRANT create view TO #{@config['username']}"
34
- connection.execute "GRANT create sequence TO #{@config['username']}"
30
+
31
+ OracleEnhancedAdapter.permissions.each do |permission|
32
+ connection.execute "GRANT #{permission} TO #{@config[:username]}"
33
+ end
35
34
  end
36
35
 
37
36
  def drop
@@ -47,7 +46,7 @@ module ActiveRecord
47
46
  def structure_dump(filename, extra_flags)
48
47
  establish_connection(@config)
49
48
  File.open(filename, "w:utf-8") { |f| f << connection.structure_dump }
50
- if @config["structure_dump"] == "db_stored_code"
49
+ if @config[:structure_dump] == "db_stored_code"
51
50
  File.open(filename, "a") { |f| f << connection.structure_dump_db_stored_code }
52
51
  end
53
52
  end
@@ -31,8 +31,7 @@ module ActiveRecord
31
31
  end
32
32
 
33
33
  private
34
-
35
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
34
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false)
36
35
  super
37
36
  ensure
38
37
  log_dbms_output if dbms_output_enabled?
@@ -16,9 +16,10 @@ begin
16
16
  # Oracle 11g client ojdbc6.jar is also compatible with Java 1.7
17
17
  # Oracle 12c Release 1 client provides ojdbc7.jar
18
18
  # Oracle 12c Release 2 client provides ojdbc8.jar
19
- ojdbc_jars = %w(ojdbc8.jar ojdbc7.jar ojdbc6.jar)
19
+ # Oracle 21c provides ojdbc11.jar for Java 11 and above
20
+ ojdbc_jars = %w(ojdbc11.jar ojdbc8.jar ojdbc7.jar ojdbc6.jar)
20
21
 
21
- if ENV_JAVA["java.class.path"] !~ Regexp.new(ojdbc_jars.join("|"))
22
+ if !ENV_JAVA["java.class.path"]&.match?(Regexp.new(ojdbc_jars.join("|")))
22
23
  # On Unix environment variable should be PATH, on Windows it is sometimes Path
23
24
  env_path = (ENV["PATH"] || ENV["Path"] || "").split(File::PATH_SEPARATOR)
24
25
  # Look for JDBC driver at first in lib subdirectory (application specific JDBC file version)
@@ -26,7 +27,7 @@ begin
26
27
  ["./lib"].concat($LOAD_PATH).concat(env_path).detect do |dir|
27
28
  # check any compatible JDBC driver in the priority order
28
29
  ojdbc_jars.any? do |ojdbc_jar|
29
- if File.exists?(file_path = File.join(dir, ojdbc_jar))
30
+ if File.exist?(file_path = File.join(dir, ojdbc_jar))
30
31
  require file_path
31
32
  true
32
33
  end
@@ -42,16 +43,16 @@ begin
42
43
  java.lang.System.set_property("oracle.net.tns_admin", ENV["TNS_ADMIN"])
43
44
  end
44
45
 
45
- rescue LoadError, NameError
46
+ rescue LoadError, NameError => e
46
47
  # JDBC driver is unavailable.
47
- raise LoadError, "ERROR: ActiveRecord oracle_enhanced adapter could not load Oracle JDBC driver. Please install #{ojdbc_jars.join(' or ') } library."
48
+ raise LoadError, "ERROR: ActiveRecord oracle_enhanced adapter could not load Oracle JDBC driver. Please install #{ojdbc_jars.join(' or ') } library.\n#{e.class}:#{e.message}"
48
49
  end
49
50
 
50
51
  module ActiveRecord
51
52
  module ConnectionAdapters
52
53
  # JDBC database interface for JRuby
53
54
  module OracleEnhanced
54
- class JDBCConnection < OracleEnhanced::Connection #:nodoc:
55
+ class JDBCConnection < OracleEnhanced::Connection # :nodoc:
55
56
  attr_accessor :active
56
57
  alias :active? :active
57
58
 
@@ -98,6 +99,8 @@ module ActiveRecord
98
99
  @raw_connection = @raw_connection.underlying_connection
99
100
  end
100
101
 
102
+ # Workaround FrozenError (can't modify frozen Hash):
103
+ config = config.dup
101
104
  config[:driver] ||= @raw_connection.meta_data.connection.java_class.name
102
105
  username = @raw_connection.meta_data.user_name
103
106
  else
@@ -113,11 +116,11 @@ module ActiveRecord
113
116
  if database && (using_tns_alias || host == "connection-string")
114
117
  url = "jdbc:oracle:thin:@#{database}"
115
118
  else
116
- unless database.match(/^(\:|\/)/)
119
+ unless database.match?(/^(:|\/)/)
117
120
  # assume database is a SID if no colon or slash are supplied (backward-compatibility)
118
- database = ":#{database}"
121
+ database = "/#{database}"
119
122
  end
120
- url = config[:url] || "jdbc:oracle:thin:@#{host || 'localhost'}:#{port || 1521}#{database}"
123
+ url = config[:url] || "jdbc:oracle:thin:@//#{host || 'localhost'}:#{port || 1521}#{database}"
121
124
  end
122
125
 
123
126
  prefetch_rows = config[:prefetch_rows] || 100
@@ -125,6 +128,8 @@ module ActiveRecord
125
128
  time_zone = config[:time_zone] || ENV["TZ"] || java.util.TimeZone.default.getID
126
129
 
127
130
  properties = java.util.Properties.new
131
+ raise "username not set" unless username
132
+ raise "password not set" unless password
128
133
  properties.put("user", username)
129
134
  properties.put("password", password)
130
135
  properties.put("defaultRowPrefetch", "#{prefetch_rows}") if prefetch_rows
@@ -140,12 +145,18 @@ module ActiveRecord
140
145
  end
141
146
 
142
147
  # Set session time zone to current time zone
143
- if ActiveRecord::Base.default_timezone == :local
148
+ if ActiveRecord.default_timezone == :local
144
149
  @raw_connection.setSessionTimeZone(time_zone)
145
- elsif ActiveRecord::Base.default_timezone == :utc
150
+ elsif ActiveRecord.default_timezone == :utc
146
151
  @raw_connection.setSessionTimeZone("UTC")
147
152
  end
148
153
 
154
+ if config[:jdbc_statement_cache_size]
155
+ raise "Integer value expected for :jdbc_statement_cache_size" unless config[:jdbc_statement_cache_size].instance_of? Integer
156
+ @raw_connection.setImplicitCachingEnabled(true)
157
+ @raw_connection.setStatementCacheSize(config[:jdbc_statement_cache_size])
158
+ end
159
+
149
160
  # Set default number of rows to prefetch
150
161
  # @raw_connection.setDefaultRowPrefetch(prefetch_rows) if prefetch_rows
151
162
  end
@@ -161,6 +172,10 @@ module ActiveRecord
161
172
  end
162
173
  end
163
174
 
175
+ OracleEnhancedAdapter::FIXED_NLS_PARAMETERS.each do |key, value|
176
+ exec "alter session set #{key} = '#{value}'"
177
+ end
178
+
164
179
  self.autocommit = true
165
180
 
166
181
  schema = config[:schema] && config[:schema].to_s
@@ -232,7 +247,7 @@ module ActiveRecord
232
247
  begin
233
248
  yield if block_given?
234
249
  rescue Java::JavaSql::SQLException => e
235
- raise unless e.message =~ /^(Closed Connection|Io exception:|No more data to read from socket|IO Error:)/
250
+ raise unless /^(Closed Connection|Io exception:|No more data to read from socket|IO Error:)/.match?(e.message)
236
251
  @active = false
237
252
  raise unless should_retry
238
253
  should_retry = false
@@ -312,6 +327,8 @@ module ActiveRecord
312
327
  @raw_statement.setClob(position, value)
313
328
  when Type::OracleEnhanced::Raw
314
329
  @raw_statement.setString(position, OracleEnhanced::Quoting.encode_raw(value))
330
+ when Type::OracleEnhanced::CharacterString::Data
331
+ @raw_statement.setFixedCHAR(position, value.to_s)
315
332
  when String
316
333
  @raw_statement.setString(position, value)
317
334
  when Java::OracleSql::DATE
@@ -470,19 +487,24 @@ module ActiveRecord
470
487
  end
471
488
  when :BINARY_FLOAT
472
489
  rset.getFloat(i)
473
- when :VARCHAR2, :CHAR, :LONG, :NVARCHAR2, :NCHAR
490
+ when :VARCHAR2, :LONG, :NVARCHAR2
474
491
  rset.getString(i)
492
+ when :CHAR, :NCHAR
493
+ char_str = rset.getString(i)
494
+ if !char_str.nil?
495
+ char_str.rstrip
496
+ end
475
497
  when :DATE
476
498
  if dt = rset.getDATE(i)
477
499
  d = dt.dateValue
478
500
  t = dt.timeValue
479
- Time.send(Base.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
501
+ Time.send(ActiveRecord.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
480
502
  else
481
503
  nil
482
504
  end
483
505
  when :TIMESTAMP, :TIMESTAMPTZ, :TIMESTAMPLTZ, :"TIMESTAMP WITH TIME ZONE", :"TIMESTAMP WITH LOCAL TIME ZONE"
484
506
  ts = rset.getTimestamp(i)
485
- ts && Time.send(Base.default_timezone, ts.year + 1900, ts.month + 1, ts.date, ts.hours, ts.minutes, ts.seconds,
507
+ ts && Time.send(ActiveRecord.default_timezone, ts.year + 1900, ts.month + 1, ts.date, ts.hours, ts.minutes, ts.seconds,
486
508
  ts.nanos / 1000)
487
509
  when :CLOB
488
510
  get_lob_value ? lob_to_ruby_value(rset.getClob(i)) : rset.getClob(i)
@@ -499,7 +521,6 @@ module ActiveRecord
499
521
  end
500
522
 
501
523
  private
502
-
503
524
  def lob_to_ruby_value(val)
504
525
  case val
505
526
  when ::Java::OracleSql::CLOB
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module OracleEnhanced
6
6
  module JDBCQuoting
7
- def _type_cast(value)
7
+ def type_cast(value)
8
8
  case value
9
9
  when ActiveModel::Type::Binary::Data
10
10
  blob = Java::OracleSql::BLOB.createTemporary(@connection.raw_connection, false, Java::OracleSql::BLOB::DURATION_SESSION)
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ActiveRecord #:nodoc:
4
- module ConnectionAdapters #:nodoc:
5
- module OracleEnhanced #:nodoc:
6
- module Lob #:nodoc:
3
+ module ActiveRecord # :nodoc:
4
+ module ConnectionAdapters # :nodoc:
5
+ module OracleEnhanced # :nodoc:
6
+ module Lob # :nodoc:
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
@@ -18,13 +18,12 @@ module ActiveRecord #:nodoc:
18
18
  module ClassMethods
19
19
  def lob_columns
20
20
  columns.select do |column|
21
- column.sql_type_metadata.sql_type =~ /LOB$/
21
+ column.sql_type_metadata.sql_type.end_with?("LOB")
22
22
  end
23
23
  end
24
24
  end
25
25
 
26
26
  private
27
-
28
27
  def enhanced_write_lobs
29
28
  if self.class.connection.is_a?(ConnectionAdapters::OracleEnhancedAdapter) &&
30
29
  !(self.class.custom_create_method || self.class.custom_update_method)
@@ -15,7 +15,7 @@ end
15
15
  required_oci8_version = [2, 2, 4]
16
16
  oci8_version_ints = OCI8::VERSION.scan(/\d+/).map { |s| s.to_i }
17
17
  if (oci8_version_ints <=> required_oci8_version) < 0
18
- $stderr.puts <<-EOS.strip_heredoc
18
+ $stderr.puts <<~EOS
19
19
  "ERROR: ruby-oci8 version #{OCI8::VERSION} is too old. Please install ruby-oci8 version #{required_oci8_version.join('.')} or later."
20
20
  EOS
21
21
 
@@ -26,7 +26,7 @@ module ActiveRecord
26
26
  module ConnectionAdapters
27
27
  # OCI database interface for MRI
28
28
  module OracleEnhanced
29
- class OCIConnection < OracleEnhanced::Connection #:nodoc:
29
+ class OCIConnection < OracleEnhanced::Connection # :nodoc:
30
30
  def initialize(config)
31
31
  @raw_connection = OCI8EnhancedAutoRecover.new(config, OracleEnhancedOCIFactory)
32
32
  # default schema owner
@@ -97,6 +97,10 @@ module ActiveRecord
97
97
  @raw_connection.exec(sql, *bindvars, &block)
98
98
  end
99
99
 
100
+ def with_retry(&block)
101
+ @raw_connection.with_retry(&block)
102
+ end
103
+
100
104
  def prepare(sql)
101
105
  Cursor.new(self, @raw_connection.parse(sql))
102
106
  end
@@ -125,6 +129,8 @@ module ActiveRecord
125
129
  @raw_cursor.bind_param(position, OracleEnhanced::Quoting.encode_raw(value))
126
130
  when ActiveModel::Type::Decimal
127
131
  @raw_cursor.bind_param(position, BigDecimal(value.to_s))
132
+ when Type::OracleEnhanced::CharacterString::Data
133
+ @raw_cursor.bind_param(position, value.to_character_str)
128
134
  when NilClass
129
135
  @raw_cursor.bind_param(position, nil, String)
130
136
  else
@@ -151,8 +157,19 @@ module ActiveRecord
151
157
  def fetch(options = {})
152
158
  if row = @raw_cursor.fetch
153
159
  get_lob_value = options[:get_lob_value]
160
+ col_index = 0
154
161
  row.map do |col|
155
- @connection.typecast_result_value(col, get_lob_value)
162
+ col_value = @connection.typecast_result_value(col, get_lob_value)
163
+ col_metadata = @raw_cursor.column_metadata.fetch(col_index)
164
+ if !col_metadata.nil?
165
+ key = col_metadata.data_type
166
+ case key.to_s.downcase
167
+ when "char"
168
+ col_value = col.to_s.rstrip
169
+ end
170
+ end
171
+ col_index = col_index + 1
172
+ col_value
156
173
  end
157
174
  end
158
175
  end
@@ -184,7 +201,16 @@ module ActiveRecord
184
201
  hash = column_hash.dup
185
202
 
186
203
  cols.each_with_index do |col, i|
187
- hash[col] = typecast_result_value(row[i], get_lob_value)
204
+ col_value = typecast_result_value(row[i], get_lob_value)
205
+ col_metadata = cursor.column_metadata.fetch(i)
206
+ if !col_metadata.nil?
207
+ key = col_metadata.data_type
208
+ case key.to_s.downcase
209
+ when "char"
210
+ col_value = col_value.to_s.rstrip
211
+ end
212
+ end
213
+ hash[col] = col_value
188
214
  end
189
215
 
190
216
  rows << hash
@@ -200,17 +226,7 @@ module ActiveRecord
200
226
  end
201
227
 
202
228
  def describe(name)
203
- # fall back to SELECT based describe if using database link
204
- return super if name.to_s.include?("@")
205
- quoted_name = OracleEnhanced::Quoting.valid_table_name?(name) ? name : "\"#{name}\""
206
- @raw_connection.describe(quoted_name)
207
- rescue OCIException => e
208
- if e.code == 4043
209
- raise OracleEnhanced::ConnectionException, %Q{"DESC #{name}" failed; does it exist?}
210
- else
211
- # fall back to SELECT which can handle synonyms to database links
212
- super
213
- end
229
+ super
214
230
  end
215
231
 
216
232
  # Return OCIError error code
@@ -253,7 +269,6 @@ module ActiveRecord
253
269
  end
254
270
 
255
271
  private
256
-
257
272
  def date_without_time?(value)
258
273
  case value
259
274
  when OraDate
@@ -274,9 +289,9 @@ module ActiveRecord
274
289
  end
275
290
  # code from Time.time_with_datetime_fallback
276
291
  begin
277
- Time.send(Base.default_timezone, year, month, day, hour, min, sec, usec)
292
+ Time.send(ActiveRecord.default_timezone, year, month, day, hour, min, sec, usec)
278
293
  rescue
279
- offset = Base.default_timezone.to_sym == :local ? ::DateTime.local_offset : 0
294
+ offset = ActiveRecord.default_timezone.to_sym == :local ? ::DateTime.local_offset : 0
280
295
  ::DateTime.civil(year, month, day, hour, min, sec, offset)
281
296
  end
282
297
  end
@@ -284,7 +299,7 @@ module ActiveRecord
284
299
 
285
300
  # The OracleEnhancedOCIFactory factors out the code necessary to connect and
286
301
  # configure an Oracle/OCI connection.
287
- class OracleEnhancedOCIFactory #:nodoc:
302
+ class OracleEnhancedOCIFactory # :nodoc:
288
303
  DEFAULT_TCP_KEEPALIVE_TIME = 600
289
304
 
290
305
  def self.new_connection(config)
@@ -307,9 +322,9 @@ module ActiveRecord
307
322
  # connection using host, port and database name
308
323
  elsif host || port
309
324
  host ||= "localhost"
310
- host = "[#{host}]" if host =~ /^[^\[].*:/ # IPv6
325
+ host = "[#{host}]" if /^[^\[].*:/.match?(host) # IPv6
311
326
  port ||= 1521
312
- database = "/#{database}" unless database.match(/^\//)
327
+ database = "/#{database}" unless database.start_with?("/")
313
328
  "//#{host}:#{port}#{database}"
314
329
  # if no host is specified then assume that
315
330
  # database parameter is TNS alias or TNS connection string
@@ -328,9 +343,9 @@ module ActiveRecord
328
343
  conn.non_blocking = true if async
329
344
  conn.prefetch_rows = prefetch_rows
330
345
  conn.exec "alter session set cursor_sharing = #{cursor_sharing}" rescue nil if cursor_sharing
331
- if ActiveRecord::Base.default_timezone == :local
346
+ if ActiveRecord.default_timezone == :local
332
347
  conn.exec "alter session set time_zone = '#{time_zone}'" unless time_zone.blank?
333
- elsif ActiveRecord::Base.default_timezone == :utc
348
+ elsif ActiveRecord.default_timezone == :utc
334
349
  conn.exec "alter session set time_zone = '+00:00'"
335
350
  end
336
351
  conn.exec "alter session set current_schema = #{schema}" unless schema.blank?
@@ -342,6 +357,10 @@ module ActiveRecord
342
357
  conn.exec "alter session set #{key} = '#{value}'"
343
358
  end
344
359
  end
360
+
361
+ OracleEnhancedAdapter::FIXED_NLS_PARAMETERS.each do |key, value|
362
+ conn.exec "alter session set #{key} = '#{value}'"
363
+ end
345
364
  conn
346
365
  end
347
366
  end
@@ -349,18 +368,6 @@ module ActiveRecord
349
368
  end
350
369
  end
351
370
 
352
- class OCI8 #:nodoc:
353
- def describe(name)
354
- info = describe_table(name.to_s)
355
- raise %Q{"DESC #{name}" failed} if info.nil?
356
- if info.respond_to?(:obj_link) && info.obj_link
357
- [info.obj_schema, info.obj_name, "@" + info.obj_link]
358
- else
359
- [info.obj_schema, info.obj_name]
360
- end
361
- end
362
- end
363
-
364
371
  # The OCI8AutoRecover class enhances the OCI8 driver with auto-recover and
365
372
  # reset functionality. If a call to #exec fails, and autocommit is turned on
366
373
  # (ie., we're not in the middle of a longer transaction), it will
@@ -368,18 +375,18 @@ end
368
375
  # this would be dangerous (as the earlier part of the implied transaction
369
376
  # may have failed silently if the connection died) -- so instead the
370
377
  # connection is marked as dead, to be reconnected on it's next use.
371
- #:stopdoc:
372
- class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
373
- attr_accessor :active #:nodoc:
374
- alias :active? :active #:nodoc:
378
+ # :stopdoc:
379
+ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) # :nodoc:
380
+ attr_accessor :active # :nodoc:
381
+ alias :active? :active # :nodoc:
375
382
 
376
383
  cattr_accessor :auto_retry
377
384
  class << self
378
- alias :auto_retry? :auto_retry #:nodoc:
385
+ alias :auto_retry? :auto_retry # :nodoc:
379
386
  end
380
387
  @@auto_retry = false
381
388
 
382
- def initialize(config, factory) #:nodoc:
389
+ def initialize(config, factory) # :nodoc:
383
390
  @active = true
384
391
  @config = config
385
392
  @factory = factory
@@ -390,7 +397,7 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
390
397
  # Checks connection, returns true if active. Note that ping actively
391
398
  # checks the connection, while #active? simply returns the last
392
399
  # known state.
393
- def ping #:nodoc:
400
+ def ping # :nodoc:
394
401
  @connection.exec("select 1 from dual") { |r| nil }
395
402
  @active = true
396
403
  rescue
@@ -399,7 +406,7 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
399
406
  end
400
407
 
401
408
  # Resets connection, by logging off and creating a new connection.
402
- def reset! #:nodoc:
409
+ def reset! # :nodoc:
403
410
  logoff rescue nil
404
411
  begin
405
412
  @connection = @factory.new_connection @config
@@ -416,16 +423,14 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
416
423
  # ORA-03113: end-of-file on communication channel
417
424
  # ORA-03114: not connected to ORACLE
418
425
  # ORA-03135: connection lost contact
419
- LOST_CONNECTION_ERROR_CODES = [ 28, 1012, 3113, 3114, 3135 ] #:nodoc:
426
+ LOST_CONNECTION_ERROR_CODES = [ 28, 1012, 3113, 3114, 3135 ] # :nodoc:
420
427
 
421
428
  # Adds auto-recovery functionality.
422
- #
423
- # See: http://www.jiubao.org/ruby-oci8/api.en.html#label-11
424
- def exec(sql, *bindvars, &block) #:nodoc:
429
+ def with_retry # :nodoc:
425
430
  should_retry = self.class.auto_retry? && autocommit?
426
431
 
427
432
  begin
428
- @connection.exec(sql, *bindvars, &block)
433
+ yield
429
434
  rescue OCIException => e
430
435
  raise unless e.is_a?(OCIError) && LOST_CONNECTION_ERROR_CODES.include?(e.code)
431
436
  @active = false
@@ -435,5 +440,9 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
435
440
  retry
436
441
  end
437
442
  end
443
+
444
+ def exec(sql, *bindvars, &block) # :nodoc:
445
+ with_retry { @connection.exec(sql, *bindvars, &block) }
446
+ end
438
447
  end
439
- #:startdoc:
448
+ # :startdoc:
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module OracleEnhanced
6
6
  module OCIQuoting
7
- def _type_cast(value)
7
+ def type_cast(value)
8
8
  case value
9
9
  when ActiveModel::Type::Binary::Data
10
10
  lob_value = value == "" ? " " : value
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "active_support"
4
4
 
5
- module ActiveRecord #:nodoc:
5
+ module ActiveRecord # :nodoc:
6
6
  # Custom create, update, delete methods functionality.
7
7
  #
8
8
  # Example:
@@ -33,7 +33,7 @@ module ActiveRecord #:nodoc:
33
33
  # end
34
34
  # end
35
35
  #
36
- module OracleEnhancedProcedures #:nodoc:
36
+ module OracleEnhancedProcedures # :nodoc:
37
37
  module ClassMethods
38
38
  # Specify custom create method which should be used instead of Rails generated INSERT statement.
39
39
  # Provided block should return ID of new record.
@@ -83,7 +83,7 @@ module ActiveRecord #:nodoc:
83
83
  end
84
84
  end
85
85
 
86
- def destroy #:nodoc:
86
+ def destroy # :nodoc:
87
87
  # check if class has custom delete method
88
88
  if self.class.custom_delete_method
89
89
  # wrap destroy in transaction
@@ -97,7 +97,6 @@ module ActiveRecord #:nodoc:
97
97
  end
98
98
 
99
99
  private
100
-
101
100
  # Creates a record with custom create method
102
101
  # and returns its id.
103
102
  def _create_record
@@ -151,7 +150,7 @@ module ActiveRecord #:nodoc:
151
150
  end
152
151
  end
153
152
  # update just dirty attributes
154
- if partial_writes?
153
+ if partial_updates?
155
154
  # Serialized attributes should always be written in case they've been
156
155
  # changed in place.
157
156
  update_using_custom_method(changed | (attributes.keys & self.class.columns.select { |column| column.is_a?(Type::Serialized) }))
@@ -186,8 +185,8 @@ module ActiveRecord #:nodoc:
186
185
  freeze
187
186
  end
188
187
 
189
- def log_custom_method(*args)
190
- self.class.connection.send(:log, *args) { yield }
188
+ def log_custom_method(*args, &block)
189
+ self.class.connection.send(:log, *args, &block)
191
190
  end
192
191
 
193
192
  alias_method :update_record, :_update_record if private_method_defined?(:_update_record)