mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-34860 Implement MAX_EXECUTION_TIME hint
It places a limit N (a timeout value in milliseconds) on how long a statement is permitted to execute before the server terminates it. Syntax: SELECT /*+ MAX_EXECUTION_TIME(milliseconds) */ ... Only top-level SELECT statements support the hint.
This commit is contained in:
113
mysql-test/main/opt_hint_timeout.result
Normal file
113
mysql-test/main/opt_hint_timeout.result
Normal file
@ -0,0 +1,113 @@
|
||||
#
|
||||
# MAX_EXECUTION_TIME hint testing
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b VARCHAR(300));
|
||||
INSERT INTO t1 VALUES (1, 'string');
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
# Correct hint usage
|
||||
SELECT /*+ MAX_EXECUTION_TIME(10) */* FROM t1 a, t1 b;
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
EXPLAIN EXTENDED SELECT /*+ MAX_EXECUTION_TIME(000149) */* FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 512 100.00
|
||||
Warnings:
|
||||
Note 1003 select /*+ MAX_EXECUTION_TIME(000149) */ `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`
|
||||
SELECT /*+ MAX_EXECUTION_TIME(20) */ *, SLEEP(1) FROM t1 UNION SELECT 1, 2, 3;
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
(SELECT /*+ MAX_EXECUTION_TIME(30) */ *, SLEEP(1) FROM t1) UNION (SELECT 1, 2, 3);
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
((SELECT /*+ MAX_EXECUTION_TIME(50) */ *, SLEEP(1) FROM t1));
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
# Check that prepared statements process the hint correctly
|
||||
PREPARE s FROM 'SELECT /*+ MAX_EXECUTION_TIME(20) */ seq, SLEEP(1) FROM seq_1_to_10';
|
||||
EXECUTE s;
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
EXECUTE s;
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
# Hint duplication
|
||||
SELECT /*+ MAX_EXECUTION_TIME(10) MAX_EXECUTION_TIME(100) */ count(*) FROM t1;
|
||||
count(*)
|
||||
512
|
||||
Warnings:
|
||||
Warning 4202 Hint MAX_EXECUTION_TIME(100) is ignored as conflicting/duplicated
|
||||
# Wrong values
|
||||
SELECT /*+ MAX_EXECUTION_TIME(0) */ count(*) FROM t1;
|
||||
count(*)
|
||||
512
|
||||
Warnings:
|
||||
Warning 1912 Incorrect value '0' for option 'MAX_EXECUTION_TIME'
|
||||
SELECT /*+ MAX_EXECUTION_TIME(-1) */ count(*) FROM t1;
|
||||
count(*)
|
||||
512
|
||||
Warnings:
|
||||
Warning 1064 Optimizer hint syntax error near '-1) */ count(*) FROM t1' at line 1
|
||||
SELECT /*+ MAX_EXECUTION_TIME(4294967296) */ count(*) FROM t1;
|
||||
count(*)
|
||||
512
|
||||
Warnings:
|
||||
Warning 1912 Incorrect value '4294967296' for option 'MAX_EXECUTION_TIME'
|
||||
# Conflicting max_statement_time and hint (must issue a warning)
|
||||
SET STATEMENT max_statement_time=1 FOR
|
||||
SELECT /*+ MAX_EXECUTION_TIME(500) */ count(*) FROM t1 a;
|
||||
count(*)
|
||||
512
|
||||
Warnings:
|
||||
Warning 4202 Hint MAX_EXECUTION_TIME(500) is ignored as conflicting/duplicated
|
||||
|
||||
# only SELECT statements supports the MAX_EXECUTION_TIME hint (warning):
|
||||
|
||||
CREATE TABLE t2 (i INT);
|
||||
INSERT /*+ MAX_EXECUTION_TIME(10) */ INTO t2 SELECT 1;
|
||||
Warnings:
|
||||
Warning 4172 'MAX_EXECUTION_TIME(10)' is not allowed in this context
|
||||
REPLACE /*+ MAX_EXECUTION_TIME(15) */ INTO t2 SELECT 1;
|
||||
Warnings:
|
||||
Warning 4172 'MAX_EXECUTION_TIME(15)' is not allowed in this context
|
||||
UPDATE /*+ MAX_EXECUTION_TIME(23) */ t2 SET i = 1;
|
||||
Warnings:
|
||||
Warning 4172 'MAX_EXECUTION_TIME(23)' is not allowed in this context
|
||||
DELETE /*+ MAX_EXECUTION_TIME(5000) */ FROM t2 WHERE i = 1;
|
||||
Warnings:
|
||||
Warning 4172 'MAX_EXECUTION_TIME(5000)' is not allowed in this context
|
||||
# Not supported inside stored procedures/functions
|
||||
CREATE PROCEDURE p1() BEGIN SELECT /*+ MAX_EXECUTION_TIME(10) */ count(*) FROM t1 a, t1 b
|
||||
INTO @a; END|
|
||||
CALL p1();
|
||||
Warnings:
|
||||
Warning 4172 'MAX_EXECUTION_TIME(10)' is not allowed in this context
|
||||
DROP PROCEDURE p1;
|
||||
# Hint in a subquery is not allowed (warning):
|
||||
SELECT 1 FROM (SELECT /*+ MAX_EXECUTION_TIME(10) */ 1) a;
|
||||
1
|
||||
1
|
||||
Warnings:
|
||||
Warning 4172 'MAX_EXECUTION_TIME(10)' is not allowed in this context
|
||||
# Hint is allowed only for the first select of UNION (warning):
|
||||
SELECT /*+ MAX_EXECUTION_TIME(20) */ count(*) FROM t1
|
||||
UNION
|
||||
SELECT /*+ MAX_EXECUTION_TIME(30) */ count(*) FROM t1;
|
||||
count(*)
|
||||
512
|
||||
Warnings:
|
||||
Warning 4202 Hint MAX_EXECUTION_TIME(30) is ignored as conflicting/duplicated
|
||||
SELECT count(*) FROM t1
|
||||
UNION
|
||||
SELECT /*+ MAX_EXECUTION_TIME(30) */ count(*) FROM t1;
|
||||
count(*)
|
||||
512
|
||||
Warnings:
|
||||
Warning 4172 'MAX_EXECUTION_TIME(30)' is not allowed in this context
|
||||
# Check that hint actually works:
|
||||
SELECT /*+ MAX_EXECUTION_TIME(20) */ count(*), SLEEP(1) FROM t1
|
||||
UNION
|
||||
SELECT count(*), SLEEP(1) FROM t1;
|
||||
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
|
||||
DROP TABLE t1, t2;
|
95
mysql-test/main/opt_hint_timeout.test
Normal file
95
mysql-test/main/opt_hint_timeout.test
Normal file
@ -0,0 +1,95 @@
|
||||
--source include/have_sequence.inc
|
||||
--echo #
|
||||
--echo # MAX_EXECUTION_TIME hint testing
|
||||
--echo #
|
||||
--enable_prepare_warnings
|
||||
|
||||
CREATE TABLE t1 (a INT, b VARCHAR(300));
|
||||
INSERT INTO t1 VALUES (1, 'string');
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
|
||||
-- disable_query_log
|
||||
-- disable_result_log
|
||||
analyze table t1;
|
||||
-- enable_result_log
|
||||
-- enable_query_log
|
||||
|
||||
--echo # Correct hint usage
|
||||
--error ER_STATEMENT_TIMEOUT
|
||||
SELECT /*+ MAX_EXECUTION_TIME(10) */* FROM t1 a, t1 b;
|
||||
|
||||
EXPLAIN EXTENDED SELECT /*+ MAX_EXECUTION_TIME(000149) */* FROM t1;
|
||||
|
||||
--error ER_STATEMENT_TIMEOUT
|
||||
SELECT /*+ MAX_EXECUTION_TIME(20) */ *, SLEEP(1) FROM t1 UNION SELECT 1, 2, 3;
|
||||
--error ER_STATEMENT_TIMEOUT
|
||||
(SELECT /*+ MAX_EXECUTION_TIME(30) */ *, SLEEP(1) FROM t1) UNION (SELECT 1, 2, 3);
|
||||
--error ER_STATEMENT_TIMEOUT
|
||||
((SELECT /*+ MAX_EXECUTION_TIME(50) */ *, SLEEP(1) FROM t1));
|
||||
|
||||
--echo # Check that prepared statements process the hint correctly
|
||||
PREPARE s FROM 'SELECT /*+ MAX_EXECUTION_TIME(20) */ seq, SLEEP(1) FROM seq_1_to_10';
|
||||
--error ER_STATEMENT_TIMEOUT
|
||||
EXECUTE s;
|
||||
--error ER_STATEMENT_TIMEOUT
|
||||
EXECUTE s;
|
||||
|
||||
--echo # Hint duplication
|
||||
|
||||
SELECT /*+ MAX_EXECUTION_TIME(10) MAX_EXECUTION_TIME(100) */ count(*) FROM t1;
|
||||
|
||||
--echo # Wrong values
|
||||
SELECT /*+ MAX_EXECUTION_TIME(0) */ count(*) FROM t1;
|
||||
SELECT /*+ MAX_EXECUTION_TIME(-1) */ count(*) FROM t1;
|
||||
SELECT /*+ MAX_EXECUTION_TIME(4294967296) */ count(*) FROM t1;
|
||||
|
||||
--echo # Conflicting max_statement_time and hint (must issue a warning)
|
||||
SET STATEMENT max_statement_time=1 FOR
|
||||
SELECT /*+ MAX_EXECUTION_TIME(500) */ count(*) FROM t1 a;
|
||||
|
||||
--echo
|
||||
--echo # only SELECT statements supports the MAX_EXECUTION_TIME hint (warning):
|
||||
--echo
|
||||
CREATE TABLE t2 (i INT);
|
||||
INSERT /*+ MAX_EXECUTION_TIME(10) */ INTO t2 SELECT 1;
|
||||
REPLACE /*+ MAX_EXECUTION_TIME(15) */ INTO t2 SELECT 1;
|
||||
UPDATE /*+ MAX_EXECUTION_TIME(23) */ t2 SET i = 1;
|
||||
DELETE /*+ MAX_EXECUTION_TIME(5000) */ FROM t2 WHERE i = 1;
|
||||
|
||||
--echo # Not supported inside stored procedures/functions
|
||||
DELIMITER |;
|
||||
CREATE PROCEDURE p1() BEGIN SELECT /*+ MAX_EXECUTION_TIME(10) */ count(*) FROM t1 a, t1 b
|
||||
INTO @a; END|
|
||||
DELIMITER ;|
|
||||
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo # Hint in a subquery is not allowed (warning):
|
||||
SELECT 1 FROM (SELECT /*+ MAX_EXECUTION_TIME(10) */ 1) a;
|
||||
|
||||
--echo # Hint is allowed only for the first select of UNION (warning):
|
||||
SELECT /*+ MAX_EXECUTION_TIME(20) */ count(*) FROM t1
|
||||
UNION
|
||||
SELECT /*+ MAX_EXECUTION_TIME(30) */ count(*) FROM t1;
|
||||
|
||||
SELECT count(*) FROM t1
|
||||
UNION
|
||||
SELECT /*+ MAX_EXECUTION_TIME(30) */ count(*) FROM t1;
|
||||
|
||||
--echo # Check that hint actually works:
|
||||
--error ER_STATEMENT_TIMEOUT
|
||||
SELECT /*+ MAX_EXECUTION_TIME(20) */ count(*), SLEEP(1) FROM t1
|
||||
UNION
|
||||
SELECT count(*), SLEEP(1) FROM t1;
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
@ -1799,6 +1799,14 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
Warnings:
|
||||
Note 1003 select /*+ QB_NAME(`a
|
||||
b`) */ 1 AS `1`
|
||||
# Identifiers starting with digits must be supported:
|
||||
CREATE OR REPLACE TABLE 0a (8a INT, KEY 6a(8a));
|
||||
EXPLAIN EXTENDED SELECT /*+ NO_MRR(0a 6a) BKA(0a)*/ 8a FROM 0a;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE 0a system NULL NULL NULL NULL 0 0.00 Const row not found
|
||||
Warnings:
|
||||
Note 1003 select /*+ BKA(`0a`@`select#1`) NO_MRR(`0a`@`select#1` `6a`) */ NULL AS `8a` from `test`.`0a`
|
||||
DROP TABLE 0a;
|
||||
# hint syntax error: empty quoted identifier
|
||||
EXPLAIN EXTENDED SELECT /*+ QB_NAME(``) */ 1;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
@ -1876,7 +1884,7 @@ SELECT /*+ NO_ICP(10) */ 1;
|
||||
1
|
||||
1
|
||||
Warnings:
|
||||
Warning 4204 Unresolved table name `10`@`select#1` for NO_ICP hint
|
||||
Warning 1064 Optimizer hint syntax error near '10) */ 1' at line 1
|
||||
SELECT /*+ NO_ICP( */ 1;
|
||||
1
|
||||
1
|
||||
|
@ -914,6 +914,11 @@ EXPLAIN EXTENDED SELECT /*+ QB_NAME(`*b`) */ 1;
|
||||
EXPLAIN EXTENDED SELECT /*+ QB_NAME(`a
|
||||
b`) */ 1;
|
||||
|
||||
--echo # Identifiers starting with digits must be supported:
|
||||
CREATE OR REPLACE TABLE 0a (8a INT, KEY 6a(8a));
|
||||
EXPLAIN EXTENDED SELECT /*+ NO_MRR(0a 6a) BKA(0a)*/ 8a FROM 0a;
|
||||
DROP TABLE 0a;
|
||||
|
||||
--echo # hint syntax error: empty quoted identifier
|
||||
EXPLAIN EXTENDED SELECT /*+ QB_NAME(``) */ 1;
|
||||
|
||||
|
@ -4857,7 +4857,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
||||
set/reset the slave thread's timer; a Rows_log_event update needs to set
|
||||
the timer itself
|
||||
*/
|
||||
thd->set_query_timer();
|
||||
thd->set_query_timer_if_needed();
|
||||
|
||||
/*
|
||||
If there are no tables open, this must be the first row event seen
|
||||
|
188
sql/opt_hints.cc
188
sql/opt_hints.cc
@ -19,7 +19,6 @@
|
||||
#include "sql_lex.h"
|
||||
#include "sql_select.h"
|
||||
#include "opt_hints.h"
|
||||
#include "opt_hints_parser.h"
|
||||
|
||||
/**
|
||||
Information about hints. Sould be
|
||||
@ -34,12 +33,13 @@
|
||||
|
||||
struct st_opt_hint_info opt_hint_info[]=
|
||||
{
|
||||
{{STRING_WITH_LEN("BKA")}, true, true},
|
||||
{{STRING_WITH_LEN("BNL")}, true, true},
|
||||
{{STRING_WITH_LEN("ICP")}, true, true},
|
||||
{{STRING_WITH_LEN("MRR")}, true, true},
|
||||
{{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, true},
|
||||
{{STRING_WITH_LEN("BKA")}, true, false},
|
||||
{{STRING_WITH_LEN("BNL")}, true, false},
|
||||
{{STRING_WITH_LEN("ICP")}, true, false},
|
||||
{{STRING_WITH_LEN("MRR")}, true, false},
|
||||
{{STRING_WITH_LEN("NO_RANGE_OPTIMIZATION")}, true, false},
|
||||
{{STRING_WITH_LEN("QB_NAME")}, false, false},
|
||||
{{STRING_WITH_LEN("MAX_EXECUTION_TIME")}, false, true},
|
||||
{null_clex_str, 0, 0}
|
||||
};
|
||||
|
||||
@ -52,12 +52,14 @@ const LEX_CSTRING sys_qb_prefix= {"select#", 7};
|
||||
|
||||
static const Lex_ident_sys null_ident_sys;
|
||||
|
||||
template<typename Hint_type>
|
||||
static
|
||||
void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
|
||||
bool hint_state,
|
||||
const Lex_ident_sys *qb_name_arg,
|
||||
const Lex_ident_sys *table_name_arg,
|
||||
const Lex_ident_sys *key_name_arg)
|
||||
const Lex_ident_sys *key_name_arg,
|
||||
Hint_type *hint)
|
||||
{
|
||||
String str;
|
||||
|
||||
@ -77,6 +79,18 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
|
||||
return;
|
||||
}
|
||||
|
||||
/* ER_BAD_OPTION_VALUE with two arguments. hint argument is required here */
|
||||
if (err_code == ER_BAD_OPTION_VALUE)
|
||||
{
|
||||
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());
|
||||
return;
|
||||
}
|
||||
|
||||
/* ER_WARN_CONFLICTING_HINT with one argument */
|
||||
str.append('(');
|
||||
|
||||
@ -105,6 +119,15 @@ void print_warn(THD *thd, uint err_code, opt_hints_enum hint_type,
|
||||
append_identifier(thd, &str, key_name_arg->str, key_name_arg->length);
|
||||
}
|
||||
|
||||
/* Append additional hint arguments if they exist */
|
||||
if (hint)
|
||||
{
|
||||
if (qb_name_arg || table_name_arg || key_name_arg)
|
||||
str.append(' ');
|
||||
|
||||
hint->append_args(thd, &str);
|
||||
}
|
||||
|
||||
str.append(')');
|
||||
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
@ -131,8 +154,6 @@ static Opt_hints_global *get_global_hints(Parse_context *pc)
|
||||
lex->opt_hints_global= new (pc->thd->mem_root)
|
||||
Opt_hints_global(pc->thd->mem_root);
|
||||
}
|
||||
if (lex->opt_hints_global)
|
||||
lex->opt_hints_global->set_resolved();
|
||||
return lex->opt_hints_global;
|
||||
}
|
||||
|
||||
@ -184,7 +205,7 @@ static Opt_hints_qb *find_qb_hints(Parse_context *pc,
|
||||
if (qb == NULL)
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_UNKNOWN_QB_NAME, hint_type, hint_state,
|
||||
&qb_name, NULL, NULL);
|
||||
&qb_name, NULL, NULL, (Parser::Hint*) NULL);
|
||||
}
|
||||
return qb;
|
||||
}
|
||||
@ -252,7 +273,21 @@ void Opt_hints::print(THD *thd, String *str)
|
||||
{
|
||||
append_hint_type(str, static_cast<opt_hints_enum>(i));
|
||||
str->append(STRING_WITH_LEN("("));
|
||||
uint32 len_before_name= str->length();
|
||||
append_name(thd, str);
|
||||
uint32 len_after_name= str->length();
|
||||
if (len_after_name > len_before_name)
|
||||
str->append(' ');
|
||||
if (opt_hint_info[i].has_arguments)
|
||||
{
|
||||
std::function<void(THD*, String*)> args_printer= get_args_printer();
|
||||
args_printer(thd, str);
|
||||
}
|
||||
if (str->length() == len_after_name + 1)
|
||||
{
|
||||
// No additional arguments were printed, trim the space added before
|
||||
str->length(len_after_name);
|
||||
}
|
||||
str->append(STRING_WITH_LEN(") "));
|
||||
}
|
||||
}
|
||||
@ -396,7 +431,7 @@ static bool get_hint_state(Opt_hints *hint,
|
||||
{
|
||||
DBUG_ASSERT(parent_hint);
|
||||
|
||||
if (opt_hint_info[type_arg].switch_hint)
|
||||
if (!opt_hint_info[type_arg].has_arguments)
|
||||
{
|
||||
if (hint && hint->is_specified(type_arg))
|
||||
{
|
||||
@ -412,7 +447,7 @@ static bool get_hint_state(Opt_hints *hint,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Complex hint, not implemented atm */
|
||||
/* Complex hint with arguments, not implemented atm */
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
return false;
|
||||
@ -524,8 +559,10 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
||||
{
|
||||
// e.g. BKA(@qb1)
|
||||
if (qb->set_switch(hint_state, hint_type, false))
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||
&qb_name_sys, NULL, NULL);
|
||||
&qb_name_sys, NULL, NULL, (Parser::Hint*) NULL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@ -539,8 +576,10 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
||||
if (!tab)
|
||||
return true;
|
||||
if (tab->set_switch(hint_state, hint_type, true))
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||
&qb_name_sys, &table_name_sys, NULL);
|
||||
&qb_name_sys, &table_name_sys, NULL, (Parser::Hint*) NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -556,8 +595,10 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
||||
{
|
||||
// e.g. BKA()
|
||||
if (qb->set_switch(hint_state, hint_type, false))
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||
&null_ident_sys, NULL, NULL);
|
||||
&null_ident_sys, NULL, NULL, (Parser::Hint*) NULL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
for (const Table_name &table : table_name_list)
|
||||
@ -568,8 +609,11 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
||||
if (!tab)
|
||||
return true;
|
||||
if (tab->set_switch(hint_state, hint_type, true))
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||
&null_ident_sys, &table_name_sys, NULL);
|
||||
&null_ident_sys, &table_name_sys,
|
||||
NULL, (Parser::Hint*) NULL);
|
||||
}
|
||||
}
|
||||
|
||||
for (const Hint_param_table &table : opt_hint_param_table_list)
|
||||
@ -586,15 +630,17 @@ bool Optimizer_hint_parser::Table_level_hint::resolve(Parse_context *pc) const
|
||||
if (!tab)
|
||||
return true;
|
||||
if (tab->set_switch(hint_state, hint_type, true))
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||
&qb_name_sys, &table_name_sys, NULL);
|
||||
&qb_name_sys, &table_name_sys, NULL, (Parser::Hint*) NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Optimizer_hint_parser::Index_level_hint::resolve(Parse_context *pc) const
|
||||
bool Parser::Index_level_hint::resolve(Parse_context *pc) const
|
||||
{
|
||||
const Index_level_hint_type &index_level_hint_type= *this;
|
||||
opt_hints_enum hint_type;
|
||||
@ -639,8 +685,10 @@ bool Optimizer_hint_parser::Index_level_hint::resolve(Parse_context *pc) const
|
||||
if (is_empty()) // Table level hint
|
||||
{
|
||||
if (tab->set_switch(hint_state, hint_type, false))
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||
&qb_name_sys, &table_name_sys, NULL);
|
||||
&qb_name_sys, &table_name_sys, NULL, (Parser::Hint*) NULL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -656,15 +704,18 @@ bool Optimizer_hint_parser::Index_level_hint::resolve(Parse_context *pc) const
|
||||
}
|
||||
|
||||
if (idx->set_switch(hint_state, hint_type, true))
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, hint_type, hint_state,
|
||||
&qb_name_sys, &table_name_sys, &index_name_sys);
|
||||
&qb_name_sys, &table_name_sys, &index_name_sys,
|
||||
(Parser::Hint*) NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Optimizer_hint_parser::Qb_name_hint::resolve(Parse_context *pc) const
|
||||
bool Parser::Qb_name_hint::resolve(Parse_context *pc) const
|
||||
{
|
||||
Opt_hints_qb *qb= pc->select->opt_hints_qb;
|
||||
|
||||
@ -676,7 +727,7 @@ bool Optimizer_hint_parser::Qb_name_hint::resolve(Parse_context *pc) const
|
||||
qb->get_parent()->find_by_name(qb_name_sys)) // Name is already used
|
||||
{
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, QB_NAME_HINT_ENUM, true,
|
||||
&qb_name_sys, NULL, NULL);
|
||||
&qb_name_sys, NULL, NULL, (Parser::Hint*) NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -684,6 +735,94 @@ bool Optimizer_hint_parser::Qb_name_hint::resolve(Parse_context *pc) const
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
This is the first step of MAX_EXECUTION_TIME() hint resolution. It is invoked
|
||||
during the parsing phase, but at this stage some essential information is
|
||||
not yet available, preventing a full validation of the hint.
|
||||
Particularly, the type of SQL command, mark of a stored procedure execution
|
||||
or whether SELECT_LEX is not top-level (i.e., a subquery) are not yet set.
|
||||
However, some basic checks like the numeric argument validation or hint
|
||||
duplication check can still be performed.
|
||||
The second step of hint validation is performed during the JOIN preparation
|
||||
phase, within Opt_hints_global::resolve(). By this point, all necessary
|
||||
information is up-to-date, allowing the hint to be fully resolved
|
||||
*/
|
||||
bool Parser::Max_execution_time_hint::resolve(Parse_context *pc) const
|
||||
{
|
||||
const Unsigned_Number& hint_arg= *this;
|
||||
const ULonglong_null time_ms= hint_arg.get_ulonglong();
|
||||
|
||||
if (time_ms.is_null() || time_ms.value() == 0 || time_ms.value() > INT_MAX32)
|
||||
{
|
||||
print_warn(pc->thd, ER_BAD_OPTION_VALUE, MAX_EXEC_TIME_HINT_ENUM,
|
||||
true, NULL, NULL, NULL, this);
|
||||
return false;
|
||||
}
|
||||
|
||||
Opt_hints_global *global_hint= get_global_hints(pc);
|
||||
if (global_hint->is_specified(MAX_EXEC_TIME_HINT_ENUM))
|
||||
{
|
||||
// Hint duplication: /*+ MAX_EXECUTION_TIME ... MAX_EXECUTION_TIME */
|
||||
print_warn(pc->thd, ER_WARN_CONFLICTING_HINT, MAX_EXEC_TIME_HINT_ENUM, true,
|
||||
NULL, NULL, NULL, this);
|
||||
return false;
|
||||
}
|
||||
|
||||
global_hint->set_switch(true, MAX_EXEC_TIME_HINT_ENUM, false);
|
||||
global_hint->max_exec_time_hint= this;
|
||||
global_hint->max_exec_time_select_lex= pc->select;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Parser::Max_execution_time_hint::append_args(THD *thd, String *str) const
|
||||
{
|
||||
const Unsigned_Number& hint_arg= *this;
|
||||
str->append(ErrConvString(hint_arg.str, hint_arg.length,
|
||||
&my_charset_latin1).lex_cstring());
|
||||
}
|
||||
|
||||
|
||||
ulong Parser::Max_execution_time_hint::get_milliseconds() const
|
||||
{
|
||||
const Unsigned_Number& hint_arg= *this;
|
||||
return hint_arg.get_ulonglong().value();
|
||||
}
|
||||
|
||||
|
||||
bool Opt_hints_global::resolve(THD *thd)
|
||||
{
|
||||
if (!max_exec_time_hint || thd->lex->is_ps_or_view_context_analysis())
|
||||
return false;
|
||||
|
||||
/*
|
||||
2nd step of MAX_EXECUTION_TIME() hint validation. Some checks were already
|
||||
performed during the parsing stage (Max_execution_time_hint::resolve()),
|
||||
but the following checks can only be performed during the JOIN preparation
|
||||
because thd->lex variables are not available during parsing
|
||||
*/
|
||||
if (thd->lex->sql_command != SQLCOM_SELECT || // not a SELECT statement
|
||||
thd->lex->sphead || thd->in_sub_stmt != 0 || // or a SP/trigger/event
|
||||
max_exec_time_select_lex->master_unit() != &thd->lex->unit || // or a subquery
|
||||
max_exec_time_select_lex->select_number != 1) // not a top-level select
|
||||
{
|
||||
print_warn(thd, ER_NOT_ALLOWED_IN_THIS_CONTEXT, MAX_EXEC_TIME_HINT_ENUM,
|
||||
true, NULL, NULL, NULL, max_exec_time_hint);
|
||||
}
|
||||
else if (thd->variables.max_statement_time != 0 ||
|
||||
thd->query_timer.expired == 0)
|
||||
{
|
||||
print_warn(thd, ER_WARN_CONFLICTING_HINT, MAX_EXEC_TIME_HINT_ENUM, true,
|
||||
NULL, NULL, NULL, max_exec_time_hint);
|
||||
}
|
||||
else
|
||||
{
|
||||
thd->set_query_timer_force(max_exec_time_hint->get_milliseconds() * 1000);
|
||||
}
|
||||
set_resolved();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool Optimizer_hint_parser::Hint_list::resolve(Parse_context *pc) const
|
||||
{
|
||||
@ -717,6 +856,11 @@ bool Optimizer_hint_parser::Hint_list::resolve(Parse_context *pc) const
|
||||
if (qb_hint.resolve(pc))
|
||||
return true;
|
||||
}
|
||||
else if (const Max_execution_time_hint &max_hint= hint)
|
||||
{
|
||||
if (max_hint.resolve(pc))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -65,6 +65,7 @@
|
||||
#ifndef OPT_HINTS_INCLUDED
|
||||
#define OPT_HINTS_INCLUDED
|
||||
|
||||
#include <functional>
|
||||
#include "my_config.h"
|
||||
#include "sql_alloc.h"
|
||||
#include "sql_list.h"
|
||||
@ -73,7 +74,7 @@
|
||||
#include "sql_bitmap.h"
|
||||
#include "sql_show.h"
|
||||
#include "mysqld_error.h"
|
||||
|
||||
#include "opt_hints_parser.h"
|
||||
|
||||
struct LEX;
|
||||
struct TABLE;
|
||||
@ -91,6 +92,7 @@ enum opt_hints_enum
|
||||
MRR_HINT_ENUM,
|
||||
NO_RANGE_HINT_ENUM,
|
||||
QB_NAME_HINT_ENUM,
|
||||
MAX_EXEC_TIME_HINT_ENUM,
|
||||
MAX_HINT_ENUM
|
||||
};
|
||||
|
||||
@ -100,9 +102,10 @@ struct st_opt_hint_info
|
||||
LEX_CSTRING hint_name; // Hint name.
|
||||
bool check_upper_lvl; // true if upper level hint check is needed (for hints
|
||||
// which can be specified on more than one level).
|
||||
bool switch_hint; // true if hint is not complex.
|
||||
bool has_arguments; // true if hint has additional arguments.
|
||||
};
|
||||
|
||||
typedef Optimizer_hint_parser Parser;
|
||||
|
||||
/**
|
||||
Opt_hints_map contains information
|
||||
@ -304,6 +307,16 @@ public:
|
||||
void check_unresolved(THD *thd);
|
||||
virtual void append_name(THD *thd, String *str)= 0;
|
||||
|
||||
/**
|
||||
Get the function appending additional hint arguments to the printed string,
|
||||
if the arguments exist. For example, SEMIJOIN and SUBQUERY hints may have
|
||||
a list of strategies as additional arguments
|
||||
*/
|
||||
virtual std::function<void(THD*, String*)> get_args_printer() const
|
||||
{
|
||||
return [](THD*, String*) {};
|
||||
}
|
||||
|
||||
virtual ~Opt_hints() {}
|
||||
|
||||
private:
|
||||
@ -336,13 +349,31 @@ protected:
|
||||
|
||||
class Opt_hints_global : public Opt_hints
|
||||
{
|
||||
|
||||
public:
|
||||
const Parser::Max_execution_time_hint *max_exec_time_hint= nullptr;
|
||||
|
||||
/*
|
||||
If MAX_EXECUTION_TIME() hint was provided, this pointer is set to
|
||||
the SELECT_LEX which the hint is attached to.
|
||||
NULL if MAX_EXECUTION_TIME() hint is missing.
|
||||
*/
|
||||
st_select_lex *max_exec_time_select_lex= nullptr;
|
||||
|
||||
Opt_hints_global(MEM_ROOT *mem_root_arg)
|
||||
: Opt_hints(Lex_ident_sys(), NULL, mem_root_arg)
|
||||
{}
|
||||
|
||||
virtual void append_name(THD *thd, String *str) override {}
|
||||
|
||||
virtual std::function<void(THD*, String*)> get_args_printer() const override
|
||||
{
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
return std::bind(&Parser::Max_execution_time_hint::append_args,
|
||||
max_exec_time_hint, _1, _2);
|
||||
}
|
||||
|
||||
bool resolve(THD *thd);
|
||||
};
|
||||
|
||||
|
||||
|
@ -57,11 +57,30 @@ Optimizer_hint_tokenizer::find_keyword(const LEX_CSTRING &str)
|
||||
return TokenID::keyword_QB_NAME;
|
||||
break;
|
||||
|
||||
case 18:
|
||||
if ("MAX_EXECUTION_TIME"_Lex_ident_column.streq(str))
|
||||
return TokenID::keyword_MAX_EXECUTION_TIME;
|
||||
break;
|
||||
|
||||
case 21:
|
||||
if ("NO_RANGE_OPTIMIZATION"_Lex_ident_column.streq(str))
|
||||
return TokenID::keyword_NO_RANGE_OPTIMIZATION;
|
||||
break;
|
||||
}
|
||||
|
||||
if (str.length > 0 && (str.str[0] >= '0' && str.str[0] <= '9'))
|
||||
{
|
||||
/*
|
||||
If all characters are digits, qualify the token as a number,
|
||||
otherwise as an identifier
|
||||
*/
|
||||
for(size_t i = 1; i < str.length; i++)
|
||||
{
|
||||
if (str.str[i] < '0' || str.str[i] > '9')
|
||||
return TokenID::tIDENT;
|
||||
}
|
||||
return TokenID::tUNSIGNED_NUMBER;
|
||||
}
|
||||
return TokenID::tIDENT;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "simple_tokenizer.h"
|
||||
#include "sql_list.h"
|
||||
#include "sql_string.h"
|
||||
#include "sql_type_int.h"
|
||||
#include "simple_parser.h"
|
||||
|
||||
class st_select_lex;
|
||||
@ -72,9 +73,11 @@ public:
|
||||
keyword_NO_RANGE_OPTIMIZATION,
|
||||
keyword_MRR,
|
||||
keyword_QB_NAME,
|
||||
keyword_MAX_EXECUTION_TIME,
|
||||
|
||||
// Other token types
|
||||
tIDENT
|
||||
tIDENT,
|
||||
tUNSIGNED_NUMBER
|
||||
};
|
||||
|
||||
class Token: public Lex_cstring
|
||||
@ -240,6 +243,13 @@ private:
|
||||
using TOKEN::TOKEN;
|
||||
};
|
||||
|
||||
class Keyword_MAX_EXECUTION_TIME:
|
||||
public TOKEN<Parser, TokenID::keyword_MAX_EXECUTION_TIME>
|
||||
{
|
||||
public:
|
||||
using TOKEN::TOKEN;
|
||||
};
|
||||
|
||||
class Identifier: public TOKEN<Parser, TokenID::tIDENT>
|
||||
{
|
||||
public:
|
||||
@ -258,6 +268,28 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class Unsigned_Number: public TOKEN<Parser, TokenID::tUNSIGNED_NUMBER>
|
||||
{
|
||||
public:
|
||||
using TOKEN::TOKEN;
|
||||
|
||||
/*
|
||||
Converts token string to a non-negative number ( >=0 ).
|
||||
Returns the converted number if the conversion succeeds.
|
||||
Returns non-NULL ULonglong_null value on successful string conversion and
|
||||
NULL ULonglong_null if the conversion failed or the number is negative
|
||||
*/
|
||||
ULonglong_null get_ulonglong() const
|
||||
{
|
||||
int error;
|
||||
char *end= const_cast<char *>(str + length);
|
||||
longlong n= my_strtoll10(str, &end, &error);
|
||||
if (error != 0 || end != str + length || n < 0)
|
||||
return ULonglong_null(0, true);
|
||||
return ULonglong_null(n, false);
|
||||
}
|
||||
};
|
||||
|
||||
class LParen: public TOKEN<Parser, TokenID::tLPAREN>
|
||||
{
|
||||
public:
|
||||
@ -554,21 +586,40 @@ private:
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
// max_execution_time_hint ::= MAX_EXECUTION_TIME ( milliseconds )
|
||||
class Max_execution_time_hint: public AND4<Parser,
|
||||
Keyword_MAX_EXECUTION_TIME,
|
||||
LParen,
|
||||
Unsigned_Number,
|
||||
RParen>
|
||||
{
|
||||
public:
|
||||
using AND4::AND4;
|
||||
|
||||
bool resolve(Parse_context *pc) const;
|
||||
void append_args(THD *thd, String *str) const;
|
||||
ulong get_milliseconds() const;
|
||||
};
|
||||
|
||||
/*
|
||||
hint ::= index_level_hint
|
||||
| table_level_hint
|
||||
| qb_name_hint
|
||||
| statement_level_hint
|
||||
*/
|
||||
class Hint: public OR3<Parser,
|
||||
class Hint: public OR4<Parser,
|
||||
Index_level_hint,
|
||||
Table_level_hint,
|
||||
Qb_name_hint>
|
||||
Qb_name_hint,
|
||||
Max_execution_time_hint>
|
||||
{
|
||||
public:
|
||||
using OR3::OR3;
|
||||
using OR4::OR4;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
// hint_list ::= hint [ hint... ]
|
||||
class Hint_list_container: public List<Hint>
|
||||
{
|
||||
|
@ -380,7 +380,7 @@ protected:
|
||||
|
||||
|
||||
/*
|
||||
A rule consisting of a choice of thee rules:
|
||||
A rule consisting of a choice of three rules:
|
||||
rule ::= rule1 | rule2 | rule3
|
||||
|
||||
For the case when the three branches have incompatible storage
|
||||
@ -478,7 +478,50 @@ protected:
|
||||
|
||||
|
||||
/*
|
||||
A list with at least MIN_COUNT elements (typlically 0 or 1),
|
||||
A rule consisting of a choice of four rules:
|
||||
rule ::= rule1 | rule2 | rule3 | rule4
|
||||
|
||||
For the case when the three branches have incompatible storage
|
||||
*/
|
||||
template<class PARSER, class A, class B, class C, class D>
|
||||
class OR4: public A, public B, public C, public D
|
||||
{
|
||||
public:
|
||||
OR4()
|
||||
{ }
|
||||
OR4(OR4 &&rhs)
|
||||
:A(std::move(static_cast<A&&>(rhs))),
|
||||
B(std::move(static_cast<B&&>(rhs))),
|
||||
C(std::move(static_cast<C&&>(rhs))),
|
||||
D(std::move(static_cast<D&&>(rhs)))
|
||||
{ }
|
||||
OR4 & operator=(OR4 &&rhs)
|
||||
{
|
||||
A::operator=(std::move(static_cast<A&&>(rhs)));
|
||||
B::operator=(std::move(static_cast<B&&>(rhs)));
|
||||
C::operator=(std::move(static_cast<C&&>(rhs)));
|
||||
D::operator=(std::move(static_cast<D&&>(rhs)));
|
||||
return *this;
|
||||
}
|
||||
OR4(PARSER *p)
|
||||
:A(p),
|
||||
B(A::operator bool() ? B() : B(p)),
|
||||
C(A::operator bool() || B::operator bool() ? C() : C(p)),
|
||||
D(A::operator bool() || B::operator bool() || C::operator bool() ?
|
||||
D() : D(p))
|
||||
{
|
||||
DBUG_ASSERT(!operator bool() || !p->is_error());
|
||||
}
|
||||
operator bool() const
|
||||
{
|
||||
return A::operator bool() || B::operator bool() || C::operator bool() ||
|
||||
D::operator bool();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
A list with at least MIN_COUNT elements (typically 0 or 1),
|
||||
with or without a token separator between elements:
|
||||
|
||||
list ::= element [ {, element }... ] // with a separator
|
||||
|
@ -8229,6 +8229,7 @@ void make_leaves_list(THD *thd, List<TABLE_LIST> &list, TABLE_LIST *tables,
|
||||
refresh It is only refresh for subquery
|
||||
select_insert It is SELECT ... INSERT command
|
||||
full_table_list a parameter to pass to the make_leaves_list function
|
||||
resolve_opt_hints Whether optimizer hints must be resolved here
|
||||
|
||||
NOTE
|
||||
Check also that the 'used keys' and 'ignored keys' exists and set up the
|
||||
@ -8248,7 +8249,7 @@ void make_leaves_list(THD *thd, List<TABLE_LIST> &list, TABLE_LIST *tables,
|
||||
bool setup_tables(THD *thd, Name_resolution_context *context,
|
||||
List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
|
||||
List<TABLE_LIST> &leaves, bool select_insert,
|
||||
bool full_table_list)
|
||||
bool full_table_list, bool resolve_opt_hints)
|
||||
{
|
||||
uint tablenr= 0;
|
||||
List_iterator<TABLE_LIST> ti(leaves);
|
||||
@ -8393,8 +8394,13 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
|
||||
if (setup_natural_join_row_types(thd, from_clause, context))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (qb_hints)
|
||||
qb_hints->check_unresolved(thd);
|
||||
if (resolve_opt_hints)
|
||||
{
|
||||
if (thd->lex->opt_hints_global && select_lex->select_number == 1)
|
||||
thd->lex->opt_hints_global->resolve(thd);
|
||||
if (qb_hints)
|
||||
qb_hints->check_unresolved(thd);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -8414,6 +8420,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
|
||||
select_insert It is SELECT ... INSERT command
|
||||
want_access what access is needed
|
||||
full_table_list a parameter to pass to the make_leaves_list function
|
||||
resolve_opt_hints Whether optimizer hints must be resolved here
|
||||
|
||||
NOTE
|
||||
a wrapper for check_tables that will also check the resulting
|
||||
@ -8430,12 +8437,13 @@ bool setup_tables_and_check_access(THD *thd, Name_resolution_context *context,
|
||||
bool select_insert,
|
||||
privilege_t want_access_first,
|
||||
privilege_t want_access,
|
||||
bool full_table_list)
|
||||
bool full_table_list,
|
||||
bool resolve_opt_hints)
|
||||
{
|
||||
DBUG_ENTER("setup_tables_and_check_access");
|
||||
|
||||
if (setup_tables(thd, context, from_clause, tables,
|
||||
leaves, select_insert, full_table_list))
|
||||
leaves, select_insert, full_table_list, resolve_opt_hints))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
List_iterator<TABLE_LIST> ti(leaves);
|
||||
|
@ -228,7 +228,7 @@ Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
|
||||
bool setup_tables(THD *thd, Name_resolution_context *context,
|
||||
List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
|
||||
List<TABLE_LIST> &leaves, bool select_insert,
|
||||
bool full_table_list);
|
||||
bool full_table_list, bool resolve_opt_hints);
|
||||
bool setup_tables_and_check_access(THD *thd,
|
||||
Name_resolution_context *context,
|
||||
List<TABLE_LIST> *from_clause,
|
||||
@ -237,7 +237,8 @@ bool setup_tables_and_check_access(THD *thd,
|
||||
bool select_insert,
|
||||
privilege_t want_access_first,
|
||||
privilege_t want_access,
|
||||
bool full_table_list);
|
||||
bool full_table_list,
|
||||
bool resolve_opt_hints);
|
||||
bool wait_while_table_is_used(THD *thd, TABLE *table,
|
||||
enum ha_extra_function function);
|
||||
|
||||
|
@ -6040,7 +6040,7 @@ public:
|
||||
ulonglong num_of_strings_sorted_on_truncated_length;
|
||||
|
||||
public:
|
||||
void set_query_timer()
|
||||
void set_query_timer_if_needed()
|
||||
{
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
/*
|
||||
@ -6059,9 +6059,13 @@ public:
|
||||
*/
|
||||
if (!timeout_val || spcont || in_sub_stmt || query_timer.expired == 0)
|
||||
return;
|
||||
thr_timer_settime(&query_timer, timeout_val);
|
||||
set_query_timer_force(timeout_val);
|
||||
#endif
|
||||
}
|
||||
void set_query_timer_force(ulonglong timeout_val)
|
||||
{
|
||||
thr_timer_settime(&query_timer, timeout_val);
|
||||
}
|
||||
void reset_query_timer()
|
||||
{
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
@ -1880,11 +1880,11 @@ bool Sql_cmd_delete::prepare_inner(THD *thd)
|
||||
if (setup_tables_and_check_access(thd, &select_lex->context,
|
||||
&select_lex->top_join_list,
|
||||
table_list, select_lex->leaf_tables,
|
||||
false, DELETE_ACL, SELECT_ACL, true))
|
||||
false, DELETE_ACL, SELECT_ACL, true, false))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
|
||||
table_list, select_lex->leaf_tables, false, false))
|
||||
table_list, select_lex->leaf_tables, false, false, true))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (!multitable)
|
||||
|
@ -801,7 +801,7 @@ static bool init_items_for_help_command(THD *thd,
|
||||
|
||||
if (setup_tables(thd, &first_select_lex->context,
|
||||
&first_select_lex->top_join_list,
|
||||
&tables[0], leaves, false, false))
|
||||
&tables[0], leaves, false, false, true))
|
||||
return true;
|
||||
|
||||
memcpy((char*) used_fields, (char*) init_used_fields,
|
||||
|
@ -1647,7 +1647,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
table_list,
|
||||
thd->lex->first_select_lex()->leaf_tables,
|
||||
select_insert, INSERT_ACL, SELECT_ACL,
|
||||
TRUE))
|
||||
true, true))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (insert_into_view && !fields.elements)
|
||||
|
@ -419,7 +419,7 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list,
|
||||
thd->lex->first_select_lex()->leaf_tables,
|
||||
FALSE,
|
||||
INSERT_ACL | UPDATE_ACL,
|
||||
INSERT_ACL | UPDATE_ACL, FALSE))
|
||||
INSERT_ACL | UPDATE_ACL, false, true))
|
||||
DBUG_RETURN(-1);
|
||||
if (!table_list->table || // do not support join view
|
||||
!table_list->single_table_updatable() || // and derived tables
|
||||
|
@ -3822,7 +3822,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt)
|
||||
thd->query_plan_flags|= QPLAN_ADMIN;
|
||||
|
||||
/* Start timeouts */
|
||||
thd->set_query_timer();
|
||||
thd->set_query_timer_if_needed();
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
/* Check wsrep_mode rules before command execution. */
|
||||
|
@ -1468,7 +1468,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
|
||||
if (!(select_options & OPTION_SETUP_TABLES_DONE) &&
|
||||
setup_tables_and_check_access(thd, &select_lex->context, join_list,
|
||||
tables_list, select_lex->leaf_tables,
|
||||
FALSE, SELECT_ACL, SELECT_ACL, FALSE))
|
||||
false, SELECT_ACL, SELECT_ACL, false, true))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/* System Versioning: handle FOR SYSTEM_TIME clause. */
|
||||
|
@ -1672,7 +1672,7 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd)
|
||||
|
||||
if (setup_tables_and_check_access(thd, &select_lex->context,
|
||||
&select_lex->top_join_list, table_list, select_lex->leaf_tables,
|
||||
FALSE, UPDATE_ACL, SELECT_ACL, TRUE))
|
||||
false, UPDATE_ACL, SELECT_ACL, true, false))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (table_list->has_period() &&
|
||||
@ -3118,7 +3118,7 @@ bool Sql_cmd_update::prepare_inner(THD *thd)
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list,
|
||||
table_list, select_lex->leaf_tables, false, false))
|
||||
table_list, select_lex->leaf_tables, false, false, true))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (select_lex->vers_setup_conds(thd, table_list))
|
||||
|
Reference in New Issue
Block a user