odbc-rails 1.3 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/ChangeLog +18 -0
  2. data/NEWS +5 -0
  3. data/README +20 -7
  4. data/lib/active_record/connection_adapters/odbc_adapter.rb +254 -211
  5. data/lib/active_record/vendor/odbcext_informix.rb +17 -4
  6. data/lib/active_record/vendor/odbcext_ingres.rb +5 -5
  7. data/lib/active_record/vendor/odbcext_microsoftsqlserver.rb +35 -4
  8. data/lib/active_record/vendor/odbcext_mysql.rb +36 -8
  9. data/lib/active_record/vendor/odbcext_oracle.rb +4 -4
  10. data/lib/active_record/vendor/odbcext_postgresql.rb +8 -12
  11. data/lib/active_record/vendor/odbcext_progress.rb +3 -3
  12. data/lib/active_record/vendor/odbcext_progress89.rb +5 -4
  13. data/lib/active_record/vendor/odbcext_sybase.rb +6 -5
  14. data/lib/active_record/vendor/odbcext_virtuoso.rb +16 -3
  15. data/support/odbc_rails.diff +335 -266
  16. data/support/rake_fixes/README +6 -0
  17. data/support/rake_fixes/databases.dif +13 -0
  18. data/support/test/base_test.rb +333 -75
  19. data/support/test/migration_test.rb +430 -149
  20. data/test/connections/native_odbc/connection.rb +63 -44
  21. data/test/fixtures/db_definitions/db2.drop.sql +1 -0
  22. data/test/fixtures/db_definitions/db2.sql +9 -0
  23. data/test/fixtures/db_definitions/informix.drop.sql +1 -0
  24. data/test/fixtures/db_definitions/informix.sql +10 -0
  25. data/test/fixtures/db_definitions/ingres.drop.sql +2 -0
  26. data/test/fixtures/db_definitions/ingres.sql +9 -0
  27. data/test/fixtures/db_definitions/mysql.drop.sql +1 -0
  28. data/test/fixtures/db_definitions/mysql.sql +21 -12
  29. data/test/fixtures/db_definitions/oracle_odbc.drop.sql +4 -0
  30. data/test/fixtures/db_definitions/oracle_odbc.sql +29 -1
  31. data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
  32. data/test/fixtures/db_definitions/postgresql.sql +13 -3
  33. data/test/fixtures/db_definitions/progress.drop.sql +2 -0
  34. data/test/fixtures/db_definitions/progress.sql +11 -0
  35. data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
  36. data/test/fixtures/db_definitions/sqlserver.sql +35 -0
  37. data/test/fixtures/db_definitions/sybase.drop.sql +2 -0
  38. data/test/fixtures/db_definitions/sybase.sql +16 -7
  39. data/test/fixtures/db_definitions/virtuoso.drop.sql +1 -0
  40. data/test/fixtures/db_definitions/virtuoso.sql +10 -0
  41. metadata +6 -3
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_informix.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_informix.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Copyright (C) 2006 OpenLink Software
@@ -45,6 +45,17 @@ module ODBCExt
45
45
  #
46
46
  # DBMS specific methods which override the default implementation
47
47
  # provided by the ODBCAdapter core.
48
+
49
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
50
+ if type == :decimal
51
+ # Force an explicit scale if none supplied to specify the fixed
52
+ # point form of Informix's DECIMAL type. If no scale is specified,
53
+ # the Informix DECIMAL type stores floating point values.
54
+ precision ||= 32
55
+ scale ||= 0
56
+ end
57
+ super(type, limit, precision, scale)
58
+ end
48
59
 
49
60
  def quoted_date(value)
50
61
  @logger.unknown("ODBCAdapter#quoted_date>") if @trace
@@ -73,7 +84,7 @@ module ODBCExt
73
84
  @logger.unknown("ODBCAdapter#change_column>") if @trace
74
85
  @logger.unknown("args=[#{table_name}|#{column_name}|#{type}]") if @trace
75
86
  change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} " +
76
- "#{type_to_sql(type)}"
87
+ "#{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
77
88
  # Add any :null and :default options
78
89
  add_column_options!(change_column_sql, options)
79
90
  execute(change_column_sql)
@@ -84,8 +95,10 @@ module ODBCExt
84
95
 
85
96
  def change_column_default(table_name, column_name, default)
86
97
  @logger.unknown("ODBCAdapter#change_column_default>") if @trace
87
- @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
88
- change_column(table_name, column_name, nil, {:default => default})
98
+ @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
99
+ col = columns(table_name).find {|c| c.name == column_name.to_s }
100
+ change_column(table_name, column_name, col.type, :default => default,
101
+ :limit => col.limit, :precision => col.precision, :scale => col.scale)
89
102
  rescue Exception => e
90
103
  @logger.unknown("exception=#{e}") if @trace
91
104
  raise ActiveRecord::ActiveRecordError, e.message
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_ingres.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_ingres.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Copyright (C) 2006 OpenLink Software
@@ -82,10 +82,10 @@ module ODBCExt
82
82
  raise ActiveRecord::ActiveRecordError, e.message
83
83
  end
84
84
 
85
- def drop_table(name)
85
+ def drop_table(name, options = {})
86
86
  @logger.unknown("ODBCAdapter#drop_table>") if @trace
87
87
  @logger.unknown("args=[#{name}]") if @trace
88
- super
88
+ super(name, options)
89
89
  execute "DROP SEQUENCE #{name}_seq"
90
90
  rescue Exception => e
91
91
  @logger.unknown("exception=#{e}") if @trace
@@ -96,7 +96,7 @@ module ODBCExt
96
96
  @logger.unknown("ODBCAdapter#add_column>") if @trace
97
97
  @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
98
98
 
99
- sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit])}"
99
+ sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
100
100
  sql << " DEFAULT #{quote(options[:default], options[:column])}" unless options[:default].nil?
101
101
 
102
102
  # Ingres requires that if 'ALTER TABLE table ADD column' specifies a NOT NULL constraint,
@@ -125,7 +125,7 @@ module ODBCExt
125
125
  @logger.unknown("ODBCAdapter#change_column>") if @trace
126
126
  @logger.unknown("args=[#{table_name}|#{column_name}|#{type}]") if @trace
127
127
  change_column_sql = "ALTER TABLE #{table_name} ALTER #{column_name} " +
128
- "#{type_to_sql(type)}"
128
+ "#{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
129
129
  # Add any :null and :default options
130
130
  add_column_options!(change_column_sql, options)
131
131
  execute(change_column_sql)
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_microsoftsqlserver.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_microsoftsqlserver.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Copyright (C) 2006 OpenLink Software
@@ -77,6 +77,24 @@ module ODBCExt
77
77
  #
78
78
  # DBMS specific methods which override the default implementation
79
79
  # provided by the ODBCAdapter core.
80
+ #
81
+ def create_database(name)
82
+ @logger.unknown("ODBCAdapter#create_database>") if @trace
83
+ @logger.unknown("args=[#{name}]") if @trace
84
+ execute "CREATE DATABASE #{name}"
85
+ rescue Exception => e
86
+ @logger.unknown("exception=#{e}") if @trace
87
+ raise
88
+ end
89
+
90
+ def drop_database(name)
91
+ @logger.unknown("ODBCAdapter#drop_database>") if @trace
92
+ @logger.unknown("args=[#{name}]") if @trace
93
+ execute "DROP DATABASE #{name}"
94
+ rescue Exception => e
95
+ @logger.unknown("exception=#{e}") if @trace
96
+ raise
97
+ end
80
98
 
81
99
  def rename_table(name, new_name)
82
100
  @logger.unknown("ODBCAdapter#rename_table>") if @trace
@@ -101,14 +119,14 @@ module ODBCExt
101
119
 
102
120
  def change_column(table_name, column_name, type, options = {})
103
121
  @logger.unknown("ODBCAdapter#change_column>") if @trace
104
- sql_commands = ["ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"]
105
- if options[:default]
122
+ sql_commands = ["ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"]
123
+ if options_include_default?(options)
106
124
  # Remove default constraints first
107
125
  defaults = select_all "select def.name from sysobjects def, syscolumns col, sysobjects tab where col.cdefault = def.id and col.name = '#{column_name}' and tab.name = '#{table_name}' and col.id = tab.id"
108
126
  defaults.each {|constraint|
109
127
  execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
110
128
  }
111
- sql_commands << "ALTER TABLE #{table_name} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{options[:default]} FOR #{column_name}"
129
+ sql_commands << "ALTER TABLE #{table_name} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{quote(options[:default])} FOR #{column_name}"
112
130
  end
113
131
  sql_commands.each {|c|
114
132
  execute(c)
@@ -118,6 +136,19 @@ module ODBCExt
118
136
  raise
119
137
  end
120
138
 
139
+ def change_column_default(table_name, column_name, default)
140
+ @logger.unknown("ODBCAdapter#change_column_default>") if @trace
141
+ # Remove default constraints first
142
+ defaults = select_all "select def.name from sysobjects def, syscolumns col, sysobjects tab where col.cdefault = def.id and col.name = '#{column_name}' and tab.name = '#{table_name}' and col.id = tab.id"
143
+ defaults.each {|constraint|
144
+ execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{constraint["name"]}"
145
+ }
146
+ execute "ALTER TABLE #{table_name} ADD CONSTRAINT DF_#{table_name}_#{column_name} DEFAULT #{quote(default)} FOR #{column_name}"
147
+ rescue Exception => e
148
+ @logger.unknown("exception=#{e}") if @trace
149
+ raise
150
+ end
151
+
121
152
  def rename_column(table_name, column_name, new_column_name)
122
153
  @logger.unknown("ODBCAdapter#rename_column>") if @trace
123
154
  execute "EXEC sp_rename '#{table_name}.#{column_name}', '#{new_column_name}'"
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_mysql.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_mysql.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Copyright (C) 2006 OpenLink Software
@@ -23,7 +23,6 @@
23
23
  # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
24
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
25
  #
26
-
27
26
  module ODBCExt
28
27
 
29
28
  # ------------------------------------------------------------------------
@@ -68,6 +67,24 @@ module ODBCExt
68
67
  string.gsub(/\\/, '\&\&').gsub(/'/, "''")
69
68
  end
70
69
 
70
+ def create_database(name)
71
+ @logger.unknown("ODBCAdapter#create_database>") if @trace
72
+ @logger.unknown("args=[#{name}]") if @trace
73
+ execute "CREATE DATABASE `#{name}`"
74
+ rescue Exception => e
75
+ @logger.unknown("exception=#{e}") if @trace
76
+ raise
77
+ end
78
+
79
+ def drop_database(name)
80
+ @logger.unknown("ODBCAdapter#drop_database>") if @trace
81
+ @logger.unknown("args=[#{name}]") if @trace
82
+ execute "DROP DATABASE IF EXISTS `#{name}`"
83
+ rescue Exception => e
84
+ @logger.unknown("exception=#{e}") if @trace
85
+ raise
86
+ end
87
+
71
88
  def create_table(name, options = {})
72
89
  @logger.unknown("ODBCAdapter#create_table>") if @trace
73
90
  super(name, {:options => "ENGINE=InnoDB"}.merge(options))
@@ -87,8 +104,10 @@ module ODBCExt
87
104
  def change_column(table_name, column_name, type, options = {})
88
105
  @logger.unknown("ODBCAdapter#change_column>") if @trace
89
106
  # column_name.to_s used in case column_name is a symbol
90
- options[:default] ||= columns(table_name).find { |c| c.name == column_name.to_s }.default
91
- change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit])}"
107
+ unless options_include_default?(options)
108
+ options[:default] = columns(table_name).find { |c| c.name == column_name.to_s }.default
109
+ end
110
+ change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
92
111
  add_column_options!(change_column_sql, options)
93
112
  execute(change_column_sql)
94
113
  rescue Exception => e
@@ -110,9 +129,8 @@ module ODBCExt
110
129
  def change_column_default(table_name, column_name, default)
111
130
  @logger.unknown("ODBCAdapter#change_column_default>") if @trace
112
131
  col = columns(table_name).find{ |c| c.name == column_name.to_s }
113
- current_type = col.sql_type
114
- current_type << "(#{col.limit})" if col.limit
115
- change_column(table_name, column_name, current_type, { :default => default })
132
+ change_column(table_name, column_name, col.type, :default => default,
133
+ :limit => col.limit, :precision => col.precision, :scale => col.scale)
116
134
  rescue Exception => e
117
135
  @logger.unknown("exception=#{e}") if @trace
118
136
  raise
@@ -122,7 +140,17 @@ module ODBCExt
122
140
  # Skip primary key indexes
123
141
  super(table_name, name).delete_if { |i| i.unique && i.name =~ /^PRIMARY$/ }
124
142
  end
125
-
143
+
144
+ def options_include_default?(options)
145
+ # MySQL 5.x doesn't allow DEFAULT NULL for first timestamp column in a table
146
+ if options.include?(:default) && options[:default].nil?
147
+ if options.include?(:column) && options[:column].sql_type =~ /timestamp/i
148
+ options.delete(:default)
149
+ end
150
+ end
151
+ super(options)
152
+ end
153
+
126
154
  def structure_dump
127
155
  @logger.unknown("ODBCAdapter#structure_dump>") if @trace
128
156
  select_all("SHOW TABLES").inject("") do |structure, table|
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_oracle.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_oracle.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Copyright (C) 2006 OpenLink Software
@@ -106,9 +106,9 @@ module ODBCExt
106
106
  raise
107
107
  end
108
108
 
109
- def drop_table(name)
109
+ def drop_table(name, options = {})
110
110
  @logger.unknown("ODBCAdapter#drop_table>") if @trace
111
- super(name)
111
+ super(name, options)
112
112
  execute "DROP SEQUENCE #{name}_seq"
113
113
  rescue Exception => e
114
114
  if e.message !~ /ORA-02289/i
@@ -129,7 +129,7 @@ module ODBCExt
129
129
 
130
130
  def change_column(table_name, column_name, type, options = {})
131
131
  @logger.unknown("ODBCAdapter#change_column>") if @trace
132
- change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit])}"
132
+ change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
133
133
  add_column_options!(change_column_sql, options)
134
134
  execute(change_column_sql)
135
135
  rescue Exception => e
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_postgresql.rb,v 1.2 2007/01/09 10:11:40 source Exp $
2
+ # $Id: odbcext_postgresql.rb,v 1.3 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Copyright (C) 2006 OpenLink Software
@@ -106,14 +106,10 @@ module ODBCExt
106
106
 
107
107
  def add_column(table_name, column_name, type, options = {})
108
108
  @logger.unknown("ODBCAdapter#add_column>") if @trace
109
- sql_commands = ["ALTER TABLE #{table_name} ADD #{column_name} #{type_to_sql(type, options[:limit])}"]
110
- if options[:default]
111
- sql_commands << "ALTER TABLE #{table_name} ALTER #{column_name} SET DEFAULT '#{options[:default]}'"
112
- end
113
- if options[:null] == false
114
- sql_commands << "ALTER TABLE #{table_name} ALTER #{column_name} SET NOT NULL"
115
- end
116
- sql_commands.each { |cmd| execute(cmd) }
109
+ sql = "ALTER TABLE #{table_name} ADD #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
110
+ sql << " NOT NULL" if options[:null] == false
111
+ sql << " DEFAULT #{quote(options[:default])}" if options[:default]
112
+ execute(sql)
117
113
  rescue Exception => e
118
114
  @logger.unknown("exception=#{e}") if @trace
119
115
  raise
@@ -121,8 +117,8 @@ module ODBCExt
121
117
 
122
118
  def change_column(table_name, column_name, type, options = {})
123
119
  @logger.unknown("ODBCAdapter#change_column>") if @trace
124
- execute "ALTER TABLE #{table_name} ALTER #{column_name} TYPE #{type_to_sql(type, options[:limit])}"
125
- change_column_default(table_name, column_name, options[:default]) unless options[:default].nil?
120
+ execute "ALTER TABLE #{table_name} ALTER #{column_name} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
121
+ change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
126
122
  rescue Exception => e
127
123
  @logger.unknown("exception=#{e}") if @trace
128
124
  raise
@@ -130,7 +126,7 @@ module ODBCExt
130
126
 
131
127
  def change_column_default(table_name, column_name, default)
132
128
  @logger.unknown("ODBCAdapter#change_column_default>") if @trace
133
- execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT '#{default}'"
129
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT #{quote(default)}"
134
130
  rescue Exception => e
135
131
  @logger.unknown("exception=#{e}") if @trace
136
132
  raise
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_progress.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_progress.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Extension module for Progress v9 and later using SQL-92 engine
@@ -94,9 +94,9 @@ module ODBCExt
94
94
  raise ActiveRecord::ActiveRecordError, e.message
95
95
  end
96
96
 
97
- def drop_table(name)
97
+ def drop_table(name, options = {})
98
98
  @logger.unknown("ODBCAdapter#drop_table>") if @trace
99
- super(name)
99
+ super(name, options)
100
100
  execute "DROP SEQUENCE PUB.#{name}_seq"
101
101
  rescue Exception => e
102
102
  if e.message !~ /10520/
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_progress89.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_progress89.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Extension module for Progress v8 and earlier using SQL-89 engine
@@ -65,7 +65,8 @@ module ODBCExt
65
65
  @logger.unknown("ODBCAdapter#add_column_options!>") if @trace
66
66
  @logger.unknown("args=[#{sql}]") if @trace
67
67
  sql << " NOT NULL" if options[:null] == false
68
- sql << " DEFAULT #{quote(options[:default], options[:column])}" unless options[:default].nil?
68
+ # Progress 89 doesn't accept 'DEFAULT NULL'
69
+ sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options) && !options[:default].nil?
69
70
  rescue Exception => e
70
71
  @logger.unknown("exception=#{e}") if @trace
71
72
  raise StatementInvalid, e.message
@@ -131,9 +132,9 @@ module ODBCExt
131
132
  raise ActiveRecord::ActiveRecordError, e.message
132
133
  end
133
134
 
134
- def drop_table(name)
135
+ def drop_table(name, options = {})
135
136
  @logger.unknown("ODBCAdapter#drop_table>") if @trace
136
- super(name)
137
+ super(name, options)
137
138
  drop_sequence("#{name}_seq")
138
139
  rescue Exception => e
139
140
  @logger.unknown("exception=#{e}") if @trace
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_sybase.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_sybase.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Copyright (C) 2006 OpenLink Software
@@ -103,12 +103,12 @@ module ODBCExt
103
103
 
104
104
  def change_column(table_name, column_name, type, options = {})
105
105
  @logger.unknown("ODBCAdapter#change_column>") if @trace
106
- if options[:default]
106
+ if options.include?(:default)
107
107
  # Sybase ASE's ALTER TABLE statement doesn't allow a column's DEFAULT to be changed.
108
108
  raise ActiveRecord::ActiveRecordError,
109
109
  "Sybase ASE does not support changing a column's DEFAULT definition"
110
110
  end
111
- execute "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit])}"
111
+ execute "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
112
112
  rescue Exception => e
113
113
  @logger.unknown("exception=#{e}") if @trace
114
114
  raise
@@ -137,13 +137,14 @@ module ODBCExt
137
137
 
138
138
  def indexes(table_name, name = nil)
139
139
  # Hide primary key indexes.
140
- super(table_name, name).delete_if { |i| i.name =~ /^PK_/ }
140
+ # Primary key indexes take the form <tablename>_<primary key name>_<integer>
141
+ super(table_name, name).delete_if { |i| i.unique && i.name =~ /^\w+_\w+_\d+$/ }
141
142
  end
142
143
 
143
144
  def add_column_options!(sql, options) # :nodoc:
144
145
  @logger.unknown("ODBCAdapter#add_column_options!>") if @trace
145
146
  @logger.unknown("args=[#{sql}]") if @trace
146
- sql << " DEFAULT #{quote(options[:default], options[:column])}" unless options[:default].nil?
147
+ sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
147
148
 
148
149
  if column_type_allows_null?(sql, options)
149
150
  sql << (options[:null] == false ? " NOT NULL" : " NULL")
@@ -1,5 +1,5 @@
1
1
  #
2
- # $Id: odbcext_virtuoso.rb,v 1.1 2006/12/06 14:42:11 source Exp $
2
+ # $Id: odbcext_virtuoso.rb,v 1.2 2007/02/27 11:00:49 source Exp $
3
3
  #
4
4
  # OpenLink ODBC Adapter for Ruby on Rails
5
5
  # Copyright (C) 2006 OpenLink Software
@@ -74,6 +74,17 @@ module ODBCExt
74
74
  # DBMS specific methods which override the default implementation
75
75
  # provided by the ODBCAdapter core.
76
76
 
77
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
78
+ if type == :decimal
79
+ # Force an explicit scale if none supplied to specify the fixed
80
+ # point form of Virtuoso's DECIMAL type. If no scale is specified,
81
+ # the Virtuoso DECIMAL type stores floating point values.
82
+ precision ||= 32
83
+ scale ||= 0
84
+ end
85
+ super(type, limit, precision, scale)
86
+ end
87
+
77
88
  def quote_string(s)
78
89
  s.gsub(/\\/, '\&\&').gsub(/'/, "''")
79
90
  end
@@ -104,7 +115,7 @@ module ODBCExt
104
115
  @logger.unknown("ODBCAdapter#change_column>") if @trace
105
116
  @logger.unknown("args=[#{table_name}|#{column_name}|#{type}]") if @trace
106
117
  change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} " +
107
- "#{type_to_sql(type)}"
118
+ "#{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
108
119
 
109
120
  # Add any :null and :default options
110
121
  add_column_options!(change_column_sql, options)
@@ -117,7 +128,9 @@ module ODBCExt
117
128
  def change_column_default(table_name, column_name, default)
118
129
  @logger.unknown("ODBCAdapter#change_column_default>") if @trace
119
130
  @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
120
- change_column(table_name, column_name, nil, {:default => default})
131
+ col = columns(table_name).find {|c| c.name == column_name.to_s }
132
+ change_column(table_name, column_name, col.type, :default => default,
133
+ :limit => col.limit, :precision => col.precision, :scale => col.scale)
121
134
  rescue Exception => e
122
135
  @logger.unknown("exception=#{e}") if @trace
123
136
  raise ActiveRecord::ActiveRecordError, e.message
@@ -1,31 +1,8 @@
1
- Index: lib/active_record/connection_adapters/abstract/schema_definitions.rb
2
- ===================================================================
3
- --- lib/active_record/connection_adapters/abstract/schema_definitions.rb (revision 1)
4
- +++ lib/active_record/connection_adapters/abstract/schema_definitions.rb (working copy)
5
- @@ -195,7 +195,8 @@
6
- # Appends a primary key definition to the table definition.
7
- # Can be called multiple times, but this is probably not a good idea.
8
- def primary_key(name)
9
- - column(name, native[:primary_key])
10
- + # column(name, native[:primary_key])
11
- + column(name, :primary_key)
12
- end
13
-
14
- # Returns a ColumnDefinition for the column with name +name+.
15
1
  Index: test/base_test.rb
16
2
  ===================================================================
17
3
  --- test/base_test.rb (revision 1)
18
4
  +++ test/base_test.rb (working copy)
19
- @@ -44,7 +44,7 @@
20
- end
21
-
22
- class BasicsTest < Test::Unit::TestCase
23
- - fixtures :topics, :companies, :developers, :projects, :computers
24
- + fixtures :topics, :companies, :developers, :projects, :computers, :accounts
25
-
26
- def test_table_exists
27
- assert !NonExistentTable.table_exists?
28
- @@ -297,7 +297,15 @@
5
+ @@ -319,6 +319,12 @@
29
6
  Time, Topic.find(1).last_read,
30
7
  "The last_read attribute should be of the Time class"
31
8
  )
@@ -36,12 +13,9 @@ Index: test/base_test.rb
36
13
  + "The last_read attribute should be of the Time class"
37
14
  + )
38
15
  else
39
- + # ODBCAdapter fails against SQL Server because topics.last_read is
40
- + # defined as a datetime column, which is returned as a Ruby Time object.
41
16
  assert_kind_of(
42
17
  Date, Topic.find(1).last_read,
43
- "The last_read attribute should be of the Date class"
44
- @@ -563,7 +571,12 @@
18
+ @@ -610,7 +616,12 @@
45
19
 
46
20
  def test_default_values_on_empty_strings
47
21
  topic = Topic.new
@@ -55,7 +29,7 @@ Index: test/base_test.rb
55
29
  topic.last_read = nil
56
30
 
57
31
  topic.save
58
- @@ -572,7 +585,8 @@
32
+ @@ -619,7 +630,8 @@
59
33
  assert_nil topic.last_read
60
34
 
61
35
  # Sybase adapter does not allow nulls in boolean columns
@@ -65,27 +39,55 @@ Index: test/base_test.rb
65
39
  assert topic.approved == false
66
40
  else
67
41
  assert_nil topic.approved
68
- @@ -733,7 +747,12 @@
69
-
42
+ @@ -815,6 +827,10 @@
70
43
  def test_attributes_on_dummy_time
71
- # Oracle and SQL Server do not have a TIME datatype.
72
- - return true if current_adapter?(:SQLServerAdapter) || current_adapter?(:OracleAdapter)
73
- + return true if current_adapter?(:SQLServerAdapter) ||
74
- + current_adapter?(:OracleAdapter)
44
+ # Oracle, SQL Server, and Sybase do not have a TIME datatype.
45
+ return true if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
75
46
  + if current_adapter?(:ODBCAdapter)
76
- + # Check for databases which don't have a true TIME datatype
77
- + return true if [:ingres, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
47
+ + # Check for databases which don't have a true TIME datatype
48
+ + return true if [:ingres, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
78
49
  + end
79
50
 
80
51
  attributes = {
81
52
  "bonus_time" => "5:42:00AM"
82
- @@ -965,7 +984,12 @@
53
+ @@ -1014,6 +1030,7 @@
54
+
55
+ assert_kind_of BigDecimal, m1.big_bank_balance
56
+ assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
57
+ +
58
+ end
59
+
60
+ def test_auto_id
61
+ @@ -1037,7 +1054,7 @@
62
+
63
+ def test_sql_injection_via_find
64
+ assert_raises(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
65
+ - Topic.find("123456 OR id > 0")
66
+ + Topic.find("123456 OR id > 0")
67
+ end
68
+ end
69
+
70
+ @@ -1055,8 +1072,11 @@
71
+ replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
72
+ assert_equal topics(:first).replies.size, replies.size
73
+
74
+ - replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
75
+ - assert_equal 0, replies.size
76
+ + # DB2 doesn't support "WHERE (id IN (NULL))" clause
77
+ + unless current_adapter?(:ODBCAdapter) && [:db2].include?(ActiveRecord::Base.connection.dbmsName)
78
+ + replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
79
+ + assert_equal 0, replies.size
80
+ + end
81
+ end
82
+
83
+ MyObject = Struct.new :attribute1, :attribute2
84
+ @@ -1082,7 +1102,12 @@
83
85
  end
84
86
 
85
87
  def test_quote
86
88
  - author_name = "\\ \001 ' \n \\n \""
87
89
  + if current_adapter?(:ODBCAdapter) && [:informix, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
88
- + #Informix and Sybase only allow printable characters in VARCHAR columns.
90
+ + #Some databases only allow printable characters in VARCHAR columns.
89
91
  + author_name = "\\ \041 ' \n \\n \""
90
92
  + else
91
93
  + author_name = "\\ \001 ' \n \\n \""
@@ -93,29 +95,45 @@ Index: test/base_test.rb
93
95
  topic = Topic.create('author_name' => author_name)
94
96
  assert_equal author_name, Topic.find(topic.id).author_name
95
97
  end
96
- @@ -1204,14 +1228,22 @@
98
+ @@ -1414,6 +1439,8 @@
99
+ xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true)
100
+ bonus_time_in_current_timezone = topics(:first).bonus_time.xmlschema
101
+ written_on_in_current_timezone = topics(:first).written_on.xmlschema
102
+ + #cb+- Follwoing works
103
+ + #written_on = topics(:first).written_on
104
+ last_read_in_current_timezone = topics(:first).last_read.xmlschema
105
+ assert_equal "<topic>", xml.first(7)
106
+ assert xml.include?(%(<title>The First Topic</title>))
107
+ @@ -1421,17 +1448,29 @@
108
+ assert xml.include?(%(<id type="integer">1</id>))
109
+ assert xml.include?(%(<replies-count type="integer">1</replies-count>))
110
+ assert xml.include?(%(<written-on type="datetime">#{written_on_in_current_timezone}</written-on>))
111
+ + #cb+- Following works
112
+ + #assert xml.include?(%(<written-on type="timestamp">#{written_on}</written-on>))
97
113
  assert xml.include?(%(<content>Have a nice day</content>))
98
114
  assert xml.include?(%(<author-email-address>david@loudthinking.com</author-email-address>))
99
- assert xml.include?(%(<parent-id></parent-id>))
100
- - if current_adapter?(:SybaseAdapter) or current_adapter?(:SQLServerAdapter)
115
+ assert xml.match(%(<parent-id type="integer"></parent-id>))
116
+ - if current_adapter?(:SybaseAdapter, :SQLServerAdapter, :OracleAdapter)
101
117
  + # Following databases don't have a true date type, only a composite datetime type
102
- + if current_adapter?(:SybaseAdapter) or current_adapter?(:SQLServerAdapter) or
103
- + current_adapter?(:ODBCAdapter) &&
104
- + [:ingres,:oracle,:microsoftsqlserver].include?(ActiveRecord::Base.connection.dbmsName)
118
+ + if current_adapter?(:SybaseAdapter, :SQLServerAdapter, :OracleAdapter) or
119
+ + current_adapter?(:ODBCAdapter) && [:ingres,:oracle,:microsoftsqlserver].include?(ActiveRecord::Base.connection.dbmsName)
105
120
  assert xml.include?(%(<last-read type="datetime">#{last_read_in_current_timezone}</last-read>))
106
121
  else
107
122
  assert xml.include?(%(<last-read type="date">2004-04-15</last-read>))
108
123
  end
109
124
  - # Oracle and DB2 don't have true boolean or time-only fields
110
125
  + # Following databases don't have a true boolean type
111
- + unless current_adapter?(:OracleAdapter) || current_adapter?(:DB2Adapter) ||
112
- + current_adapter?(:ODBCAdapter) &&
113
- + [:ingres,:virtuoso,:oracle,:mysql,:db2].include?(ActiveRecord::Base.connection.dbmsName)
114
- + assert xml.include?(%(<approved type="boolean">false</approved>)), "Approved should be a boolean"
126
+ unless current_adapter?(:OracleAdapter, :DB2Adapter)
127
+ - assert xml.include?(%(<approved type="boolean">false</approved>)), "Approved should be a boolean"
128
+ + if current_adapter?(:ODBCAdapter) &&
129
+ + [:ingres,:virtuoso,:oracle,:mysql,:db2,:progress].include?(ActiveRecord::Base.connection.dbmsName)
130
+ + assert xml.include?(%(<approved type="integer">0</approved>)), "Approved should be an integer"
131
+ + else
132
+ + assert xml.include?(%(<approved type="boolean">false</approved>)), "Approved should be a boolean"
133
+ + end
115
134
  + end
116
135
  + # Oracle and DB2 don't have a true time-only field
117
- unless current_adapter?(:OracleAdapter) || current_adapter?(:DB2Adapter)
118
- - assert xml.include?(%(<approved type="boolean">false</approved>)), "Approved should be a boolean"
136
+ + unless current_adapter?(:OracleAdapter, :DB2Adapter)
119
137
  assert xml.include?(%(<bonus-time type="datetime">#{bonus_time_in_current_timezone}</bonus-time>))
120
138
  end
121
139
  end
@@ -132,28 +150,15 @@ Index: test/fixtures/db_definitions/db2.sql
132
150
  );
133
151
 
134
152
  CREATE TABLE posts (
135
- Index: test/fixtures/db_definitions/mysql.sql
136
- ===================================================================
137
- --- test/fixtures/db_definitions/mysql.sql (revision 1)
138
- +++ test/fixtures/db_definitions/mysql.sql (working copy)
139
- @@ -51,7 +51,7 @@
140
- CREATE TABLE `projects` (
141
- `id` int(11) NOT NULL auto_increment,
142
- `name` varchar(100) default NULL,
143
- - `type` VARCHAR(255) NOT NULL,
144
- + `type` VARCHAR(255) default NULL,
145
- PRIMARY KEY (`id`)
146
- ) TYPE=InnoDB;
147
-
148
- @@ -131,7 +131,7 @@
149
- ) TYPE=InnoDB;
150
-
151
- CREATE TABLE `people` (
152
- - `id` INTEGER NOT NULL PRIMARY KEY,
153
- + `id` INTEGER NOT NULL auto_increment PRIMARY KEY,
154
- `first_name` VARCHAR(40) NOT NULL,
155
- `lock_version` INTEGER NOT NULL DEFAULT 0
156
- ) TYPE=InnoDB;
153
+ @@ -217,7 +217,7 @@
154
+ );
155
+
156
+ CREATE TABLE numeric_data (
157
+ - id INT NOT NULL PRIMARY KEY,
158
+ + id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
159
+ bank_balance DECIMAL(10,2),
160
+ big_bank_balance DECIMAL(15,2),
161
+ world_population DECIMAL(10),
157
162
  Index: test/fixtures/db_definitions/sybase.sql
158
163
  ===================================================================
159
164
  --- test/fixtures/db_definitions/sybase.sql (revision 1)
@@ -178,7 +183,7 @@ Index: test/fixtures/db_definitions/sybase.sql
178
183
  type varchar(50) NULL,
179
184
  ruby_type varchar(50) NULL,
180
185
  firm_id int NULL,
181
- @@ -21,13 +21,13 @@
186
+ @@ -21,7 +21,7 @@
182
187
 
183
188
 
184
189
  CREATE TABLE topics (
@@ -187,13 +192,6 @@ Index: test/fixtures/db_definitions/sybase.sql
187
192
  title varchar(255) NULL,
188
193
  author_name varchar(255) NULL,
189
194
  author_email_address varchar(255) NULL,
190
- written_on datetime NULL,
191
- bonus_time time NULL,
192
- - last_read datetime NULL,
193
- + last_read date NULL,
194
- content varchar(255) NULL,
195
- approved bit default 1,
196
- replies_count int default 0,
197
195
  @@ -36,7 +36,7 @@
198
196
  )
199
197
 
@@ -278,7 +276,7 @@ Index: test/fixtures/db_definitions/sybase.sql
278
276
  CREATE TABLE people (
279
277
  - id numeric(9,0) IDENTITY PRIMARY KEY,
280
278
  + id int IDENTITY PRIMARY KEY,
281
- first_name varchar(40) NOT NULL,
279
+ first_name varchar(40) NULL,
282
280
  lock_version int DEFAULT 0
283
281
  )
284
282
 
@@ -338,7 +336,7 @@ Index: test/fixtures/db_definitions/sybase.sql
338
336
  name varchar(255) NOT NULL,
339
337
  type varchar(255) NOT NULL
340
338
  )
341
- @@ -177,25 +177,25 @@
339
+ @@ -177,7 +177,7 @@
342
340
  )
343
341
 
344
342
  CREATE TABLE fk_test_has_pk (
@@ -347,13 +345,7 @@ Index: test/fixtures/db_definitions/sybase.sql
347
345
  )
348
346
 
349
347
  CREATE TABLE fk_test_has_fk (
350
- - id numeric(9,0) PRIMARY KEY,
351
- - fk_id numeric(9,0) NOT NULL,
352
- + id int PRIMARY KEY,
353
- + fk_id int NOT NULL,
354
-
355
- FOREIGN KEY (fk_id) REFERENCES fk_test_has_pk(id)
356
- )
348
+ @@ -189,20 +189,20 @@
357
349
 
358
350
 
359
351
  CREATE TABLE keyboards (
@@ -367,158 +359,137 @@ Index: test/fixtures/db_definitions/sybase.sql
367
359
  - id numeric(9,0) IDENTITY PRIMARY KEY,
368
360
  + id int IDENTITY PRIMARY KEY,
369
361
  tps_report_number int default NULL,
370
- version int default 0,
362
+ version int default 0
371
363
  )
364
+
365
+
366
+ CREATE TABLE numeric_data (
367
+ - id numeric(9,0) IDENTITY PRIMARY KEY,
368
+ + id int IDENTITY PRIMARY KEY,
369
+ bank_balance numeric(10,2),
370
+ big_bank_balance numeric(15,2),
371
+ world_population numeric(10),
372
372
  Index: test/migration_test.rb
373
373
  ===================================================================
374
374
  --- test/migration_test.rb (revision 1)
375
375
  +++ test/migration_test.rb (working copy)
376
- @@ -46,7 +46,14 @@
376
+ @@ -50,8 +50,15 @@
377
377
  end
378
378
 
379
379
  def test_add_index
380
- - Person.connection.add_column "people", "last_name", :string
380
+ - # Limit size of last_name and key columns to support Firebird index limitations
381
+ - Person.connection.add_column "people", "last_name", :string, :limit => 100
381
382
  + if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :informix
382
383
  + # Index on (last_name, first_name) exceeds max. index width supported by Informix if
383
384
  + # both columns are created with a default width of 255, in which case
384
385
  + # Informix may return error -517: "The total size of the index is too large..."
385
386
  + Person.connection.add_column "people", "last_name", :string, {:limit => 40}
386
387
  + else
387
- + Person.connection.add_column "people", "last_name", :string
388
+ + # Limit size of last_name and key columns to support Firebird index limitations
389
+ + Person.connection.add_column "people", "last_name", :string, :limit => 100
388
390
  + end
391
+ Person.connection.add_column "people", "key", :string, :limit => 100
389
392
  Person.connection.add_column "people", "administrator", :boolean
390
- Person.connection.add_column "people", "key", :string
391
-
392
- @@ -61,7 +68,8 @@
393
- assert_nothing_raised { Person.connection.remove_index("people", :name => "key") }
393
+
394
+ @@ -59,7 +66,8 @@
395
+ assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
396
+
397
+ # Orcl nds shrt indx nms. Sybs 2.
398
+ - unless current_adapter?(:OracleAdapter, :SybaseAdapter)
399
+ + unless current_adapter?(:OracleAdapter, :SybaseAdapter) ||
400
+ + current_adapter?(:ODBCAdapter) && [:sybase, :oracle].include?(ActiveRecord::Base.connection.dbmsName)
401
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
402
+ assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
403
+ assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
404
+ @@ -76,7 +84,8 @@
405
+ assert_nothing_raised { Person.connection.remove_index("people", :name => "key_idx", :unique => true) }
394
406
 
395
407
  # Sybase adapter does not support indexes on :boolean columns
396
408
  - unless current_adapter?(:SybaseAdapter)
397
- + unless current_adapter?(:SybaseAdapter) ||
409
+ + unless current_adapter?(:SybaseAdapter) ||
398
410
  + current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :sybase
399
411
  assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
400
412
  assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
401
413
  end
402
- @@ -109,6 +117,12 @@
403
- # Oracle doesn't support native booleans
404
- assert_equal true, two.default == 1
405
- assert_equal false, three.default != 0
406
- + elsif current_adapter?(:ODBCAdapter) &&
407
- + [:informix, :ingres, :virtuoso, :oracle, :mysql, :microsoftsqlserver].include?(ActiveRecord::Base.connection.dbmsName)
408
- + # Above databases/ODBC drivers don't support native booleans.
409
- + # They use an integer type instead.
410
- + assert_equal true, two.default == 1
411
- + assert_equal false, three.default != 0
412
- else
413
- assert_equal true, two.default
414
- assert_equal false, three.default
415
- @@ -122,12 +136,14 @@
414
+ @@ -170,7 +179,8 @@
416
415
  # SQL Server and Sybase will not allow you to add a NOT NULL column
417
416
  # to a table without specifying a default value, so the
418
- # following test must be skipped
419
- - unless current_adapter?(:SQLServerAdapter) || current_adapter?(:SybaseAdapter)
420
- + unless current_adapter?(:SQLServerAdapter) || current_adapter?(:SybaseAdapter) ||
417
+ # following test must be skipped
418
+ - unless current_adapter?(:SQLServerAdapter, :SybaseAdapter)
419
+ + unless current_adapter?(:SQLServerAdapter, :SybaseAdapter) ||
421
420
  + current_adapter?(:ODBCAdapter) && [:microsoftsqlserver, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
422
421
  def test_add_column_not_null_without_default
423
- +
424
422
  Person.connection.create_table :testings do |t|
425
- - t.column :foo, :string
426
- + t.column :foo, :string
427
- end
428
- - Person.connection.add_column :testings, :bar, :string, :null => false
429
- + Person.connection.add_column :testings, :bar, :string, :null => false
430
-
431
- assert_raises(ActiveRecord::StatementInvalid) do
432
- Person.connection.execute "insert into testings (foo, bar) values ('hello', NULL)"
433
- @@ -141,8 +157,14 @@
434
- Person.connection.create_table :testings do |t|
435
- t.column :foo, :string
436
- end
437
- - Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default"
438
- -
439
- + if current_adapter?(:ODBCAdapter) && [:ingres].include?(ActiveRecord::Base.connection.dbmsName)
423
+ t.column :foo, :string
424
+ @@ -194,7 +204,13 @@
425
+ Person.connection.enable_identity_insert("testings", true) if current_adapter?(:SybaseAdapter)
426
+ Person.connection.execute "insert into testings (#{con.quote_column_name('id')}, #{con.quote_column_name('foo')}) values (1, 'hello')"
427
+ Person.connection.enable_identity_insert("testings", false) if current_adapter?(:SybaseAdapter)
428
+ - assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default" }
429
+ + if current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
440
430
  + # Ingres requires that if 'ALTER TABLE table ADD column' specifies a NOT NULL constraint,
441
431
  + # then 'WITH DEFAULT' must also be specified *without* a default value.
442
- + Person.connection.add_column :testings, :bar, :string, :null => false
432
+ + assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false}
443
433
  + else
444
- + Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default"
434
+ + assert_nothing_raised {Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default"}
445
435
  + end
446
- +
436
+
447
437
  assert_raises(ActiveRecord::StatementInvalid) do
448
- Person.connection.execute "insert into testings (foo, bar) values ('hello', NULL)"
449
- end
450
- @@ -174,8 +196,12 @@
438
+ 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)"
439
+ @@ -282,8 +298,10 @@
451
440
  assert_equal Fixnum, bob.age.class
452
441
  assert_equal Time, bob.birthday.class
453
442
 
454
- - if current_adapter?(:SQLServerAdapter) || current_adapter?(:OracleAdapter) || current_adapter?(:SybaseAdapter)
455
- - # SQL Server, Sybase, and Oracle don't differentiate between date/time
456
- + if current_adapter?(:SQLServerAdapter) ||
457
- + current_adapter?(:OracleAdapter) ||
458
- + current_adapter?(:SybaseAdapter) ||
443
+ - if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
444
+ - # Sybase, and Oracle don't differentiate between date/time
445
+ + if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter) ||
459
446
  + (current_adapter?(:ODBCAdapter) &&
460
447
  + [:ingres, :oracle, :microsoftsqlserver].include?(ActiveRecord::Base.connection.dbmsName))
461
448
  + # SQL Server, Sybase, Oracle and Ingres don't differentiate between date/time
462
449
  assert_equal Time, bob.favorite_day.class
463
450
  else
464
451
  assert_equal Date, bob.favorite_day.class
465
- @@ -186,7 +212,7 @@
466
-
467
- def test_add_remove_single_field_using_string_arguments
468
- assert !Person.column_methods_hash.include?(:last_name)
469
- -
470
- +
471
- ActiveRecord::Migration.add_column 'people', 'last_name', :string
472
-
473
- Person.reset_column_information
474
- @@ -212,94 +238,130 @@
452
+ @@ -321,145 +339,193 @@
475
453
  assert !Person.column_methods_hash.include?(:last_name)
476
454
  end
477
-
455
+
478
456
  - def test_add_rename
479
457
  - Person.delete_all
480
- -
481
- - begin
482
- - Person.connection.add_column "people", "girlfriend", :string
483
- - Person.create :girlfriend => 'bobette'
484
- -
485
- - Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
486
- -
487
- - Person.reset_column_information
488
- - bob = Person.find(:first)
489
- -
490
- - assert_equal "bobette", bob.exgirlfriend
491
- - ensure
492
- - Person.connection.remove_column("people", "girlfriend") rescue nil
493
458
  + # Ingres, Virtuoso:
494
459
  + # Neither supports renaming of columns. Skip test.
495
460
  + unless current_adapter?(:ODBCAdapter) &&
496
461
  + [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
497
462
  + def test_add_rename
498
463
  + Person.delete_all
499
- +
464
+
465
+ - begin
466
+ - Person.connection.add_column "people", "girlfriend", :string
467
+ - Person.create :girlfriend => 'bobette'
500
468
  + begin
501
- + # Some DBs complain girlfriend column already exists on two consecutive add_column calls
502
- + unless current_adapter?(:ODBCAdapter) && [:informix, :oracle, :mysql, :microsoftsqlserver, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
503
- + Person.connection.add_column "people", "girlfriend", :string
504
- + end
505
- + Person.connection.add_column "people", "girlfriend", :string, :limit => 40
506
- + Person.create :girlfriend => 'bobette'
507
- +
469
+ + Person.connection.add_column "people", "girlfriend", :string
470
+ + Person.create :girlfriend => 'bobette'
471
+
472
+ - Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
508
473
  + Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
509
- +
510
- + Person.reset_column_information
474
+
475
+ - Person.reset_column_information
476
+ - bob = Person.find(:first)
477
+ + Person.reset_column_information
511
478
  + bob = Person.find(:first)
512
- +
479
+
480
+ - assert_equal "bobette", bob.exgirlfriend
481
+ - ensure
482
+ - Person.connection.remove_column("people", "girlfriend") rescue nil
483
+ - Person.connection.remove_column("people", "exgirlfriend") rescue nil
513
484
  + assert_equal "bobette", bob.exgirlfriend
514
485
  + ensure
515
486
  + Person.connection.remove_column("people", "girlfriend") rescue nil
516
- Person.connection.remove_column("people", "exgirlfriend") rescue nil
517
- + end
487
+ + Person.connection.remove_column("people", "exgirlfriend") rescue nil
488
+ + end
518
489
  end
519
- -
490
+ -
520
491
  end
521
-
492
+
522
493
  - def test_rename_column_using_symbol_arguments
523
494
  - begin
524
495
  - Person.connection.rename_column :people, :first_name, :nick_name
@@ -540,7 +511,7 @@ Index: test/migration_test.rb
540
511
  + end
541
512
  end
542
513
  end
543
- -
514
+
544
515
  - def test_rename_column
545
516
  - begin
546
517
  - Person.connection.rename_column "people", "first_name", "nick_name"
@@ -549,8 +520,6 @@ Index: test/migration_test.rb
549
520
  - ensure
550
521
  - Person.connection.remove_column("people","nick_name")
551
522
  - Person.connection.add_column("people","first_name", :string)
552
- +
553
- + # Ingres and Virtuoso don't support renaming of columns. Skip test.
554
523
  + unless current_adapter?(:ODBCAdapter) && [:ingres, :virtuoso].include?(ActiveRecord::Base.connection.dbmsName)
555
524
  + def test_rename_column
556
525
  + begin
@@ -563,51 +532,86 @@ Index: test/migration_test.rb
563
532
  + end
564
533
  end
565
534
  end
566
-
535
+
567
536
  - def test_rename_table
568
537
  - begin
569
538
  - ActiveRecord::Base.connection.create_table :octopuses do |t|
570
539
  - t.column :url, :string
571
540
  - end
572
541
  - ActiveRecord::Base.connection.rename_table :octopuses, :octopi
573
- -
574
- - assert_nothing_raised do
575
- - if current_adapter?(:OracleAdapter)
576
- - # Oracle requires the explicit sequence value for the pk
577
- - ActiveRecord::Base.connection.execute "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')"
578
- - else
579
- - ActiveRecord::Base.connection.execute "INSERT INTO octopi (url) VALUES ('http://www.foreverflying.com/octopus-black7.jpg')"
580
542
  + # Ingres doesn't support renaming of tables. Skip test.
581
- + unless current_adapter?(:ODBCAdapter) && [:ingres].include?(ActiveRecord::Base.connection.dbmsName)
543
+ + unless current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
582
544
  + def test_rename_table
583
545
  + begin
584
546
  + ActiveRecord::Base.connection.create_table :octopuses do |t|
585
547
  + t.column :url, :string
586
- end
587
- + ActiveRecord::Base.connection.rename_table :octopuses, :octopi
588
- +
589
- + assert_nothing_raised do
590
- + if current_adapter?(:OracleAdapter) ||
591
- + current_adapter?(:ODBCAdapter) && [:oracle].include?(ActiveRecord::Base.connection.dbmsName)
592
- + # Oracle requires the explicit sequence value for the pk
593
- + ActiveRecord::Base.connection.execute "INSERT INTO octopi (id, url) VALUES (1, 'http://www.foreverflying.com/octopus-black7.jpg')"
594
- + else
595
- + ActiveRecord::Base.connection.execute "INSERT INTO octopi (url) VALUES ('http://www.foreverflying.com/octopus-black7.jpg')"
596
- + end
597
548
  + end
598
- +
549
+ + ActiveRecord::Base.connection.rename_table :octopuses, :octopi
550
+
551
+ - # Using explicit id in insert for compatibility across all databases
552
+ - con = ActiveRecord::Base.connection
553
+ - con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
554
+ - 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')" }
555
+ - con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
556
+ + # Using explicit id in insert for compatibility across all databases
557
+ + con = ActiveRecord::Base.connection
558
+ + con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
559
+ + 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')" }
560
+ + con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
561
+
562
+ - assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
599
563
  + assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
600
- +
564
+
565
+ - ensure
566
+ - ActiveRecord::Base.connection.drop_table :octopuses rescue nil
567
+ - ActiveRecord::Base.connection.drop_table :octopi rescue nil
601
568
  + ensure
602
569
  + ActiveRecord::Base.connection.drop_table :octopuses rescue nil
603
- + ActiveRecord::Base.connection.drop_table :octopi rescue nil
604
- end
605
- -
570
+ + ActiveRecord::Base.connection.drop_table :octopi rescue nil
571
+ + end
572
+ end
573
+ end
574
+
575
+ - def test_rename_table_with_an_index
576
+ - begin
577
+ - ActiveRecord::Base.connection.create_table :octopuses do |t|
578
+ - t.column :url, :string
579
+ - end
580
+ - ActiveRecord::Base.connection.add_index :octopuses, :url
581
+ + # Ingres doesn't support renaming of tables. Skip test.
582
+ + unless current_adapter?(:ODBCAdapter) && ActiveRecord::Base.connection.dbmsName == :ingres
583
+ + def test_rename_table_with_an_index
584
+ + begin
585
+ + ActiveRecord::Base.connection.create_table :octopuses do |t|
586
+ + t.column :url, :string
587
+ + end
588
+ + ActiveRecord::Base.connection.add_index :octopuses, :url
589
+
590
+ - ActiveRecord::Base.connection.rename_table :octopuses, :octopi
591
+ + ActiveRecord::Base.connection.rename_table :octopuses, :octopi
592
+
593
+ - # Using explicit id in insert for compatibility across all databases
594
+ - con = ActiveRecord::Base.connection
595
+ - con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
596
+ - 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')" }
597
+ - con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
598
+ + # Using explicit id in insert for compatibility across all databases
599
+ + con = ActiveRecord::Base.connection
600
+ + con.enable_identity_insert("octopi", true) if current_adapter?(:SybaseAdapter)
601
+ + 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')" }
602
+ + con.enable_identity_insert("octopi", false) if current_adapter?(:SybaseAdapter)
603
+
606
604
  - assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
607
- -
605
+ - assert ActiveRecord::Base.connection.indexes(:octopi).first.columns.include?("url")
608
606
  - ensure
609
607
  - ActiveRecord::Base.connection.drop_table :octopuses rescue nil
610
608
  - ActiveRecord::Base.connection.drop_table :octopi rescue nil
609
+ + assert_equal 'http://www.foreverflying.com/octopus-black7.jpg', ActiveRecord::Base.connection.select_value("SELECT url FROM octopi WHERE id=1")
610
+ + assert ActiveRecord::Base.connection.indexes(:octopi).first.columns.include?("url")
611
+ + ensure
612
+ + ActiveRecord::Base.connection.drop_table :octopuses rescue nil
613
+ + ActiveRecord::Base.connection.drop_table :octopi rescue nil
614
+ + end
611
615
  end
612
616
  end
613
617
 
@@ -632,76 +636,141 @@ Index: test/migration_test.rb
632
636
  + Person.connection.add_column 'people', 'age', initial_type
633
637
  + old_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
634
638
  + assert old_columns.find { |c| c.name == 'age' and c.type == initial_type }
635
- +
636
- + assert_nothing_raised { Person.connection.change_column "people", "age", new_type }
637
- +
638
- + new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
639
- + assert_nil new_columns.find { |c| c.name == 'age' and c.type == initial_type }
640
- + assert new_columns.find { |c| c.name == 'age' and c.type == new_type }
641
- + end
642
- + end
643
639
 
644
640
  - assert_nothing_raised { Person.connection.change_column "people", "age", :string }
645
- -
641
+ + assert_nothing_raised { Person.connection.change_column "people", "age", new_type }
642
+
646
643
  - new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
647
644
  - assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
648
645
  - assert new_columns.find { |c| c.name == 'age' and c.type == :string }
649
- - end
650
- -
646
+ + new_columns = Person.connection.columns(Person.table_name, "#{name} Columns")
647
+ + assert_nil new_columns.find { |c| c.name == 'age' and c.type == initial_type }
648
+ + assert new_columns.find { |c| c.name == 'age' and c.type == new_type }
649
+
650
+ - old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
651
+ - assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
652
+ - assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
653
+ - new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
654
+ - assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
655
+ - assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
656
+ - assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
657
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
658
+ + unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
659
+ + old_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
660
+ + assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
661
+ + assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
662
+ + new_columns = Topic.connection.columns(Topic.table_name, "#{name} Columns")
663
+ + assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
664
+ + assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
665
+ + assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
666
+ + end
667
+ + end
668
+ end
669
+
670
+ - def test_change_column_with_nil_default
671
+ - Person.connection.add_column "people", "contributor", :boolean, :default => true
672
+ - Person.reset_column_information
673
+ - assert Person.new.contributor?
674
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
675
+ + unless current_adapter?(:ODBCAdapter) && [:ingres, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
676
+ + def test_change_column_with_nil_default
677
+ + Person.connection.add_column "people", "contributor", :boolean, :default => true
678
+ + Person.reset_column_information
679
+ + assert Person.new.contributor?
680
+
681
+ - assert_nothing_raised { Person.connection.change_column "people", "contributor", :boolean, :default => nil }
682
+ - Person.reset_column_information
683
+ - assert !Person.new.contributor?
684
+ - assert_nil Person.new.contributor
685
+ + assert_nothing_raised { Person.connection.change_column "people", "contributor", :boolean, :default => nil }
686
+ + Person.reset_column_information
687
+ + a = Person.new.contributor
688
+ + assert !Person.new.contributor?
689
+ + assert_nil Person.new.contributor
690
+ + ensure
691
+ + Person.connection.remove_column "people", "contributor"
692
+ + end
693
+ end
694
+
651
695
  - def test_change_column_with_new_default
652
- - Person.connection.add_column "people", "administrator", :boolean, :default => 1
653
- - Person.reset_column_information
696
+ - Person.connection.add_column "people", "administrator", :boolean, :default => true
697
+ - Person.reset_column_information
654
698
  - assert Person.new.administrator?
655
- -
656
- - assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => 0 }
657
- - Person.reset_column_information
658
- - assert !Person.new.administrator?
659
- - end
660
- -
661
699
  + # Ingres doesn't support ALTER TABLE ADD COLUMN WITH NULL WITH DEFAULT.
662
700
  + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
663
701
  + unless current_adapter?(:ODBCAdapter) && [:ingres, :sybase].include?(ActiveRecord::Base.connection.dbmsName)
664
702
  + def test_change_column_with_new_default
665
- + Person.connection.add_column "people", "administrator", :boolean, :default => 1
666
- + Person.reset_column_information
703
+ + Person.connection.add_column "people", "administrator", :boolean, :default => true
704
+ + Person.reset_column_information
667
705
  + assert Person.new.administrator?
668
- +
669
- + assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => 0 }
670
- + Person.reset_column_information
706
+
707
+ - assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
708
+ - Person.reset_column_information
709
+ - assert !Person.new.administrator?
710
+ + assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
711
+ + Person.reset_column_information
671
712
  + assert !Person.new.administrator?
672
- + end
713
+ + end
714
+ end
715
+
716
+ - def test_change_column_default
717
+ - Person.connection.change_column_default "people", "first_name", "Tester"
718
+ - Person.reset_column_information
719
+ - assert_equal "Tester", Person.new.first_name
720
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
721
+ + unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
722
+ + def test_change_column_default
723
+ + Person.connection.change_column_default "people", "first_name", "Tester"
724
+ + Person.reset_column_information
725
+ + assert_equal "Tester", Person.new.first_name
726
+ + end
727
+ end
728
+ +
729
+ + # Sybase ASE's ALTER TABLE doesn't support altering a column's DEFAULT definition.
730
+ + unless current_adapter?(:ODBCAdapter) && [:sybase].include?(ActiveRecord::Base.connection.dbmsName)
731
+ + def test_change_column_default_to_null
732
+ + Person.connection.change_column_default "people", "first_name", nil
733
+ + Person.reset_column_information
734
+ + assert_nil Person.new.first_name
735
+ + end
673
736
  + end
674
- +
737
+
738
+ - def test_change_column_default_to_null
739
+ - Person.connection.change_column_default "people", "first_name", nil
740
+ - Person.reset_column_information
741
+ - assert_nil Person.new.first_name
742
+ - end
743
+ -
675
744
  def test_add_table
676
745
  assert !Reminder.table_exists?
677
-
678
- @@ -465,9 +527,20 @@
679
- Person.connection.drop_table :binary_testings rescue nil
680
-
681
- assert_nothing_raised {
682
- + if current_adapter?(:ODBCAdapter) && [:informix, :ingres].include?(ActiveRecord::Base.connection.dbmsName)
683
- + # Specifying a non-null default generates the following error:
684
- + # Informix:
685
- + # "Cannot specify non-null default value for blob column. (-594)"
686
- + # Ingres:
687
- + # "Cannot create a default on column of type 'long byte'"
688
- Person.connection.create_table :binary_testings do |t|
689
- + t.column "data", :binary
746
+
747
+ @@ -692,9 +758,20 @@
748
+ Person.connection.drop_table :binary_testings rescue nil
749
+
750
+ assert_nothing_raised {
751
+ + if current_adapter?(:ODBCAdapter) && [:informix, :ingres].include?(ActiveRecord::Base.connection.dbmsName)
752
+ + # Specifying a non-null default generates the following error:
753
+ + # Informix:
754
+ + # "Cannot specify non-null default value for blob column. (-594)"
755
+ + # Ingres:
756
+ + # "Cannot create a default on column of type 'long byte'"
757
+ + Person.connection.create_table :binary_testings do |t|
758
+ + t.column "data", :binary
759
+ + end
760
+ + else
761
+ Person.connection.create_table :binary_testings do |t|
762
+ t.column "data", :binary, :default => "", :null => false
763
+ end
690
764
  + end
691
- + else
692
- + Person.connection.create_table :binary_testings do |t|
693
- t.column "data", :binary, :default => "", :null => false
694
- end
695
- + end
696
- }
697
-
698
- columns = Person.connection.columns(:binary_testings)
699
- @@ -475,6 +548,8 @@
765
+ }
700
766
 
701
- if current_adapter?(:OracleAdapter)
702
- assert_equal "empty_blob()", data_column.default
703
- + elsif current_adapter?(:ODBCAdapter) && [:informix, :ingres].include?(ActiveRecord::Base.connection.dbmsName)
704
- + assert_nil data_column.default
705
- else
706
- assert_equal "", data_column.default
707
- end
767
+ columns = Person.connection.columns(:binary_testings)
768
+ @@ -702,6 +779,8 @@
769
+
770
+ if current_adapter?(:OracleAdapter)
771
+ assert_equal "empty_blob()", data_column.default
772
+ + elsif current_adapter?(:ODBCAdapter) && [:informix, :ingres].include?(ActiveRecord::Base.connection.dbmsName)
773
+ + assert_nil data_column.default
774
+ else
775
+ assert_equal "", data_column.default
776
+ end