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.rb63
-rw-r--r--activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/boolean_test.rb11
-rw-r--r--activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb3
-rw-r--r--activerecord/test/cases/adapters/mysql2/charset_collation_test.rb54
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb44
-rw-r--r--activerecord/test/cases/adapters/mysql2/enum_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/explain_test.rb5
-rw-r--r--activerecord/test/cases/adapters/mysql2/json_test.rb172
-rw-r--r--activerecord/test/cases/adapters/mysql2/quoting_test.rb21
-rw-r--r--activerecord/test/cases/adapters/mysql2/reserved_word_test.rb48
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb73
-rw-r--r--activerecord/test/cases/adapters/mysql2/schema_test.rb27
-rw-r--r--activerecord/test/cases/adapters/mysql2/sp_test.rb30
-rw-r--r--activerecord/test/cases/adapters/mysql2/sql_types_test.rb4
-rw-r--r--activerecord/test/cases/adapters/mysql2/table_options_test.rb42
-rw-r--r--activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb65
17 files changed, 550 insertions, 116 deletions
diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb
index cefc3e3c7e..31dc69a45b 100644
--- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
require 'support/connection_helper'
-class ActiveSchemaTest < ActiveRecord::TestCase
+class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase
include ConnectionHelper
def setup
@@ -59,21 +59,56 @@ class ActiveSchemaTest < ActiveRecord::TestCase
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)
+ def test_index_in_create
+ def (ActiveRecord::Base.connection).table_exists?(*); false; end
+
+ %w(SPATIAL FULLTEXT UNIQUE).each do |type|
+ expected = "CREATE TABLE `people` (#{type} INDEX `index_people_on_last_name` (`last_name`) ) ENGINE=InnoDB"
+ actual = ActiveRecord::Base.connection.create_table(:people, id: false) do |t|
+ t.index :last_name, type: type
+ end
+ assert_equal expected, actual
+ end
+
+ expected = "CREATE TABLE `people` ( INDEX `index_people_on_last_name` USING btree (`last_name`(10)) ) ENGINE=InnoDB"
+ actual = ActiveRecord::Base.connection.create_table(:people, id: false) do |t|
+ t.index :last_name, length: 10, using: :btree
+ end
+ assert_equal expected, actual
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})
+ def test_index_in_bulk_change
+ def (ActiveRecord::Base.connection).table_exists?(*); true; end
+ def (ActiveRecord::Base.connection).index_name_exists?(*); false; end
+
+ %w(SPATIAL FULLTEXT UNIQUE).each do |type|
+ expected = "ALTER TABLE `people` ADD #{type} INDEX `index_people_on_last_name` (`last_name`)"
+ actual = ActiveRecord::Base.connection.change_table(:people, bulk: true) do |t|
+ t.index :last_name, type: type
+ end
+ assert_equal expected, actual
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'})
+ expected = "ALTER TABLE `peaple` ADD INDEX `index_peaple_on_last_name` USING btree (`last_name`(10)), ALGORITHM = COPY"
+ actual = ActiveRecord::Base.connection.change_table(:peaple, bulk: true) do |t|
+ t.index :last_name, length: 10, using: :btree, algorithm: :copy
end
+ assert_equal expected, actual
+ end
+
+ def test_drop_table
+ assert_equal "DROP TABLE `people`", drop_table(:people)
+ end
+
+ 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
def test_add_column
@@ -92,7 +127,7 @@ class ActiveSchemaTest < ActiveRecord::TestCase
with_real_execute do
begin
ActiveRecord::Base.connection.create_table :delete_me
- ActiveRecord::Base.connection.add_timestamps :delete_me
+ ActiveRecord::Base.connection.add_timestamps :delete_me, null: true
assert column_present?('delete_me', 'updated_at', 'datetime')
assert column_present?('delete_me', 'created_at', 'datetime')
ensure
@@ -105,9 +140,9 @@ class ActiveSchemaTest < ActiveRecord::TestCase
with_real_execute do
begin
ActiveRecord::Base.connection.create_table :delete_me do |t|
- t.timestamps
+ t.timestamps null: true
end
- ActiveRecord::Base.connection.remove_timestamps :delete_me
+ ActiveRecord::Base.connection.remove_timestamps :delete_me, { null: true }
assert !column_present?('delete_me', 'updated_at', 'datetime')
assert !column_present?('delete_me', 'created_at', 'datetime')
ensure
diff --git a/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
index 5e8065d80d..abdf3dbf5b 100644
--- a/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
@@ -4,7 +4,7 @@ require 'models/topic'
module ActiveRecord
module ConnectionAdapters
class Mysql2Adapter
- class BindParameterTest < ActiveRecord::TestCase
+ class BindParameterTest < ActiveRecord::Mysql2TestCase
fixtures :topics
def test_update_question_marks
diff --git a/activerecord/test/cases/adapters/mysql2/boolean_test.rb b/activerecord/test/cases/adapters/mysql2/boolean_test.rb
index f3c711a64b..8575df9e43 100644
--- a/activerecord/test/cases/adapters/mysql2/boolean_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/boolean_test.rb
@@ -1,7 +1,7 @@
require "cases/helper"
-class Mysql2BooleanTest < ActiveRecord::TestCase
- self.use_transactional_fixtures = false
+class Mysql2BooleanTest < ActiveRecord::Mysql2TestCase
+ self.use_transactional_tests = false
class BooleanType < ActiveRecord::Base
self.table_name = "mysql_booleans"
@@ -9,6 +9,7 @@ class Mysql2BooleanTest < ActiveRecord::TestCase
setup do
@connection = ActiveRecord::Base.connection
+ @connection.clear_cache!
@connection.create_table("mysql_booleans") do |t|
t.boolean "archived"
t.string "published", limit: 1
@@ -46,8 +47,7 @@ class Mysql2BooleanTest < ActiveRecord::TestCase
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)
+ assert_equal 1, @connection.type_cast(true)
end
test "test type casting without emulated booleans" do
@@ -59,8 +59,7 @@ class Mysql2BooleanTest < ActiveRecord::TestCase
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)
+ assert_equal 1, @connection.type_cast(true)
end
test "with booleans stored as 1 and 0" do
diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
index 09bebf3071..963116f08a 100644
--- a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
@@ -1,7 +1,6 @@
require "cases/helper"
-require 'models/person'
-class Mysql2CaseSensitivityTest < ActiveRecord::TestCase
+class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
class CollationTest < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb
new file mode 100644
index 0000000000..4fd34def15
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb
@@ -0,0 +1,54 @@
+require "cases/helper"
+require 'support/schema_dumping_helper'
+
+class Mysql2CharsetCollationTest < ActiveRecord::Mysql2TestCase
+ include SchemaDumpingHelper
+ self.use_transactional_tests = false
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table :charset_collations, force: true do |t|
+ t.string :string_ascii_bin, charset: 'ascii', collation: 'ascii_bin'
+ t.text :text_ucs2_unicode_ci, charset: 'ucs2', collation: 'ucs2_unicode_ci'
+ end
+ end
+
+ teardown do
+ @connection.drop_table :charset_collations, if_exists: true
+ end
+
+ test "string column with charset and collation" do
+ column = @connection.columns(:charset_collations).find { |c| c.name == 'string_ascii_bin' }
+ assert_equal :string, column.type
+ assert_equal 'ascii_bin', column.collation
+ end
+
+ test "text column with charset and collation" do
+ column = @connection.columns(:charset_collations).find { |c| c.name == 'text_ucs2_unicode_ci' }
+ assert_equal :text, column.type
+ assert_equal 'ucs2_unicode_ci', column.collation
+ end
+
+ test "add column with charset and collation" do
+ @connection.add_column :charset_collations, :title, :string, charset: 'utf8', collation: 'utf8_bin'
+
+ column = @connection.columns(:charset_collations).find { |c| c.name == 'title' }
+ assert_equal :string, column.type
+ assert_equal 'utf8_bin', column.collation
+ end
+
+ test "change column with charset and collation" do
+ @connection.add_column :charset_collations, :description, :string, charset: 'utf8', collation: 'utf8_unicode_ci'
+ @connection.change_column :charset_collations, :description, :text, charset: 'utf8', collation: 'utf8_general_ci'
+
+ column = @connection.columns(:charset_collations).find { |c| c.name == 'description' }
+ assert_equal :text, column.type
+ assert_equal 'utf8_general_ci', column.collation
+ end
+
+ test "schema dump includes collation" do
+ output = dump_table_schema("charset_collations")
+ assert_match %r{t.string\s+"string_ascii_bin",\s+limit: 255,\s+collation: "ascii_bin"$}, output
+ assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+limit: 65535,\s+collation: "ucs2_unicode_ci"$}, output
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index 3b35e69e0d..000bcadebe 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -1,9 +1,11 @@
require "cases/helper"
require 'support/connection_helper'
-class MysqlConnectionTest < ActiveRecord::TestCase
+class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
include ConnectionHelper
+ fixtures :comments
+
def setup
super
@subscriber = SQLSubscriber.new
@@ -20,10 +22,21 @@ class MysqlConnectionTest < ActiveRecord::TestCase
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')
+ connection.drop_table 'ex', if_exists: true
end
end
+ def test_truncate
+ rows = ActiveRecord::Base.connection.exec_query("select count(*) from comments")
+ count = rows.first.values.first
+ assert_operator count, :>, 0
+
+ ActiveRecord::Base.connection.truncate("comments")
+ rows = ActiveRecord::Base.connection.exec_query("select count(*) from comments")
+ count = rows.first.values.first
+ assert_equal 0, count
+ end
+
def test_no_automatic_reconnection_after_timeout
assert @connection.active?
@connection.update('set @@wait_timeout=1')
@@ -31,9 +44,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
assert !@connection.active?
# Repair all fixture connections so other tests won't break.
- @fixture_connections.each do |c|
- c.verify!
- end
+ @fixture_connections.each(&:verify!)
end
def test_successful_reconnection_after_timeout_with_manual_reconnect
@@ -52,6 +63,11 @@ class MysqlConnectionTest < ActiveRecord::TestCase
assert @connection.active?
end
+ def test_mysql_connection_collation_is_configured
+ assert_equal 'utf8_unicode_ci', @connection.show_variable('collation_connection')
+ assert_equal 'utf8_general_ci', ARUnit2Model.connection.show_variable('collation_connection')
+ 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.
@@ -68,6 +84,15 @@ class MysqlConnectionTest < ActiveRecord::TestCase
end
end
+ def test_mysql_strict_mode_specified_default
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.merge({strict: :default}))
+ global_sql_mode = ActiveRecord::Base.connection.exec_query "SELECT @@GLOBAL.sql_mode"
+ session_sql_mode = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.sql_mode"
+ assert_equal global_sql_mode.rows, session_sql_mode.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}}))
@@ -76,7 +101,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
end
end
- def test_mysql_sql_mode_variable_overides_strict_mode
+ def test_mysql_sql_mode_variable_overrides_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'
@@ -106,11 +131,4 @@ class MysqlConnectionTest < ActiveRecord::TestCase
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
index 6dd9a5ec87..bd732b5eca 100644
--- a/activerecord/test/cases/adapters/mysql2/enum_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/enum_test.rb
@@ -1,6 +1,6 @@
require "cases/helper"
-class Mysql2EnumTest < ActiveRecord::TestCase
+class Mysql2EnumTest < ActiveRecord::Mysql2TestCase
class EnumTest < ActiveRecord::Base
end
diff --git a/activerecord/test/cases/adapters/mysql2/explain_test.rb b/activerecord/test/cases/adapters/mysql2/explain_test.rb
index 675703caa1..4fc7414b18 100644
--- a/activerecord/test/cases/adapters/mysql2/explain_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/explain_test.rb
@@ -1,10 +1,11 @@
require "cases/helper"
require 'models/developer'
+require 'models/computer'
module ActiveRecord
module ConnectionAdapters
class Mysql2Adapter
- class ExplainTest < ActiveRecord::TestCase
+ class ExplainTest < ActiveRecord::Mysql2TestCase
fixtures :developers
def test_explain_for_one_query
@@ -17,7 +18,7 @@ module ActiveRecord
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 %(EXPLAIN for: SELECT `audit_logs`.* FROM `audit_logs` WHERE `audit_logs`.`developer_id` = 1), explain
assert_match %r(audit_logs |.* ALL), explain
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/json_test.rb b/activerecord/test/cases/adapters/mysql2/json_test.rb
new file mode 100644
index 0000000000..c8c933af5e
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/json_test.rb
@@ -0,0 +1,172 @@
+require 'cases/helper'
+require 'support/schema_dumping_helper'
+
+if ActiveRecord::Base.connection.supports_json?
+class Mysql2JSONTest < ActiveRecord::Mysql2TestCase
+ include SchemaDumpingHelper
+ self.use_transactional_tests = false
+
+ class JsonDataType < ActiveRecord::Base
+ self.table_name = 'json_data_type'
+
+ store_accessor :settings, :resolution
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ begin
+ @connection.create_table('json_data_type') do |t|
+ t.json 'payload'
+ t.json 'settings'
+ end
+ end
+ end
+
+ def teardown
+ @connection.drop_table :json_data_type, if_exists: true
+ JsonDataType.reset_column_information
+ end
+
+ def test_column
+ column = JsonDataType.columns_hash["payload"]
+ assert_equal :json, column.type
+ assert_equal 'json', column.sql_type
+
+ type = JsonDataType.type_for_attribute("payload")
+ assert_not type.binary?
+ end
+
+ def test_change_table_supports_json
+ @connection.change_table('json_data_type') do |t|
+ t.json 'users'
+ end
+ JsonDataType.reset_column_information
+ column = JsonDataType.columns_hash['users']
+ assert_equal :json, column.type
+ end
+
+ def test_schema_dumping
+ output = dump_table_schema("json_data_type")
+ assert_match(/t\.json\s+"settings"/, output)
+ end
+
+ def test_cast_value_on_write
+ x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar}
+ assert_equal({"string" => "foo", :symbol => :bar}, x.payload_before_type_cast)
+ assert_equal({"string" => "foo", "symbol" => "bar"}, x.payload)
+ x.save
+ assert_equal({"string" => "foo", "symbol" => "bar"}, x.reload.payload)
+ end
+
+ def test_type_cast_json
+ type = JsonDataType.type_for_attribute("payload")
+
+ data = "{\"a_key\":\"a_value\"}"
+ hash = type.deserialize(data)
+ assert_equal({'a_key' => 'a_value'}, hash)
+ assert_equal({'a_key' => 'a_value'}, type.deserialize(data))
+
+ assert_equal({}, type.deserialize("{}"))
+ assert_equal({'key'=>nil}, type.deserialize('{"key": null}'))
+ assert_equal({'c'=>'}','"a"'=>'b "a b'}, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"})))
+ end
+
+ def test_rewrite
+ @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')"
+ x = JsonDataType.first
+ x.payload = { '"a\'' => 'b' }
+ assert x.save!
+ end
+
+ def test_select
+ @connection.execute "insert into json_data_type (payload) VALUES ('{\"k\":\"v\"}')"
+ x = JsonDataType.first
+ assert_equal({'k' => 'v'}, x.payload)
+ end
+
+ def test_select_multikey
+ @connection.execute %q|insert into json_data_type (payload) VALUES ('{"k1":"v1", "k2":"v2", "k3":[1,2,3]}')|
+ x = JsonDataType.first
+ assert_equal({'k1' => 'v1', 'k2' => 'v2', 'k3' => [1,2,3]}, x.payload)
+ end
+
+ def test_null_json
+ @connection.execute %q|insert into json_data_type (payload) VALUES(null)|
+ x = JsonDataType.first
+ assert_equal(nil, x.payload)
+ end
+
+ def test_select_array_json_value
+ @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')|
+ x = JsonDataType.first
+ assert_equal(['v0', {'k1' => 'v1'}], x.payload)
+ end
+
+ def test_rewrite_array_json_value
+ @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')|
+ x = JsonDataType.first
+ x.payload = ['v1', {'k2' => 'v2'}, 'v3']
+ assert x.save!
+ end
+
+ def test_with_store_accessors
+ x = JsonDataType.new(resolution: "320×480")
+ assert_equal "320×480", x.resolution
+
+ x.save!
+ x = JsonDataType.first
+ assert_equal "320×480", x.resolution
+
+ x.resolution = "640×1136"
+ x.save!
+
+ x = JsonDataType.first
+ assert_equal "640×1136", x.resolution
+ end
+
+ def test_duplication_with_store_accessors
+ x = JsonDataType.new(resolution: "320×480")
+ assert_equal "320×480", x.resolution
+
+ y = x.dup
+ assert_equal "320×480", y.resolution
+ end
+
+ def test_yaml_round_trip_with_store_accessors
+ x = JsonDataType.new(resolution: "320×480")
+ assert_equal "320×480", x.resolution
+
+ y = YAML.load(YAML.dump(x))
+ assert_equal "320×480", y.resolution
+ end
+
+ def test_changes_in_place
+ json = JsonDataType.new
+ assert_not json.changed?
+
+ json.payload = { 'one' => 'two' }
+ assert json.changed?
+ assert json.payload_changed?
+
+ json.save!
+ assert_not json.changed?
+
+ json.payload['three'] = 'four'
+ assert json.payload_changed?
+
+ json.save!
+ json.reload
+
+ assert_equal({ 'one' => 'two', 'three' => 'four' }, json.payload)
+ assert_not json.changed?
+ end
+
+ def test_assigning_invalid_json
+ json = JsonDataType.new
+
+ json.payload = 'foo'
+
+ assert_nil json.payload
+ end
+end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/quoting_test.rb b/activerecord/test/cases/adapters/mysql2/quoting_test.rb
new file mode 100644
index 0000000000..2de7e1b526
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/quoting_test.rb
@@ -0,0 +1,21 @@
+require "cases/helper"
+
+class Mysql2QuotingTest < ActiveRecord::Mysql2TestCase
+ setup do
+ @connection = ActiveRecord::Base.connection
+ end
+
+ test 'quoted date precision for gte 5.6.4' do
+ @connection.stubs(:full_version).returns('5.6.4')
+ @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version)
+ t = Time.now.change(usec: 1)
+ assert_match(/\.000001\z/, @connection.quoted_date(t))
+ end
+
+ test 'quoted date precision for lt 5.6.4' do
+ @connection.stubs(:full_version).returns('5.6.3')
+ @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version)
+ t = Time.now.change(usec: 1)
+ assert_no_match(/\.000001\z/, @connection.quoted_date(t))
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
index 799d927ee4..ffb4e2c5cf 100644
--- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
@@ -1,29 +1,29 @@
require "cases/helper"
-class Group < ActiveRecord::Base
- Group.table_name = 'group'
- belongs_to :select
- has_one :values
-end
+# a suite of tests to ensure the ConnectionAdapters#MysqlAdapter can handle tables with
+# reserved word names (ie: group, order, values, etc...)
+class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase
+ 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 Select < ActiveRecord::Base
+ Select.table_name = 'select'
+ has_many :groups
+ end
-class Values < ActiveRecord::Base
- Values.table_name = 'values'
-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
+ 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
@@ -71,7 +71,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
#fixtures
self.use_instantiated_fixtures = true
- self.use_transactional_fixtures = false
+ self.use_transactional_tests = false
#activerecord model class with reserved-word table name
def test_activerecord_model
@@ -100,7 +100,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
gs = nil
assert_nothing_raised { gs = Select.find(2).groups }
assert_equal gs.length, 2
- assert(gs.collect{|x| x.id}.sort == [2, 3])
+ assert(gs.collect(&:id).sort == [2, 3])
end
# has_and_belongs_to_many with reserved-word table name
@@ -109,7 +109,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
s = nil
assert_nothing_raised { s = Distinct.find(1).selects }
assert_equal s.length, 2
- assert(s.collect{|x|x.id}.sort == [1, 2])
+ assert(s.collect(&:id).sort == [1, 2])
end
# activerecord model introspection with reserved-word table and column names
@@ -138,7 +138,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
# 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}`")
+ connection.drop_table name, if_exists: true
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
index 9c49599d34..396f235e77 100644
--- a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb
@@ -1,39 +1,42 @@
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
+class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase
+ 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_exists: true
+
+ database_name = connection.current_database
+ database_info = connection.select_one("SELECT * FROM information_schema.schemata WHERE schema_name = '#{database_name}'")
+
+ original_charset = database_info["DEFAULT_CHARACTER_SET_NAME"]
+ original_collation = database_info["DEFAULT_COLLATION_NAME"]
+
+ execute("ALTER DATABASE #{database_name} DEFAULT CHARACTER SET utf8mb4")
+
+ connection.initialize_schema_migrations_table
+
+ limit = ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MAX_INDEX_LENGTH_FOR_CHARSETS_OF_4BYTES_MAXLEN
+ assert connection.column_exists?(smtn, :version, :string, limit: limit)
+ ensure
+ execute("ALTER DATABASE #{database_name} DEFAULT CHARACTER SET #{original_charset} COLLATE #{original_collation}")
+ end
+
+ private
+ def connection
+ @connection ||= ActiveRecord::Base.connection
+ end
+
+ def execute(sql)
+ connection.execute(sql)
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/schema_test.rb b/activerecord/test/cases/adapters/mysql2/schema_test.rb
index 43c9116b5a..1ebdca661c 100644
--- a/activerecord/test/cases/adapters/mysql2/schema_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/schema_test.rb
@@ -4,7 +4,7 @@ require 'models/comment'
module ActiveRecord
module ConnectionAdapters
- class Mysql2SchemaTest < ActiveRecord::TestCase
+ class Mysql2SchemaTest < ActiveRecord::Mysql2TestCase
fixtures :posts
def setup
@@ -14,6 +14,7 @@ module ActiveRecord
@db_name = db
@omgpost = Class.new(ActiveRecord::Base) do
+ self.inheritance_column = :disabled
self.table_name = "#{db}.#{table}"
def self.name; 'Post'; end
end
@@ -36,14 +37,6 @@ module ActiveRecord
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'
@@ -51,7 +44,7 @@ module ActiveRecord
table = 'key_tests'
- indexes = @connection.indexes(table).sort_by {|i| i.name}
+ indexes = @connection.indexes(table).sort_by(&:name)
assert_equal 3,indexes.size
index_a = indexes.select{|i| i.name == index_a_name}[0]
@@ -66,12 +59,14 @@ module ActiveRecord
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)
+ unless mysql_enforcing_gtid_consistency?
+ 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
diff --git a/activerecord/test/cases/adapters/mysql2/sp_test.rb b/activerecord/test/cases/adapters/mysql2/sp_test.rb
new file mode 100644
index 0000000000..cdaa2cca44
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/sp_test.rb
@@ -0,0 +1,30 @@
+require "cases/helper"
+require 'models/topic'
+require 'models/reply'
+
+class Mysql2StoredProcedureTest < ActiveRecord::Mysql2TestCase
+ fixtures :topics
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ unless ActiveRecord::Base.connection.version >= '5.6.0'
+ skip("no stored procedure support")
+ end
+ end
+
+ # Test that MySQL allows multiple results for stored procedures
+ #
+ # In MySQL 5.6, CLIENT_MULTI_RESULTS is enabled by default.
+ # http://dev.mysql.com/doc/refman/5.6/en/call.html
+ def test_multi_results
+ rows = @connection.select_rows('CALL ten();')
+ assert_equal 10, rows[0][0].to_i, "ten() did not return 10 as expected: #{rows.inspect}"
+ assert @connection.active?, "Bad connection use by 'Mysql2Adapter.select_rows'"
+ end
+
+ def test_multi_results_from_find_by_sql
+ topics = Topic.find_by_sql 'CALL topics(3);'
+ assert_equal 3, topics.size
+ assert @connection.active?, "Bad connection use by 'Mysql2Adapter.select'"
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/sql_types_test.rb b/activerecord/test/cases/adapters/mysql2/sql_types_test.rb
index 1ddb1b91c9..4926bc2267 100644
--- a/activerecord/test/cases/adapters/mysql2/sql_types_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/sql_types_test.rb
@@ -1,10 +1,10 @@
require "cases/helper"
-class SqlTypesTest < ActiveRecord::TestCase
+class Mysql2SqlTypesTest < ActiveRecord::Mysql2TestCase
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, 4096)
assert_equal 'blob', type_to_sql(:binary)
end
diff --git a/activerecord/test/cases/adapters/mysql2/table_options_test.rb b/activerecord/test/cases/adapters/mysql2/table_options_test.rb
new file mode 100644
index 0000000000..af121ee7d9
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/table_options_test.rb
@@ -0,0 +1,42 @@
+require "cases/helper"
+require 'support/schema_dumping_helper'
+
+class Mysql2TableOptionsTest < ActiveRecord::Mysql2TestCase
+ include SchemaDumpingHelper
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ end
+
+ def teardown
+ @connection.drop_table "mysql_table_options", if_exists: true
+ end
+
+ test "table options with ENGINE" do
+ @connection.create_table "mysql_table_options", force: true, options: "ENGINE=MyISAM"
+ output = dump_table_schema("mysql_table_options")
+ options = %r{create_table "mysql_table_options", force: :cascade, options: "(?<options>.*)"}.match(output)[:options]
+ assert_match %r{ENGINE=MyISAM}, options
+ end
+
+ test "table options with ROW_FORMAT" do
+ @connection.create_table "mysql_table_options", force: true, options: "ROW_FORMAT=REDUNDANT"
+ output = dump_table_schema("mysql_table_options")
+ options = %r{create_table "mysql_table_options", force: :cascade, options: "(?<options>.*)"}.match(output)[:options]
+ assert_match %r{ROW_FORMAT=REDUNDANT}, options
+ end
+
+ test "table options with CHARSET" do
+ @connection.create_table "mysql_table_options", force: true, options: "CHARSET=utf8mb4"
+ output = dump_table_schema("mysql_table_options")
+ options = %r{create_table "mysql_table_options", force: :cascade, options: "(?<options>.*)"}.match(output)[:options]
+ assert_match %r{CHARSET=utf8mb4}, options
+ end
+
+ test "table options with COLLATE" do
+ @connection.create_table "mysql_table_options", force: true, options: "COLLATE=utf8mb4_bin"
+ output = dump_table_schema("mysql_table_options")
+ options = %r{create_table "mysql_table_options", force: :cascade, options: "(?<options>.*)"}.match(output)[:options]
+ assert_match %r{COLLATE=utf8mb4_bin}, options
+ end
+end
diff --git a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
new file mode 100644
index 0000000000..a6f6dd21bb
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
@@ -0,0 +1,65 @@
+require "cases/helper"
+require "support/schema_dumping_helper"
+
+class Mysql2UnsignedTypeTest < ActiveRecord::Mysql2TestCase
+ include SchemaDumpingHelper
+ self.use_transactional_tests = false
+
+ class UnsignedType < ActiveRecord::Base
+ end
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table("unsigned_types", force: true) do |t|
+ t.integer :unsigned_integer, unsigned: true
+ t.bigint :unsigned_bigint, unsigned: true
+ t.float :unsigned_float, unsigned: true
+ t.decimal :unsigned_decimal, unsigned: true, precision: 10, scale: 2
+ end
+ end
+
+ teardown do
+ @connection.drop_table "unsigned_types", if_exists: true
+ end
+
+ test "unsigned int max value is in range" do
+ assert expected = UnsignedType.create(unsigned_integer: 4294967295)
+ assert_equal expected, UnsignedType.find_by(unsigned_integer: 4294967295)
+ end
+
+ test "minus value is out of range" do
+ assert_raise(RangeError) do
+ UnsignedType.create(unsigned_integer: -10)
+ end
+ assert_raise(RangeError) do
+ UnsignedType.create(unsigned_bigint: -10)
+ end
+ assert_raise(ActiveRecord::StatementInvalid) do
+ UnsignedType.create(unsigned_float: -10.0)
+ end
+ assert_raise(ActiveRecord::StatementInvalid) do
+ UnsignedType.create(unsigned_decimal: -10.0)
+ end
+ end
+
+ test "schema definition can use unsigned as the type" do
+ @connection.change_table("unsigned_types") do |t|
+ t.unsigned_integer :unsigned_integer_t
+ t.unsigned_bigint :unsigned_bigint_t
+ t.unsigned_float :unsigned_float_t
+ t.unsigned_decimal :unsigned_decimal_t, precision: 10, scale: 2
+ end
+
+ @connection.columns("unsigned_types").select { |c| /^unsigned_/ === c.name }.each do |column|
+ assert column.unsigned?
+ end
+ end
+
+ test "schema dump includes unsigned option" do
+ schema = dump_table_schema "unsigned_types"
+ assert_match %r{t.integer\s+"unsigned_integer",\s+limit: 4,\s+unsigned: true$}, schema
+ assert_match %r{t.integer\s+"unsigned_bigint",\s+limit: 8,\s+unsigned: true$}, schema
+ assert_match %r{t.float\s+"unsigned_float",\s+limit: 24,\s+unsigned: true$}, schema
+ assert_match %r{t.decimal\s+"unsigned_decimal",\s+precision: 10,\s+scale: 2,\s+unsigned: true$}, schema
+ end
+end