diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 67b0291bcd..a8a4170a20 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* MySQL: detect when a NOT NULL column without a default value is misreported as default ''. Can't detect for string, text, and binary columns since '' is a legitimate default. #6156 [simon@redhillconsulting.com.au, obrie, Jeremy Kemper] + * Simplify association proxy implementation by factoring construct_scope out of method_missing. #6643 [martin] * Oracle: automatically detect the primary key. #6594 [vesaria, Michael Schoen] diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 6c75896233..574196e351 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -1,4 +1,5 @@ require 'active_record/connection_adapters/abstract_adapter' +require 'set' module MysqlCompat # add all_hashes method to standard mysql-c bindings or pure ruby version @@ -84,12 +85,30 @@ def self.mysql_connection(config) # :nodoc: module ConnectionAdapters class MysqlColumn < Column #:nodoc: + TYPES_ALLOWING_EMPTY_STRING_DEFAULT = Set.new([:binary, :string, :text]) + + def initialize(name, default, sql_type = nil, null = true) + super + self.default = nil if missing_default_forged_as_empty_string? + end + private def simplified_type(field_type) return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)") return :string if field_type =~ /enum/i super end + + # MySQL misreports NOT NULL column default when none is given. + # We can't detect this for columns which may have a legitimate '' + # default (string, text, binary) but we can for others (integer, + # datetime, boolean, and the rest). + # + # Test whether the column has default '', is not null, and is not + # a type allowing default ''. + def missing_default_forged_as_empty_string? + !null && default == '' && !TYPES_ALLOWING_EMPTY_STRING_DEFAULT.include?(type) + end end # The MySQL adapter will work with both Ruby/MySQL, which is a Ruby-based MySQL adapter that comes bundled with Active Record, and with diff --git a/activerecord/test/defaults_test.rb b/activerecord/test/defaults_test.rb index aba3c66de4..f15f422dc7 100644 --- a/activerecord/test/defaults_test.rb +++ b/activerecord/test/defaults_test.rb @@ -1,8 +1,24 @@ require 'abstract_unit' require 'fixtures/default' +require 'fixtures/entrant' -if current_adapter?(:PostgreSQLAdapter, :SQLServerAdapter) - class DefaultsTest < Test::Unit::TestCase +class DefaultTest < Test::Unit::TestCase + def test_nil_defaults_for_not_null_columns + column_defaults = + if current_adapter?(:MysqlAdapter) + { 'id' => nil, 'name' => '', 'course_id' => 0 } + else + { 'id' => nil, 'name' => nil, 'course_id' => nil } + end + + column_defaults.each do |name, default| + column = Entrant.columns_hash[name] + assert !column.null, "#{name} column should be NOT NULL" + assert_equal default, column.default, "#{name} column should be DEFAULT #{default.inspect}" + end + end + + if current_adapter?(:PostgreSQLAdapter, :SQLServerAdapter, :FirebirdAdapter, :OpenBaseAdapter) def test_default_integers default = Default.new assert_instance_of Fixnum, default.positive_integer diff --git a/activerecord/test/fixtures/db_definitions/postgresql.sql b/activerecord/test/fixtures/db_definitions/postgresql.sql index ce2c775aba..b5412c7400 100644 --- a/activerecord/test/fixtures/db_definitions/postgresql.sql +++ b/activerecord/test/fixtures/db_definitions/postgresql.sql @@ -130,8 +130,8 @@ CREATE TABLE auto_id_tests ( CREATE TABLE entrants ( id serial, - name text, - course_id integer + name text not null, + course_id integer not null ); CREATE TABLE colnametests (