activerecord-oracle_enhanced-adapter 7.0.0 → 7.1.0

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +56 -0
  3. data/README.md +0 -1
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +5 -0
  6. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +1 -1
  7. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +2 -2
  8. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +35 -27
  9. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +15 -2
  10. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +9 -2
  11. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +3 -3
  12. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +24 -15
  13. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +3 -3
  14. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +7 -5
  15. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +1 -1
  16. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +5 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +1 -1
  18. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +24 -22
  19. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +17 -17
  20. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +72 -29
  21. data/lib/activerecord-oracle_enhanced-adapter.rb +8 -0
  22. data/lib/arel/visitors/oracle.rb +6 -3
  23. data/lib/arel/visitors/oracle12.rb +6 -5
  24. data/lib/arel/visitors/oracle_common.rb +46 -0
  25. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +24 -5
  26. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +7 -2
  27. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +2 -2
  28. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +3 -0
  29. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +25 -15
  30. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +15 -18
  31. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +14 -10
  32. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +2 -2
  33. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +24 -0
  34. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  35. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +4 -2
  36. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +8 -0
  37. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +3 -3
  38. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +15 -0
  39. data/spec/active_record/oracle_enhanced/type/text_spec.rb +18 -3
  40. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +5 -1
  41. data/spec/spec_config.yaml.template +2 -2
  42. data/spec/spec_helper.rb +14 -3
  43. metadata +27 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28b353a0c4917c1696bc44c5c3e60565c2863fc6639e48ff71814064394497a5
4
- data.tar.gz: bdf94614cb38f1ad7ab121f580164ccb48e974ac7f09bcce3bbdfaca7cc51ca8
3
+ metadata.gz: 2c54d072a9a65f5b91b230da739c0b2f117d397813b9f2dfb0ca56c13da00979
4
+ data.tar.gz: 0b4e805aff8d23258dda658e70a87494cb93d6da7b5e0024bd74a3807f54295e
5
5
  SHA512:
6
- metadata.gz: b0586d8753686b7f81a2b8137397fe0ab9af4f0607775f866f06e0625d9dc9eae480093bbb73f9331798dcba124b5d0b86039d06e039827281cbb05ba2e9b0dc
7
- data.tar.gz: 90c2613d22b1705db2f82d5dca382327c3b4c36edba9ac46879441614b143e136e054eed07aebb2f12b06aac95e7d89e17021ac62dfb22f8efaa67206577d341
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
@@ -18,7 +18,6 @@ When using Ruby on Rails version 7.0 then in Gemfile include
18
18
  ```ruby
19
19
  # Use oracle as the database for Active Record
20
20
  gem 'activerecord-oracle_enhanced-adapter', '~> 7.0.0'
21
- gem 'ruby-oci8' # only for CRuby users
22
21
  ```
23
22
 
24
23
  ### Rails 6.1
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.0.0
1
+ 7.1.0
@@ -13,6 +13,11 @@ module ActiveRecord
13
13
  def virtual?
14
14
  virtual
15
15
  end
16
+
17
+ def auto_incremented_by_db?
18
+ # TODO: Identify if a column is the primary key and is auto-incremented (e.g. by a sequence)
19
+ super
20
+ end
16
21
  end
17
22
  end
18
23
  end
@@ -101,7 +101,7 @@ module ActiveRecord
101
101
  _oracle_downcase(col_name)
102
102
  end
103
103
  row = cursor.fetch
104
- columns.each_with_index.map { |x, i| [x, row[i]] }.to_h if row
104
+ columns.each_with_index.to_h { |x, i| [x, row[i]] } if row
105
105
  ensure
106
106
  cursor.close
107
107
  end
@@ -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) { @connection.exec(sql) }
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 = @connection.prepare(sql)
28
+ cursor = _connection.prepare(sql)
29
29
  else
30
30
  unless @statements.key? sql
31
- @statements[sql] = @connection.prepare(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 = @connection.prepare(sql)
110
+ cursor = _connection.prepare(sql)
105
111
  else
106
112
  unless @statements.key?(sql)
107
- @statements[sql] = @connection.prepare(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 = @connection.prepare(sql)
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] = @connection.prepare(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
- @connection.autocommit = false
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
- @connection.commit
196
+ _connection.commit
187
197
  ensure
188
- @connection.autocommit = true
198
+ _connection.autocommit = true
189
199
  end
190
200
 
191
201
  def exec_rollback_db_transaction # :nodoc:
192
- @connection.rollback
202
+ _connection.rollback
193
203
  ensure
194
- @connection.autocommit = true
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
- if klass.attribute_types[col.name].is_a? Type::Serialized
258
- value = klass.attribute_types[col.name].serialize(value)
259
- # value can be nil after serialization because ActiveRecord serializes [] and {} as nil
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
- @connection.write_lob(lob, value.to_s, col.type == :binary)
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
- @connection.with_retry do
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
- super
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
- @connection = connection
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
- @connection.get_ruby_value_from_result_set(@raw_result_set, i + 1, column_type, get_lob_value)
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(@connection.raw_connection, false, Java::OracleSql::BLOB::DURATION_SESSION)
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(@connection.raw_connection, false, Java::OracleSql::CLOB::DURATION_SESSION)
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(@connection.raw_connection, false, Java::OracleSql::NCLOB::DURATION_SESSION)
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(:@connection)
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
- @connection = connection
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 = @connection.typecast_result_value(col, get_lob_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
- @connection = @factory.new_connection @config
394
- super @connection
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
- @connection.exec("select 1 from dual") { |r| nil }
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
- @connection = @factory.new_connection @config
413
- __setobj__ @connection
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 { @connection.exec(sql, *bindvars, &block) }
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(@connection.raw_oci_connection, lob_value)
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(@connection.raw_oci_connection, lob_value)
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(@connection.raw_oci_connection, lob_value)
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
- self.class.quoted_column_names[name] ||= if /\A[a-z][a-z_0-9$#]*\Z/.match?(name)
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$#\-]*$/i
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
- self.class.quoted_table_names[name] ||= [name.split(".").map { |n| quote_column_name(n) }].join(".")
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+")) | \w+\((?:|\g<2>)\)
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+")) | \w+\((?:|\g<2>)\)
160
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+") | \w+\((?:|\g<2>)\))
159
161
  )
160
162
  (?:\s+ASC|\s+DESC)?
161
163
  (?:\s+NULLS\s+(?:FIRST|LAST))?
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  statements = o.columns.map { |c| accept c }
21
21
  statements << accept(o.primary_keys) if o.primary_keys
22
22
 
23
- if supports_foreign_keys?
23
+ if use_foreign_keys?
24
24
  statements.concat(o.foreign_keys.map { |fk| accept fk })
25
25
  end
26
26
 
@@ -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 /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ data_default from all_tab_columns
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