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,589 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe "OracleEnhancedAdapter establish connection" do
|
|
4
|
+
it "should connect to database" do
|
|
5
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
6
|
+
expect(ActiveRecord::Base.connection).not_to be_nil
|
|
7
|
+
expect(ActiveRecord::Base.connection.class).to eq(ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should connect to database as SYSDBA" do
|
|
11
|
+
ActiveRecord::Base.establish_connection(SYS_CONNECTION_PARAMS)
|
|
12
|
+
expect(ActiveRecord::Base.connection).not_to be_nil
|
|
13
|
+
expect(ActiveRecord::Base.connection.class).to eq(ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should be active after connection to database" do
|
|
17
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
18
|
+
expect(ActiveRecord::Base.connection).to be_active
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should not be active after disconnection to database" do
|
|
22
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
23
|
+
ActiveRecord::Base.connection.disconnect!
|
|
24
|
+
expect(ActiveRecord::Base.connection).not_to be_active
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should be active after reconnection to database" do
|
|
28
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
29
|
+
ActiveRecord::Base.connection.reconnect!
|
|
30
|
+
expect(ActiveRecord::Base.connection).to be_active
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should be active after reconnection to database with restore_transactions: true" do
|
|
34
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
35
|
+
ActiveRecord::Base.connection.reconnect!(restore_transactions: true)
|
|
36
|
+
expect(ActiveRecord::Base.connection).to be_active
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should use database default cursor_sharing parameter value force by default" do
|
|
40
|
+
# Use `SYSTEM_CONNECTION_PARAMS` to query v$parameter
|
|
41
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS)
|
|
42
|
+
expect(ActiveRecord::Base.connection.select_value("select value from v$parameter where name = 'cursor_sharing'")).to eq("FORCE")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should use modified cursor_sharing value exact" do
|
|
46
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(cursor_sharing: :exact))
|
|
47
|
+
expect(ActiveRecord::Base.connection.select_value("select value from v$parameter where name = 'cursor_sharing'")).to eq("EXACT")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should not use JDBC statement caching" do
|
|
51
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
52
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS)
|
|
53
|
+
expect(ActiveRecord::Base.connection.raw_connection.getImplicitCachingEnabled).to be(false)
|
|
54
|
+
expect(ActiveRecord::Base.connection.raw_connection.getStatementCacheSize).to eq(-1)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should use JDBC statement caching" do
|
|
59
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
60
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(jdbc_statement_cache_size: 100))
|
|
61
|
+
expect(ActiveRecord::Base.connection.raw_connection.getImplicitCachingEnabled).to be(true)
|
|
62
|
+
expect(ActiveRecord::Base.connection.raw_connection.getStatementCacheSize).to eq(100)
|
|
63
|
+
# else: don't raise error if OCI connection has parameter "jdbc_statement_cache_size", still ignore it
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should not encrypt JDBC network connection" do
|
|
68
|
+
skip "Oracle 11g XE does not support native network encryption" if ENV["DATABASE_VERSION"] == "11.2.0.2"
|
|
69
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
70
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(jdbc_connect_properties: { "oracle.net.encryption_client" => "REJECTED" }))
|
|
71
|
+
conn = ActiveRecord::Base.connection.send(:_connection)
|
|
72
|
+
expect(conn.select("SELECT COUNT(*) Records FROM v$Session_Connect_Info WHERE SID=SYS_CONTEXT('USERENV', 'SID') AND Network_Service_Banner LIKE '%Encryption service adapter%'")).to eq([{ "records" => 0 }])
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "should encrypt JDBC network connection" do
|
|
77
|
+
skip "Oracle 11g XE does not support native network encryption" if ENV["DATABASE_VERSION"] == "11.2.0.2"
|
|
78
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
79
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(jdbc_connect_properties: { "oracle.net.encryption_client" => "REQUESTED" }))
|
|
80
|
+
conn = ActiveRecord::Base.connection.send(:_connection)
|
|
81
|
+
expect(conn.select("SELECT COUNT(*) Records FROM v$Session_Connect_Info WHERE SID=SYS_CONTEXT('USERENV', 'SID') AND Network_Service_Banner LIKE '%Encryption service adapter%'")).to eq([{ "records" => 1 }])
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should connect to database using service_name" do
|
|
86
|
+
ActiveRecord::Base.establish_connection(SERVICE_NAME_CONNECTION_PARAMS)
|
|
87
|
+
expect(ActiveRecord::Base.connection).not_to be_nil
|
|
88
|
+
expect(ActiveRecord::Base.connection.class).to eq(ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "OracleEnhancedConnection" do
|
|
93
|
+
describe "create connection" do
|
|
94
|
+
before(:all) do
|
|
95
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
before(:each) do
|
|
99
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS) unless @conn.active?
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "should create new connection" do
|
|
103
|
+
expect(@conn).to be_active
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "should ping active connection" do
|
|
107
|
+
expect(@conn.ping).to be_truthy
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "should not ping inactive connection" do
|
|
111
|
+
@conn.logoff
|
|
112
|
+
expect { @conn.ping }.to raise_error(ActiveRecord::ConnectionAdapters::OracleEnhanced::ConnectionException)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should reset active connection" do
|
|
116
|
+
@conn.reset!
|
|
117
|
+
expect(@conn).to be_active
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "should be in autocommit mode after connection" do
|
|
121
|
+
expect(@conn).to be_autocommit
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it "should raise ArgumentError when JDBC exec is called with bindvars" do
|
|
125
|
+
skip unless ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
126
|
+
expect {
|
|
127
|
+
@conn.exec("SELECT ? FROM dual", 1)
|
|
128
|
+
}.to raise_error(ArgumentError, /JDBC exec does not support bindvars/)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
describe "create connection with schema option" do
|
|
133
|
+
it "should create new connection" do
|
|
134
|
+
ActiveRecord::Base.establish_connection(CONNECTION_WITH_SCHEMA_PARAMS)
|
|
135
|
+
expect(ActiveRecord::Base.connection).to be_active
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "should switch to specified schema" do
|
|
139
|
+
ActiveRecord::Base.establish_connection(CONNECTION_WITH_SCHEMA_PARAMS)
|
|
140
|
+
expect(ActiveRecord::Base.connection.current_schema).to eq(CONNECTION_WITH_SCHEMA_PARAMS[:schema].upcase)
|
|
141
|
+
expect(ActiveRecord::Base.connection.current_user).to eq(CONNECTION_WITH_SCHEMA_PARAMS[:username].upcase)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should switch to specified schema after reset" do
|
|
145
|
+
ActiveRecord::Base.connection.reset!
|
|
146
|
+
expect(ActiveRecord::Base.connection.current_schema).to eq(CONNECTION_WITH_SCHEMA_PARAMS[:schema].upcase)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
describe "create connection with NLS parameters" do
|
|
151
|
+
after do
|
|
152
|
+
ENV["NLS_TERRITORY"] = nil
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "should use NLS_TERRITORY environment variable" do
|
|
156
|
+
ENV["NLS_TERRITORY"] = "JAPAN"
|
|
157
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
158
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_TERRITORY') as value from dual")).to eq([{ "value" => "JAPAN" }])
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "should use configuration value and ignore NLS_TERRITORY environment variable" do
|
|
162
|
+
ENV["NLS_TERRITORY"] = "AMERICA"
|
|
163
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS.merge(nls_territory: "INDONESIA"))
|
|
164
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_TERRITORY') as value from dual")).to eq([{ "value" => "INDONESIA" }])
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe "Fixed NLS parameters" do
|
|
169
|
+
after do
|
|
170
|
+
ENV["NLS_DATE_FORMAT"] = nil
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it "should ignore NLS_DATE_FORMAT environment variable" do
|
|
174
|
+
ENV["NLS_DATE_FORMAT"] = "YYYY-MM-DD"
|
|
175
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
176
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => "YYYY-MM-DD HH24:MI:SS" }])
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "should ignore NLS_DATE_FORMAT configuration value" do
|
|
180
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS.merge(nls_date_format: "YYYY-MM-DD HH24:MI"))
|
|
181
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => "YYYY-MM-DD HH24:MI:SS" }])
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "should use default value when NLS_DATE_FORMAT environment variable is not set" do
|
|
185
|
+
ENV["NLS_DATE_FORMAT"] = nil
|
|
186
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
187
|
+
default = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::FIXED_NLS_PARAMETERS[:nls_date_format]
|
|
188
|
+
expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => default }])
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
if defined?(OCI8)
|
|
193
|
+
describe "with TCP keepalive parameters" do
|
|
194
|
+
it "should use database default `tcp_keepalive` value true by default" do
|
|
195
|
+
ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
196
|
+
|
|
197
|
+
expect(OCI8.properties[:tcp_keepalive]).to be true
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
it "should use modified `tcp_keepalive` value false" do
|
|
201
|
+
ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS.dup.merge(tcp_keepalive: false))
|
|
202
|
+
|
|
203
|
+
expect(OCI8.properties[:tcp_keepalive]).to be false
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it "should use database default `tcp_keepalive_time` value 600 by default" do
|
|
207
|
+
ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
208
|
+
|
|
209
|
+
expect(OCI8.properties[:tcp_keepalive_time]).to eq(600)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "should use modified `tcp_keepalive_time` value 3000" do
|
|
213
|
+
ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS.dup.merge(tcp_keepalive_time: 3000))
|
|
214
|
+
|
|
215
|
+
expect(OCI8.properties[:tcp_keepalive_time]).to eq(3000)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
describe "with non-string parameters" do
|
|
221
|
+
before(:all) do
|
|
222
|
+
params = CONNECTION_PARAMS.dup
|
|
223
|
+
params[:username] = params[:username].to_sym
|
|
224
|
+
params[:password] = params[:password].to_sym
|
|
225
|
+
params[:database] = params[:database].to_sym
|
|
226
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it "should create new connection" do
|
|
230
|
+
expect(@conn).to be_active
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
describe "with slash-prefixed database name (service name)" do
|
|
235
|
+
before(:all) do
|
|
236
|
+
params = CONNECTION_PARAMS.dup
|
|
237
|
+
params[:database] = "/#{params[:database]}" unless params[:database].start_with?("/")
|
|
238
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it "should create new connection" do
|
|
242
|
+
expect(@conn).to be_active
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
describe "default_timezone" do
|
|
247
|
+
include SchemaSpecHelper
|
|
248
|
+
|
|
249
|
+
before(:all) do
|
|
250
|
+
ActiveRecord::Base.establish_connection(CONNECTION_WITH_TIMEZONE_PARAMS)
|
|
251
|
+
schema_define do
|
|
252
|
+
create_table :posts, force: true do |t|
|
|
253
|
+
t.timestamps null: false
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
class ::Post < ActiveRecord::Base
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
after(:all) do
|
|
261
|
+
Object.send(:remove_const, "Post") if defined?(Post)
|
|
262
|
+
ActiveRecord::Base.clear_cache!
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
it "should respect default_timezone = :utc than time_zone setting" do
|
|
266
|
+
# it expects that ActiveRecord.default_timezone = :utc
|
|
267
|
+
ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_WITH_TIMEZONE_PARAMS)
|
|
268
|
+
post = Post.create!
|
|
269
|
+
created_at = post.created_at
|
|
270
|
+
expect(post).to eq(Post.find_by!(created_at: created_at))
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
describe 'with host="connection-string"' do
|
|
275
|
+
let(:username) { CONNECTION_PARAMS[:username] }
|
|
276
|
+
let(:password) { CONNECTION_PARAMS[:password] }
|
|
277
|
+
let(:connection_string) { "(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=#{DATABASE_HOST})(PORT=#{DATABASE_PORT})))(CONNECT_DATA=(SERVICE_NAME=#{DATABASE_NAME})))" }
|
|
278
|
+
let(:params) { { username: username, password: password, host: "connection-string", database: connection_string } }
|
|
279
|
+
|
|
280
|
+
it "uses the database param as the connection string" do
|
|
281
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
282
|
+
expect(java.sql.DriverManager).to receive(:getConnection).with("jdbc:oracle:thin:@#{connection_string}", anything).and_call_original
|
|
283
|
+
else
|
|
284
|
+
expect(OCI8).to receive(:new).with(username, password, connection_string, nil).and_call_original
|
|
285
|
+
end
|
|
286
|
+
conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
|
287
|
+
expect(conn).to be_active
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
|
|
292
|
+
|
|
293
|
+
describe "create JDBC connection" do
|
|
294
|
+
it "should create new connection using :url" do
|
|
295
|
+
params = CONNECTION_PARAMS.dup
|
|
296
|
+
params[:url] = "jdbc:oracle:thin:@#{DATABASE_HOST && "//#{DATABASE_HOST}#{DATABASE_PORT && ":#{DATABASE_PORT}"}/"}#{DATABASE_NAME}"
|
|
297
|
+
|
|
298
|
+
params[:host] = nil
|
|
299
|
+
params[:database] = nil
|
|
300
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
|
301
|
+
expect(@conn).to be_active
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "should create new connection using :url and tnsnames alias" do
|
|
305
|
+
params = CONNECTION_PARAMS.dup
|
|
306
|
+
params[:url] = "jdbc:oracle:thin:@#{DATABASE_NAME}"
|
|
307
|
+
params[:host] = nil
|
|
308
|
+
params[:database] = nil
|
|
309
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
|
310
|
+
expect(@conn).to be_active
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it "should create new connection using just tnsnames alias" do
|
|
314
|
+
params = CONNECTION_PARAMS.dup
|
|
315
|
+
params[:host] = nil
|
|
316
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
|
317
|
+
expect(@conn).to be_active
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it "should create a new connection using JNDI" do
|
|
321
|
+
begin
|
|
322
|
+
import "oracle.jdbc.driver.OracleDriver"
|
|
323
|
+
import "org.apache.commons.pool.impl.GenericObjectPool"
|
|
324
|
+
import "org.apache.commons.dbcp.PoolingDataSource"
|
|
325
|
+
import "org.apache.commons.dbcp.PoolableConnectionFactory"
|
|
326
|
+
import "org.apache.commons.dbcp.DriverManagerConnectionFactory"
|
|
327
|
+
rescue NameError => e
|
|
328
|
+
return skip e.message
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
class InitialContextMock
|
|
332
|
+
def initialize
|
|
333
|
+
connection_pool = GenericObjectPool.new(nil)
|
|
334
|
+
uri = "jdbc:oracle:thin:@#{DATABASE_HOST && "#{DATABASE_HOST}:"}#{DATABASE_PORT && "#{DATABASE_PORT}:"}#{DATABASE_NAME}"
|
|
335
|
+
connection_factory = DriverManagerConnectionFactory.new(uri, DATABASE_USER, DATABASE_PASSWORD)
|
|
336
|
+
PoolableConnectionFactory.new(connection_factory, connection_pool, nil, nil, false, true)
|
|
337
|
+
@data_source = PoolingDataSource.new(connection_pool)
|
|
338
|
+
@data_source.access_to_underlying_connection_allowed = true
|
|
339
|
+
end
|
|
340
|
+
def lookup(path)
|
|
341
|
+
if path == "java:/comp/env"
|
|
342
|
+
self
|
|
343
|
+
else
|
|
344
|
+
@data_source
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
allow(javax.naming.InitialContext).to receive(:new).and_return(InitialContextMock.new)
|
|
350
|
+
|
|
351
|
+
params = {}
|
|
352
|
+
params[:jndi] = "java:comp/env/jdbc/test"
|
|
353
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
|
354
|
+
expect(@conn).to be_active
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
it "should fall back to directly instantiating OracleDriver" do
|
|
359
|
+
params = CONNECTION_PARAMS.dup
|
|
360
|
+
params[:url] = "jdbc:oracle:thin:@#{DATABASE_HOST && "//#{DATABASE_HOST}#{DATABASE_PORT && ":#{DATABASE_PORT}"}/"}#{DATABASE_NAME}"
|
|
361
|
+
params[:host] = nil
|
|
362
|
+
params[:database] = nil
|
|
363
|
+
allow(java.sql.DriverManager).to receive(:getConnection).and_raise("no suitable driver found")
|
|
364
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
|
|
365
|
+
expect(@conn).to be_active
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
describe "SQL execution" do
|
|
371
|
+
before(:all) do
|
|
372
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
it "should execute SQL statement" do
|
|
376
|
+
expect(@conn.exec("SELECT * FROM dual")).not_to be_nil
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
it "should execute SQL select" do
|
|
380
|
+
expect(@conn.select("SELECT * FROM dual")).to eq([{ "dummy" => "X" }])
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
it "should execute SQL select and return also columns" do
|
|
384
|
+
expect(@conn.select("SELECT * FROM dual", nil, true)).to eq([ [{ "dummy" => "X" }], ["dummy"] ])
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
describe "SQL with bind parameters" do
|
|
389
|
+
before(:all) do
|
|
390
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
it "should execute SQL statement with bind parameter" do
|
|
394
|
+
cursor = @conn.prepare("SELECT * FROM dual WHERE :1 = 1")
|
|
395
|
+
cursor.bind_param(1, 1)
|
|
396
|
+
cursor.exec
|
|
397
|
+
expect(cursor.get_col_names).to eq(["DUMMY"])
|
|
398
|
+
expect(cursor.fetch).to eq(["X"])
|
|
399
|
+
cursor.close
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
it "should execute prepared statement with different bind parameters" do
|
|
403
|
+
cursor = @conn.prepare("SELECT * FROM dual WHERE :1 = 1")
|
|
404
|
+
cursor.bind_param(1, 1)
|
|
405
|
+
cursor.exec
|
|
406
|
+
expect(cursor.fetch).to eq(["X"])
|
|
407
|
+
cursor.bind_param(1, 0)
|
|
408
|
+
cursor.exec
|
|
409
|
+
expect(cursor.fetch).to be_nil
|
|
410
|
+
cursor.close
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
describe "SQL with bind parameters when NLS_NUMERIC_CHARACTERS is set to ', '" do
|
|
415
|
+
before(:all) do
|
|
416
|
+
ENV["NLS_NUMERIC_CHARACTERS"] = ", "
|
|
417
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
418
|
+
@conn_base = ActiveRecord::Base.connection
|
|
419
|
+
@conn = @conn_base.send(:_connection)
|
|
420
|
+
@conn.exec "CREATE TABLE test_employees (age NUMBER(10,2))"
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
after(:all) do
|
|
424
|
+
ENV["NLS_NUMERIC_CHARACTERS"] = nil
|
|
425
|
+
@conn.exec "DROP TABLE test_employees" rescue nil
|
|
426
|
+
ActiveRecord::Base.clear_cache!
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
it "should execute prepared statement with decimal bind parameter" do
|
|
430
|
+
cursor = @conn.prepare("INSERT INTO test_employees VALUES(:1)")
|
|
431
|
+
type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "NUMBER", type: :decimal, limit: 10, precision: nil, scale: 2)
|
|
432
|
+
cast_type = @conn_base.lookup_cast_type("NUMBER(10,2)")
|
|
433
|
+
column = ActiveRecord::ConnectionAdapters::OracleEnhanced::Column.new("age", cast_type, nil, type_metadata, false, comment: nil)
|
|
434
|
+
expect(column.type).to eq(:decimal)
|
|
435
|
+
# Here 1.5 expects that this value has been type casted already
|
|
436
|
+
# it should use bind_params in the long term.
|
|
437
|
+
cursor.bind_param(1, 1.5)
|
|
438
|
+
cursor.exec
|
|
439
|
+
cursor.close
|
|
440
|
+
cursor = @conn.prepare("SELECT age FROM test_employees")
|
|
441
|
+
cursor.exec
|
|
442
|
+
expect(cursor.fetch).to eq([1.5])
|
|
443
|
+
cursor.close
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
describe "auto reconnection" do
|
|
448
|
+
include SchemaSpecHelper
|
|
449
|
+
|
|
450
|
+
before(:all) do
|
|
451
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
452
|
+
@conn = ActiveRecord::Base.connection.send(:_connection)
|
|
453
|
+
@sys_conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(SYS_CONNECTION_PARAMS)
|
|
454
|
+
schema_define do
|
|
455
|
+
create_table :posts, force: true
|
|
456
|
+
end
|
|
457
|
+
class ::Post < ActiveRecord::Base
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
after(:all) do
|
|
462
|
+
Object.send(:remove_const, "Post")
|
|
463
|
+
ActiveRecord::Base.clear_cache!
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
before(:each) do
|
|
467
|
+
ActiveRecord::Base.connection.reconnect! unless @conn.active?
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def kill_current_session
|
|
471
|
+
audsid = @conn.select("SELECT userenv('sessionid') audsid FROM dual").first["audsid"]
|
|
472
|
+
sid_serial = @sys_conn.select("SELECT s.sid||','||s.serial# sid_serial
|
|
473
|
+
FROM v$session s
|
|
474
|
+
WHERE audsid = '#{audsid}'").first["sid_serial"]
|
|
475
|
+
@sys_conn.exec "ALTER SYSTEM KILL SESSION '#{sid_serial}' IMMEDIATE"
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
it "should reconnect and execute SQL statement if connection is lost and auto retry is enabled" do
|
|
479
|
+
# @conn.auto_retry = true
|
|
480
|
+
ActiveRecord::Base.connection.auto_retry = true
|
|
481
|
+
kill_current_session
|
|
482
|
+
expect(@conn.exec("SELECT * FROM dual")).not_to be_nil
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
it "should reconnect and execute SQL statement if connection is lost and allow_retry is passed" do
|
|
486
|
+
kill_current_session
|
|
487
|
+
expect(@conn.exec("SELECT * FROM dual", allow_retry: true)).not_to be_nil
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
it "should not reconnect and execute SQL statement if connection is lost and auto retry is disabled" do
|
|
491
|
+
# @conn.auto_retry = false
|
|
492
|
+
ActiveRecord::Base.connection.auto_retry = false
|
|
493
|
+
kill_current_session
|
|
494
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
|
|
495
|
+
expect { @conn.exec("SELECT * FROM dual") }.to raise_error(Java::JavaSql::SQLRecoverableException)
|
|
496
|
+
else
|
|
497
|
+
expect { @conn.exec("SELECT * FROM dual") }.to raise_error(OCIError)
|
|
498
|
+
end
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it "should reconnect and execute SQL select if connection is lost and auto retry is enabled" do
|
|
502
|
+
# @conn.auto_retry = true
|
|
503
|
+
ActiveRecord::Base.connection.auto_retry = true
|
|
504
|
+
kill_current_session
|
|
505
|
+
expect(@conn.select("SELECT * FROM dual")).to eq([{ "dummy" => "X" }])
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
it "should not reconnect and execute SQL select if connection is lost and auto retry is disabled" do
|
|
509
|
+
# @conn.auto_retry = false
|
|
510
|
+
ActiveRecord::Base.connection.auto_retry = false
|
|
511
|
+
kill_current_session
|
|
512
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
|
|
513
|
+
expect { @conn.select("SELECT * FROM dual") }.to raise_error(Java::JavaSql::SQLRecoverableException)
|
|
514
|
+
else
|
|
515
|
+
expect { @conn.select("SELECT * FROM dual") }.to raise_error(OCIError)
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
it "should reconnect and execute query if connection is lost and auto retry is enabled" do
|
|
520
|
+
Post.create!
|
|
521
|
+
ActiveRecord::Base.connection.auto_retry = true
|
|
522
|
+
kill_current_session
|
|
523
|
+
expect(Post.take).not_to be_nil
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
it "should not reconnect and execute query if connection is lost and auto retry is disabled" do
|
|
527
|
+
Post.create!
|
|
528
|
+
ActiveRecord::Base.connection.auto_retry = false
|
|
529
|
+
kill_current_session
|
|
530
|
+
expect { Post.take }.to raise_error(ActiveRecord::StatementInvalid)
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
describe "describe table" do
|
|
535
|
+
before(:all) do
|
|
536
|
+
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
|
|
537
|
+
@owner = CONNECTION_PARAMS[:username].upcase
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
it "should describe existing table" do
|
|
541
|
+
@conn.exec "CREATE TABLE test_employees (first_name VARCHAR2(20))" rescue nil
|
|
542
|
+
expect(@conn.describe("test_employees")).to eq([@owner, "TEST_EMPLOYEES"])
|
|
543
|
+
@conn.exec "DROP TABLE test_employees" rescue nil
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
it "should not describe non-existing table" do
|
|
547
|
+
expect { @conn.describe("test_xxx") }.to raise_error(ActiveRecord::ConnectionAdapters::OracleEnhanced::ConnectionException)
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
it "should describe table in other schema" do
|
|
551
|
+
expect(@conn.describe("sys.dual")).to eq(["SYS", "DUAL"])
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
it "should describe table in other schema if the schema and table are in different cases" do
|
|
555
|
+
expect(@conn.describe("SYS.dual")).to eq(["SYS", "DUAL"])
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
it "should describe existing view" do
|
|
559
|
+
@conn.exec "CREATE TABLE test_employees (first_name VARCHAR2(20))" rescue nil
|
|
560
|
+
@conn.exec "CREATE VIEW test_employees_v AS SELECT * FROM test_employees" rescue nil
|
|
561
|
+
expect(@conn.describe("test_employees_v")).to eq([@owner, "TEST_EMPLOYEES_V"])
|
|
562
|
+
@conn.exec "DROP VIEW test_employees_v" rescue nil
|
|
563
|
+
@conn.exec "DROP TABLE test_employees" rescue nil
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
it "should describe view in other schema" do
|
|
567
|
+
expect(@conn.describe("sys.v_$version")).to eq(["SYS", "V_$VERSION"])
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
it "should describe existing private synonym" do
|
|
571
|
+
@conn.exec "CREATE SYNONYM test_dual FOR sys.dual" rescue nil
|
|
572
|
+
expect(@conn.describe("test_dual")).to eq(["SYS", "DUAL"])
|
|
573
|
+
@conn.exec "DROP SYNONYM test_dual" rescue nil
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
it "should describe existing public synonym" do
|
|
577
|
+
expect(@conn.describe("all_tables")).to eq(["SYS", "ALL_TABLES"])
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
if defined?(OCI8)
|
|
581
|
+
context "OCI8 adapter" do
|
|
582
|
+
it "should not fallback to SELECT-based logic when querying non-existent table information" do
|
|
583
|
+
expect(@conn).not_to receive(:select_one)
|
|
584
|
+
@conn.describe("non_existent") rescue ActiveRecord::ConnectionAdapters::OracleEnhanced::ConnectionException
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
end
|