activerecord-odbc-adapter 2.0

Sign up to get free protection for your applications and to get access to all the features.
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,28 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # $Id: odbc_adapter.rb,v 1.1 2006/12/06 16:16:08 source Exp $
4
+ #
5
+ # OpenLink ODBC Adapter for Ruby on Rails
6
+ # Copyright (C) 2006 OpenLink Software
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to
13
+ # permit persons to whom the Software is furnished to do so, subject
14
+ # to the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be
17
+ # included in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
23
+ # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
24
+ # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #
27
+
28
+ require 'active_record/connection_adapters/odbc_adapter'
@@ -0,0 +1,259 @@
1
+ require 'parsedate'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters #:nodoc:
5
+ # An abstract definition of a column in a table.
6
+ class Column
7
+ attr_reader :name, :default, :type, :limit, :null, :sql_type
8
+ attr_accessor :primary
9
+
10
+ # Instantiates a new column in the table.
11
+ #
12
+ # +name+ is the column's name, as in <tt><b>supplier_id</b> int(11)</tt>.
13
+ # +default+ is the type-casted default value, such as <tt>sales_stage varchar(20) default <b>'new'</b></tt>.
14
+ # +sql_type+ is only used to extract the column's length, if necessary. For example, <tt>company_name varchar(<b>60</b>)</tt>.
15
+ # +null+ determines if this column allows +NULL+ values.
16
+ def initialize(name, default, sql_type = nil, null = true)
17
+ @name, @type, @null = name, simplified_type(sql_type), null
18
+ @sql_type = sql_type
19
+ # have to do this one separately because type_cast depends on #type
20
+ @default = type_cast(default)
21
+ @limit = extract_limit(sql_type) unless sql_type.nil?
22
+ @primary = nil
23
+ @text = [:string, :text].include? @type
24
+ @number = [:float, :integer].include? @type
25
+ end
26
+
27
+ def text?
28
+ @text
29
+ end
30
+
31
+ def number?
32
+ @number
33
+ end
34
+
35
+ # Returns the Ruby class that corresponds to the abstract data type.
36
+ def klass
37
+ case type
38
+ when :integer then Fixnum
39
+ when :float then Float
40
+ when :datetime then Time
41
+ when :date then Date
42
+ when :timestamp then Time
43
+ when :time then Time
44
+ when :text, :string then String
45
+ when :binary then String
46
+ when :boolean then Object
47
+ end
48
+ end
49
+
50
+ # Casts value (which is a String) to an appropriate instance.
51
+ def type_cast(value)
52
+ return nil if value.nil?
53
+ case type
54
+ when :string then value
55
+ when :text then value
56
+ when :integer then value.to_i rescue value ? 1 : 0
57
+ when :float then value.to_f
58
+ when :datetime then self.class.string_to_time(value)
59
+ when :timestamp then self.class.string_to_time(value)
60
+ when :time then self.class.string_to_dummy_time(value)
61
+ when :date then self.class.string_to_date(value)
62
+ when :binary then self.class.binary_to_string(value)
63
+ when :boolean then self.class.value_to_boolean(value)
64
+ else value
65
+ end
66
+ end
67
+
68
+ def type_cast_code(var_name)
69
+ case type
70
+ when :string then nil
71
+ when :text then nil
72
+ when :integer then "(#{var_name}.to_i rescue #{var_name} ? 1 : 0)"
73
+ when :float then "#{var_name}.to_f"
74
+ when :datetime then "#{self.class.name}.string_to_time(#{var_name})"
75
+ when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
76
+ when :time then "#{self.class.name}.string_to_dummy_time(#{var_name})"
77
+ when :date then "#{self.class.name}.string_to_date(#{var_name})"
78
+ when :binary then "#{self.class.name}.binary_to_string(#{var_name})"
79
+ when :boolean then "#{self.class.name}.value_to_boolean(#{var_name})"
80
+ else nil
81
+ end
82
+ end
83
+
84
+ # Returns the human name of the column name.
85
+ #
86
+ # ===== Examples
87
+ # Column.new('sales_stage', ...).human_name #=> 'Sales stage'
88
+ def human_name
89
+ Base.human_attribute_name(@name)
90
+ end
91
+
92
+ # Used to convert from Strings to BLOBs
93
+ def self.string_to_binary(value)
94
+ value
95
+ end
96
+
97
+ # Used to convert from BLOBs to Strings
98
+ def self.binary_to_string(value)
99
+ value
100
+ end
101
+
102
+ def self.string_to_date(string)
103
+ return string unless string.is_a?(String)
104
+ date_array = ParseDate.parsedate(string)
105
+ # treat 0000-00-00 as nil
106
+ Date.new(date_array[0], date_array[1], date_array[2]) rescue nil
107
+ end
108
+
109
+ def self.string_to_time(string)
110
+ return string unless string.is_a?(String)
111
+ time_array = ParseDate.parsedate(string)[0..5]
112
+ # treat 0000-00-00 00:00:00 as nil
113
+ Time.send(Base.default_timezone, *time_array) rescue nil
114
+ end
115
+
116
+ def self.string_to_dummy_time(string)
117
+ return string unless string.is_a?(String)
118
+ time_array = ParseDate.parsedate(string)
119
+ # pad the resulting array with dummy date information
120
+ time_array[0] = 2000; time_array[1] = 1; time_array[2] = 1;
121
+ Time.send(Base.default_timezone, *time_array) rescue nil
122
+ end
123
+
124
+ # convert something to a boolean
125
+ def self.value_to_boolean(value)
126
+ return value if value==true || value==false
127
+ case value.to_s.downcase
128
+ when "true", "t", "1" then true
129
+ else false
130
+ end
131
+ end
132
+
133
+ private
134
+ def extract_limit(sql_type)
135
+ $1.to_i if sql_type =~ /\((.*)\)/
136
+ end
137
+
138
+ def simplified_type(field_type)
139
+ case field_type
140
+ when /int/i
141
+ :integer
142
+ when /float|double|decimal|numeric/i
143
+ :float
144
+ when /datetime/i
145
+ :datetime
146
+ when /timestamp/i
147
+ :timestamp
148
+ when /time/i
149
+ :time
150
+ when /date/i
151
+ :date
152
+ when /clob/i, /text/i
153
+ :text
154
+ when /blob/i, /binary/i
155
+ :binary
156
+ when /char/i, /string/i
157
+ :string
158
+ when /boolean/i
159
+ :boolean
160
+ end
161
+ end
162
+ end
163
+
164
+ class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc:
165
+ end
166
+
167
+ class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :default, :null) #:nodoc:
168
+ def to_sql
169
+ column_sql = "#{base.quote_column_name(name)} #{type_to_sql(type.to_sym, limit)}"
170
+ add_column_options!(column_sql, :null => null, :default => default)
171
+ column_sql
172
+ end
173
+ alias to_s :to_sql
174
+
175
+ private
176
+ def type_to_sql(name, limit)
177
+ base.type_to_sql(name, limit) rescue name
178
+ end
179
+
180
+ def add_column_options!(sql, options)
181
+ base.add_column_options!(sql, options.merge(:column => self))
182
+ end
183
+ end
184
+
185
+ # Represents a SQL table in an abstract way.
186
+ # Columns are stored as ColumnDefinition in the #columns attribute.
187
+ class TableDefinition
188
+ attr_accessor :columns
189
+
190
+ def initialize(base)
191
+ @columns = []
192
+ @base = base
193
+ end
194
+
195
+ # Appends a primary key definition to the table definition.
196
+ # Can be called multiple times, but this is probably not a good idea.
197
+ def primary_key(name)
198
+ column(name, :primary_key)
199
+ end
200
+
201
+ # Returns a ColumnDefinition for the column with name +name+.
202
+ def [](name)
203
+ @columns.find {|column| column.name.to_s == name.to_s}
204
+ end
205
+
206
+ # Instantiates a new column for the table.
207
+ # The +type+ parameter must be one of the following values:
208
+ # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
209
+ # <tt>:integer</tt>, <tt>:float</tt>, <tt>:datetime</tt>,
210
+ # <tt>:timestamp</tt>, <tt>:time</tt>, <tt>:date</tt>,
211
+ # <tt>:binary</tt>, <tt>:boolean</tt>.
212
+ #
213
+ # Available options are (none of these exists by default):
214
+ # * <tt>:limit</tt>:
215
+ # Requests a maximum column length (<tt>:string</tt>, <tt>:text</tt>,
216
+ # <tt>:binary</tt> or <tt>:integer</tt> columns only)
217
+ # * <tt>:default</tt>:
218
+ # The column's default value. You cannot explicitely set the default
219
+ # value to +NULL+. Simply leave off this option if you want a +NULL+
220
+ # default value.
221
+ # * <tt>:null</tt>:
222
+ # Allows or disallows +NULL+ values in the column. This option could
223
+ # have been named <tt>:null_allowed</tt>.
224
+ #
225
+ # This method returns <tt>self</tt>.
226
+ #
227
+ # ===== Examples
228
+ # # Assuming def is an instance of TableDefinition
229
+ # def.column(:granted, :boolean)
230
+ # #=> granted BOOLEAN
231
+ #
232
+ # def.column(:picture, :binary, :limit => 2.megabytes)
233
+ # #=> picture BLOB(2097152)
234
+ #
235
+ # def.column(:sales_stage, :string, :limit => 20, :default => 'new', :null => false)
236
+ # #=> sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
237
+ def column(name, type, options = {})
238
+ column = self[name] || ColumnDefinition.new(@base, name, type)
239
+ column.limit = options[:limit] || native[type.to_sym][:limit] if options[:limit] or native[type.to_sym]
240
+ column.default = options[:default]
241
+ column.null = options[:null]
242
+ @columns << column unless @columns.include? column
243
+ self
244
+ end
245
+
246
+ # Returns a String whose contents are the column definitions
247
+ # concatenated together. This string can then be pre and appended to
248
+ # to generate the final SQL to create the table.
249
+ def to_sql
250
+ @columns * ', '
251
+ end
252
+
253
+ private
254
+ def native
255
+ @base.native_database_types
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,367 @@
1
+ Index: base_test.rb
2
+ ===================================================================
3
+ --- base_test.rb (revision 1)
4
+ +++ base_test.rb (working copy)
5
+ @@ -389,6 +389,8 @@
6
+ if current_adapter?(:SybaseAdapter, :OracleAdapter)
7
+ # Sybase ctlib does not (yet?) support the date type; use datetime instead.
8
+ # Oracle treats all dates/times as Time.
9
+ + elsif current_adapter?(:ODBCAdapter) && [:ingres, :microsoftsqlserver, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
10
+ + # Above databases don't have a pure date type. (They have a datetime-like type).
11
+ assert_kind_of(
12
+ Time, Topic.find(1).last_read,
13
+ "The last_read attribute should be of the Time class"
14
+ @@ -704,7 +706,12 @@
15
+
16
+ def test_default_values_on_empty_strings
17
+ topic = Topic.new
18
+ - topic.approved = nil
19
+ + #Sybase does not allow nulls in boolean columns
20
+ + if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :sybase
21
+ + topic.approved = false
22
+ + else
23
+ + topic.approved = nil
24
+ + end
25
+ topic.last_read = nil
26
+
27
+ topic.save
28
+ @@ -713,7 +720,8 @@
29
+ assert_nil topic.last_read
30
+
31
+ # Sybase adapter does not allow nulls in boolean columns
32
+ - if current_adapter?(:SybaseAdapter)
33
+ + if current_adapter?(:SybaseAdapter) ||
34
+ + current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :sybase
35
+ assert topic.approved == false
36
+ else
37
+ assert_nil topic.approved
38
+ @@ -941,6 +949,10 @@
39
+ def test_attributes_on_dummy_time
40
+ # Oracle, SQL Server, and Sybase do not have a TIME datatype.
41
+ return true if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
42
+ + if current_adapter?(:ODBCAdapter)
43
+ + # Check for databases which don't have a true TIME datatype
44
+ + return true if [:ingres, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
45
+ + end
46
+
47
+ attributes = {
48
+ "bonus_time" => "5:42:00AM"
49
+ @@ -1185,8 +1197,11 @@
50
+ replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
51
+ assert_equal topics(:first).replies.size, replies.size
52
+
53
+ - replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
54
+ - assert_equal 0, replies.size
55
+ + # DB2 doesn't support "WHERE (id IN (NULL))" clause
56
+ + unless current_adapter?(:ODBCAdapter) && [:db2].include?(ActiveRecord::Base.connection.dbmsName)
57
+ + replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
58
+ + assert_equal 0, replies.size
59
+ + end
60
+ end
61
+
62
+ MyObject = Struct.new :attribute1, :attribute2
63
+ @@ -1225,7 +1240,12 @@
64
+ end
65
+
66
+ def test_quote
67
+ - author_name = "\\ \001 ' \n \\n \""
68
+ + if current_adapter?(:ODBCAdapter) && [:informix, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
69
+ + #Some databases only allow printable characters in VARCHAR columns.
70
+ + author_name = "\\ \041 ' \n \\n \""
71
+ + else
72
+ + author_name = "\\ \001 ' \n \\n \""
73
+ + end
74
+ topic = Topic.create('author_name' => author_name)
75
+ assert_equal author_name, Topic.find(topic.id).author_name
76
+ end
77
+ Index: migration_test.rb
78
+ ===================================================================
79
+ --- migration_test.rb (revision 1)
80
+ +++ migration_test.rb (working copy)
81
+ @@ -52,8 +52,15 @@
82
+ end
83
+
84
+ def test_add_index
85
+ - # Limit size of last_name and key columns to support Firebird index limitations
86
+ - Person.connection.add_column "people", "last_name", :string, :limit => 100
87
+ + if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :informix
88
+ + # Index on (last_name, first_name) exceeds max. index width supported by Informix if
89
+ + # both columns are created with a default width of 255, in which case
90
+ + # Informix may return error -517: "The total size of the index is too large..."
91
+ + Person.connection.add_column "people", "last_name", :string, {:limit => 40}
92
+ + else
93
+ + # Limit size of last_name and key columns to support Firebird index limitations
94
+ + Person.connection.add_column "people", "last_name", :string, :limit => 100
95
+ + end
96
+ Person.connection.add_column "people", "key", :string, :limit => 100
97
+ Person.connection.add_column "people", "administrator", :boolean
98
+
99
+ @@ -62,7 +69,8 @@
100
+
101
+ # Orcl nds shrt indx nms. Sybs 2.
102
+ # OpenBase does not have named indexes. You must specify a single column name
103
+ - unless current_adapter?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter)
104
+ + unless current_adapter?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter) ||
105
+ + current_adapter?(:ODBCAdapter) && [:sybase, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
106
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
107
+ assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
108
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
109
+ @@ -83,7 +91,8 @@
110
+
111
+ # Sybase adapter does not support indexes on :boolean columns
112
+ # OpenBase does not have named indexes. You must specify a single column
113
+ - unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter)
114
+ + unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter) ||
115
+ + current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :sybase
116
+ assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
117
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
118
+ end
119
+ @@ -182,7 +191,8 @@
120
+
121
+ # SQL Server, Sybase, and SQLite3 will not allow you to add a NOT NULL
122
+ # column to a table without a default value.
123
+ - unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter)
124
+ + unless current_adapter?(:SQLServerAdapter, :SybaseAdapter, :SQLiteAdapter) ||
125
+ + current_adapter?(:ODBCAdapter) && [:microsoftsqlserver, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
126
+ def test_add_column_not_null_without_default
127
+ Person.connection.create_table :testings do |t|
128
+ t.column :foo, :string
129
+ @@ -206,7 +216,13 @@
130
+ Person.connection.enable_identity_insert("testings", true) if current_adapter?(:SybaseAdapter)
131
+ Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')"
132
+ Person.connection.enable_identity_insert("testings", false) if current_adapter?(:SybaseAdapter)
133
+ - assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
134
+ + if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
135
+ + # Ingres requires that if 'ALTER TABLE table ADD column' specifies a NOT NULL constraint,
136
+ + # then 'WITH DEFAULT' must also be specified *without* a default value.
137
+ + assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false}
138
+ + else
139
+ + assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
140
+ + end
141
+
142
+ assert_raises(ActiveRecord::StatementInvalid) do
143
+ unless current_adapter?(:OpenBaseAdapter)
144
+ @@ -310,8 +326,10 @@
145
+ assert_equal Fixnum, bob.age.class
146
+ assert_equal Time, bob.birthday.class
147
+
148
+ - if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
149
+ - # Sybase, and Oracle don't differentiate between date/time
150
+ + if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter) ||
151
+ + (current_adapter?(:ODBCAdapter) &&
152
+ + [:ingres, :oracle, :microsoftsqlserver].include?(ActiveRecord::Base.connection.dbmsName))
153
+ + # SQL Server, Sybase, Oracle and Ingres don't differentiate between date/time
154
+ assert_equal Time, bob.favorite_day.class
155
+ else
156
+ assert_equal Date, bob.favorite_day.class
157
+ @@ -373,27 +391,33 @@
158
+ assert !Person.column_methods_hash.include?(:last_name)
159
+ end
160
+
161
+ - def test_add_rename
162
+ - Person.delete_all
163
+ + # Ingres, Virtuoso:
164
+ + # Neither supports renaming of columns. Skip test.
165
+ + unless current_adapter?(:ODBCAdapter) &&
166
+ + [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
167
+ + def test_add_rename
168
+ + Person.delete_all
169
+
170
+ - begin
171
+ - Person.connection.add_column "people", "girlfriend", :string
172
+ - Person.reset_column_information
173
+ - Person.create :girlfriend => 'bobette'
174
+ + begin
175
+ + Person.connection.add_column "people", "girlfriend", :string
176
+ + Person.reset_column_information
177
+ + Person.create :girlfriend => 'bobette'
178
+
179
+ - Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
180
+ + Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
181
+
182
+ - Person.reset_column_information
183
+ - bob = Person.find(:first)
184
+ + Person.reset_column_information
185
+ + bob = Person.find(:first)
186
+
187
+ - assert_equal "bobette", bob.exgirlfriend
188
+ - ensure
189
+ - Person.connection.remove_column("people", "girlfriend") rescue nil
190
+ - Person.connection.remove_column("people", "exgirlfriend") rescue nil
191
+ + assert_equal "bobette", bob.exgirlfriend
192
+ + ensure
193
+ + Person.connection.remove_column("people", "girlfriend") rescue nil
194
+ + Person.connection.remove_column("people", "exgirlfriend") rescue nil
195
+ + end
196
+ end
197
+ -
198
+ end
199
+
200
+ + # Ingres and Virtuoso don't support renaming of columns. Skip test.
201
+ + unless current_adapter?(:ODBCAdapter) && [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
202
+ def test_rename_column_using_symbol_arguments
203
+ begin
204
+ names_before = Person.find(:all).map(&:first_name)
205
+ @@ -406,7 +430,9 @@
206
+ Person.connection.add_column("people","first_name", :string)
207
+ end
208
+ end
209
+ + end
210
+
211
+ + unless current_adapter?(:ODBCAdapter) && [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
212
+ def test_rename_column
213
+ begin
214
+ names_before = Person.find(:all).map(&:first_name)
215
+ @@ -419,6 +445,7 @@
216
+ Person.connection.add_column("people","first_name", :string)
217
+ end
218
+ end
219
+ + end
220
+
221
+ def test_rename_column_with_sql_reserved_word
222
+ begin
223
+ @@ -441,6 +468,8 @@
224
+ end
225
+ end
226
+
227
+ + # Ingres doesn't support renaming of tables. Skip test.
228
+ + unless current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
229
+ def test_rename_table
230
+ begin
231
+ ActiveRecord::Base.connection.create_table :octopuses do |t|
232
+ @@ -461,6 +490,7 @@
233
+ ActiveRecord::Base.connection.drop_table :octopi rescue nil
234
+ end
235
+ end
236
+ + end
237
+
238
+ def test_change_column_nullability
239
+ Person.delete_all
240
+ @@ -475,6 +505,8 @@
241
+ assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
242
+ end
243
+
244
+ + # Ingres doesn't support renaming of tables. Skip test.
245
+ + unless current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
246
+ def test_rename_table_with_an_index
247
+ begin
248
+ ActiveRecord::Base.connection.create_table :octopuses do |t|
249
+ @@ -497,18 +529,34 @@
250
+ ActiveRecord::Base.connection.drop_table :octopi rescue nil
251
+ end
252
+ end
253
+ + end
254
+
255
+ + # Virtuoso disallows virtually all column type conversions.
256
+ + # Conversion between any of the native types used by the ActiveRecord generic types is not allowed.
257
+ + # Skip the test.
258
+ + unless current_adapter?(:ODBCAdapter) && [:virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
259
+ def test_change_column
260
+ - Person.connection.add_column 'people', 'age', :integer
261
+ + #Ingres doesn't support changing an integer column to varchar/text.
262
+ + if current_adapter?(:ODBCAdapter) && [:ingres].include?(ActiveRecord::Base.connection.dbmsName)
263
+ + initial_type = :integer
264
+ + new_type = :float
265
+ + else
266
+ + initial_type = :integer
267
+ + new_type = :string
268
+ + end
269
+ +
270
+ + Person.connection.add_column 'people', 'age', initial_type
271
+ old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
272
+ - assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
273
+ + assert old_columns.find { |c| c.name == 'age' and c.type == initial_type }
274
+
275
+ - assert_nothing_raised { Person.connection.change_column "people", "age", :string }
276
+ + assert_nothing_raised { Person.connection.change_column "people", "age", new_type }
277
+
278
+ new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
279
+ - assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
280
+ - assert new_columns.find { |c| c.name == 'age' and c.type == :string }
281
+ + assert_nil new_columns.find { |c| c.name == 'age' and c.type == initial_type }
282
+ + assert new_columns.find { |c| c.name == 'age' and c.type == new_type }
283
+
284
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
285
+ + unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
286
+ old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
287
+ assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
288
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
289
+ @@ -516,8 +564,12 @@
290
+ assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
291
+ assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
292
+ assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
293
+ + end
294
+ + end
295
+ end
296
+
297
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
298
+ + unless current_adapter?(:ODBCAdapter) && [:ingres, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
299
+ def test_change_column_with_nil_default
300
+ Person.connection.add_column "people", "contributor", :boolean, :default => true
301
+ Person.reset_column_information
302
+ @@ -530,7 +582,11 @@
303
+ ensure
304
+ Person.connection.remove_column("people", "contributor") rescue nil
305
+ end
306
+ + end
307
+
308
+ + # Ingres doesn't support ALTER TABLE ADD COLUMN WITH NULL WITH DEFAULT.
309
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
310
+ + unless current_adapter?(:ODBCAdapter) && [:ingres, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
311
+ def test_change_column_with_new_default
312
+ Person.connection.add_column "people", "administrator", :boolean, :default => true
313
+ Person.reset_column_information
314
+ @@ -542,12 +598,16 @@
315
+ ensure
316
+ Person.connection.remove_column("people", "administrator") rescue nil
317
+ end
318
+ + end
319
+
320
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
321
+ + unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
322
+ def test_change_column_default
323
+ Person.connection.change_column_default "people", "first_name", "Tester"
324
+ Person.reset_column_information
325
+ assert_equal "Tester", Person.new.first_name
326
+ end
327
+ + end
328
+
329
+ def test_change_column_quotes_column_names
330
+ Person.connection.create_table :testings do |t|
331
+ @@ -561,11 +621,14 @@
332
+ Person.connection.drop_table :testings rescue nil
333
+ end
334
+
335
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
336
+ + unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
337
+ def test_change_column_default_to_null
338
+ Person.connection.change_column_default "people", "first_name", nil
339
+ Person.reset_column_information
340
+ assert_nil Person.new.first_name
341
+ end
342
+ + end
343
+
344
+ def test_add_table
345
+ assert !Reminder.table_exists?
346
+ @@ -797,8 +860,19 @@
347
+ Person.connection.drop_table :binary_testings rescue nil
348
+
349
+ assert_nothing_raised {
350
+ - Person.connection.create_table :binary_testings do |t|
351
+ - t.column "data", :binary, :null => false
352
+ + if current_adapter?(:ODBCAdapter) && [:informix, :ingres].include?(ActiveRecord::Base.connection.dbmsName)
353
+ + # Specifying a non-null default generates the following error:
354
+ + # Informix:
355
+ + # "Cannot specify non-null default value for blob column. (-594)"
356
+ + # Ingres:
357
+ + # "Cannot create a default on column of type 'long byte'"
358
+ + Person.connection.create_table :binary_testings do |t|
359
+ + t.column "data", :binary
360
+ + end
361
+ + else
362
+ + Person.connection.create_table :binary_testings do |t|
363
+ + t.column "data", :binary, :null => false
364
+ + end
365
+ end
366
+ }
367
+