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
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
 
13
13
  def tables # :nodoc:
14
14
  select_values(<<~SQL.squish, "SCHEMA")
15
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
15
+ SELECT
16
16
  DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name)
17
17
  FROM all_tables
18
18
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -45,7 +45,7 @@ module ActiveRecord
45
45
  end
46
46
 
47
47
  select_values(<<~SQL.squish, "SCHEMA", [bind_string("owner", table_owner), bind_string("table_name", table_name)]).any?
48
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ owner, table_name
48
+ SELECT owner, table_name
49
49
  FROM all_tables
50
50
  WHERE owner = :owner
51
51
  AND table_name = :table_name
@@ -53,7 +53,7 @@ module ActiveRecord
53
53
  end
54
54
 
55
55
  def data_source_exists?(table_name)
56
- (_owner, _table_name) = @connection.describe(table_name)
56
+ (_owner, _table_name) = _connection.describe(table_name)
57
57
  true
58
58
  rescue
59
59
  false
@@ -61,14 +61,14 @@ module ActiveRecord
61
61
 
62
62
  def views # :nodoc:
63
63
  select_values(<<~SQL.squish, "SCHEMA")
64
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
64
+ SELECT
65
65
  LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
66
66
  SQL
67
67
  end
68
68
 
69
69
  def materialized_views # :nodoc:
70
70
  select_values(<<~SQL.squish, "SCHEMA")
71
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
71
+ SELECT
72
72
  LOWER(mview_name) FROM all_mviews WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
73
73
  SQL
74
74
  end
@@ -87,11 +87,11 @@ module ActiveRecord
87
87
  end
88
88
 
89
89
  def indexes(table_name) # :nodoc:
90
- (_owner, table_name) = @connection.describe(table_name)
90
+ (_owner, table_name) = _connection.describe(table_name)
91
91
  default_tablespace_name = default_tablespace
92
92
 
93
93
  result = select_all(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
94
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
94
+ SELECT LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
95
95
  i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
96
96
  LOWER(i.tablespace_name) AS tablespace_name,
97
97
  LOWER(c.column_name) AS column_name, e.column_expression,
@@ -121,7 +121,7 @@ module ActiveRecord
121
121
  if row["index_type"] == "DOMAIN" && row["ityp_owner"] == "CTXSYS" && row["ityp_name"] == "CONTEXT"
122
122
  procedure_name = default_datastore_procedure(row["index_name"])
123
123
  source = select_values(<<~SQL.squish, "SCHEMA", [bind_string("procedure_name", procedure_name.upcase)]).join
124
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ text
124
+ SELECT text
125
125
  FROM all_source
126
126
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
127
127
  AND name = :procedure_name
@@ -276,7 +276,7 @@ module ActiveRecord
276
276
  end
277
277
 
278
278
  def insert_versions_sql(versions) # :nodoc:
279
- sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
279
+ sm_table = quote_table_name(ActiveRecord::Base.connection.schema_migration.table_name)
280
280
 
281
281
  if supports_multi_insert?
282
282
  versions.inject(+"INSERT ALL\n") { |sql, version|
@@ -300,7 +300,7 @@ module ActiveRecord
300
300
  execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})#{tablespace} #{index_options}"
301
301
  if index_type == "UNIQUE"
302
302
  unless /\(.*\)/.match?(quoted_column_names)
303
- execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(index_name)} #{index_type} (#{quoted_column_names})"
303
+ execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(index_name)} #{index_type} (#{quoted_column_names}) USING INDEX #{quote_column_name(index_name)}"
304
304
  end
305
305
  end
306
306
  end
@@ -330,6 +330,8 @@ module ActiveRecord
330
330
  # Remove the given index from the table.
331
331
  # Gives warning if index does not exist
332
332
  def remove_index(table_name, column_name = nil, **options) # :nodoc:
333
+ return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
334
+
333
335
  index_name = index_name_for_remove(table_name, column_name, options)
334
336
  # TODO: It should execute only when index_type == "UNIQUE"
335
337
  execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
@@ -366,9 +368,9 @@ module ActiveRecord
366
368
  #
367
369
  # Will always query database and not index cache.
368
370
  def index_name_exists?(table_name, index_name)
369
- (_owner, table_name) = @connection.describe(table_name)
371
+ (_owner, table_name) = _connection.describe(table_name)
370
372
  result = select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name), bind_string("index_name", index_name.to_s.upcase)])
371
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ 1 FROM all_indexes i
373
+ SELECT 1 FROM all_indexes i
372
374
  WHERE i.owner = SYS_CONTEXT('userenv', 'current_schema')
373
375
  AND i.table_owner = SYS_CONTEXT('userenv', 'current_schema')
374
376
  AND i.table_name = :table_name
@@ -509,9 +511,9 @@ module ActiveRecord
509
511
 
510
512
  def table_comment(table_name) # :nodoc:
511
513
  # TODO
512
- (_owner, table_name) = @connection.describe(table_name)
514
+ (_owner, table_name) = _connection.describe(table_name)
513
515
  select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
514
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ comments FROM all_tab_comments
516
+ SELECT comments FROM all_tab_comments
515
517
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
516
518
  AND table_name = :table_name
517
519
  SQL
@@ -525,9 +527,9 @@ module ActiveRecord
525
527
 
526
528
  def column_comment(table_name, column_name) # :nodoc:
527
529
  # TODO: it does not exist in Abstract adapter
528
- (_owner, table_name) = @connection.describe(table_name)
530
+ (_owner, table_name) = _connection.describe(table_name)
529
531
  select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name), bind_string("column_name", column_name.upcase)])
530
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ comments FROM all_col_comments
532
+ SELECT comments FROM all_col_comments
531
533
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
532
534
  AND table_name = :table_name
533
535
  AND column_name = :column_name
@@ -544,7 +546,7 @@ module ActiveRecord
544
546
 
545
547
  def tablespace(table_name)
546
548
  select_value(<<~SQL.squish, "SCHEMA")
547
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ tablespace_name
549
+ SELECT tablespace_name
548
550
  FROM all_tables
549
551
  WHERE table_name='#{table_name.to_s.upcase}'
550
552
  AND owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -553,10 +555,10 @@ module ActiveRecord
553
555
 
554
556
  # get table foreign keys for schema dump
555
557
  def foreign_keys(table_name) # :nodoc:
556
- (_owner, desc_table_name) = @connection.describe(table_name)
558
+ (_owner, desc_table_name) = _connection.describe(table_name)
557
559
 
558
560
  fk_info = select_all(<<~SQL.squish, "SCHEMA", [bind_string("desc_table_name", desc_table_name)])
559
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ r.table_name to_table
561
+ SELECT r.table_name to_table
560
562
  ,rc.column_name references_column
561
563
  ,cc.column_name
562
564
  ,c.constraint_name name
@@ -598,7 +600,7 @@ module ActiveRecord
598
600
 
599
601
  def disable_referential_integrity(&block) # :nodoc:
600
602
  old_constraints = select_all(<<~SQL.squish, "SCHEMA")
601
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ constraint_name, owner, table_name
603
+ SELECT constraint_name, owner, table_name
602
604
  FROM all_constraints
603
605
  WHERE constraint_type = 'R'
604
606
  AND status = 'ENABLED'
@@ -637,7 +639,7 @@ module ActiveRecord
637
639
  OracleEnhanced::TableDefinition.new(self, name, **options)
638
640
  end
639
641
 
640
- def new_column_from_field(table_name, field)
642
+ def new_column_from_field(table_name, field, definitions)
641
643
  limit, scale = field["limit"], field["scale"]
642
644
  if limit || scale
643
645
  field["sql_type"] += "(#{(limit || 38).to_i}" + ((scale = scale.to_i) > 0 ? ",#{scale})" : ")")
@@ -713,7 +715,7 @@ module ActiveRecord
713
715
  return unless tablespace
714
716
 
715
717
  index_name = select_value(<<~SQL.squish, "Index name for primary key", [bind_string("table_name", table_name.upcase)])
716
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ index_name FROM all_constraints
718
+ SELECT index_name FROM all_constraints
717
719
  WHERE table_name = :table_name
718
720
  AND constraint_type = 'P'
719
721
  AND owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -9,7 +9,7 @@ module ActiveRecord # :nodoc:
9
9
 
10
10
  def structure_dump # :nodoc:
11
11
  sequences = select(<<~SQL.squish, "SCHEMA")
12
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
12
+ SELECT
13
13
  sequence_name, min_value, max_value, increment_by, order_flag, cycle_flag
14
14
  FROM all_sequences
15
15
  where sequence_owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
@@ -19,7 +19,7 @@ module ActiveRecord # :nodoc:
19
19
  "CREATE SEQUENCE #{quote_table_name(result["sequence_name"])} MINVALUE #{result["min_value"]} MAXVALUE #{result["max_value"]} INCREMENT BY #{result["increment_by"]} #{result["order_flag"] == 'Y' ? "ORDER" : "NOORDER"} #{result["cycle_flag"] == 'Y' ? "CYCLE" : "NOCYCLE"}"
20
20
  end
21
21
  tables = select_values(<<~SQL.squish, "SCHEMA")
22
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ table_name FROM all_tables t
22
+ SELECT table_name FROM all_tables t
23
23
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
24
24
  AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv
25
25
  WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
@@ -31,7 +31,7 @@ module ActiveRecord # :nodoc:
31
31
  virtual_columns = virtual_columns_for(table_name) if supports_virtual_columns?
32
32
  ddl = +"CREATE#{ ' GLOBAL TEMPORARY' if temporary_table?(table_name)} TABLE \"#{table_name}\" (\n"
33
33
  columns = select_all(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
34
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ column_name, data_type, data_length, char_used, char_length,
34
+ SELECT column_name, data_type, data_length, char_used, char_length,
35
35
  data_precision, data_scale, data_default, nullable
36
36
  FROM all_tab_columns
37
37
  WHERE table_name = :table_name
@@ -92,7 +92,7 @@ module ActiveRecord # :nodoc:
92
92
  def structure_dump_primary_key(table) # :nodoc:
93
93
  opts = { name: "", cols: [] }
94
94
  pks = select_all(<<~SQL.squish, "SCHEMA")
95
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ a.constraint_name, a.column_name, a.position
95
+ SELECT a.constraint_name, a.column_name, a.position
96
96
  FROM all_cons_columns a
97
97
  JOIN all_constraints c
98
98
  ON a.constraint_name = c.constraint_name
@@ -111,7 +111,7 @@ module ActiveRecord # :nodoc:
111
111
  def structure_dump_unique_keys(table) # :nodoc:
112
112
  keys = {}
113
113
  uks = select_all(<<~SQL.squish, "SCHEMA")
114
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ a.constraint_name, a.column_name, a.position
114
+ SELECT a.constraint_name, a.column_name, a.position
115
115
  FROM all_cons_columns a
116
116
  JOIN all_constraints c
117
117
  ON a.constraint_name = c.constraint_name
@@ -147,7 +147,7 @@ module ActiveRecord # :nodoc:
147
147
 
148
148
  def structure_dump_fk_constraints # :nodoc:
149
149
  foreign_keys = select_all(<<~SQL.squish, "SCHEMA")
150
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ table_name FROM all_tables
150
+ SELECT table_name FROM all_tables
151
151
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
152
152
  SQL
153
153
  fks = foreign_keys.map do |table|
@@ -175,7 +175,7 @@ module ActiveRecord # :nodoc:
175
175
  def structure_dump_column_comments(table_name)
176
176
  comments = []
177
177
  columns = select_values(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
178
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ column_name FROM all_tab_columns
178
+ SELECT column_name FROM all_tab_columns
179
179
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
180
180
  AND table_name = :table_name ORDER BY column_id
181
181
  SQL
@@ -210,7 +210,7 @@ module ActiveRecord # :nodoc:
210
210
  def structure_dump_db_stored_code # :nodoc:
211
211
  structure = []
212
212
  all_source = select_all(<<~SQL.squish, "SCHEMA")
213
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ DISTINCT name, type
213
+ SELECT DISTINCT name, type
214
214
  FROM all_source
215
215
  WHERE type IN ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TRIGGER', 'TYPE')
216
216
  AND name NOT LIKE 'BIN$%'
@@ -219,7 +219,7 @@ module ActiveRecord # :nodoc:
219
219
  all_source.each do |source|
220
220
  ddl = +"CREATE OR REPLACE \n"
221
221
  texts = select_all(<<~SQL.squish, "all source at structure dump", [bind_string("source_name", source["name"]), bind_string("source_type", source["type"])])
222
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ text
222
+ SELECT text
223
223
  FROM all_source
224
224
  WHERE name = :source_name
225
225
  AND type = :source_type
@@ -242,7 +242,7 @@ module ActiveRecord # :nodoc:
242
242
  def structure_dump_views # :nodoc:
243
243
  structure = []
244
244
  views = select_all(<<~SQL.squish, "SCHEMA")
245
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ view_name, text FROM all_views
245
+ SELECT view_name, text FROM all_views
246
246
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY view_name ASC
247
247
  SQL
248
248
  views.each do |view|
@@ -254,7 +254,7 @@ module ActiveRecord # :nodoc:
254
254
  def structure_dump_synonyms # :nodoc:
255
255
  structure = []
256
256
  synonyms = select_all(<<~SQL.squish, "SCHEMA")
257
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ owner, synonym_name, table_name, table_owner
257
+ SELECT owner, synonym_name, table_name, table_owner
258
258
  FROM all_synonyms
259
259
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
260
260
  SQL
@@ -267,14 +267,14 @@ module ActiveRecord # :nodoc:
267
267
 
268
268
  def structure_drop # :nodoc:
269
269
  sequences = select_values(<<~SQL.squish, "SCHEMA")
270
- SELECT/*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
270
+ SELECT
271
271
  sequence_name FROM all_sequences where sequence_owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
272
272
  SQL
273
273
  statements = sequences.map do |seq|
274
274
  "DROP SEQUENCE \"#{seq}\""
275
275
  end
276
276
  tables = select_values(<<~SQL.squish, "SCHEMA")
277
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ table_name from all_tables t
277
+ SELECT table_name from all_tables t
278
278
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
279
279
  AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv
280
280
  WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
@@ -290,7 +290,7 @@ module ActiveRecord # :nodoc:
290
290
 
291
291
  def temp_table_drop # :nodoc:
292
292
  temporary_tables = select_values(<<~SQL.squish, "SCHEMA")
293
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ table_name FROM all_tables
293
+ SELECT table_name FROM all_tables
294
294
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
295
295
  AND secondary = 'N' AND temporary = 'Y' ORDER BY 1
296
296
  SQL
@@ -324,7 +324,7 @@ module ActiveRecord # :nodoc:
324
324
  # return [{'column_name' => 'FOOS', 'data_default' => '...'}, ...]
325
325
  def virtual_columns_for(table)
326
326
  select_all(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table.upcase)])
327
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ column_name, data_default
327
+ SELECT column_name, data_default
328
328
  FROM all_tab_cols
329
329
  WHERE virtual_column = 'YES'
330
330
  AND owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -335,7 +335,7 @@ module ActiveRecord # :nodoc:
335
335
  def drop_sql_for_feature(type)
336
336
  short_type = type == "materialized view" ? "mview" : type
337
337
  features = select_values(<<~SQL.squish, "SCHEMA")
338
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ #{short_type}_name FROM all_#{short_type.tableize}
338
+ SELECT #{short_type}_name FROM all_#{short_type.tableize}
339
339
  where owner = SYS_CONTEXT('userenv', 'current_schema')
340
340
  SQL
341
341
  statements = features.map do |name|
@@ -346,7 +346,7 @@ module ActiveRecord # :nodoc:
346
346
 
347
347
  def drop_sql_for_object(type)
348
348
  objects = select_values(<<~SQL.squish, "SCHEMA")
349
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ object_name FROM all_objects
349
+ SELECT object_name FROM all_objects
350
350
  WHERE object_type = '#{type.upcase}' and owner = SYS_CONTEXT('userenv', 'current_schema')
351
351
  SQL
352
352
  statements = objects.map do |name|
@@ -121,6 +121,12 @@ module ActiveRecord
121
121
  # * <tt>:tcp_keepalive</tt> - TCP keepalive is enabled for OCI client, defaults to true
122
122
  # * <tt>:tcp_keepalive_time</tt> - TCP keepalive time for OCI client, defaults to 600
123
123
  # * <tt>:jdbc_statement_cache_size</tt> - number of cached SQL cursors to keep open, disabled per default (for unpooled JDBC only)
124
+ # * <tt>:jdbc_connect_properties</tt> - Additional properties for establishing Oracle JDBC connection (for unpooled JDBC only)
125
+ # example to require encryption and checksumming for network connection:
126
+ # adapter: oracle_enhanced
127
+ # jdbc_connect_properties:
128
+ # 'oracle.net.encryption_client': REQUIRED
129
+ # 'oracle.net.crypto_checksum_client': REQUIRED
124
130
  #
125
131
  # Optionals NLS parameters:
126
132
  #
@@ -240,8 +246,10 @@ module ActiveRecord
240
246
  end
241
247
  end
242
248
 
243
- def initialize(connection, logger = nil, config = {}) # :nodoc:
244
- super(connection, logger, config)
249
+ def initialize(config_or_deprecated_connection, deprecated_logger = nil, deprecated_connection_options = nil, deprecated_config = nil) # :nodoc:
250
+ super(config_or_deprecated_connection, deprecated_logger, deprecated_connection_options, deprecated_config)
251
+
252
+ @raw_connection = ConnectionAdapters::OracleEnhanced::Connection.create(@config)
245
253
  @enable_dbms_output = false
246
254
  @do_not_prefetch_primary_key = {}
247
255
  @columns_cache = {}
@@ -269,6 +277,11 @@ module ActiveRecord
269
277
  end
270
278
  end
271
279
 
280
+ def return_value_after_insert?(column) # :nodoc:
281
+ # TODO: Return true if there this column will be populated (e.g by a sequence)
282
+ super
283
+ end
284
+
272
285
  def build_statement_pool
273
286
  StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
274
287
  end
@@ -298,11 +311,12 @@ module ActiveRecord
298
311
  end
299
312
 
300
313
  def supports_fetch_first_n_rows_and_offset?
301
- if !use_old_oracle_visitor && database_version.first >= 12
302
- true
303
- else
304
- false
305
- end
314
+ false
315
+
316
+ # TODO: At this point the connection is not initialized yet,
317
+ # so `database_version` raises an error
318
+ #
319
+ # !use_old_oracle_visitor && database_version.first >= 12
306
320
  end
307
321
 
308
322
  def supports_datetime_with_precision?
@@ -426,12 +440,13 @@ module ActiveRecord
426
440
 
427
441
  def auto_retry=(value) # :nodoc:
428
442
  @auto_retry = value
429
- @connection.auto_retry = value if @connection
443
+ _connection.auto_retry = value if _connection
430
444
  end
431
445
 
432
446
  # return raw OCI8 or JDBC connection
433
447
  def raw_connection
434
- @connection.raw_connection
448
+ verify!
449
+ _connection.raw_connection
435
450
  end
436
451
 
437
452
  # Returns true if the connection is active.
@@ -440,19 +455,30 @@ module ActiveRecord
440
455
  # #active? method is also available, but that simply returns the
441
456
  # last known state, which isn't good enough if the connection has
442
457
  # gone stale since the last use.
443
- @connection.ping
458
+ _connection.ping
444
459
  rescue OracleEnhanced::ConnectionException
445
460
  false
446
461
  end
447
462
 
463
+ def reconnect
464
+ _connection.reset # tentative
465
+ rescue OracleEnhanced::ConnectionException
466
+ connect
467
+ end
468
+
448
469
  # Reconnects to the database.
449
470
  def reconnect! # :nodoc:
450
471
  super
451
- @connection.reset!
472
+ _connection.reset!
452
473
  rescue OracleEnhanced::ConnectionException => e
453
474
  @logger.warn "#{adapter_name} automatic reconnection failed: #{e.message}" if @logger
454
475
  end
455
476
 
477
+ def clear_cache!(*args, **kwargs)
478
+ super
479
+ self.class.clear_type_map!
480
+ end
481
+
456
482
  def reset!
457
483
  clear_cache!
458
484
  super
@@ -461,12 +487,12 @@ module ActiveRecord
461
487
  # Disconnects from the database.
462
488
  def disconnect! # :nodoc:
463
489
  super
464
- @connection.logoff rescue nil
490
+ _connection.logoff rescue nil
465
491
  end
466
492
 
467
493
  def discard!
468
494
  super
469
- @connection = nil
495
+ _connection = nil
470
496
  end
471
497
 
472
498
  # use in set_sequence_name to avoid fetching primary key value from sequence
@@ -491,7 +517,7 @@ module ActiveRecord
491
517
  table_name = table_name.to_s
492
518
  do_not_prefetch = @do_not_prefetch_primary_key[table_name]
493
519
  if do_not_prefetch.nil?
494
- owner, desc_table_name = @connection.describe(table_name)
520
+ owner, desc_table_name = _connection.describe(table_name)
495
521
  @do_not_prefetch_primary_key[table_name] = do_not_prefetch = !has_primary_key?(table_name, owner, desc_table_name)
496
522
  end
497
523
  !do_not_prefetch
@@ -554,16 +580,16 @@ module ActiveRecord
554
580
  # Default tablespace name of current user
555
581
  def default_tablespace
556
582
  select_value(<<~SQL.squish, "SCHEMA")
557
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ LOWER(default_tablespace) FROM user_users
583
+ SELECT LOWER(default_tablespace) FROM user_users
558
584
  WHERE username = SYS_CONTEXT('userenv', 'current_schema')
559
585
  SQL
560
586
  end
561
587
 
562
588
  def column_definitions(table_name)
563
- (owner, desc_table_name) = @connection.describe(table_name)
589
+ (owner, desc_table_name) = _connection.describe(table_name)
564
590
 
565
591
  select_all(<<~SQL.squish, "SCHEMA", [bind_string("owner", owner), bind_string("table_name", desc_table_name)])
566
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cols.column_name AS name, cols.data_type AS sql_type,
592
+ SELECT cols.column_name AS name, cols.data_type AS sql_type,
567
593
  cols.data_default, cols.nullable, cols.virtual_column, cols.hidden_column,
568
594
  cols.data_type_owner AS sql_type_owner,
569
595
  DECODE(cols.data_type, 'NUMBER', data_precision,
@@ -592,10 +618,10 @@ module ActiveRecord
592
618
  # Find a table's primary key and sequence.
593
619
  # *Note*: Only primary key is implemented - sequence will be nil.
594
620
  def pk_and_sequence_for(table_name, owner = nil, desc_table_name = nil) # :nodoc:
595
- (owner, desc_table_name) = @connection.describe(table_name)
621
+ (owner, desc_table_name) = _connection.describe(table_name)
596
622
 
597
623
  seqs = select_values_forcing_binds(<<~SQL.squish, "SCHEMA", [bind_string("owner", owner), bind_string("sequence_name", default_sequence_name(desc_table_name))])
598
- select /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ us.sequence_name
624
+ select us.sequence_name
599
625
  from all_sequences us
600
626
  where us.sequence_owner = :owner
601
627
  and us.sequence_name = upper(:sequence_name)
@@ -603,7 +629,7 @@ module ActiveRecord
603
629
 
604
630
  # changed back from user_constraints to all_constraints for consistency
605
631
  pks = select_values_forcing_binds(<<~SQL.squish, "SCHEMA", [bind_string("owner", owner), bind_string("table_name", desc_table_name)])
606
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cc.column_name
632
+ SELECT cc.column_name
607
633
  FROM all_constraints c, all_cons_columns cc
608
634
  WHERE c.owner = :owner
609
635
  AND c.table_name = :table_name
@@ -634,10 +660,10 @@ module ActiveRecord
634
660
  end
635
661
 
636
662
  def primary_keys(table_name) # :nodoc:
637
- (_owner, desc_table_name) = @connection.describe(table_name)
663
+ (_owner, desc_table_name) = _connection.describe(table_name)
638
664
 
639
665
  pks = select_values_forcing_binds(<<~SQL.squish, "SCHEMA", [bind_string("table_name", desc_table_name)])
640
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cc.column_name
666
+ SELECT cc.column_name
641
667
  FROM all_constraints c, all_cons_columns cc
642
668
  WHERE c.owner = SYS_CONTEXT('userenv', 'current_schema')
643
669
  AND c.table_name = :table_name
@@ -662,12 +688,12 @@ module ActiveRecord
662
688
  }.reject(&:blank?).map.with_index { |column, i|
663
689
  "FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns} ORDER BY #{column}) AS alias_#{i}__"
664
690
  }
665
- [super, *order_columns].join(", ")
691
+ (order_columns << super).join(", ")
666
692
  end
667
693
 
668
694
  def temporary_table?(table_name) # :nodoc:
669
695
  select_value_forcing_binds(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name.upcase)]) == "Y"
670
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
696
+ SELECT
671
697
  temporary FROM all_tables WHERE table_name = :table_name and owner = SYS_CONTEXT('userenv', 'current_schema')
672
698
  SQL
673
699
  end
@@ -678,8 +704,14 @@ module ActiveRecord
678
704
  alias table_alias_length max_identifier_length
679
705
  alias index_name_length max_identifier_length
680
706
 
707
+ # This is to ensure rails is not shortening the index name,
708
+ # in order to preserve the local shortening behavior.
709
+ def max_index_name_size
710
+ 128
711
+ end
712
+
681
713
  def get_database_version
682
- @connection.database_version
714
+ _connection.database_version
683
715
  end
684
716
 
685
717
  def check_version
@@ -690,7 +722,20 @@ module ActiveRecord
690
722
  end
691
723
  end
692
724
 
725
+ private def _connection
726
+ @unconfigured_connection || @raw_connection
727
+ end
728
+
693
729
  class << self
730
+ def type_map
731
+ @type_map ||= Type::TypeMap.new.tap { |m| initialize_type_map(m) }
732
+ @type_map
733
+ end
734
+
735
+ def clear_type_map!
736
+ @type_map = nil
737
+ end
738
+
694
739
  private
695
740
  def initialize_type_map(m)
696
741
  super
@@ -724,10 +769,8 @@ module ActiveRecord
724
769
  end
725
770
  end
726
771
 
727
- TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
728
-
729
772
  def type_map
730
- TYPE_MAP
773
+ self.class.type_map
731
774
  end
732
775
 
733
776
  def extract_value_from_default(default)
@@ -749,7 +792,7 @@ module ActiveRecord
749
792
  end
750
793
 
751
794
  def translate_exception(exception, message:, sql:, binds:) # :nodoc:
752
- case @connection.error_code(exception)
795
+ case _connection.error_code(exception)
753
796
  when 1
754
797
  RecordNotUnique.new(message, sql: sql, binds: binds)
755
798
  when 60
@@ -10,6 +10,14 @@ if defined?(Rails)
10
10
 
11
11
  ActiveSupport.on_load(:active_record) do
12
12
  require "active_record/connection_adapters/oracle_enhanced_adapter"
13
+
14
+ if ActiveRecord::ConnectionAdapters.respond_to?(:register)
15
+ ActiveRecord::ConnectionAdapters.register(
16
+ "oracle_enhanced",
17
+ "ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter",
18
+ "active_record/connection_adapters/oracle_enhanced_adapter"
19
+ )
20
+ end
13
21
  end
14
22
  end
15
23
  end
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "oracle_common"
4
+
3
5
  module Arel # :nodoc: all
4
6
  module Visitors
5
7
  class Oracle < Arel::Visitors::ToSql
8
+ include OracleCommon
9
+
6
10
  private
7
11
  def visit_Arel_Nodes_SelectStatement(o, collector)
8
12
  o = order_hacks(o)
@@ -92,7 +96,6 @@ module Arel # :nodoc: all
92
96
  def visit_Arel_Nodes_HomogeneousIn(o, collector)
93
97
  in_clause_length = @connection.in_clause_length
94
98
  values = o.casted_values.map { |v| @connection.quote(v) }
95
- column_name = quote_table_name(o.table_name) + "." + quote_column_name(o.column_name)
96
99
  operator =
97
100
  if o.type == :in
98
101
  " IN ("
@@ -101,7 +104,7 @@ module Arel # :nodoc: all
101
104
  end
102
105
 
103
106
  if !Array === values || values.length <= in_clause_length
104
- collector << column_name
107
+ visit o.left, collector
105
108
  collector << operator
106
109
 
107
110
  expr =
@@ -123,7 +126,7 @@ module Arel # :nodoc: all
123
126
  collector << "("
124
127
  values.each_slice(in_clause_length).each_with_index do |valuez, i|
125
128
  collector << separator unless i == 0
126
- collector << column_name
129
+ visit o.left, collector
127
130
  collector << operator
128
131
  collector << valuez.join(",")
129
132
  collector << ")"