activerecord-oracle_enhanced-adapter 6.0.4 → 6.1.1
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.
- checksums.yaml +4 -4
- data/History.md +108 -0
- data/README.md +12 -1
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +2 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +0 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +0 -9
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +9 -7
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +4 -5
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +0 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +3 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +1 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +2 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +0 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +2 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +2 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +16 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +58 -52
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +38 -36
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +2 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +64 -21
- data/lib/active_record/type/oracle_enhanced/boolean.rb +0 -1
- data/lib/active_record/type/oracle_enhanced/integer.rb +0 -1
- data/lib/arel/visitors/oracle.rb +217 -0
- data/lib/arel/visitors/oracle12.rb +124 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +9 -3
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +6 -1
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +0 -1
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +27 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +161 -0
- data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +4 -2
- data/spec/spec_config.yaml.template +2 -2
- data/spec/spec_helper.rb +13 -2
- metadata +25 -23
@@ -4,6 +4,8 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters #:nodoc:
|
5
5
|
module OracleEnhanced
|
6
6
|
class TypeMetadata < DelegateClass(ActiveRecord::ConnectionAdapters::SqlTypeMetadata) # :nodoc:
|
7
|
+
include Deduplicable
|
8
|
+
|
7
9
|
attr_reader :virtual
|
8
10
|
|
9
11
|
def initialize(type_metadata, virtual: nil)
|
@@ -23,7 +25,6 @@ module ActiveRecord
|
|
23
25
|
end
|
24
26
|
|
25
27
|
protected
|
26
|
-
|
27
28
|
def attributes_for_hash
|
28
29
|
[self.class, @type_metadata, virtual]
|
29
30
|
end
|
@@ -30,6 +30,9 @@
|
|
30
30
|
# contribution.
|
31
31
|
# portions Copyright 2005 Graham Jenkins
|
32
32
|
|
33
|
+
require "arel/visitors/oracle"
|
34
|
+
require "arel/visitors/oracle12"
|
35
|
+
require "active_record/connection_adapters"
|
33
36
|
require "active_record/connection_adapters/abstract_adapter"
|
34
37
|
require "active_record/connection_adapters/statement_pool"
|
35
38
|
require "active_record/connection_adapters/oracle_enhanced/connection"
|
@@ -213,13 +216,24 @@ module ActiveRecord
|
|
213
216
|
cattr_accessor :use_shorter_identifier
|
214
217
|
self.use_shorter_identifier = false
|
215
218
|
|
219
|
+
##
|
220
|
+
# :singleton-method:
|
221
|
+
# By default, OracleEnhanced adapter will grant unlimited tablespace, create session, create table, create view,
|
222
|
+
# and create sequence when running the rake task db:create.
|
223
|
+
#
|
224
|
+
# If you wish to change these permissions you can add the following line to your initializer file:
|
225
|
+
#
|
226
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.permissions =
|
227
|
+
# ["create session", "create table", "create view", "create sequence", "create trigger", "ctxapp"]
|
228
|
+
cattr_accessor :permissions
|
229
|
+
self.permissions = ["create session", "create table", "create view", "create sequence"]
|
230
|
+
|
216
231
|
##
|
217
232
|
# :singleton-method:
|
218
233
|
# Specify default sequence start with value (by default 1 if not explicitly set), e.g.:
|
219
234
|
|
220
235
|
class StatementPool < ConnectionAdapters::StatementPool
|
221
236
|
private
|
222
|
-
|
223
237
|
def dealloc(stmt)
|
224
238
|
stmt.close
|
225
239
|
end
|
@@ -238,6 +252,14 @@ module ActiveRecord
|
|
238
252
|
ADAPTER_NAME
|
239
253
|
end
|
240
254
|
|
255
|
+
# Oracle enhanced adapter has no implementation because
|
256
|
+
# Oracle Database cannot detect `NoDatabaseError`.
|
257
|
+
# Please refer to the following discussion for details.
|
258
|
+
# https://github.com/rsim/oracle-enhanced/pull/1900
|
259
|
+
def self.database_exists?(config)
|
260
|
+
raise NotImplementedError
|
261
|
+
end
|
262
|
+
|
241
263
|
def arel_visitor # :nodoc:
|
242
264
|
if supports_fetch_first_n_rows_and_offset?
|
243
265
|
Arel::Visitors::Oracle12.new(self)
|
@@ -266,6 +288,10 @@ module ActiveRecord
|
|
266
288
|
true
|
267
289
|
end
|
268
290
|
|
291
|
+
def supports_common_table_expressions?
|
292
|
+
true
|
293
|
+
end
|
294
|
+
|
269
295
|
def supports_views?
|
270
296
|
true
|
271
297
|
end
|
@@ -438,6 +464,7 @@ module ActiveRecord
|
|
438
464
|
end
|
439
465
|
|
440
466
|
def discard!
|
467
|
+
super
|
441
468
|
@connection = nil
|
442
469
|
end
|
443
470
|
|
@@ -449,9 +476,9 @@ module ActiveRecord
|
|
449
476
|
# when inserting a new database record (see #prefetch_primary_key?).
|
450
477
|
def next_sequence_value(sequence_name)
|
451
478
|
# if sequence_name is set to :autogenerated then it means that primary key will be populated by trigger
|
452
|
-
raise ArgumentError "Trigger based primary key is not supported" if sequence_name == AUTOGENERATED_SEQUENCE_NAME
|
479
|
+
raise ArgumentError.new "Trigger based primary key is not supported" if sequence_name == AUTOGENERATED_SEQUENCE_NAME
|
453
480
|
# call directly connection method to avoid prepared statement which causes fetching of next sequence value twice
|
454
|
-
select_value(<<~SQL.squish, "
|
481
|
+
select_value(<<~SQL.squish, "SCHEMA")
|
455
482
|
SELECT #{quote_table_name(sequence_name)}.NEXTVAL FROM dual
|
456
483
|
SQL
|
457
484
|
end
|
@@ -489,7 +516,7 @@ module ActiveRecord
|
|
489
516
|
end
|
490
517
|
|
491
518
|
if primary_key && sequence_name
|
492
|
-
new_start_value = select_value(<<~SQL.squish, "
|
519
|
+
new_start_value = select_value(<<~SQL.squish, "SCHEMA")
|
493
520
|
select NVL(max(#{quote_column_name(primary_key)}),0) + 1 from #{quote_table_name(table_name)}
|
494
521
|
SQL
|
495
522
|
|
@@ -500,33 +527,33 @@ module ActiveRecord
|
|
500
527
|
|
501
528
|
# Current database name
|
502
529
|
def current_database
|
503
|
-
select_value(<<~SQL.squish, "
|
530
|
+
select_value(<<~SQL.squish, "SCHEMA")
|
504
531
|
SELECT SYS_CONTEXT('userenv', 'con_name') FROM dual
|
505
532
|
SQL
|
506
533
|
rescue ActiveRecord::StatementInvalid
|
507
|
-
select_value(<<~SQL.squish, "
|
534
|
+
select_value(<<~SQL.squish, "SCHEMA")
|
508
535
|
SELECT SYS_CONTEXT('userenv', 'db_name') FROM dual
|
509
536
|
SQL
|
510
537
|
end
|
511
538
|
|
512
539
|
# Current database session user
|
513
540
|
def current_user
|
514
|
-
select_value(<<~SQL.squish, "
|
541
|
+
select_value(<<~SQL.squish, "SCHEMA")
|
515
542
|
SELECT SYS_CONTEXT('userenv', 'session_user') FROM dual
|
516
543
|
SQL
|
517
544
|
end
|
518
545
|
|
519
546
|
# Current database session schema
|
520
547
|
def current_schema
|
521
|
-
select_value(<<~SQL.squish, "
|
548
|
+
select_value(<<~SQL.squish, "SCHEMA")
|
522
549
|
SELECT SYS_CONTEXT('userenv', 'current_schema') FROM dual
|
523
550
|
SQL
|
524
551
|
end
|
525
552
|
|
526
553
|
# Default tablespace name of current user
|
527
554
|
def default_tablespace
|
528
|
-
select_value(<<~SQL.squish, "
|
529
|
-
SELECT LOWER(default_tablespace) FROM user_users
|
555
|
+
select_value(<<~SQL.squish, "SCHEMA")
|
556
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ LOWER(default_tablespace) FROM user_users
|
530
557
|
WHERE username = SYS_CONTEXT('userenv', 'current_schema')
|
531
558
|
SQL
|
532
559
|
end
|
@@ -534,8 +561,8 @@ module ActiveRecord
|
|
534
561
|
def column_definitions(table_name)
|
535
562
|
(owner, desc_table_name) = @connection.describe(table_name)
|
536
563
|
|
537
|
-
select_all(<<~SQL.squish, "
|
538
|
-
SELECT cols.column_name AS name, cols.data_type AS sql_type,
|
564
|
+
select_all(<<~SQL.squish, "SCHEMA")
|
565
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cols.column_name AS name, cols.data_type AS sql_type,
|
539
566
|
cols.data_default, cols.nullable, cols.virtual_column, cols.hidden_column,
|
540
567
|
cols.data_type_owner AS sql_type_owner,
|
541
568
|
DECODE(cols.data_type, 'NUMBER', data_precision,
|
@@ -566,16 +593,16 @@ module ActiveRecord
|
|
566
593
|
def pk_and_sequence_for(table_name, owner = nil, desc_table_name = nil) #:nodoc:
|
567
594
|
(owner, desc_table_name) = @connection.describe(table_name)
|
568
595
|
|
569
|
-
seqs = select_values(<<~SQL.squish, "
|
570
|
-
select us.sequence_name
|
596
|
+
seqs = select_values(<<~SQL.squish, "SCHEMA")
|
597
|
+
select /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ us.sequence_name
|
571
598
|
from all_sequences us
|
572
599
|
where us.sequence_owner = '#{owner}'
|
573
600
|
and us.sequence_name = upper(#{quote(default_sequence_name(desc_table_name))})
|
574
601
|
SQL
|
575
602
|
|
576
603
|
# changed back from user_constraints to all_constraints for consistency
|
577
|
-
pks = select_values(<<~SQL.squish, "
|
578
|
-
SELECT cc.column_name
|
604
|
+
pks = select_values(<<~SQL.squish, "SCHEMA")
|
605
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cc.column_name
|
579
606
|
FROM all_constraints c, all_cons_columns cc
|
580
607
|
WHERE c.owner = '#{owner}'
|
581
608
|
AND c.table_name = #{quote(desc_table_name)}
|
@@ -608,8 +635,8 @@ module ActiveRecord
|
|
608
635
|
def primary_keys(table_name) # :nodoc:
|
609
636
|
(_owner, desc_table_name) = @connection.describe(table_name)
|
610
637
|
|
611
|
-
pks = select_values(<<~SQL.squish, "
|
612
|
-
SELECT cc.column_name
|
638
|
+
pks = select_values(<<~SQL.squish, "SCHEMA", [bind_string("table_name", desc_table_name)])
|
639
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cc.column_name
|
613
640
|
FROM all_constraints c, all_cons_columns cc
|
614
641
|
WHERE c.owner = SYS_CONTEXT('userenv', 'current_schema')
|
615
642
|
AND c.table_name = :table_name
|
@@ -628,7 +655,7 @@ module ActiveRecord
|
|
628
655
|
#
|
629
656
|
# It does not construct DISTINCT clause. Just return column names for distinct.
|
630
657
|
order_columns = orders.reject(&:blank?).map { |s|
|
631
|
-
s = s
|
658
|
+
s = visitor.compile(s) unless s.is_a?(String)
|
632
659
|
# remove any ASC/DESC modifiers
|
633
660
|
s.gsub(/\s+(ASC|DESC)\s*?/i, "")
|
634
661
|
}.reject(&:blank?).map.with_index { |column, i|
|
@@ -638,8 +665,9 @@ module ActiveRecord
|
|
638
665
|
end
|
639
666
|
|
640
667
|
def temporary_table?(table_name) #:nodoc:
|
641
|
-
select_value(<<~SQL.squish, "
|
642
|
-
SELECT
|
668
|
+
select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name.upcase)]) == "Y"
|
669
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
|
670
|
+
temporary FROM all_tables WHERE table_name = :table_name and owner = SYS_CONTEXT('userenv', 'current_schema')
|
643
671
|
SQL
|
644
672
|
end
|
645
673
|
|
@@ -746,3 +774,18 @@ require "active_record/connection_adapters/oracle_enhanced/version"
|
|
746
774
|
module ActiveRecord
|
747
775
|
autoload :OracleEnhancedProcedures, "active_record/connection_adapters/oracle_enhanced/procedures"
|
748
776
|
end
|
777
|
+
|
778
|
+
# Workaround for https://github.com/jruby/jruby/issues/6267
|
779
|
+
if RUBY_ENGINE == "jruby"
|
780
|
+
require "jruby"
|
781
|
+
|
782
|
+
class org.jruby::RubyObjectSpace::WeakMap
|
783
|
+
field_reader :map
|
784
|
+
end
|
785
|
+
|
786
|
+
class ObjectSpace::WeakMap
|
787
|
+
def values
|
788
|
+
JRuby.ref(self).map.values.reject(&:nil?)
|
789
|
+
end
|
790
|
+
end
|
791
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
module Visitors
|
5
|
+
class Oracle < Arel::Visitors::ToSql
|
6
|
+
private
|
7
|
+
def visit_Arel_Nodes_SelectStatement(o, collector)
|
8
|
+
o = order_hacks(o)
|
9
|
+
|
10
|
+
# if need to select first records without ORDER BY and GROUP BY and without DISTINCT
|
11
|
+
# then can use simple ROWNUM in WHERE clause
|
12
|
+
if o.limit && o.orders.empty? && o.cores.first.groups.empty? && !o.offset && !o.cores.first.set_quantifier.class.to_s.match?(/Distinct/)
|
13
|
+
o.cores.last.wheres.push Nodes::LessThanOrEqual.new(
|
14
|
+
Nodes::SqlLiteral.new("ROWNUM"), o.limit.expr
|
15
|
+
)
|
16
|
+
return super
|
17
|
+
end
|
18
|
+
|
19
|
+
if o.limit && o.offset
|
20
|
+
o = o.dup
|
21
|
+
limit = o.limit.expr
|
22
|
+
offset = o.offset
|
23
|
+
o.offset = nil
|
24
|
+
collector << "
|
25
|
+
SELECT * FROM (
|
26
|
+
SELECT raw_sql_.*, rownum raw_rnum_
|
27
|
+
FROM ("
|
28
|
+
|
29
|
+
collector = super(o, collector)
|
30
|
+
|
31
|
+
if offset.expr.is_a? Nodes::BindParam
|
32
|
+
collector << ") raw_sql_ WHERE rownum <= ("
|
33
|
+
collector = visit offset.expr, collector
|
34
|
+
collector << " + "
|
35
|
+
collector = visit limit, collector
|
36
|
+
collector << ") ) WHERE raw_rnum_ > "
|
37
|
+
collector = visit offset.expr, collector
|
38
|
+
return collector
|
39
|
+
else
|
40
|
+
collector << ") raw_sql_
|
41
|
+
WHERE rownum <= #{offset.expr.to_i + limit}
|
42
|
+
)
|
43
|
+
WHERE "
|
44
|
+
return visit(offset, collector)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if o.limit
|
49
|
+
o = o.dup
|
50
|
+
limit = o.limit.expr
|
51
|
+
collector << "SELECT * FROM ("
|
52
|
+
collector = super(o, collector)
|
53
|
+
collector << ") WHERE ROWNUM <= "
|
54
|
+
return visit limit, collector
|
55
|
+
end
|
56
|
+
|
57
|
+
if o.offset
|
58
|
+
o = o.dup
|
59
|
+
offset = o.offset
|
60
|
+
o.offset = nil
|
61
|
+
collector << "SELECT * FROM (
|
62
|
+
SELECT raw_sql_.*, rownum raw_rnum_
|
63
|
+
FROM ("
|
64
|
+
collector = super(o, collector)
|
65
|
+
collector << ") raw_sql_
|
66
|
+
)
|
67
|
+
WHERE "
|
68
|
+
return visit offset, collector
|
69
|
+
end
|
70
|
+
|
71
|
+
super
|
72
|
+
end
|
73
|
+
|
74
|
+
def visit_Arel_Nodes_Limit(o, collector)
|
75
|
+
collector
|
76
|
+
end
|
77
|
+
|
78
|
+
def visit_Arel_Nodes_Offset(o, collector)
|
79
|
+
collector << "raw_rnum_ > "
|
80
|
+
visit o.expr, collector
|
81
|
+
end
|
82
|
+
|
83
|
+
def visit_Arel_Nodes_Except(o, collector)
|
84
|
+
collector << "( "
|
85
|
+
collector = infix_value o, collector, " MINUS "
|
86
|
+
collector << " )"
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# To avoid ORA-01795: maximum number of expressions in a list is 1000
|
91
|
+
# tell ActiveRecord to limit us to 1000 ids at a time
|
92
|
+
def visit_Arel_Nodes_HomogeneousIn(o, collector)
|
93
|
+
in_clause_length = @connection.in_clause_length
|
94
|
+
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
|
+
operator =
|
97
|
+
if o.type == :in
|
98
|
+
" IN ("
|
99
|
+
else
|
100
|
+
" NOT IN ("
|
101
|
+
end
|
102
|
+
|
103
|
+
if !Array === values || values.length <= in_clause_length
|
104
|
+
collector << column_name
|
105
|
+
collector << operator
|
106
|
+
|
107
|
+
expr =
|
108
|
+
if values.empty?
|
109
|
+
@connection.quote(nil)
|
110
|
+
else
|
111
|
+
values.join(",")
|
112
|
+
end
|
113
|
+
|
114
|
+
collector << expr
|
115
|
+
collector << ")"
|
116
|
+
else
|
117
|
+
separator =
|
118
|
+
if o.type == :in
|
119
|
+
" OR "
|
120
|
+
else
|
121
|
+
" AND "
|
122
|
+
end
|
123
|
+
collector << "("
|
124
|
+
values.each_slice(in_clause_length).each_with_index do |valuez, i|
|
125
|
+
collector << separator unless i == 0
|
126
|
+
collector << column_name
|
127
|
+
collector << operator
|
128
|
+
collector << valuez.join(",")
|
129
|
+
collector << ")"
|
130
|
+
end
|
131
|
+
collector << ")"
|
132
|
+
end
|
133
|
+
|
134
|
+
collector
|
135
|
+
end
|
136
|
+
|
137
|
+
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
138
|
+
# Oracle does not allow ORDER BY/LIMIT in UPDATEs.
|
139
|
+
if o.orders.any? && o.limit.nil?
|
140
|
+
# However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided,
|
141
|
+
# otherwise let the user deal with the error
|
142
|
+
o = o.dup
|
143
|
+
o.orders = []
|
144
|
+
end
|
145
|
+
|
146
|
+
super
|
147
|
+
end
|
148
|
+
|
149
|
+
###
|
150
|
+
# Hacks for the order clauses specific to Oracle
|
151
|
+
def order_hacks(o)
|
152
|
+
return o if o.orders.empty?
|
153
|
+
return o unless o.cores.any? do |core|
|
154
|
+
core.projections.any? do |projection|
|
155
|
+
/FIRST_VALUE/ === projection
|
156
|
+
end
|
157
|
+
end
|
158
|
+
# Previous version with join and split broke ORDER BY clause
|
159
|
+
# if it contained functions with several arguments (separated by ',').
|
160
|
+
#
|
161
|
+
# orders = o.orders.map { |x| visit x }.join(', ').split(',')
|
162
|
+
orders = o.orders.map do |x|
|
163
|
+
string = visit(x, Arel::Collectors::SQLString.new).value
|
164
|
+
if string.include?(",")
|
165
|
+
split_order_string(string)
|
166
|
+
else
|
167
|
+
string
|
168
|
+
end
|
169
|
+
end.flatten
|
170
|
+
o.orders = []
|
171
|
+
orders.each_with_index do |order, i|
|
172
|
+
o.orders <<
|
173
|
+
Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i.match?(order)}")
|
174
|
+
end
|
175
|
+
o
|
176
|
+
end
|
177
|
+
|
178
|
+
# Split string by commas but count opening and closing brackets
|
179
|
+
# and ignore commas inside brackets.
|
180
|
+
def split_order_string(string)
|
181
|
+
array = []
|
182
|
+
i = 0
|
183
|
+
string.split(",").each do |part|
|
184
|
+
if array[i]
|
185
|
+
array[i] << "," << part
|
186
|
+
else
|
187
|
+
# to ensure that array[i] will be String and not Arel::Nodes::SqlLiteral
|
188
|
+
array[i] = part.to_s
|
189
|
+
end
|
190
|
+
i += 1 if array[i].count("(") == array[i].count(")")
|
191
|
+
end
|
192
|
+
array
|
193
|
+
end
|
194
|
+
|
195
|
+
def visit_Arel_Nodes_BindParam(o, collector)
|
196
|
+
collector.add_bind(o.value) { |i| ":a#{i}" }
|
197
|
+
end
|
198
|
+
|
199
|
+
def is_distinct_from(o, collector)
|
200
|
+
collector << "DECODE("
|
201
|
+
collector = visit [o.left, o.right, 0, 1], collector
|
202
|
+
collector << ")"
|
203
|
+
end
|
204
|
+
|
205
|
+
# Oracle will occur an error `ORA-00907: missing right parenthesis`
|
206
|
+
# when using `ORDER BY` in `UPDATE` or `DELETE`'s subquery.
|
207
|
+
#
|
208
|
+
# This method has been overridden based on the following code.
|
209
|
+
# https://github.com/rails/rails/blob/v6.1.0.rc1/activerecord/lib/arel/visitors/to_sql.rb#L815-L825
|
210
|
+
def build_subselect(key, o)
|
211
|
+
stmt = super
|
212
|
+
stmt.orders = [] # `orders` will never be set to prevent `ORA-00907`.
|
213
|
+
stmt
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|