diff options
Diffstat (limited to 'activerecord/test/cases/adapters/mysql2')
14 files changed, 221 insertions, 86 deletions
diff --git a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb index 99f97c7914..95d1f6b8a3 100644 --- a/activerecord/test/cases/adapters/mysql2/active_schema_test.rb +++ b/activerecord/test/cases/adapters/mysql2/active_schema_test.rb @@ -63,14 +63,14 @@ 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`) ) ENGINE=InnoDB" + 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" + 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 @@ -155,7 +155,7 @@ class Mysql2ActiveSchemaTest < ActiveRecord::Mysql2TestCase ActiveRecord::Base.connection.stubs(:data_source_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" + 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 diff --git a/activerecord/test/cases/adapters/mysql2/boolean_test.rb b/activerecord/test/cases/adapters/mysql2/boolean_test.rb index 8575df9e43..739bb275ce 100644 --- a/activerecord/test/cases/adapters/mysql2/boolean_test.rb +++ b/activerecord/test/cases/adapters/mysql2/boolean_test.rb @@ -43,11 +43,16 @@ class Mysql2BooleanTest < ActiveRecord::Mysql2TestCase boolean = BooleanType.create!(archived: true, published: true) attributes = boolean.reload.attributes_before_type_cast - assert_equal 1, attributes["archived"] assert_equal "1", attributes["published"] + boolean = BooleanType.create!(archived: false, published: false) + attributes = boolean.reload.attributes_before_type_cast + assert_equal 0, attributes["archived"] + assert_equal "0", attributes["published"] + assert_equal 1, @connection.type_cast(true) + assert_equal 0, @connection.type_cast(false) end test "test type casting without emulated booleans" do @@ -55,11 +60,16 @@ class Mysql2BooleanTest < ActiveRecord::Mysql2TestCase boolean = BooleanType.create!(archived: true, published: true) attributes = boolean.reload.attributes_before_type_cast - assert_equal 1, attributes["archived"] assert_equal "1", attributes["published"] + boolean = BooleanType.create!(archived: false, published: false) + attributes = boolean.reload.attributes_before_type_cast + assert_equal 0, attributes["archived"] + assert_equal "0", attributes["published"] + assert_equal 1, @connection.type_cast(true) + assert_equal 0, @connection.type_cast(false) 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 963116f08a..9cb05119a2 100644 --- a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb +++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb @@ -51,4 +51,13 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) } assert_no_match(/binary/i, cs_uniqueness_query) end + + def test_case_sensitive_comparison_for_binary_column + CollationTest.validates_uniqueness_of(:binary_column, case_sensitive: true) + CollationTest.create!(binary_column: 'A') + invalid = CollationTest.new(binary_column: 'A') + queries = assert_sql { invalid.save } + bin_uniqueness_query = queries.detect { |q| q.match(/binary_column/) } + assert_no_match(/\bBINARY\b/, bin_uniqueness_query) + end end diff --git a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb index 668c07dacb..c8028b6b36 100644 --- a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb +++ b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb @@ -49,6 +49,6 @@ class Mysql2CharsetCollationTest < ActiveRecord::Mysql2TestCase test "schema dump includes collation" do output = dump_table_schema("charset_collations") assert_match %r{t.string\s+"string_ascii_bin",\s+collation: "ascii_bin"$}, output - assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+limit: 65535,\s+collation: "ucs2_unicode_ci"$}, output + assert_match %r{t.text\s+"text_ucs2_unicode_ci",\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 575138eb2a..fe610ae951 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -69,40 +69,48 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase end def test_mysql_default_in_strict_mode - result = @connection.exec_query "SELECT @@SESSION.sql_mode" - assert_equal [["STRICT_ALL_TABLES"]], result.rows + result = @connection.select_value("SELECT @@SESSION.sql_mode") + assert_match %r(STRICT_ALL_TABLES), result 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 + ActiveRecord::Base.establish_connection(orig_connection.merge(strict: false)) + result = ActiveRecord::Base.connection.select_value("SELECT @@SESSION.sql_mode") + assert_no_match %r(STRICT_ALL_TABLES), result + 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.select_value("SELECT @@GLOBAL.sql_mode") + session_sql_mode = ActiveRecord::Base.connection.select_value("SELECT @@SESSION.sql_mode") + assert_equal global_sql_mode, session_sql_mode + end + end + + 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.select_value('SELECT @@SESSION.sql_mode') + assert_no_match %r(STRICT_ALL_TABLES), result end end def test_passing_arbitary_flags_to_adapter - run_without_connection do |orig_connection| + run_without_connection do |orig_connection| ActiveRecord::Base.establish_connection(orig_connection.merge({flags: Mysql2::Client::COMPRESS})) assert_equal (Mysql2::Client::COMPRESS | Mysql2::Client::FOUND_ROWS), ActiveRecord::Base.connection.raw_connection.query_options[:flags] end end - + def test_passing_flags_by_array_to_adapter - run_without_connection do |orig_connection| + run_without_connection do |orig_connection| ActiveRecord::Base.establish_connection(orig_connection.merge({flags: ['COMPRESS'] })) assert_equal ["COMPRESS", "FOUND_ROWS"], ActiveRecord::Base.connection.raw_connection.query_options[:flags] 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| @@ -112,14 +120,6 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase end end - 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' - 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}})) @@ -144,7 +144,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase end def test_get_and_release_advisory_lock - lock_name = "test_lock_name" + lock_name = "test lock'n'name" got_lock = @connection.get_advisory_lock(lock_name) assert got_lock, "get_advisory_lock should have returned true but it didn't" @@ -159,7 +159,7 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase end def test_release_non_existent_advisory_lock - lock_name = "fake_lock_name" + lock_name = "fake lock'n'name" released_non_existent_lock = @connection.release_advisory_lock(lock_name) assert_equal released_non_existent_lock, false, 'expected release_advisory_lock to return false when there was no lock to release' @@ -168,6 +168,6 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase protected def test_lock_free(lock_name) - @connection.select_value("SELECT IS_FREE_LOCK('#{lock_name}');") == 1 + @connection.select_value("SELECT IS_FREE_LOCK(#{@connection.quote(lock_name)})") == 1 end end diff --git a/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb b/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb new file mode 100644 index 0000000000..e349c67c93 --- /dev/null +++ b/activerecord/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb @@ -0,0 +1,45 @@ +require "cases/helper" + +class Mysql2DatetimePrecisionQuotingTest < ActiveRecord::Mysql2TestCase + setup do + @connection = ActiveRecord::Base.connection + end + + test 'microsecond precision for MySQL gte 5.6.4' do + stub_version '5.6.4' + assert_microsecond_precision + end + + test 'no microsecond precision for MySQL lt 5.6.4' do + stub_version '5.6.3' + assert_no_microsecond_precision + end + + test 'microsecond precision for MariaDB gte 5.3.0' do + stub_version '5.5.5-10.1.8-MariaDB-log' + assert_microsecond_precision + end + + test 'no microsecond precision for MariaDB lt 5.3.0' do + stub_version '5.2.9-MariaDB' + assert_no_microsecond_precision + end + + private + def assert_microsecond_precision + assert_match_quoted_microsecond_datetime(/\.000001\z/) + end + + def assert_no_microsecond_precision + assert_match_quoted_microsecond_datetime(/\d\z/) + end + + def assert_match_quoted_microsecond_datetime(match) + assert_match match, @connection.quoted_date(Time.now.change(usec: 1)) + end + + def stub_version(full_version_string) + @connection.stubs(:full_version).returns(full_version_string) + @connection.remove_instance_variable(:@version) if @connection.instance_variable_defined?(:@version) + end +end diff --git a/activerecord/test/cases/adapters/mysql2/enum_test.rb b/activerecord/test/cases/adapters/mysql2/enum_test.rb index bb89e893e0..35dbc76d1b 100644 --- a/activerecord/test/cases/adapters/mysql2/enum_test.rb +++ b/activerecord/test/cases/adapters/mysql2/enum_test.rb @@ -18,4 +18,9 @@ class Mysql2EnumTest < ActiveRecord::Mysql2TestCase column = EnumTest.columns_hash['enum_column'] assert_not column.unsigned? end + + def test_should_not_be_bigint + column = EnumTest.columns_hash['enum_column'] + assert_not column.bigint? + end end diff --git a/activerecord/test/cases/adapters/mysql2/explain_test.rb b/activerecord/test/cases/adapters/mysql2/explain_test.rb index 4fc7414b18..b783b5fcd9 100644 --- a/activerecord/test/cases/adapters/mysql2/explain_test.rb +++ b/activerecord/test/cases/adapters/mysql2/explain_test.rb @@ -2,26 +2,20 @@ require "cases/helper" require 'models/developer' require 'models/computer' -module ActiveRecord - module ConnectionAdapters - class Mysql2Adapter - class ExplainTest < ActiveRecord::Mysql2TestCase - fixtures :developers +class Mysql2ExplainTest < ActiveRecord::Mysql2TestCase + 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_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` = 1), explain - assert_match %r(audit_logs |.* ALL), explain - end - end - 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` = 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 index c8c933af5e..9c3fef1b59 100644 --- a/activerecord/test/cases/adapters/mysql2/json_test.rb +++ b/activerecord/test/cases/adapters/mysql2/json_test.rb @@ -161,12 +161,19 @@ class Mysql2JSONTest < ActiveRecord::Mysql2TestCase assert_not json.changed? end - def test_assigning_invalid_json - json = JsonDataType.new + def test_assigning_string_literal + json = JsonDataType.create(payload: "foo") + assert_equal "foo", json.payload + end - json.payload = 'foo' + def test_assigning_number + json = JsonDataType.create(payload: 1.234) + assert_equal 1.234, json.payload + end - assert_nil json.payload + def test_assigning_boolean + json = JsonDataType.create(payload: true) + assert_equal true, json.payload end end end diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb index 4efd728754..61dd0828d0 100644 --- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb @@ -1,10 +1,33 @@ require "cases/helper" +require "support/ddl_helper" class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase + include DdlHelper + def setup @conn = ActiveRecord::Base.connection end + def test_exec_query_nothing_raises_with_no_result_queries + assert_nothing_raised do + with_example_table do + @conn.exec_query('INSERT INTO ex (number) VALUES (1)') + @conn.exec_query('DELETE FROM ex WHERE number = 1') + end + end + end + + def test_valid_column + with_example_table do + column = @conn.columns('ex').find { |col| col.name == 'id' } + assert @conn.valid_type?(column.type) + end + end + + def test_invalid_column + assert_not @conn.valid_type?(:foobar) + end + def test_columns_for_distinct_zero_orders assert_equal "posts.id", @conn.columns_for_distinct("posts.id", []) @@ -41,4 +64,10 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase assert_equal "posts.id, posts.created_at AS alias_0", @conn.columns_for_distinct("posts.id", [order]) end + + private + + def with_example_table(definition = 'id int auto_increment primary key, number int, data varchar(255)', &block) + super(@conn, 'ex', definition, &block) + end end diff --git a/activerecord/test/cases/adapters/mysql2/quoting_test.rb b/activerecord/test/cases/adapters/mysql2/quoting_test.rb deleted file mode 100644 index 2de7e1b526..0000000000 --- a/activerecord/test/cases/adapters/mysql2/quoting_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -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/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb index 9a9a4fed42..7c89fda582 100644 --- a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb +++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb @@ -33,11 +33,6 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase end end - def test_key_limit_max_matches_max - assert_equal ActiveRecord::InternalMetadata::KEY_LIMIT ,ActiveRecord::ConnectionAdapters::Mysql2Adapter::MAX_INDEX_LENGTH_FOR_CHARSETS_OF_4BYTES_MAXLEN - end - - private def with_encoding_utf8mb4 diff --git a/activerecord/test/cases/adapters/mysql2/transaction_test.rb b/activerecord/test/cases/adapters/mysql2/transaction_test.rb new file mode 100644 index 0000000000..0e37c70e5c --- /dev/null +++ b/activerecord/test/cases/adapters/mysql2/transaction_test.rb @@ -0,0 +1,62 @@ +require "cases/helper" +require 'support/connection_helper' + +module ActiveRecord + class Mysql2TransactionTest < ActiveRecord::Mysql2TestCase + self.use_transactional_tests = false + + class Sample < ActiveRecord::Base + self.table_name = 'samples' + end + + setup do + @connection = ActiveRecord::Base.connection + @connection.clear_cache! + + @connection.transaction do + @connection.drop_table 'samples', if_exists: true + @connection.create_table('samples') do |t| + t.integer 'value' + end + end + + Sample.reset_column_information + end + + teardown do + @connection.drop_table 'samples', if_exists: true + end + + test "raises error when a serialization failure occurs" do + assert_raises(ActiveRecord::TransactionSerializationError) do + thread = Thread.new do + Sample.transaction isolation: :serializable do + Sample.delete_all + + 10.times do |i| + sleep 0.1 + + Sample.create value: i + end + end + end + + sleep 0.1 + + Sample.transaction isolation: :serializable do + Sample.delete_all + + 10.times do |i| + sleep 0.1 + + Sample.create value: i + end + + sleep 1 + end + + thread.join + end + end + end +end diff --git a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb index c95a64cc16..3df11ce11b 100644 --- a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb +++ b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb @@ -28,10 +28,10 @@ class Mysql2UnsignedTypeTest < ActiveRecord::Mysql2TestCase end test "minus value is out of range" do - assert_raise(RangeError) do + assert_raise(ActiveModel::RangeError) do UnsignedType.create(unsigned_integer: -10) end - assert_raise(RangeError) do + assert_raise(ActiveModel::RangeError) do UnsignedType.create(unsigned_bigint: -10) end assert_raise(ActiveRecord::StatementInvalid) do @@ -58,7 +58,7 @@ class Mysql2UnsignedTypeTest < ActiveRecord::Mysql2TestCase test "schema dump includes unsigned option" do schema = dump_table_schema "unsigned_types" assert_match %r{t.integer\s+"unsigned_integer",\s+unsigned: true$}, schema - assert_match %r{t.integer\s+"unsigned_bigint",\s+limit: 8,\s+unsigned: true$}, schema + assert_match %r{t.bigint\s+"unsigned_bigint",\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 |