rails: MySQL create_table loses ENGINE default info if options doesn't provide it.

Steps to reproduce

In ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter the default value "ENGINE=InnoDB" for options is provided. This value is propagated unless the create_table method receives another options String, in that case the ENGINE reference is lost.

How to reproduce

# frozen_string_literal: true

begin
  require "bundler/inline"
rescue LoadError => e
  $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
  raise e
end

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem "rails", github: "rails/rails"
  gem "arel", github: "rails/arel"
  gem "mysql2"
end

require "active_record"
require "minitest/autorun"
require "logger"

LOG_FILE_PATH = "mysql_create_table_engine.log"

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "mysql2", database: "test", username: "root", password: "")
ActiveRecord::Base.logger = Logger.new(LOG_FILE_PATH)

class CreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users, options: "DEFAULT CHARSET=utf8" do |t|
      t.string :name
      t.string :email
    end
  end
end

class CreateProducts < ActiveRecord::Migration[5.2]
  def change
    create_table :products do |t|
      t.string :name
      t.integer :price
    end
  end
end

class BugTest < Minitest::Test
  def test_create_table_loses_engine_info
    create_users_migration = CreateUsers.new
    create_users_migration.change

    logged_info = File.read(LOG_FILE_PATH)
    assert !logged_info.include?("ENGINE")

    create_users_migration = CreateProducts.new
    create_users_migration.change

    logged_info = File.read(LOG_FILE_PATH)
    assert logged_info.include?("ENGINE")

    File.delete(LOG_FILE_PATH)
  end
end

Expected behavior

Default ENGINE=InnoDB is provided by default unless options string provides a different ENGINE, in which case this new engine will override the default one, as documented in Rails Guides. See last paragraph at point 3.1 in Rails Migrations Guides.

Actual behavior

The generated SQL does NOT contain default ENGINE=InnoDB information if an options string is provided.

System configuration

Rails version: Edge

Ruby version: 2.4.1

I am preparing a fix which will satisfy the expected behavior. Please confirm the issue and I will submit a PR.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 18 (16 by maintainers)

Most upvoted comments

Fixed by #31177.

Thanks @albertoalmagro !

In case anyone finds my comment above, here’s how I’m working around this issue:

https://gist.github.com/blimmer/1ef562ac5981dd8f65653075f16c1157

The reason for explicitly passing ENGINE=InnoDB is because the default storage engine was MyISAM in MySQL 5.1. This is not absolutely necessary in MySQL 5.5 unless you intentionally change the server’s default configuration. And MySQL 5.1 had already been EOL in Dec 2013. So I’m not excited to keep the passing default for a future version of Rails.

https://dev.mysql.com/doc/refman/5.5/en/innodb-introduction.html