diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 58992f9..b8cd2f1 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -271,7 +271,7 @@ module ActiveRecord
column_options = {}
column_options[:null] = null unless null.nil?
column_options[:default] = default unless default.nil?
- add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key
+ add_column_options!(column_sql, column_options)
column_sql
end
alias to_s :to_sql
@@ -315,8 +315,8 @@ module ActiveRecord
# Appends a primary key definition to the table definition.
# Can be called multiple times, but this is probably not a good idea.
- def primary_key(name)
- column(name, :primary_key)
+ def primary_key(name, options = {})
+ column(name, :primary_key, options)
end
# Returns a ColumnDefinition for the column with name +name+.
@@ -338,7 +338,7 @@ module ActiveRecord
#
# Available options are (none of these exists by default):
# * :limit -
- # Requests a maximum column length. This is number of characters for :string and :text columns and number of bytes for :binary and :integer columns.
+ # Requests a maximum column length. This is number of characters for :string and :text columns and number of bytes for :binary, :integer and :primary_key columns.
# * :default -
# The column's default value. Use nil for NULL.
# * :null -
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 1e452ae..6bd382a 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -177,7 +177,7 @@ module ActiveRecord
QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
NATIVE_DATABASE_TYPES = {
- :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY".freeze,
+ :primary_key => { :name => "DEFAULT NULL auto_increment PRIMARY KEY", :limit => 4 },
:string => { :name => "varchar", :limit => 255 },
:text => { :name => "text" },
:integer => { :name => "int", :limit => 4 },
@@ -496,15 +496,21 @@ module ActiveRecord
# Maps logical Rails types to MySQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
- return super unless type.to_s == 'integer'
-
- case limit
- when 1; 'tinyint'
- when 2; 'smallint'
- when 3; 'mediumint'
- when nil, 4, 11; 'int(11)' # compatibility with MySQL default
- when 5..8; 'bigint'
- else raise(ActiveRecordError, "No integer type has byte size #{limit}")
+ case type.to_s
+ when 'primary_key':
+ native = native_database_types[:primary_key]
+ return type_to_sql('integer', limit) + ' ' + native[:name]
+ when 'integer':
+ case limit
+ when 1; 'tinyint'
+ when 2; 'smallint'
+ when 3; 'mediumint'
+ when nil, 4, 11; 'int(11)' # compatibility with MySQL default
+ when 5..8; 'bigint'
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}")
+ end
+ else
+ super
end
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 2181bdf..ef55c28 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -75,34 +75,29 @@ HEADER
columns = @connection.columns(table)
begin
tbl = StringIO.new
+ tbl.puts " create_table #{table.inspect}, :id => false, :force => true do |t|"
if @connection.respond_to?(:pk_and_sequence_for)
pk, pk_seq = @connection.pk_and_sequence_for(table)
end
pk ||= 'id'
- tbl.print " create_table #{table.inspect}"
- if columns.detect { |c| c.name == pk }
- if pk != 'id'
- tbl.print %Q(, :primary_key => "#{pk}")
- end
- else
- tbl.print ", :id => false"
- end
- tbl.print ", :force => true"
- tbl.puts " do |t|"
-
column_specs = columns.map do |column|
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
- next if column.name == pk
spec = {}
- spec[:name] = column.name.inspect
- spec[:type] = column.type.to_s
- spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
- 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.has_default?
+ spec[:name] = column.name.inspect
+ spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
+
+ if column.name == pk
+ spec[:type] = 'primary_key'
+ else
+ spec[:type] = column.type.to_s
+ 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.has_default?
+ end
+
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
spec
end.compact
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index ee7e285..11f8831 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -41,7 +41,7 @@ class SchemaDumperTest < ActiveRecord::TestCase
next if column_set.empty?
lengths = column_set.map do |column|
- if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
+ if match = column.match(/t\.(?:primary_key|integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
match[0].length
end
end
@@ -156,9 +156,16 @@ class SchemaDumperTest < ActiveRecord::TestCase
def test_mysql_schema_dump_should_honor_nonstandard_primary_keys
output = standard_dump
- match = output.match(%r{create_table "movies"(.*)do})
+ match = output.match(%r{create_table "movies",.*?:id => false\b.*? do (.*?)\bend$}m)
assert_not_nil(match, "nonstandardpk table not found")
- assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
+ assert_match %r(t.primary_key\s+"movieid"$), match[1], "non-standard primary key not preserved"
+ end
+
+ def test_mysql_schema_dump_should_honor_primary_keys_limits
+ output = standard_dump
+ match = output.match(%r{create_table "primary_key_limit",.*?:id => false\b.*? do (.*?)\bend$}m)
+ assert_not_nil(match, output)
+ assert_match %r(t.primary_key\s+"id",\s+:limit => \d+$), match[1], "limit option not found on primary key"
end
def test_schema_dump_includes_length_for_mysql_blob_and_text_fields
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 6217e3b..9cf81df 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -324,6 +324,10 @@ ActiveRecord::Schema.define do
t.integer :price
end
+ create_table :primary_key_limit, :force => true, :id => false do |t|
+ t.primary_key :id, :limit => 8
+ end
+
create_table :projects, :force => true do |t|
t.string :name
t.string :type