activerecord-oracle_enhanced-adapter 8.1.0-java

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 (78) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +1971 -0
  3. data/License.txt +20 -0
  4. data/README.md +947 -0
  5. data/VERSION +1 -0
  6. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +7 -0
  7. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +24 -0
  8. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +137 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +359 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +47 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +325 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +63 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +71 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +629 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +57 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +465 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +195 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +186 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +99 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +197 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +739 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +394 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +34 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +886 -0
  29. data/lib/active_record/type/oracle_enhanced/boolean.rb +19 -0
  30. data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
  31. data/lib/active_record/type/oracle_enhanced/integer.rb +14 -0
  32. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  33. data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
  34. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  35. data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
  36. data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
  37. data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
  38. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  39. data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
  40. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  41. data/lib/arel/visitors/oracle.rb +216 -0
  42. data/lib/arel/visitors/oracle12.rb +121 -0
  43. data/lib/arel/visitors/oracle_common.rb +51 -0
  44. data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +24 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +40 -0
  46. data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
  47. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +589 -0
  48. data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
  49. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
  50. data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
  51. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
  52. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
  53. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
  54. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
  55. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1318 -0
  56. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +485 -0
  57. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
  58. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
  59. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  60. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
  61. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
  62. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  63. data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
  64. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
  65. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  66. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +101 -0
  67. data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
  68. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  69. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  70. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
  71. data/spec/active_record/oracle_enhanced/type/text_spec.rb +295 -0
  72. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +107 -0
  73. data/spec/spec_config.yaml.template +11 -0
  74. data/spec/spec_helper.rb +225 -0
  75. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  76. data/spec/support/alter_system_user_password.sql +2 -0
  77. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  78. metadata +181 -0
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class Boolean < ActiveModel::Type::Boolean # :nodoc:
7
+ private
8
+ def cast_value(value)
9
+ # Kind of adding 'n' and 'N' to `FALSE_VALUES`
10
+ if ["n", "N"].include?(value)
11
+ false
12
+ else
13
+ super
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class CharacterString < ActiveRecord::Type::OracleEnhanced::String # :nodoc:
9
+ def serialize(value)
10
+ return unless value
11
+ Data.new(super, self.limit)
12
+ end
13
+
14
+ class Data # :nodoc:
15
+ def initialize(value, limit)
16
+ @value = value
17
+ @limit = limit
18
+ end
19
+
20
+ def to_s
21
+ @value
22
+ end
23
+
24
+ def to_character_str
25
+ len = @value.to_s.length
26
+ if len < @limit
27
+ "%-#{@limit}s" % @value
28
+ else
29
+ @value
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class Integer < ActiveModel::Type::Integer # :nodoc:
7
+ private
8
+ def max_value
9
+ ("9" * 38).to_i
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class Json < ActiveRecord::Type::Json
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class NationalCharacterString < ActiveRecord::Type::OracleEnhanced::String # :nodoc:
9
+ def serialize(value)
10
+ return unless value
11
+ Data.new(super)
12
+ end
13
+
14
+ class Data # :nodoc:
15
+ def initialize(value)
16
+ @value = value
17
+ end
18
+
19
+ def to_s
20
+ @value
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class NationalCharacterText < ActiveRecord::Type::Text # :nodoc:
9
+ def type
10
+ :ntext
11
+ end
12
+
13
+ def changed_in_place?(raw_old_value, new_value)
14
+ # TODO: Needs to find a way not to cast here.
15
+ raw_old_value = cast(raw_old_value)
16
+ super
17
+ end
18
+
19
+ def serialize(value)
20
+ return unless value
21
+ Data.new(super)
22
+ end
23
+
24
+ class Data # :nodoc:
25
+ def initialize(value)
26
+ @value = value
27
+ end
28
+
29
+ def to_s
30
+ @value
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class Raw < ActiveModel::Type::String # :nodoc:
9
+ def type
10
+ :raw
11
+ end
12
+
13
+ def serialize(value)
14
+ # Encode a string or byte array as string of hex codes
15
+ if value.nil?
16
+ super
17
+ else
18
+ value = value.unpack("C*")
19
+ value.map { |x| "%02X" % x }.join
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class String < ActiveModel::Type::String # :nodoc:
9
+ def changed?(old_value, new_value, _new_value_before_type_cast)
10
+ if old_value.nil?
11
+ new_value = nil if new_value == ""
12
+ old_value != new_value
13
+ else
14
+ super
15
+ end
16
+ end
17
+
18
+ def changed_in_place?(raw_old_value, new_value)
19
+ if raw_old_value.nil?
20
+ new_value = nil if new_value == ""
21
+ raw_old_value != new_value
22
+ else
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class Text < ActiveRecord::Type::Text # :nodoc:
9
+ def changed_in_place?(raw_old_value, new_value)
10
+ # TODO: Needs to find a way not to cast here.
11
+ raw_old_value = cast(raw_old_value)
12
+ super
13
+ end
14
+
15
+ def serialize(value)
16
+ return unless value
17
+ Data.new(super)
18
+ end
19
+
20
+ class Data # :nodoc:
21
+ def initialize(value)
22
+ @value = value
23
+ end
24
+
25
+ def to_s
26
+ @value
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class TimestampLtz < ActiveRecord::Type::DateTime
7
+ def type
8
+ :timestampltz
9
+ end
10
+
11
+ class Data < DelegateClass(::Time) # :nodoc:
12
+ end
13
+
14
+ def serialize(value)
15
+ case value = super
16
+ when ::Time
17
+ Data.new(value)
18
+ else
19
+ value
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class TimestampTz < ActiveRecord::Type::DateTime
7
+ def type
8
+ :timestamptz
9
+ end
10
+
11
+ class Data < DelegateClass(::Time) # :nodoc:
12
+ end
13
+
14
+ def serialize(value)
15
+ case value = super
16
+ when ::Time
17
+ Data.new(value)
18
+ else
19
+ value
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Rails)
4
+ module ActiveRecord
5
+ module ConnectionAdapters
6
+ class OracleEnhancedRailtie < ::Rails::Railtie
7
+ rake_tasks do
8
+ load "active_record/connection_adapters/oracle_enhanced/database_tasks.rb"
9
+ end
10
+
11
+ ActiveSupport.on_load(:active_record) do
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
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "oracle_common"
4
+
5
+ module Arel # :nodoc: all
6
+ module Visitors
7
+ class Oracle < Arel::Visitors::ToSql
8
+ include OracleCommon
9
+
10
+ private
11
+ def visit_Arel_Nodes_SelectStatement(o, collector)
12
+ o = order_hacks(o)
13
+
14
+ # if need to select first records without ORDER BY and GROUP BY and without DISTINCT
15
+ # then can use simple ROWNUM in WHERE clause
16
+ if o.limit && o.orders.empty? && o.cores.first.groups.empty? && !o.offset && !o.cores.first.set_quantifier.class.to_s.match?(/Distinct/)
17
+ o.cores.last.wheres.push Nodes::LessThanOrEqual.new(
18
+ Nodes::SqlLiteral.new("ROWNUM"), o.limit.expr
19
+ )
20
+ return super
21
+ end
22
+
23
+ if o.limit && o.offset
24
+ o = o.dup
25
+ limit = o.limit.expr
26
+ offset = o.offset
27
+ o.offset = nil
28
+ collector << "
29
+ SELECT * FROM (
30
+ SELECT raw_sql_.*, rownum raw_rnum_
31
+ FROM ("
32
+
33
+ collector = super(o, collector)
34
+
35
+ if offset.expr.type.is_a? ActiveModel::Type::Value
36
+ collector << ") raw_sql_ WHERE rownum <= ("
37
+ collector = visit offset.expr, collector
38
+ collector << " + "
39
+ collector = visit limit, collector
40
+ collector << ") ) WHERE raw_rnum_ > "
41
+ collector = visit offset.expr, collector
42
+ return collector
43
+ else
44
+ collector << ") raw_sql_
45
+ WHERE rownum <= #{offset.expr.value_before_type_cast + limit.value_before_type_cast}
46
+ )
47
+ WHERE "
48
+ return visit(offset, collector)
49
+ end
50
+ end
51
+
52
+ if o.limit
53
+ o = o.dup
54
+ limit = o.limit.expr
55
+ collector << "SELECT * FROM ("
56
+ collector = super(o, collector)
57
+ collector << ") WHERE ROWNUM <= "
58
+ return visit limit, collector
59
+ end
60
+
61
+ if o.offset
62
+ o = o.dup
63
+ offset = o.offset
64
+ o.offset = nil
65
+ collector << "SELECT * FROM (
66
+ SELECT raw_sql_.*, rownum raw_rnum_
67
+ FROM ("
68
+ collector = super(o, collector)
69
+ collector << ") raw_sql_
70
+ )
71
+ WHERE "
72
+ return visit offset, collector
73
+ end
74
+
75
+ super
76
+ end
77
+
78
+ def visit_Arel_Nodes_Limit(o, collector)
79
+ collector
80
+ end
81
+
82
+ def visit_Arel_Nodes_Offset(o, collector)
83
+ collector << "raw_rnum_ > "
84
+ visit o.expr, collector
85
+ end
86
+
87
+ def visit_Arel_Nodes_Except(o, collector)
88
+ collector << "( "
89
+ collector = infix_value o, collector, " MINUS "
90
+ collector << " )"
91
+ end
92
+
93
+ ##
94
+ # To avoid ORA-01795: maximum number of expressions in a list is 1000
95
+ # tell ActiveRecord to limit us to 1000 ids at a time
96
+ def visit_Arel_Nodes_HomogeneousIn(o, collector)
97
+ in_clause_length = @connection.in_clause_length
98
+ values = o.casted_values.map { |v| @connection.quote(v) }
99
+ operator =
100
+ if o.type == :in
101
+ " IN ("
102
+ else
103
+ " NOT IN ("
104
+ end
105
+
106
+ if !Array === values || values.length <= in_clause_length
107
+ visit o.left, collector
108
+ collector << operator
109
+
110
+ expr =
111
+ if values.empty?
112
+ @connection.quote(nil)
113
+ else
114
+ values.join(",")
115
+ end
116
+
117
+ collector << expr
118
+ collector << ")"
119
+ else
120
+ separator =
121
+ if o.type == :in
122
+ " OR "
123
+ else
124
+ " AND "
125
+ end
126
+ collector << "("
127
+ values.each_slice(in_clause_length).each_with_index do |valuez, i|
128
+ collector << separator unless i == 0
129
+ visit o.left, collector
130
+ collector << operator
131
+ collector << valuez.join(",")
132
+ collector << ")"
133
+ end
134
+ collector << ")"
135
+ end
136
+
137
+ collector
138
+ end
139
+
140
+ def visit_Arel_Nodes_UpdateStatement(o, collector)
141
+ # Oracle does not allow ORDER BY/LIMIT in UPDATEs.
142
+ if o.orders.any? && o.limit.nil?
143
+ # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided,
144
+ # otherwise let the user deal with the error
145
+ o = o.dup
146
+ o.orders = []
147
+ end
148
+
149
+ super
150
+ end
151
+
152
+ ###
153
+ # Hacks for the order clauses specific to Oracle
154
+ def order_hacks(o)
155
+ return o if o.orders.empty?
156
+ return o unless o.cores.any? do |core|
157
+ core.projections.any? do |projection|
158
+ /FIRST_VALUE/ === projection
159
+ end
160
+ end
161
+ # Previous version with join and split broke ORDER BY clause
162
+ # if it contained functions with several arguments (separated by ',').
163
+ #
164
+ # orders = o.orders.map { |x| visit x }.join(', ').split(',')
165
+ orders = o.orders.map do |x|
166
+ string = visit(x, Arel::Collectors::SQLString.new).value
167
+ if string.include?(",")
168
+ split_order_string(string)
169
+ else
170
+ string
171
+ end
172
+ end.flatten
173
+ o.orders = []
174
+ orders.each_with_index do |order, i|
175
+ o.orders <<
176
+ Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i.match?(order)}")
177
+ end
178
+ o
179
+ end
180
+
181
+ # Split string by commas but count opening and closing brackets
182
+ # and ignore commas inside brackets.
183
+ def split_order_string(string)
184
+ array = []
185
+ i = 0
186
+ string.split(",").each do |part|
187
+ if array[i]
188
+ array[i] << "," << part
189
+ else
190
+ # to ensure that array[i] will be String and not Arel::Nodes::SqlLiteral
191
+ array[i] = part.to_s
192
+ end
193
+ i += 1 if array[i].count("(") == array[i].count(")")
194
+ end
195
+ array
196
+ end
197
+
198
+ def is_distinct_from(o, collector)
199
+ collector << "DECODE("
200
+ collector = visit [o.left, o.right, 0, 1], collector
201
+ collector << ")"
202
+ end
203
+
204
+ # Oracle will occur an error `ORA-00907: missing right parenthesis`
205
+ # when using `ORDER BY` in `UPDATE` or `DELETE`'s subquery.
206
+ #
207
+ # This method has been overridden based on the following code.
208
+ # https://github.com/rails/rails/blob/v6.1.0.rc1/activerecord/lib/arel/visitors/to_sql.rb#L815-L825
209
+ def build_subselect(key, o)
210
+ stmt = super
211
+ stmt.orders = [] # `orders` will never be set to prevent `ORA-00907`.
212
+ stmt
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "oracle_common"
4
+
5
+ module Arel # :nodoc: all
6
+ module Visitors
7
+ class Oracle12 < Arel::Visitors::ToSql
8
+ include OracleCommon
9
+
10
+ private
11
+ def visit_Arel_Nodes_SelectStatement(o, collector)
12
+ # Oracle does not allow LIMIT clause with select for update
13
+ if o.limit && o.lock
14
+ raise ArgumentError, <<~MSG
15
+ Combination of limit and lock is not supported. Because generated SQL statements
16
+ `SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.
17
+ MSG
18
+ end
19
+ super
20
+ end
21
+
22
+ def visit_Arel_Nodes_SelectOptions(o, collector)
23
+ collector = maybe_visit o.offset, collector
24
+ collector = maybe_visit o.limit, collector
25
+ maybe_visit o.lock, collector
26
+ end
27
+
28
+ def visit_Arel_Nodes_Limit(o, collector)
29
+ collector << "FETCH FIRST "
30
+ collector = visit o.expr, collector
31
+ collector << " ROWS ONLY"
32
+ end
33
+
34
+ def visit_Arel_Nodes_Offset(o, collector)
35
+ collector << "OFFSET "
36
+ visit o.expr, collector
37
+ collector << " ROWS"
38
+ end
39
+
40
+ def visit_Arel_Nodes_Except(o, collector)
41
+ collector << "( "
42
+ collector = infix_value o, collector, " MINUS "
43
+ collector << " )"
44
+ end
45
+
46
+ ##
47
+ # To avoid ORA-01795: maximum number of expressions in a list is 1000
48
+ # tell ActiveRecord to limit us to 1000 ids at a time
49
+ def visit_Arel_Nodes_HomogeneousIn(o, collector)
50
+ in_clause_length = @connection.in_clause_length
51
+ values = o.casted_values.map { |v| @connection.quote(v) }
52
+ operator =
53
+ if o.type == :in
54
+ " IN ("
55
+ else
56
+ " NOT IN ("
57
+ end
58
+
59
+ if !Array === values || values.length <= in_clause_length
60
+ visit o.left, collector
61
+ collector << operator
62
+
63
+ expr =
64
+ if values.empty?
65
+ @connection.quote(nil)
66
+ else
67
+ values.join(",")
68
+ end
69
+
70
+ collector << expr
71
+ collector << ")"
72
+ else
73
+ separator =
74
+ if o.type == :in
75
+ " OR "
76
+ else
77
+ " AND "
78
+ end
79
+ collector << "("
80
+ values.each_slice(in_clause_length).each_with_index do |valuez, i|
81
+ collector << separator unless i == 0
82
+ visit o.left, collector
83
+ collector << operator
84
+ collector << valuez.join(",")
85
+ collector << ")"
86
+ end
87
+ collector << ")"
88
+ end
89
+ end
90
+
91
+ def visit_Arel_Nodes_UpdateStatement(o, collector)
92
+ # Oracle does not allow ORDER BY/LIMIT in UPDATEs.
93
+ if o.orders.any? && o.limit.nil?
94
+ # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided,
95
+ # otherwise let the user deal with the error
96
+ o = o.dup
97
+ o.orders = []
98
+ end
99
+
100
+ super
101
+ end
102
+
103
+ def is_distinct_from(o, collector)
104
+ collector << "DECODE("
105
+ collector = visit [o.left, o.right, 0, 1], collector
106
+ collector << ")"
107
+ end
108
+
109
+ # Oracle will occur an error `ORA-00907: missing right parenthesis`
110
+ # when using `ORDER BY` in `UPDATE` or `DELETE`'s subquery.
111
+ #
112
+ # This method has been overridden based on the following code.
113
+ # https://github.com/rails/rails/blob/v6.1.0.rc1/activerecord/lib/arel/visitors/to_sql.rb#L815-L825
114
+ def build_subselect(key, o)
115
+ stmt = super
116
+ stmt.orders = [] # `orders` will never be set to prevent `ORA-00907`.
117
+ stmt
118
+ end
119
+ end
120
+ end
121
+ end