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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +390 -21
  3. data/README.md +35 -8
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
  6. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +3 -3
  7. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +42 -37
  8. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +59 -60
  9. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +5 -10
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +86 -81
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +9 -10
  12. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +1 -2
  13. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +37 -16
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -1
  15. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +5 -6
  16. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +58 -49
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +1 -1
  18. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +6 -7
  19. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +75 -51
  20. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +13 -14
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +14 -4
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +27 -24
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +156 -155
  24. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +103 -90
  25. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +3 -2
  26. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +261 -161
  27. data/lib/active_record/type/oracle_enhanced/boolean.rb +0 -1
  28. data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
  29. data/lib/active_record/type/oracle_enhanced/integer.rb +0 -1
  30. data/lib/arel/visitors/oracle.rb +221 -0
  31. data/lib/arel/visitors/oracle12.rb +128 -0
  32. data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +0 -2
  33. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +78 -26
  34. data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +7 -15
  35. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +5 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +17 -17
  37. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +7 -10
  38. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +0 -15
  39. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +33 -36
  40. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +77 -258
  41. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +38 -39
  42. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +273 -85
  43. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +7 -8
  44. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +2 -4
  45. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +43 -0
  46. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  47. data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
  48. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +1 -1
  49. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +2 -2
  50. data/spec/active_record/oracle_enhanced/type/json_spec.rb +0 -1
  51. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +6 -5
  52. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +2 -4
  53. data/spec/spec_config.yaml.template +2 -2
  54. data/spec/spec_helper.rb +13 -2
  55. metadata +52 -30
  56. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +0 -28
@@ -5,7 +5,6 @@ module ActiveRecord
5
5
  module OracleEnhanced
6
6
  class Boolean < ActiveModel::Type::Boolean # :nodoc:
7
7
  private
8
-
9
8
  def cast_value(value)
10
9
  # Kind of adding 'n' and 'N' to `FALSE_VALUES`
11
10
  if ["n", "N"].include?(value)
@@ -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
@@ -5,7 +5,6 @@ module ActiveRecord
5
5
  module OracleEnhanced
6
6
  class Integer < ActiveModel::Type::Integer # :nodoc:
7
7
  private
8
-
9
8
  def max_value
10
9
  ("9" * 38).to_i
11
10
  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 swith to specified schema" do
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 swith to specified schema after reset" do
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 use NLS_DATE_FORMAT environment variable" do
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 use configuration value and ignore NLS_DATE_FORMAT environment variable" do
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::DEFAULT_NLS_PARAMETERS[:nls_date_format]
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].match(/^\//)
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::Base.default_timezone = :utc
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 (path == "java:/comp/env")
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, "test_employees", nil)
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