activerecord-oracle_enhanced-adapter 7.0.0 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +56 -0
- data/README.md +0 -1
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +5 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +2 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +35 -27
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +15 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +9 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +24 -15
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +7 -5
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +5 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +24 -22
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +17 -17
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +72 -29
- data/lib/activerecord-oracle_enhanced-adapter.rb +8 -0
- data/lib/arel/visitors/oracle.rb +6 -3
- data/lib/arel/visitors/oracle12.rb +6 -5
- data/lib/arel/visitors/oracle_common.rb +46 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +24 -5
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +7 -2
- data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +3 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +25 -15
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +15 -18
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +14 -10
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +2 -2
- data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +24 -0
- data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
- data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +4 -2
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +8 -0
- data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +3 -3
- data/spec/active_record/oracle_enhanced/type/raw_spec.rb +15 -0
- data/spec/active_record/oracle_enhanced/type/text_spec.rb +18 -3
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +5 -1
- data/spec/spec_config.yaml.template +2 -2
- data/spec/spec_helper.rb +14 -3
- metadata +27 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c54d072a9a65f5b91b230da739c0b2f117d397813b9f2dfb0ca56c13da00979
|
4
|
+
data.tar.gz: 0b4e805aff8d23258dda658e70a87494cb93d6da7b5e0024bd74a3807f54295e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72464c92eb71576aae495a2e93674d6823e1a2967f7f8bc45116d14dfbe8f29291c71b7f122e83c74698834be25e729bfddc0b64baf23de7e1b26044960faf26
|
7
|
+
data.tar.gz: 165de73dc654f318d7dc3042ae10f669047733255decd38f9abb2c3db3522bbb6f4c471db44a1ffe40ebaab05b400f9cd2eede381ea1018ea28217529a1c7610
|
data/History.md
CHANGED
@@ -1,3 +1,59 @@
|
|
1
|
+
## 7.1.0 / 2024-09-25
|
2
|
+
|
3
|
+
* Changes and bug fixes
|
4
|
+
No changes since 7.1.0.beta2
|
5
|
+
|
6
|
+
## 7.1.0.beta2 / 2024-09-23
|
7
|
+
* Changes and bug fixes
|
8
|
+
* Implement `build_explain_clause(options = [])` as no-op [#2394, #2398, #2402]
|
9
|
+
|
10
|
+
## 7.1.0.beta1 / 2024-09-23
|
11
|
+
|
12
|
+
* Changes and bug fixes
|
13
|
+
* Support Rails 7.1 [#2384]
|
14
|
+
* All attributes serialized before writing [#2203]
|
15
|
+
* Support LIKE case-insensitive matching [#2247]
|
16
|
+
* Support LOB equality [#2258]
|
17
|
+
* Rename the raw connection ivar to @raw_connection [#2265]
|
18
|
+
* Require 'activerecord', not 'rails' not to attempt to install digest [#2241]
|
19
|
+
* Add ruby-oci8 as dependency only for CRuby [#2240]
|
20
|
+
* Address uninitialized constant TestEmployee::AttributeSignature::Base64 [#2264]
|
21
|
+
* Enable Lint/EnsureReturn cop [#2259]
|
22
|
+
* Enable Performance/OpenStruct cop [#2263]
|
23
|
+
* Enable Style/MapToHash cop [#2266]
|
24
|
+
* Fix broken link [#2250]
|
25
|
+
* Use debug gem to replace byebug [#2275]
|
26
|
+
* Support linting YAML files [#2272]
|
27
|
+
|
28
|
+
* Known issues
|
29
|
+
* `build_explain_clause(options = [])` has not been implemented yet [#2394]
|
30
|
+
* `supports_fetch_first_n_rows_and_offset?` always returns `false` [#2395]
|
31
|
+
* Oracle enhanced adapter has not been tested against JRuby
|
32
|
+
* bug_report_templates are not tested [#2318]
|
33
|
+
|
34
|
+
## 7.0.3 / 2023-08-10
|
35
|
+
|
36
|
+
* Changes and bug fixes
|
37
|
+
* Support Rails 7.0.7
|
38
|
+
* Make ActiveRecord's quoted name caches thread-safe on JRuby/TruffleRuby [#2347, #2346]
|
39
|
+
* Address `NameError: uninitialized constant TestEmployee::AttributeSignature::Base64` [#2347]
|
40
|
+
* Address `Style/RedundantRegexpEscape` offense [#2347]
|
41
|
+
|
42
|
+
## 7.0.2 / 2022-01-21
|
43
|
+
|
44
|
+
* Changes and bug fixes
|
45
|
+
* Fix `columns_for_distinct` when using Rails 6.1 [#2249 #2251 rails/rails#31966]
|
46
|
+
|
47
|
+
## 7.0.1 / 2022-01-13
|
48
|
+
|
49
|
+
* Changes and bug fixes
|
50
|
+
* Add ruby-oci8 as dependency only for CRuby [#2238 #2240 #2243]
|
51
|
+
* Add if_exists option to remove_index [#2219 #2233]
|
52
|
+
* all attributes serialized before writing [#2203 #2234]
|
53
|
+
* Require 'activerecord', not 'rails' not to attempt to install digest [#2241]
|
54
|
+
* CI
|
55
|
+
* Bump Ruby versions at Travis CI [#2242]
|
56
|
+
* CI against Ruby 3.1 at GitHub Actions [#2235 #2244]
|
1
57
|
## 7.0.0 / 2021-12-16
|
2
58
|
* Changes and bug fixes
|
3
59
|
* Support Rails 7.0.0
|
data/README.md
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
7.
|
1
|
+
7.1.0
|
@@ -17,13 +17,13 @@ module ActiveRecord
|
|
17
17
|
def table_name_length
|
18
18
|
IDENTIFIER_MAX_LENGTH
|
19
19
|
end
|
20
|
-
deprecate :table_name_length
|
20
|
+
deprecate :table_name_length, deprecator: ActiveSupport::Deprecation.new
|
21
21
|
|
22
22
|
# the maximum length of a column name
|
23
23
|
def column_name_length
|
24
24
|
IDENTIFIER_MAX_LENGTH
|
25
25
|
end
|
26
|
-
deprecate :column_name_length
|
26
|
+
deprecate :column_name_length, deprecator: ActiveSupport::Deprecation.new
|
27
27
|
|
28
28
|
# the maximum length of an index name
|
29
29
|
# supported by this database
|
@@ -9,13 +9,13 @@ module ActiveRecord
|
|
9
9
|
# see: abstract/database_statements.rb
|
10
10
|
|
11
11
|
# Executes a SQL statement
|
12
|
-
def execute(sql, name = nil, async: false)
|
12
|
+
def execute(sql, name = nil, async: false, allow_retry: false)
|
13
13
|
sql = transform_query(sql)
|
14
14
|
|
15
|
-
log(sql, name, async: async) {
|
15
|
+
log(sql, name, async: async) { _connection.exec(sql, allow_retry: allow_retry) }
|
16
16
|
end
|
17
17
|
|
18
|
-
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false)
|
18
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false)
|
19
19
|
sql = transform_query(sql)
|
20
20
|
|
21
21
|
type_casted_binds = type_casted_binds(binds)
|
@@ -25,10 +25,10 @@ module ActiveRecord
|
|
25
25
|
cached = false
|
26
26
|
with_retry do
|
27
27
|
if without_prepared_statement?(binds)
|
28
|
-
cursor =
|
28
|
+
cursor = _connection.prepare(sql)
|
29
29
|
else
|
30
30
|
unless @statements.key? sql
|
31
|
-
@statements[sql] =
|
31
|
+
@statements[sql] = _connection.prepare(sql)
|
32
32
|
end
|
33
33
|
|
34
34
|
cursor = @statements[sql]
|
@@ -59,12 +59,13 @@ module ActiveRecord
|
|
59
59
|
res
|
60
60
|
end
|
61
61
|
end
|
62
|
+
alias_method :internal_exec_query, :exec_query
|
62
63
|
|
63
64
|
def supports_explain?
|
64
65
|
true
|
65
66
|
end
|
66
67
|
|
67
|
-
def explain(arel, binds = [])
|
68
|
+
def explain(arel, binds = [], options = [])
|
68
69
|
sql = "EXPLAIN PLAN FOR #{to_sql(arel, binds)}"
|
69
70
|
return if /FROM all_/.match?(sql)
|
70
71
|
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
@@ -75,9 +76,14 @@ module ActiveRecord
|
|
75
76
|
select_values("SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)", "EXPLAIN").join("\n")
|
76
77
|
end
|
77
78
|
|
79
|
+
def build_explain_clause(options = [])
|
80
|
+
# Oracle does not have anything similar to "EXPLAIN ANALYZE"
|
81
|
+
# https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/EXPLAIN-PLAN.html#GUID-FD540872-4ED3-4936-96A2-362539931BA0
|
82
|
+
end
|
83
|
+
|
78
84
|
# New method in ActiveRecord 3.1
|
79
85
|
# Will add RETURNING clause in case of trigger generated primary keys
|
80
|
-
def sql_for_insert(sql, pk, binds)
|
86
|
+
def sql_for_insert(sql, pk, binds, _returning)
|
81
87
|
unless pk == false || pk.nil? || pk.is_a?(Array) || pk.is_a?(String)
|
82
88
|
sql = "#{sql} RETURNING #{quote_column_name(pk)} INTO :returning_id"
|
83
89
|
(binds = binds.dup) << ActiveRecord::Relation::QueryAttribute.new("returning_id", nil, Type::OracleEnhanced::Integer.new)
|
@@ -85,14 +91,14 @@ module ActiveRecord
|
|
85
91
|
super
|
86
92
|
end
|
87
93
|
|
88
|
-
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
94
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
|
89
95
|
pk = nil if id_value
|
90
|
-
super
|
96
|
+
Array(super || id_value)
|
91
97
|
end
|
92
98
|
|
93
99
|
# New method in ActiveRecord 3.1
|
94
|
-
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
95
|
-
sql, binds = sql_for_insert(sql, pk, binds)
|
100
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
|
101
|
+
sql, binds = sql_for_insert(sql, pk, binds, returning)
|
96
102
|
type_casted_binds = type_casted_binds(binds)
|
97
103
|
|
98
104
|
log(sql, name, binds, type_casted_binds) do
|
@@ -101,10 +107,10 @@ module ActiveRecord
|
|
101
107
|
returning_id_col = returning_id_index = nil
|
102
108
|
with_retry do
|
103
109
|
if without_prepared_statement?(binds)
|
104
|
-
cursor =
|
110
|
+
cursor = _connection.prepare(sql)
|
105
111
|
else
|
106
112
|
unless @statements.key?(sql)
|
107
|
-
@statements[sql] =
|
113
|
+
@statements[sql] = _connection.prepare(sql)
|
108
114
|
end
|
109
115
|
|
110
116
|
cursor = @statements[sql]
|
@@ -141,12 +147,12 @@ module ActiveRecord
|
|
141
147
|
with_retry do
|
142
148
|
cached = false
|
143
149
|
if without_prepared_statement?(binds)
|
144
|
-
cursor =
|
150
|
+
cursor = _connection.prepare(sql)
|
145
151
|
else
|
146
152
|
if @statements.key?(sql)
|
147
153
|
cursor = @statements[sql]
|
148
154
|
else
|
149
|
-
cursor = @statements[sql] =
|
155
|
+
cursor = @statements[sql] = _connection.prepare(sql)
|
150
156
|
end
|
151
157
|
|
152
158
|
cursor.bind_params(type_casted_binds)
|
@@ -163,8 +169,12 @@ module ActiveRecord
|
|
163
169
|
|
164
170
|
alias :exec_delete :exec_update
|
165
171
|
|
172
|
+
def returning_column_values(result)
|
173
|
+
result.rows.first
|
174
|
+
end
|
175
|
+
|
166
176
|
def begin_db_transaction # :nodoc:
|
167
|
-
|
177
|
+
_connection.autocommit = false
|
168
178
|
end
|
169
179
|
|
170
180
|
def transaction_isolation_levels
|
@@ -183,15 +193,15 @@ module ActiveRecord
|
|
183
193
|
end
|
184
194
|
|
185
195
|
def commit_db_transaction # :nodoc:
|
186
|
-
|
196
|
+
_connection.commit
|
187
197
|
ensure
|
188
|
-
|
198
|
+
_connection.autocommit = true
|
189
199
|
end
|
190
200
|
|
191
201
|
def exec_rollback_db_transaction # :nodoc:
|
192
|
-
|
202
|
+
_connection.rollback
|
193
203
|
ensure
|
194
|
-
|
204
|
+
_connection.autocommit = true
|
195
205
|
end
|
196
206
|
|
197
207
|
def create_savepoint(name = current_savepoint_name) # :nodoc:
|
@@ -254,11 +264,9 @@ module ActiveRecord
|
|
254
264
|
value = attributes[col.name]
|
255
265
|
# changed sequence of next two lines - should check if value is nil before converting to yaml
|
256
266
|
next unless value
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
next unless value
|
261
|
-
end
|
267
|
+
value = klass.attribute_types[col.name].serialize(value)
|
268
|
+
# value can be nil after serialization because ActiveRecord serializes [] and {} as nil
|
269
|
+
next unless value
|
262
270
|
uncached do
|
263
271
|
unless lob_record = select_one(sql = <<~SQL.squish, "Writable Large Object")
|
264
272
|
SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)}
|
@@ -267,14 +275,14 @@ module ActiveRecord
|
|
267
275
|
raise ActiveRecord::RecordNotFound, "statement #{sql} returned no rows"
|
268
276
|
end
|
269
277
|
lob = lob_record[col.name]
|
270
|
-
|
278
|
+
_connection.write_lob(lob, value.to_s, col.type == :binary)
|
271
279
|
end
|
272
280
|
end
|
273
281
|
end
|
274
282
|
|
275
283
|
private
|
276
284
|
def with_retry
|
277
|
-
|
285
|
+
_connection.with_retry do
|
278
286
|
yield
|
279
287
|
rescue
|
280
288
|
@statements.clear
|
@@ -31,8 +31,21 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
|
-
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false)
|
35
|
-
|
34
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false, &block)
|
35
|
+
@instrumenter.instrument(
|
36
|
+
"sql.active_record",
|
37
|
+
sql: sql,
|
38
|
+
name: name,
|
39
|
+
binds: binds,
|
40
|
+
type_casted_binds: type_casted_binds,
|
41
|
+
statement_name: statement_name,
|
42
|
+
async: async,
|
43
|
+
connection: self,
|
44
|
+
&block
|
45
|
+
)
|
46
|
+
rescue => e
|
47
|
+
# FIXME: raise ex.set_query(sql, binds)
|
48
|
+
raise translate_exception_class(e, sql, binds)
|
36
49
|
ensure
|
37
50
|
log_dbms_output if dbms_output_enabled?
|
38
51
|
end
|
@@ -135,6 +135,13 @@ module ActiveRecord
|
|
135
135
|
properties.put("defaultRowPrefetch", "#{prefetch_rows}") if prefetch_rows
|
136
136
|
properties.put("internal_logon", privilege) if privilege
|
137
137
|
|
138
|
+
if config[:jdbc_connect_properties] # arbitrary additional properties for JDBC connection
|
139
|
+
raise "jdbc_connect_properties should contain an associative array / hash" unless config[:jdbc_connect_properties].is_a? Hash
|
140
|
+
config[:jdbc_connect_properties].each do |key, value|
|
141
|
+
properties.put(key, value)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
138
145
|
begin
|
139
146
|
@raw_connection = java.sql.DriverManager.getConnection(url, properties)
|
140
147
|
rescue
|
@@ -295,7 +302,7 @@ module ActiveRecord
|
|
295
302
|
|
296
303
|
class Cursor
|
297
304
|
def initialize(connection, raw_statement)
|
298
|
-
@
|
305
|
+
@raw_connection = connection
|
299
306
|
@raw_statement = raw_statement
|
300
307
|
end
|
301
308
|
|
@@ -384,7 +391,7 @@ module ActiveRecord
|
|
384
391
|
row_values = []
|
385
392
|
column_types.each_with_index do |column_type, i|
|
386
393
|
row_values <<
|
387
|
-
@
|
394
|
+
@raw_connection.get_ruby_value_from_result_set(@raw_result_set, i + 1, column_type, get_lob_value)
|
388
395
|
end
|
389
396
|
row_values
|
390
397
|
else
|
@@ -7,15 +7,15 @@ module ActiveRecord
|
|
7
7
|
def type_cast(value)
|
8
8
|
case value
|
9
9
|
when ActiveModel::Type::Binary::Data
|
10
|
-
blob = Java::OracleSql::BLOB.createTemporary(@
|
10
|
+
blob = Java::OracleSql::BLOB.createTemporary(@raw_connection.raw_connection, false, Java::OracleSql::BLOB::DURATION_SESSION)
|
11
11
|
blob.setBytes(1, value.to_s.to_java_bytes)
|
12
12
|
blob
|
13
13
|
when Type::OracleEnhanced::Text::Data
|
14
|
-
clob = Java::OracleSql::CLOB.createTemporary(@
|
14
|
+
clob = Java::OracleSql::CLOB.createTemporary(@raw_connection.raw_connection, false, Java::OracleSql::CLOB::DURATION_SESSION)
|
15
15
|
clob.setString(1, value.to_s)
|
16
16
|
clob
|
17
17
|
when Type::OracleEnhanced::NationalCharacterText::Data
|
18
|
-
clob = Java::OracleSql::NCLOB.createTemporary(@
|
18
|
+
clob = Java::OracleSql::NCLOB.createTemporary(@raw_connection.raw_connection, false, Java::OracleSql::NCLOB::DURATION_SESSION)
|
19
19
|
clob.setString(1, value.to_s)
|
20
20
|
clob
|
21
21
|
else
|
@@ -41,7 +41,7 @@ module ActiveRecord
|
|
41
41
|
# ActiveRecord Oracle enhanced adapter puts OCI8EnhancedAutoRecover wrapper around OCI8
|
42
42
|
# in this case we need to pass original OCI8 connection
|
43
43
|
else
|
44
|
-
@raw_connection.instance_variable_get(:@
|
44
|
+
@raw_connection.instance_variable_get(:@raw_connection)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -87,18 +87,22 @@ module ActiveRecord
|
|
87
87
|
@raw_connection.active?
|
88
88
|
end
|
89
89
|
|
90
|
+
def reset
|
91
|
+
@raw_connection.reset
|
92
|
+
end
|
93
|
+
|
90
94
|
def reset!
|
91
95
|
@raw_connection.reset!
|
92
96
|
rescue OCIException => e
|
93
97
|
raise OracleEnhanced::ConnectionException, e.message
|
94
98
|
end
|
95
99
|
|
96
|
-
def exec(sql, *bindvars, &block)
|
97
|
-
@raw_connection.exec(sql, *bindvars, &block)
|
100
|
+
def exec(sql, *bindvars, allow_retry: false, &block)
|
101
|
+
with_retry(allow_retry: allow_retry) { @raw_connection.exec(sql, *bindvars, &block) }
|
98
102
|
end
|
99
103
|
|
100
|
-
def with_retry(&block)
|
101
|
-
@raw_connection.with_retry(&block)
|
104
|
+
def with_retry(allow_retry: false, &block)
|
105
|
+
@raw_connection.with_retry(allow_retry: allow_retry, &block)
|
102
106
|
end
|
103
107
|
|
104
108
|
def prepare(sql)
|
@@ -107,7 +111,7 @@ module ActiveRecord
|
|
107
111
|
|
108
112
|
class Cursor
|
109
113
|
def initialize(connection, raw_cursor)
|
110
|
-
@
|
114
|
+
@raw_connection = connection
|
111
115
|
@raw_cursor = raw_cursor
|
112
116
|
end
|
113
117
|
|
@@ -159,7 +163,7 @@ module ActiveRecord
|
|
159
163
|
get_lob_value = options[:get_lob_value]
|
160
164
|
col_index = 0
|
161
165
|
row.map do |col|
|
162
|
-
col_value = @
|
166
|
+
col_value = @raw_connection.typecast_result_value(col, get_lob_value)
|
163
167
|
col_metadata = @raw_cursor.column_metadata.fetch(col_index)
|
164
168
|
if !col_metadata.nil?
|
165
169
|
key = col_metadata.data_type
|
@@ -390,27 +394,32 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) # :nodoc:
|
|
390
394
|
@active = true
|
391
395
|
@config = config
|
392
396
|
@factory = factory
|
393
|
-
@
|
394
|
-
super @
|
397
|
+
@raw_connection = @factory.new_connection @config
|
398
|
+
super @raw_connection
|
395
399
|
end
|
396
400
|
|
397
401
|
# Checks connection, returns true if active. Note that ping actively
|
398
402
|
# checks the connection, while #active? simply returns the last
|
399
403
|
# known state.
|
400
404
|
def ping # :nodoc:
|
401
|
-
@
|
405
|
+
@raw_connection.exec("select 1 from dual") { |r| nil }
|
402
406
|
@active = true
|
403
407
|
rescue
|
404
408
|
@active = false
|
405
409
|
raise
|
406
410
|
end
|
407
411
|
|
412
|
+
def reset
|
413
|
+
# tentative
|
414
|
+
reset!
|
415
|
+
end
|
416
|
+
|
408
417
|
# Resets connection, by logging off and creating a new connection.
|
409
418
|
def reset! # :nodoc:
|
410
419
|
logoff rescue nil
|
411
420
|
begin
|
412
|
-
@
|
413
|
-
__setobj__ @
|
421
|
+
@raw_connection = @factory.new_connection @config
|
422
|
+
__setobj__ @raw_connection
|
414
423
|
@active = true
|
415
424
|
rescue
|
416
425
|
@active = false
|
@@ -426,8 +435,8 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) # :nodoc:
|
|
426
435
|
LOST_CONNECTION_ERROR_CODES = [ 28, 1012, 3113, 3114, 3135 ] # :nodoc:
|
427
436
|
|
428
437
|
# Adds auto-recovery functionality.
|
429
|
-
def with_retry # :nodoc:
|
430
|
-
should_retry = self.class.auto_retry? && autocommit?
|
438
|
+
def with_retry(allow_retry: false) # :nodoc:
|
439
|
+
should_retry = (allow_retry || self.class.auto_retry?) && autocommit?
|
431
440
|
|
432
441
|
begin
|
433
442
|
yield
|
@@ -442,7 +451,7 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) # :nodoc:
|
|
442
451
|
end
|
443
452
|
|
444
453
|
def exec(sql, *bindvars, &block) # :nodoc:
|
445
|
-
with_retry { @
|
454
|
+
with_retry { @raw_connection.exec(sql, *bindvars, &block) }
|
446
455
|
end
|
447
456
|
end
|
448
457
|
# :startdoc:
|
@@ -9,19 +9,19 @@ module ActiveRecord
|
|
9
9
|
when ActiveModel::Type::Binary::Data
|
10
10
|
lob_value = value == "" ? " " : value
|
11
11
|
bind_type = OCI8::BLOB
|
12
|
-
ora_value = bind_type.new(
|
12
|
+
ora_value = bind_type.new(_connection.raw_oci_connection, lob_value)
|
13
13
|
ora_value.size = 0 if value == ""
|
14
14
|
ora_value
|
15
15
|
when Type::OracleEnhanced::Text::Data
|
16
16
|
lob_value = value.to_s == "" ? " " : value.to_s
|
17
17
|
bind_type = OCI8::CLOB
|
18
|
-
ora_value = bind_type.new(
|
18
|
+
ora_value = bind_type.new(_connection.raw_oci_connection, lob_value)
|
19
19
|
ora_value.size = 0 if value.to_s == ""
|
20
20
|
ora_value
|
21
21
|
when Type::OracleEnhanced::NationalCharacterText::Data
|
22
22
|
lob_value = value.to_s == "" ? " " : value.to_s
|
23
23
|
bind_type = OCI8::NCLOB
|
24
|
-
ora_value = bind_type.new(
|
24
|
+
ora_value = bind_type.new(_connection.raw_oci_connection, lob_value)
|
25
25
|
ora_value.size = 0 if value.to_s == ""
|
26
26
|
ora_value
|
27
27
|
else
|
@@ -7,10 +7,12 @@ module ActiveRecord
|
|
7
7
|
# QUOTING ==================================================
|
8
8
|
#
|
9
9
|
# see: abstract/quoting.rb
|
10
|
+
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
11
|
+
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
10
12
|
|
11
13
|
def quote_column_name(name) # :nodoc:
|
12
14
|
name = name.to_s
|
13
|
-
|
15
|
+
QUOTED_COLUMN_NAMES[name] ||= if /\A[a-z][a-z_0-9$#]*\Z/.match?(name)
|
14
16
|
"\"#{name.upcase}\""
|
15
17
|
else
|
16
18
|
# remove double quotes which cannot be used inside quoted identifier
|
@@ -26,7 +28,7 @@ module ActiveRecord
|
|
26
28
|
# if only valid lowercase column characters in name
|
27
29
|
when /^[a-z][a-z_0-9$#]*$/
|
28
30
|
"\"#{name.upcase}\""
|
29
|
-
when /^[a-z][a-z_0-9
|
31
|
+
when /^[a-z][a-z_0-9$#-]*$/i
|
30
32
|
"\"#{name}\""
|
31
33
|
# if other characters present then assume that it is expression
|
32
34
|
# which should not be quoted
|
@@ -67,7 +69,7 @@ module ActiveRecord
|
|
67
69
|
|
68
70
|
def quote_table_name(name) # :nodoc:
|
69
71
|
name, _link = name.to_s.split("@")
|
70
|
-
|
72
|
+
QUOTED_TABLE_NAMES[name] ||= [name.split(".").map { |n| quote_column_name(n) }].join(".")
|
71
73
|
end
|
72
74
|
|
73
75
|
def quote_string(s) # :nodoc:
|
@@ -142,7 +144,7 @@ module ActiveRecord
|
|
142
144
|
(
|
143
145
|
(?:
|
144
146
|
# "table_name"."column_name" | function(one or no argument)
|
145
|
-
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")
|
147
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
146
148
|
)
|
147
149
|
(?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
|
148
150
|
)
|
@@ -155,7 +157,7 @@ module ActiveRecord
|
|
155
157
|
(
|
156
158
|
(?:
|
157
159
|
# "table_name"."column_name" | function(one or no argument)
|
158
|
-
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")
|
160
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
|
159
161
|
)
|
160
162
|
(?:\s+ASC|\s+DESC)?
|
161
163
|
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
@@ -81,6 +81,11 @@ module ActiveRecord
|
|
81
81
|
super(*args, type: :integer, **options)
|
82
82
|
end
|
83
83
|
alias :belongs_to :references
|
84
|
+
|
85
|
+
private
|
86
|
+
def valid_column_definition_options
|
87
|
+
super + [ :as, :sequence_name, :sequence_start_value, :type ]
|
88
|
+
end
|
84
89
|
end
|
85
90
|
|
86
91
|
class AlterTable < ActiveRecord::ConnectionAdapters::AlterTable
|
@@ -181,7 +181,7 @@ module ActiveRecord # :nodoc:
|
|
181
181
|
def extract_expression_for_virtual_column(column)
|
182
182
|
column_name = column.name
|
183
183
|
@connection.select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name.upcase), bind_string("column_name", column_name.upcase)]).inspect
|
184
|
-
select
|
184
|
+
select data_default from all_tab_columns
|
185
185
|
where owner = SYS_CONTEXT('userenv', 'current_schema')
|
186
186
|
and table_name = :table_name
|
187
187
|
and column_name = :column_name
|