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,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
+