activerecord-oracle_enhanced-adapter 5.2.8 → 7.0.3
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 +390 -21
- data/README.md +35 -8
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +42 -37
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +59 -60
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +5 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +86 -81
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +9 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +1 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +37 -16
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +5 -6
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +58 -49
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +6 -7
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +75 -51
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +13 -14
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +14 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +27 -24
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +156 -155
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +103 -90
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +3 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +261 -161
- data/lib/active_record/type/oracle_enhanced/boolean.rb +0 -1
- data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/integer.rb +0 -1
- data/lib/arel/visitors/oracle.rb +221 -0
- data/lib/arel/visitors/oracle12.rb +128 -0
- data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +0 -2
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +78 -26
- data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +7 -15
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +5 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +17 -17
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +7 -10
- data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +0 -15
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +33 -36
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +77 -258
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +38 -39
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +273 -85
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +7 -8
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +2 -4
- data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +43 -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 +1 -1
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +2 -2
- data/spec/active_record/oracle_enhanced/type/json_spec.rb +0 -1
- data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +6 -5
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +2 -4
- data/spec/spec_config.yaml.template +2 -2
- data/spec/spec_helper.rb +13 -2
- metadata +52 -30
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +0 -28
@@ -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,221 @@
|
|
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.type.is_a? ActiveModel::Type::Value
|
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.value_before_type_cast + limit.value_before_type_cast}
|
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_ActiveModel_Attribute(o, collector)
|
196
|
+
collector.add_bind(o) { |i| ":a#{i}" }
|
197
|
+
end
|
198
|
+
|
199
|
+
def visit_Arel_Nodes_BindParam(o, collector)
|
200
|
+
collector.add_bind(o.value) { |i| ":a#{i}" }
|
201
|
+
end
|
202
|
+
|
203
|
+
def is_distinct_from(o, collector)
|
204
|
+
collector << "DECODE("
|
205
|
+
collector = visit [o.left, o.right, 0, 1], collector
|
206
|
+
collector << ")"
|
207
|
+
end
|
208
|
+
|
209
|
+
# Oracle will occur an error `ORA-00907: missing right parenthesis`
|
210
|
+
# when using `ORDER BY` in `UPDATE` or `DELETE`'s subquery.
|
211
|
+
#
|
212
|
+
# This method has been overridden based on the following code.
|
213
|
+
# https://github.com/rails/rails/blob/v6.1.0.rc1/activerecord/lib/arel/visitors/to_sql.rb#L815-L825
|
214
|
+
def build_subselect(key, o)
|
215
|
+
stmt = super
|
216
|
+
stmt.orders = [] # `orders` will never be set to prevent `ORA-00907`.
|
217
|
+
stmt
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arel # :nodoc: all
|
4
|
+
module Visitors
|
5
|
+
class Oracle12 < Arel::Visitors::ToSql
|
6
|
+
private
|
7
|
+
def visit_Arel_Nodes_SelectStatement(o, collector)
|
8
|
+
# Oracle does not allow LIMIT clause with select for update
|
9
|
+
if o.limit && o.lock
|
10
|
+
raise ArgumentError, <<~MSG
|
11
|
+
Combination of limit and lock is not supported. Because generated SQL statements
|
12
|
+
`SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.
|
13
|
+
MSG
|
14
|
+
end
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_Arel_Nodes_SelectOptions(o, collector)
|
19
|
+
collector = maybe_visit o.offset, collector
|
20
|
+
collector = maybe_visit o.limit, collector
|
21
|
+
maybe_visit o.lock, collector
|
22
|
+
end
|
23
|
+
|
24
|
+
def visit_Arel_Nodes_Limit(o, collector)
|
25
|
+
collector << "FETCH FIRST "
|
26
|
+
collector = visit o.expr, collector
|
27
|
+
collector << " ROWS ONLY"
|
28
|
+
end
|
29
|
+
|
30
|
+
def visit_Arel_Nodes_Offset(o, collector)
|
31
|
+
collector << "OFFSET "
|
32
|
+
visit o.expr, collector
|
33
|
+
collector << " ROWS"
|
34
|
+
end
|
35
|
+
|
36
|
+
def visit_Arel_Nodes_Except(o, collector)
|
37
|
+
collector << "( "
|
38
|
+
collector = infix_value o, collector, " MINUS "
|
39
|
+
collector << " )"
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# To avoid ORA-01795: maximum number of expressions in a list is 1000
|
44
|
+
# tell ActiveRecord to limit us to 1000 ids at a time
|
45
|
+
def visit_Arel_Nodes_HomogeneousIn(o, collector)
|
46
|
+
in_clause_length = @connection.in_clause_length
|
47
|
+
values = o.casted_values.map { |v| @connection.quote(v) }
|
48
|
+
column_name = quote_table_name(o.table_name) + "." + quote_column_name(o.column_name)
|
49
|
+
operator =
|
50
|
+
if o.type == :in
|
51
|
+
" IN ("
|
52
|
+
else
|
53
|
+
" NOT IN ("
|
54
|
+
end
|
55
|
+
|
56
|
+
if !Array === values || values.length <= in_clause_length
|
57
|
+
collector << column_name
|
58
|
+
collector << operator
|
59
|
+
|
60
|
+
expr =
|
61
|
+
if values.empty?
|
62
|
+
@connection.quote(nil)
|
63
|
+
else
|
64
|
+
values.join(",")
|
65
|
+
end
|
66
|
+
|
67
|
+
collector << expr
|
68
|
+
collector << ")"
|
69
|
+
else
|
70
|
+
separator =
|
71
|
+
if o.type == :in
|
72
|
+
" OR "
|
73
|
+
else
|
74
|
+
" AND "
|
75
|
+
end
|
76
|
+
collector << "("
|
77
|
+
values.each_slice(in_clause_length).each_with_index do |valuez, i|
|
78
|
+
collector << separator unless i == 0
|
79
|
+
collector << column_name
|
80
|
+
collector << operator
|
81
|
+
collector << valuez.join(",")
|
82
|
+
collector << ")"
|
83
|
+
end
|
84
|
+
collector << ")"
|
85
|
+
end
|
86
|
+
|
87
|
+
collector
|
88
|
+
end
|
89
|
+
|
90
|
+
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
91
|
+
# Oracle does not allow ORDER BY/LIMIT in UPDATEs.
|
92
|
+
if o.orders.any? && o.limit.nil?
|
93
|
+
# However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided,
|
94
|
+
# otherwise let the user deal with the error
|
95
|
+
o = o.dup
|
96
|
+
o.orders = []
|
97
|
+
end
|
98
|
+
|
99
|
+
super
|
100
|
+
end
|
101
|
+
|
102
|
+
def visit_ActiveModel_Attribute(o, collector)
|
103
|
+
collector.add_bind(o) { |i| ":a#{i}" }
|
104
|
+
end
|
105
|
+
|
106
|
+
def visit_Arel_Nodes_BindParam(o, collector)
|
107
|
+
collector.add_bind(o.value) { |i| ":a#{i}" }
|
108
|
+
end
|
109
|
+
|
110
|
+
def is_distinct_from(o, collector)
|
111
|
+
collector << "DECODE("
|
112
|
+
collector = visit [o.left, o.right, 0, 1], collector
|
113
|
+
collector << ")"
|
114
|
+
end
|
115
|
+
|
116
|
+
# Oracle will occur an error `ORA-00907: missing right parenthesis`
|
117
|
+
# when using `ORDER BY` in `UPDATE` or `DELETE`'s subquery.
|
118
|
+
#
|
119
|
+
# This method has been overridden based on the following code.
|
120
|
+
# https://github.com/rails/rails/blob/v6.1.0.rc1/activerecord/lib/arel/visitors/to_sql.rb#L815-L825
|
121
|
+
def build_subselect(key, o)
|
122
|
+
stmt = super
|
123
|
+
stmt.orders = [] # `orders` will never be set to prevent `ORA-00907`.
|
124
|
+
stmt
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
describe "OracleEnhancedAdapter emulate OracleAdapter" do
|
4
|
-
|
5
4
|
before(:all) do
|
6
5
|
@old_oracle_adapter = nil
|
7
6
|
if defined?(ActiveRecord::ConnectionAdapters::OracleAdapter)
|
@@ -22,5 +21,4 @@ describe "OracleEnhancedAdapter emulate OracleAdapter" do
|
|
22
21
|
ActiveRecord::ConnectionAdapters::OracleAdapter = @old_oracle_adapter
|
23
22
|
end
|
24
23
|
end
|
25
|
-
|
26
24
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
describe "OracleEnhancedAdapter establish connection" do
|
4
|
-
|
5
4
|
it "should connect to database" do
|
6
5
|
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
7
6
|
expect(ActiveRecord::Base.connection).not_to be_nil
|
@@ -41,10 +40,32 @@ describe "OracleEnhancedAdapter establish connection" do
|
|
41
40
|
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(cursor_sharing: :exact))
|
42
41
|
expect(ActiveRecord::Base.connection.select_value("select value from v$parameter where name = 'cursor_sharing'")).to eq("EXACT")
|
43
42
|
end
|
43
|
+
|
44
|
+
it "should not use JDBC statement caching" do
|
45
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
46
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS)
|
47
|
+
expect(ActiveRecord::Base.connection.raw_connection.getImplicitCachingEnabled).to eq(false)
|
48
|
+
expect(ActiveRecord::Base.connection.raw_connection.getStatementCacheSize).to eq(-1)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should use JDBC statement caching" do
|
53
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
54
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(jdbc_statement_cache_size: 100))
|
55
|
+
expect(ActiveRecord::Base.connection.raw_connection.getImplicitCachingEnabled).to eq(true)
|
56
|
+
expect(ActiveRecord::Base.connection.raw_connection.getStatementCacheSize).to eq(100)
|
57
|
+
# else: don't raise error if OCI connection has parameter "jdbc_statement_cache_size", still ignore it
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should connect to database using service_name" do
|
62
|
+
ActiveRecord::Base.establish_connection(SERVICE_NAME_CONNECTION_PARAMS)
|
63
|
+
expect(ActiveRecord::Base.connection).not_to be_nil
|
64
|
+
expect(ActiveRecord::Base.connection.class).to eq(ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter)
|
65
|
+
end
|
44
66
|
end
|
45
67
|
|
46
68
|
describe "OracleEnhancedConnection" do
|
47
|
-
|
48
69
|
describe "create connection" do
|
49
70
|
before(:all) do
|
50
71
|
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
@@ -75,49 +96,64 @@ describe "OracleEnhancedConnection" do
|
|
75
96
|
it "should be in autocommit mode after connection" do
|
76
97
|
expect(@conn).to be_autocommit
|
77
98
|
end
|
78
|
-
|
79
99
|
end
|
80
100
|
|
81
101
|
describe "create connection with schema option" do
|
82
|
-
|
83
102
|
it "should create new connection" do
|
84
103
|
ActiveRecord::Base.establish_connection(CONNECTION_WITH_SCHEMA_PARAMS)
|
85
104
|
expect(ActiveRecord::Base.connection).to be_active
|
86
105
|
end
|
87
106
|
|
88
|
-
it "should
|
107
|
+
it "should switch to specified schema" do
|
89
108
|
ActiveRecord::Base.establish_connection(CONNECTION_WITH_SCHEMA_PARAMS)
|
90
109
|
expect(ActiveRecord::Base.connection.current_schema).to eq(CONNECTION_WITH_SCHEMA_PARAMS[:schema].upcase)
|
110
|
+
expect(ActiveRecord::Base.connection.current_user).to eq(CONNECTION_WITH_SCHEMA_PARAMS[:username].upcase)
|
91
111
|
end
|
92
112
|
|
93
|
-
it "should
|
113
|
+
it "should switch to specified schema after reset" do
|
94
114
|
ActiveRecord::Base.connection.reset!
|
95
115
|
expect(ActiveRecord::Base.connection.current_schema).to eq(CONNECTION_WITH_SCHEMA_PARAMS[:schema].upcase)
|
96
116
|
end
|
97
|
-
|
98
117
|
end
|
99
118
|
|
100
119
|
describe "create connection with NLS parameters" do
|
120
|
+
after do
|
121
|
+
ENV["NLS_TERRITORY"] = nil
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should use NLS_TERRITORY environment variable" do
|
125
|
+
ENV["NLS_TERRITORY"] = "JAPAN"
|
126
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
127
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_TERRITORY') as value from dual")).to eq([{ "value" => "JAPAN" }])
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should use configuration value and ignore NLS_TERRITORY environment variable" do
|
131
|
+
ENV["NLS_TERRITORY"] = "AMERICA"
|
132
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS.merge(nls_territory: "INDONESIA"))
|
133
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_TERRITORY') as value from dual")).to eq([{ "value" => "INDONESIA" }])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "Fixed NLS parameters" do
|
101
138
|
after do
|
102
139
|
ENV["NLS_DATE_FORMAT"] = nil
|
103
140
|
end
|
104
141
|
|
105
|
-
it "should
|
142
|
+
it "should ignore NLS_DATE_FORMAT environment variable" do
|
106
143
|
ENV["NLS_DATE_FORMAT"] = "YYYY-MM-DD"
|
107
144
|
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
108
|
-
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => "YYYY-MM-DD" }])
|
145
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => "YYYY-MM-DD HH24:MI:SS" }])
|
109
146
|
end
|
110
147
|
|
111
|
-
it "should
|
112
|
-
ENV["NLS_DATE_FORMAT"] = "YYYY-MM-DD"
|
148
|
+
it "should ignore NLS_DATE_FORMAT configuration value" do
|
113
149
|
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS.merge(nls_date_format: "YYYY-MM-DD HH24:MI"))
|
114
|
-
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => "YYYY-MM-DD HH24:MI" }])
|
150
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => "YYYY-MM-DD HH24:MI:SS" }])
|
115
151
|
end
|
116
152
|
|
117
153
|
it "should use default value when NLS_DATE_FORMAT environment variable is not set" do
|
118
154
|
ENV["NLS_DATE_FORMAT"] = nil
|
119
155
|
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
120
|
-
default = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::
|
156
|
+
default = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::FIXED_NLS_PARAMETERS[:nls_date_format]
|
121
157
|
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => default }])
|
122
158
|
end
|
123
159
|
end
|
@@ -167,7 +203,7 @@ describe "OracleEnhancedConnection" do
|
|
167
203
|
describe "with slash-prefixed database name (service name)" do
|
168
204
|
before(:all) do
|
169
205
|
params = CONNECTION_PARAMS.dup
|
170
|
-
params[:database] = "/#{params[:database]}" unless params[:database].
|
206
|
+
params[:database] = "/#{params[:database]}" unless params[:database].start_with?("/")
|
171
207
|
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
172
208
|
end
|
173
209
|
|
@@ -196,13 +232,12 @@ describe "OracleEnhancedConnection" do
|
|
196
232
|
end
|
197
233
|
|
198
234
|
it "should respect default_timezone = :utc than time_zone setting" do
|
199
|
-
# it expects that ActiveRecord
|
235
|
+
# it expects that ActiveRecord.default_timezone = :utc
|
200
236
|
ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_WITH_TIMEZONE_PARAMS)
|
201
237
|
post = Post.create!
|
202
238
|
created_at = post.created_at
|
203
239
|
expect(post).to eq(Post.find_by!(created_at: created_at))
|
204
240
|
end
|
205
|
-
|
206
241
|
end
|
207
242
|
|
208
243
|
describe 'with host="connection-string"' do
|
@@ -225,7 +260,6 @@ describe "OracleEnhancedConnection" do
|
|
225
260
|
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
|
226
261
|
|
227
262
|
describe "create JDBC connection" do
|
228
|
-
|
229
263
|
it "should create new connection using :url" do
|
230
264
|
params = CONNECTION_PARAMS.dup
|
231
265
|
params[:url] = "jdbc:oracle:thin:@#{DATABASE_HOST && "//#{DATABASE_HOST}#{DATABASE_PORT && ":#{DATABASE_PORT}"}/"}#{DATABASE_NAME}"
|
@@ -253,7 +287,6 @@ describe "OracleEnhancedConnection" do
|
|
253
287
|
end
|
254
288
|
|
255
289
|
it "should create a new connection using JNDI" do
|
256
|
-
|
257
290
|
begin
|
258
291
|
import "oracle.jdbc.driver.OracleDriver"
|
259
292
|
import "org.apache.commons.pool.impl.GenericObjectPool"
|
@@ -274,7 +307,7 @@ describe "OracleEnhancedConnection" do
|
|
274
307
|
@data_source.access_to_underlying_connection_allowed = true
|
275
308
|
end
|
276
309
|
def lookup(path)
|
277
|
-
if
|
310
|
+
if path == "java:/comp/env"
|
278
311
|
self
|
279
312
|
else
|
280
313
|
@data_source
|
@@ -289,7 +322,6 @@ describe "OracleEnhancedConnection" do
|
|
289
322
|
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
290
323
|
expect(@conn).to be_active
|
291
324
|
end
|
292
|
-
|
293
325
|
end
|
294
326
|
|
295
327
|
it "should fall back to directly instantiating OracleDriver" do
|
@@ -320,7 +352,6 @@ describe "OracleEnhancedConnection" do
|
|
320
352
|
it "should execute SQL select and return also columns" do
|
321
353
|
expect(@conn.select("SELECT * FROM dual", nil, true)).to eq([ [{ "dummy" => "X" }], ["dummy"] ])
|
322
354
|
end
|
323
|
-
|
324
355
|
end
|
325
356
|
|
326
357
|
describe "SQL with bind parameters" do
|
@@ -364,7 +395,7 @@ describe "OracleEnhancedConnection" do
|
|
364
395
|
it "should execute prepared statement with decimal bind parameter " do
|
365
396
|
cursor = @conn.prepare("INSERT INTO test_employees VALUES(:1)")
|
366
397
|
type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "NUMBER", type: :decimal, limit: 10, precision: nil, scale: 2)
|
367
|
-
column = ActiveRecord::ConnectionAdapters::OracleEnhanced::Column.new("age", nil, type_metadata, false,
|
398
|
+
column = ActiveRecord::ConnectionAdapters::OracleEnhanced::Column.new("age", nil, type_metadata, false, comment: nil)
|
368
399
|
expect(column.type).to eq(:decimal)
|
369
400
|
# Here 1.5 expects that this value has been type casted already
|
370
401
|
# it should use bind_params in the long term.
|
@@ -379,10 +410,22 @@ describe "OracleEnhancedConnection" do
|
|
379
410
|
end
|
380
411
|
|
381
412
|
describe "auto reconnection" do
|
413
|
+
include SchemaSpecHelper
|
414
|
+
|
382
415
|
before(:all) do
|
383
416
|
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
384
417
|
@conn = ActiveRecord::Base.connection.instance_variable_get("@connection")
|
385
418
|
@sys_conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(SYS_CONNECTION_PARAMS)
|
419
|
+
schema_define do
|
420
|
+
create_table :posts, force: true
|
421
|
+
end
|
422
|
+
class ::Post < ActiveRecord::Base
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
after(:all) do
|
427
|
+
Object.send(:remove_const, "Post")
|
428
|
+
ActiveRecord::Base.clear_cache!
|
386
429
|
end
|
387
430
|
|
388
431
|
before(:each) do
|
@@ -433,6 +476,19 @@ describe "OracleEnhancedConnection" do
|
|
433
476
|
end
|
434
477
|
end
|
435
478
|
|
479
|
+
it "should reconnect and execute query if connection is lost and auto retry is enabled" do
|
480
|
+
Post.create!
|
481
|
+
ActiveRecord::Base.connection.auto_retry = true
|
482
|
+
kill_current_session
|
483
|
+
expect(Post.take).not_to be_nil
|
484
|
+
end
|
485
|
+
|
486
|
+
it "should not reconnect and execute query if connection is lost and auto retry is disabled" do
|
487
|
+
Post.create!
|
488
|
+
ActiveRecord::Base.connection.auto_retry = false
|
489
|
+
kill_current_session
|
490
|
+
expect { Post.take }.to raise_error(ActiveRecord::StatementInvalid)
|
491
|
+
end
|
436
492
|
end
|
437
493
|
|
438
494
|
describe "describe table" do
|
@@ -483,15 +539,11 @@ describe "OracleEnhancedConnection" do
|
|
483
539
|
|
484
540
|
if defined?(OCI8)
|
485
541
|
context "OCI8 adapter" do
|
486
|
-
|
487
542
|
it "should not fallback to SELECT-based logic when querying non-existent table information" do
|
488
543
|
expect(@conn).not_to receive(:select_one)
|
489
544
|
@conn.describe("non_existent") rescue ActiveRecord::ConnectionAdapters::OracleEnhanced::ConnectionException
|
490
545
|
end
|
491
|
-
|
492
546
|
end
|
493
547
|
end
|
494
|
-
|
495
548
|
end
|
496
|
-
|
497
549
|
end
|