1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-05 13:16:09 +03:00

MDEV-34888 Implement SEMIJOIN() and SUBQUERY() hints

This commit is contained in:
Oleg Smirnov
2024-09-11 19:53:57 +07:00
parent e3bf4c826c
commit 2c8f6058c1
28 changed files with 3712 additions and 164 deletions

View File

@@ -26,6 +26,7 @@
#include "simple_parser.h"
class st_select_lex;
class Opt_hints_qb;
/**
Environment data for the name resolution phase
@@ -74,6 +75,14 @@ public:
keyword_MRR,
keyword_QB_NAME,
keyword_MAX_EXECUTION_TIME,
keyword_SEMIJOIN,
keyword_NO_SEMIJOIN,
keyword_SUBQUERY,
keyword_MATERIALIZATION,
keyword_FIRSTMATCH,
keyword_LOOSESCAN,
keyword_DUPSWEEDOUT,
keyword_INTOEXISTS,
// Other token types
tIDENT,
@@ -250,6 +259,12 @@ private:
using TOKEN::TOKEN;
};
class Keyword_SUBQUERY: public TOKEN<Parser, TokenID::keyword_SUBQUERY>
{
public:
using TOKEN::TOKEN;
};
class Identifier: public TOKEN<Parser, TokenID::tIDENT>
{
public:
@@ -344,10 +359,8 @@ private:
using TokenChoice::TokenChoice;
};
// Identifiers of various kinds
// query_block_name ::= identifier
class Query_block_name: public Identifier
{
@@ -599,25 +612,230 @@ public:
bool resolve(Parse_context *pc) const;
void append_args(THD *thd, String *str) const;
ulong get_milliseconds() const;
ulonglong get_milliseconds() const;
};
// semijoin_hint_type ::= SEMIJOIN | NO_SEMIJOIN
class Semijoin_hint_type_cond
{
public:
static bool allowed_token_id(TokenID id)
{
return id == TokenID::keyword_SEMIJOIN ||
id == TokenID::keyword_NO_SEMIJOIN;
}
};
class Semijoin_hint_type: public TokenChoice<Parser,
Semijoin_hint_type_cond>
{
public:
using TokenChoice::TokenChoice;
};
// semijoin_strategy ::= MATERIALIZATION | FIRSTMATCH | LOOSESCAN | DUPSWEEDOUT
class Semijoin_strategy_cond
{
public:
static bool allowed_token_id(TokenID id)
{
return id == TokenID::keyword_MATERIALIZATION ||
id == TokenID::keyword_FIRSTMATCH ||
id == TokenID::keyword_LOOSESCAN ||
id == TokenID::keyword_DUPSWEEDOUT;
}
};
class Semijoin_strategy: public TokenChoice<Parser, Semijoin_strategy_cond>
{
public:
using TokenChoice::TokenChoice;
};
/*
strategy_list ::= strategy_name [ {, strategy_name }... ]
opt_strategy_list ::= [ strategy_list ]
*/
class Semijoin_strategy_list_container: public List<Semijoin_strategy>
{
public:
Semijoin_strategy_list_container()
{ }
bool add(Optimizer_hint_parser *p, Semijoin_strategy &&strategy);
size_t count() const { return elements; }
};
class Opt_sj_strategy_list: public LIST<Parser,
Semijoin_strategy_list_container,
Semijoin_strategy, TokenID::tCOMMA, 0>
{
public:
using LIST::LIST;
};
class Hint_param_opt_sj_strategy_list: public LIST<Parser,
Semijoin_strategy_list_container,
Semijoin_strategy, TokenID::tCOMMA, 0>
{
public:
using LIST::LIST;
};
/*
at_query_block_name_opt_strategies_list ::=
@ query_block_name opt_strategies_list
*/
class At_query_block_name_opt_strategy_list: public AND2<
Parser,
At_query_block_name,
Opt_sj_strategy_list>
{
public:
using AND2::AND2;
};
/*
semijoin_hint_body: @ query_block_name opt_sj_strategy_list
| opt_sj_strategy_list
*/
class Semijoin_hint_body: public OR2<Parser,
At_query_block_name_opt_strategy_list,
Hint_param_opt_sj_strategy_list>
{
public:
using OR2::OR2;
};
public:
/*
semijoin_hint ::= semijoin_hint_type ( semijoin_hint_body )
*/
class Semijoin_hint: public AND4<Parser,
Semijoin_hint_type,
LParen,
Semijoin_hint_body,
RParen>
{
public:
using AND4::AND4;
bool resolve(Parse_context *pc) const;
void append_args(THD *thd, String *str) const;
private:
Opt_hints_qb* resolve_for_qb_name(Parse_context *pc, bool hint_state,
const Lex_ident_sys *qb_name) const;
void fill_strategies_map(Opt_hints_qb *qb) const;
void add_strategy_to_map(TokenID token_id, Opt_hints_qb *qb) const;
void append_strategy_name(TokenID token_id, String *str) const;
};
private:
// subquery_strategy ::= MATERIALIZATION | INTOEXISTS
class Subquery_strategy_cond
{
public:
static bool allowed_token_id(TokenID id)
{
return id == TokenID::keyword_MATERIALIZATION ||
id == TokenID::keyword_INTOEXISTS;
}
};
class Subquery_strategy: public TokenChoice<Parser, Subquery_strategy_cond>
{
public:
using TokenChoice::TokenChoice;
};
class Hint_param_subquery_strategy: public TokenChoice<Parser,
Subquery_strategy_cond>
{
public:
using TokenChoice::TokenChoice;
};
/*
at_query_block_name_subquery_strategy ::=
@ query_block_name subquery_strategy
*/
class At_query_block_name_subquery_strategy: public AND2<
Parser,
At_query_block_name,
Subquery_strategy>
{
public:
using AND2::AND2;
};
/*
subquery_hint_body: @ query_block_name subquery_strategy
| subquery_strategy
*/
class Subquery_hint_body: public OR2<Parser,
At_query_block_name_subquery_strategy,
Hint_param_subquery_strategy>
{
public:
using OR2::OR2;
};
public:
// subquery_hint ::= SUBQUERY( subquery_hint_body )
class Subquery_hint: public AND4<Parser,
Keyword_SUBQUERY,
LParen,
Subquery_hint_body,
RParen>
{
public:
using AND4::AND4;
bool resolve(Parse_context *pc) const;
void append_args(THD *thd, String *str) const;
private:
void set_subquery_strategy(TokenID token_id, Opt_hints_qb *qb) const;
Opt_hints_qb* resolve_for_qb_name(Parse_context *pc, TokenID token_id,
const Lex_ident_sys *qb_name) const;
};
/*
hint ::= index_level_hint
| table_level_hint
| qb_name_hint
| statement_level_hint
| max_execution_time_hint
| semijoin_hint
| subquery_hint
*/
class Hint: public OR4<Parser,
class Hint: public OR6<Parser,
Index_level_hint,
Table_level_hint,
Qb_name_hint,
Max_execution_time_hint>
Max_execution_time_hint,
Semijoin_hint,
Subquery_hint>
{
public:
using OR4::OR4;
};
using OR6::OR6;
/**
Append additional hint arguments to the printed string.
Implement this method in Hint specifications if needed:
Table_level_hint, Semijoin_hint, etc
@param thd Pointer to THD object
@param str Pointer to String object
*/
void append_args(THD *thd, String *str) const {}
};
private:
// hint_list ::= hint [ hint... ]
@@ -630,6 +848,7 @@ private:
size_t count() const { return elements; }
};
class Hint_list: public LIST<Parser, Hint_list_container,
Hint, TokenID::tNULL/*not separated list*/, 1>
{
@@ -649,12 +868,11 @@ public:
public:
using AND2::AND2;
};
};
/*
This wrapper class is needed to use a forward declaration in sql_lex.h
These wrapper class is needed to use a forward declarations in sql_lex.h
instead of including the entire opt_hints_parser.h.
(forward declarations of qualified nested classes are not possible in C++)
*/
@@ -664,5 +882,4 @@ public:
using Hints::Hints;
};
#endif // OPT_HINTS_PARSER