activerecord-oracle_enhanced-adapter 5.2.8 → 7.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|