odbc-rails 1.3 → 1.4

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 (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