activerecord-odbc-adapter 2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/AUTHORS +16 -0
  2. data/COPYING +21 -0
  3. data/ChangeLog +139 -0
  4. data/LICENSE +5 -0
  5. data/NEWS +25 -0
  6. data/README +229 -0
  7. data/lib/active_record/connection_adapters/odbc_adapter.rb +1950 -0
  8. data/lib/active_record/vendor/odbcext_db2.rb +87 -0
  9. data/lib/active_record/vendor/odbcext_informix.rb +144 -0
  10. data/lib/active_record/vendor/odbcext_informix_col.rb +45 -0
  11. data/lib/active_record/vendor/odbcext_ingres.rb +156 -0
  12. data/lib/active_record/vendor/odbcext_microsoftsqlserver.rb +216 -0
  13. data/lib/active_record/vendor/odbcext_microsoftsqlserver_col.rb +40 -0
  14. data/lib/active_record/vendor/odbcext_mysql.rb +174 -0
  15. data/lib/active_record/vendor/odbcext_oracle.rb +219 -0
  16. data/lib/active_record/vendor/odbcext_postgresql.rb +158 -0
  17. data/lib/active_record/vendor/odbcext_progress.rb +139 -0
  18. data/lib/active_record/vendor/odbcext_progress89.rb +259 -0
  19. data/lib/active_record/vendor/odbcext_sqlanywhere.rb +115 -0
  20. data/lib/active_record/vendor/odbcext_sqlanywhere_col.rb +49 -0
  21. data/lib/active_record/vendor/odbcext_sybase.rb +213 -0
  22. data/lib/active_record/vendor/odbcext_sybase_col.rb +49 -0
  23. data/lib/active_record/vendor/odbcext_virtuoso.rb +158 -0
  24. data/lib/odbc_adapter.rb +28 -0
  25. data/support/lib/active_record/connection_adapters/abstract/schema_definitions.rb +259 -0
  26. data/support/odbc_rails.diff +367 -0
  27. data/support/pack_odbc.rb +119 -0
  28. data/support/rake/rails_plugin_package_task.rb +212 -0
  29. data/support/rake_fixes/README +6 -0
  30. data/support/rake_fixes/databases.dif +13 -0
  31. data/support/test/base_test.rb +1765 -0
  32. data/support/test/migration_test.rb +1007 -0
  33. data/test/connections/native_odbc/connection.rb +137 -0
  34. data/test/fixtures/db_definitions/db2.drop.sql +33 -0
  35. data/test/fixtures/db_definitions/db2.sql +237 -0
  36. data/test/fixtures/db_definitions/db22.drop.sql +2 -0
  37. data/test/fixtures/db_definitions/db22.sql +5 -0
  38. data/test/fixtures/db_definitions/informix.drop.sql +33 -0
  39. data/test/fixtures/db_definitions/informix.sql +223 -0
  40. data/test/fixtures/db_definitions/informix2.drop.sql +2 -0
  41. data/test/fixtures/db_definitions/informix2.sql +5 -0
  42. data/test/fixtures/db_definitions/ingres.drop.sql +68 -0
  43. data/test/fixtures/db_definitions/ingres.sql +252 -0
  44. data/test/fixtures/db_definitions/ingres2.drop.sql +2 -0
  45. data/test/fixtures/db_definitions/ingres2.sql +5 -0
  46. data/test/fixtures/db_definitions/mysql.drop.sql +33 -0
  47. data/test/fixtures/db_definitions/mysql.sql +238 -0
  48. data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
  49. data/test/fixtures/db_definitions/mysql2.sql +5 -0
  50. data/test/fixtures/db_definitions/oracle_odbc.drop.sql +72 -0
  51. data/test/fixtures/db_definitions/oracle_odbc.sql +296 -0
  52. data/test/fixtures/db_definitions/oracle_odbc2.drop.sql +2 -0
  53. data/test/fixtures/db_definitions/oracle_odbc2.sql +6 -0
  54. data/test/fixtures/db_definitions/postgresql.drop.sql +38 -0
  55. data/test/fixtures/db_definitions/postgresql.sql +267 -0
  56. data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
  57. data/test/fixtures/db_definitions/postgresql2.sql +5 -0
  58. data/test/fixtures/db_definitions/progress.drop.sql +67 -0
  59. data/test/fixtures/db_definitions/progress.sql +255 -0
  60. data/test/fixtures/db_definitions/progress2.drop.sql +2 -0
  61. data/test/fixtures/db_definitions/progress2.sql +6 -0
  62. data/test/fixtures/db_definitions/sqlserver.drop.sql +35 -0
  63. data/test/fixtures/db_definitions/sqlserver.sql +247 -0
  64. data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
  65. data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
  66. data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
  67. data/test/fixtures/db_definitions/sybase.sql +222 -0
  68. data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
  69. data/test/fixtures/db_definitions/sybase2.sql +5 -0
  70. data/test/fixtures/db_definitions/virtuoso.drop.sql +33 -0
  71. data/test/fixtures/db_definitions/virtuoso.sql +218 -0
  72. data/test/fixtures/db_definitions/virtuoso2.drop.sql +2 -0
  73. data/test/fixtures/db_definitions/virtuoso2.sql +5 -0
  74. metadata +166 -0
@@ -0,0 +1,1007 @@
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
+ fixtures :people
29
+
30
+ def setup
31
+ ActiveRecord::Migration.verbose = true
32
+ PeopleHaveLastNames.message_count = 0
33
+ end
34
+
35
+ def teardown
36
+ ActiveRecord::Base.connection.initialize_schema_information
37
+ ActiveRecord::Base.connection.update "UPDATE #{ActiveRecord::Migrator.schema_info_table_name} SET version = 0"
38
+
39
+ %w(reminders people_reminders prefix_reminders_suffix).each do |table|
40
+ Reminder.connection.drop_table(table) rescue nil
41
+ end
42
+ Reminder.reset_column_information
43
+
44
+ %w(last_name key bio age height wealth birthday favorite_day
45
+ moment_of_truth male administrator funny).each do |column|
46
+ Person.connection.remove_column('people', column) rescue nil
47
+ end
48
+ Person.connection.remove_column("people", "first_name") rescue nil
49
+ Person.connection.remove_column("people", "middle_name") rescue nil
50
+ Person.connection.add_column("people", "first_name", :string, :limit => 40)
51
+ Person.reset_column_information
52
+ end
53
+
54
+ def test_add_index
55
+ if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :informix
56
+ # Index on (last_name, first_name) exceeds max. index width supported by Informix if
57
+ # both columns are created with a default width of 255, in which case
58
+ # Informix may return error -517: "The total size of the index is too large..."
59
+ Person.connection.add_column "people", "last_name", :string, {:limit => 40}
60
+ else
61
+ # Limit size of last_name and key columns to support Firebird index limitations
62
+ Person.connection.add_column "people", "last_name", :string, :limit => 100
63
+ end
64
+ Person.connection.add_column "people", "key", :string, :limit => 100
65
+ Person.connection.add_column "people", "administrator", :boolean
66
+
67
+ assert_nothing_raised { Person.connection.add_index("people", "last_name") }
68
+ assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
69
+
70
+ # Orcl nds shrt indx nms. Sybs 2.
71
+ # OpenBase does not have named indexes. You must specify a single column name
72
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter) ||
73
+ current_adapter?(:ODBCAdapter) && [:sybase, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
74
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
75
+ assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
76
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
77
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "index_people_on_last_name_and_first_name") }
78
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
79
+ assert_nothing_raised { Person.connection.remove_index("people", "last_name_and_first_name") }
80
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
81
+ assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
82
+ end
83
+
84
+ # quoting
85
+ # Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
86
+ # OpenBase does not have named indexes. You must specify a single column name
87
+ unless current_adapter?(:OpenBaseAdapter)
88
+ assert_nothing_raised { Person.connection.add_index("people", ["key"], :name => "key_idx", :unique => true) }
89
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "key_idx", :unique => true) }
90
+ end
91
+
92
+ # Sybase adapter does not support indexes on :boolean columns
93
+ # OpenBase does not have named indexes. You must specify a single column
94
+ unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter) ||
95
+ current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :sybase
96
+ assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
97
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
98
+ end
99
+ end
100
+
101
+ def test_create_table_adds_id
102
+ Person.connection.create_table :testings do |t|
103
+ t.column :foo, :string
104
+ end
105
+
106
+ assert_equal %w(foo id),
107
+ Person.connection.columns(:testings).map { |c| c.name }.sort
108
+ ensure
109
+ Person.connection.drop_table :testings rescue nil
110
+ end
111
+
112
+ def test_create_table_with_not_null_column
113
+ assert_nothing_raised do
114
+ Person.connection.create_table :testings do |t|
115
+ t.column :foo, :string, :null => false
116
+ end
117
+ end
118
+
119
+ assert_raises(ActiveRecord::StatementInvalid) do
120
+ Person.connection.execute "insert into testings (foo) values (NULL)"
121
+ end
122
+ ensure
123
+ Person.connection.drop_table :testings rescue nil
124
+ end
125
+
126
+ def test_create_table_with_defaults
127
+ # MySQL doesn't allow defaults on TEXT or BLOB columns.
128
+ mysql = current_adapter?(:MysqlAdapter)
129
+
130
+ Person.connection.create_table :testings do |t|
131
+ t.column :one, :string, :default => "hello"
132
+ t.column :two, :boolean, :default => true
133
+ t.column :three, :boolean, :default => false
134
+ t.column :four, :integer, :default => 1
135
+ t.column :five, :text, :default => "hello" unless mysql
136
+ end
137
+
138
+ columns = Person.connection.columns(:testings)
139
+ one = columns.detect { |c| c.name == "one" }
140
+ two = columns.detect { |c| c.name == "two" }
141
+ three = columns.detect { |c| c.name == "three" }
142
+ four = columns.detect { |c| c.name == "four" }
143
+ five = columns.detect { |c| c.name == "five" } unless mysql
144
+
145
+ assert_equal "hello", one.default
146
+ assert_equal true, two.default
147
+ assert_equal false, three.default
148
+ assert_equal 1, four.default
149
+ assert_equal "hello", five.default unless mysql
150
+
151
+ ensure
152
+ Person.connection.drop_table :testings rescue nil
153
+ end
154
+
155
+ def test_create_table_with_limits
156
+ assert_nothing_raised do
157
+ Person.connection.create_table :testings do |t|
158
+ t.column :foo, :string, :limit => 255
159
+
160
+ t.column :default_int, :integer
161
+
162
+ t.column :one_int, :integer, :limit => 1
163
+ t.column :four_int, :integer, :limit => 4
164
+ t.column :eight_int, :integer, :limit => 8
165
+ end
166
+ end
167
+
168
+ columns = Person.connection.columns(:testings)
169
+ foo = columns.detect { |c| c.name == "foo" }
170
+ assert_equal 255, foo.limit
171
+
172
+ default = columns.detect { |c| c.name == "default_int" }
173
+ one = columns.detect { |c| c.name == "one_int" }
174
+ four = columns.detect { |c| c.name == "four_int" }
175
+ eight = columns.detect { |c| c.name == "eight_int" }
176
+
177
+ if current_adapter?(:PostgreSQLAdapter)
178
+ assert_equal 'integer', default.sql_type
179
+ assert_equal 'smallint', one.sql_type
180
+ assert_equal 'integer', four.sql_type
181
+ assert_equal 'bigint', eight.sql_type
182
+ elsif current_adapter?(:OracleAdapter)
183
+ assert_equal 'NUMBER(38)', default.sql_type
184
+ assert_equal 'NUMBER(1)', one.sql_type
185
+ assert_equal 'NUMBER(4)', four.sql_type
186
+ assert_equal 'NUMBER(8)', eight.sql_type
187
+ end
188
+ ensure
189
+ Person.connection.drop_table :testings rescue nil
190
+ end
191
+
192
+ # SQL Server, Sybase, and SQLite3 will not allow you to add a NOT NULL
193
+ # column to a table without a default value.
194
+ unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter) ||
195
+ current_adapter?(:ODBCAdapter) && [:microsoftsqlserver, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
196
+ def test_add_column_not_null_without_default
197
+ Person.connection.create_table :testings do |t|
198
+ t.column :foo, :string
199
+ end
200
+ Person.connection.add_column :testings, :bar, :string, :null => false
201
+
202
+ assert_raises(ActiveRecord::StatementInvalid) do
203
+ Person.connection.execute "insert into testings (foo, bar) values ('hello', NULL)"
204
+ end
205
+ ensure
206
+ Person.connection.drop_table :testings rescue nil
207
+ end
208
+ end
209
+
210
+ def test_add_column_not_null_with_default
211
+ Person.connection.create_table :testings do |t|
212
+ t.column :foo, :string
213
+ end
214
+
215
+ con = Person.connection
216
+ Person.connection.enable_identity_insert("testings", true) if current_adapter?(:SybaseAdapter)
217
+ Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')"
218
+ Person.connection.enable_identity_insert("testings", false) if current_adapter?(:SybaseAdapter)
219
+ if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
220
+ # Ingres requires that if 'ALTER TABLE table ADD column' specifies a NOT NULL constraint,
221
+ # then 'WITH DEFAULT' must also be specified *without* a default value.
222
+ assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false}
223
+ else
224
+ assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
225
+ end
226
+
227
+ assert_raises(ActiveRecord::StatementInvalid) do
228
+ unless current_adapter?(:OpenBaseAdapter)
229
+ 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)"
230
+ else
231
+ Person.connection.insert("INSERT INTO testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}, #{con.quote_column_name('bar')}) VALUES (2, 'hello', NULL)",
232
+ "Testing Insert","id",2)
233
+ end
234
+ end
235
+ ensure
236
+ Person.connection.drop_table :testings rescue nil
237
+ end
238
+
239
+ # We specifically do a manual INSERT here, and then test only the SELECT
240
+ # functionality. This allows us to more easily catch INSERT being broken,
241
+ # but SELECT actually working fine.
242
+ def test_native_decimal_insert_manual_vs_automatic
243
+ correct_value = '0012345678901234567890.0123456789'.to_d
244
+
245
+ Person.delete_all
246
+ Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
247
+ Person.reset_column_information
248
+
249
+ # Do a manual insertion
250
+ if current_adapter?(:OracleAdapter)
251
+ Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
252
+ elsif current_adapter?(:OpenBaseAdapter)
253
+ Person.connection.execute "insert into people (wealth) values ('12345678901234567890.0123456789')"
254
+ else
255
+ Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)"
256
+ end
257
+
258
+ # SELECT
259
+ row = Person.find(:first)
260
+ assert_kind_of BigDecimal, row.wealth
261
+
262
+ # If this assert fails, that means the SELECT is broken!
263
+ unless current_adapter?(:SQLite3Adapter)
264
+ assert_equal correct_value, row.wealth
265
+ end
266
+
267
+ # Reset to old state
268
+ Person.delete_all
269
+
270
+ # Now use the Rails insertion
271
+ assert_nothing_raised { Person.create :wealth => BigDecimal.new("12345678901234567890.0123456789") }
272
+
273
+ # SELECT
274
+ row = Person.find(:first)
275
+ assert_kind_of BigDecimal, row.wealth
276
+
277
+ # If these asserts fail, that means the INSERT (create function, or cast to SQL) is broken!
278
+ unless current_adapter?(:SQLite3Adapter)
279
+ assert_equal correct_value, row.wealth
280
+ end
281
+
282
+ # Reset to old state
283
+ Person.connection.del_column "people", "wealth" rescue nil
284
+ Person.reset_column_information
285
+ end
286
+
287
+ def test_native_types
288
+ Person.delete_all
289
+ Person.connection.add_column "people", "last_name", :string
290
+ Person.connection.add_column "people", "bio", :text
291
+ Person.connection.add_column "people", "age", :integer
292
+ Person.connection.add_column "people", "height", :float
293
+ Person.connection.add_column "people", "wealth", :decimal, :precision => '30', :scale => '10'
294
+ Person.connection.add_column "people", "birthday", :datetime
295
+ Person.connection.add_column "people", "favorite_day", :date
296
+ Person.connection.add_column "people", "moment_of_truth", :datetime
297
+ Person.connection.add_column "people", "male", :boolean
298
+ Person.reset_column_information
299
+
300
+ assert_nothing_raised do
301
+ Person.create :first_name => 'bob', :last_name => 'bobsen',
302
+ :bio => "I was born ....", :age => 18, :height => 1.78,
303
+ :wealth => BigDecimal.new("12345678901234567890.0123456789"),
304
+ :birthday => 18.years.ago, :favorite_day => 10.days.ago,
305
+ :moment_of_truth => "1782-10-10 21:40:18", :male => true
306
+ end
307
+
308
+ bob = Person.find(:first)
309
+ assert_equal 'bob', bob.first_name
310
+ assert_equal 'bobsen', bob.last_name
311
+ assert_equal "I was born ....", bob.bio
312
+ assert_equal 18, bob.age
313
+
314
+ # Test for 30 significent digits (beyond the 16 of float), 10 of them
315
+ # after the decimal place.
316
+
317
+ unless current_adapter?(:SQLite3Adapter)
318
+ assert_equal BigDecimal.new("0012345678901234567890.0123456789"), bob.wealth
319
+ end
320
+
321
+ assert_equal true, bob.male?
322
+
323
+ assert_equal String, bob.first_name.class
324
+ assert_equal String, bob.last_name.class
325
+ assert_equal String, bob.bio.class
326
+ assert_equal Fixnum, bob.age.class
327
+ assert_equal Time, bob.birthday.class
328
+
329
+ if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter) ||
330
+ (current_adapter?(:ODBCAdapter) &&
331
+ [:ingres, :oracle, :microsoftsqlserver].include?(ActiveRecord::Base.connection.dbmsName))
332
+ # SQL Server, Sybase, Oracle and Ingres don't differentiate between date/time
333
+ assert_equal Time, bob.favorite_day.class
334
+ else
335
+ assert_equal Date, bob.favorite_day.class
336
+ end
337
+
338
+ # Test DateTime column and defaults, including timezone.
339
+ # FIXME: moment of truth may be Time on 64-bit platforms.
340
+ if bob.moment_of_truth.is_a?(DateTime)
341
+ assert_equal DateTime.now.offset, bob.moment_of_truth.offset
342
+ assert_not_equal 0, bob.moment_of_truth.offset
343
+ assert_not_equal "Z", bob.moment_of_truth.zone
344
+ assert_equal DateTime::ITALY, bob.moment_of_truth.start
345
+ end
346
+
347
+ assert_equal TrueClass, bob.male?.class
348
+ assert_kind_of BigDecimal, bob.wealth
349
+ end
350
+
351
+ if current_adapter?(:MysqlAdapter)
352
+ def test_unabstracted_database_dependent_types
353
+ Person.delete_all
354
+
355
+ ActiveRecord::Migration.add_column :people, :intelligence_quotient, :tinyint
356
+ Person.reset_column_information
357
+ Person.create :intelligence_quotient => 300
358
+ jonnyg = Person.find(:first)
359
+ assert_equal 127, jonnyg.intelligence_quotient
360
+ jonnyg.destroy
361
+ ensure
362
+ ActiveRecord::Migration.remove_column :people, :intelligence_quotient rescue nil
363
+ end
364
+ end
365
+
366
+ def test_add_remove_single_field_using_string_arguments
367
+ assert !Person.column_methods_hash.include?(:last_name)
368
+
369
+ ActiveRecord::Migration.add_column 'people', 'last_name', :string
370
+
371
+ Person.reset_column_information
372
+ assert Person.column_methods_hash.include?(:last_name)
373
+
374
+ ActiveRecord::Migration.remove_column 'people', 'last_name'
375
+
376
+ Person.reset_column_information
377
+ assert !Person.column_methods_hash.include?(:last_name)
378
+ end
379
+
380
+ def test_add_remove_single_field_using_symbol_arguments
381
+ assert !Person.column_methods_hash.include?(:last_name)
382
+
383
+ ActiveRecord::Migration.add_column :people, :last_name, :string
384
+
385
+ Person.reset_column_information
386
+ assert Person.column_methods_hash.include?(:last_name)
387
+
388
+ ActiveRecord::Migration.remove_column :people, :last_name
389
+
390
+ Person.reset_column_information
391
+ assert !Person.column_methods_hash.include?(:last_name)
392
+ end
393
+
394
+ # Ingres, Virtuoso:
395
+ # Neither supports renaming of columns. Skip test.
396
+ unless current_adapter?(:ODBCAdapter) &&
397
+ [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
398
+ def test_add_rename
399
+ Person.delete_all
400
+
401
+ begin
402
+ Person.connection.add_column "people", "girlfriend", :string
403
+ Person.reset_column_information
404
+ Person.create :girlfriend => 'bobette'
405
+
406
+ Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
407
+
408
+ Person.reset_column_information
409
+ bob = Person.find(:first)
410
+
411
+ assert_equal "bobette", bob.exgirlfriend
412
+ ensure
413
+ Person.connection.remove_column("people", "girlfriend") rescue nil
414
+ Person.connection.remove_column("people", "exgirlfriend") rescue nil
415
+ end
416
+ end
417
+ end
418
+
419
+ # Ingres and Virtuoso don't support renaming of columns. Skip test.
420
+ unless current_adapter?(:ODBCAdapter) && [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
421
+ def test_rename_column_using_symbol_arguments
422
+ begin
423
+ names_before = Person.find(:all).map(&:first_name)
424
+ Person.connection.rename_column :people, :first_name, :nick_name
425
+ Person.reset_column_information
426
+ assert Person.column_names.include?("nick_name")
427
+ assert_equal names_before, Person.find(:all).map(&:nick_name)
428
+ ensure
429
+ Person.connection.remove_column("people","nick_name")
430
+ Person.connection.add_column("people","first_name", :string)
431
+ end
432
+ end
433
+ end
434
+
435
+ unless current_adapter?(:ODBCAdapter) && [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
436
+ def test_rename_column
437
+ begin
438
+ names_before = Person.find(:all).map(&:first_name)
439
+ Person.connection.rename_column "people", "first_name", "nick_name"
440
+ Person.reset_column_information
441
+ assert Person.column_names.include?("nick_name")
442
+ assert_equal names_before, Person.find(:all).map(&:nick_name)
443
+ ensure
444
+ Person.connection.remove_column("people","nick_name")
445
+ Person.connection.add_column("people","first_name", :string)
446
+ end
447
+ end
448
+ end
449
+
450
+ def test_rename_column_with_sql_reserved_word
451
+ begin
452
+ assert_nothing_raised { Person.connection.rename_column "people", "first_name", "group" }
453
+ Person.reset_column_information
454
+ assert Person.column_names.include?("group")
455
+ ensure
456
+ Person.connection.remove_column("people", "group") rescue nil
457
+ Person.connection.add_column("people", "first_name", :string) rescue nil
458
+ end
459
+ end
460
+
461
+ def test_change_type_of_not_null_column
462
+ assert_nothing_raised do
463
+ Topic.connection.change_column "topics", "written_on", :datetime, :null => false
464
+ Topic.reset_column_information
465
+
466
+ Topic.connection.change_column "topics", "written_on", :datetime, :null => false
467
+ Topic.reset_column_information
468
+ end
469
+ end
470
+
471
+ # Ingres doesn't support renaming of tables. Skip test.
472
+ unless current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
473
+ def test_rename_table
474
+ begin
475
+ ActiveRecord::Base.connection.create_table :octopuses do |t|
476
+ t.column :url, :string
477
+ end
478
+ ActiveRecord::Base.connection.rename_table :octopuses, :octopi
479
+
480
+ # Using explicit id in insert for compatibility across all databases
481
+ con = ActiveRecord::Base.connection
482
+ con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
483
+ 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')" }
484
+ con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
485
+
486
+ assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
487
+
488
+ ensure
489
+ ActiveRecord::Base.connection.drop_table :octopuses rescue nil
490
+ ActiveRecord::Base.connection.drop_table :octopi rescue nil
491
+ end
492
+ end
493
+ end
494
+
495
+ def test_change_column_nullability
496
+ Person.delete_all
497
+ Person.connection.add_column "people", "funny", :boolean
498
+ Person.reset_column_information
499
+ assert Person.columns_hash["funny"].null, "Column 'funny' must initially allow nulls"
500
+ Person.connection.change_column "people", "funny", :boolean, :null => false, :default => true
501
+ Person.reset_column_information
502
+ assert !Person.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point"
503
+ Person.connection.change_column "people", "funny", :boolean, :null => true
504
+ Person.reset_column_information
505
+ assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
506
+ end
507
+
508
+ # Ingres doesn't support renaming of tables. Skip test.
509
+ unless current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
510
+ def test_rename_table_with_an_index
511
+ begin
512
+ ActiveRecord::Base.connection.create_table :octopuses do |t|
513
+ t.column :url, :string
514
+ end
515
+ ActiveRecord::Base.connection.add_index :octopuses, :url
516
+
517
+ ActiveRecord::Base.connection.rename_table :octopuses, :octopi
518
+
519
+ # Using explicit id in insert for compatibility across all databases
520
+ con = ActiveRecord::Base.connection
521
+ con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
522
+ 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')" }
523
+ con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
524
+
525
+ assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
526
+ assert ActiveRecord::Base.connection.indexes(:octopi).first.columns.include?("url")
527
+ ensure
528
+ ActiveRecord::Base.connection.drop_table :octopuses rescue nil
529
+ ActiveRecord::Base.connection.drop_table :octopi rescue nil
530
+ end
531
+ end
532
+ end
533
+
534
+ # Virtuoso disallows virtually all column type conversions.
535
+ # Conversion between any of the native types used by the ActiveRecord generic types is not allowed.
536
+ # Skip the test.
537
+ unless current_adapter?(:ODBCAdapter) && [:virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
538
+ def test_change_column
539
+ #Ingres doesn't support changing an integer column to varchar/text.
540
+ if current_adapter?(:ODBCAdapter) && [:ingres].include?(ActiveRecord::Base.connection.dbmsName)
541
+ initial_type = :integer
542
+ new_type = :float
543
+ else
544
+ initial_type = :integer
545
+ new_type = :string
546
+ end
547
+
548
+ Person.connection.add_column 'people', 'age', initial_type
549
+ old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
550
+ assert old_columns.find { |c| c.name == 'age' and c.type == initial_type }
551
+
552
+ assert_nothing_raised { Person.connection.change_column "people", "age", new_type }
553
+
554
+ new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
555
+ assert_nil new_columns.find { |c| c.name == 'age' and c.type == initial_type }
556
+ assert new_columns.find { |c| c.name == 'age' and c.type == new_type }
557
+
558
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
559
+ unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
560
+ old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
561
+ assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
562
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
563
+ new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
564
+ assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
565
+ assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
566
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
567
+ end
568
+ end
569
+ end
570
+
571
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
572
+ unless current_adapter?(:ODBCAdapter) && [:ingres, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
573
+ def test_change_column_with_nil_default
574
+ Person.connection.add_column "people", "contributor", :boolean, :default => true
575
+ Person.reset_column_information
576
+ assert Person.new.contributor?
577
+
578
+ assert_nothing_raised { Person.connection.change_column "people", "contributor", :boolean, :default => nil }
579
+ Person.reset_column_information
580
+ assert !Person.new.contributor?
581
+ assert_nil Person.new.contributor
582
+ ensure
583
+ Person.connection.remove_column("people", "contributor") rescue nil
584
+ end
585
+ end
586
+
587
+ # Ingres doesn't support ALTER TABLE ADD COLUMN WITH NULL WITH DEFAULT.
588
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
589
+ unless current_adapter?(:ODBCAdapter) && [:ingres, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
590
+ def test_change_column_with_new_default
591
+ Person.connection.add_column "people", "administrator", :boolean, :default => true
592
+ Person.reset_column_information
593
+ assert Person.new.administrator?
594
+
595
+ assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
596
+ Person.reset_column_information
597
+ assert !Person.new.administrator?
598
+ ensure
599
+ Person.connection.remove_column("people", "administrator") rescue nil
600
+ end
601
+ end
602
+
603
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
604
+ unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
605
+ def test_change_column_default
606
+ Person.connection.change_column_default "people", "first_name", "Tester"
607
+ Person.reset_column_information
608
+ assert_equal "Tester", Person.new.first_name
609
+ end
610
+ end
611
+
612
+ def test_change_column_quotes_column_names
613
+ Person.connection.create_table :testings do |t|
614
+ t.column :select, :string
615
+ end
616
+
617
+ assert_nothing_raised { Person.connection.change_column :testings, :select, :string, :limit => 10 }
618
+
619
+ assert_nothing_raised { Person.connection.execute "insert into testings (#{Person.connection.quote_column_name('select')}) values ('7 chars')" }
620
+ ensure
621
+ Person.connection.drop_table :testings rescue nil
622
+ end
623
+
624
+ # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
625
+ unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
626
+ def test_change_column_default_to_null
627
+ Person.connection.change_column_default "people", "first_name", nil
628
+ Person.reset_column_information
629
+ assert_nil Person.new.first_name
630
+ end
631
+ end
632
+
633
+ def test_add_table
634
+ assert !Reminder.table_exists?
635
+
636
+ WeNeedReminders.up
637
+
638
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
639
+ assert_equal "hello world", Reminder.find(:first).content
640
+
641
+ WeNeedReminders.down
642
+ assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
643
+ end
644
+
645
+ def test_add_table_with_decimals
646
+ Person.connection.drop_table :big_numbers rescue nil
647
+
648
+ assert !BigNumber.table_exists?
649
+ GiveMeBigNumbers.up
650
+
651
+ assert BigNumber.create(
652
+ :bank_balance => 1586.43,
653
+ :big_bank_balance => BigDecimal("1000234000567.95"),
654
+ :world_population => 6000000000,
655
+ :my_house_population => 3,
656
+ :value_of_e => BigDecimal("2.7182818284590452353602875")
657
+ )
658
+
659
+ b = BigNumber.find(:first)
660
+ assert_not_nil b
661
+
662
+ assert_not_nil b.bank_balance
663
+ assert_not_nil b.big_bank_balance
664
+ assert_not_nil b.world_population
665
+ assert_not_nil b.my_house_population
666
+ assert_not_nil b.value_of_e
667
+
668
+ # TODO: set world_population >= 2**62 to cover 64-bit platforms and test
669
+ # is_a?(Bignum)
670
+ assert_kind_of Integer, b.world_population
671
+ assert_equal 6000000000, b.world_population
672
+ assert_kind_of Fixnum, b.my_house_population
673
+ assert_equal 3, b.my_house_population
674
+ assert_kind_of BigDecimal, b.bank_balance
675
+ assert_equal BigDecimal("1586.43"), b.bank_balance
676
+ assert_kind_of BigDecimal, b.big_bank_balance
677
+ assert_equal BigDecimal("1000234000567.95"), b.big_bank_balance
678
+
679
+ # This one is fun. The 'value_of_e' field is defined as 'DECIMAL' with
680
+ # precision/scale explicitly left out. By the SQL standard, numbers
681
+ # assigned to this field should be truncated but that's seldom respected.
682
+ if current_adapter?(:PostgreSQLAdapter, :SQLite2Adapter)
683
+ # - PostgreSQL changes the SQL spec on columns declared simply as
684
+ # "decimal" to something more useful: instead of being given a scale
685
+ # of 0, they take on the compile-time limit for precision and scale,
686
+ # so the following should succeed unless you have used really wacky
687
+ # compilation options
688
+ # - SQLite2 has the default behavior of preserving all data sent in,
689
+ # so this happens there too
690
+ assert_kind_of BigDecimal, b.value_of_e
691
+ assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
692
+ elsif current_adapter?(:SQLiteAdapter)
693
+ # - SQLite3 stores a float, in violation of SQL
694
+ assert_kind_of BigDecimal, b.value_of_e
695
+ assert_equal BigDecimal("2.71828182845905"), b.value_of_e
696
+ elsif current_adapter?(:SQLServer)
697
+ # - SQL Server rounds instead of truncating
698
+ assert_kind_of Fixnum, b.value_of_e
699
+ assert_equal 3, b.value_of_e
700
+ else
701
+ # - SQL standard is an integer
702
+ assert_kind_of Fixnum, b.value_of_e
703
+ assert_equal 2, b.value_of_e
704
+ end
705
+
706
+ GiveMeBigNumbers.down
707
+ assert_raises(ActiveRecord::StatementInvalid) { BigNumber.find(:first) }
708
+ end
709
+
710
+ def test_migrator
711
+ assert !Person.column_methods_hash.include?(:last_name)
712
+ assert !Reminder.table_exists?
713
+
714
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')
715
+
716
+ assert_equal 3, ActiveRecord::Migrator.current_version
717
+ Person.reset_column_information
718
+ assert Person.column_methods_hash.include?(:last_name)
719
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
720
+ assert_equal "hello world", Reminder.find(:first).content
721
+
722
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/')
723
+
724
+ assert_equal 0, ActiveRecord::Migrator.current_version
725
+ Person.reset_column_information
726
+ assert !Person.column_methods_hash.include?(:last_name)
727
+ assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
728
+ end
729
+
730
+ def test_migrator_one_up
731
+ assert !Person.column_methods_hash.include?(:last_name)
732
+ assert !Reminder.table_exists?
733
+
734
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
735
+
736
+ Person.reset_column_information
737
+ assert Person.column_methods_hash.include?(:last_name)
738
+ assert !Reminder.table_exists?
739
+
740
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 2)
741
+
742
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
743
+ assert_equal "hello world", Reminder.find(:first).content
744
+ end
745
+
746
+ def test_migrator_one_down
747
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')
748
+
749
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
750
+
751
+ Person.reset_column_information
752
+ assert Person.column_methods_hash.include?(:last_name)
753
+ assert !Reminder.table_exists?
754
+ end
755
+
756
+ def test_migrator_one_up_one_down
757
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
758
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
759
+
760
+ assert !Person.column_methods_hash.include?(:last_name)
761
+ assert !Reminder.table_exists?
762
+ end
763
+
764
+ def test_migrator_verbosity
765
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
766
+ assert PeopleHaveLastNames.message_count > 0
767
+ PeopleHaveLastNames.message_count = 0
768
+
769
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
770
+ assert PeopleHaveLastNames.message_count > 0
771
+ PeopleHaveLastNames.message_count = 0
772
+ end
773
+
774
+ def test_migrator_verbosity_off
775
+ PeopleHaveLastNames.verbose = false
776
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
777
+ assert PeopleHaveLastNames.message_count.zero?
778
+ ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
779
+ assert PeopleHaveLastNames.message_count.zero?
780
+ end
781
+
782
+ def test_migrator_going_down_due_to_version_target
783
+ ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/', 1)
784
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations/', 0)
785
+
786
+ assert !Person.column_methods_hash.include?(:last_name)
787
+ assert !Reminder.table_exists?
788
+
789
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations/')
790
+
791
+ Person.reset_column_information
792
+ assert Person.column_methods_hash.include?(:last_name)
793
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
794
+ assert_equal "hello world", Reminder.find(:first).content
795
+ end
796
+
797
+ def test_schema_info_table_name
798
+ ActiveRecord::Base.table_name_prefix = "prefix_"
799
+ ActiveRecord::Base.table_name_suffix = "_suffix"
800
+ Reminder.reset_table_name
801
+ assert_equal "prefix_schema_info_suffix", ActiveRecord::Migrator.schema_info_table_name
802
+ ActiveRecord::Base.table_name_prefix = ""
803
+ ActiveRecord::Base.table_name_suffix = ""
804
+ Reminder.reset_table_name
805
+ assert_equal "schema_info", ActiveRecord::Migrator.schema_info_table_name
806
+ ensure
807
+ ActiveRecord::Base.table_name_prefix = ""
808
+ ActiveRecord::Base.table_name_suffix = ""
809
+ end
810
+
811
+ def test_proper_table_name
812
+ assert_equal "table", ActiveRecord::Migrator.proper_table_name('table')
813
+ assert_equal "table", ActiveRecord::Migrator.proper_table_name(:table)
814
+ assert_equal "reminders", ActiveRecord::Migrator.proper_table_name(Reminder)
815
+ Reminder.reset_table_name
816
+ assert_equal Reminder.table_name, ActiveRecord::Migrator.proper_table_name(Reminder)
817
+
818
+ # Use the model's own prefix/suffix if a model is given
819
+ ActiveRecord::Base.table_name_prefix = "ARprefix_"
820
+ ActiveRecord::Base.table_name_suffix = "_ARsuffix"
821
+ Reminder.table_name_prefix = 'prefix_'
822
+ Reminder.table_name_suffix = '_suffix'
823
+ Reminder.reset_table_name
824
+ assert_equal "prefix_reminders_suffix", ActiveRecord::Migrator.proper_table_name(Reminder)
825
+ Reminder.table_name_prefix = ''
826
+ Reminder.table_name_suffix = ''
827
+ Reminder.reset_table_name
828
+
829
+ # Use AR::Base's prefix/suffix if string or symbol is given
830
+ ActiveRecord::Base.table_name_prefix = "prefix_"
831
+ ActiveRecord::Base.table_name_suffix = "_suffix"
832
+ Reminder.reset_table_name
833
+ assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name('table')
834
+ assert_equal "prefix_table_suffix", ActiveRecord::Migrator.proper_table_name(:table)
835
+ ActiveRecord::Base.table_name_prefix = ""
836
+ ActiveRecord::Base.table_name_suffix = ""
837
+ Reminder.reset_table_name
838
+ end
839
+
840
+ def test_add_drop_table_with_prefix_and_suffix
841
+ assert !Reminder.table_exists?
842
+ ActiveRecord::Base.table_name_prefix = 'prefix_'
843
+ ActiveRecord::Base.table_name_suffix = '_suffix'
844
+ Reminder.reset_table_name
845
+ Reminder.reset_sequence_name
846
+ WeNeedReminders.up
847
+ assert Reminder.create("content" => "hello world", "remind_at" => Time.now)
848
+ assert_equal "hello world", Reminder.find(:first).content
849
+
850
+ WeNeedReminders.down
851
+ assert_raises(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
852
+ ensure
853
+ ActiveRecord::Base.table_name_prefix = ''
854
+ ActiveRecord::Base.table_name_suffix = ''
855
+ Reminder.reset_table_name
856
+ Reminder.reset_sequence_name
857
+ end
858
+
859
+ def test_create_table_with_binary_column
860
+ Person.connection.drop_table :binary_testings rescue nil
861
+
862
+ assert_nothing_raised {
863
+ if current_adapter?(:ODBCAdapter) && [:informix, :ingres].include?(ActiveRecord::Base.connection.dbmsName)
864
+ # Specifying a non-null default generates the following error:
865
+ # Informix:
866
+ # "Cannot specify non-null default value for blob column. (-594)"
867
+ # Ingres:
868
+ # "Cannot create a default on column of type 'long byte'"
869
+ Person.connection.create_table :binary_testings do |t|
870
+ t.column "data", :binary
871
+ end
872
+ else
873
+ Person.connection.create_table :binary_testings do |t|
874
+ t.column "data", :binary, :null => false
875
+ end
876
+ end
877
+ }
878
+
879
+ columns = Person.connection.columns(:binary_testings)
880
+ data_column = columns.detect { |c| c.name == "data" }
881
+
882
+ if current_adapter?(:MysqlAdapter)
883
+ assert_equal '', data_column.default
884
+ else
885
+ assert_nil data_column.default
886
+ end
887
+
888
+ Person.connection.drop_table :binary_testings rescue nil
889
+ end
890
+
891
+ def test_migrator_with_duplicates
892
+ assert_raises(ActiveRecord::DuplicateMigrationVersionError) do
893
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_duplicate/', nil)
894
+ end
895
+ end
896
+
897
+ def test_migrator_with_missing_version_numbers
898
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_missing_versions/', 500)
899
+ assert !Person.column_methods_hash.include?(:middle_name)
900
+ assert_equal 4, ActiveRecord::Migrator.current_version
901
+
902
+ ActiveRecord::Migrator.migrate(File.dirname(__FILE__) + '/fixtures/migrations_with_missing_versions/', 2)
903
+ Person.reset_column_information
904
+ assert !Reminder.table_exists?
905
+ assert Person.column_methods_hash.include?(:last_name)
906
+ assert_equal 2, ActiveRecord::Migrator.current_version
907
+ end
908
+
909
+ def test_create_table_with_custom_sequence_name
910
+ return unless current_adapter? :OracleAdapter
911
+
912
+ # table name is 29 chars, the standard sequence name will
913
+ # be 33 chars and fail
914
+ assert_raises(ActiveRecord::StatementInvalid) do
915
+ begin
916
+ Person.connection.create_table :table_with_name_thats_just_ok do |t|
917
+ t.column :foo, :string, :null => false
918
+ end
919
+ ensure
920
+ Person.connection.drop_table :table_with_name_thats_just_ok rescue nil
921
+ end
922
+ end
923
+
924
+ # should be all good w/ a custom sequence name
925
+ assert_nothing_raised do
926
+ begin
927
+ Person.connection.create_table :table_with_name_thats_just_ok,
928
+ :sequence_name => 'suitably_short_seq' do |t|
929
+ t.column :foo, :string, :null => false
930
+ end
931
+
932
+ Person.connection.execute("select suitably_short_seq.nextval from dual")
933
+
934
+ ensure
935
+ Person.connection.drop_table :table_with_name_thats_just_ok,
936
+ :sequence_name => 'suitably_short_seq' rescue nil
937
+ end
938
+ end
939
+
940
+ # confirm the custom sequence got dropped
941
+ assert_raises(ActiveRecord::StatementInvalid) do
942
+ Person.connection.execute("select suitably_short_seq.nextval from dual")
943
+ end
944
+ end
945
+ end
946
+
947
+ uses_mocha 'Sexy migration tests' do
948
+ class SexyMigrationsTest < Test::Unit::TestCase
949
+ def test_references_column_type_adds_id
950
+ with_new_table do |t|
951
+ t.expects(:column).with('customer_id', :integer, {})
952
+ t.references :customer
953
+ end
954
+ end
955
+
956
+ def test_references_column_type_with_polymorphic_adds_type
957
+ with_new_table do |t|
958
+ t.expects(:column).with('taggable_type', :string, {})
959
+ t.expects(:column).with('taggable_id', :integer, {})
960
+ t.references :taggable, :polymorphic => true
961
+ end
962
+ end
963
+
964
+ def test_belongs_to_works_like_references
965
+ with_new_table do |t|
966
+ t.expects(:column).with('customer_id', :integer, {})
967
+ t.belongs_to :customer
968
+ end
969
+ end
970
+
971
+ def test_timestamps_creates_updated_at_and_created_at
972
+ with_new_table do |t|
973
+ t.expects(:column).with(:created_at, :datetime)
974
+ t.expects(:column).with(:updated_at, :datetime)
975
+ t.timestamps
976
+ end
977
+ end
978
+
979
+ def test_integer_creates_integer_column
980
+ with_new_table do |t|
981
+ t.expects(:column).with(:foo, 'integer', {})
982
+ t.expects(:column).with(:bar, 'integer', {})
983
+ t.integer :foo, :bar
984
+ end
985
+ end
986
+
987
+ def test_string_creates_string_column
988
+ with_new_table do |t|
989
+ t.expects(:column).with(:foo, 'string', {})
990
+ t.expects(:column).with(:bar, 'string', {})
991
+ t.string :foo, :bar
992
+ end
993
+ end
994
+
995
+ protected
996
+ def with_new_table
997
+ Person.connection.create_table :delete_me do |t|
998
+ yield t
999
+ end
1000
+ ensure
1001
+ Person.connection.drop_table :delete_me rescue nil
1002
+ end
1003
+
1004
+ end # SexyMigrationsTest
1005
+ end # uses_mocha
1006
+ end
1007
+