ctreatma-activerecord-oracle_enhanced-adapter 1.4.1.1

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 (47) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +51 -0
  3. data/History.md +269 -0
  4. data/License.txt +20 -0
  5. data/README.md +378 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +46 -0
  8. data/VERSION +1 -0
  9. data/activerecord-oracle_enhanced-adapter.gemspec +130 -0
  10. data/ctreatma-activerecord-oracle_enhanced-adapter.gemspec +129 -0
  11. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1390 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +106 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +136 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +119 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +328 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +553 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +492 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +213 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +252 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +373 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +265 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +290 -0
  30. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  31. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  32. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +749 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +310 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +426 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +19 -0
  37. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +113 -0
  38. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +1330 -0
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +69 -0
  40. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +121 -0
  41. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  42. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +374 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +380 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1112 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +323 -0
  46. data/spec/spec_helper.rb +185 -0
  47. metadata +287 -0
@@ -0,0 +1,380 @@
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
+ oracle11g = @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, :default=>"first_name || ', ' || last_name" if oracle11g
356
+ end
357
+ end
358
+ end
359
+ before(:each) do
360
+ class ::TestName < ActiveRecord::Base
361
+ set_table_name "test_names"
362
+ end
363
+ end
364
+
365
+ after(:all) do
366
+ schema_define do
367
+ drop_table :test_names
368
+ end
369
+ end
370
+
371
+ it 'should dump correctly' do
372
+ pending "Not supported in this database version" unless @oracle11g
373
+ standard_dump.should =~ /t.virtual "full_name",(\s*):limit => 512,(\s*):default => "/
374
+ end
375
+
376
+ end
377
+
378
+
379
+ end
380
+
@@ -0,0 +1,1112 @@
1
+ require 'spec_helper'
2
+
3
+ describe "OracleEnhancedAdapter schema definition" do
4
+ include SchemaSpecHelper
5
+
6
+ before(:all) do
7
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
8
+ @oracle11g = !! ActiveRecord::Base.connection.select_value("SELECT * FROM v$version WHERE banner LIKE 'Oracle%11g%'")
9
+ end
10
+
11
+ describe "table and sequence creation with non-default primary key" do
12
+
13
+ before(:all) do
14
+ @conn = ActiveRecord::Base.connection
15
+ schema_define do
16
+ create_table :keyboards, :force => true, :id => false do |t|
17
+ t.primary_key :key_number
18
+ t.string :name
19
+ end
20
+ create_table :id_keyboards, :force => true do |t|
21
+ t.string :name
22
+ end
23
+ end
24
+ class ::Keyboard < ActiveRecord::Base
25
+ set_primary_key :key_number
26
+ end
27
+ class ::IdKeyboard < ActiveRecord::Base
28
+ end
29
+ end
30
+
31
+ after(:all) do
32
+ schema_define do
33
+ drop_table :keyboards
34
+ drop_table :id_keyboards
35
+ end
36
+ Object.send(:remove_const, "Keyboard")
37
+ Object.send(:remove_const, "IdKeyboard")
38
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
39
+ end
40
+
41
+ it "should create sequence for non-default primary key" do
42
+ ActiveRecord::Base.connection.next_sequence_value(Keyboard.sequence_name).should_not be_nil
43
+ end
44
+
45
+ it "should create sequence for default primary key" do
46
+ ActiveRecord::Base.connection.next_sequence_value(IdKeyboard.sequence_name).should_not be_nil
47
+ end
48
+ end
49
+
50
+ describe "sequence creation parameters" do
51
+
52
+ def create_test_employees_table(sequence_start_value = nil)
53
+ schema_define do
54
+ create_table :test_employees, sequence_start_value ? {:sequence_start_value => sequence_start_value} : {} do |t|
55
+ t.string :first_name
56
+ t.string :last_name
57
+ end
58
+ end
59
+ end
60
+
61
+ def save_default_sequence_start_value
62
+ @saved_sequence_start_value = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value
63
+ end
64
+
65
+ def restore_default_sequence_start_value
66
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = @saved_sequence_start_value
67
+ end
68
+
69
+ before(:all) do
70
+ @conn = ActiveRecord::Base.connection
71
+ end
72
+
73
+ before(:each) do
74
+ save_default_sequence_start_value
75
+ end
76
+
77
+ after(:each) do
78
+ restore_default_sequence_start_value
79
+ schema_define do
80
+ drop_table :test_employees
81
+ end
82
+ Object.send(:remove_const, "TestEmployee")
83
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
84
+ end
85
+
86
+ it "should use default sequence start value 10000" do
87
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value.should == 10000
88
+
89
+ create_test_employees_table
90
+ class ::TestEmployee < ActiveRecord::Base; end
91
+
92
+ employee = TestEmployee.create!
93
+ employee.id.should == 10000
94
+ end
95
+
96
+ it "should use specified default sequence start value" do
97
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = 1
98
+
99
+ create_test_employees_table
100
+ class ::TestEmployee < ActiveRecord::Base; end
101
+
102
+ employee = TestEmployee.create!
103
+ employee.id.should == 1
104
+ end
105
+
106
+ it "should use sequence start value from table definition" do
107
+ create_test_employees_table(10)
108
+ class ::TestEmployee < ActiveRecord::Base; end
109
+
110
+ employee = TestEmployee.create!
111
+ employee.id.should == 10
112
+ end
113
+
114
+ it "should use sequence start value and other options from table definition" do
115
+ create_test_employees_table("100 NOCACHE INCREMENT BY 10")
116
+ class ::TestEmployee < ActiveRecord::Base; end
117
+
118
+ employee = TestEmployee.create!
119
+ employee.id.should == 100
120
+ employee = TestEmployee.create!
121
+ employee.id.should == 110
122
+ end
123
+
124
+ end
125
+
126
+ describe "create table with primary key trigger" do
127
+ def create_table_with_trigger(options = {})
128
+ options.merge! :primary_key_trigger => true, :force => true
129
+ schema_define do
130
+ create_table :test_employees, options do |t|
131
+ t.string :first_name
132
+ t.string :last_name
133
+ end
134
+ end
135
+ end
136
+
137
+ def create_table_and_separately_trigger(options = {})
138
+ options.merge! :force => true
139
+ schema_define do
140
+ create_table :test_employees, options do |t|
141
+ t.string :first_name
142
+ t.string :last_name
143
+ end
144
+ add_primary_key_trigger :test_employees, options
145
+ end
146
+ end
147
+
148
+ def drop_table_with_trigger(options = {})
149
+ seq_name = options[:sequence_name]
150
+ schema_define do
151
+ drop_table :test_employees, (seq_name ? {:sequence_name => seq_name} : {})
152
+ end
153
+ Object.send(:remove_const, "TestEmployee")
154
+ @conn.clear_prefetch_primary_key
155
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
156
+ end
157
+
158
+ describe "with default primary key" do
159
+ before(:all) do
160
+ @conn = ActiveRecord::Base.connection
161
+ create_table_with_trigger
162
+ class ::TestEmployee < ActiveRecord::Base
163
+ end
164
+ end
165
+
166
+ after(:all) do
167
+ drop_table_with_trigger
168
+ end
169
+
170
+ it "should populate primary key using trigger" do
171
+ lambda do
172
+ @conn.execute "INSERT INTO test_employees (first_name) VALUES ('Raimonds')"
173
+ end.should_not raise_error
174
+ end
175
+
176
+ it "should return new key value using connection insert method" do
177
+ insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Raimonds')", nil, "id")
178
+ @conn.select_value("SELECT test_employees_seq.currval FROM dual").should == insert_id
179
+ end
180
+
181
+ it "should create new record for model" do
182
+ e = TestEmployee.create!(:first_name => 'Raimonds')
183
+ @conn.select_value("SELECT test_employees_seq.currval FROM dual").should == e.id
184
+ end
185
+ end
186
+
187
+ describe "with separate creation of primary key trigger" do
188
+ before(:all) do
189
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
190
+ @conn = ActiveRecord::Base.connection
191
+ create_table_and_separately_trigger
192
+ class ::TestEmployee < ActiveRecord::Base
193
+ end
194
+ end
195
+
196
+ after(:all) do
197
+ drop_table_with_trigger
198
+ end
199
+
200
+ it "should populate primary key using trigger" do
201
+ lambda do
202
+ @conn.execute "INSERT INTO test_employees (first_name) VALUES ('Raimonds')"
203
+ end.should_not raise_error
204
+ end
205
+
206
+ it "should return new key value using connection insert method" do
207
+ insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Raimonds')", nil, "id")
208
+ @conn.select_value("SELECT test_employees_seq.currval FROM dual").should == insert_id
209
+ end
210
+
211
+ it "should create new record for model" do
212
+ e = TestEmployee.create!(:first_name => 'Raimonds')
213
+ @conn.select_value("SELECT test_employees_seq.currval FROM dual").should == e.id
214
+ end
215
+ end
216
+
217
+ describe "with non-default primary key and non-default sequence name" do
218
+ before(:all) do
219
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
220
+ @conn = ActiveRecord::Base.connection
221
+ @primary_key = "employee_id"
222
+ @sequence_name = "test_employees_s"
223
+ create_table_with_trigger(:primary_key => @primary_key, :sequence_name => @sequence_name)
224
+ class ::TestEmployee < ActiveRecord::Base
225
+ set_primary_key "employee_id"
226
+ end
227
+ end
228
+
229
+ after(:all) do
230
+ drop_table_with_trigger(:sequence_name => @sequence_name)
231
+ end
232
+
233
+ it "should populate primary key using trigger" do
234
+ lambda do
235
+ @conn.execute "INSERT INTO test_employees (first_name) VALUES ('Raimonds')"
236
+ end.should_not raise_error
237
+ end
238
+
239
+ it "should return new key value using connection insert method" do
240
+ insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Raimonds')", nil, @primary_key)
241
+ @conn.select_value("SELECT #{@sequence_name}.currval FROM dual").should == insert_id
242
+ end
243
+
244
+ it "should create new record for model with autogenerated sequence option" do
245
+ e = TestEmployee.create!(:first_name => 'Raimonds')
246
+ @conn.select_value("SELECT #{@sequence_name}.currval FROM dual").should == e.id
247
+ end
248
+ end
249
+
250
+ describe "with non-default sequence name and non-default trigger name" do
251
+ before(:all) do
252
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
253
+ @conn = ActiveRecord::Base.connection
254
+ @sequence_name = "test_employees_s"
255
+ create_table_with_trigger(:sequence_name => @sequence_name, :trigger_name => "test_employees_t1")
256
+ class ::TestEmployee < ActiveRecord::Base
257
+ set_sequence_name :autogenerated
258
+ end
259
+ end
260
+
261
+ after(:all) do
262
+ drop_table_with_trigger(:sequence_name => @sequence_name)
263
+ end
264
+
265
+ it "should populate primary key using trigger" do
266
+ lambda do
267
+ @conn.execute "INSERT INTO test_employees (first_name) VALUES ('Raimonds')"
268
+ end.should_not raise_error
269
+ end
270
+
271
+ it "should return new key value using connection insert method" do
272
+ insert_id = @conn.insert("INSERT INTO test_employees (first_name) VALUES ('Raimonds')", nil, "id")
273
+ @conn.select_value("SELECT #{@sequence_name}.currval FROM dual").should == insert_id
274
+ end
275
+
276
+ it "should create new record for model with autogenerated sequence option" do
277
+ e = TestEmployee.create!(:first_name => 'Raimonds')
278
+ @conn.select_value("SELECT #{@sequence_name}.currval FROM dual").should == e.id
279
+ end
280
+ end
281
+
282
+ end
283
+
284
+ describe "table and column comments" do
285
+
286
+ def create_test_employees_table(table_comment=nil, column_comments={})
287
+ schema_define do
288
+ create_table :test_employees, :comment => table_comment do |t|
289
+ t.string :first_name, :comment => column_comments[:first_name]
290
+ t.string :last_name, :comment => column_comments[:last_name]
291
+ end
292
+ end
293
+ end
294
+
295
+ before(:all) do
296
+ @conn = ActiveRecord::Base.connection
297
+ end
298
+
299
+ after(:each) do
300
+ schema_define do
301
+ drop_table :test_employees
302
+ end
303
+ Object.send(:remove_const, "TestEmployee")
304
+ ActiveRecord::Base.table_name_prefix = nil
305
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
306
+ end
307
+
308
+ it "should create table with table comment" do
309
+ table_comment = "Test Employees"
310
+ create_test_employees_table(table_comment)
311
+ class ::TestEmployee < ActiveRecord::Base; end
312
+
313
+ @conn.table_comment("test_employees").should == table_comment
314
+ TestEmployee.table_comment.should == table_comment
315
+ end
316
+
317
+ it "should create table with columns comment" do
318
+ column_comments = {:first_name => "Given Name", :last_name => "Surname"}
319
+ create_test_employees_table(nil, column_comments)
320
+ class ::TestEmployee < ActiveRecord::Base; end
321
+
322
+ [:first_name, :last_name].each do |attr|
323
+ @conn.column_comment("test_employees", attr.to_s).should == column_comments[attr]
324
+ end
325
+ [:first_name, :last_name].each do |attr|
326
+ TestEmployee.columns_hash[attr.to_s].comment.should == column_comments[attr]
327
+ end
328
+ end
329
+
330
+ it "should create table with table and columns comment and custom table name prefix" do
331
+ ActiveRecord::Base.table_name_prefix = "xxx_"
332
+ table_comment = "Test Employees"
333
+ column_comments = {:first_name => "Given Name", :last_name => "Surname"}
334
+ create_test_employees_table(table_comment, column_comments)
335
+ class ::TestEmployee < ActiveRecord::Base; end
336
+
337
+ @conn.table_comment(TestEmployee.table_name).should == table_comment
338
+ TestEmployee.table_comment.should == table_comment
339
+ [:first_name, :last_name].each do |attr|
340
+ @conn.column_comment(TestEmployee.table_name, attr.to_s).should == column_comments[attr]
341
+ end
342
+ [:first_name, :last_name].each do |attr|
343
+ TestEmployee.columns_hash[attr.to_s].comment.should == column_comments[attr]
344
+ end
345
+ end
346
+
347
+ end
348
+
349
+ describe "rename tables and sequences" do
350
+ before(:each) do
351
+ @conn = ActiveRecord::Base.connection
352
+ schema_define do
353
+ drop_table :test_employees rescue nil
354
+ drop_table :new_test_employees rescue nil
355
+ create_table :test_employees do |t|
356
+ t.string :first_name
357
+ t.string :last_name
358
+ end
359
+ end
360
+ end
361
+
362
+ after(:each) do
363
+ schema_define do
364
+ drop_table :test_employees rescue nil
365
+ drop_table :new_test_employees rescue nil
366
+ end
367
+ end
368
+
369
+ it "should rename table name with new one" do
370
+ lambda do
371
+ @conn.rename_table("test_employees","new_test_employees")
372
+ end.should_not raise_error
373
+ end
374
+
375
+ it "should raise error when new table name length is too long" do
376
+ lambda do
377
+ @conn.rename_table("test_employees","a"*31)
378
+ end.should raise_error
379
+ end
380
+
381
+ it "should raise error when new sequence name length is too long" do
382
+ lambda do
383
+ @conn.rename_table("test_employees","a"*27)
384
+ end.should raise_error
385
+ end
386
+
387
+ end
388
+
389
+ describe "create triggers" do
390
+
391
+ before(:all) do
392
+ @conn = ActiveRecord::Base.connection
393
+ schema_define do
394
+ create_table :test_employees do |t|
395
+ t.string :first_name
396
+ t.string :last_name
397
+ end
398
+ end
399
+ class ::TestEmployee < ActiveRecord::Base; end
400
+ end
401
+
402
+ after(:all) do
403
+ schema_define do
404
+ drop_table :test_employees
405
+ end
406
+ Object.send(:remove_const, "TestEmployee")
407
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
408
+ end
409
+
410
+ it "should create table trigger with :new reference" do
411
+ lambda do
412
+ @conn.execute <<-SQL
413
+ CREATE OR REPLACE TRIGGER test_employees_pkt
414
+ BEFORE INSERT ON test_employees FOR EACH ROW
415
+ BEGIN
416
+ IF inserting THEN
417
+ IF :new.id IS NULL THEN
418
+ SELECT test_employees_seq.NEXTVAL INTO :new.id FROM dual;
419
+ END IF;
420
+ END IF;
421
+ END;
422
+ SQL
423
+ end.should_not raise_error
424
+ end
425
+ end
426
+
427
+ describe "add index" do
428
+ before(:all) do
429
+ @conn = ActiveRecord::Base.connection
430
+ end
431
+
432
+ it "should return default index name if it is not larger than 30 characters" do
433
+ @conn.index_name("employees", :column => "first_name").should == "index_employees_on_first_name"
434
+ end
435
+
436
+ it "should return shortened index name by removing 'index', 'on' and 'and' keywords" do
437
+ @conn.index_name("employees", :column => ["first_name", "email"]).should == "i_employees_first_name_email"
438
+ end
439
+
440
+ it "should return shortened index name by shortening table and column names" do
441
+ @conn.index_name("employees", :column => ["first_name", "last_name"]).should == "i_emp_fir_nam_las_nam"
442
+ end
443
+
444
+ it "should raise error if too large index name cannot be shortened" do
445
+ @conn.index_name("test_employees", :column => ["first_name", "middle_name", "last_name"]).should ==
446
+ 'i'+Digest::SHA1.hexdigest("index_test_employees_on_first_name_and_middle_name_and_last_name")[0,29]
447
+ end
448
+
449
+ end
450
+
451
+ describe "rename index" do
452
+ before(:each) do
453
+ @conn = ActiveRecord::Base.connection
454
+ schema_define do
455
+ create_table :test_employees do |t|
456
+ t.string :first_name
457
+ t.string :last_name
458
+ end
459
+ add_index :test_employees, :first_name
460
+ end
461
+ class ::TestEmployee < ActiveRecord::Base; end
462
+ end
463
+
464
+ after(:each) do
465
+ schema_define do
466
+ drop_table :test_employees
467
+ end
468
+ Object.send(:remove_const, "TestEmployee")
469
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
470
+ end
471
+
472
+ it "should raise error when current index name and new index name are identical" do
473
+ lambda do
474
+ @conn.rename_index("test_employees","i_test_employees_first_name","i_test_employees_first_name")
475
+ end.should raise_error
476
+ end
477
+
478
+ it "should raise error when new index name length is too long" do
479
+ lambda do
480
+ @conn.rename_index("test_employees","i_test_employees_first_name","a"*31)
481
+ end.should raise_error
482
+ end
483
+
484
+ it "should raise error when current index name does not exist" do
485
+ lambda do
486
+ @conn.rename_index("test_employees","nonexist_index_name","new_index_name")
487
+ end.should raise_error
488
+ end
489
+
490
+ it "should rename index name with new one" do
491
+ lambda do
492
+ @conn.rename_index("test_employees","i_test_employees_first_name","new_index_name")
493
+ end.should_not raise_error
494
+ end
495
+ end
496
+
497
+ describe "ignore options for LOB columns" do
498
+ after(:each) do
499
+ schema_define do
500
+ drop_table :test_posts
501
+ end
502
+ end
503
+
504
+ it "should ignore :limit option for :text column" do
505
+ lambda do
506
+ schema_define do
507
+ create_table :test_posts, :force => true do |t|
508
+ t.text :body, :limit => 10000
509
+ end
510
+ end
511
+ end.should_not raise_error
512
+ end
513
+
514
+ it "should ignore :limit option for :binary column" do
515
+ lambda do
516
+ schema_define do
517
+ create_table :test_posts, :force => true do |t|
518
+ t.binary :picture, :limit => 10000
519
+ end
520
+ end
521
+ end.should_not raise_error
522
+ end
523
+
524
+ end
525
+
526
+ describe "foreign key constraints" do
527
+ before(:each) do
528
+ schema_define do
529
+ create_table :test_posts, :force => true do |t|
530
+ t.string :title
531
+ end
532
+ create_table :test_comments, :force => true do |t|
533
+ t.string :body, :limit => 4000
534
+ t.references :test_post
535
+ t.integer :post_id
536
+ end
537
+ end
538
+ class ::TestPost < ActiveRecord::Base
539
+ has_many :test_comments
540
+ end
541
+ class ::TestComment < ActiveRecord::Base
542
+ belongs_to :test_post
543
+ end
544
+ end
545
+
546
+ after(:each) do
547
+ Object.send(:remove_const, "TestPost")
548
+ Object.send(:remove_const, "TestComment")
549
+ schema_define do
550
+ drop_table :test_comments rescue nil
551
+ drop_table :test_posts rescue nil
552
+ end
553
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
554
+ end
555
+
556
+ it "should add foreign key" do
557
+ schema_define do
558
+ add_foreign_key :test_comments, :test_posts
559
+ end
560
+ lambda do
561
+ TestComment.create(:body => "test", :test_post_id => 1)
562
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291.*\.TEST_COMMENTS_TEST_POST_ID_FK/}
563
+ end
564
+
565
+ it "should add foreign key with name" do
566
+ schema_define do
567
+ add_foreign_key :test_comments, :test_posts, :name => "comments_posts_fk"
568
+ end
569
+ lambda do
570
+ TestComment.create(:body => "test", :test_post_id => 1)
571
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291.*\.COMMENTS_POSTS_FK/}
572
+ end
573
+
574
+ it "should add foreign key with long name which is shortened" do
575
+ schema_define do
576
+ add_foreign_key :test_comments, :test_posts, :name => "test_comments_test_post_id_foreign_key"
577
+ end
578
+ lambda do
579
+ TestComment.create(:body => "test", :test_post_id => 1)
580
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291.*\.TES_COM_TES_POS_ID_FOR_KEY/}
581
+ end
582
+
583
+ it "should add foreign key with very long name which is shortened" do
584
+ schema_define do
585
+ add_foreign_key :test_comments, :test_posts, :name => "long_prefix_test_comments_test_post_id_foreign_key"
586
+ end
587
+ lambda do
588
+ TestComment.create(:body => "test", :test_post_id => 1)
589
+ end.should raise_error() {|e| e.message.should =~
590
+ /ORA-02291.*\.C#{Digest::SHA1.hexdigest("long_prefix_test_comments_test_post_id_foreign_key")[0,29].upcase}/}
591
+ end
592
+
593
+ it "should add foreign key with column" do
594
+ schema_define do
595
+ add_foreign_key :test_comments, :test_posts, :column => "post_id"
596
+ end
597
+ lambda do
598
+ TestComment.create(:body => "test", :post_id => 1)
599
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291.*\.TEST_COMMENTS_POST_ID_FK/}
600
+ end
601
+
602
+ it "should add foreign key with delete dependency" do
603
+ schema_define do
604
+ add_foreign_key :test_comments, :test_posts, :dependent => :delete
605
+ end
606
+ p = TestPost.create(:title => "test")
607
+ c = TestComment.create(:body => "test", :test_post => p)
608
+ TestPost.delete(p.id)
609
+ TestComment.find_by_id(c.id).should be_nil
610
+ end
611
+
612
+ it "should add foreign key with nullify dependency" do
613
+ schema_define do
614
+ add_foreign_key :test_comments, :test_posts, :dependent => :nullify
615
+ end
616
+ p = TestPost.create(:title => "test")
617
+ c = TestComment.create(:body => "test", :test_post => p)
618
+ TestPost.delete(p.id)
619
+ TestComment.find_by_id(c.id).test_post_id.should be_nil
620
+ end
621
+
622
+ it "should add a composite foreign key" do
623
+ schema_define do
624
+ add_column :test_posts, :baz_id, :integer
625
+ add_column :test_posts, :fooz_id, :integer
626
+
627
+ execute <<-SQL
628
+ ALTER TABLE TEST_POSTS
629
+ ADD CONSTRAINT UK_FOOZ_BAZ UNIQUE (BAZ_ID,FOOZ_ID)
630
+ SQL
631
+
632
+ add_column :test_comments, :baz_id, :integer
633
+ add_column :test_comments, :fooz_id, :integer
634
+
635
+ add_foreign_key :test_comments, :test_posts, :columns => ["baz_id", "fooz_id"]
636
+ end
637
+
638
+ lambda do
639
+ TestComment.create(:body => "test", :fooz_id => 1, :baz_id => 1)
640
+ end.should raise_error() {|e| e.message.should =~
641
+ /ORA-02291.*\.TES_COM_BAZ_ID_FOO_ID_FK/}
642
+ end
643
+
644
+ it "should add a composite foreign key with name" do
645
+ schema_define do
646
+ add_column :test_posts, :baz_id, :integer
647
+ add_column :test_posts, :fooz_id, :integer
648
+
649
+ execute <<-SQL
650
+ ALTER TABLE TEST_POSTS
651
+ ADD CONSTRAINT UK_FOOZ_BAZ UNIQUE (BAZ_ID,FOOZ_ID)
652
+ SQL
653
+
654
+ add_column :test_comments, :baz_id, :integer
655
+ add_column :test_comments, :fooz_id, :integer
656
+
657
+ add_foreign_key :test_comments, :test_posts, :columns => ["baz_id", "fooz_id"], :name => 'comments_posts_baz_fooz_fk'
658
+ end
659
+
660
+ lambda do
661
+ TestComment.create(:body => "test", :baz_id => 1, :fooz_id => 1)
662
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291.*\.COMMENTS_POSTS_BAZ_FOOZ_FK/}
663
+ end
664
+
665
+ it "should remove foreign key by table name" do
666
+ schema_define do
667
+ add_foreign_key :test_comments, :test_posts
668
+ remove_foreign_key :test_comments, :test_posts
669
+ end
670
+ lambda do
671
+ TestComment.create(:body => "test", :test_post_id => 1)
672
+ end.should_not raise_error
673
+ end
674
+
675
+ it "should remove foreign key by constraint name" do
676
+ schema_define do
677
+ add_foreign_key :test_comments, :test_posts, :name => "comments_posts_fk"
678
+ remove_foreign_key :test_comments, :name => "comments_posts_fk"
679
+ end
680
+ lambda do
681
+ TestComment.create(:body => "test", :test_post_id => 1)
682
+ end.should_not raise_error
683
+ end
684
+
685
+ it "should remove foreign key by column name" do
686
+ schema_define do
687
+ add_foreign_key :test_comments, :test_posts
688
+ remove_foreign_key :test_comments, :column => "test_post_id"
689
+ end
690
+ lambda do
691
+ TestComment.create(:body => "test", :test_post_id => 1)
692
+ end.should_not raise_error
693
+ end
694
+
695
+ end
696
+
697
+ describe "foreign key in table definition" do
698
+ before(:each) do
699
+ schema_define do
700
+ create_table :test_posts, :force => true do |t|
701
+ t.string :title
702
+ end
703
+ end
704
+ class ::TestPost < ActiveRecord::Base
705
+ has_many :test_comments
706
+ end
707
+ class ::TestComment < ActiveRecord::Base
708
+ belongs_to :test_post
709
+ end
710
+ end
711
+
712
+ after(:each) do
713
+ Object.send(:remove_const, "TestPost")
714
+ Object.send(:remove_const, "TestComment")
715
+ schema_define do
716
+ drop_table :test_comments rescue nil
717
+ drop_table :test_posts rescue nil
718
+ end
719
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
720
+ end
721
+
722
+ it "should add foreign key in create_table" do
723
+ schema_define do
724
+ create_table :test_comments, :force => true do |t|
725
+ t.string :body, :limit => 4000
726
+ t.references :test_post
727
+ t.foreign_key :test_posts
728
+ end
729
+ end
730
+ lambda do
731
+ TestComment.create(:body => "test", :test_post_id => 1)
732
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291/}
733
+ end
734
+
735
+ it "should add foreign key in create_table references" do
736
+ schema_define do
737
+ create_table :test_comments, :force => true do |t|
738
+ t.string :body, :limit => 4000
739
+ t.references :test_post, :foreign_key => true
740
+ end
741
+ end
742
+ lambda do
743
+ TestComment.create(:body => "test", :test_post_id => 1)
744
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291/}
745
+ end
746
+
747
+ it "should add foreign key in change_table" do
748
+ return pending("Not in this ActiveRecord version") unless ENV['RAILS_GEM_VERSION'] >= '2.1'
749
+ schema_define do
750
+ create_table :test_comments, :force => true do |t|
751
+ t.string :body, :limit => 4000
752
+ t.references :test_post
753
+ end
754
+ change_table :test_comments do |t|
755
+ t.foreign_key :test_posts
756
+ end
757
+ end
758
+ lambda do
759
+ TestComment.create(:body => "test", :test_post_id => 1)
760
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291/}
761
+ end
762
+
763
+ it "should add foreign key in change_table references" do
764
+ return pending("Not in this ActiveRecord version") unless ENV['RAILS_GEM_VERSION'] >= '2.1'
765
+ schema_define do
766
+ create_table :test_comments, :force => true do |t|
767
+ t.string :body, :limit => 4000
768
+ end
769
+ change_table :test_comments do |t|
770
+ t.references :test_post, :foreign_key => true
771
+ end
772
+ end
773
+ lambda do
774
+ TestComment.create(:body => "test", :test_post_id => 1)
775
+ end.should raise_error() {|e| e.message.should =~ /ORA-02291/}
776
+ end
777
+
778
+ it "should remove foreign key by table name" do
779
+ return pending("Not in this ActiveRecord version") unless ENV['RAILS_GEM_VERSION'] >= '2.1'
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
+ end
785
+ change_table :test_comments do |t|
786
+ t.foreign_key :test_posts
787
+ end
788
+ change_table :test_comments do |t|
789
+ t.remove_foreign_key :test_posts
790
+ end
791
+ end
792
+ lambda do
793
+ TestComment.create(:body => "test", :test_post_id => 1)
794
+ end.should_not raise_error
795
+ end
796
+
797
+ end
798
+
799
+ describe "disable referential integrity" do
800
+ before(:all) do
801
+ @conn = ActiveRecord::Base.connection
802
+ end
803
+
804
+ before(:each) do
805
+ schema_define do
806
+ create_table :test_posts, :force => true do |t|
807
+ t.string :title
808
+ end
809
+ create_table :test_comments, :force => true do |t|
810
+ t.string :body, :limit => 4000
811
+ t.references :test_post, :foreign_key => true
812
+ end
813
+ end
814
+ end
815
+
816
+ after(:each) do
817
+ schema_define do
818
+ drop_table :test_comments rescue nil
819
+ drop_table :test_posts rescue nil
820
+ end
821
+ end
822
+
823
+ it "should disable all foreign keys" do
824
+ lambda do
825
+ @conn.execute "INSERT INTO test_comments (id, body, test_post_id) VALUES (1, 'test', 1)"
826
+ end.should raise_error
827
+ @conn.disable_referential_integrity do
828
+ lambda do
829
+ @conn.execute "INSERT INTO test_comments (id, body, test_post_id) VALUES (2, 'test', 2)"
830
+ @conn.execute "INSERT INTO test_posts (id, title) VALUES (2, 'test')"
831
+ end.should_not raise_error
832
+ end
833
+ lambda do
834
+ @conn.execute "INSERT INTO test_comments (id, body, test_post_id) VALUES (3, 'test', 3)"
835
+ end.should raise_error
836
+ end
837
+
838
+ end
839
+
840
+ describe "synonyms" do
841
+ before(:all) do
842
+ @conn = ActiveRecord::Base.connection
843
+ @db_link = "db_link"
844
+ @username = @db_link_username = CONNECTION_PARAMS[:username]
845
+ @db_link_password = CONNECTION_PARAMS[:password]
846
+ @db_link_database = CONNECTION_PARAMS[:database]
847
+ @conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
848
+ @conn.execute "CREATE DATABASE LINK #{@db_link} CONNECT TO #{@db_link_username} IDENTIFIED BY \"#{@db_link_password}\" USING '#{@db_link_database}'"
849
+ schema_define do
850
+ create_table :test_posts, :force => true do |t|
851
+ t.string :title
852
+ end
853
+ end
854
+ end
855
+
856
+ after(:all) do
857
+ schema_define do
858
+ drop_table :test_posts
859
+ end
860
+ @conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
861
+ end
862
+
863
+ before(:each) do
864
+ class ::TestPost < ActiveRecord::Base
865
+ set_table_name "synonym_to_posts"
866
+ end
867
+ end
868
+
869
+ after(:each) do
870
+ Object.send(:remove_const, "TestPost")
871
+ schema_define do
872
+ remove_synonym :synonym_to_posts
873
+ remove_synonym :synonym_to_posts_seq
874
+ end
875
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
876
+ end
877
+
878
+ it "should create synonym to table and sequence" do
879
+ schema_name = @username
880
+ schema_define do
881
+ add_synonym :synonym_to_posts, "#{schema_name}.test_posts", :force => true
882
+ add_synonym :synonym_to_posts_seq, "#{schema_name}.test_posts_seq", :force => true
883
+ end
884
+ lambda do
885
+ TestPost.create(:title => "test")
886
+ end.should_not raise_error
887
+ end
888
+
889
+ it "should create synonym to table over database link" do
890
+ db_link = @db_link
891
+ schema_define do
892
+ add_synonym :synonym_to_posts, "test_posts@#{db_link}", :force => true
893
+ add_synonym :synonym_to_posts_seq, "test_posts_seq@#{db_link}", :force => true
894
+ end
895
+ lambda do
896
+ TestPost.create(:title => "test")
897
+ end.should_not raise_error
898
+ end
899
+
900
+ end
901
+
902
+ describe "alter columns with column cache" do
903
+ include LoggerSpecHelper
904
+
905
+ before(:all) do
906
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = true
907
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:clob)
908
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:blob)
909
+ end
910
+
911
+ after(:all) do
912
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = nil
913
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:clob)
914
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:blob)
915
+ end
916
+
917
+ before(:each) do
918
+ schema_define do
919
+ create_table :test_posts, :force => true do |t|
920
+ t.string :title, :null => false
921
+ end
922
+ end
923
+ class ::TestPost < ActiveRecord::Base; end
924
+ TestPost.columns_hash['title'].null.should be_false
925
+ end
926
+
927
+ after(:each) do
928
+ Object.send(:remove_const, "TestPost")
929
+ schema_define { drop_table :test_posts }
930
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
931
+ end
932
+
933
+ it "should change column to nullable" do
934
+ schema_define do
935
+ change_column :test_posts, :title, :string, :null => true
936
+ end
937
+ TestPost.reset_column_information
938
+ TestPost.columns_hash['title'].null.should be_true
939
+ end
940
+
941
+ it "should add column" do
942
+ schema_define do
943
+ add_column :test_posts, :body, :string
944
+ end
945
+ TestPost.reset_column_information
946
+ TestPost.columns_hash['body'].should_not be_nil
947
+ end
948
+
949
+ it "should add lob column with non_default tablespace" do
950
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = DATABASE_NON_DEFAULT_TABLESPACE
951
+ schema_define do
952
+ add_column :test_posts, :body, :text
953
+ end
954
+ TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'BODY'").should == DATABASE_NON_DEFAULT_TABLESPACE
955
+ end
956
+
957
+ it "should add blob column with non_default tablespace" do
958
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:blob] = DATABASE_NON_DEFAULT_TABLESPACE
959
+ schema_define do
960
+ add_column :test_posts, :attachment, :binary
961
+ end
962
+ TestPost.connection.select_value("SELECT tablespace_name FROM user_lobs WHERE table_name='TEST_POSTS' and column_name = 'ATTACHMENT'").should == DATABASE_NON_DEFAULT_TABLESPACE
963
+ end
964
+
965
+ it "should rename column" do
966
+ schema_define do
967
+ rename_column :test_posts, :title, :subject
968
+ end
969
+ TestPost.reset_column_information
970
+ TestPost.columns_hash['subject'].should_not be_nil
971
+ TestPost.columns_hash['title'].should be_nil
972
+ end
973
+
974
+ it "should remove column" do
975
+ schema_define do
976
+ remove_column :test_posts, :title
977
+ end
978
+ TestPost.reset_column_information
979
+ TestPost.columns_hash['title'].should be_nil
980
+ end
981
+
982
+ end
983
+
984
+ describe 'virtual columns' do
985
+ before(:all) do
986
+ oracle11g = @oracle11g
987
+ schema_define do
988
+ expr = "( numerator/NULLIF(denominator,0) )*100"
989
+ create_table :test_fractions, :force => true do |t|
990
+ t.integer :numerator, :default=>0
991
+ t.integer :denominator, :default=>0
992
+ t.virtual :percent, :default=>expr if oracle11g
993
+ end
994
+ end
995
+ end
996
+ before(:each) do
997
+ class ::TestFraction < ActiveRecord::Base
998
+ set_table_name "test_fractions"
999
+ end
1000
+ end
1001
+
1002
+ after(:all) do
1003
+ schema_define do
1004
+ drop_table :test_fractions
1005
+ end
1006
+ end
1007
+
1008
+ it 'should include virtual columns and not try to update them' do
1009
+ pending "Not supported in this database version" unless @oracle11g
1010
+ tf = TestFraction.columns.detect { |c| c.virtual? }
1011
+ tf.should_not be nil
1012
+ tf.name.should == "percent"
1013
+ tf.virtual?.should be true
1014
+ lambda do
1015
+ tf = TestFraction.new(:numerator=>20, :denominator=>100)
1016
+ tf.percent.should==0 # not whatever is in DATA_DEFAULT column
1017
+ tf.save!
1018
+ tf.reload
1019
+ end.should_not raise_error
1020
+ tf.percent.to_i.should == 20
1021
+ end
1022
+ end
1023
+
1024
+ describe "miscellaneous options" do
1025
+ before(:all) do
1026
+ @conn = ActiveRecord::Base.connection
1027
+ end
1028
+
1029
+ before(:each) do
1030
+ @conn.instance_variable_set :@would_execute_sql, @would_execute_sql=''
1031
+ class <<@conn
1032
+ def execute(sql,name=nil); @would_execute_sql << sql << ";\n"; end
1033
+ def index_name_exists?(table_name, index_name, default); default; end
1034
+ end
1035
+ end
1036
+
1037
+ after(:each) do
1038
+ class <<@conn
1039
+ remove_method :execute
1040
+ end
1041
+ @conn.instance_eval{ remove_instance_variable :@would_execute_sql }
1042
+ end
1043
+
1044
+ it "should support the :options option to create_table" do
1045
+ schema_define do
1046
+ create_table :test_posts, :options=>'NOLOGGING', :force => true do |t|
1047
+ t.string :title, :null => false
1048
+ end
1049
+ end
1050
+ @would_execute_sql.should =~ /CREATE +TABLE .* \(.*\) NOLOGGING/
1051
+ end
1052
+
1053
+ it "should support the :tablespace option to create_table" do
1054
+ schema_define do
1055
+ create_table :test_posts, :tablespace=>'bogus', :force => true do |t|
1056
+ t.string :title, :null => false
1057
+ end
1058
+ end
1059
+ @would_execute_sql.should =~ /CREATE +TABLE .* \(.*\) TABLESPACE bogus/
1060
+ end
1061
+
1062
+ describe "creating a table with a tablespace defaults set" do
1063
+ after(:each) do
1064
+ @conn.drop_table :tablespace_tests rescue nil
1065
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:table)
1066
+ end
1067
+ it "should use correct tablespace" do
1068
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:table] = DATABASE_NON_DEFAULT_TABLESPACE
1069
+ @conn.create_table :tablespace_tests do |t|
1070
+ t.integer :id
1071
+ end
1072
+ @would_execute_sql.should =~ /CREATE +TABLE .* \(.*\) TABLESPACE #{DATABASE_NON_DEFAULT_TABLESPACE}/
1073
+ end
1074
+ end
1075
+
1076
+ describe "creating an index-organized table" do
1077
+ after(:each) do
1078
+ @conn.drop_table :tablespace_tests rescue nil
1079
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:table)
1080
+ end
1081
+ it "should use correct tablespace" do
1082
+ @conn.create_table :tablespace_tests, :id=>false, :organization=>'INDEX INITRANS 4 COMPRESS 1', :tablespace=>'bogus' do |t|
1083
+ t.integer :id
1084
+ end
1085
+ @would_execute_sql.should =~ /CREATE +TABLE .*\(.*\)\s+ORGANIZATION INDEX INITRANS 4 COMPRESS 1 TABLESPACE bogus/
1086
+ end
1087
+ end
1088
+
1089
+ it "should support the :options option to add_index" do
1090
+ schema_define do
1091
+ add_index :keyboards, :name, :options=>'NOLOGGING'
1092
+ end
1093
+ @would_execute_sql.should =~ /CREATE +INDEX .* ON .* \(.*\) NOLOGGING/
1094
+ end
1095
+
1096
+ it "should support the :tablespace option to add_index" do
1097
+ schema_define do
1098
+ add_index :keyboards, :name, :tablespace=>'bogus'
1099
+ end
1100
+ @would_execute_sql.should =~ /CREATE +INDEX .* ON .* \(.*\) TABLESPACE bogus/
1101
+ end
1102
+
1103
+ it "should use default_tablespaces in add_index" do
1104
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:index] = DATABASE_NON_DEFAULT_TABLESPACE
1105
+ schema_define do
1106
+ add_index :keyboards, :name
1107
+ end
1108
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces.delete(:index)
1109
+ @would_execute_sql.should =~ /CREATE +INDEX .* ON .* \(.*\) TABLESPACE #{DATABASE_NON_DEFAULT_TABLESPACE}/
1110
+ end
1111
+ end
1112
+ end