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.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +1971 -0
  3. data/License.txt +20 -0
  4. data/README.md +947 -0
  5. data/VERSION +1 -0
  6. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +7 -0
  7. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +24 -0
  8. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +137 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +359 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +47 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +325 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +63 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +71 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +629 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +57 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +465 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +195 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +186 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +99 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +197 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +739 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +394 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +34 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +886 -0
  29. data/lib/active_record/type/oracle_enhanced/boolean.rb +19 -0
  30. data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
  31. data/lib/active_record/type/oracle_enhanced/integer.rb +14 -0
  32. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  33. data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
  34. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  35. data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
  36. data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
  37. data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
  38. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  39. data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
  40. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  41. data/lib/arel/visitors/oracle.rb +216 -0
  42. data/lib/arel/visitors/oracle12.rb +121 -0
  43. data/lib/arel/visitors/oracle_common.rb +51 -0
  44. data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +24 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +40 -0
  46. data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
  47. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +589 -0
  48. data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
  49. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
  50. data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
  51. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
  52. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
  53. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
  54. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
  55. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1318 -0
  56. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +485 -0
  57. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
  58. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
  59. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  60. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
  61. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
  62. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  63. data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
  64. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
  65. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  66. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +101 -0
  67. data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
  68. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  69. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  70. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
  71. data/spec/active_record/oracle_enhanced/type/text_spec.rb +295 -0
  72. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +107 -0
  73. data/spec/spec_config.yaml.template +11 -0
  74. data/spec/spec_helper.rb +225 -0
  75. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  76. data/spec/support/alter_system_user_password.sql +2 -0
  77. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  78. metadata +181 -0
@@ -0,0 +1,485 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe "OracleEnhancedAdapter structure dump" do
4
+ include LoggerSpecHelper
5
+
6
+ before(:all) do
7
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
8
+ @conn = ActiveRecord::Base.connection
9
+ @oracle11g_or_higher = !! @conn.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 "structure dump" do
14
+ before(:each) do
15
+ @conn.create_table :test_posts, force: true do |t|
16
+ t.string :title
17
+ t.string :foo
18
+ t.integer :foo_id
19
+ end
20
+ @conn.create_table :foos do |t|
21
+ end
22
+ class ::TestPost < ActiveRecord::Base
23
+ end
24
+ TestPost.table_name = "test_posts"
25
+ end
26
+
27
+ after(:each) do
28
+ @conn.drop_table :test_posts
29
+ @conn.drop_table :foos
30
+ @conn.execute "DROP SEQUENCE test_posts_seq" rescue nil
31
+ @conn.execute "ALTER TABLE test_posts drop CONSTRAINT fk_test_post_foo" rescue nil
32
+ @conn.execute "DROP TRIGGER test_post_trigger" rescue nil
33
+ @conn.execute "DROP TYPE TEST_TYPE" rescue nil
34
+ @conn.execute "DROP TABLE bars" rescue nil
35
+ @conn.execute "ALTER TABLE foos drop CONSTRAINT UK_BAZ" rescue nil
36
+ @conn.execute "ALTER TABLE foos drop CONSTRAINT UK_FOOZ_BAZ" rescue nil
37
+ @conn.execute "ALTER TABLE foos drop column fooz_id" rescue nil
38
+ @conn.execute "ALTER TABLE foos drop column baz_id" rescue nil
39
+ @conn.execute "ALTER TABLE test_posts drop column fooz_id" rescue nil
40
+ @conn.execute "ALTER TABLE test_posts drop column baz_id" rescue nil
41
+ @conn.execute "DROP VIEW test_posts_view_z" rescue nil
42
+ @conn.execute "DROP VIEW test_posts_view_a" rescue nil
43
+ end
44
+
45
+ it "should dump single primary key" do
46
+ dump = ActiveRecord::Base.connection.structure_dump
47
+ expect(dump).to match(/CONSTRAINT (.+) PRIMARY KEY \(ID\)\n/)
48
+ end
49
+
50
+ it "should dump composite primary keys" do
51
+ pk = @conn.send(:select_one, <<~SQL)
52
+ select constraint_name from user_constraints where table_name = 'TEST_POSTS' and constraint_type='P'
53
+ SQL
54
+ @conn.execute <<~SQL
55
+ alter table test_posts drop constraint #{pk["constraint_name"]}
56
+ SQL
57
+ @conn.execute <<~SQL
58
+ ALTER TABLE TEST_POSTS
59
+ add CONSTRAINT pk_id_title PRIMARY KEY (id, title)
60
+ SQL
61
+ dump = ActiveRecord::Base.connection.structure_dump
62
+ expect(dump).to match(/CONSTRAINT (.+) PRIMARY KEY \(ID,TITLE\)\n/)
63
+ end
64
+
65
+ it "should dump foreign keys" do
66
+ @conn.execute <<~SQL
67
+ ALTER TABLE TEST_POSTS
68
+ ADD CONSTRAINT fk_test_post_foo FOREIGN KEY (foo_id) REFERENCES foos(id)
69
+ SQL
70
+ dump = ActiveRecord::Base.connection.structure_dump
71
+ expect(dump.split('\n').length).to eq(1)
72
+ expect(dump).to match(/ALTER TABLE "?TEST_POSTS"? ADD CONSTRAINT "?FK_TEST_POST_FOO"? FOREIGN KEY \("?FOO_ID"?\) REFERENCES "?FOOS"?\("?ID"?\)/i)
73
+ end
74
+
75
+ it "should dump foreign keys when reference column name is not 'id'" do
76
+ @conn.add_column :foos, :baz_id, :integer
77
+
78
+ @conn.execute <<~SQL
79
+ ALTER TABLE FOOS
80
+ ADD CONSTRAINT UK_BAZ UNIQUE (BAZ_ID)
81
+ SQL
82
+
83
+ @conn.add_column :test_posts, :baz_id, :integer
84
+
85
+ @conn.execute <<~SQL
86
+ ALTER TABLE TEST_POSTS
87
+ ADD CONSTRAINT fk_test_post_baz FOREIGN KEY (baz_id) REFERENCES foos(baz_id)
88
+ SQL
89
+
90
+ dump = ActiveRecord::Base.connection.structure_dump
91
+ expect(dump.split('\n').length).to eq(1)
92
+ expect(dump).to match(/ALTER TABLE "?TEST_POSTS"? ADD CONSTRAINT "?FK_TEST_POST_BAZ"? FOREIGN KEY \("?BAZ_ID"?\) REFERENCES "?FOOS"?\("?BAZ_ID"?\)/i)
93
+ end
94
+
95
+ it "should not error when no foreign keys are present" do
96
+ dump = ActiveRecord::Base.connection.structure_dump_fk_constraints
97
+ expect(dump.split('\n').length).to eq(0)
98
+ expect(dump).to eq("")
99
+ end
100
+
101
+ it "should dump triggers" do
102
+ @conn.execute <<~SQL
103
+ create or replace TRIGGER TEST_POST_TRIGGER
104
+ BEFORE INSERT
105
+ ON TEST_POSTS
106
+ FOR EACH ROW
107
+ BEGIN
108
+ SELECT 'bar' INTO :new.FOO FROM DUAL;
109
+ END;
110
+ SQL
111
+ dump = ActiveRecord::Base.connection.structure_dump_db_stored_code.gsub(/\n|\s+/, " ")
112
+ expect(dump).to match(/CREATE OR REPLACE TRIGGER TEST_POST_TRIGGER/)
113
+ end
114
+
115
+ it "should dump types" do
116
+ @conn.execute <<~SQL
117
+ create or replace TYPE TEST_TYPE AS TABLE OF VARCHAR2(10);
118
+ SQL
119
+ dump = ActiveRecord::Base.connection.structure_dump_db_stored_code.gsub(/\n|\s+/, " ")
120
+ expect(dump).to match(/CREATE OR REPLACE TYPE TEST_TYPE/)
121
+ end
122
+
123
+ it "should dump views" do
124
+ @conn.execute "create or replace VIEW test_posts_view_z as select * from test_posts"
125
+ @conn.execute "create or replace VIEW test_posts_view_a as select * from test_posts_view_z"
126
+ dump = ActiveRecord::Base.connection.structure_dump.gsub(/\n|\s+/, " ")
127
+ expect(dump).to match(/CREATE OR REPLACE FORCE VIEW TEST_POSTS_VIEW_A.*CREATE OR REPLACE FORCE VIEW TEST_POSTS_VIEW_Z/)
128
+ end
129
+
130
+ it "should dump virtual columns" do
131
+ skip "Not supported in this database version" unless @oracle11g_or_higher
132
+ @conn.execute <<~SQL
133
+ CREATE TABLE bars (
134
+ id NUMBER(38,0) NOT NULL,
135
+ id_plus NUMBER GENERATED ALWAYS AS(id + 2) VIRTUAL,
136
+ PRIMARY KEY (ID)
137
+ )
138
+ SQL
139
+ dump = ActiveRecord::Base.connection.structure_dump
140
+ expect(dump).to match(/"?ID_PLUS"? NUMBER GENERATED ALWAYS AS \(ID\+2\) VIRTUAL/)
141
+ end
142
+
143
+ it "should dump RAW virtual columns" do
144
+ skip "Not supported in this database version" unless @oracle11g_or_higher
145
+ @conn.execute <<~SQL
146
+ CREATE TABLE bars (
147
+ id NUMBER(38,0) NOT NULL,
148
+ super RAW(255) GENERATED ALWAYS AS \( HEXTORAW\(ID\) \) VIRTUAL,
149
+ PRIMARY KEY (ID)
150
+ )
151
+ SQL
152
+ dump = ActiveRecord::Base.connection.structure_dump
153
+ expect(dump).to match(/CREATE TABLE "BARS" \(\n "ID" NUMBER\(38,0\) NOT NULL,\n "SUPER" RAW\(255\) GENERATED ALWAYS AS \(HEXTORAW\(TO_CHAR\(ID\)\)\) VIRTUAL/)
154
+ end
155
+
156
+ it "should dump NCLOB columns" do
157
+ @conn.execute <<~SQL
158
+ CREATE TABLE bars (
159
+ id NUMBER(38,0) NOT NULL,
160
+ nclob_text NCLOB,
161
+ PRIMARY KEY (ID)
162
+ )
163
+ SQL
164
+ dump = ActiveRecord::Base.connection.structure_dump
165
+ expect(dump).to match(/CREATE TABLE "BARS" \(\n "ID" NUMBER\(38,0\) NOT NULL,\n "NCLOB_TEXT" NCLOB/)
166
+ end
167
+
168
+ it "should dump unique keys" do
169
+ @conn.execute <<~SQL
170
+ ALTER TABLE test_posts
171
+ add CONSTRAINT uk_foo_foo_id UNIQUE (foo, foo_id)
172
+ SQL
173
+ dump = ActiveRecord::Base.connection.structure_dump_unique_keys("test_posts")
174
+ expect(dump).to eq(["ALTER TABLE TEST_POSTS ADD CONSTRAINT UK_FOO_FOO_ID UNIQUE (FOO,FOO_ID)"])
175
+
176
+ dump = ActiveRecord::Base.connection.structure_dump
177
+ expect(dump).to match(/CONSTRAINT UK_FOO_FOO_ID UNIQUE \(FOO,FOO_ID\)/)
178
+ end
179
+
180
+ it "should dump indexes" do
181
+ ActiveRecord::Base.connection.add_index(:test_posts, :foo, name: :ix_test_posts_foo)
182
+ ActiveRecord::Base.connection.add_index(:test_posts, :foo_id, name: :ix_test_posts_foo_id, unique: true)
183
+
184
+ @conn.execute <<~SQL
185
+ ALTER TABLE test_posts
186
+ add CONSTRAINT uk_foo_foo_id UNIQUE (foo, foo_id)
187
+ SQL
188
+
189
+ dump = ActiveRecord::Base.connection.structure_dump
190
+ expect(dump).to match(/CREATE UNIQUE INDEX "?IX_TEST_POSTS_FOO_ID"? ON "?TEST_POSTS"? \("?FOO_ID"?\)/i)
191
+ expect(dump).to match(/CREATE INDEX "?IX_TEST_POSTS_FOO"? ON "?TEST_POSTS"? \("?FOO"?\)/i)
192
+ expect(dump).not_to match(/CREATE UNIQUE INDEX "?UK_TEST_POSTS_/i)
193
+ end
194
+
195
+ it "should dump multi-value and function value indexes" do
196
+ ActiveRecord::Base.connection.add_index(:test_posts, [:foo, :foo_id], name: :ix_test_posts_foo_foo_id)
197
+
198
+ @conn.execute <<~SQL
199
+ CREATE INDEX "IX_TEST_POSTS_FUNCTION" ON "TEST_POSTS" (TO_CHAR(LENGTH("FOO"))||"FOO")
200
+ SQL
201
+
202
+ dump = ActiveRecord::Base.connection.structure_dump
203
+ expect(dump).to match(/CREATE INDEX "?IX_TEST_POSTS_FOO_FOO_ID"? ON "?TEST_POSTS"? \("?FOO"?, "?FOO_ID"?\)/i)
204
+ expect(dump).to match(/CREATE INDEX "?IX_TEST_POSTS_FUNCTION"? ON "?TEST_POSTS"? \(TO_CHAR\(LENGTH\("?FOO"?\)\)\|\|"?FOO"?\)/i)
205
+ end
206
+
207
+ it "should dump RAW columns" do
208
+ @conn.execute <<~SQL
209
+ CREATE TABLE bars (
210
+ id NUMBER(38,0) NOT NULL,
211
+ super RAW(255),
212
+ PRIMARY KEY (ID)
213
+ )
214
+ SQL
215
+ dump = ActiveRecord::Base.connection.structure_dump
216
+ expect(dump).to match(/CREATE TABLE "BARS" \(\n "ID" NUMBER\(38,0\) NOT NULL,\n "SUPER" RAW\(255\)/)
217
+ end
218
+
219
+ it "should dump check constraints" do
220
+ @conn.execute <<~SQL
221
+ ALTER TABLE test_posts ADD CONSTRAINT test_posts_title_check CHECK (LENGTH(title) > 0)
222
+ SQL
223
+ dump = ActiveRecord::Base.connection.structure_dump_check_constraints("test_posts")
224
+ expect(dump.first).to match(/ALTER TABLE "TEST_POSTS" ADD CONSTRAINT "TEST_POSTS_TITLE_CHECK" CHECK/)
225
+
226
+ dump = ActiveRecord::Base.connection.structure_dump
227
+ expect(dump).to match(/ALTER TABLE "TEST_POSTS" ADD CONSTRAINT "TEST_POSTS_TITLE_CHECK" CHECK/)
228
+ end
229
+
230
+ it "should dump table comments" do
231
+ comment_sql = %Q(COMMENT ON TABLE "TEST_POSTS" IS 'Test posts with ''some'' "quotes"')
232
+ @conn.execute comment_sql
233
+ dump = ActiveRecord::Base.connection.structure_dump
234
+ expect(dump).to match(/#{comment_sql}/)
235
+ end
236
+
237
+ it "should dump column comments" do
238
+ comment_sql = %Q(COMMENT ON COLUMN "TEST_POSTS"."TITLE" IS 'The title of the post with ''some'' "quotes"')
239
+ @conn.execute comment_sql
240
+ dump = ActiveRecord::Base.connection.structure_dump
241
+ expect(dump).to match(/#{comment_sql}/)
242
+ end
243
+ end
244
+
245
+ describe "temporary tables" do
246
+ after(:all) do
247
+ @conn.drop_table :test_comments, if_exists: true
248
+ end
249
+
250
+ it "should dump correctly" do
251
+ @conn.create_table :test_comments, temporary: true, id: false do |t|
252
+ t.integer :post_id
253
+ end
254
+ dump = ActiveRecord::Base.connection.structure_dump
255
+ expect(dump).to match(/CREATE GLOBAL TEMPORARY TABLE "?TEST_COMMENTS"?/i)
256
+ end
257
+ end
258
+
259
+ describe "sequences" do
260
+ let(:sequence_name) { "test_sequence_a" }
261
+ before(:each) do
262
+ @conn.execute sql
263
+ end
264
+
265
+ after(:each) do
266
+ @conn.execute "drop SEQUENCE \"#{sequence_name}\""
267
+ end
268
+
269
+ subject do
270
+ ActiveRecord::Base.connection.structure_dump
271
+ end
272
+
273
+ context "default sequence" do
274
+ let(:sql) { "CREATE SEQUENCE \"#{sequence_name}\"" }
275
+ it { is_expected.to_not match(%r{CREATE SEQUENCE "#{sequence_name}" MAXVALUE \d+ MINVALUE \d+ NOORDER NOCYCLE}) }
276
+ end
277
+
278
+ context "noorder" do
279
+ let(:sql) { "CREATE SEQUENCE \"#{sequence_name}\" NOORDER" }
280
+ it { is_expected.to include("NOORDER") }
281
+ it { is_expected.to_not include(" ORDER") }
282
+ end
283
+
284
+ context "order" do
285
+ let(:sql) { "CREATE SEQUENCE \"#{sequence_name}\" ORDER" }
286
+ it { is_expected.to include(" ORDER") }
287
+ it { is_expected.to_not include("NOORDER") }
288
+ end
289
+
290
+ context "min max values" do
291
+ let(:sql) { "CREATE SEQUENCE \"#{sequence_name}\" MINVALUE 7 MAXVALUE 444" }
292
+ it { is_expected.to include("MINVALUE 7") }
293
+ it { is_expected.to include("MAXVALUE 444") }
294
+ end
295
+ end
296
+
297
+ describe "database structure dump extensions" do
298
+ before(:all) do
299
+ @conn.execute <<~SQL
300
+ CREATE TABLE nvarchartable (
301
+ unq_nvarchar NVARCHAR2(255) DEFAULT NULL
302
+ )
303
+ SQL
304
+ end
305
+
306
+ after(:all) do
307
+ @conn.execute "DROP TABLE nvarchartable"
308
+ end
309
+
310
+ it "should return the character size of nvarchar fields" do
311
+ if /.*unq_nvarchar nvarchar2\((\d+)\).*/ =~ @conn.structure_dump
312
+ expect("#$1").to eq("255")
313
+ end
314
+ end
315
+ end
316
+
317
+ describe "temp_table_drop" do
318
+ before(:each) do
319
+ @conn.create_table :temp_tbl, temporary: true do |t|
320
+ t.string :foo
321
+ end
322
+ @conn.create_table :not_temp_tbl do |t|
323
+ t.string :foo
324
+ end
325
+ end
326
+
327
+ it "should dump drop sql for just temp tables" do
328
+ dump = @conn.temp_table_drop
329
+ expect(dump).to match(/DROP TABLE "TEMP_TBL"/)
330
+ expect(dump).not_to match(/DROP TABLE "?NOT_TEMP_TBL"?/i)
331
+ end
332
+ after(:each) do
333
+ @conn.drop_table :temp_tbl
334
+ @conn.drop_table :not_temp_tbl
335
+ end
336
+ end
337
+
338
+ describe "schema migrations" do
339
+ let(:versions) do
340
+ (1..10).map do |i|
341
+ Time.parse("2016.01.#{i}").strftime("%Y%m%d%H%M%S")
342
+ end
343
+ end
344
+
345
+ let(:dump) { ActiveRecord::Base.connection.dump_schema_versions }
346
+
347
+ before do
348
+ ActiveRecord::Base.connection_pool.schema_migration.create_table
349
+ versions.each do |i|
350
+ ActiveRecord::Base.connection_pool.schema_migration.create_version(i)
351
+ end
352
+ end
353
+
354
+ context "multi insert is supported" do
355
+ it "should dump schema migrations using multi inserts" do
356
+ skip "Not supported in this database version" unless ActiveRecord::Base.connection.supports_multi_insert?
357
+
358
+ expect(dump).to eq <<~SQL
359
+ INSERT ALL
360
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160101000000')
361
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160102000000')
362
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160103000000')
363
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160104000000')
364
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160105000000')
365
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160106000000')
366
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160107000000')
367
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160108000000')
368
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160109000000')
369
+ INTO "SCHEMA_MIGRATIONS" (version) VALUES ('20160110000000')
370
+ SELECT * FROM DUAL
371
+ SQL
372
+ end
373
+ end
374
+
375
+ context "multi insert is NOT supported" do
376
+ let(:insert_statement_per_migration) {
377
+ 1.step(10).map { |i|
378
+ %Q|INSERT INTO "SCHEMA_MIGRATIONS" (version) VALUES ('201601#{sprintf("%02d", i)}000000')|
379
+ }.join("\n\n/\n\n")
380
+ }
381
+
382
+ it "should dump schema migrations one version per insert" do
383
+ skip "Not supported in this database version" if ActiveRecord::Base.connection.supports_multi_insert?
384
+
385
+ expect(dump).to eq insert_statement_per_migration
386
+ end
387
+ end
388
+
389
+ after do
390
+ ActiveRecord::Base.connection_pool.schema_migration.drop_table
391
+ end
392
+ end
393
+
394
+ describe "full drop" do
395
+ before(:each) do
396
+ @conn.create_table :full_drop_test do |t|
397
+ t.string :foo
398
+ end
399
+ @conn.create_table :full_drop_test_temp, temporary: true do |t|
400
+ t.string :foo
401
+ end
402
+ # view
403
+ @conn.execute <<~SQL
404
+ create or replace view full_drop_test_view (foo) as select id as "foo" from full_drop_test
405
+ SQL
406
+ # materialized view
407
+ @conn.execute <<~SQL
408
+ create materialized view full_drop_test_mview (foo) as select id as "foo" from full_drop_test
409
+ SQL
410
+ # package
411
+ @conn.execute <<~SQL
412
+ create or replace package full_drop_test_package as
413
+ function test_func return varchar2;
414
+ end test_package;
415
+ SQL
416
+ @conn.execute <<~SQL
417
+ create or replace package body full_drop_test_package as
418
+ function test_func return varchar2 is
419
+ begin
420
+ return ('foo');
421
+ end test_func;
422
+ end test_package;
423
+ SQL
424
+ # function
425
+ @conn.execute <<~SQL
426
+ create or replace function full_drop_test_function
427
+ return varchar2
428
+ is
429
+ foo varchar2(3);
430
+ begin
431
+ return('foo');
432
+ end;
433
+ SQL
434
+ # procedure
435
+ @conn.execute <<~SQL
436
+ create or replace procedure full_drop_test_procedure
437
+ begin
438
+ delete from full_drop_test where id=1231231231
439
+ exception
440
+ when no_data_found then
441
+ dbms_output.put_line('foo');
442
+ end;
443
+ SQL
444
+ # synonym
445
+ @conn.execute <<~SQL
446
+ create or replace synonym full_drop_test_synonym for full_drop_test
447
+ SQL
448
+ # type
449
+ @conn.execute <<~SQL
450
+ create or replace type full_drop_test_type as table of number
451
+ SQL
452
+ end
453
+
454
+ after(:each) do
455
+ @conn.drop_table :full_drop_test
456
+ @conn.drop_table :full_drop_test_temp
457
+ @conn.execute "DROP VIEW FULL_DROP_TEST_VIEW" rescue nil
458
+ @conn.execute "DROP MATERIALIZED VIEW FULL_DROP_TEST_MVIEW" rescue nil
459
+ @conn.execute "DROP SYNONYM FULL_DROP_TEST_SYNONYM" rescue nil
460
+ @conn.execute "DROP PACKAGE FULL_DROP_TEST_PACKAGE" rescue nil
461
+ @conn.execute "DROP FUNCTION FULL_DROP_TEST_FUNCTION" rescue nil
462
+ @conn.execute "DROP PROCEDURE FULL_DROP_TEST_PROCEDURE" rescue nil
463
+ @conn.execute "DROP TYPE FULL_DROP_TEST_TYPE" rescue nil
464
+ end
465
+
466
+ it "should contain correct sql" do
467
+ drop = @conn.full_drop
468
+ expect(drop).to match(/DROP TABLE "FULL_DROP_TEST" CASCADE CONSTRAINTS/)
469
+ expect(drop).to match(/DROP SEQUENCE "FULL_DROP_TEST_SEQ"/)
470
+ expect(drop).to match(/DROP VIEW "FULL_DROP_TEST_VIEW"/)
471
+ expect(drop).not_to match(/DROP TABLE "?FULL_DROP_TEST_MVIEW"?/i)
472
+ expect(drop).to match(/DROP MATERIALIZED VIEW "FULL_DROP_TEST_MVIEW"/)
473
+ expect(drop).to match(/DROP PACKAGE "FULL_DROP_TEST_PACKAGE"/)
474
+ expect(drop).to match(/DROP FUNCTION "FULL_DROP_TEST_FUNCTION"/)
475
+ expect(drop).to match(/DROP PROCEDURE "FULL_DROP_TEST_PROCEDURE"/)
476
+ expect(drop).to match(/DROP SYNONYM "FULL_DROP_TEST_SYNONYM"/)
477
+ expect(drop).to match(/DROP TYPE "FULL_DROP_TEST_TYPE"/)
478
+ end
479
+ it "should not drop tables when preserve_tables is true" do
480
+ drop = @conn.full_drop(true)
481
+ expect(drop).to match(/DROP TABLE "FULL_DROP_TEST_TEMP"/)
482
+ expect(drop).not_to match(/DROP TABLE "?FULL_DROP_TEST"? CASCADE CONSTRAINTS/i)
483
+ end
484
+ end
485
+ end