ibm_db 0.4.0 → 0.4.6

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.
@@ -0,0 +1,779 @@
1
+ require 'abstract_unit'
2
+ require 'bigdecimal/util'
3
+
4
+ require 'fixtures/person'
5
+ require 'fixtures/topic'
6
+ require File.dirname(__FILE__) + '/fixtures/migrations/1_people_have_last_names'
7
+ require File.dirname(__FILE__) + '/fixtures/migrations/2_we_need_reminders'
8
+ require File.dirname(__FILE__) + '/fixtures/migrations_with_decimal/1_give_me_big_numbers'
9
+
10
+ if ActiveRecord::Base.connection.supports_migrations?
11
+ class BigNumber < ActiveRecord::Base; end
12
+
13
+ class Reminder < ActiveRecord::Base; end
14
+
15
+ class ActiveRecord::Migration
16
+ class <<self
17
+ attr_accessor :message_count
18
+ def puts(text="")
19
+ self.message_count ||= 0
20
+ self.message_count += 1
21
+ end
22
+ end
23
+ end
24
+
25
+ class MigrationTest < Test::Unit::TestCase
26
+ self.use_transactional_fixtures = false
27
+
28
+ def setup
29
+ ActiveRecord::Migration.verbose = true
30
+ PeopleHaveLastNames.message_count = 0
31
+ end
32
+
33
+ def teardown
34
+ ActiveRecord::Base.connection.initialize_schema_information
35
+ ActiveRecord::Base.connection.update "UPDATE #{ActiveRecord::Migrator.schema_info_table_name} SET version = 0"
36
+
37
+ %w(reminders people_reminders prefix_reminders_suffix).each do |table|
38
+ Reminder.connection.drop_table(table) rescue nil
39
+ end
40
+ Reminder.reset_column_information
41
+
42
+ %w(last_name key bio age height wealth birthday favorite_day
43
+ male administrator).each do |column|
44
+ Person.connection.remove_column('people', column) rescue nil
45
+ end
46
+ Person.connection.remove_column("people", "first_name") rescue nil
47
+ Person.connection.remove_column("people", "middle_name") rescue nil
48
+ Person.connection.add_column("people", "first_name", :string, :limit => 40)
49
+ Person.reset_column_information
50
+ end
51
+
52
+ def test_add_index
53
+ # Limit size of last_name and key columns to support Firebird index limitations
54
+ Person.connection.add_column "people", "last_name", :string, :limit => 100
55
+ Person.connection.add_column "people", "key", :string, :limit => 100
56
+ Person.connection.add_column "people", "administrator", :boolean
57
+
58
+ assert_nothing_raised { Person.connection.add_index("people", "last_name") }
59
+ assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
60
+
61
+ # Orcl nds shrt indx nms. Sybs 2.
62
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :IBM_DBAdapter)
63
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
64
+ assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
65
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
66
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "index_people_on_last_name_and_first_name") }
67
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
68
+ assert_nothing_raised { Person.connection.remove_index("people", "last_name_and_first_name") }
69
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
70
+ assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
71
+ end
72
+
73
+ # quoting
74
+ # Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
75
+ assert_nothing_raised { Person.connection.add_index("people", ["key"], :name => "key_idx", :unique => true) }
76
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "key_idx", :unique => true) }
77
+
78
+ # Sybase adapter does not support indexes on :boolean columns
79
+ unless current_adapter?(:SybaseAdapter)
80
+ assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
81
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
82
+ end
83
+ end
84
+
85
+ def test_create_table_adds_id
86
+ Person.connection.create_table :testings do |t|
87
+ t.column :foo, :string
88
+ end
89
+
90
+ assert_equal %w(foo id),
91
+ Person.connection.columns(:testings).map { |c| c.name }.sort
92
+ ensure
93
+ Person.connection.drop_table :testings rescue nil
94
+ end
95
+
96
+ def test_create_table_with_not_null_column
97
+ assert_nothing_raised do
98
+ Person.connection.create_table :testings do |t|
99
+ t.column :foo, :string, :null => false
100
+ end
101
+ end
102
+
103
+ assert_raises(ActiveRecord::StatementInvalid) do
104
+ Person.connection.execute "insert into testings (foo) values (NULL)"
105
+ end
106
+ ensure
107
+ Person.connection.drop_table :testings rescue nil
108
+ end
109
+
110
+ def test_create_table_with_defaults
111
+ Person.connection.create_table :testings do |t|
112
+ t.column :one, :string, :default => "hello"
113
+ t.column :two, :boolean, :default => true
114
+ t.column :three, :boolean, :default => false
115
+ t.column :four, :integer, :default => 1
116
+ end
117
+
118
+ columns = Person.connection.columns(:testings)
119
+ one = columns.detect { |c| c.name == "one" }
120
+ two = columns.detect { |c| c.name == "two" }
121
+ three = columns.detect { |c| c.name == "three" }
122
+ four = columns.detect { |c| c.name == "four" }
123
+
124
+ assert_equal "hello", one.default
125
+ assert_equal true, two.default
126
+ assert_equal false, three.default
127
+ assert_equal 1, four.default
128
+
129
+ ensure
130
+ Person.connection.drop_table :testings rescue nil
131
+ end
132
+
133
+ def test_create_table_with_limits
134
+ assert_nothing_raised do
135
+ Person.connection.create_table :testings do |t|
136
+ t.column :foo, :string, :limit => 255
137
+
138
+ t.column :default_int, :integer
139
+
140
+ t.column :one_int, :integer, :limit => 1
141
+ t.column :four_int, :integer, :limit => 4
142
+ t.column :eight_int, :integer, :limit => 8
143
+ end
144
+ end
145
+
146
+ columns = Person.connection.columns(:testings)
147
+ foo = columns.detect { |c| c.name == "foo" }
148
+ assert_equal 255, foo.limit
149
+
150
+ default = columns.detect { |c| c.name == "default_int" }
151
+ one = columns.detect { |c| c.name == "one_int" }
152
+ four = columns.detect { |c| c.name == "four_int" }
153
+ eight = columns.detect { |c| c.name == "eight_int" }
154
+
155
+ if current_adapter?(:PostgreSQLAdapter)
156
+ assert_equal 'integer', default.sql_type
157
+ assert_equal 'smallint', one.sql_type
158
+ assert_equal 'integer', four.sql_type
159
+ assert_equal 'bigint', eight.sql_type
160
+ elsif current_adapter?(:OracleAdapter)
161
+ assert_equal 'NUMBER(38)', default.sql_type
162
+ assert_equal 'NUMBER(1)', one.sql_type
163
+ assert_equal 'NUMBER(4)', four.sql_type
164
+ assert_equal 'NUMBER(8)', eight.sql_type
165
+ end
166
+ ensure
167
+ Person.connection.drop_table :testings rescue nil
168
+ end
169
+
170
+ # SQL Server and Sybase will not allow you to add a NOT NULL column
171
+ # to a table without specifying a default value, so the
172
+ # following test must be skipped
173
+ unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :IBM_DBAdapter)
174
+ def test_add_column_not_null_without_default
175
+ Person.connection.create_table :testings do |t|
176
+ t.column :foo, :string
177
+ end
178
+ Person.connection.add_column :testings, :bar, :string, :null => false
179
+
180
+ assert_raises(ActiveRecord::StatementInvalid) do
181
+ Person.connection.execute "insert into testings (foo, bar) values ('hello', NULL)"
182
+ end
183
+ ensure
184
+ Person.connection.drop_table :testings rescue nil
185
+ end
186
+ end
187
+
188
+ def test_add_column_not_null_with_default
189
+ Person.connection.create_table :testings do |t|
190
+ t.column :foo, :string
191
+ end
192
+
193
+ con = Person.connection
194
+ Person.connection.enable_identity_insert("testings", true) if current_adapter?(:SybaseAdapter)
195
+ Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')"
196
+ Person.connection.enable_identity_insert("testings", false) if current_adapter?(:SybaseAdapter)
197
+ assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
198
+
199
+ assert_raises(ActiveRecord::StatementInvalid) do
200
+ Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) values (2, 'hello', NULL)"
201
+ end
202
+ ensure
203
+ Person.connection.drop_table :testings rescue nil
204
+ end
205
+
206
+ # We specifically do a manual INSERT here, and then test only the SELECT
207
+ # functionality. This allows us to more easily catch INSERT being broken,
208
+ # but SELECT actually working fine.
209
+ def test_native_decimal_insert_manual_vs_automatic
210
+ # SQLite3 always uses float in violation of SQL
211
+ # 16 decimal places
212
+ correct_value = (current_adapter?(:SQLiteAdapter) ? '0.123456789012346E20' : '0012345678901234567890.0123456789').to_d
213
+
214
+ Person.delete_all
215
+ Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
216
+ Person.reset_column_information
217
+
218
+ # Do a manual insertion
219
+ if current_adapter?(:OracleAdapter)
220
+ Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
221
+ else
222
+ Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)"
223
+ end
224
+
225
+ # SELECT
226
+ row = Person.find(:first)
227
+ assert_kind_of BigDecimal, row.wealth
228
+
229
+ # If this assert fails, that means the SELECT is broken!
230
+ assert_equal correct_value, row.wealth
231
+
232
+ # Reset to old state
233
+ Person.delete_all
234
+
235
+ # Now use the Rails insertion
236
+ assert_nothing_raised { Person.create :wealth => BigDecimal.new("12345678901234567890.0123456789") }
237
+
238
+ # SELECT
239
+ row = Person.find(:first)
240
+ assert_kind_of BigDecimal, row.wealth
241
+
242
+ # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
243
+ assert_equal correct_value, row.wealth
244
+
245
+ # Reset to old state
246
+ Person.connection.del_column "people", "wealth" rescue nil
247
+ Person.reset_column_information
248
+ end
249
+
250
+ def test_native_types
251
+ Person.delete_all
252
+ Person.connection.add_column "people", "last_name", :string
253
+ Person.connection.add_column "people", "bio", :text
254
+ Person.connection.add_column "people", "age", :integer
255
+ Person.connection.add_column "people", "height", :float
256
+ Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
257
+ Person.connection.add_column "people", "birthday", :datetime
258
+ Person.connection.add_column "people", "favorite_day", :date
259
+ Person.connection.add_column "people", "male", :boolean
260
+ assert_nothing_raised { Person.create :first_name => 'bob', :last_name => 'bobsen', :bio => "I was born ....", :age => 18, :height => 1.78, :wealth => BigDecimal.new("12345678901234567890.0123456789"), :birthday => 18.years.ago, :favorite_day => 10.days.ago, :male => true }
261
+ bob = Person.find(:first)
262
+
263
+ assert_equal 'bob', bob.first_name
264
+ assert_equal 'bobsen', bob.last_name
265
+ assert_equal "I was born ....", bob.bio
266
+ assert_equal 18, bob.age
267
+
268
+ # Test for 30 significent digits (beyond the 16 of float), 10 of them
269
+ # after the decimal place.
270
+ if current_adapter?(:SQLiteAdapter)
271
+ # SQLite3 uses float in violation of SQL. Test for 16 decimal places.
272
+ assert_equal BigDecimal.new('0.123456789012346E20'), bob.wealth
273
+ else
274
+ assert_equal BigDecimal.new("0012345678901234567890.0123456789"), bob.wealth
275
+ end
276
+
277
+ assert_equal true, bob.male?
278
+
279
+ assert_equal String, bob.first_name.class
280
+ assert_equal String, bob.last_name.class
281
+ assert_equal String, bob.bio.class
282
+ assert_equal Fixnum, bob.age.class
283
+ assert_equal Time, bob.birthday.class
284
+
285
+ if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
286
+ # Sybase, and Oracle don't differentiate between date/time
287
+ assert_equal Time, bob.favorite_day.class
288
+ else
289
+ assert_equal Date, bob.favorite_day.class
290
+ end
291
+
292
+ assert_equal TrueClass, bob.male?.class
293
+ assert_kind_of BigDecimal, bob.wealth
294
+ end
295
+
296
+ def test_add_remove_single_field_using_string_arguments
297
+ assert !Person.column_methods_hash.include?(:last_name)
298
+
299
+ ActiveRecord::Migration.add_column 'people', 'last_name', :string
300
+
301
+ Person.reset_column_information
302
+ assert Person.column_methods_hash.include?(:last_name)
303
+
304
+ ActiveRecord::Migration.remove_column 'people', 'last_name'
305
+
306
+ Person.reset_column_information
307
+ assert !Person.column_methods_hash.include?(:last_name)
308
+ end
309
+
310
+ def test_add_remove_single_field_using_symbol_arguments
311
+ assert !Person.column_methods_hash.include?(:last_name)
312
+
313
+ ActiveRecord::Migration.add_column :people, :last_name, :string
314
+
315
+ Person.reset_column_information
316
+ assert Person.column_methods_hash.include?(:last_name)
317
+
318
+ ActiveRecord::Migration.remove_column :people, :last_name
319
+
320
+ Person.reset_column_information
321
+ assert !Person.column_methods_hash.include?(:last_name)
322
+ end
323
+
324
+ def test_add_rename
325
+ Person.delete_all
326
+
327
+ begin
328
+ Person.connection.add_column "people", "girlfriend", :string
329
+ Person.create :girlfriend => 'bobette'
330
+
331
+ Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
332
+
333
+ Person.reset_column_information
334
+ bob = Person.find(:first)
335
+
336
+ assert_equal "bobette", bob.exgirlfriend
337
+ ensure
338
+ Person.connection.remove_column("people", "girlfriend") rescue nil
339
+ Person.connection.remove_column("people", "exgirlfriend") rescue nil
340
+ end
341
+ end
342
+
343
+ def test_rename_column_using_symbol_arguments
344
+ begin
345
+ Person.connection.rename_column :people, :first_name, :nick_name
346
+ Person.reset_column_information
347
+ assert Person.column_names.include?("nick_name")
348
+ ensure
349
+ Person.connection.remove_column("people","nick_name")
350
+ Person.connection.add_column("people","first_name", :string)
351
+ end
352
+ end
353
+
354
+ def test_rename_column
355
+ begin
356
+ Person.connection.rename_column "people", "first_name", "nick_name"
357
+ Person.reset_column_information
358
+ assert Person.column_names.include?("nick_name")
359
+ ensure
360
+ Person.connection.remove_column("people","nick_name")
361
+ Person.connection.add_column("people","first_name", :string)
362
+ end
363
+ end
364
+
365
+ def test_rename_table
366
+ begin
367
+ ActiveRecord::Base.connection.create_table :octopuses do |t|
368
+ t.column :url, :string
369
+ end
370
+ ActiveRecord::Base.connection.rename_table :octopuses, :octopi
371
+
372
+ # Using explicit id in insert for compatibility across all databases
373
+ con = ActiveRecord::Base.connection
374
+ con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
375
+ assert_nothing_raised { con.execute "INSERT INTO octopi (#{con.quote_column_name('id')}, #{con.quote_column_name('url')}) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')" }
376
+ con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
377
+
378
+ assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
379
+
380
+ ensure
381
+ ActiveRecord::Base.connection.drop_table :octopuses rescue nil
382
+ ActiveRecord::Base.connection.drop_table :octopi rescue nil
383
+ end
384
+ end
385
+
386
+ def test_rename_table_with_an_index
387
+ begin
388
+ ActiveRecord::Base.connection.create_table :octopuses do |t|
389
+ t.column :url, :string
390
+ end
391
+ ActiveRecord::Base.connection.add_index :octopuses, :url
392
+
393
+ ActiveRecord::Base.connection.rename_table :octopuses, :octopi
394
+
395
+ # Using explicit id in insert for compatibility across all databases
396
+ con = ActiveRecord::Base.connection
397
+ con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
398
+ assert_nothing_raised { con.execute "INSERT INTO octopi (#{con.quote_column_name('id')}, #{con.quote_column_name('url')}) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')" }
399
+ con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
400
+
401
+ assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
402
+ assert ActiveRecord::Base.connection.indexes(:octopi).first.columns.include?("url")
403
+ ensure
404
+ ActiveRecord::Base.connection.drop_table :octopuses rescue nil
405
+ ActiveRecord::Base.connection.drop_table :octopi rescue nil
406
+ end
407
+ end
408
+
409
+ def test_change_column
410
+ Person.connection.add_column 'people', 'age', :integer
411
+ old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
412
+ assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
413
+
414
+ assert_nothing_raised { Person.connection.change_column "people", "age", :string }
415
+
416
+ new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
417
+ assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
418
+ assert new_columns.find { |c| c.name == 'age' and c.type == :string }
419
+
420
+ old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
421
+ assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
422
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
423
+ new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
424
+ assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
425
+ assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
426
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
427
+ end
428
+
429
+ def test_change_column_with_nil_default
430
+ Person.connection.add_column "people", "contributor", :boolean, :default => true
431
+ Person.reset_column_information
432
+ assert Person.new.contributor?
433
+
434
+ assert_nothing_raised { Person.connection.change_column "people", "contributor", :boolean, :default => nil }
435
+ Person.reset_column_information
436
+ assert !Person.new.contributor?
437
+ assert_nil Person.new.contributor
438
+ end
439
+
440
+ def test_change_column_with_new_default
441
+ Person.connection.add_column "people", "administrator", :boolean, :default => true
442
+ Person.reset_column_information
443
+ assert Person.new.administrator?
444
+
445
+ assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
446
+ Person.reset_column_information
447
+ assert !Person.new.administrator?
448
+ end
449
+
450
+ def test_change_column_default
451
+ Person.connection.change_column_default "people", "first_name", "Tester"
452
+ Person.reset_column_information
453
+ assert_equal "Tester", Person.new.first_name
454
+ end
455
+
456
+ def test_change_column_default_to_null
457
+ Person.connection.change_column_default "people", "first_name", nil
458
+ Person.reset_column_information
459
+ assert_nil Person.new.first_name
460
+ end
461
+
462
+ def test_add_table
463
+ assert !Reminder.table_exists?
464
+
465
+ WeNeedReminders.up
466
+
467
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
468
+ assert_equal "hello world", Reminder.find(:first).content
469
+
470
+ WeNeedReminders.down
471
+ assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
472
+ end
473
+
474
+ def test_add_table_with_decimals
475
+ Person.connection.drop_table :big_numbers rescue nil
476
+
477
+ assert !BigNumber.table_exists?
478
+ GiveMeBigNumbers.up
479
+
480
+ assert BigNumber.create(
481
+ :bank_balance => 1586.43,
482
+ :big_bank_balance => BigDecimal("1000234000567.95"),
483
+ :world_population => 6000000000,
484
+ :my_house_population => 3,
485
+ :value_of_e => BigDecimal("2.7182818284590452353602875")
486
+ )
487
+
488
+ b = BigNumber.find(:first)
489
+ assert_not_nil b
490
+
491
+ assert_not_nil b.bank_balance
492
+ assert_not_nil b.big_bank_balance
493
+ assert_not_nil b.world_population
494
+ assert_not_nil b.my_house_population
495
+ assert_not_nil b.value_of_e
496
+
497
+ # TODO: set world_population >= 2**62 to cover 64-bit platforms and test
498
+ # is_a?(Bignum)
499
+ unless current_adapter?(:IBM_DBAdapter)
500
+ assert_kind_of Integer, b.world_population
501
+ else
502
+ assert_kind_of BigDecimal, b.world_population
503
+ end
504
+ assert_equal 6000000000, b.world_population
505
+ unless current_adapter?(:IBM_DBAdapter)
506
+ assert_kind_of Fixnum, b.my_house_population
507
+ else
508
+ assert_kind_of BigDecimal, b.my_house_population
509
+ end
510
+ assert_equal 3, b.my_house_population
511
+ assert_kind_of BigDecimal, b.bank_balance
512
+ assert_equal BigDecimal("1586.43"), b.bank_balance
513
+ assert_kind_of BigDecimal, b.big_bank_balance
514
+ assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
515
+
516
+ # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with
517
+ # precision/scale explictly left out. By the SQL standard, numbers
518
+ # assigned to this field should be truncated but that's seldom respected.
519
+ if current_adapter?(:PostgreSQLAdapter, :SQLite2Adapter)
520
+ # - PostgreSQL changes the SQL spec on columns declared simply as
521
+ # "decimal" to something more useful: instead of being given a scale
522
+ # of 0, they take on the compile-time limit for precision and scale,
523
+ # so the following should succeed unless you have used really wacky
524
+ # compilation options
525
+ # - SQLite2 has the default behavior of preserving all data sent in,
526
+ # so this happens there too
527
+ assert_kind_of BigDecimal, b.value_of_e
528
+ assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
529
+ elsif current_adapter?(:SQLiteAdapter)
530
+ # - SQLite3 stores a float, in violation of SQL
531
+ assert_kind_of BigDecimal, b.value_of_e
532
+ assert_equal BigDecimal("2.71828182845905"), b.value_of_e
533
+ elsif current_adapter?(:SQLServer)
534
+ # - SQL Server rounds instead of truncating
535
+ assert_kind_of Fixnum, b.value_of_e
536
+ assert_equal 3, b.value_of_e
537
+ else
538
+ # - SQL standard is an integer
539
+ unless current_adapter?(:IBM_DBAdapter)
540
+ assert_kind_of Fixnum, b.value_of_e
541
+ else
542
+ assert_kind_of BigDecimal, b.value_of_e
543
+ end
544
+ assert_equal 2, b.value_of_e
545
+ end
546
+
547
+ GiveMeBigNumbers.down
548
+ assert_raises(ActiveRecord::StatementInvalid) { BigNumber.find(:first) }
549
+ end
550
+
551
+ def test_migrator
552
+ assert !Person.column_methods_hash.include?(:last_name)
553
+ assert !Reminder.table_exists?
554
+
555
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')
556
+
557
+ assert_equal 3, ActiveRecord::Migrator.current_version
558
+ Person.reset_column_information
559
+ assert Person.column_methods_hash.include?(:last_name)
560
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
561
+ assert_equal "hello world", Reminder.find(:first).content
562
+
563
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/')
564
+
565
+ assert_equal 0, ActiveRecord::Migrator.current_version
566
+ Person.reset_column_information
567
+ assert !Person.column_methods_hash.include?(:last_name)
568
+ assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
569
+ end
570
+
571
+ def test_migrator_one_up
572
+ assert !Person.column_methods_hash.include?(:last_name)
573
+ assert !Reminder.table_exists?
574
+
575
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
576
+
577
+ Person.reset_column_information
578
+ assert Person.column_methods_hash.include?(:last_name)
579
+ assert !Reminder.table_exists?
580
+
581
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 2)
582
+
583
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
584
+ assert_equal "hello world", Reminder.find(:first).content
585
+ end
586
+
587
+ def test_migrator_one_down
588
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')
589
+
590
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
591
+
592
+ Person.reset_column_information
593
+ assert Person.column_methods_hash.include?(:last_name)
594
+ assert !Reminder.table_exists?
595
+ end
596
+
597
+ def test_migrator_one_up_one_down
598
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
599
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
600
+
601
+ assert !Person.column_methods_hash.include?(:last_name)
602
+ assert !Reminder.table_exists?
603
+ end
604
+
605
+ def test_migrator_verbosity
606
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
607
+ assert PeopleHaveLastNames.message_count > 0
608
+ PeopleHaveLastNames.message_count = 0
609
+
610
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
611
+ assert PeopleHaveLastNames.message_count > 0
612
+ PeopleHaveLastNames.message_count = 0
613
+ end
614
+
615
+ def test_migrator_verbosity_off
616
+ PeopleHaveLastNames.verbose = false
617
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
618
+ assert PeopleHaveLastNames.message_count.zero?
619
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
620
+ assert PeopleHaveLastNames.message_count.zero?
621
+ end
622
+
623
+ def test_migrator_going_down_due_to_version_target
624
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
625
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
626
+
627
+ assert !Person.column_methods_hash.include?(:last_name)
628
+ assert !Reminder.table_exists?
629
+
630
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations/')
631
+
632
+ Person.reset_column_information
633
+ assert Person.column_methods_hash.include?(:last_name)
634
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
635
+ assert_equal "hello world", Reminder.find(:first).content
636
+ end
637
+
638
+ def test_schema_info_table_name
639
+ ActiveRecord::Base.table_name_prefix = "prefix_"
640
+ ActiveRecord::Base.table_name_suffix = "_suffix"
641
+ Reminder.reset_table_name
642
+ assert_equal "prefix_schema_info_suffix", ActiveRecord::Migrator.schema_info_table_name
643
+ ActiveRecord::Base.table_name_prefix = ""
644
+ ActiveRecord::Base.table_name_suffix = ""
645
+ Reminder.reset_table_name
646
+ assert_equal "schema_info", ActiveRecord::Migrator.schema_info_table_name
647
+ ensure
648
+ ActiveRecord::Base.table_name_prefix = ""
649
+ ActiveRecord::Base.table_name_suffix = ""
650
+ end
651
+
652
+ def test_proper_table_name
653
+ assert_equal "table", ActiveRecord::Migrator.proper_table_name('table')
654
+ assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table)
655
+ assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder)
656
+ Reminder.reset_table_name
657
+ assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder)
658
+
659
+ # Use the model's own prefix/suffix if a model is given
660
+ ActiveRecord::Base.table_name_prefix = "ARprefix_"
661
+ ActiveRecord::Base.table_name_suffix = "_ARsuffix"
662
+ Reminder.table_name_prefix = 'prefix_'
663
+ Reminder.table_name_suffix = '_suffix'
664
+ Reminder.reset_table_name
665
+ assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder)
666
+ Reminder.table_name_prefix = ''
667
+ Reminder.table_name_suffix = ''
668
+ Reminder.reset_table_name
669
+
670
+ # Use AR::Base's prefix/suffix if string or symbol is given
671
+ ActiveRecord::Base.table_name_prefix = "prefix_"
672
+ ActiveRecord::Base.table_name_suffix = "_suffix"
673
+ Reminder.reset_table_name
674
+ assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table')
675
+ assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table)
676
+ ActiveRecord::Base.table_name_prefix = ""
677
+ ActiveRecord::Base.table_name_suffix = ""
678
+ Reminder.reset_table_name
679
+ end
680
+
681
+ def test_add_drop_table_with_prefix_and_suffix
682
+ assert !Reminder.table_exists?
683
+ ActiveRecord::Base.table_name_prefix = 'prefix_'
684
+ ActiveRecord::Base.table_name_suffix = '_suffix'
685
+ Reminder.reset_table_name
686
+ Reminder.reset_sequence_name
687
+ WeNeedReminders.up
688
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
689
+ assert_equal "hello world", Reminder.find(:first).content
690
+
691
+ WeNeedReminders.down
692
+ assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
693
+ ensure
694
+ ActiveRecord::Base.table_name_prefix = ''
695
+ ActiveRecord::Base.table_name_suffix = ''
696
+ Reminder.reset_table_name
697
+ Reminder.reset_sequence_name
698
+ end
699
+
700
+ # FrontBase does not support default values on BLOB/CLOB columns
701
+ unless current_adapter?(:FrontBaseAdapter)
702
+ def test_create_table_with_binary_column
703
+ Person.connection.drop_table :binary_testings rescue nil
704
+
705
+ assert_nothing_raised {
706
+ Person.connection.create_table :binary_testings do |t|
707
+ t.column "data", :binary, :default => "", :null => false
708
+ end
709
+ }
710
+
711
+ columns = Person.connection.columns(:binary_testings)
712
+ data_column = columns.detect { |c| c.name == "data" }
713
+
714
+ if current_adapter?(:OracleAdapter)
715
+ assert_equal "empty_blob()", data_column.default
716
+ else
717
+ assert_equal "", data_column.default
718
+ end
719
+
720
+ Person.connection.drop_table :binary_testings rescue nil
721
+ end
722
+ end
723
+ def test_migrator_with_duplicates
724
+ assert_raises(ActiveRecord::DuplicateMigrationVersionError) do
725
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_duplicate/', nil)
726
+ end
727
+ end
728
+
729
+ def test_migrator_with_missing_version_numbers
730
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_missing_versions/', 500)
731
+ assert !Person.column_methods_hash.include?(:middle_name)
732
+ assert_equal 4, ActiveRecord::Migrator.current_version
733
+
734
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_missing_versions/', 2)
735
+ assert !Reminder.table_exists?
736
+ assert Person.column_methods_hash.include?(:last_name)
737
+ assert_equal 2, ActiveRecord::Migrator.current_version
738
+ end
739
+
740
+ def test_create_table_with_custom_sequence_name
741
+ return unless current_adapter? :OracleAdapter
742
+
743
+ # table name is 29 chars, the standard sequence name will
744
+ # be 33 chars and fail
745
+ assert_raises(ActiveRecord::StatementInvalid) do
746
+ begin
747
+ Person.connection.create_table :table_with_name_thats_just_ok do |t|
748
+ t.column :foo, :string, :null => false
749
+ end
750
+ ensure
751
+ Person.connection.drop_table :table_with_name_thats_just_ok rescue nil
752
+ end
753
+ end
754
+
755
+ # should be all good w/ a custom sequence name
756
+ assert_nothing_raised do
757
+ begin
758
+ Person.connection.create_table :table_with_name_thats_just_ok,
759
+ :sequence_name => 'suitably_short_seq' do |t|
760
+ t.column :foo, :string, :null => false
761
+ end
762
+
763
+ Person.connection.execute("select suitably_short_seq.nextval from dual")
764
+
765
+ ensure
766
+ Person.connection.drop_table :table_with_name_thats_just_ok,
767
+ :sequence_name => 'suitably_short_seq' rescue nil
768
+ end
769
+ end
770
+
771
+ # confirm the custom sequence got dropped
772
+ assert_raises(ActiveRecord::StatementInvalid) do
773
+ Person.connection.execute("select suitably_short_seq.nextval from dual")
774
+ end
775
+ end
776
+
777
+ end
778
+ end
779
+