目录文档:MySQL 源码|源码剖析文档目录
源码位置(版本 = MySQL 8.0.37):sql/sql_yacc.yy
前置文档:
在此之前,我们已经梳理了基础查询语句中涉及的 INTO
子句、FROM
子句、JOIN
子句、索引指示子句(USE
、FORCE
或 IGNORE
关键字引导)、WHERE
子句、GROUP BY
子句、HAVING
子句、QUALIFY
子句、WINDOW
子句和 ORDER BY
子句,下面我们来梳理解析基础查询语句的 query_specification
语义组。其中涉及的 symbol 及 symbol 之间的关系如下(图中绿色节点为字符串字面值涉及节点、蓝色节点为其他语义组、灰色节点为其他终结符):
query_specification
query_specification
语义组用于解析基础查询语句。在这个语义组中不包含 ORDER BY
子句和 LIMIT
子句,是因为 MySQL 的查询树结构中,ORDER BY
子句和 LIMIT
子句的逻辑保存在 Query_block
之中,而这个语义组解析的是 Query_expression
。
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr] ...
[into_option]
[FROM table_references
[PARTITION partition_list]]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
[HAVING where_condition]
[WINDOW window_name AS (window_spec)
[, window_name AS (window_spec)] ...]
PT_query_primary
对象(query_primary
),其中 PT_query_primary
为 PT_query_expression_body
的子类query_primary
语义组INTO
子句):query_specification:
SELECT_SYM
select_options
select_item_list
into_clause
opt_from_clause
opt_where_clause
opt_group_clause
opt_having_clause
opt_window_clause
opt_qualify_clause
{
$$= NEW_PTN PT_query_specification(
@$,
$1, // SELECT_SYM
$2, // select_options
$3, // select_item_list
$4, // into_clause
$5, // from
$6, // where
$7, // group
$8, // having
$9, // windows
$10, // qualify
@5.raw.is_empty()); // implicit FROM
}
| SELECT_SYM
select_options
select_item_list
opt_from_clause
opt_where_clause
opt_group_clause
opt_having_clause
opt_window_clause
opt_qualify_clause
{
$$= NEW_PTN PT_query_specification(
@$,
$1, // SELECT_SYM
$2, // select_options
$3, // select_item_list
nullptr,// no INTO clause
$4, // from
$5, // where
$6, // group
$7, // having
$8, // windows
$9, // qualify
@4.raw.is_empty()); // implicit FROM
}
;
select_options
语义组用于解析可选的查询选项,详见下文;
select_item_list
语义组用于解析查询字段的列表,详见下文;
into_clause
语义组用于解析INTO
子句,详见 MySQL 源码|53 - 语法解析(V2):INTO 子句;
opt_from_clause
语义组用于解析可选的FROM
子句,其中包含JOIN
子句,详见 MySQL 源码|52 - 语法解析(V2):FROM 子句和 JOIN 子句;
opt_where_clause
语义组用于解析可选的WHERE
子句,详见 MySQL 源码|77 - 语法解析(V2):WHERE、HAVING 和 QUALIFY 子句;
opt_group_clause
语义组用于解析可选的GROUP BY
子句,详见 MySQL 源码|40 - 语法解析(V2):GROUP BY 子句;
opt_having_clause
语义组用于解析可选的HAVING
子句,详见 MySQL 源码|77 - 语法解析(V2):WHERE、HAVING 和 QUALIFY 子句;
opt_window_clause
语义组用于解析WINDOW
子句,指定有名称的窗口以便在查询表达式的其他位置复用,详见 MySQL 源码|54 - 语法解析(V2):WINDOW 子句;
opt_qualify_clause
语义组用于解析可选的QUALIFY
子句,详见 MySQL 源码|77 - 语法解析(V2):WHERE、HAVING 和 QUALIFY 子句。
select_options
select_options
语义组用于解析可选的、任意数量、空格分隔的查询选项。
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
Query_options
结构体(select_options
),其中包含状态压缩 query_spec_options
属性。select_options:
%empty
{
$$.query_spec_options= 0;
}
| select_option_list
;
select_option_list
select_option_list
语义组用于解析大于等于 1 个、空格分隔的查询选项。
Query_options
结构体(select_options
)select_option_list:
select_option_list select_option
{
if ($$.merge($1, $2))
MYSQL_YYABORT;
}
| select_option
;
select_option
select_option
语义组用于解析一个查询选项。
Query_options
结构体(select_options
)select_option:
query_spec_option
{
$$.query_spec_options= $1;
}
| SQL_NO_CACHE_SYM
{
push_deprecated_warn_no_replacement(YYTHD, "SQL_NO_CACHE");
/* Ignored since MySQL 8.0. */
$$.query_spec_options= 0;
}
;
query_spec_option
query_spec_option
语义组用于解析除 SQL_NO_CACHE
之外的其他查询选项。
unsigned long long int
类型(ulonglong_number
)query_spec_option:
STRAIGHT_JOIN { $$= SELECT_STRAIGHT_JOIN; }
| HIGH_PRIORITY { $$= SELECT_HIGH_PRIORITY; }
| DISTINCT { $$= SELECT_DISTINCT; }
| SQL_SMALL_RESULT { $$= SELECT_SMALL_RESULT; }
| SQL_BIG_RESULT { $$= SELECT_BIG_RESULT; }
| SQL_BUFFER_RESULT { $$= OPTION_BUFFER_RESULT; }
| SQL_CALC_FOUND_ROWS {
push_warning(YYTHD, Sql_condition::SL_WARNING,
ER_WARN_DEPRECATED_SYNTAX,
ER_THD(YYTHD, ER_WARN_DEPRECATED_SQL_CALC_FOUND_ROWS));
$$= OPTION_FOUND_ROWS;
}
| ALL { $$= SELECT_ALL; }
;
select_item_list
select_item_list
语义组用于解析逗号分隔、任意数量的查询字段或通配符 *
。
PT_item_list
对象(item_list2
)select_item_list:
select_item_list ',' select_item
{
if ($1 == nullptr || $1->push_back($3))
MYSQL_YYABORT;
$$= $1;
$$->m_pos = @$;
}
| select_item
{
$$= NEW_PTN PT_select_item_list(@$);
if ($$ == nullptr || $$->push_back($1))
MYSQL_YYABORT;
}
| '*'
{
Item *item = NEW_PTN Item_asterisk(@$, nullptr, nullptr);
$$ = NEW_PTN PT_select_item_list(@$);
if ($$ == nullptr || item == nullptr || $$->push_back(item))
MYSQL_YYABORT;
}
;
select_item
select_item
语义组用于解析单个查询字段。
Item
类(item
),用于表示查询任何类型表达式的基类select_item:
table_wild { $$= $1; }
| expr select_alias
{
$$= NEW_PTN PTI_expr_with_alias(@$, $1, @1.cpp, to_lex_cstring($2));
}
;
table_wild
语义组用于解析ident.*
或ident.ident.*
,详见下文;
expr
语义组用于解析最高级的一般表达式,详见 MySQL 源码|72 - 语法解析(V2):一般表达式(expr);
select_alias
语义组用于解析可选的AS
关键字引导(可省略)别名子句,详见 MySQL 源码|45 - 语法解析(V2):通用函数。
table_wild
规则用于匹配 ident.*
或 ident.ident.*
的通配符名称expr
规则用于匹配一般表达式select_alias
规则用于匹配 AS
子句指定别名table_wild
规则table_wild
语义组用于解析 ident.*
或 ident.ident.*
。
Item
类(item
),用于表示查询任何类型表达式的基类table_wild:
ident '.' '*'
{
$$ = NEW_PTN Item_asterisk(@$, nullptr, $1.str);
}
| ident '.' ident '.' '*'
{
if (check_and_convert_db_name(&$1, false) != Ident_name_check::OK)
MYSQL_YYABORT;
auto schema_name = YYCLIENT_NO_SCHEMA ? nullptr : $1.str;
$$ = NEW_PTN Item_asterisk(@$, schema_name, $3.str);
}
;
ident
语义组用于解析标识符或任意未保留关键字,详见 MySQL 源码|41 - 语法解析(V2):标识符 IDENT。