activerecord-oracle_enhanced-adapter 5.2.8 → 7.0.3

Sign up to get free protection for your applications and to get access to all the features.
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)