aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/adapters/mysql2
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/test/cases/adapters/mysql2')
-rw-r--r--activerecord/test/cases/adapters/mysql2/active_schema_test.rb155
-rw-r--r--activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb50
-rw-r--r--activerecord/test/cases/adapters/mysql2/boolean_test.rb91
-rw-r--r--activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb55
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb116
-rw-r--r--activerecord/test/cases/adapters/mysql2/enum_test.rb10
-rw-r--r--activerecord/test/cases/adapters/mysql2/explain_test.rb26
-rw-r--r--activerecord/test/cases/adapters/mysql2/reserved_word_test.rb152
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb39
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_test.rb79
-rw-r--r--activerecord/test/cases/adapters/mysql2/sql_types_test.rb14
11 files changed, 787 insertions, 0 deletions
diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb
new file mode 100644
index 0000000000..cefc3e3c7e
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb
@@ -0,0 +1,155 @@
+require "cases/helper"
+require 'support/connection_helper'
+
+class ActiveSchemaTest < ActiveRecord::TestCase
+ include ConnectionHelper
+
+ def setup
+ ActiveRecord::Base.connection.singleton_class.class_eval do
+ alias_method :execute_without_stub, :execute
+ def execute(sql, name = nil) return sql end
+ end
+ end
+
+ teardown do
+ reset_connection
+ end
+
+ def test_add_index
+ # add_index calls table_exists? and index_name_exists? which can't work since execute is stubbed
+ def (ActiveRecord::Base.connection).table_exists?(*); true; end
+ def (ActiveRecord::Base.connection).index_name_exists?(*); false; end
+
+ expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) "
+ assert_equal expected, add_index(:people, :last_name, :length => nil)
+
+ expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`(10)) "
+ assert_equal expected, add_index(:people, :last_name, :length => 10)
+
+ expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15)) "
+ assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15)
+
+ expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`) "
+ assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15})
+
+ expected = "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10)) "
+ assert_equal expected, add_index(:people, [:last_name, :first_name], :length => {:last_name => 15, :first_name => 10})
+
+ %w(SPATIAL FULLTEXT UNIQUE).each do |type|
+ expected = "CREATE #{type} INDEX `index_people_on_last_name` ON `people` (`last_name`) "
+ assert_equal expected, add_index(:people, :last_name, :type => type)
+ end
+
+ %w(btree hash).each do |using|
+ expected = "CREATE INDEX `index_people_on_last_name` USING #{using} ON `people` (`last_name`) "
+ assert_equal expected, add_index(:people, :last_name, :using => using)
+ end
+
+ expected = "CREATE INDEX `index_people_on_last_name` USING btree ON `people` (`last_name`(10)) "
+ assert_equal expected, add_index(:people, :last_name, :length => 10, :using => :btree)
+
+ expected = "CREATE INDEX `index_people_on_last_name` USING btree ON `people` (`last_name`(10)) ALGORITHM = COPY"
+ assert_equal expected, add_index(:people, :last_name, :length => 10, using: :btree, algorithm: :copy)
+
+ assert_raise ArgumentError do
+ add_index(:people, :last_name, algorithm: :coyp)
+ end
+
+ expected = "CREATE INDEX `index_people_on_last_name_and_first_name` USING btree ON `people` (`last_name`(15), `first_name`(15)) "
+ assert_equal expected, add_index(:people, [:last_name, :first_name], :length => 15, :using => :btree)
+ end
+
+ def test_drop_table
+ assert_equal "DROP TABLE `people`", drop_table(:people)
+ end
+
+ if current_adapter?(:Mysql2Adapter)
+ def test_create_mysql_database_with_encoding
+ assert_equal "CREATE DATABASE `matt` DEFAULT CHARACTER SET `utf8`", create_database(:matt)
+ assert_equal "CREATE DATABASE `aimonetti` DEFAULT CHARACTER SET `latin1`", create_database(:aimonetti, {:charset => 'latin1'})
+ assert_equal "CREATE DATABASE `matt_aimonetti` DEFAULT CHARACTER SET `big5` COLLATE `big5_chinese_ci`", create_database(:matt_aimonetti, {:charset => :big5, :collation => :big5_chinese_ci})
+ end
+
+ def test_recreate_mysql_database_with_encoding
+ create_database(:luca, {:charset => 'latin1'})
+ assert_equal "CREATE DATABASE `luca` DEFAULT CHARACTER SET `latin1`", recreate_database(:luca, {:charset => 'latin1'})
+ end
+ end
+
+ def test_add_column
+ assert_equal "ALTER TABLE `people` ADD `last_name` varchar(255)", add_column(:people, :last_name, :string)
+ end
+
+ def test_add_column_with_limit
+ assert_equal "ALTER TABLE `people` ADD `key` varchar(32)", add_column(:people, :key, :string, :limit => 32)
+ end
+
+ def test_drop_table_with_specific_database
+ assert_equal "DROP TABLE `otherdb`.`people`", drop_table('otherdb.people')
+ end
+
+ def test_add_timestamps
+ with_real_execute do
+ begin
+ ActiveRecord::Base.connection.create_table :delete_me
+ ActiveRecord::Base.connection.add_timestamps :delete_me
+ assert column_present?('delete_me', 'updated_at', 'datetime')
+ assert column_present?('delete_me', 'created_at', 'datetime')
+ ensure
+ ActiveRecord::Base.connection.drop_table :delete_me rescue nil
+ end
+ end
+ end
+
+ def test_remove_timestamps
+ with_real_execute do
+ begin
+ ActiveRecord::Base.connection.create_table :delete_me do |t|
+ t.timestamps
+ end
+ ActiveRecord::Base.connection.remove_timestamps :delete_me
+ assert !column_present?('delete_me', 'updated_at', 'datetime')
+ assert !column_present?('delete_me', 'created_at', 'datetime')
+ ensure
+ ActiveRecord::Base.connection.drop_table :delete_me rescue nil
+ end
+ end
+ end
+
+ def test_indexes_in_create
+ ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false)
+ ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false)
+
+ expected = "CREATE TEMPORARY TABLE `temp` ( INDEX `index_temp_on_zip` (`zip`) ) ENGINE=InnoDB 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
+ end
+
+ private
+ def with_real_execute
+ ActiveRecord::Base.connection.singleton_class.class_eval do
+ alias_method :execute_with_stub, :execute
+ remove_method :execute
+ alias_method :execute, :execute_without_stub
+ end
+
+ yield
+ ensure
+ ActiveRecord::Base.connection.singleton_class.class_eval do
+ remove_method :execute
+ alias_method :execute, :execute_with_stub
+ end
+ end
+
+ def method_missing(method_symbol, *arguments)
+ ActiveRecord::Base.connection.send(method_symbol, *arguments)
+ end
+
+ def column_present?(table_name, column_name, type)
+ results = ActiveRecord::Base.connection.select_all("SHOW FIELDS FROM #{table_name} LIKE '#{column_name}'")
+ results.first && results.first['Type'] == type
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
new file mode 100644
index 0000000000..5e8065d80d
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
@@ -0,0 +1,50 @@
+require "cases/helper"
+require 'models/topic'
+
+module ActiveRecord
+ module ConnectionAdapters
+ class Mysql2Adapter
+ class BindParameterTest < ActiveRecord::TestCase
+ fixtures :topics
+
+ def test_update_question_marks
+ str = "foo?bar"
+ x = Topic.first
+ x.title = str
+ x.content = str
+ x.save!
+ x.reload
+ assert_equal str, x.title
+ assert_equal str, x.content
+ end
+
+ def test_create_question_marks
+ str = "foo?bar"
+ x = Topic.create!(:title => str, :content => str)
+ x.reload
+ assert_equal str, x.title
+ assert_equal str, x.content
+ end
+
+ def test_update_null_bytes
+ str = "foo\0bar"
+ x = Topic.first
+ x.title = str
+ x.content = str
+ x.save!
+ x.reload
+ assert_equal str, x.title
+ assert_equal str, x.content
+ end
+
+ def test_create_null_bytes
+ str = "foo\0bar"
+ x = Topic.create!(:title => str, :content => str)
+ x.reload
+ assert_equal str, x.title
+ assert_equal str, x.content
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/boolean_test.rb b/activerecord/test/cases/adapters/mysql2/boolean_test.rb
new file mode 100644
index 0000000000..f3c711a64b
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/boolean_test.rb
@@ -0,0 +1,91 @@
+require "cases/helper"
+
+class Mysql2BooleanTest < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ class BooleanType < ActiveRecord::Base
+ self.table_name = "mysql_booleans"
+ end
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table("mysql_booleans") do |t|
+ t.boolean "archived"
+ t.string "published", limit: 1
+ end
+ BooleanType.reset_column_information
+
+ @emulate_booleans = ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans
+ end
+
+ teardown do
+ emulate_booleans @emulate_booleans
+ @connection.drop_table "mysql_booleans"
+ end
+
+ test "column type with emulated booleans" do
+ emulate_booleans true
+
+ assert_equal :boolean, boolean_column.type
+ assert_equal :string, string_column.type
+ end
+
+ test "column type without emulated booleans" do
+ emulate_booleans false
+
+ assert_equal :integer, boolean_column.type
+ assert_equal :string, string_column.type
+ end
+
+ test "test type casting with emulated booleans" do
+ emulate_booleans true
+
+ boolean = BooleanType.create!(archived: true, published: true)
+ attributes = boolean.reload.attributes_before_type_cast
+
+ assert_equal 1, attributes["archived"]
+ assert_equal "1", attributes["published"]
+
+ assert_equal 1, @connection.type_cast(true, boolean_column)
+ assert_equal "1", @connection.type_cast(true, string_column)
+ end
+
+ test "test type casting without emulated booleans" do
+ emulate_booleans false
+
+ boolean = BooleanType.create!(archived: true, published: true)
+ attributes = boolean.reload.attributes_before_type_cast
+
+ assert_equal 1, attributes["archived"]
+ assert_equal "1", attributes["published"]
+
+ assert_equal 1, @connection.type_cast(true, boolean_column)
+ assert_equal "1", @connection.type_cast(true, string_column)
+ end
+
+ test "with booleans stored as 1 and 0" do
+ @connection.execute "INSERT INTO mysql_booleans(archived, published) VALUES(1, '1')"
+ boolean = BooleanType.first
+ assert_equal true, boolean.archived
+ assert_equal "1", boolean.published
+ end
+
+ test "with booleans stored as t" do
+ @connection.execute "INSERT INTO mysql_booleans(published) VALUES('t')"
+ boolean = BooleanType.first
+ assert_equal "t", boolean.published
+ end
+
+ def boolean_column
+ BooleanType.columns.find { |c| c.name == 'archived' }
+ end
+
+ def string_column
+ BooleanType.columns.find { |c| c.name == 'published' }
+ end
+
+ def emulate_booleans(value)
+ ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans = value
+ BooleanType.reset_column_information
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
new file mode 100644
index 0000000000..09bebf3071
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
@@ -0,0 +1,55 @@
+require "cases/helper"
+require 'models/person'
+
+class Mysql2CaseSensitivityTest < ActiveRecord::TestCase
+ class CollationTest < ActiveRecord::Base
+ end
+
+ repair_validations(CollationTest)
+
+ def test_columns_include_collation_different_from_table
+ assert_equal 'utf8_bin', CollationTest.columns_hash['string_cs_column'].collation
+ assert_equal 'utf8_general_ci', CollationTest.columns_hash['string_ci_column'].collation
+ end
+
+ def test_case_sensitive
+ assert !CollationTest.columns_hash['string_ci_column'].case_sensitive?
+ assert CollationTest.columns_hash['string_cs_column'].case_sensitive?
+ end
+
+ def test_case_insensitive_comparison_for_ci_column
+ CollationTest.validates_uniqueness_of(:string_ci_column, :case_sensitive => false)
+ CollationTest.create!(:string_ci_column => 'A')
+ invalid = CollationTest.new(:string_ci_column => 'a')
+ queries = assert_sql { invalid.save }
+ ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) }
+ assert_no_match(/lower/i, ci_uniqueness_query)
+ end
+
+ def test_case_insensitive_comparison_for_cs_column
+ CollationTest.validates_uniqueness_of(:string_cs_column, :case_sensitive => false)
+ CollationTest.create!(:string_cs_column => 'A')
+ invalid = CollationTest.new(:string_cs_column => 'a')
+ queries = assert_sql { invalid.save }
+ cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/)}
+ assert_match(/lower/i, cs_uniqueness_query)
+ end
+
+ def test_case_sensitive_comparison_for_ci_column
+ CollationTest.validates_uniqueness_of(:string_ci_column, :case_sensitive => true)
+ CollationTest.create!(:string_ci_column => 'A')
+ invalid = CollationTest.new(:string_ci_column => 'A')
+ queries = assert_sql { invalid.save }
+ ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) }
+ assert_match(/binary/i, ci_uniqueness_query)
+ end
+
+ def test_case_sensitive_comparison_for_cs_column
+ CollationTest.validates_uniqueness_of(:string_cs_column, :case_sensitive => true)
+ CollationTest.create!(:string_cs_column => 'A')
+ invalid = CollationTest.new(:string_cs_column => 'A')
+ queries = assert_sql { invalid.save }
+ cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
+ assert_no_match(/binary/i, cs_uniqueness_query)
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
new file mode 100644
index 0000000000..3b35e69e0d
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -0,0 +1,116 @@
+require "cases/helper"
+require 'support/connection_helper'
+
+class MysqlConnectionTest < ActiveRecord::TestCase
+ include ConnectionHelper
+
+ def setup
+ super
+ @subscriber = SQLSubscriber.new
+ @subscription = ActiveSupport::Notifications.subscribe('sql.active_record', @subscriber)
+ @connection = ActiveRecord::Base.connection
+ end
+
+ def teardown
+ ActiveSupport::Notifications.unsubscribe(@subscription)
+ super
+ end
+
+ def test_bad_connection
+ assert_raise ActiveRecord::NoDatabaseError do
+ configuration = ActiveRecord::Base.configurations['arunit'].merge(database: 'inexistent_activerecord_unittest')
+ connection = ActiveRecord::Base.mysql2_connection(configuration)
+ connection.exec_query('drop table if exists ex')
+ end
+ end
+
+ def test_no_automatic_reconnection_after_timeout
+ assert @connection.active?
+ @connection.update('set @@wait_timeout=1')
+ sleep 2
+ assert !@connection.active?
+
+ # Repair all fixture connections so other tests won't break.
+ @fixture_connections.each do |c|
+ c.verify!
+ end
+ end
+
+ def test_successful_reconnection_after_timeout_with_manual_reconnect
+ assert @connection.active?
+ @connection.update('set @@wait_timeout=1')
+ sleep 2
+ @connection.reconnect!
+ assert @connection.active?
+ end
+
+ def test_successful_reconnection_after_timeout_with_verify
+ assert @connection.active?
+ @connection.update('set @@wait_timeout=1')
+ sleep 2
+ @connection.verify!
+ assert @connection.active?
+ end
+
+ # TODO: Below is a straight up copy/paste from mysql/connection_test.rb
+ # I'm not sure what the correct way is to share these tests between
+ # adapters in minitest.
+ def test_mysql_default_in_strict_mode
+ result = @connection.exec_query "SELECT @@SESSION.sql_mode"
+ assert_equal [["STRICT_ALL_TABLES"]], result.rows
+ end
+
+ def test_mysql_strict_mode_disabled
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.merge({:strict => false}))
+ result = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.sql_mode"
+ assert_equal [['']], result.rows
+ end
+ end
+
+ def test_mysql_set_session_variable
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:default_week_format => 3}}))
+ session_mode = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.DEFAULT_WEEK_FORMAT"
+ assert_equal 3, session_mode.rows.first.first.to_i
+ end
+ end
+
+ def test_mysql_sql_mode_variable_overides_strict_mode
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { 'sql_mode' => 'ansi' }))
+ result = ActiveRecord::Base.connection.exec_query 'SELECT @@SESSION.sql_mode'
+ assert_not_equal [['STRICT_ALL_TABLES']], result.rows
+ end
+ end
+
+ def test_mysql_set_session_variable_to_default
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:default_week_format => :default}}))
+ global_mode = ActiveRecord::Base.connection.exec_query "SELECT @@GLOBAL.DEFAULT_WEEK_FORMAT"
+ session_mode = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.DEFAULT_WEEK_FORMAT"
+ assert_equal global_mode.rows, session_mode.rows
+ end
+ end
+
+ def test_logs_name_show_variable
+ @connection.show_variable 'foo'
+ assert_equal "SCHEMA", @subscriber.logged[0][1]
+ end
+
+ def test_logs_name_rename_column_sql
+ @connection.execute "CREATE TABLE `bar_baz` (`foo` varchar(255))"
+ @subscriber.logged.clear
+ @connection.send(:rename_column_sql, 'bar_baz', 'foo', 'foo2')
+ assert_equal "SCHEMA", @subscriber.logged[0][1]
+ ensure
+ @connection.execute "DROP TABLE `bar_baz`"
+ end
+
+ if mysql_56?
+ def test_quote_time_usec
+ assert_equal "'1970-01-01 00:00:00.000000'", @connection.quote(Time.at(0))
+ assert_equal "'1970-01-01 00:00:00.000000'", @connection.quote(Time.at(0).to_datetime)
+ end
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/enum_test.rb b/activerecord/test/cases/adapters/mysql2/enum_test.rb
new file mode 100644
index 0000000000..6dd9a5ec87
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/enum_test.rb
@@ -0,0 +1,10 @@
+require "cases/helper"
+
+class Mysql2EnumTest < ActiveRecord::TestCase
+ class EnumTest < ActiveRecord::Base
+ end
+
+ def test_enum_limit
+ assert_equal 6, EnumTest.columns.first.limit
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/explain_test.rb b/activerecord/test/cases/adapters/mysql2/explain_test.rb
new file mode 100644
index 0000000000..675703caa1
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/explain_test.rb
@@ -0,0 +1,26 @@
+require "cases/helper"
+require 'models/developer'
+
+module ActiveRecord
+ module ConnectionAdapters
+ class Mysql2Adapter
+ class ExplainTest < ActiveRecord::TestCase
+ fixtures :developers
+
+ def test_explain_for_one_query
+ explain = Developer.where(:id => 1).explain
+ assert_match %(EXPLAIN for: SELECT `developers`.* FROM `developers` WHERE `developers`.`id` = 1), explain
+ assert_match %r(developers |.* const), explain
+ end
+
+ def test_explain_with_eager_loading
+ explain = Developer.where(:id => 1).includes(:audit_logs).explain
+ assert_match %(EXPLAIN for: SELECT `developers`.* FROM `developers` WHERE `developers`.`id` = 1), explain
+ assert_match %r(developers |.* const), explain
+ assert_match %(EXPLAIN for: SELECT `audit_logs`.* FROM `audit_logs` WHERE `audit_logs`.`developer_id` IN (1)), explain
+ assert_match %r(audit_logs |.* ALL), explain
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
new file mode 100644
index 0000000000..799d927ee4
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
@@ -0,0 +1,152 @@
+require "cases/helper"
+
+class Group < ActiveRecord::Base
+ Group.table_name = 'group'
+ belongs_to :select
+ has_one :values
+end
+
+class Select < ActiveRecord::Base
+ Select.table_name = 'select'
+ has_many :groups
+end
+
+class Values < ActiveRecord::Base
+ Values.table_name = 'values'
+end
+
+class Distinct < ActiveRecord::Base
+ Distinct.table_name = 'distinct'
+ has_and_belongs_to_many :selects
+ has_many :values, :through => :groups
+end
+
+# a suite of tests to ensure the ConnectionAdapters#MysqlAdapter can handle tables with
+# reserved word names (ie: group, order, values, etc...)
+class MysqlReservedWordTest < ActiveRecord::TestCase
+ def setup
+ @connection = ActiveRecord::Base.connection
+
+ # we call execute directly here (and do similar below) because ActiveRecord::Base#create_table()
+ # will fail with these table names if these test cases fail
+
+ create_tables_directly 'group'=>'id int auto_increment primary key, `order` varchar(255), select_id int',
+ 'select'=>'id int auto_increment primary key',
+ 'values'=>'id int auto_increment primary key, group_id int',
+ 'distinct'=>'id int auto_increment primary key',
+ 'distinct_select'=>'distinct_id int, select_id int'
+ end
+
+ teardown do
+ drop_tables_directly ['group', 'select', 'values', 'distinct', 'distinct_select', 'order']
+ end
+
+ # create tables with reserved-word names and columns
+ def test_create_tables
+ assert_nothing_raised {
+ @connection.create_table :order do |t|
+ t.column :group, :string
+ end
+ }
+ end
+
+ # rename tables with reserved-word names
+ def test_rename_tables
+ assert_nothing_raised { @connection.rename_table(:group, :order) }
+ end
+
+ # alter column with a reserved-word name in a table with a reserved-word name
+ def test_change_columns
+ assert_nothing_raised { @connection.change_column_default(:group, :order, 'whatever') }
+ #the quoting here will reveal any double quoting issues in change_column's interaction with the column method in the adapter
+ assert_nothing_raised { @connection.change_column('group', 'order', :Int, :default => 0) }
+ assert_nothing_raised { @connection.rename_column(:group, :order, :values) }
+ end
+
+ # introspect table with reserved word name
+ def test_introspect
+ assert_nothing_raised { @connection.columns(:group) }
+ assert_nothing_raised { @connection.indexes(:group) }
+ end
+
+ #fixtures
+ self.use_instantiated_fixtures = true
+ self.use_transactional_fixtures = false
+
+ #activerecord model class with reserved-word table name
+ def test_activerecord_model
+ create_test_fixtures :select, :distinct, :group, :values, :distinct_select
+ x = nil
+ assert_nothing_raised { x = Group.new }
+ x.order = 'x'
+ assert_nothing_raised { x.save }
+ x.order = 'y'
+ assert_nothing_raised { x.save }
+ assert_nothing_raised { Group.find_by_order('y') }
+ assert_nothing_raised { Group.find(1) }
+ end
+
+ # has_one association with reserved-word table name
+ def test_has_one_associations
+ create_test_fixtures :select, :distinct, :group, :values, :distinct_select
+ v = nil
+ assert_nothing_raised { v = Group.find(1).values }
+ assert_equal 2, v.id
+ end
+
+ # belongs_to association with reserved-word table name
+ def test_belongs_to_associations
+ create_test_fixtures :select, :distinct, :group, :values, :distinct_select
+ gs = nil
+ assert_nothing_raised { gs = Select.find(2).groups }
+ assert_equal gs.length, 2
+ assert(gs.collect{|x| x.id}.sort == [2, 3])
+ end
+
+ # has_and_belongs_to_many with reserved-word table name
+ def test_has_and_belongs_to_many
+ create_test_fixtures :select, :distinct, :group, :values, :distinct_select
+ s = nil
+ assert_nothing_raised { s = Distinct.find(1).selects }
+ assert_equal s.length, 2
+ assert(s.collect{|x|x.id}.sort == [1, 2])
+ end
+
+ # activerecord model introspection with reserved-word table and column names
+ def test_activerecord_introspection
+ assert_nothing_raised { Group.table_exists? }
+ assert_nothing_raised { Group.columns }
+ end
+
+ # Calculations
+ def test_calculations_work_with_reserved_words
+ assert_nothing_raised { Group.count }
+ end
+
+ def test_associations_work_with_reserved_words
+ assert_nothing_raised { Select.all.merge!(:includes => [:groups]).to_a }
+ end
+
+ #the following functions were added to DRY test cases
+
+ private
+ # custom fixture loader, uses FixtureSet#create_fixtures and appends base_path to the current file's path
+ def create_test_fixtures(*fixture_names)
+ ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT + "/reserved_words", fixture_names)
+ end
+
+ # custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name
+ def drop_tables_directly(table_names, connection = @connection)
+ table_names.each do |name|
+ connection.execute("DROP TABLE IF EXISTS `#{name}`")
+ end
+ end
+
+ # custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns
+ def create_tables_directly (tables, connection = @connection)
+ tables.each do |table_name, column_properties|
+ connection.execute("CREATE TABLE `#{table_name}` ( #{column_properties} )")
+ end
+ end
+
+end
diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
new file mode 100644
index 0000000000..9c49599d34
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
@@ -0,0 +1,39 @@
+require "cases/helper"
+
+module ActiveRecord
+ module ConnectionAdapters
+ class Mysql2Adapter
+ class SchemaMigrationsTest < ActiveRecord::TestCase
+ def test_renaming_index_on_foreign_key
+ connection.add_index "engines", "car_id"
+ connection.add_foreign_key :engines, :cars, name: "fk_engines_cars"
+
+ connection.rename_index("engines", "index_engines_on_car_id", "idx_renamed")
+ assert_equal ["idx_renamed"], connection.indexes("engines").map(&:name)
+ ensure
+ connection.remove_foreign_key :engines, name: "fk_engines_cars"
+ end
+
+ def test_initializes_schema_migrations_for_encoding_utf8mb4
+ smtn = ActiveRecord::Migrator.schema_migrations_table_name
+ connection.drop_table(smtn) if connection.table_exists?(smtn)
+
+ config = connection.instance_variable_get(:@config)
+ original_encoding = config[:encoding]
+
+ config[:encoding] = 'utf8mb4'
+ connection.initialize_schema_migrations_table
+
+ assert connection.column_exists?(smtn, :version, :string, limit: Mysql2Adapter::MAX_INDEX_LENGTH_FOR_UTF8MB4)
+ ensure
+ config[:encoding] = original_encoding
+ end
+
+ private
+ def connection
+ @connection ||= ActiveRecord::Base.connection
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/schema_test.rb b/activerecord/test/cases/adapters/mysql2/schema_test.rb
new file mode 100644
index 0000000000..43c9116b5a
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/schema_test.rb
@@ -0,0 +1,79 @@
+require "cases/helper"
+require 'models/post'
+require 'models/comment'
+
+module ActiveRecord
+ module ConnectionAdapters
+ class Mysql2SchemaTest < ActiveRecord::TestCase
+ fixtures :posts
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ db = Post.connection_pool.spec.config[:database]
+ table = Post.table_name
+ @db_name = db
+
+ @omgpost = Class.new(ActiveRecord::Base) do
+ self.table_name = "#{db}.#{table}"
+ def self.name; 'Post'; end
+ end
+ end
+
+ def test_schema
+ assert @omgpost.first
+ end
+
+ def test_primary_key
+ assert_equal 'id', @omgpost.primary_key
+ end
+
+ def test_table_exists?
+ name = @omgpost.table_name
+ assert @connection.table_exists?(name), "#{name} table should exist"
+ end
+
+ def test_table_exists_wrong_schema
+ assert(!@connection.table_exists?("#{@db_name}.zomg"), "table should not exist")
+ end
+
+ def test_tables_quoting
+ @connection.tables(nil, "foo-bar", nil)
+ flunk
+ rescue => e
+ # assertion for *quoted* database properly
+ assert_match(/database 'foo-bar'/, e.inspect)
+ end
+
+ def test_dump_indexes
+ index_a_name = 'index_key_tests_on_snack'
+ index_b_name = 'index_key_tests_on_pizza'
+ index_c_name = 'index_key_tests_on_awesome'
+
+ table = 'key_tests'
+
+ indexes = @connection.indexes(table).sort_by {|i| i.name}
+ assert_equal 3,indexes.size
+
+ index_a = indexes.select{|i| i.name == index_a_name}[0]
+ index_b = indexes.select{|i| i.name == index_b_name}[0]
+ index_c = indexes.select{|i| i.name == index_c_name}[0]
+ assert_equal :btree, index_a.using
+ assert_nil index_a.type
+ assert_equal :btree, index_b.using
+ assert_nil index_b.type
+
+ assert_nil index_c.using
+ assert_equal :fulltext, index_c.type
+ end
+
+ def test_drop_temporary_table
+ @connection.transaction do
+ @connection.create_table(:temp_table, temporary: true)
+ # if it doesn't properly say DROP TEMPORARY TABLE, the transaction commit
+ # will complain that no transaction is active
+ @connection.drop_table(:temp_table, temporary: true)
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/sql_types_test.rb b/activerecord/test/cases/adapters/mysql2/sql_types_test.rb
new file mode 100644
index 0000000000..1ddb1b91c9
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/sql_types_test.rb
@@ -0,0 +1,14 @@
+require "cases/helper"
+
+class SqlTypesTest < ActiveRecord::TestCase
+ def test_binary_types
+ assert_equal 'varbinary(64)', type_to_sql(:binary, 64)
+ assert_equal 'varbinary(4095)', type_to_sql(:binary, 4095)
+ assert_equal 'blob(4096)', type_to_sql(:binary, 4096)
+ assert_equal 'blob', type_to_sql(:binary)
+ end
+
+ def type_to_sql(*args)
+ ActiveRecord::Base.connection.type_to_sql(*args)
+ end
+end