目录文档:MySQL 源码|源码剖析文档目录
源码位置(版本 = MySQL 8.0.37):sql/sql_yacc.yy
前置文档:
- MySQL 源码|37 - 语法解析:聚集函数
- MySQL 源码|38 - 语法解析:窗口函数
- MySQL 源码|43 - 语法解析:关键字函数
- MySQL 源码|44 - 语法解析:非关键字函数
- MySQL 源码|45 - 语法解析:通用函数
- MySQL 源码|46 - 语法解析:为避免语法冲突专门处理的函数
- MySQL 源码|47 - 语法解析:子查询
- MySQL 源码|48 - 语法解析:字面值
- MySQL 源码|49 - 语法解析:CAST 函数、CONVERT 函数和 BINARY 关键字
在此之前,我们已经梳理的规则关系如下图所示。梳理基础表达式(simple_expr
)规则的前置条件已经成熟,下面让我们开始梳理 simple_expr
规则。
simple_expr
规则相关关系如下图所示:其中绿色节点为本章节梳理,蓝色节点为之前章节已梳理,红色节点为后续章节梳理。
simple_expr
规则
simple_expr
规则用于匹配基础表达式,也可以理解为匹配一元表达式的结果,有如下备选方案:
- 匹配
simple_ident
规则的结果:用于匹配ident
、ident.ident
或ident.ident.ident
- 匹配
function_call_keyword
规则匹配结果:用于匹配关键字函数,详见 MySQL 源码|43 - 语法解析:关键字函数 - 匹配
function_call_nonkeyword
规则匹配结果:用于匹配非关键字函数,详见 MySQL 源码|44 - 语法解析:非关键字函数 - 匹配
function_call_generic
规则匹配结果:用于匹配通用函数,详见 MySQL 源码|45 - 语法解析:通用函数 - 匹配
function_call_conflict
规则匹配结果:用于匹配为避免语法冲突专门处理的函数,详见 MySQL 源码|46 - 语法解析:为避免语法冲突专门处理的函数 - 依次匹配
simple_expr
规则匹配结果、COLLATE
关键字和ident_or_text
规则匹配结果:用于在基础表达式的基础上指定排序规则 - 匹配
literal_or_null
规则匹配结果:用于匹配字面值和NULL
值,详见 MySQL 源码|48 - 语法解析:字面值 - 匹配
param_marker
规则匹配结果:用于匹配参数值,详见 MySQL 源码|48 - 语法解析:字面值 - 匹配
rvalue_system_or_user_variable
规则匹配结果:用于匹配系统变量或用户变量 - 匹配
in_expression_user_variable_assignment
规则匹配结果:用于匹配用户变量赋值语句 - 匹配
set_function_specification
规则匹配结果:用于匹配聚集函数,详见 MySQL 源码|37 - 语法解析:聚集函数 - 匹配
window_func_call
规则匹配结果:用于匹配窗口函数,详见 MySQL 源码|38 - 语法解析:窗口函数 - 依次匹配
simple_expr
规则匹配结果、||
(OR_OR_SYM
)和simple_expr
关键字:用于匹配使用逻辑或符号连接的基础表达式 - 依次匹配
+
和simple_expr
规则匹配结果:用于匹配使用了+
前缀一元表达式的基础表达式 - 依次匹配
-
和simple_expr
规则匹配结果:用于匹配使用了-
前缀一元表达式的基础表达式 - 依次匹配
~
和simple_expr
规则匹配结果:用于匹配使用了~
前缀一元表达式的基础表达式 - 依次匹配
not2
规则匹配结果和simple_expr
规则用于:用于匹配使用了!
前缀一元表达式(或 SQL_MODE 为MODE_HIGH_NOT_PRECEDENCE
时的NOT
关键字)的基础表达式 - 匹配
row_subquery
规则匹配结果:用于匹配单行子查询,详见 MySQL 源码|47 - 语法解析:子查询 - 依次匹配
(
、expr
规则匹配结果和)
:用于匹配被括号框柱的一个更高级别表达式 - 依次匹配
ROW
关键字、(
、expr
规则匹配结果、,
、expr_list
和)
:用于匹配ROW
子句和其中被括号框柱的多个更高级别表达式 - 依次匹配
EXISTS
关键字和table_subquery
规则匹配结果:用于匹配EXISTS
子句和其中的多行子查询,详见 详见 MySQL 源码|47 - 语法解析:子查询 - 依次匹配
{
、ident
规则匹配结果、expr
规则匹配结果和}
:用于匹配 ODBC 日期 - 依次匹配
MATCH
关键字、ident_list_arg
规则匹配结果、AGAINST
关键字、(
、bit_expr
规则匹配结果、fulltext_options
规则匹配结果和)
:用于匹配全文搜索子句,其中ident_list_arg
规则匹配任意数量的逗号分隔的标识符,fulltext_options
规则匹配全文搜索的配置 - 依次匹配
BINARY
关键字和simple_expr
:用于匹配BINARY
关键字将字符串转换为二进制字符串 - 依次匹配
CAST
关键字、(
、expr
规则匹配结果、AS
关键字、cast_type
规则匹配结果、opt_array_cast
规则匹配结果和)
:用于匹配CAST
函数,详见 MySQL 源码|49 - 语法解析:CAST 函数、CONVERT 函数和 BINARY 关键字 - 依次匹配
CAST
关键字、(
、expr
规则匹配结果、AT
关键字、LOCAL
关键字、AS
关键字、cast_type
规则匹配结果、opt_array_cast
规则匹配结果和)
:用于匹配CAST
函数,详见 MySQL 源码|49 - 语法解析:CAST 函数、CONVERT 函数和 BINARY 关键字 - 依次匹配
CAST
关键字、(
、expr
规则匹配结果、AT
关键字、TIME
关键字、ZONE
关键字、opt_interval
规则匹配结果、TEXT_STRING_literal
规则匹配结果、AS
关键字、DATETIME
关键字、type_datetime_precision
规则匹配结果和)
:用于匹配CAST
函数,详见 MySQL 源码|49 - 语法解析:CAST 函数、CONVERT 函数和 BINARY 关键字 - 依次匹配
CASE
关键字、opt_expr
规则匹配结果、when_list
规则匹配结果opt_else
规则匹配结果和END
关键字:用于匹配CASE
子句,其中opt_expr
规则匹配可选的一般表达式,when_list
规则匹配CASE
子句中任意数量的WHEN {expr} THEN {expr}
子句,opt_else
规则匹配可选的ELSE {expr}
子句 - 依次匹配
CONVERT
关键字、(
、expr
规则匹配结果,,
、cast_type
规则匹配结果和)
:用于匹配CONVERT
函数,详见 MySQL 源码|49 - 语法解析:CAST 函数、CONVERT 函数和 BINARY 关键字依次匹配CONVERT
关键字、(
、expr
规则匹配结果、USING
关键字、charset_name
关键字匹配结果和)
:用于匹配CONVERT
函数,详见 MySQL 源码|49 - 语法解析:CAST 函数、CONVERT 函数和 BINARY 关键字 - 依次匹配
DEFUALT
关键字、(
、simple_ident
规则匹配结果和)
:用于匹配DEFAULT
函数 - 依次匹配
VALUES
关键字、(
、simple_ident_nospvar
规则匹配结果和)
:用于匹配VALUES
函数 - 依次匹配
INTERVAL_SYM
关键字、expr
规则匹配结果、interval
规则匹配结果、+
和expr
规则匹配结果:用于匹配INTERVAL
关键字引导的时间长度 - 依次匹配
simple_ident
规则匹配结果、->
(JSON_SEPARATOR_SYM
规则)和TEXT_STRING_literal
规则匹配结果:用于匹配 Json 数据提取语句 - 依次匹配
simple_ident
规则匹配结果、->>
(JSON_UNQUOTED_SEPARATOR_SYM
规则)和TEXT_STRING_literal
规则匹配结果:用于匹配 Json 数据提取语句
Bison 语法如下:
simple_expr:
simple_ident
| function_call_keyword
| function_call_nonkeyword
| function_call_generic
| function_call_conflict
| simple_expr COLLATE_SYM ident_or_text %prec NEG
{
warn_on_deprecated_user_defined_collation(YYTHD, $3);
$$= NEW_PTN Item_func_set_collation(@$, $1, $3);
}
| literal_or_null
| param_marker { $$= $1; }
| rvalue_system_or_user_variable
| in_expression_user_variable_assignment
| set_function_specification
| window_func_call
| simple_expr OR_OR_SYM simple_expr
{
$$= NEW_PTN Item_func_concat(@$, $1, $3);
}
| '+' simple_expr %prec NEG
{
$$= $2; // TODO: do we really want to ignore unary '+' before any kind of literals?
if ($$ != nullptr) $$->m_pos = @$;
}
| '-' simple_expr %prec NEG
{
$$= NEW_PTN Item_func_neg(@$, $2);
}
| '~' simple_expr %prec NEG
{
$$= NEW_PTN Item_func_bit_neg(@$, $2);
}
| not2 simple_expr %prec NEG
{
$$= NEW_PTN PTI_truth_transform(@$, $2, Item::BOOL_NEGATED);
}
| row_subquery
{
$$= NEW_PTN PTI_singlerow_subselect(@$, $1);
}
| '(' expr ')'
{
$$= $2;
if ($$ != nullptr) $$->m_pos = @$;
}
| '(' expr ',' expr_list ')'
{
$$= NEW_PTN Item_row(@$, $2, $4->value);
}
| ROW_SYM '(' expr ',' expr_list ')'
{
$$= NEW_PTN Item_row(@$, $3, $5->value);
}
| EXISTS table_subquery
{
$$= NEW_PTN PTI_exists_subselect(@$, $2);
}
| '{' ident expr '}'
{
$$= NEW_PTN PTI_odbc_date(@$, $2, $3);
}
| MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')'
{
$$= NEW_PTN Item_func_match(@$, $2, $5, $6);
}
| BINARY_SYM simple_expr %prec NEG
{
push_deprecated_warn(YYTHD, "BINARY expr", "CAST");
$$= create_func_cast(YYTHD, @$, $2, ITEM_CAST_CHAR, &my_charset_bin);
if ($$ == nullptr)
MYSQL_YYABORT;
}
| CAST_SYM '(' expr AS cast_type opt_array_cast ')'
{
$$= create_func_cast(YYTHD, @$, $3, $5, $6);
if ($$ == nullptr)
MYSQL_YYABORT;
}
| CAST_SYM '(' expr AT_SYM LOCAL_SYM AS cast_type opt_array_cast ')'
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "AT LOCAL");
}
| CAST_SYM '(' expr AT_SYM TIME_SYM ZONE_SYM opt_interval
TEXT_STRING_literal AS DATETIME_SYM type_datetime_precision ')'
{
Cast_type cast_type{ITEM_CAST_DATETIME, nullptr, nullptr, $11};
auto datetime_factor =
NEW_PTN Item_func_at_time_zone(@3, $3, $8.str, $7);
$$ = create_func_cast(YYTHD, @$, datetime_factor, cast_type, false);
if ($$ == nullptr)
MYSQL_YYABORT;
}
| CASE_SYM opt_expr when_list opt_else END
{
$$= NEW_PTN Item_func_case(@$, $3, $2, $4 );
}
| CONVERT_SYM '(' expr ',' cast_type ')'
{
$$= create_func_cast(YYTHD, @$, $3, $5, false);
if ($$ == nullptr)
MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr USING charset_name ')'
{
$$= NEW_PTN Item_func_conv_charset(@$, $3,$5);
}
| DEFAULT_SYM '(' simple_ident ')'
{
$$= NEW_PTN Item_default_value(@$, $3);
}
| VALUES '(' simple_ident_nospvar ')'
{
$$= NEW_PTN Item_insert_value(@$, $3);
}
| INTERVAL_SYM expr interval '+' expr %prec INTERVAL_SYM
/* we cannot put interval before - */
{
$$= NEW_PTN Item_date_add_interval(@$, $5, $2, $3, 0);
}
| simple_ident JSON_SEPARATOR_SYM TEXT_STRING_literal
{
Item_string *path=
NEW_PTN Item_string(@3, $3.str, $3.length,
YYTHD->variables.collation_connection);
$$= NEW_PTN Item_func_json_extract(YYTHD, @$, $1, path);
}
| simple_ident JSON_UNQUOTED_SEPARATOR_SYM TEXT_STRING_literal
{
Item_string *path=
NEW_PTN Item_string(@3, $3.str, $3.length,
YYTHD->variables.collation_connection);
Item *extr= NEW_PTN Item_func_json_extract(YYTHD, @$, $1, path);
$$= NEW_PTN Item_func_json_unquote(@$, extr);
}
;
simple_ident
规则
simple_ident
规则用于匹配 ident
、ident.ident
或 ident.ident.ident
,包含如下两种备选方案,其中 simple_ident_q
规则用于匹配 ident.ident
或 ident.ident.ident
。Bison 语法如下:
simple_ident:
ident
{
$$= NEW_PTN PTI_simple_ident_ident(@$, to_lex_cstring($1));
}
| simple_ident_q
;
simple_ident_q
规则
simple_ident_q
规则用于匹配 ident.ident
或 ident.ident.ident
,Bison 语法如下:
simple_ident_q:
ident '.' ident
{
$$= NEW_PTN PTI_simple_ident_q_2d(@$, $1.str, $3.str);
}
| ident '.' ident '.' ident
{
if (check_and_convert_db_name(&$1, false) != Ident_name_check::OK)
MYSQL_YYABORT;
$$= NEW_PTN PTI_simple_ident_q_3d(@$, $1.str, $3.str, $5.str);
}
;
rvalue_system_or_user_variable
规则
rvalue_system_or_user_variable
规则用于匹配系统变量和用户变量,包含如下 2 种备选方案:
- 依次匹配
@
和ident_or_text
规则匹配结果。 - 依次匹配
@
、@
、opt_rvalue_system_variable_type
规则匹配结果和rvalue_system_variable
规则匹配结果,其中opt_rvalue_system_variable_type
规则用于匹配GLOBAL
关键字、LOCAL
关键字或SESSION
关键字。
Bison 语法如下:
rvalue_system_or_user_variable:
'@' ident_or_text
{
$$ = NEW_PTN PTI_user_variable(@$, $2);
}
| '@' '@' opt_rvalue_system_variable_type rvalue_system_variable
{
$$ = NEW_PTN PTI_get_system_variable(@$, $3,
@4, $4.prefix, $4.name);
}
;
opt_rvalue_system_variable_type
规则
opt_rvalue_system_variable_type
规则用于匹配 GLOBAL
关键字、LOCAL
关键字或 SESSION
关键字,Bison 语法如下:
opt_rvalue_system_variable_type:
%empty { $$=OPT_DEFAULT; }
| GLOBAL_SYM '.' { $$=OPT_GLOBAL; }
| LOCAL_SYM '.' { $$=OPT_SESSION; }
| SESSION_SYM '.' { $$=OPT_SESSION; }
;
rvalue_system_variable
规则
rvalue_system_variable
规则用于匹配 ident_or_text[.ident]
,Bison 语法如下:
rvalue_system_variable:
ident_or_text
{
$$ = Bipartite_name{{}, to_lex_cstring($1)};
}
| ident_or_text '.' ident
{
// disallow "SELECT @@global.global.variable"
if (check_reserved_words($1.str)) {
YYTHD->syntax_error_at(@1);
MYSQL_YYABORT;
}
$$ = Bipartite_name{to_lex_cstring($1), to_lex_cstring($3)};
}
;
in_expression_user_variable_assignment
规则
in_expression_user_variable_assignment
规则用于匹配用户变量赋值语句,其中 SET_VAR
匹配 :=
。Bison 语法如下:
in_expression_user_variable_assignment:
'@' ident_or_text SET_VAR expr
{
push_warning(YYTHD, Sql_condition::SL_WARNING,
ER_WARN_DEPRECATED_SYNTAX,
ER_THD(YYTHD, ER_WARN_DEPRECATED_USER_SET_EXPR));
$$ = NEW_PTN PTI_variable_aux_set_var(@$, $2, $4);
}
;
not2
规则
not2
规则用于匹配 !
运算符或 NOT2_SYM
关键字,其中 NOT2_SYM
关键字为 SQL_MODE 开启了 MODE_HIGH_NOT_PRECEDENCE
时的 NOT
关键字。Bison 语法如下:
not2:
'!' { push_deprecated_warn(YYTHD, "!", "NOT"); }
| NOT2_SYM
;
ident_list_arg
规则
ident_list_arg
规则用于匹配包含外层括号或不包含外层括号的标识符的、逗号分隔的、任意数量的标识符,Bison 语法如下:
ident_list_arg:
ident_list { $$= $1; }
| '(' ident_list ')' { $$= $2; }
;
ident_list
规则
ident_list
规则用于匹配使用逗号分隔的任意数量标识符,Bison 语法如下:
ident_list:
simple_ident
{
$$= NEW_PTN PT_item_list(@$);
if ($$ == nullptr || $$->push_back($1))
MYSQL_YYABORT;
}
| ident_list ',' simple_ident
{
if ($1 == nullptr || $1->push_back($3))
MYSQL_YYABORT;
$$= $1;
$$->m_pos = @$;
}
;
fulltext_options
规则
fulltext_options
规则用于匹配全文搜索的配置,提供如下两种备选方案:
- 依次匹配
opt_natural_language_mode
规则匹配结果和opt_query_expansion
规则匹配结果,其中opt_natural_language_mode
规则匹配可选的IN NATURAL LANGUAGE MODE
,opt_query_expansion
规则匹配可选的WITH QUERY EXPANSION
。 - 依次匹配
IN
关键字、BOOLEAN
关键字和MODE
关键字
Bison 语法如下:
fulltext_options:
opt_natural_language_mode opt_query_expansion
{ $$= $1 | $2; }
| IN_SYM BOOLEAN_SYM MODE_SYM
{
$$= FT_BOOL;
DBUG_EXECUTE_IF("simulate_bug18831513",
{
THD *thd= YYTHD;
if (thd->sp_runtime_ctx)
YYTHD->syntax_error();
});
}
;
opt_natural_language_mode
规则
opt_natural_language_mode
规则用于匹配可选的 IN NATURAL LANGUAGE MODE
,Bison 语法如下:
opt_natural_language_mode:
%empty { $$= FT_NL; }
| IN_SYM NATURAL LANGUAGE_SYM MODE_SYM { $$= FT_NL; }
;
opt_query_expansion
规则
opt_query_expansion
规则用于匹配可选的 WITH QUERY EXPANSION
,Bison 语法如下:
opt_query_expansion:
%empty { $$= 0; }
| WITH QUERY_SYM EXPANSION_SYM { $$= FT_EXPAND; }
;
opt_expr
规则
opt_expr
规则用于匹配可选的一般表达式,Bison 语法如下:
opt_expr:
%empty { $$= nullptr; }
| expr { $$= $1; }
;
when_list
规则
when_list
规则用于匹配 CASE
子句中任意数量的 WHEN {expr} THEN {expr}
子句,Bison 语法如下:
when_list:
WHEN_SYM expr THEN_SYM expr
{
$$= new (YYMEM_ROOT) mem_root_deque<Item *>(YYMEM_ROOT);
if ($$ == nullptr)
MYSQL_YYABORT;
$$->push_back($2);
$$->push_back($4);
}
| when_list WHEN_SYM expr THEN_SYM expr
{
$1->push_back($3);
$1->push_back($5);
$$= $1;
}
;
opt_else
规则
opt_else
规则匹配可选的 ELSE {expr}
子句,Bison 语法如下:
opt_else:
%empty { $$= nullptr; }
| ELSE expr { $$= $2; }
;