activerecord-oracle_enhanced-adapter 1.4.3 → 5.2.0
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 +5 -5
- data/History.md +1162 -2
- data/README.md +567 -155
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +3 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +19 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +132 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +345 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +52 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +280 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +64 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +59 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +538 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +46 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +435 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +196 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +164 -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 +79 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +194 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +709 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +28 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +353 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +33 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +385 -1083
- data/lib/active_record/type/oracle_enhanced/boolean.rb +20 -0
- data/lib/active_record/type/oracle_enhanced/integer.rb +15 -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 +5 -13
- data/spec/active_record/connection_adapters/{oracle_enhanced_emulate_oracle_adapter_spec.rb → emulation/oracle_adapter_spec.rb} +5 -4
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +469 -0
- data/spec/active_record/connection_adapters/{oracle_enhanced_context_index_spec.rb → oracle_enhanced/context_index_spec.rb} +140 -128
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +112 -0
- data/spec/active_record/connection_adapters/{oracle_enhanced_dbms_output_spec.rb → oracle_enhanced/dbms_output_spec.rb} +13 -13
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +365 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +196 -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 +1433 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +478 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +385 -550
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +92 -1249
- data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +208 -0
- data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +139 -0
- data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +91 -0
- data/spec/active_record/oracle_enhanced/type/json_spec.rb +57 -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 +122 -0
- data/spec/active_record/oracle_enhanced/type/text_spec.rb +229 -0
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +75 -0
- data/spec/spec_config.yaml.template +11 -0
- data/spec/spec_helper.rb +100 -93
- 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 +105 -152
- data/.rspec +0 -2
- data/Gemfile +0 -52
- data/RUNNING_TESTS.md +0 -45
- data/Rakefile +0 -59
- data/activerecord-oracle_enhanced-adapter.gemspec +0 -130
- data/lib/active_record/connection_adapters/oracle_enhanced.rake +0 -105
- data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +0 -41
- data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +0 -121
- data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +0 -151
- data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +0 -119
- data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +0 -359
- data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +0 -25
- data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +0 -21
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +0 -46
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +0 -572
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +0 -497
- data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +0 -260
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +0 -227
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +0 -260
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +0 -428
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +0 -258
- data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +0 -294
- data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +0 -17
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +0 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +0 -334
- data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +0 -19
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +0 -113
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +0 -141
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +0 -378
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +0 -440
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +0 -1400
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +0 -339
|
@@ -0,0 +1,1433 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe "OracleEnhancedAdapter schema definition" do
|
|
4
|
+
include SchemaSpecHelper
|
|
5
|
+
include LoggerSpecHelper
|
|
6
|
+
|
|
7
|
+
before(:all) do
|
|
8
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
9
|
+
@oracle11g_or_higher = !! !! ActiveRecord::Base.connection.select_value(
|
|
10
|
+
"select * from product_component_version where product like 'Oracle%' and to_number(substr(version,1,2)) >= 11")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "option to create sequence when adding a column" do
|
|
14
|
+
before do
|
|
15
|
+
@conn = ActiveRecord::Base.connection
|
|
16
|
+
schema_define do
|
|
17
|
+
create_table :keyboards, force: true, id: false do |t|
|
|
18
|
+
t.string :name
|
|
19
|
+
end
|
|
20
|
+
add_column :keyboards, :id, :primary_key
|
|
21
|
+
end
|
|
22
|
+
class ::Keyboard < ActiveRecord::Base; end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "creates a sequence when adding a column with create_sequence = true" do
|
|
26
|
+
_, sequence_name = ActiveRecord::Base.connection.pk_and_sequence_for(:keyboards)
|
|
27
|
+
|
|
28
|
+
expect(sequence_name).to eq(Keyboard.sequence_name)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "table and sequence creation with non-default primary key" do
|
|
33
|
+
|
|
34
|
+
before(:all) do
|
|
35
|
+
@conn = ActiveRecord::Base.connection
|
|
36
|
+
schema_define do
|
|
37
|
+
create_table :keyboards, force: true, id: false do |t|
|
|
38
|
+
t.primary_key :key_number
|
|
39
|
+
t.string :name
|
|
40
|
+
end
|
|
41
|
+
create_table :id_keyboards, force: true do |t|
|
|
42
|
+
t.string :name
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
class ::Keyboard < ActiveRecord::Base
|
|
46
|
+
self.primary_key = :key_number
|
|
47
|
+
end
|
|
48
|
+
class ::IdKeyboard < ActiveRecord::Base
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
after(:all) do
|
|
53
|
+
schema_define do
|
|
54
|
+
drop_table :keyboards
|
|
55
|
+
drop_table :id_keyboards
|
|
56
|
+
end
|
|
57
|
+
Object.send(:remove_const, "Keyboard")
|
|
58
|
+
Object.send(:remove_const, "IdKeyboard")
|
|
59
|
+
ActiveRecord::Base.clear_cache!
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should create sequence for non-default primary key" do
|
|
63
|
+
expect(ActiveRecord::Base.connection.next_sequence_value(Keyboard.sequence_name)).not_to be_nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "should create sequence for default primary key" do
|
|
67
|
+
expect(ActiveRecord::Base.connection.next_sequence_value(IdKeyboard.sequence_name)).not_to be_nil
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "default sequence name" do
|
|
72
|
+
|
|
73
|
+
it "should return sequence name without truncating too much" do
|
|
74
|
+
seq_name_length = ActiveRecord::Base.connection.sequence_name_length
|
|
75
|
+
tname = "#{DATABASE_USER}" + "." + "a" * (seq_name_length - DATABASE_USER.length) + "z" * (DATABASE_USER).length
|
|
76
|
+
expect(ActiveRecord::Base.connection.default_sequence_name(tname)).to match (/z_seq$/)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe "sequence creation parameters" do
|
|
81
|
+
|
|
82
|
+
def create_test_employees_table(sequence_start_value = nil)
|
|
83
|
+
schema_define do
|
|
84
|
+
create_table :test_employees, sequence_start_value ? { sequence_start_value: sequence_start_value } : {} do |t|
|
|
85
|
+
t.string :first_name
|
|
86
|
+
t.string :last_name
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def save_default_sequence_start_value
|
|
92
|
+
@saved_sequence_start_value = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def restore_default_sequence_start_value
|
|
96
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = @saved_sequence_start_value
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
before(:all) do
|
|
100
|
+
@conn = ActiveRecord::Base.connection
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
before(:each) do
|
|
104
|
+
save_default_sequence_start_value
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
after(:each) do
|
|
108
|
+
restore_default_sequence_start_value
|
|
109
|
+
schema_define do
|
|
110
|
+
drop_table :test_employees
|
|
111
|
+
end
|
|
112
|
+
Object.send(:remove_const, "TestEmployee")
|
|
113
|
+
ActiveRecord::Base.clear_cache!
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "should use default sequence start value 10000" do
|
|
117
|
+
expect(ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value).to eq(10000)
|
|
118
|
+
|
|
119
|
+
create_test_employees_table
|
|
120
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
121
|
+
|
|
122
|
+
employee = TestEmployee.create!
|
|
123
|
+
expect(employee.id).to eq(10000)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "should use specified default sequence start value" do
|
|
127
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = 1
|
|
128
|
+
|
|
129
|
+
create_test_employees_table
|
|
130
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
131
|
+
|
|
132
|
+
employee = TestEmployee.create!
|
|
133
|
+
expect(employee.id).to eq(1)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "should use sequence start value from table definition" do
|
|
137
|
+
create_test_employees_table(10)
|
|
138
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
139
|
+
|
|
140
|
+
employee = TestEmployee.create!
|
|
141
|
+
expect(employee.id).to eq(10)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should use sequence start value and other options from table definition" do
|
|
145
|
+
create_test_employees_table("100 NOCACHE INCREMENT BY 10")
|
|
146
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
147
|
+
|
|
148
|
+
employee = TestEmployee.create!
|
|
149
|
+
expect(employee.id).to eq(100)
|
|
150
|
+
employee = TestEmployee.create!
|
|
151
|
+
expect(employee.id).to eq(110)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
describe "create table with primary key trigger" do
|
|
157
|
+
def create_table_with_trigger(options = {})
|
|
158
|
+
options.merge! primary_key_trigger: true, force: true
|
|
159
|
+
schema_define do
|
|
160
|
+
create_table :test_employees, options do |t|
|
|
161
|
+
t.string :first_name
|
|
162
|
+
t.string :last_name
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def create_table_and_separately_trigger(options = {})
|
|
168
|
+
options.merge! force: true
|
|
169
|
+
schema_define do
|
|
170
|
+
create_table :test_employees, options do |t|
|
|
171
|
+
t.string :first_name
|
|
172
|
+
t.string :last_name
|
|
173
|
+
end
|
|
174
|
+
add_primary_key_trigger :test_employees, options
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def drop_table_with_trigger(options = {})
|
|
179
|
+
seq_name = options[:sequence_name]
|
|
180
|
+
schema_define do
|
|
181
|
+
drop_table :test_employees, (seq_name ? { sequence_name: seq_name } : {})
|
|
182
|
+
end
|
|
183
|
+
Object.send(:remove_const, "TestEmployee")
|
|
184
|
+
ActiveRecord::Base.clear_cache!
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
describe "with default primary key" do
|
|
188
|
+
before(:all) do
|
|
189
|
+
@conn = ActiveRecord::Base.connection
|
|
190
|
+
create_table_with_trigger
|
|
191
|
+
class ::TestEmployee < ActiveRecord::Base
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
after(:all) do
|
|
196
|
+
drop_table_with_trigger
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "should populate primary key using trigger" do
|
|
200
|
+
expect do
|
|
201
|
+
@conn.execute "INSERT INTO test_employees (first_name) VALUES ('Raimonds')"
|
|
202
|
+
end.not_to raise_error
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it "should return new key value using connection insert method" do
|
|
206
|
+
insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Raimonds')", nil, "id")
|
|
207
|
+
expect(@conn.select_value("SELECT test_employees_seq.currval FROM dual")).to eq(insert_id)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it "should create new record for model" do
|
|
211
|
+
e = TestEmployee.create!(first_name: "Raimonds")
|
|
212
|
+
expect(@conn.select_value("SELECT test_employees_seq.currval FROM dual")).to eq(e.id)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it "should not generate NoMethodError for :returning_id:Symbol" do
|
|
216
|
+
set_logger
|
|
217
|
+
@conn.reconnect! unless @conn.active?
|
|
218
|
+
@conn.insert("INSERT INTO test_employees (first_name) VALUES ('Yasuo')", nil, "id")
|
|
219
|
+
expect(@logger.output(:error)).not_to match(/^Could not log "sql.active_record" event. NoMethodError: undefined method `name' for :returning_id:Symbol/)
|
|
220
|
+
clear_logger
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe "with separate creation of primary key trigger" do
|
|
226
|
+
before(:all) do
|
|
227
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
228
|
+
@conn = ActiveRecord::Base.connection
|
|
229
|
+
create_table_and_separately_trigger
|
|
230
|
+
class ::TestEmployee < ActiveRecord::Base
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
after(:all) do
|
|
235
|
+
drop_table_with_trigger
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "should populate primary key using trigger" do
|
|
239
|
+
expect do
|
|
240
|
+
@conn.execute "INSERT INTO test_employees (first_name) VALUES ('Raimonds')"
|
|
241
|
+
end.not_to raise_error
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it "should return new key value using connection insert method" do
|
|
245
|
+
insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Raimonds')", nil, "id")
|
|
246
|
+
expect(@conn.select_value("SELECT test_employees_seq.currval FROM dual")).to eq(insert_id)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
it "should create new record for model" do
|
|
250
|
+
e = TestEmployee.create!(first_name: "Raimonds")
|
|
251
|
+
expect(@conn.select_value("SELECT test_employees_seq.currval FROM dual")).to eq(e.id)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
describe "with non-default primary key and non-default sequence name" do
|
|
256
|
+
before(:all) do
|
|
257
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
258
|
+
@conn = ActiveRecord::Base.connection
|
|
259
|
+
@primary_key = "employee_id"
|
|
260
|
+
@sequence_name = "test_employees_s"
|
|
261
|
+
create_table_with_trigger(primary_key: @primary_key, sequence_name: @sequence_name)
|
|
262
|
+
class ::TestEmployee < ActiveRecord::Base
|
|
263
|
+
self.primary_key = "employee_id"
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
after(:all) do
|
|
268
|
+
drop_table_with_trigger(sequence_name: @sequence_name)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it "should populate primary key using trigger" do
|
|
272
|
+
expect do
|
|
273
|
+
@conn.execute "INSERT INTO test_employees (first_name) VALUES ('Raimonds')"
|
|
274
|
+
end.not_to raise_error
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it "should return new key value using connection insert method" do
|
|
278
|
+
insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Raimonds')", nil, @primary_key)
|
|
279
|
+
expect(@conn.select_value("SELECT #{@sequence_name}.currval FROM dual")).to eq(insert_id)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it "should create new record for model with autogenerated sequence option" do
|
|
283
|
+
e = TestEmployee.create!(first_name: "Raimonds")
|
|
284
|
+
expect(@conn.select_value("SELECT #{@sequence_name}.currval FROM dual")).to eq(e.id)
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
describe "with non-default sequence name and non-default trigger name" do
|
|
289
|
+
before(:all) do
|
|
290
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
291
|
+
@conn = ActiveRecord::Base.connection
|
|
292
|
+
@sequence_name = "test_employees_s"
|
|
293
|
+
create_table_with_trigger(sequence_name: @sequence_name, trigger_name: "test_employees_t1")
|
|
294
|
+
class ::TestEmployee < ActiveRecord::Base
|
|
295
|
+
self.sequence_name = :autogenerated
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
after(:all) do
|
|
300
|
+
drop_table_with_trigger(sequence_name: @sequence_name)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it "should populate primary key using trigger" do
|
|
304
|
+
expect do
|
|
305
|
+
@conn.execute "INSERT INTO test_employees (first_name) VALUES ('Raimonds')"
|
|
306
|
+
end.not_to raise_error
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
it "should return new key value using connection insert method" do
|
|
310
|
+
insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Raimonds')", nil, "id")
|
|
311
|
+
expect(@conn.select_value("SELECT #{@sequence_name}.currval FROM dual")).to eq(insert_id)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it "should create new record for model with autogenerated sequence option" do
|
|
315
|
+
e = TestEmployee.create!(first_name: "Raimonds")
|
|
316
|
+
expect(@conn.select_value("SELECT #{@sequence_name}.currval FROM dual")).to eq(e.id)
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
describe "table and column comments" do
|
|
323
|
+
|
|
324
|
+
def create_test_employees_table(table_comment = nil, column_comments = {})
|
|
325
|
+
schema_define do
|
|
326
|
+
create_table :test_employees, comment: table_comment do |t|
|
|
327
|
+
t.string :first_name, comment: column_comments[:first_name]
|
|
328
|
+
t.string :last_name, comment: column_comments[:last_name]
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
before(:all) do
|
|
334
|
+
@conn = ActiveRecord::Base.connection
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
before(:each) do
|
|
338
|
+
@conn.clear_cache!
|
|
339
|
+
set_logger
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
after(:each) do
|
|
343
|
+
clear_logger
|
|
344
|
+
schema_define do
|
|
345
|
+
drop_table :test_employees
|
|
346
|
+
end
|
|
347
|
+
Object.send(:remove_const, "TestEmployee")
|
|
348
|
+
ActiveRecord::Base.table_name_prefix = ""
|
|
349
|
+
ActiveRecord::Base.clear_cache!
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
it "should create table with table comment" do
|
|
353
|
+
table_comment = "Test Employees"
|
|
354
|
+
create_test_employees_table(table_comment)
|
|
355
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
356
|
+
expect(@conn.table_comment("test_employees")).to eq(table_comment)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
it "should create table with columns comment" do
|
|
360
|
+
column_comments = { first_name: "Given Name", last_name: "Surname" }
|
|
361
|
+
create_test_employees_table(nil, column_comments)
|
|
362
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
363
|
+
|
|
364
|
+
[:first_name, :last_name].each do |attr|
|
|
365
|
+
expect(@conn.column_comment("test_employees", attr.to_s)).to eq(column_comments[attr])
|
|
366
|
+
end
|
|
367
|
+
[:first_name, :last_name].each do |attr|
|
|
368
|
+
expect(TestEmployee.columns_hash[attr.to_s].comment).to eq(column_comments[attr])
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
it "should create table with table and columns comment and custom table name prefix" do
|
|
373
|
+
ActiveRecord::Base.table_name_prefix = "xxx_"
|
|
374
|
+
table_comment = "Test Employees"
|
|
375
|
+
column_comments = { first_name: "Given Name", last_name: "Surname" }
|
|
376
|
+
create_test_employees_table(table_comment, column_comments)
|
|
377
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
378
|
+
|
|
379
|
+
expect(@conn.table_comment(TestEmployee.table_name)).to eq(table_comment)
|
|
380
|
+
[:first_name, :last_name].each do |attr|
|
|
381
|
+
expect(@conn.column_comment(TestEmployee.table_name, attr.to_s)).to eq(column_comments[attr])
|
|
382
|
+
end
|
|
383
|
+
[:first_name, :last_name].each do |attr|
|
|
384
|
+
expect(TestEmployee.columns_hash[attr.to_s].comment).to eq(column_comments[attr])
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
it "should query table_comment using bind variables" do
|
|
389
|
+
table_comment = "Test Employees"
|
|
390
|
+
create_test_employees_table(table_comment)
|
|
391
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
392
|
+
expect(@conn.table_comment(TestEmployee.table_name)).to eq(table_comment)
|
|
393
|
+
expect(@logger.logged(:debug).last).to match(/:owner/)
|
|
394
|
+
expect(@logger.logged(:debug).last).to match(/:table_name/)
|
|
395
|
+
expect(@logger.logged(:debug).last).to match(/\[\["owner", "#{DATABASE_USER.upcase}"\], \["table_name", "TEST_EMPLOYEES"\]\]/)
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
it "should query column_comment using bind variables" do
|
|
399
|
+
table_comment = "Test Employees"
|
|
400
|
+
column_comment = { first_name: "Given Name" }
|
|
401
|
+
create_test_employees_table(table_comment, column_comment)
|
|
402
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
403
|
+
expect(@conn.column_comment(TestEmployee.table_name, :first_name)).to eq(column_comment[:first_name])
|
|
404
|
+
expect(@logger.logged(:debug).last).to match(/:owner/)
|
|
405
|
+
expect(@logger.logged(:debug).last).to match(/:table_name/)
|
|
406
|
+
expect(@logger.logged(:debug).last).to match(/:column_name/)
|
|
407
|
+
expect(@logger.logged(:debug).last).to match(/\[\["owner", "#{DATABASE_USER.upcase}"\], \["table_name", "TEST_EMPLOYEES"\], \["column_name", "FIRST_NAME"\]\]/)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
describe "drop tables" do
|
|
413
|
+
before(:each) do
|
|
414
|
+
@conn = ActiveRecord::Base.connection
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
it "should drop table with :if_exists option no raise error" do
|
|
418
|
+
expect do
|
|
419
|
+
@conn.drop_table("nonexistent_table", if_exists: true)
|
|
420
|
+
end.not_to raise_error
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
describe "rename tables and sequences" do
|
|
425
|
+
before(:each) do
|
|
426
|
+
@conn = ActiveRecord::Base.connection
|
|
427
|
+
schema_define do
|
|
428
|
+
create_table :test_employees, force: true do |t|
|
|
429
|
+
t.string :first_name
|
|
430
|
+
t.string :last_name
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
create_table :test_employees_no_pkey, force: true, id: false do |t|
|
|
434
|
+
t.string :first_name
|
|
435
|
+
t.string :last_name
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
after(:each) do
|
|
441
|
+
schema_define do
|
|
442
|
+
drop_table :test_employees_no_primary_key, if_exists: true
|
|
443
|
+
drop_table :test_employees, if_exists: true
|
|
444
|
+
drop_table :new_test_employees, if_exists: true
|
|
445
|
+
drop_table :test_employees_no_pkey, if_exists: true
|
|
446
|
+
drop_table :new_test_employees_no_pkey, if_exists: true
|
|
447
|
+
drop_table :aaaaaaaaaaaaaaaaaaaaaaaaaaa, if_exists: true
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
it "should rename table name with new one" do
|
|
452
|
+
expect do
|
|
453
|
+
@conn.rename_table("test_employees", "new_test_employees")
|
|
454
|
+
end.not_to raise_error
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
it "should raise error when new table name length is too long" do
|
|
458
|
+
expect do
|
|
459
|
+
@conn.rename_table("test_employees", "a" * 31)
|
|
460
|
+
end.to raise_error(ArgumentError)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
it "should not raise error when new sequence name length is too long" do
|
|
464
|
+
expect do
|
|
465
|
+
@conn.rename_table("test_employees", "a" * 27)
|
|
466
|
+
end.not_to raise_error
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
it "should rename table when table has no primary key and sequence" do
|
|
470
|
+
expect do
|
|
471
|
+
@conn.rename_table("test_employees_no_pkey", "new_test_employees_no_pkey")
|
|
472
|
+
end.not_to raise_error
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
describe "create triggers" do
|
|
478
|
+
|
|
479
|
+
before(:all) do
|
|
480
|
+
@conn = ActiveRecord::Base.connection
|
|
481
|
+
schema_define do
|
|
482
|
+
create_table :test_employees do |t|
|
|
483
|
+
t.string :first_name
|
|
484
|
+
t.string :last_name
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
after(:all) do
|
|
491
|
+
schema_define do
|
|
492
|
+
drop_table :test_employees
|
|
493
|
+
end
|
|
494
|
+
Object.send(:remove_const, "TestEmployee")
|
|
495
|
+
ActiveRecord::Base.clear_cache!
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
it "should create table trigger with :new reference" do
|
|
499
|
+
expect do
|
|
500
|
+
@conn.execute <<-SQL
|
|
501
|
+
CREATE OR REPLACE TRIGGER test_employees_pkt
|
|
502
|
+
BEFORE INSERT ON test_employees FOR EACH ROW
|
|
503
|
+
BEGIN
|
|
504
|
+
IF inserting THEN
|
|
505
|
+
IF :new.id IS NULL THEN
|
|
506
|
+
SELECT test_employees_seq.NEXTVAL INTO :new.id FROM dual;
|
|
507
|
+
END IF;
|
|
508
|
+
END IF;
|
|
509
|
+
END;
|
|
510
|
+
SQL
|
|
511
|
+
end.not_to raise_error
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
describe "add index" do
|
|
516
|
+
before(:all) do
|
|
517
|
+
@conn = ActiveRecord::Base.connection
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
it "should return default index name if it is not larger than 30 characters" do
|
|
521
|
+
expect(@conn.index_name("employees", column: "first_name")).to eq("index_employees_on_first_name")
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
it "should return shortened index name by removing 'index', 'on' and 'and' keywords" do
|
|
525
|
+
expect(@conn.index_name("employees", column: ["first_name", "email"])).to eq("i_employees_first_name_email")
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
it "should return shortened index name by shortening table and column names" do
|
|
529
|
+
expect(@conn.index_name("employees", column: ["first_name", "last_name"])).to eq("i_emp_fir_nam_las_nam")
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
it "should raise error if too large index name cannot be shortened" do
|
|
533
|
+
expect(@conn.index_name("test_employees", column: ["first_name", "middle_name", "last_name"])).to eq(
|
|
534
|
+
"i" + Digest::SHA1.hexdigest("index_test_employees_on_first_name_and_middle_name_and_last_name")[0, 29]
|
|
535
|
+
)
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
describe "rename index" do
|
|
541
|
+
before(:each) do
|
|
542
|
+
@conn = ActiveRecord::Base.connection
|
|
543
|
+
schema_define do
|
|
544
|
+
create_table :test_employees do |t|
|
|
545
|
+
t.string :first_name
|
|
546
|
+
t.string :last_name
|
|
547
|
+
end
|
|
548
|
+
add_index :test_employees, :first_name
|
|
549
|
+
end
|
|
550
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
after(:each) do
|
|
554
|
+
schema_define do
|
|
555
|
+
drop_table :test_employees
|
|
556
|
+
end
|
|
557
|
+
Object.send(:remove_const, "TestEmployee")
|
|
558
|
+
ActiveRecord::Base.clear_cache!
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
it "should raise error when current index name and new index name are identical" do
|
|
562
|
+
expect do
|
|
563
|
+
@conn.rename_index("test_employees", "i_test_employees_first_name", "i_test_employees_first_name")
|
|
564
|
+
end.to raise_error(ActiveRecord::StatementInvalid)
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
it "should raise error when new index name length is too long" do
|
|
568
|
+
expect do
|
|
569
|
+
@conn.rename_index("test_employees", "i_test_employees_first_name", "a" * 31)
|
|
570
|
+
end.to raise_error(ArgumentError)
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
it "should raise error when current index name does not exist" do
|
|
574
|
+
expect do
|
|
575
|
+
@conn.rename_index("test_employees", "nonexist_index_name", "new_index_name")
|
|
576
|
+
end.to raise_error(ActiveRecord::StatementInvalid)
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
it "should rename index name with new one" do
|
|
580
|
+
expect do
|
|
581
|
+
@conn.rename_index("test_employees", "i_test_employees_first_name", "new_index_name")
|
|
582
|
+
end.not_to raise_error
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
describe "ignore options for LOB columns" do
|
|
587
|
+
after(:each) do
|
|
588
|
+
schema_define do
|
|
589
|
+
drop_table :test_posts
|
|
590
|
+
end
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
it "should ignore :limit option for :text column" do
|
|
594
|
+
expect do
|
|
595
|
+
schema_define do
|
|
596
|
+
create_table :test_posts, force: true do |t|
|
|
597
|
+
t.text :body, limit: 10000
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
end.not_to raise_error
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
it "should ignore :limit option for :binary column" do
|
|
604
|
+
expect do
|
|
605
|
+
schema_define do
|
|
606
|
+
create_table :test_posts, force: true do |t|
|
|
607
|
+
t.binary :picture, limit: 10000
|
|
608
|
+
end
|
|
609
|
+
end
|
|
610
|
+
end.not_to raise_error
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
describe "foreign key constraints" do
|
|
616
|
+
let(:table_name_prefix) { "" }
|
|
617
|
+
let(:table_name_suffix) { "" }
|
|
618
|
+
|
|
619
|
+
before(:each) do
|
|
620
|
+
ActiveRecord::Base.table_name_prefix = table_name_prefix
|
|
621
|
+
ActiveRecord::Base.table_name_suffix = table_name_suffix
|
|
622
|
+
schema_define do
|
|
623
|
+
create_table :test_posts, force: true do |t|
|
|
624
|
+
t.string :title
|
|
625
|
+
end
|
|
626
|
+
create_table :test_comments, force: true do |t|
|
|
627
|
+
t.string :body, limit: 4000
|
|
628
|
+
t.references :test_post
|
|
629
|
+
t.integer :post_id
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
class ::TestPost < ActiveRecord::Base
|
|
633
|
+
has_many :test_comments
|
|
634
|
+
end
|
|
635
|
+
class ::TestComment < ActiveRecord::Base
|
|
636
|
+
belongs_to :test_post
|
|
637
|
+
end
|
|
638
|
+
set_logger
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
after(:each) do
|
|
642
|
+
Object.send(:remove_const, "TestPost")
|
|
643
|
+
Object.send(:remove_const, "TestComment")
|
|
644
|
+
schema_define do
|
|
645
|
+
drop_table :test_comments, if_exists: true
|
|
646
|
+
drop_table :test_posts, if_exists: true
|
|
647
|
+
end
|
|
648
|
+
ActiveRecord::Base.table_name_prefix = ""
|
|
649
|
+
ActiveRecord::Base.table_name_suffix = ""
|
|
650
|
+
ActiveRecord::Base.clear_cache!
|
|
651
|
+
clear_logger
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
it "should add foreign key" do
|
|
655
|
+
fk_name = "fk_rails_#{Digest::SHA256.hexdigest("test_comments_test_post_id_fk").first(10)}"
|
|
656
|
+
|
|
657
|
+
schema_define do
|
|
658
|
+
add_foreign_key :test_comments, :test_posts
|
|
659
|
+
end
|
|
660
|
+
expect do
|
|
661
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
662
|
+
end.to raise_error() { |e| expect(e.message).to match(/ORA-02291.*\.#{fk_name}/i) }
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
it "should add foreign key with name" do
|
|
666
|
+
schema_define do
|
|
667
|
+
add_foreign_key :test_comments, :test_posts, name: "comments_posts_fk"
|
|
668
|
+
end
|
|
669
|
+
expect do
|
|
670
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
671
|
+
end.to raise_error() { |e| expect(e.message).to match(/ORA-02291.*\.COMMENTS_POSTS_FK/) }
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
it "should add foreign key with column" do
|
|
675
|
+
fk_name = "fk_rails_#{Digest::SHA256.hexdigest("test_comments_post_id_fk").first(10)}"
|
|
676
|
+
|
|
677
|
+
schema_define do
|
|
678
|
+
add_foreign_key :test_comments, :test_posts, column: "post_id"
|
|
679
|
+
end
|
|
680
|
+
expect do
|
|
681
|
+
TestComment.create(body: "test", post_id: 1)
|
|
682
|
+
end.to raise_error() { |e| expect(e.message).to match(/ORA-02291.*\.#{fk_name}/i) }
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
it "should add foreign key with delete dependency" do
|
|
686
|
+
schema_define do
|
|
687
|
+
add_foreign_key :test_comments, :test_posts, on_delete: :cascade
|
|
688
|
+
end
|
|
689
|
+
p = TestPost.create(title: "test")
|
|
690
|
+
c = TestComment.create(body: "test", test_post: p)
|
|
691
|
+
TestPost.delete(p.id)
|
|
692
|
+
expect(TestComment.find_by_id(c.id)).to be_nil
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
it "should add foreign key with nullify dependency" do
|
|
696
|
+
schema_define do
|
|
697
|
+
add_foreign_key :test_comments, :test_posts, on_delete: :nullify
|
|
698
|
+
end
|
|
699
|
+
p = TestPost.create(title: "test")
|
|
700
|
+
c = TestComment.create(body: "test", test_post: p)
|
|
701
|
+
TestPost.delete(p.id)
|
|
702
|
+
expect(TestComment.find_by_id(c.id).test_post_id).to be_nil
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
it "should remove foreign key by table name" do
|
|
706
|
+
schema_define do
|
|
707
|
+
add_foreign_key :test_comments, :test_posts
|
|
708
|
+
remove_foreign_key :test_comments, :test_posts
|
|
709
|
+
end
|
|
710
|
+
expect do
|
|
711
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
712
|
+
end.not_to raise_error
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
it "should remove foreign key by constraint name" do
|
|
716
|
+
schema_define do
|
|
717
|
+
add_foreign_key :test_comments, :test_posts, name: "comments_posts_fk"
|
|
718
|
+
remove_foreign_key :test_comments, name: "comments_posts_fk"
|
|
719
|
+
end
|
|
720
|
+
expect do
|
|
721
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
722
|
+
end.not_to raise_error
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
it "should remove foreign key by column name" do
|
|
726
|
+
schema_define do
|
|
727
|
+
add_foreign_key :test_comments, :test_posts
|
|
728
|
+
remove_foreign_key :test_comments, column: "test_post_id"
|
|
729
|
+
end
|
|
730
|
+
expect do
|
|
731
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
732
|
+
end.not_to raise_error
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
it "should query foreign_keys using bind variables" do
|
|
736
|
+
schema_define do
|
|
737
|
+
add_foreign_key :test_comments, :test_posts
|
|
738
|
+
end
|
|
739
|
+
ActiveRecord::Base.connection.foreign_keys(:test_comments)
|
|
740
|
+
expect(@logger.logged(:debug).last).to match(/:owner/)
|
|
741
|
+
expect(@logger.logged(:debug).last).to match(/:desc_table_name/)
|
|
742
|
+
expect(@logger.logged(:debug).last).to match(/\[\["owner", "#{DATABASE_USER.upcase}"\], \["desc_table_name", "TEST_COMMENTS"\]\]/)
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
end
|
|
746
|
+
|
|
747
|
+
describe "lob in table definition" do
|
|
748
|
+
before do
|
|
749
|
+
class ::TestPost < ActiveRecord::Base
|
|
750
|
+
end
|
|
751
|
+
end
|
|
752
|
+
it "should use default tablespace for clobs" do
|
|
753
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
754
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:nclob] = nil
|
|
755
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:blob] = nil
|
|
756
|
+
schema_define do
|
|
757
|
+
create_table :test_posts, force: true do |t|
|
|
758
|
+
t.text :test_clob
|
|
759
|
+
t.ntext :test_nclob
|
|
760
|
+
t.binary :test_blob
|
|
761
|
+
end
|
|
762
|
+
end
|
|
763
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_CLOB'")).to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
764
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_NCLOB'")).not_to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
765
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_BLOB'")).not_to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
it "should use default tablespace for nclobs" do
|
|
769
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:nclob] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
770
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = nil
|
|
771
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:blob] = nil
|
|
772
|
+
schema_define do
|
|
773
|
+
create_table :test_posts, force: true do |t|
|
|
774
|
+
t.text :test_clob
|
|
775
|
+
t.ntext :test_nclob
|
|
776
|
+
t.binary :test_blob
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_NCLOB'")).to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
780
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_CLOB'")).not_to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
781
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_BLOB'")).not_to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
it "should use default tablespace for blobs" do
|
|
785
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:blob] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
786
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = nil
|
|
787
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:nclob] = nil
|
|
788
|
+
schema_define do
|
|
789
|
+
create_table :test_posts, force: true do |t|
|
|
790
|
+
t.text :test_clob
|
|
791
|
+
t.ntext :test_nclob
|
|
792
|
+
t.binary :test_blob
|
|
793
|
+
end
|
|
794
|
+
end
|
|
795
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_BLOB'")).to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
796
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_CLOB'")).not_to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
797
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'TEST_NCLOB'")).not_to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
after do
|
|
801
|
+
Object.send(:remove_const, "TestPost")
|
|
802
|
+
schema_define do
|
|
803
|
+
drop_table :test_posts, if_exists: true
|
|
804
|
+
end
|
|
805
|
+
end
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
describe "primary key in table definition" do
|
|
809
|
+
before do
|
|
810
|
+
@conn = ActiveRecord::Base.connection
|
|
811
|
+
|
|
812
|
+
class ::TestPost < ActiveRecord::Base
|
|
813
|
+
end
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
it "should use default tablespace for primary key" do
|
|
817
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:index] = nil
|
|
818
|
+
schema_define do
|
|
819
|
+
create_table :test_posts, force: true
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
index_name = @conn.select_value(
|
|
823
|
+
"SELECT index_name FROM all_constraints
|
|
824
|
+
WHERE table_name = 'TEST_POSTS'
|
|
825
|
+
AND constraint_type = 'P'
|
|
826
|
+
AND owner = SYS_CONTEXT('userenv', 'current_schema')")
|
|
827
|
+
|
|
828
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_indexes WHERE index_name = '#{index_name}'")).to eq("USERS")
|
|
829
|
+
end
|
|
830
|
+
|
|
831
|
+
it "should use non default tablespace for primary key" do
|
|
832
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:index] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
833
|
+
schema_define do
|
|
834
|
+
create_table :test_posts, force: true
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
index_name = @conn.select_value(
|
|
838
|
+
"SELECT index_name FROM all_constraints
|
|
839
|
+
WHERE table_name = 'TEST_POSTS'
|
|
840
|
+
AND constraint_type = 'P'
|
|
841
|
+
AND owner = SYS_CONTEXT('userenv', 'current_schema')")
|
|
842
|
+
|
|
843
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_indexes WHERE index_name = '#{index_name}'")).to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
after do
|
|
847
|
+
Object.send(:remove_const, "TestPost")
|
|
848
|
+
schema_define do
|
|
849
|
+
drop_table :test_posts, if_exists: true
|
|
850
|
+
end
|
|
851
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:index] = nil
|
|
852
|
+
end
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
describe "foreign key in table definition" do
|
|
856
|
+
before(:each) do
|
|
857
|
+
schema_define do
|
|
858
|
+
create_table :test_posts, force: true do |t|
|
|
859
|
+
t.string :title
|
|
860
|
+
end
|
|
861
|
+
end
|
|
862
|
+
class ::TestPost < ActiveRecord::Base
|
|
863
|
+
has_many :test_comments
|
|
864
|
+
end
|
|
865
|
+
class ::TestComment < ActiveRecord::Base
|
|
866
|
+
belongs_to :test_post
|
|
867
|
+
end
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
after(:each) do
|
|
871
|
+
Object.send(:remove_const, "TestPost")
|
|
872
|
+
Object.send(:remove_const, "TestComment")
|
|
873
|
+
schema_define do
|
|
874
|
+
drop_table :test_comments, if_exists: true
|
|
875
|
+
drop_table :test_posts, if_exists: true
|
|
876
|
+
end
|
|
877
|
+
ActiveRecord::Base.clear_cache!
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
it "should add foreign key in create_table" do
|
|
881
|
+
schema_define do
|
|
882
|
+
create_table :test_comments, force: true do |t|
|
|
883
|
+
t.string :body, limit: 4000
|
|
884
|
+
t.references :test_post
|
|
885
|
+
t.foreign_key :test_posts
|
|
886
|
+
end
|
|
887
|
+
end
|
|
888
|
+
expect do
|
|
889
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
890
|
+
end.to raise_error() { |e| expect(e.message).to match(/ORA-02291/) }
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
it "should add foreign key in create_table references" do
|
|
894
|
+
schema_define do
|
|
895
|
+
create_table :test_comments, force: true do |t|
|
|
896
|
+
t.string :body, limit: 4000
|
|
897
|
+
t.references :test_post, foreign_key: true
|
|
898
|
+
end
|
|
899
|
+
end
|
|
900
|
+
expect do
|
|
901
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
902
|
+
end.to raise_error() { |e| expect(e.message).to match(/ORA-02291/) }
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
it "should add foreign key in change_table" do
|
|
906
|
+
schema_define do
|
|
907
|
+
create_table :test_comments, force: true do |t|
|
|
908
|
+
t.string :body, limit: 4000
|
|
909
|
+
t.references :test_post
|
|
910
|
+
end
|
|
911
|
+
change_table :test_comments do |t|
|
|
912
|
+
t.foreign_key :test_posts
|
|
913
|
+
end
|
|
914
|
+
end
|
|
915
|
+
expect do
|
|
916
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
917
|
+
end.to raise_error() { |e| expect(e.message).to match(/ORA-02291/) }
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
it "should add foreign key in change_table references" do
|
|
921
|
+
schema_define do
|
|
922
|
+
create_table :test_comments, force: true do |t|
|
|
923
|
+
t.string :body, limit: 4000
|
|
924
|
+
end
|
|
925
|
+
change_table :test_comments do |t|
|
|
926
|
+
t.references :test_post, foreign_key: true
|
|
927
|
+
end
|
|
928
|
+
end
|
|
929
|
+
expect do
|
|
930
|
+
TestComment.create(body: "test", test_post_id: 1)
|
|
931
|
+
end.to raise_error() { |e| expect(e.message).to match(/ORA-02291/) }
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
describe "disable referential integrity" do
|
|
937
|
+
before(:all) do
|
|
938
|
+
@conn = ActiveRecord::Base.connection
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
before(:each) do
|
|
942
|
+
schema_define do
|
|
943
|
+
create_table :test_posts, force: true do |t|
|
|
944
|
+
t.string :title
|
|
945
|
+
end
|
|
946
|
+
create_table :test_comments, force: true do |t|
|
|
947
|
+
t.string :body, limit: 4000
|
|
948
|
+
t.references :test_post, foreign_key: true
|
|
949
|
+
end
|
|
950
|
+
create_table "test_Mixed_Comments", force: true do |t|
|
|
951
|
+
t.string :body, limit: 4000
|
|
952
|
+
t.references :test_post, foreign_key: true
|
|
953
|
+
end
|
|
954
|
+
end
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
after(:each) do
|
|
958
|
+
schema_define do
|
|
959
|
+
drop_table "test_Mixed_Comments", if_exists: true
|
|
960
|
+
drop_table :test_comments, if_exists: true
|
|
961
|
+
drop_table :test_posts, if_exists: true
|
|
962
|
+
end
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
it "should disable all foreign keys" do
|
|
966
|
+
expect do
|
|
967
|
+
@conn.execute "INSERT INTO test_comments (id, body, test_post_id) VALUES (1, 'test', 1)"
|
|
968
|
+
end.to raise_error(ActiveRecord::InvalidForeignKey)
|
|
969
|
+
@conn.disable_referential_integrity do
|
|
970
|
+
expect do
|
|
971
|
+
@conn.execute "INSERT INTO \"test_Mixed_Comments\" (id, body, test_post_id) VALUES (2, 'test', 2)"
|
|
972
|
+
@conn.execute "INSERT INTO test_comments (id, body, test_post_id) VALUES (2, 'test', 2)"
|
|
973
|
+
@conn.execute "INSERT INTO test_posts (id, title) VALUES (2, 'test')"
|
|
974
|
+
end.not_to raise_error
|
|
975
|
+
end
|
|
976
|
+
expect do
|
|
977
|
+
@conn.execute "INSERT INTO test_comments (id, body, test_post_id) VALUES (3, 'test', 3)"
|
|
978
|
+
end.to raise_error(ActiveRecord::InvalidForeignKey)
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
end
|
|
982
|
+
|
|
983
|
+
describe "synonyms" do
|
|
984
|
+
before(:all) do
|
|
985
|
+
@conn = ActiveRecord::Base.connection
|
|
986
|
+
@db_link = "db_link"
|
|
987
|
+
@username = @db_link_username = CONNECTION_PARAMS[:username]
|
|
988
|
+
@db_link_password = CONNECTION_PARAMS[:password]
|
|
989
|
+
@db_link_database = CONNECTION_PARAMS[:database]
|
|
990
|
+
@conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
|
|
991
|
+
@conn.execute "CREATE DATABASE LINK #{@db_link} CONNECT TO #{@db_link_username} IDENTIFIED BY \"#{@db_link_password}\" USING '#{@db_link_database}'"
|
|
992
|
+
schema_define do
|
|
993
|
+
create_table :test_posts, force: true do |t|
|
|
994
|
+
t.string :title
|
|
995
|
+
end
|
|
996
|
+
end
|
|
997
|
+
end
|
|
998
|
+
|
|
999
|
+
after(:all) do
|
|
1000
|
+
schema_define do
|
|
1001
|
+
drop_table :test_posts
|
|
1002
|
+
end
|
|
1003
|
+
@conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
before(:each) do
|
|
1007
|
+
class ::TestPost < ActiveRecord::Base
|
|
1008
|
+
self.table_name = "synonym_to_posts"
|
|
1009
|
+
end
|
|
1010
|
+
end
|
|
1011
|
+
|
|
1012
|
+
after(:each) do
|
|
1013
|
+
Object.send(:remove_const, "TestPost")
|
|
1014
|
+
schema_define do
|
|
1015
|
+
remove_synonym :synonym_to_posts
|
|
1016
|
+
remove_synonym :synonym_to_posts_seq
|
|
1017
|
+
end
|
|
1018
|
+
ActiveRecord::Base.clear_cache!
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
it "should create synonym to table and sequence" do
|
|
1022
|
+
schema_name = @username
|
|
1023
|
+
schema_define do
|
|
1024
|
+
add_synonym :synonym_to_posts, "#{schema_name}.test_posts", force: true
|
|
1025
|
+
add_synonym :synonym_to_posts_seq, "#{schema_name}.test_posts_seq", force: true
|
|
1026
|
+
end
|
|
1027
|
+
expect do
|
|
1028
|
+
TestPost.create(title: "test")
|
|
1029
|
+
end.not_to raise_error
|
|
1030
|
+
end
|
|
1031
|
+
|
|
1032
|
+
it "should create synonym to table over database link" do
|
|
1033
|
+
db_link = @db_link
|
|
1034
|
+
schema_define do
|
|
1035
|
+
add_synonym :synonym_to_posts, "test_posts@#{db_link}", force: true
|
|
1036
|
+
add_synonym :synonym_to_posts_seq, "test_posts_seq@#{db_link}", force: true
|
|
1037
|
+
end
|
|
1038
|
+
expect do
|
|
1039
|
+
TestPost.create(title: "test")
|
|
1040
|
+
end.not_to raise_error
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
describe "alter columns with column cache" do
|
|
1046
|
+
include LoggerSpecHelper
|
|
1047
|
+
|
|
1048
|
+
before(:all) do
|
|
1049
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:clob)
|
|
1050
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:nclob)
|
|
1051
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:blob)
|
|
1052
|
+
end
|
|
1053
|
+
|
|
1054
|
+
after(:all) do
|
|
1055
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:clob)
|
|
1056
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:nclob)
|
|
1057
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:blob)
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
before(:each) do
|
|
1061
|
+
schema_define do
|
|
1062
|
+
create_table :test_posts, force: true do |t|
|
|
1063
|
+
t.string :title, null: false
|
|
1064
|
+
t.string :content
|
|
1065
|
+
end
|
|
1066
|
+
end
|
|
1067
|
+
class ::TestPost < ActiveRecord::Base; end
|
|
1068
|
+
expect(TestPost.columns_hash["title"].null).to be_falsey
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
after(:each) do
|
|
1072
|
+
Object.send(:remove_const, "TestPost")
|
|
1073
|
+
schema_define { drop_table :test_posts }
|
|
1074
|
+
ActiveRecord::Base.clear_cache!
|
|
1075
|
+
end
|
|
1076
|
+
|
|
1077
|
+
it "should change column to nullable" do
|
|
1078
|
+
schema_define do
|
|
1079
|
+
change_column :test_posts, :title, :string, null: true
|
|
1080
|
+
end
|
|
1081
|
+
TestPost.reset_column_information
|
|
1082
|
+
expect(TestPost.columns_hash["title"].null).to be_truthy
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
it "should add column" do
|
|
1086
|
+
schema_define do
|
|
1087
|
+
add_column :test_posts, :body, :string
|
|
1088
|
+
end
|
|
1089
|
+
TestPost.reset_column_information
|
|
1090
|
+
expect(TestPost.columns_hash["body"]).not_to be_nil
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
it "should add lob column with non_default tablespace" do
|
|
1094
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
1095
|
+
schema_define do
|
|
1096
|
+
add_column :test_posts, :body, :text
|
|
1097
|
+
end
|
|
1098
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'BODY'")).to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
it "should add lob column with non_default tablespace" do
|
|
1102
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:nclob] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
1103
|
+
schema_define do
|
|
1104
|
+
add_column :test_posts, :body, :ntext
|
|
1105
|
+
end
|
|
1106
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'BODY'")).to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
1107
|
+
end
|
|
1108
|
+
|
|
1109
|
+
it "should add blob column with non_default tablespace" do
|
|
1110
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:blob] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
1111
|
+
schema_define do
|
|
1112
|
+
add_column :test_posts, :attachment, :binary
|
|
1113
|
+
end
|
|
1114
|
+
expect(TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'ATTACHMENT'")).to eq(DATABASE_NON_DEFAULT_TABLESPACE)
|
|
1115
|
+
end
|
|
1116
|
+
|
|
1117
|
+
it "should rename column" do
|
|
1118
|
+
schema_define do
|
|
1119
|
+
rename_column :test_posts, :title, :subject
|
|
1120
|
+
end
|
|
1121
|
+
TestPost.reset_column_information
|
|
1122
|
+
expect(TestPost.columns_hash["subject"]).not_to be_nil
|
|
1123
|
+
expect(TestPost.columns_hash["title"]).to be_nil
|
|
1124
|
+
end
|
|
1125
|
+
|
|
1126
|
+
it "should remove column" do
|
|
1127
|
+
schema_define do
|
|
1128
|
+
remove_column :test_posts, :title
|
|
1129
|
+
end
|
|
1130
|
+
TestPost.reset_column_information
|
|
1131
|
+
expect(TestPost.columns_hash["title"]).to be_nil
|
|
1132
|
+
end
|
|
1133
|
+
|
|
1134
|
+
it "should remove column when using change_table" do
|
|
1135
|
+
schema_define do
|
|
1136
|
+
change_table :test_posts do |t|
|
|
1137
|
+
t.remove :title
|
|
1138
|
+
end
|
|
1139
|
+
end
|
|
1140
|
+
TestPost.reset_column_information
|
|
1141
|
+
expect(TestPost.columns_hash["title"]).to be_nil
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
it "should remove multiple columns when using change_table" do
|
|
1145
|
+
schema_define do
|
|
1146
|
+
change_table :test_posts do |t|
|
|
1147
|
+
t.remove :title, :content
|
|
1148
|
+
end
|
|
1149
|
+
end
|
|
1150
|
+
TestPost.reset_column_information
|
|
1151
|
+
expect(TestPost.columns_hash["title"]).to be_nil
|
|
1152
|
+
expect(TestPost.columns_hash["content"]).to be_nil
|
|
1153
|
+
end
|
|
1154
|
+
|
|
1155
|
+
it "should ignore type and options parameter and remove column" do
|
|
1156
|
+
schema_define do
|
|
1157
|
+
remove_column :test_posts, :title, :string, {}
|
|
1158
|
+
end
|
|
1159
|
+
TestPost.reset_column_information
|
|
1160
|
+
expect(TestPost.columns_hash["title"]).to be_nil
|
|
1161
|
+
end
|
|
1162
|
+
end
|
|
1163
|
+
|
|
1164
|
+
describe "virtual columns in create_table" do
|
|
1165
|
+
before(:each) do
|
|
1166
|
+
skip "Not supported in this database version" unless @oracle11g_or_higher
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
it "should raise error if column expression is not provided" do
|
|
1170
|
+
expect {
|
|
1171
|
+
schema_define do
|
|
1172
|
+
create_table :test_fractions do |t|
|
|
1173
|
+
t.integer :field1
|
|
1174
|
+
t.virtual :field2
|
|
1175
|
+
end
|
|
1176
|
+
end
|
|
1177
|
+
}.to raise_error(RuntimeError, "No virtual column definition found.")
|
|
1178
|
+
end
|
|
1179
|
+
end
|
|
1180
|
+
|
|
1181
|
+
describe "virtual columns" do
|
|
1182
|
+
before(:each) do
|
|
1183
|
+
skip "Not supported in this database version" unless @oracle11g_or_higher
|
|
1184
|
+
expr = "( numerator/NULLIF(denominator,0) )*100"
|
|
1185
|
+
schema_define do
|
|
1186
|
+
create_table :test_fractions, force: true do |t|
|
|
1187
|
+
t.integer :numerator, default: 0
|
|
1188
|
+
t.integer :denominator, default: 0
|
|
1189
|
+
t.virtual :percent, as: expr
|
|
1190
|
+
end
|
|
1191
|
+
end
|
|
1192
|
+
class ::TestFraction < ActiveRecord::Base
|
|
1193
|
+
self.table_name = "test_fractions"
|
|
1194
|
+
end
|
|
1195
|
+
TestFraction.reset_column_information
|
|
1196
|
+
end
|
|
1197
|
+
|
|
1198
|
+
after(:each) do
|
|
1199
|
+
if @oracle11g_or_higher
|
|
1200
|
+
schema_define do
|
|
1201
|
+
drop_table :test_fractions
|
|
1202
|
+
end
|
|
1203
|
+
end
|
|
1204
|
+
end
|
|
1205
|
+
|
|
1206
|
+
it "should include virtual columns and not try to update them" do
|
|
1207
|
+
tf = TestFraction.columns.detect { |c| c.virtual? }
|
|
1208
|
+
expect(tf).not_to be nil
|
|
1209
|
+
expect(tf.name).to eq("percent")
|
|
1210
|
+
expect(tf.virtual?).to be true
|
|
1211
|
+
expect do
|
|
1212
|
+
tf = TestFraction.new(numerator: 20, denominator: 100)
|
|
1213
|
+
expect(tf.percent).to be nil # not whatever is in DATA_DEFAULT column
|
|
1214
|
+
tf.save!
|
|
1215
|
+
tf.reload
|
|
1216
|
+
end.not_to raise_error
|
|
1217
|
+
expect(tf.percent.to_i).to eq(20)
|
|
1218
|
+
end
|
|
1219
|
+
|
|
1220
|
+
it "should add virtual column" do
|
|
1221
|
+
schema_define do
|
|
1222
|
+
add_column :test_fractions, :rem, :virtual, as: "remainder(numerator, NULLIF(denominator,0))"
|
|
1223
|
+
end
|
|
1224
|
+
TestFraction.reset_column_information
|
|
1225
|
+
tf = TestFraction.columns.detect { |c| c.name == "rem" }
|
|
1226
|
+
expect(tf).not_to be nil
|
|
1227
|
+
expect(tf.virtual?).to be true
|
|
1228
|
+
expect do
|
|
1229
|
+
tf = TestFraction.new(numerator: 7, denominator: 5)
|
|
1230
|
+
expect(tf.rem).to be nil
|
|
1231
|
+
tf.save!
|
|
1232
|
+
tf.reload
|
|
1233
|
+
end.not_to raise_error
|
|
1234
|
+
expect(tf.rem.to_i).to eq(2)
|
|
1235
|
+
end
|
|
1236
|
+
|
|
1237
|
+
it "should add virtual column with explicit type" do
|
|
1238
|
+
schema_define do
|
|
1239
|
+
add_column :test_fractions, :expression, :virtual, as: "TO_CHAR(numerator) || '/' || TO_CHAR(denominator)", type: :string, limit: 100
|
|
1240
|
+
end
|
|
1241
|
+
TestFraction.reset_column_information
|
|
1242
|
+
tf = TestFraction.columns.detect { |c| c.name == "expression" }
|
|
1243
|
+
expect(tf).not_to be nil
|
|
1244
|
+
expect(tf.virtual?).to be true
|
|
1245
|
+
expect(tf.type).to be :string
|
|
1246
|
+
expect(tf.limit).to be 100
|
|
1247
|
+
expect do
|
|
1248
|
+
tf = TestFraction.new(numerator: 7, denominator: 5)
|
|
1249
|
+
expect(tf.expression).to be nil
|
|
1250
|
+
tf.save!
|
|
1251
|
+
tf.reload
|
|
1252
|
+
end.not_to raise_error
|
|
1253
|
+
expect(tf.expression).to eq("7/5")
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
it "should change virtual column definition" do
|
|
1257
|
+
schema_define do
|
|
1258
|
+
change_column :test_fractions, :percent, :virtual,
|
|
1259
|
+
as: "ROUND((numerator/NULLIF(denominator,0))*100, 2)", type: :decimal, precision: 15, scale: 2
|
|
1260
|
+
end
|
|
1261
|
+
TestFraction.reset_column_information
|
|
1262
|
+
tf = TestFraction.columns.detect { |c| c.name == "percent" }
|
|
1263
|
+
expect(tf).not_to be nil
|
|
1264
|
+
expect(tf.virtual?).to be true
|
|
1265
|
+
expect(tf.type).to be :decimal
|
|
1266
|
+
expect(tf.precision).to be 15
|
|
1267
|
+
expect(tf.scale).to be 2
|
|
1268
|
+
expect do
|
|
1269
|
+
tf = TestFraction.new(numerator: 11, denominator: 17)
|
|
1270
|
+
expect(tf.percent).to be nil
|
|
1271
|
+
tf.save!
|
|
1272
|
+
tf.reload
|
|
1273
|
+
end.not_to raise_error
|
|
1274
|
+
expect(tf.percent).to eq("64.71".to_d)
|
|
1275
|
+
end
|
|
1276
|
+
|
|
1277
|
+
it "should change virtual column type" do
|
|
1278
|
+
schema_define do
|
|
1279
|
+
change_column :test_fractions, :percent, :virtual, type: :decimal, precision: 12, scale: 5
|
|
1280
|
+
end
|
|
1281
|
+
TestFraction.reset_column_information
|
|
1282
|
+
tf = TestFraction.columns.detect { |c| c.name == "percent" }
|
|
1283
|
+
expect(tf).not_to be nil
|
|
1284
|
+
expect(tf.virtual?).to be true
|
|
1285
|
+
expect(tf.type).to be :decimal
|
|
1286
|
+
expect(tf.precision).to be 12
|
|
1287
|
+
expect(tf.scale).to be 5
|
|
1288
|
+
expect do
|
|
1289
|
+
tf = TestFraction.new(numerator: 11, denominator: 17)
|
|
1290
|
+
expect(tf.percent).to be nil
|
|
1291
|
+
tf.save!
|
|
1292
|
+
tf.reload
|
|
1293
|
+
end.not_to raise_error
|
|
1294
|
+
expect(tf.percent).to eq("64.70588".to_d)
|
|
1295
|
+
end
|
|
1296
|
+
end
|
|
1297
|
+
|
|
1298
|
+
describe "miscellaneous options" do
|
|
1299
|
+
before(:all) do
|
|
1300
|
+
@conn = ActiveRecord::Base.connection
|
|
1301
|
+
end
|
|
1302
|
+
|
|
1303
|
+
before(:each) do
|
|
1304
|
+
@conn.instance_variable_set :@would_execute_sql, @would_execute_sql = "".dup
|
|
1305
|
+
class <<@conn
|
|
1306
|
+
def execute(sql, name = nil); @would_execute_sql << sql << ";\n"; end
|
|
1307
|
+
end
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
after(:each) do
|
|
1311
|
+
class <<@conn
|
|
1312
|
+
remove_method :execute
|
|
1313
|
+
end
|
|
1314
|
+
@conn.instance_eval { remove_instance_variable :@would_execute_sql }
|
|
1315
|
+
end
|
|
1316
|
+
|
|
1317
|
+
it "should support the :options option to create_table" do
|
|
1318
|
+
schema_define do
|
|
1319
|
+
create_table :test_posts, options: "NOLOGGING", force: true do |t|
|
|
1320
|
+
t.string :title, null: false
|
|
1321
|
+
end
|
|
1322
|
+
end
|
|
1323
|
+
expect(@would_execute_sql).to match(/CREATE +TABLE .* \(.*\) NOLOGGING/)
|
|
1324
|
+
end
|
|
1325
|
+
|
|
1326
|
+
it "should support the :tablespace option to create_table" do
|
|
1327
|
+
schema_define do
|
|
1328
|
+
create_table :test_posts, tablespace: "bogus", force: true do |t|
|
|
1329
|
+
t.string :title, null: false
|
|
1330
|
+
end
|
|
1331
|
+
end
|
|
1332
|
+
expect(@would_execute_sql).to match(/CREATE +TABLE .* \(.*\) TABLESPACE bogus/)
|
|
1333
|
+
end
|
|
1334
|
+
|
|
1335
|
+
describe "creating a table with a tablespace defaults set" do
|
|
1336
|
+
after(:each) do
|
|
1337
|
+
@conn.drop_table :tablespace_tests, if_exists: true
|
|
1338
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:table)
|
|
1339
|
+
end
|
|
1340
|
+
it "should use correct tablespace" do
|
|
1341
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:table] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
1342
|
+
@conn.create_table :tablespace_tests do |t|
|
|
1343
|
+
t.string :foo
|
|
1344
|
+
end
|
|
1345
|
+
expect(@would_execute_sql).to match(/CREATE +TABLE .* \(.*\) TABLESPACE #{DATABASE_NON_DEFAULT_TABLESPACE}/)
|
|
1346
|
+
end
|
|
1347
|
+
end
|
|
1348
|
+
|
|
1349
|
+
describe "creating an index-organized table" do
|
|
1350
|
+
after(:each) do
|
|
1351
|
+
@conn.drop_table :tablespace_tests, if_exists: true
|
|
1352
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:table)
|
|
1353
|
+
end
|
|
1354
|
+
it "should use correct tablespace" do
|
|
1355
|
+
@conn.create_table :tablespace_tests, id: false, organization: "INDEX INITRANS 4 COMPRESS 1", tablespace: "bogus" do |t|
|
|
1356
|
+
t.integer :id
|
|
1357
|
+
end
|
|
1358
|
+
expect(@would_execute_sql).to match(/CREATE +TABLE .*\(.*\)\s+ORGANIZATION INDEX INITRANS 4 COMPRESS 1 TABLESPACE bogus/)
|
|
1359
|
+
end
|
|
1360
|
+
end
|
|
1361
|
+
|
|
1362
|
+
it "should support the :options option to add_index" do
|
|
1363
|
+
schema_define do
|
|
1364
|
+
add_index :keyboards, :name, options: "NOLOGGING"
|
|
1365
|
+
end
|
|
1366
|
+
expect(@would_execute_sql).to match(/CREATE +INDEX .* ON .* \(.*\) NOLOGGING/)
|
|
1367
|
+
end
|
|
1368
|
+
|
|
1369
|
+
it "should support the :tablespace option to add_index" do
|
|
1370
|
+
schema_define do
|
|
1371
|
+
add_index :keyboards, :name, tablespace: "bogus"
|
|
1372
|
+
end
|
|
1373
|
+
expect(@would_execute_sql).to match(/CREATE +INDEX .* ON .* \(.*\) TABLESPACE bogus/)
|
|
1374
|
+
end
|
|
1375
|
+
|
|
1376
|
+
it "should use default_tablespaces in add_index" do
|
|
1377
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:index] = DATABASE_NON_DEFAULT_TABLESPACE
|
|
1378
|
+
schema_define do
|
|
1379
|
+
add_index :keyboards, :name
|
|
1380
|
+
end
|
|
1381
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:index)
|
|
1382
|
+
expect(@would_execute_sql).to match(/CREATE +INDEX .* ON .* \(.*\) TABLESPACE #{DATABASE_NON_DEFAULT_TABLESPACE}/)
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
it "should create unique function index but not create unique constraints" do
|
|
1386
|
+
schema_define do
|
|
1387
|
+
add_index :keyboards, "lower(name)", unique: true, name: :index_keyboards_on_lower_name
|
|
1388
|
+
end
|
|
1389
|
+
expect(@would_execute_sql).not_to match(/ALTER +TABLE .* ADD CONSTRAINT .* UNIQUE \(.*\(.*\)\)/)
|
|
1390
|
+
end
|
|
1391
|
+
|
|
1392
|
+
end
|
|
1393
|
+
|
|
1394
|
+
describe "load schema" do
|
|
1395
|
+
let(:versions) {
|
|
1396
|
+
%w(20160101000000 20160102000000 20160103000000)
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
before do
|
|
1400
|
+
@conn = ActiveRecord::Base.connection
|
|
1401
|
+
|
|
1402
|
+
ActiveRecord::SchemaMigration.create_table
|
|
1403
|
+
end
|
|
1404
|
+
|
|
1405
|
+
context "multi insert is supported" do
|
|
1406
|
+
it "should loads the migration schema table from insert versions sql" do
|
|
1407
|
+
skip "Not supported in this database version" unless ActiveRecord::Base.connection.supports_multi_insert?
|
|
1408
|
+
|
|
1409
|
+
expect {
|
|
1410
|
+
@conn.execute @conn.insert_versions_sql(versions)
|
|
1411
|
+
}.not_to raise_error
|
|
1412
|
+
|
|
1413
|
+
expect(@conn.select_value("SELECT COUNT(version) FROM schema_migrations")).to eq versions.count
|
|
1414
|
+
end
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
context "multi insert is NOT supported" do
|
|
1418
|
+
it "should loads the migration schema table from insert versions sql" do
|
|
1419
|
+
skip "Not supported in this database version" if ActiveRecord::Base.connection.supports_multi_insert?
|
|
1420
|
+
|
|
1421
|
+
expect {
|
|
1422
|
+
versions.each { |version| @conn.execute @conn.insert_versions_sql(version) }
|
|
1423
|
+
}.not_to raise_error
|
|
1424
|
+
|
|
1425
|
+
expect(@conn.select_value("SELECT COUNT(version) FROM schema_migrations")).to eq versions.count
|
|
1426
|
+
end
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
after do
|
|
1430
|
+
ActiveRecord::SchemaMigration.drop_table
|
|
1431
|
+
end
|
|
1432
|
+
end
|
|
1433
|
+
end
|