mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
MySQL: ROW_FORMAT=DYNAMIC
create table option by default
Since MySQL 5.7.9, the `innodb_default_row_format` option defines the default row format for InnoDB tables. The default setting is `DYNAMIC`. The row format is required for indexing on `varchar(255)` with `utf8mb4` columns. As long as using MySQL 5.6, CI won't be passed even if MySQL server setting is properly configured the same as MySQL 5.7 (`innodb_file_per_table = 1`, `innodb_file_format = 'Barracuda'`, and `innodb_large_prefix = 1`) since InnoDB table is created as the row format `COMPACT` by default on MySQL 5.6, therefore indexing on string with `utf8mb4` columns aren't succeeded. Making `ROW_FORMAT=DYNAMIC` create table option by default for legacy MySQL version would mitigate the indexing issue on the user side, and it makes CI would be passed on MySQL 5.6 which is configured properly.
This commit is contained in:
parent
0fa5b5510c
commit
a1652c196e
3 changed files with 40 additions and 7 deletions
|
@ -1,3 +1,11 @@
|
|||
* MySQL: `ROW_FORMAT=DYNAMIC` create table option by default.
|
||||
|
||||
Since MySQL 5.7.9, the `innodb_default_row_format` option defines the default row
|
||||
format for InnoDB tables. The default setting is `DYNAMIC`.
|
||||
The row format is required for indexing on `varchar(255)` with `utf8mb4` columns.
|
||||
|
||||
*Ryuta Kamizono*
|
||||
|
||||
* Fix join table column quoting with SQLite.
|
||||
|
||||
*Gannon McGibbon*
|
||||
|
|
|
@ -77,6 +77,10 @@ module ActiveRecord
|
|||
super
|
||||
end
|
||||
|
||||
def create_table(table_name, options: default_row_format, **)
|
||||
super
|
||||
end
|
||||
|
||||
def internal_string_options_for_primary_key
|
||||
super.tap do |options|
|
||||
if !row_format_dynamic_by_default? && CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
|
||||
|
@ -104,6 +108,20 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
def default_row_format
|
||||
return if row_format_dynamic_by_default?
|
||||
|
||||
unless defined?(@default_row_format)
|
||||
if query_value("SELECT @@innodb_file_per_table = 1 AND @@innodb_file_format = 'Barracuda'") == 1
|
||||
@default_row_format = "ROW_FORMAT=DYNAMIC"
|
||||
else
|
||||
@default_row_format = nil
|
||||
end
|
||||
end
|
||||
|
||||
@default_row_format
|
||||
end
|
||||
|
||||
def schema_creation
|
||||
MySQL::SchemaCreation.new(self)
|
||||
end
|
||||
|
|
|
@ -7,6 +7,7 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase
|
|||
include ConnectionHelper
|
||||
|
||||
def setup
|
||||
ActiveRecord::Base.connection.send(:default_row_format)
|
||||
ActiveRecord::Base.connection.singleton_class.class_eval do
|
||||
alias_method :execute_without_stub, :execute
|
||||
def execute(sql, name = nil) sql end
|
||||
|
@ -68,18 +69,18 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase
|
|||
def (ActiveRecord::Base.connection).data_source_exists?(*); false; end
|
||||
|
||||
%w(SPATIAL FULLTEXT UNIQUE).each do |type|
|
||||
expected = "CREATE TABLE `people` (#{type} INDEX `index_people_on_last_name` (`last_name`))"
|
||||
expected = /\ACREATE TABLE `people` \(#{type} INDEX `index_people_on_last_name` \(`last_name`\)\)/
|
||||
actual = ActiveRecord::Base.connection.create_table(:people, id: false) do |t|
|
||||
t.index :last_name, type: type
|
||||
end
|
||||
assert_equal expected, actual
|
||||
assert_match expected, actual
|
||||
end
|
||||
|
||||
expected = "CREATE TABLE `people` ( INDEX `index_people_on_last_name` USING btree (`last_name`(10)))"
|
||||
expected = /\ACREATE TABLE `people` \( INDEX `index_people_on_last_name` USING btree \(`last_name`\(10\)\)\)/
|
||||
actual = ActiveRecord::Base.connection.create_table(:people, id: false) do |t|
|
||||
t.index :last_name, length: 10, using: :btree
|
||||
end
|
||||
assert_equal expected, actual
|
||||
assert_match expected, actual
|
||||
end
|
||||
|
||||
def test_index_in_bulk_change
|
||||
|
@ -106,7 +107,13 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase
|
|||
end
|
||||
|
||||
def test_create_mysql_database_with_encoding
|
||||
assert_equal "CREATE DATABASE `matt` DEFAULT CHARACTER SET `utf8mb4`", create_database(:matt)
|
||||
if row_format_dynamic_by_default?
|
||||
assert_equal "CREATE DATABASE `matt` DEFAULT CHARACTER SET `utf8mb4`", create_database(:matt)
|
||||
else
|
||||
error = assert_raises(RuntimeError) { create_database(:matt) }
|
||||
expected = "Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns."
|
||||
assert_equal expected, error.message
|
||||
end
|
||||
assert_equal "CREATE DATABASE `aimonetti` DEFAULT CHARACTER SET `latin1`", create_database(:aimonetti, charset: "latin1")
|
||||
assert_equal "CREATE DATABASE `matt_aimonetti` DEFAULT COLLATE `utf8mb4_bin`", create_database(:matt_aimonetti, collation: "utf8mb4_bin")
|
||||
end
|
||||
|
@ -163,12 +170,12 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase
|
|||
[:temp],
|
||||
returns: false
|
||||
) do
|
||||
expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`)) AS SELECT id, name, zip FROM a_really_complicated_query"
|
||||
expected = /\ACREATE TEMPORARY TABLE `temp` \( INDEX `index_temp_on_zip` \(`zip`\)\)(?: ROW_FORMAT=DYNAMIC)? AS SELECT id, name, zip FROM a_really_complicated_query/
|
||||
actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t|
|
||||
t.index :zip
|
||||
end
|
||||
|
||||
assert_equal expected, actual
|
||||
assert_match expected, actual
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue