MDEV-36638 Some optimizer hint warnings are returned as errors

With strict SQL_MODE warnings generated during DDL statements
are threated as errors. This is done to prevent potential data
corruption. However, optimizer hints cannot affect the integrity
of data, so warnings during their parsing or application should not
be escalated to the level of errors.

This commit introduces `push_warning_safe()` method that guarantees
that a warning is not treated as an error, and generation of warnings
during hints processing now uses this method instead of traditional
`push_warning_printf()`
This commit is contained in:
Oleg Smirnov 2025-04-22 21:47:12 +07:00
parent 6cd27dbc43
commit 6e2a0501b6
5 changed files with 142 additions and 22 deletions

View File

@ -1324,3 +1324,44 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1003 select /*+ JOIN_PREFIX(@`select#1` `t2`@`qb2`,`t4`@`qb1`,`ta3`,`ta4`) */ count(0) AS `COUNT(*)` from `test`.`t1` semi join (`test`.`t4`) semi join (`test`.`t2`) join `test`.`t2` `ta3` join `test`.`t2` `ta4` where `test`.`ta4`.`f1` = `test`.`t4`.`f1` and `test`.`ta3`.`f2` = `test`.`t2`.`f2`
DROP TABLE t1, t2, t4;
MDEV-36638 Some optimizer hint warnings are returned as errors
SET @save_sql_mode = @@sql_mode;
SET SQL_MODE = 'STRICT_TRANS_TABLES';
CREATE TABLE t1 (id int(11) NOT NULL auto_increment, f1 INT NOT NULL, PRIMARY KEY (id));
INSERT INTO t1 (id, f1) VALUES (1,9),(2,0), (3,7);
CREATE TABLE t2 (id int(11), f2 INT NOT NULL);
INSERT INTO t2 (id, f2) VALUES
(4,5),(3,3),(1,0),(1,3),(6,1),(2,0),(4,1),(2,7),(2,1),(1,0),(3,0),(5,8),(5,4),
(3,9),(2,0),(7,2),(2,0),(1,8),(6,5),(4,1);
CREATE TABLE tn (fn_1 INT, fn_2 INT);
EXPLAIN EXTENDED
INSERT INTO tn (fn_1, fn_2)
SELECT /*+ JOIN_ORDER(t2,t1) JOIN_FIXED_ORDER() */ f1,f2
FROM t2 JOIN t1 ON t1.id=t2.id ORDER BY f1, f2;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using temporary; Using filesort
1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 3 33.33 Using where; Using join buffer (flat, BNL join)
Warnings:
Warning 4217 Hint JOIN_FIXED_ORDER() is ignored as conflicting/duplicated
Note 1003 insert into `test`.`tn`(fn_1,fn_2) select /*+ JOIN_ORDER(@`select#2` `t2`,`t1`) */ `test`.`t1`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2` from `test`.`t2` join `test`.`t1` where `test`.`t1`.`id` = `test`.`t2`.`id` order by `test`.`t1`.`f1`,`test`.`t2`.`f2`
EXPLAIN EXTENDED
INSERT INTO tn (fn_1, fn_2)
SELECT /*+ JOIN_ORDER(t1,t2) */ f1,f2 FROM t2 LEFT JOIN t1 ON t1.id=t2.id
ORDER BY f1, f2;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 20 100.00 Using temporary; Using filesort
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.id 1 100.00 Using where
Warnings:
Warning 4217 Hint JOIN_ORDER(`t1`,`t2`) is ignored as conflicting/duplicated
Note 1003 insert into `test`.`tn`(fn_1,fn_2) select `test`.`t1`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2` from `test`.`t2` left join `test`.`t1` on(`test`.`t1`.`id` = `test`.`t2`.`id` and `test`.`t2`.`id` is not null) where 1 order by `test`.`t1`.`f1`,`test`.`t2`.`f2`
DROP TABLE tn;
DROP TABLE t1, t2;
CREATE TABLE t1 (a int, b varchar(50), c varchar(50));
INSERT t1 (a,b) VALUES (1,'1'), (2,'2'), (3,'3');
CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW
SET new.c = (SELECT /*+ NO_RANGE_OPTIMIZATION(t1) */ 1);
UPDATE t1 SET t1.b = 10;
DROP TABLE t1;
SET SQL_MODE = @save_sql_mode;

View File

@ -789,3 +789,42 @@ eval $query;
eval explain extended $query;
DROP TABLE t1, t2, t4;
--echo
--echo MDEV-36638 Some optimizer hint warnings are returned as errors
--echo
SET @save_sql_mode = @@sql_mode;
SET SQL_MODE = 'STRICT_TRANS_TABLES';
CREATE TABLE t1 (id int(11) NOT NULL auto_increment, f1 INT NOT NULL, PRIMARY KEY (id));
INSERT INTO t1 (id, f1) VALUES (1,9),(2,0), (3,7);
CREATE TABLE t2 (id int(11), f2 INT NOT NULL);
INSERT INTO t2 (id, f2) VALUES
(4,5),(3,3),(1,0),(1,3),(6,1),(2,0),(4,1),(2,7),(2,1),(1,0),(3,0),(5,8),(5,4),
(3,9),(2,0),(7,2),(2,0),(1,8),(6,5),(4,1);
CREATE TABLE tn (fn_1 INT, fn_2 INT);
EXPLAIN EXTENDED
INSERT INTO tn (fn_1, fn_2)
SELECT /*+ JOIN_ORDER(t2,t1) JOIN_FIXED_ORDER() */ f1,f2
FROM t2 JOIN t1 ON t1.id=t2.id ORDER BY f1, f2;
EXPLAIN EXTENDED
INSERT INTO tn (fn_1, fn_2)
SELECT /*+ JOIN_ORDER(t1,t2) */ f1,f2 FROM t2 LEFT JOIN t1 ON t1.id=t2.id
ORDER BY f1, f2;
DROP TABLE tn;
DROP TABLE t1, t2;
CREATE TABLE t1 (a int, b varchar(50), c varchar(50));
INSERT t1 (a,b) VALUES (1,'1'), (2,'2'), (3,'3');
CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW
SET new.c = (SELECT /*+ NO_RANGE_OPTIMIZATION(t1) */ 1);
UPDATE t1 SET t1.b = 10;
DROP TABLE t1;
SET SQL_MODE = @save_sql_mode;

View File

@ -55,6 +55,28 @@ struct st_opt_hint_info opt_hint_info[]=
const LEX_CSTRING sys_qb_prefix= {"select#", 7};
/*
This is a version of push_warning_printf() guaranteeing no escalation of
the warning to the level of error
*/
void push_warning_safe(THD *thd, Sql_condition::enum_warning_level level,
uint code, const char *format, ...)
{
va_list args;
DBUG_ENTER("push_warning_safe");
DBUG_PRINT("enter",("warning: %u", code));
va_start(args,format);
bool save_abort_on_warning= thd->abort_on_warning;
thd->abort_on_warning= false; // Don't escalate to the level of error
push_warning_printf_va_list(thd, level,code, format, args);
va_end(args);
thd->abort_on_warning= save_abort_on_warning;
DBUG_VOID_RETURN;
}
void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
bool hint_state,
const Lex_ident_sys *qb_name_arg,
@ -74,9 +96,9 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
{
String qb_name_str;
append_identifier(thd, &qb_name_str, qb_name_arg->str, qb_name_arg->length);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
err_code, ER_THD(thd, err_code),
qb_name_str.c_ptr_safe(), str.c_ptr_safe());
push_warning_safe(thd, Sql_condition::WARN_LEVEL_WARN,
err_code, ER_THD(thd, err_code),
qb_name_str.c_ptr_safe(), str.c_ptr_safe());
return;
}
@ -86,9 +108,9 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
DBUG_ASSERT(hint);
String args;
hint->append_args(thd, &args);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
err_code, ER_THD(thd, err_code),
args.c_ptr_safe(), str.c_ptr_safe());
push_warning_safe(thd, Sql_condition::WARN_LEVEL_WARN,
err_code, ER_THD(thd, err_code),
args.c_ptr_safe(), str.c_ptr_safe());
return;
}
@ -131,9 +153,8 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
}
str.append(')');
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
err_code, ER_THD(thd, err_code), str.c_ptr_safe());
push_warning_safe(thd, Sql_condition::WARN_LEVEL_WARN,
err_code, ER_THD(thd, err_code), str.c_ptr_safe());
}
@ -335,11 +356,11 @@ void Opt_hints::print_unfixed_warnings(THD *thd)
{
hint_type_str.length(0);
append_hint_type(&hint_type_str, static_cast<opt_hints_enum>(i));
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
get_unfixed_warning_code(),
ER_THD(thd, get_unfixed_warning_code()),
hint_name_str.c_ptr_safe(),
hint_type_str.c_ptr_safe());
push_warning_safe(thd, Sql_condition::WARN_LEVEL_WARN,
get_unfixed_warning_code(),
ER_THD(thd, get_unfixed_warning_code()),
hint_name_str.c_ptr_safe(),
hint_type_str.c_ptr_safe());
}
}
}
@ -923,9 +944,10 @@ void Opt_hints_qb::print_join_order_warn(THD *thd, opt_hints_enum type,
hint_type_str.append(opt_hint_info[type].hint_type);
append_table_name(thd, &tbl_name_str, tbl_name.table_name, tbl_name.qb_name);
uint err_code= ER_UNRESOLVED_TABLE_HINT_NAME;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
err_code, ER_THD(thd, err_code),
tbl_name_str.c_ptr_safe(), hint_type_str.c_ptr_safe());
push_warning_safe(thd, Sql_condition::WARN_LEVEL_WARN,
err_code, ER_THD(thd, err_code),
tbl_name_str.c_ptr_safe(), hint_type_str.c_ptr_safe());
}

View File

@ -783,22 +783,36 @@ void push_warning(THD *thd, Sql_condition::enum_warning_level level,
*/
void push_warning_printf(THD *thd, Sql_condition::enum_warning_level level,
uint code, const char *format, ...)
uint code, const char *format, ...)
{
va_list args;
char warning[MYSQL_ERRMSG_SIZE];
DBUG_ENTER("push_warning_printf");
DBUG_PRINT("enter",("warning: %u", code));
va_start(args,format);
push_warning_printf_va_list(thd, level,code, format, args);
va_end(args);
DBUG_VOID_RETURN;
}
/*
This is an overload of push_warning_printf() accepting va_list as a list
of format arguments.
*/
void push_warning_printf_va_list(THD *thd,
Sql_condition::enum_warning_level level,
uint code, const char *format, va_list args)
{
char warning[MYSQL_ERRMSG_SIZE];
DBUG_ASSERT(code != 0);
DBUG_ASSERT(format != NULL);
va_start(args,format);
my_vsnprintf_ex(&my_charset_utf8mb3_general_ci, warning,
sizeof(warning), format, args);
va_end(args);
push_warning(thd, level, code, warning);
DBUG_VOID_RETURN;
}

View File

@ -1335,6 +1335,10 @@ void push_warning_printf(THD *thd, Sql_condition::enum_warning_level level,
uint code, const char *format, ...)
ATTRIBUTE_FORMAT(printf, 4, 5);
void push_warning_printf_va_list(THD *thd,
Sql_condition::enum_warning_level level,
uint code, const char *format, va_list args);
bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
size_t convert_error_message(char *to, size_t to_length,