MDEV-36675 Optimizer hints parser catches irrelevant thd->is_error() set by multi-RENAME TABLE

Optimizer hints parser analyzes `thd->is_error()` flag to detect a fatal
error occured during hints processing. However, this criteria is not
reliable and considered a bad practice.
This commit replaces the criteria with the parser's own `is_fatal_error()`
flag which is related strictly to hints parsing and not something else
This commit is contained in:
Oleg Smirnov 2025-04-23 19:26:58 +07:00
parent 349f5bf2da
commit a0e89070cc
5 changed files with 51 additions and 15 deletions

View File

@ -1985,5 +1985,21 @@ DROP TABLE t1;
set optimizer_switch = DEFAULT;
set join_cache_level = DEFAULT;
#
# End of 11.7 tests
# MDEV-36675 Optimizer hints parser catches irrelevant `thd->is_error()`
# set by multi-RENAME TABLE
#
CREATE TABLE t1 (a INT);
CREATE TRIGGER t1 AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t1 VALUES (0);
RENAME TABLE t1 TO t2, t3 TO t4;
ERROR 42S02: Table 'test.t3' doesn't exist
SHOW CREATE TRIGGER t1;
Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created
t1 CREATE DEFINER=`root`@`localhost` TRIGGER t1 AFTER INSERT ON `t1` FOR EACH ROW INSERT INTO t1 VALUES (0) utf8mb3 utf8mb3_uca1400_ai_ci utf8mb4_uca1400_ai_ci #
RENAME TABLE t1 TO t2;
SHOW CREATE TRIGGER t1;
Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation Created
t1 CREATE DEFINER=`root`@`localhost` TRIGGER t1 AFTER INSERT ON `t2` FOR EACH ROW INSERT INTO t1 VALUES (0) utf8mb3 utf8mb3_uca1400_ai_ci utf8mb4_uca1400_ai_ci #
DROP TABLE t2;
#
# End of 12.0 tests
#

View File

@ -1021,6 +1021,24 @@ SELECT
DROP TABLE t1;
set optimizer_switch = DEFAULT;
set join_cache_level = DEFAULT;
--echo #
--echo # End of 11.7 tests
--echo # MDEV-36675 Optimizer hints parser catches irrelevant `thd->is_error()`
--echo # set by multi-RENAME TABLE
--echo #
CREATE TABLE t1 (a INT);
CREATE TRIGGER t1 AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t1 VALUES (0);
--error ER_NO_SUCH_TABLE
RENAME TABLE t1 TO t2, t3 TO t4;
--replace_column 7 #
SHOW CREATE TRIGGER t1;
RENAME TABLE t1 TO t2;
--replace_column 7 #
SHOW CREATE TRIGGER t1;
DROP TABLE t2;
--echo #
--echo # End of 12.0 tests
--echo #

View File

@ -12932,22 +12932,22 @@ bool SELECT_LEX_UNIT::is_derived_eliminated() const
/*
Parse optimizer hints and return as Hint_list allocated on thd->mem_root.
The caller should check both return value and thd->is_error()
The caller should check both parts of the return value
to know what happened, as follows:
Return value thd->is_error() Meaning
Retval.first Retval.second Meaning
------------ --------------- -------
rc != nullptr false the hints were parsed without errors
rc != nullptr true not possible
rc == nullptr false no hints, empty hints, hint parse error
rc == nullptr true fatal error, such as EOM
false != nullptr the hints were parsed without errors
true != nullptr impossible combination
false == nullptr no hints, empty hints, hint parse error
true == nullptr fatal error, such as EOM
*/
Optimizer_hint_parser_output *
std::pair<bool, Optimizer_hint_parser_output *>
LEX::parse_optimizer_hints(const Lex_comment_st &hints_str)
{
DBUG_ASSERT(!hints_str.str || hints_str.length >= 5);
if (!hints_str.str)
return nullptr; // There were no a hint comment
return {false, nullptr}; // There were no a hint comment
// Instantiate the query hint parser.
// Remove the leading '/*+' and trailing '*/'
@ -12965,17 +12965,17 @@ LEX::parse_optimizer_hints(const Lex_comment_st &hints_str)
The SQL error should be in DA already.
*/
DBUG_ASSERT(thd->is_error());
return nullptr; // Continue, the caller will test thd->is_error()
return {true, nullptr}; // Set the flag of fatal error
}
if (!hints) // Hint parsing failed with a syntax error
{
p.push_warning_syntax_error(thd, hints_str.lineno);
return nullptr; // Continue and ignore hints.
return {false, nullptr}; // Continue and ignore hints.
}
// Hints were not empty and were parsed without errors
return new (thd->mem_root) Optimizer_hint_parser_output(std::move(hints));
return {false, new (thd->mem_root) Optimizer_hint_parser_output(std::move(hints))};
}

View File

@ -5001,7 +5001,7 @@ public:
return nullptr;
}
Optimizer_hint_parser_output *
std::pair<bool, Optimizer_hint_parser_output *>
parse_optimizer_hints(const Lex_comment_st &hint);
};

View File

@ -8971,7 +8971,9 @@ opt_optimizer_hint:
opt_hint_comment
{
YYLIP->hint_comment= false;
if (!($$= Lex->parse_optimizer_hints($2)) && thd->is_error())
std::pair<bool, Optimizer_hint_parser_output *> parse_res=
Lex->parse_optimizer_hints($2);
if (!($$= parse_res.second) && parse_res.first)
MYSQL_YYABORT;
}
;