diff --git a/mysql-test/suite/innodb/r/innodb-blob.result b/mysql-test/suite/innodb/r/innodb-blob.result index 8173d30e92c..0be1ca5b938 100644 --- a/mysql-test/suite/innodb/r/innodb-blob.result +++ b/mysql-test/suite/innodb/r/innodb-blob.result @@ -20,8 +20,6 @@ a RIGHT(b,20) 2 bbbbbbbbbbbbbbbbbbbb connection default; SET DEBUG='+d,row_ins_extern_checkpoint'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead SET DEBUG_SYNC='before_row_ins_extern_latch SIGNAL rec_not_blob WAIT_FOR crash'; ROLLBACK; BEGIN; @@ -88,8 +86,6 @@ BEGIN; INSERT INTO t2 VALUES (347); connection default; SET DEBUG='+d,row_upd_extern_checkpoint'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead SET DEBUG_SYNC='before_row_upd_extern SIGNAL have_latch WAIT_FOR crash'; UPDATE t3 SET c=REPEAT('i',3000) WHERE a=2; connection con2; @@ -126,8 +122,6 @@ BEGIN; INSERT INTO t2 VALUES (33101); connection default; SET DEBUG='+d,row_upd_extern_checkpoint'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead SET DEBUG_SYNC='after_row_upd_extern SIGNAL have_latch WAIT_FOR crash'; UPDATE t3 SET c=REPEAT('j',3000) WHERE a=2; connection con2; diff --git a/mysql-test/suite/innodb/r/innodb-index-debug.result b/mysql-test/suite/innodb/r/innodb-index-debug.result index 0995b526821..7167a80f3cb 100644 --- a/mysql-test/suite/innodb/r/innodb-index-debug.result +++ b/mysql-test/suite/innodb/r/innodb-index-debug.result @@ -92,8 +92,6 @@ ALTER TABLE t1 FORCE, ADD COLUMN k4 int; connection default; SET DEBUG_SYNC= 'now WAIT_FOR opened'; SET debug = '+d,row_log_tmpfile_fail'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead INSERT INTO t1 select NULL,'aaa','bbb' from t480; INSERT INTO t1 select NULL,'aaaa','bbbb' from t480; SET DEBUG_SYNC= 'now SIGNAL flushed'; diff --git a/mysql-test/suite/innodb/r/innodb-table-online.result b/mysql-test/suite/innodb/r/innodb-table-online.result index 9296fded0fd..de42ecd7979 100644 --- a/mysql-test/suite/innodb/r/innodb-table-online.result +++ b/mysql-test/suite/innodb/r/innodb-table-online.result @@ -38,16 +38,10 @@ SET DEBUG_DBUG = '+d,innodb_OOM_prepare_inplace_alter'; ALTER TABLE t1 ROW_FORMAT=REDUNDANT, ALGORITHM=INPLACE, LOCK=NONE; ERROR HY000: Out of memory. SET SESSION DEBUG = @saved_debug_dbug; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead SET SESSION DEBUG = '+d,innodb_OOM_inplace_alter'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead ALTER TABLE t1 ROW_FORMAT=REDUNDANT, ALGORITHM=INPLACE, LOCK=NONE; ERROR HY000: Out of memory. SET SESSION DEBUG = @saved_debug_dbug; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead ALTER TABLE t1 ROW_FORMAT=REDUNDANT, ALGORITHM=INPLACE, LOCK=NONE; connection default; SHOW CREATE TABLE t1; diff --git a/mysql-test/suite/innodb/r/page_reorganize.result b/mysql-test/suite/innodb/r/page_reorganize.result index 20e1600bd0d..fe85926e2b8 100644 --- a/mysql-test/suite/innodb/r/page_reorganize.result +++ b/mysql-test/suite/innodb/r/page_reorganize.result @@ -16,8 +16,6 @@ SET @save_dbug = @@debug_dbug; SET DEBUG_DBUG = '+d,do_page_reorganize,do_lock_reverse_page_reorganize'; insert into t1(f2) values (repeat('+', 100)); SET DEBUG = @save_dbug; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead commit; connection con1; f1 diff --git a/mysql-test/suite/innodb_fts/r/ft_result_cache_limit.result b/mysql-test/suite/innodb_fts/r/ft_result_cache_limit.result index 2dbdd5a04bc..74d60410d58 100644 --- a/mysql-test/suite/innodb_fts/r/ft_result_cache_limit.result +++ b/mysql-test/suite/innodb_fts/r/ft_result_cache_limit.result @@ -20,8 +20,6 @@ END// CALL populate_t1; SET autocommit=1; SET SESSION debug="+d,fts_instrument_result_cache_limit"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead ALTER TABLE t1 ADD FULLTEXT INDEX `text_content_idx` (`text_content`); SELECT FTS_DOC_ID, text_content FROM t1 diff --git a/mysql-test/suite/innodb_gis/r/check_rtree.result b/mysql-test/suite/innodb_gis/r/check_rtree.result index fe60a628fde..0d7b25b6b72 100644 --- a/mysql-test/suite/innodb_gis/r/check_rtree.result +++ b/mysql-test/suite/innodb_gis/r/check_rtree.result @@ -1,7 +1,5 @@ create table t1 (i int, g geometry not null, spatial index (g))engine=innodb; SET SESSION debug="+d,rtree_test_check_count"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead insert into t1 values (1, POINT(1,1)); insert into t1 values (1, POINT(1.5,1.5)); insert into t1 values (1, POINT(3,3)); diff --git a/mysql-test/suite/innodb_gis/r/rollback.result b/mysql-test/suite/innodb_gis/r/rollback.result index 0d2b9c7cf2c..1efe5d284f7 100644 --- a/mysql-test/suite/innodb_gis/r/rollback.result +++ b/mysql-test/suite/innodb_gis/r/rollback.result @@ -408,8 +408,6 @@ update t1 set a=point(5,5), b=point(5,5), c=5 where i < 3; ERROR 23000: Duplicate entry '5' for key 'c' rollback; set session debug="+d,row_mysql_crash_if_error"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead update t1 set a=point(5,5), b=point(5,5), c=5 where i < 3; ERROR HY000: Lost connection to server during query insert into t1 values(5, point(5,5), point(5,5), 5); diff --git a/mysql-test/suite/innodb_gis/r/rtree_compress.result b/mysql-test/suite/innodb_gis/r/rtree_compress.result index db9d5bd634c..9b646985dd4 100644 --- a/mysql-test/suite/innodb_gis/r/rtree_compress.result +++ b/mysql-test/suite/innodb_gis/r/rtree_compress.result @@ -44,8 +44,6 @@ count(*) 0 SET @saved_dbug = @@SESSION.debug_dbug; SET DEBUG='+d,page_copy_rec_list_start_compress_fail'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead delete from t1; select count(*) from t1 where MBRWithin(t1.c2, @g1); count(*) diff --git a/mysql-test/suite/innodb_gis/r/rtree_create_inplace.result b/mysql-test/suite/innodb_gis/r/rtree_create_inplace.result index a8898f5c98f..5279eea8aa8 100644 --- a/mysql-test/suite/innodb_gis/r/rtree_create_inplace.result +++ b/mysql-test/suite/innodb_gis/r/rtree_create_inplace.result @@ -31,7 +31,5 @@ COUNT(*) 0 ALTER TABLE t1 DROP INDEX idx, ADD SPATIAL INDEX idx3(c2); SET SESSION debug="+d,row_merge_instrument_log_check_flush"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead ALTER TABLE t1 DROP INDEX idx3, ADD SPATIAL INDEX idx4(c2), ADD SPATIAL INDEX idx5(c3); DROP TABLE t1; diff --git a/mysql-test/suite/perfschema/r/sxlock_func,debug.rdiff b/mysql-test/suite/perfschema/r/sxlock_func,debug.rdiff new file mode 100644 index 00000000000..0596810e553 --- /dev/null +++ b/mysql-test/suite/perfschema/r/sxlock_func,debug.rdiff @@ -0,0 +1,22 @@ +@@ -7,7 +7,6 @@ + WHERE name LIKE 'wait/synch/rwlock/innodb/%' + AND name!='wait/synch/rwlock/innodb/btr_search_latch' ORDER BY name; + name +-wait/synch/rwlock/innodb/dict_operation_lock + wait/synch/rwlock/innodb/fil_space_latch + wait/synch/rwlock/innodb/lock_latch + wait/synch/rwlock/innodb/trx_i_s_cache_lock +@@ -19,11 +18,13 @@ + select name from performance_schema.setup_instruments + where name like "wait/synch/sxlock/%" order by name; + name ++wait/synch/sxlock/innodb/dict_operation_lock + wait/synch/sxlock/innodb/index_tree_rw_lock + SELECT DISTINCT name FROM performance_schema.rwlock_instances + WHERE name LIKE 'wait/synch/sxlock/innodb/%' + ORDER BY name; + name ++wait/synch/sxlock/innodb/dict_operation_lock + wait/synch/sxlock/innodb/index_tree_rw_lock + create table t1(a int) engine=innodb; + begin; diff --git a/mysql-test/suite/perfschema/t/sxlock_func.test b/mysql-test/suite/perfschema/t/sxlock_func.test index c43adc849d2..24d0e07ca41 100644 --- a/mysql-test/suite/perfschema/t/sxlock_func.test +++ b/mysql-test/suite/perfschema/t/sxlock_func.test @@ -5,6 +5,7 @@ --source include/not_embedded.inc --source include/have_perfschema.inc --source include/have_innodb.inc +--source include/maybe_debug.inc UPDATE performance_schema.setup_instruments SET enabled = 'NO', timed = 'YES'; diff --git a/mysql-test/suite/rpl/r/rpl_semisync_ali_issues.result b/mysql-test/suite/rpl/r/rpl_semisync_ali_issues.result index 36a2bac5838..530bbac633b 100644 --- a/mysql-test/suite/rpl/r/rpl_semisync_ali_issues.result +++ b/mysql-test/suite/rpl/r/rpl_semisync_ali_issues.result @@ -270,16 +270,12 @@ Variable_name Value Rpl_semi_sync_master_clients 1 # Test failure of select error . SET GLOBAL debug = 'd,rpl_semisync_simulate_select_error'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead INSERT INTO t1 VALUES(3); connection slave; connection con1; # Test failure of pthread_create SET GLOBAL rpl_semi_sync_master_enabled = 0; SET GLOBAL debug = 'd,rpl_semisync_simulate_create_thread_failure'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead SET GLOBAL rpl_semi_sync_master_enabled= ON; # Test failure of pthread_join SET GLOBAL rpl_semi_sync_master_enabled= OFF; @@ -287,8 +283,6 @@ SET GLOBAL rpl_semi_sync_master_enabled= OFF; # Failure on registering semisync slave # SET GLOBAL debug= 'd,rpl_semisync_simulate_add_slave_failure'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead SET GLOBAL rpl_semi_sync_master_enabled= ON; connection slave; STOP SLAVE IO_THREAD; @@ -297,8 +291,6 @@ START SLAVE IO_THREAD; include/wait_for_slave_io_to_start.inc connection con1; SET GLOBAL debug=''; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead connection slave; START SLAVE IO_THREAD; include/wait_for_slave_io_to_start.inc diff --git a/mysql-test/suite/sys_vars/r/debug_basic.result b/mysql-test/suite/sys_vars/r/debug_basic.result index a97ad65b40f..5a77446d036 100644 --- a/mysql-test/suite/sys_vars/r/debug_basic.result +++ b/mysql-test/suite/sys_vars/r/debug_basic.result @@ -1,6 +1,4 @@ set session debug="L"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead select @@global.debug="1"; @@global.debug="1" 0 diff --git a/mysql-test/suite/sys_vars/r/sysvars_debug.result b/mysql-test/suite/sys_vars/r/sysvars_debug.result index fc04ac83210..01f74170b1d 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_debug.result +++ b/mysql-test/suite/sys_vars/r/sysvars_debug.result @@ -38,7 +38,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE VARIABLE_SCOPE SESSION VARIABLE_TYPE VARCHAR -VARIABLE_COMMENT Built-in DBUG debugger +VARIABLE_COMMENT Built-in DBUG debugger. Alias for --debug NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.result b/plugin/type_inet/mysql-test/type_inet/type_inet6.result index 1fe4decb388..5ac2657f0b3 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.result @@ -2284,6 +2284,81 @@ Warnings: Warning 1292 Incorrect inet6 value: '' DROP TABLE t1; # +# MDEV-32879 Server crash in my_decimal::operator= or unexpected ER_DUP_ENTRY upon comparison with INET6 and similar types +# +CREATE TABLE t1 (a CHAR(36) NOT NULL, b INET6 NOT NULL, c DATETIME(6) NOT NULL); +INSERT INTO t1 VALUES ('','::','2000-01-01'),('','::','1900-01-01'); +SELECT c + (b = a) AS f, GROUP_CONCAT(c) FROM t1 GROUP BY f; +f GROUP_CONCAT(c) +NULL 2000-01-01 00:00:00.000000,1900-01-01 00:00:00.000000 +Warnings: +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +DROP TABLE t1; +CREATE TABLE t1 (a CHAR(36) NOT NULL, b INET6 NOT NULL, c DATETIME(6) NOT NULL); +INSERT INTO t1 VALUES ('','::','2000-01-01'),('','::','1900-01-01'); +SELECT c + (b = a) AS f, COUNT(c) FROM t1 GROUP BY f; +f COUNT(c) +NULL 2 +Warnings: +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 (a CHAR(36) NOT NULL, b INET6 NOT NULL, c DATETIME(6) NOT NULL); +INSERT INTO t1 VALUES ('','::','2000-01-01'),('','::','1900-01-01'); +SELECT c + (b = a) AS f FROM t1 ORDER BY f; +f +NULL +NULL +Warnings: +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 (a CHAR(36) NOT NULL, b INET6 NOT NULL); +INSERT INTO t1 VALUES ('','::'),('','::'); +SELECT 1.00 + (b = a) AS f FROM t1 ORDER BY f; +f +NULL +NULL +Warnings: +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +SELECT 1.00 + (b BETWEEN a AND '') AS f FROM t1 ORDER BY f; +f +NULL +NULL +Warnings: +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +SELECT 1.00 + (b IN (a,'')) AS f FROM t1 ORDER BY f; +f +NULL +NULL +Warnings: +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +Warning 1292 Incorrect inet6 value: '' +DROP TABLE t1; +# # MDEV-22256 Assertion `length == pack_length()' failed in Field_timestamp_with_dec::sort_string # SET sql_mode=''; diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.test b/plugin/type_inet/mysql-test/type_inet/type_inet6.test index 99f75312f3c..0c56ecfe4bb 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6.test +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.test @@ -1675,6 +1675,32 @@ INSERT INTO t1 VALUES ('::'); SELECT * FROM t1 WHERE a IN ('','::1'); DROP TABLE t1; +--echo # +--echo # MDEV-32879 Server crash in my_decimal::operator= or unexpected ER_DUP_ENTRY upon comparison with INET6 and similar types +--echo # + +CREATE TABLE t1 (a CHAR(36) NOT NULL, b INET6 NOT NULL, c DATETIME(6) NOT NULL); +INSERT INTO t1 VALUES ('','::','2000-01-01'),('','::','1900-01-01'); +SELECT c + (b = a) AS f, GROUP_CONCAT(c) FROM t1 GROUP BY f; +DROP TABLE t1; + +CREATE TABLE t1 (a CHAR(36) NOT NULL, b INET6 NOT NULL, c DATETIME(6) NOT NULL); +INSERT INTO t1 VALUES ('','::','2000-01-01'),('','::','1900-01-01'); +SELECT c + (b = a) AS f, COUNT(c) FROM t1 GROUP BY f; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 (a CHAR(36) NOT NULL, b INET6 NOT NULL, c DATETIME(6) NOT NULL); +INSERT INTO t1 VALUES ('','::','2000-01-01'),('','::','1900-01-01'); +SELECT c + (b = a) AS f FROM t1 ORDER BY f; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 (a CHAR(36) NOT NULL, b INET6 NOT NULL); +INSERT INTO t1 VALUES ('','::'),('','::'); +SELECT 1.00 + (b = a) AS f FROM t1 ORDER BY f; +SELECT 1.00 + (b BETWEEN a AND '') AS f FROM t1 ORDER BY f; +SELECT 1.00 + (b IN (a,'')) AS f FROM t1 ORDER BY f; +DROP TABLE t1; + --echo # --echo # MDEV-22256 Assertion `length == pack_length()' failed in Field_timestamp_with_dec::sort_string --echo # diff --git a/scripts/mysql_setpermission.sh b/scripts/mysql_setpermission.sh index b3c9c27ca88..aa165a5e742 100644 --- a/scripts/mysql_setpermission.sh +++ b/scripts/mysql_setpermission.sh @@ -68,7 +68,7 @@ usage() if ($opt_help); # the help function if ($opt_host =~ s/:(\d+)$//) { - $opt_port = $1; + $opt_port = $1; } if ($opt_host eq '') @@ -98,7 +98,7 @@ my $prefix= 'mysql'; if (eval {DBI->install_driver("MariaDB")}) { $dsn ="DBI:MariaDB:;"; $prefix= 'mariadb'; -} +} else { $dsn = "DBI:mysql:;"; } @@ -226,11 +226,11 @@ sub setpwd { $pass = "PASSWORD(". $dbh->quote($pass) . ")"; } - my $uh= "$user@$host"; + my $uh= $user."@".$host; my $sth = $dbh->prepare("set password for $uh =$pass") || die $dbh->errstr; $sth->execute || die $dbh->errstr; $sth->finish; - print "The password is set for user $user.\n\n"; + print "The password is set for user $uh.\n\n"; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index bfe03e1cbc6..0dc0f49d9fc 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -457,40 +457,6 @@ void Item_bool_func::raise_note_if_key_become_unused(THD *thd, const Item_args & } -bool Item_func::setup_args_and_comparator(THD *thd, Arg_comparator *cmp) -{ - DBUG_ASSERT(arg_count >= 2); // Item_func_nullif has arg_count == 3 - - if (args[0]->cmp_type() == STRING_RESULT && - args[1]->cmp_type() == STRING_RESULT) - { - CHARSET_INFO *tmp; - /* - Use charset narrowing only for equalities, as that would allow - to construct ref access. - Non-equality comparisons with constants work without charset narrowing, - the constant gets converted. - Non-equality comparisons with non-constants would need narrowing to - enable range optimizer to handle e.g. - t1.mb3key_col <= const_table.mb4_col - But this doesn't look important. - */ - bool allow_narrowing= MY_TEST(functype()==Item_func::EQ_FUNC || - functype()==Item_func::EQUAL_FUNC); - - if (agg_arg_charsets_for_comparison(&tmp, &args[0], &args[1], - allow_narrowing)) - return true; - cmp->m_compare_collation= tmp; - } - // Convert constants when compared to int/year field - DBUG_ASSERT(functype() != LIKE_FUNC); - convert_const_compared_to_int_field(thd); - - return cmp->set_cmp_func(thd, this, &args[0], &args[1], true); -} - - /* Comparison operators remove arguments' dependency on PAD_CHAR_TO_FULL_LENGTH in case of PAD SPACE comparison collations: trailing spaces do not affect @@ -519,8 +485,15 @@ bool Item_bool_rowready_func2::fix_length_and_dec(THD *thd) if (!args[0] || !args[1]) return FALSE; Item_args old_args(args[0], args[1]); - if (setup_args_and_comparator(thd, &cmp)) + convert_const_compared_to_int_field(thd); + Type_handler_hybrid_field_type tmp; + if (tmp.aggregate_for_comparison(func_name_cstring(), args, 2, false) || + tmp.type_handler()->Item_bool_rowready_func2_fix_length_and_dec(thd, + this)) + { + DBUG_ASSERT(thd->is_error()); return true; + } raise_note_if_key_become_unused(thd, old_args); return false; } @@ -540,21 +513,14 @@ bool Item_bool_rowready_func2::fix_length_and_dec(THD *thd) */ int Arg_comparator::set_cmp_func(THD *thd, Item_func_or_sum *owner_arg, + const Type_handler *compare_handler, Item **a1, Item **a2) { owner= owner_arg; set_null= set_null && owner_arg; a= a1; b= a2; - Item *tmp_args[2]= {*a1, *a2}; - Type_handler_hybrid_field_type tmp; - if (tmp.aggregate_for_comparison(owner_arg->func_name_cstring(), tmp_args, 2, - false)) - { - DBUG_ASSERT(thd->is_error()); - return 1; - } - m_compare_handler= tmp.type_handler(); + m_compare_handler= compare_handler; return m_compare_handler->set_comparator_func(thd, this); } @@ -605,6 +571,14 @@ bool Arg_comparator::set_cmp_func_string(THD *thd) We must set cmp_collation here as we may be called from for an automatic generated item, like in natural join. Allow reinterpted superset as subset. + Use charset narrowing only for equalities, as that would allow + to construct ref access. + Non-equality comparisons with constants work without charset narrowing, + the constant gets converted. + Non-equality comparisons with non-constants would need narrowing to + enable range optimizer to handle e.g. + t1.mb3key_col <= const_table.mb4_col + But this doesn't look important. */ bool allow_narrowing= false; if (owner->type() == Item::FUNC_ITEM) @@ -2812,8 +2786,9 @@ Item_func_nullif::fix_length_and_dec(THD *thd) fix_char_length(args[2]->max_char_length()); set_maybe_null(); m_arg0= args[0]; - if (setup_args_and_comparator(thd, &cmp)) - return TRUE; + convert_const_compared_to_int_field(thd); + if (cmp.set_cmp_func(thd, this, &args[0], &args[1], true/*set_null*/)) + return true; /* A special code for EXECUTE..PREPARE. diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a67dfb5d7c8..8dc88f152d2 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -57,6 +57,7 @@ class Arg_comparator: public Sql_alloc // when one of arguments is NULL. int set_cmp_func(THD *thd, Item_func_or_sum *owner_arg, + const Type_handler *compare_handler, Item **a1, Item **a2); int compare_not_null_values(longlong val1, longlong val2) @@ -95,11 +96,24 @@ public: bool set_cmp_func_decimal(THD *thd); inline int set_cmp_func(THD *thd, Item_func_or_sum *owner_arg, - Item **a1, Item **a2, bool set_null_arg) + const Type_handler *compare_handler, + Item **a1, Item **a2, bool set_null_arg) { set_null= set_null_arg; - return set_cmp_func(thd, owner_arg, a1, a2); + return set_cmp_func(thd, owner_arg, compare_handler, a1, a2); } + int set_cmp_func(THD *thd, Item_func_or_sum *owner_arg, + Item **a1, Item **a2, bool set_null_arg) + { + Item *tmp_args[2]= { *a1, *a2 }; + Type_handler_hybrid_field_type tmp; + if (tmp.aggregate_for_comparison(owner_arg->func_name_cstring(), + tmp_args, 2, false)) + return 1; + return set_cmp_func(thd, owner_arg, tmp.type_handler(), + a1, a2, set_null_arg); + } + inline int compare() { return (this->*func)(); } int compare_string(); // compare args[0] & args[1] @@ -561,9 +575,17 @@ public: return this; } bool fix_length_and_dec(THD *thd) override; + bool fix_length_and_dec_generic(THD *thd, + const Type_handler *compare_handler) + { + DBUG_ASSERT(args == tmp_arg); + return cmp.set_cmp_func(thd, this, compare_handler, + tmp_arg, tmp_arg + 1, true/*set_null*/); + } int set_cmp_func(THD *thd) { - return cmp.set_cmp_func(thd, this, tmp_arg, tmp_arg + 1, true); + DBUG_ASSERT(args == tmp_arg); + return cmp.set_cmp_func(thd, this, tmp_arg, tmp_arg + 1, true/*set_null*/); } CHARSET_INFO *compare_collation() const override { return cmp.compare_collation(); } diff --git a/sql/item_func.h b/sql/item_func.h index 435875bd6c3..74ed1a6b425 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -388,15 +388,6 @@ public: } } void convert_const_compared_to_int_field(THD *thd); - /** - Prepare arguments and setup a comparator. - Used in Item_func_xxx with two arguments and a comparator, - e.g. Item_bool_func2 and Item_func_nullif. - args[0] or args[1] can be modified: - - converted to character set and collation of the operation - - or replaced to an Item_int_with_ref - */ - bool setup_args_and_comparator(THD *thd, Arg_comparator *cmp); Item_func *get_item_func() override { return this; } bool is_simplified_cond_processor(void *arg) override { return const_item() && !val_int(); } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index bbd09a59267..ae92f58cd6f 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1296,9 +1296,14 @@ void Item_sum_min_max::setup_hybrid(THD *thd, Item *item, Item *value_arg) /* Don't cache value, as it will change */ if (!item->const_item()) arg_cache->set_used_tables(RAND_TABLE_BIT); + DBUG_ASSERT(item->type_handler_for_comparison() == + value->type_handler_for_comparison()); + DBUG_ASSERT(item->type_handler_for_comparison() == + arg_cache->type_handler_for_comparison()); cmp= new (thd->mem_root) Arg_comparator(); if (cmp) - cmp->set_cmp_func(thd, this, (Item**)&arg_cache, (Item**)&value, FALSE); + cmp->set_cmp_func(thd, this, item->type_handler_for_comparison(), + (Item**)&arg_cache, (Item**)&value, FALSE); DBUG_VOID_RETURN; } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 277f495af4a..33c1b48aad9 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -5668,6 +5668,14 @@ Type_handler_string_result::Item_func_hybrid_field_type_get_date( /***************************************************************************/ +bool Type_handler::Item_bool_rowready_func2_fix_length_and_dec(THD *thd, + Item_bool_rowready_func2 *func) const +{ + return func->fix_length_and_dec_generic(thd, this); +} + +/***************************************************************************/ + bool Type_handler_numeric:: Item_func_between_fix_length_and_dec(Item_func_between *func) const { diff --git a/sql/sql_type.h b/sql/sql_type.h index 35c13a38668..4042976dde2 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -55,6 +55,7 @@ class Item_hybrid_func; class Item_func_min_max; class Item_func_hybrid_field_type; class Item_bool_func2; +class Item_bool_rowready_func2; class Item_func_between; class Item_func_in; class Item_func_round; @@ -4257,6 +4258,8 @@ public: } virtual bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, Item *a, Item *b) const= 0; + virtual bool Item_bool_rowready_func2_fix_length_and_dec(THD *thd, + Item_bool_rowready_func2 *func) const; virtual bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *, diff --git a/sql/sql_type_fixedbin.h b/sql/sql_type_fixedbin.h index 88c24ba0776..65418c34032 100644 --- a/sql/sql_type_fixedbin.h +++ b/sql/sql_type_fixedbin.h @@ -136,6 +136,21 @@ public: return Fbt_null(item, false).is_null(); } + /* + Check at fix_fields() time if any of the items can return a nullable + value on conversion to Fbt. + */ + static bool fix_fields_maybe_null_on_conversion_to_fbt(Item **items, + uint count) + { + for (uint i= 0; i < count; i++) + { + if (Fbt::fix_fields_maybe_null_on_conversion_to_fbt(items[i])) + return true; + } + return false; + } + public: Fbt(Item *item, bool *error, bool warn= true) @@ -1534,6 +1549,16 @@ public: Fbt_null na(a), nb(b); return !na.is_null() && !nb.is_null() && !na.cmp(nb); } + bool Item_bool_rowready_func2_fix_length_and_dec(THD *thd, + Item_bool_rowready_func2 *func) const override + { + if (Type_handler::Item_bool_rowready_func2_fix_length_and_dec(thd, func)) + return true; + if (!func->maybe_null() && + Fbt::fix_fields_maybe_null_on_conversion_to_fbt(func->arguments(), 2)) + func->set_maybe_null(); + return false; + } bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, Type_handler_hybrid_field_type *h, Type_all_attributes *attr, @@ -1715,6 +1740,9 @@ public: bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override { + if (!func->maybe_null() && + Fbt::fix_fields_maybe_null_on_conversion_to_fbt(func->arguments(), 3)) + func->set_maybe_null(); return false; } longlong Item_func_between_val_int(Item_func_between *func) const override @@ -1737,6 +1765,10 @@ public: Item_func_in *func) const override { + if (!func->maybe_null() && + Fbt::fix_fields_maybe_null_on_conversion_to_fbt(func->arguments(), + func->argument_count())) + func->set_maybe_null(); if (func->compatible_types_scalar_bisection_possible()) { return func->value_list_convert_const_to_int(thd) || diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 0df11e0b537..0319298a9d7 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1037,11 +1037,10 @@ static Sys_var_charptr_fscs Sys_datadir( static Sys_var_dbug Sys_dbug( "debug", "Built-in DBUG debugger", sys_var::SESSION, CMD_LINE(OPT_ARG, '#'), DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, - ON_CHECK(check_has_super), ON_UPDATE(0), - DEPRECATED("'@@debug_dbug'")); // since 5.5.37 + ON_CHECK(check_has_super)); static Sys_var_dbug Sys_debug_dbug( - "debug_dbug", "Built-in DBUG debugger", sys_var::SESSION, + "debug_dbug", "Built-in DBUG debugger. Alias for --debug", sys_var::SESSION, CMD_LINE(OPT_ARG, '#'), DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super)); #endif diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 08be1991f02..7b55aaabfe0 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -873,7 +873,8 @@ static rec_offs *btr_page_get_parent(rec_offs *offsets, mem_heap_t *heap, /************************************************************//** Returns the upper level node pointer to a page. It is assumed that mtr holds an x-latch on the tree. -@return rec_get_offsets() of the node pointer record */ +@return rec_get_offsets() of the node pointer record +@retval nullptr on corruption */ static rec_offs* btr_page_get_father_block( @@ -2542,6 +2543,11 @@ btr_attach_half_pages( offsets = btr_page_get_father_block(nullptr, heap, mtr, &cursor); + if (UNIV_UNLIKELY(!offsets)) { + mem_heap_free(heap); + return DB_CORRUPTION; + } + /* Replace the address of the old child node (= page) with the address of the new lower half */ @@ -3478,6 +3484,14 @@ btr_lift_page_up( offsets = btr_page_get_father_block(offsets, heap, mtr, &cursor); } + + if (UNIV_UNLIKELY(!offsets)) { +parent_corrupted: + mem_heap_free(heap); + *err = DB_CORRUPTION; + return nullptr; + } + father_block = btr_cur_get_block(&cursor); father_page_zip = buf_block_get_page_zip(father_block); @@ -3502,6 +3516,10 @@ btr_lift_page_up( &cursor); } + if (UNIV_UNLIKELY(!offsets)) { + goto parent_corrupted; + } + blocks[n_blocks++] = b = btr_cur_get_block(&cursor); } @@ -3717,6 +3735,11 @@ btr_compress( NULL, heap, mtr, &father_cursor); } + if (UNIV_UNLIKELY(!offsets)) { + err = DB_CORRUPTION; + goto func_exit; + } + if (adjust) { nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); if (UNIV_UNLIKELY(!nth_rec || nth_rec == ULINT_UNDEFINED)) { diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 7e584ae07c3..1e13314bc40 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2541,14 +2541,21 @@ lookup: if (discard_attempted || !bpage->frame) { - /* Even when we are holding a hash_lock, it should be - acceptable to wait for a page S-latch here, because - buf_page_t::read_complete() will not wait for buf_pool.mutex, - and because S-latch would not conflict with a U-latch - that would be protecting buf_page_t::write_complete(). */ - bpage->lock.s_lock(); + const bool got_s_latch= bpage->lock.s_lock_try(); hash_lock.unlock_shared(); - break; + if (UNIV_LIKELY(got_s_latch)) + break; + /* We may fail to acquire bpage->lock because + buf_page_t::read_complete() may be invoking + buf_pool_t::corrupted_evict() on this block, which it would + hold an exclusive latch on. + + Let us aqcuire and release buf_pool.mutex to ensure that any + buf_pool_t::corrupted_evict() will proceed before we reacquire + the hash_lock that it could be waiting for. */ + mysql_mutex_lock(&buf_pool.mutex); + mysql_mutex_unlock(&buf_pool.mutex); + goto lookup; } hash_lock.unlock_shared(); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 5bc7ab6edd7..0e5761a9fc7 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -958,11 +958,12 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line)) if (latch_ex_wait_start.compare_exchange_strong (old, now, std::memory_order_relaxed, std::memory_order_relaxed)) { +#ifdef UNIV_DEBUG + latch.x_lock(SRW_LOCK_ARGS(file, line)); +#else latch.wr_lock(SRW_LOCK_ARGS(file, line)); +#endif latch_ex_wait_start.store(0, std::memory_order_relaxed); - ut_ad(!latch_readers); - ut_ad(!latch_ex); - ut_d(latch_ex= pthread_self()); return; } @@ -977,33 +978,39 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line)) if (waited > threshold / 4) ib::warn() << "A long wait (" << waited << " seconds) was observed for dict_sys.latch"; +#ifdef UNIV_DEBUG + latch.x_lock(SRW_LOCK_ARGS(file, line)); +#else latch.wr_lock(SRW_LOCK_ARGS(file, line)); - ut_ad(!latch_readers); - ut_ad(!latch_ex); - ut_d(latch_ex= pthread_self()); +#endif } #ifdef UNIV_PFS_RWLOCK ATTRIBUTE_NOINLINE void dict_sys_t::unlock() { - ut_ad(latch_ex == pthread_self()); - ut_ad(!latch_readers); - ut_d(latch_ex= 0); +# ifdef UNIV_DEBUG + latch.x_unlock(); +# else latch.wr_unlock(); +# endif } ATTRIBUTE_NOINLINE void dict_sys_t::freeze(const char *file, unsigned line) { +# ifdef UNIV_DEBUG + latch.s_lock(file, line); +# else latch.rd_lock(file, line); - ut_ad(!latch_ex); - ut_d(latch_readers++); +# endif } ATTRIBUTE_NOINLINE void dict_sys_t::unfreeze() { - ut_ad(!latch_ex); - ut_ad(latch_readers--); +# ifdef UNIV_DEBUG + latch.s_unlock(); +# else latch.rd_unlock(); +# endif } #endif /* UNIV_PFS_RWLOCK */ @@ -4539,7 +4546,11 @@ void dict_sys_t::close() temp_id_hash.free(); unlock(); +#ifdef UNIV_DEBUG + latch.free(); +#else latch.destroy(); +#endif mysql_mutex_destroy(&dict_foreign_err_mutex); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c87aaea1f8b..e553b55297c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -600,7 +600,13 @@ static PSI_rwlock_info all_innodb_rwlocks[] = # ifdef BTR_CUR_HASH_ADAPT { &btr_search_latch_key, "btr_search_latch", 0 }, # endif - { &dict_operation_lock_key, "dict_operation_lock", 0 }, + { &dict_operation_lock_key, "dict_operation_lock", +# ifdef UNIV_DEBUG + PSI_RWLOCK_FLAG_SX +# else + 0 +# endif + }, { &fil_space_latch_key, "fil_space_latch", 0 }, { &trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0 }, { &trx_purge_latch_key, "trx_purge_latch", 0 }, @@ -13488,14 +13494,7 @@ int ha_innobase::delete_table(const char *name) /* FOREIGN KEY constraints cannot exist on partitioned tables. */; #endif else - { - dict_sys.freeze(SRW_LOCK_CALL); - for (const dict_foreign_t* f : table->referenced_set) - if (dict_table_t* child= f->foreign_table) - if ((err= lock_table_for_trx(child, trx, LOCK_X)) != DB_SUCCESS) - break; - dict_sys.unfreeze(); - } + err= lock_table_children(table, trx); } dict_table_t *table_stats= nullptr, *index_stats= nullptr; @@ -13893,14 +13892,7 @@ int ha_innobase::truncate() dict_table_t *table_stats = nullptr, *index_stats = nullptr; MDL_ticket *mdl_table = nullptr, *mdl_index = nullptr; - dberr_t error= DB_SUCCESS; - - dict_sys.freeze(SRW_LOCK_CALL); - for (const dict_foreign_t *f : ib_table->referenced_set) - if (dict_table_t *child= f->foreign_table) - if ((error= lock_table_for_trx(child, trx, LOCK_X)) != DB_SUCCESS) - break; - dict_sys.unfreeze(); + dberr_t error= lock_table_children(ib_table, trx); if (error == DB_SUCCESS) error= lock_table_for_trx(ib_table, trx, LOCK_X); @@ -14091,16 +14083,7 @@ ha_innobase::rename_table( /* There is no need to lock any FOREIGN KEY child tables. */ } else if (dict_table_t *table = dict_table_open_on_name( norm_from, false, DICT_ERR_IGNORE_FK_NOKEY)) { - dict_sys.freeze(SRW_LOCK_CALL); - for (const dict_foreign_t* f : table->referenced_set) { - if (dict_table_t* child = f->foreign_table) { - error = lock_table_for_trx(child, trx, LOCK_X); - if (error != DB_SUCCESS) { - break; - } - } - } - dict_sys.unfreeze(); + error = lock_table_children(table, trx); if (error == DB_SUCCESS) { error = lock_table_for_trx(table, trx, LOCK_X); } @@ -15675,15 +15658,17 @@ ha_innobase::extra( { /* Warning: since it is not sure that MariaDB calls external_lock() before calling this function, m_prebuilt->trx can be obsolete! */ - trx_t* trx = check_trx_exists(ha_thd()); + trx_t* trx; switch (operation) { case HA_EXTRA_FLUSH: + (void)check_trx_exists(ha_thd()); if (m_prebuilt->blob_heap) { row_mysql_prebuilt_free_blob_heap(m_prebuilt); } break; case HA_EXTRA_RESET_STATE: + trx = check_trx_exists(ha_thd()); reset_template(); trx->duplicates = 0; stmt_boundary: @@ -15692,18 +15677,23 @@ ha_innobase::extra( trx->bulk_insert = false; break; case HA_EXTRA_NO_KEYREAD: + (void)check_trx_exists(ha_thd()); m_prebuilt->read_just_key = 0; break; case HA_EXTRA_KEYREAD: + (void)check_trx_exists(ha_thd()); m_prebuilt->read_just_key = 1; break; case HA_EXTRA_KEYREAD_PRESERVE_FIELDS: + (void)check_trx_exists(ha_thd()); m_prebuilt->keep_other_fields_on_keyread = 1; break; case HA_EXTRA_INSERT_WITH_UPDATE: + trx = check_trx_exists(ha_thd()); trx->duplicates |= TRX_DUP_IGNORE; goto stmt_boundary; case HA_EXTRA_NO_IGNORE_DUP_KEY: + trx = check_trx_exists(ha_thd()); trx->duplicates &= ~TRX_DUP_IGNORE; if (trx->is_bulk_insert()) { /* Allow a subsequent INSERT into an empty table @@ -15715,9 +15705,11 @@ ha_innobase::extra( } goto stmt_boundary; case HA_EXTRA_WRITE_CAN_REPLACE: + trx = check_trx_exists(ha_thd()); trx->duplicates |= TRX_DUP_REPLACE; goto stmt_boundary; case HA_EXTRA_WRITE_CANNOT_REPLACE: + trx = check_trx_exists(ha_thd()); trx->duplicates &= ~TRX_DUP_REPLACE; if (trx->is_bulk_insert()) { /* Allow a subsequent INSERT into an empty table @@ -15726,6 +15718,7 @@ ha_innobase::extra( } goto stmt_boundary; case HA_EXTRA_BEGIN_ALTER_COPY: + trx = check_trx_exists(ha_thd()); m_prebuilt->table->skip_alter_undo = 1; if (m_prebuilt->table->is_temporary() || !m_prebuilt->table->versioned_by_id()) { @@ -15738,6 +15731,7 @@ ha_innobase::extra( .first->second.set_versioned(0); break; case HA_EXTRA_END_ALTER_COPY: + trx = check_trx_exists(ha_thd()); m_prebuilt->table->skip_alter_undo = 0; if (!m_prebuilt->table->is_temporary() && !high_level_read_only) { diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 2753c114881..371ed64b6ca 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -11221,16 +11221,7 @@ ha_innobase::commit_inplace_alter_table( fts_optimize_remove_table(ctx->old_table); } - dict_sys.freeze(SRW_LOCK_CALL); - for (auto f : ctx->old_table->referenced_set) { - if (dict_table_t* child = f->foreign_table) { - error = lock_table_for_trx(child, trx, LOCK_X); - if (error != DB_SUCCESS) { - break; - } - } - } - dict_sys.unfreeze(); + error = lock_table_children(ctx->old_table, trx); if (ctx->new_table->fts) { ut_ad(!ctx->new_table->fts->add_wq); diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 5fafb2c54e8..dbea692a95f 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1313,14 +1313,14 @@ class dict_sys_t /** The my_hrtime_coarse().val of the oldest lock_wait() start, or 0 */ std::atomic latch_ex_wait_start; - /** the rw-latch protecting the data dictionary cache */ - alignas(CPU_LEVEL1_DCACHE_LINESIZE) srw_lock latch; #ifdef UNIV_DEBUG - /** whether latch is being held in exclusive mode (by any thread) */ - Atomic_relaxed latch_ex; - /** number of S-latch holders */ - Atomic_counter latch_readers; + typedef index_lock dict_lock; +#else + typedef srw_lock dict_lock; #endif + + /** the rw-latch protecting the data dictionary cache */ + alignas(CPU_LEVEL1_DCACHE_LINESIZE) dict_lock latch; public: /** Indexes of SYS_TABLE[] */ enum @@ -1488,15 +1488,12 @@ public: } #ifdef UNIV_DEBUG - /** @return whether any thread (not necessarily the current thread) - is holding the latch; that is, this check may return false - positives */ - bool frozen() const { return latch_readers || latch_ex; } - /** @return whether any thread (not necessarily the current thread) - is holding a shared latch */ - bool frozen_not_locked() const { return latch_readers; } + /** @return whether the current thread is holding the latch */ + bool frozen() const { return latch.have_any(); } + /** @return whether the current thread is holding a shared latch */ + bool frozen_not_locked() const { return latch.have_s(); } /** @return whether the current thread holds the exclusive latch */ - bool locked() const { return latch_ex == pthread_self(); } + bool locked() const { return latch.have_x(); } #endif private: /** Acquire the exclusive latch */ @@ -1511,13 +1508,11 @@ public: /** Exclusively lock the dictionary cache. */ void lock(SRW_LOCK_ARGS(const char *file, unsigned line)) { - if (latch.wr_lock_try()) - { - ut_ad(!latch_readers); - ut_ad(!latch_ex); - ut_d(latch_ex= pthread_self()); - } - else +#ifdef UNIV_DEBUG + if (!latch.x_lock_try()) +#else + if (!latch.wr_lock_try()) +#endif lock_wait(SRW_LOCK_ARGS(file, line)); } @@ -1532,24 +1527,29 @@ public: /** Unlock the data dictionary cache. */ void unlock() { - ut_ad(latch_ex == pthread_self()); - ut_ad(!latch_readers); - ut_d(latch_ex= 0); +# ifdef UNIV_DEBUG + latch.x_unlock(); +# else latch.wr_unlock(); +# endif } /** Acquire a shared lock on the dictionary cache. */ void freeze() { +# ifdef UNIV_DEBUG + latch.s_lock(); +# else latch.rd_lock(); - ut_ad(!latch_ex); - ut_d(latch_readers++); +# endif } /** Release a shared lock on the dictionary cache. */ void unfreeze() { - ut_ad(!latch_ex); - ut_ad(latch_readers--); +# ifdef UNIV_DEBUG + latch.s_unlock(); +# else latch.rd_unlock(); +# endif } #endif diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 59ee7f551b4..65537859924 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -438,6 +438,13 @@ dberr_t lock_table_for_trx(dict_table_t *table, trx_t *trx, lock_mode mode, bool no_wait= false) MY_ATTRIBUTE((nonnull, warn_unused_result)); +/** Lock the child tables of a table. +@param table parent table +@param trx transaction +@return error code */ +dberr_t lock_table_children(dict_table_t *table, trx_t *trx) + MY_ATTRIBUTE((nonnull, warn_unused_result)); + /** Exclusively lock the data dictionary tables. @param trx dictionary transaction @return error code diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index df51ceb16d8..c9072998e66 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -3940,6 +3940,8 @@ static void lock_table_dequeue(lock_t *in_lock, bool owns_wait_mutex) dberr_t lock_table_for_trx(dict_table_t *table, trx_t *trx, lock_mode mode, bool no_wait) { + ut_ad(!dict_sys.frozen()); + mem_heap_t *heap= mem_heap_create(512); sel_node_t *node= sel_node_create(heap); que_thr_t *thr= pars_complete_graph_for_exec(node, trx, heap, nullptr); @@ -3976,6 +3978,36 @@ run_again: return err; } +/** Lock the child tables of a table. +@param table parent table +@param trx transaction +@return error code */ +dberr_t lock_table_children(dict_table_t *table, trx_t *trx) +{ + dict_sys.freeze(SRW_LOCK_CALL); + std::vector children; + + for (auto f : table->referenced_set) + if (dict_table_t *child= f->foreign_table) + { + child->acquire(); + children.emplace_back(child); + } + dict_sys.unfreeze(); + + dberr_t err= DB_SUCCESS; + + for (auto child : children) + if ((err= lock_table_for_trx(child, trx, LOCK_X)) != DB_SUCCESS) + break; + + for (auto child : children) + child->release(); + + return err; +} + + /** Exclusively lock the data dictionary tables. @param trx dictionary transaction @return error code