Deal with MySQL's quirky handling of defaults and blob/text columns

[#1043 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
This commit is contained in:
Frederick Cheung
2008-09-14 12:06:10 +01:00
committed by Jeremy Kemper
parent d95943b276
commit d51a39ff50
6 changed files with 49 additions and 3 deletions

View File

@@ -1,5 +1,7 @@
*Edge*
* MySQL: cope with quirky default values for not-null text columns. #1043 [Frederick Cheung]
* Multiparameter attributes skip time zone conversion for time-only columns [#1030 state:resolved] [Geoff Buesing]
* Base.skip_time_zone_conversion_for_attributes uses class_inheritable_accessor, so that subclasses don't overwrite Base [#346 state:resolved] [miloops]

View File

@@ -40,6 +40,10 @@ module ActiveRecord
type == :integer || type == :float || type == :decimal
end
def has_default?
!default.nil?
end
# Returns the Ruby class that corresponds to the abstract data type.
def klass
case type

View File

@@ -80,7 +80,7 @@ module ActiveRecord
def extract_default(default)
if type == :binary || type == :text
if default.blank?
nil
return null ? nil : ''
else
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
end
@@ -91,6 +91,11 @@ module ActiveRecord
end
end
def has_default?
return false if type == :binary || type == :text #mysql forbids defaults on blob and text columns
super
end
private
def simplified_type(field_type)
return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)")

View File

@@ -102,7 +102,7 @@ HEADER
spec[:precision] = column.precision.inspect if !column.precision.nil?
spec[:scale] = column.scale.inspect if !column.scale.nil?
spec[:null] = 'false' if !column.null
spec[:default] = default_string(column.default) if !column.default.nil?
spec[:default] = default_string(column.default) if column.has_default?
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
spec
end.compact

View File

@@ -19,6 +19,37 @@ class DefaultTest < ActiveRecord::TestCase
end
if current_adapter?(:MysqlAdapter)
#MySQL 5 and higher is quirky with not null text/blob columns.
#With MySQL Text/blob columns cannot have defaults. If the column is not null MySQL will report that the column has a null default
#but it behaves as though the column had a default of ''
def test_mysql_text_not_null_defaults
klass = Class.new(ActiveRecord::Base)
klass.table_name = 'test_mysql_text_not_null_defaults'
klass.connection.create_table klass.table_name do |t|
t.column :non_null_text, :text, :null => false
t.column :non_null_blob, :blob, :null => false
t.column :null_text, :text, :null => true
t.column :null_blob, :blob, :null => true
end
assert_equal '', klass.columns_hash['non_null_blob'].default
assert_equal '', klass.columns_hash['non_null_text'].default
assert_equal nil, klass.columns_hash['null_blob'].default
assert_equal nil, klass.columns_hash['null_text'].default
assert_nothing_raised do
instance = klass.create!
assert_equal '', instance.non_null_text
assert_equal '', instance.non_null_blob
assert_nil instance.null_text
assert_nil instance.null_blob
end
ensure
klass.connection.drop_table(klass.table_name) rescue nil
end
# MySQL uses an implicit default 0 rather than NULL unless in strict mode.
# We use an implicit NULL so schema.rb is compatible with other databases.
def test_mysql_integer_not_null_defaults

View File

@@ -1133,7 +1133,11 @@ if ActiveRecord::Base.connection.supports_migrations?
columns = Person.connection.columns(:binary_testings)
data_column = columns.detect { |c| c.name == "data" }
assert_nil data_column.default
if current_adapter?(:MysqlAdapter)
assert_equal '', data_column.default
else
assert_nil data_column.default
end
Person.connection.drop_table :binary_testings rescue nil
end