Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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

[#1043 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
  • Loading branch information...
commit d51a39ff500d94ea4a81fbc22f0d1c540e83f4e1 1 parent d95943b
@fcheung fcheung authored jeremy committed
View
2  activerecord/CHANGELOG
@@ -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
4 activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -40,6 +40,10 @@ def number?
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
7 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -80,7 +80,7 @@ class MysqlColumn < Column #:nodoc:
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 @@ def extract_default(default)
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
2  activerecord/lib/active_record/schema_dumper.rb
@@ -102,7 +102,7 @@ def table(table, stream)
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
31 activerecord/test/cases/defaults_test.rb
@@ -19,6 +19,37 @@ def test_nil_defaults_for_not_null_columns
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
6 activerecord/test/cases/migration_test.rb
@@ -1133,7 +1133,11 @@ def test_create_table_with_binary_column
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
Please sign in to comment.
Something went wrong with that request. Please try again.