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.
- checksums.yaml +7 -0
- data/History.md +1971 -0
- data/License.txt +20 -0
- data/README.md +947 -0
- data/VERSION +1 -0
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +7 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +24 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +137 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +359 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +47 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +325 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +63 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +71 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +629 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +57 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +465 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +195 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +186 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +99 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +197 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +739 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +394 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +886 -0
- data/lib/active_record/type/oracle_enhanced/boolean.rb +19 -0
- data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/integer.rb +14 -0
- data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
- data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
- data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
- data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
- data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
- data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
- data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
- data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
- data/lib/arel/visitors/oracle.rb +216 -0
- data/lib/arel/visitors/oracle12.rb +121 -0
- data/lib/arel/visitors/oracle_common.rb +51 -0
- data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +24 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +40 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +589 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1318 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +485 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
- data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
- data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
- data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
- data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
- data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
- data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +101 -0
- data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
- data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
- data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
- data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
- data/spec/active_record/oracle_enhanced/type/text_spec.rb +295 -0
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +107 -0
- data/spec/spec_config.yaml.template +11 -0
- data/spec/spec_helper.rb +225 -0
- data/spec/support/alter_system_set_open_cursors.sql +1 -0
- data/spec/support/alter_system_user_password.sql +2 -0
- data/spec/support/create_oracle_enhanced_users.sql +31 -0
- 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,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
|