activerecord-oracle_enhanced-adapter-with-schema 0.0.1

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