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.
- checksums.yaml +4 -4
- data/History.md +390 -21
- data/README.md +35 -8
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +42 -37
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +59 -60
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +5 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +86 -81
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +9 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +1 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +37 -16
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +5 -6
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +58 -49
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +6 -7
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +75 -51
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +13 -14
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +14 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +27 -24
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +156 -155
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +103 -90
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +3 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +261 -161
- data/lib/active_record/type/oracle_enhanced/boolean.rb +0 -1
- data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/integer.rb +0 -1
- data/lib/arel/visitors/oracle.rb +221 -0
- data/lib/arel/visitors/oracle12.rb +128 -0
- data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +0 -2
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +78 -26
- data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +7 -15
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +5 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +17 -17
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +7 -10
- data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +0 -15
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +33 -36
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +77 -258
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +38 -39
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +273 -85
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +7 -8
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +2 -4
- data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +43 -0
- data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
- data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
- data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +1 -1
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +2 -2
- data/spec/active_record/oracle_enhanced/type/json_spec.rb +0 -1
- data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +6 -5
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +2 -4
- data/spec/spec_config.yaml.template +2 -2
- data/spec/spec_helper.rb +13 -2
- metadata +52 -30
- 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(
|
20
|
+
establish_connection(@config.merge(username: "SYSTEM", password: system_password))
|
21
21
|
begin
|
22
|
-
connection.execute "CREATE USER #{@config[
|
22
|
+
connection.execute "CREATE USER #{@config[:username]} IDENTIFIED BY #{@config[:password]}"
|
23
23
|
rescue => e
|
24
|
-
if
|
25
|
-
connection.execute "ALTER USER #{@config[
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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[
|
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
|
-
|
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"]
|
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.
|
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
|
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 = "
|
121
|
+
database = "/#{database}"
|
119
122
|
end
|
120
|
-
url = config[:url] || "jdbc:oracle:thin
|
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
|
148
|
+
if ActiveRecord.default_timezone == :local
|
144
149
|
@raw_connection.setSessionTimeZone(time_zone)
|
145
|
-
elsif ActiveRecord
|
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
|
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, :
|
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(
|
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(
|
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
|
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
|
4
|
-
module ConnectionAdapters
|
5
|
-
module OracleEnhanced
|
6
|
-
module Lob
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
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(
|
292
|
+
Time.send(ActiveRecord.default_timezone, year, month, day, hour, min, sec, usec)
|
278
293
|
rescue
|
279
|
-
offset =
|
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
|
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
|
325
|
+
host = "[#{host}]" if /^[^\[].*:/.match?(host) # IPv6
|
311
326
|
port ||= 1521
|
312
|
-
database = "/#{database}" unless database.
|
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
|
346
|
+
if ActiveRecord.default_timezone == :local
|
332
347
|
conn.exec "alter session set time_zone = '#{time_zone}'" unless time_zone.blank?
|
333
|
-
elsif ActiveRecord
|
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
|
-
|
372
|
-
class OCI8EnhancedAutoRecover < DelegateClass(OCI8)
|
373
|
-
attr_accessor :active
|
374
|
-
alias :active? :active
|
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
|
385
|
+
alias :auto_retry? :auto_retry # :nodoc:
|
379
386
|
end
|
380
387
|
@@auto_retry = false
|
381
388
|
|
382
|
-
def initialize(config, factory)
|
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
|
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!
|
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 ]
|
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
|
-
|
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
|
-
|
448
|
+
# :startdoc:
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "active_support"
|
4
4
|
|
5
|
-
module ActiveRecord
|
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
|
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
|
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
|
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)
|
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)
|