目录文档:MySQL 源码|源码剖析文档目录
源码位置(版本 = MySQL 8.0.37):sql/sql_yacc.yy
前置文档:
下面开始逐步梳理 DQL 语句 query_specification
规则中的各个组成部分,之前已经梳理了 ORDER BY
子句和 GROUP BY
子句,现在来看 FROM
子句和 JOIN
子句,在 opt_from_clause
规则中,同时匹配 FROM
子句和 JOIN
子句。
本节涉及相关关系如下图所示:其中绿色节点为本章节梳理,蓝色节点为之前章节已梳理,红色节点为后续章节梳理。
opt_from_clause
规则
MySQL 参考手册标准语法:[FROM table_references [PARTITION partition_list]]
,其中 table_references
为 tbl_name [[AS] alias] [index_hint]
【MySQL 参考手册 - 15.2.13 SELECT Statement】
opt_from_clause
规则匹配可选的 FROM
子句,Bison 语法如下:
opt_from_clause:
%empty %prec EMPTY_FROM_CLAUSE { $$.init(YYMEM_ROOT); }
| from_clause
;
from_clause
规则
from_clause
规则匹配 FROM
子句,包含 FROM
关键字和 from_tables
规则匹配结果,Bison 语法如下:
from_clause:
FROM from_tables { $$= $2; }
;
from_tables
规则
from_tables
规则匹配 DUAL
关键字或 table_reference_list
规则匹配结果,其中 DUAL
表示虚拟表,Bison 语法如下:
from_tables:
DUAL_SYM { $$.init(YYMEM_ROOT); }
| table_reference_list
;
table_reference_list
规则
table_reference_list
规则用于匹配逗号分隔的任意数量 table_refernce
规则匹配结果,Bison 语法如下:
table_reference_list:
table_reference
{
$$.init(YYMEM_ROOT);
if ($$.push_back($1))
MYSQL_YYABORT; // OOM
}
| table_reference_list ',' table_reference
{
$$= $1;
if ($$.push_back($3))
MYSQL_YYABORT; // OOM
}
;
table_reference
规则
table_reference
规则用于匹配查询的表或关联的表,有如下三种备选方案:
- 匹配
table_factor
规则匹配结果:用于匹配单个表 - 匹配
joined_table
规则匹配结果:用于匹配多表关联 - 依次匹配
{
、OJ
关键字、esc_table_reference
规则匹配结果和}
:其中esc_table_reference
规则匹配table_factor
规则匹配结果或joined_table
规则匹配结果
Bison 语法如下:
table_reference:
table_factor { $$= $1; }
| joined_table { $$= $1; }
| '{' OJ_SYM esc_table_reference '}'
{
/*
The ODBC escape syntax for Outer Join.
All productions from table_factor and joined_table can be escaped,
not only the '{LEFT | RIGHT} [OUTER] JOIN' syntax.
*/
$$ = $3;
}
;
esc_table_reference
规则
esc_table_reference
规则匹配 table_factor
规则匹配结果或 joined_table
规则匹配结果,Bison 语法如下:
esc_table_reference:
table_factor { $$= $1; }
| joined_table { $$= $1; }
;
joined_table
规则
joined_table
规则用于匹配多表关联,包含如下 6 种备选方案:
table_reference inner_join_type table_reference ON_SYM expr
:用于匹配使用ON
关键字指定关联规则的内关联子句- 其中
inner_join_type
规则匹配JOIN
、INNER JOIN
、CROSS JOIN
和STRAIGHT_JOIN
中的任意一个
- 其中
table_reference inner_join_type table_reference USING ( using_list )
:匹配使用USING
函数指定关联规则的内关联子句- 其中
using_list
规则匹配标识符的列表
- 其中
table_reference outer_join_type table_reference ON_SYM expr
:匹配使用ON
关键字指定关联规则的外关联子句- 其中
outer_join_type
规则匹配LEFT JOIN
、LEFT OUTER JOIN
、RIGHT JOIN
、RIGHT OUTER JOIN
中的任意一个
- 其中
table_reference outer_join_type table_reference USING ( using_list )
:匹配使用USING
函数指定关联规则的外关联子句table_reference inner_join_type table_reference
:匹配没有指定关联规则的内关联子句table_reference natural_join_type table_factor
:匹配没有指定关联规则的NATURAL
关联子句- 其中
natural_join_type
规则匹配NATURAL JOIN
、NATURAL INNER JOIN
、NATURAL LEFT JOIN
、NATURAL LEFT OUTER JOIN
、NATURAL RIGHT JOIN
、NATURAL RIGHT OUTER JOIN
中的任意一个
- 其中
Bison 语法如下:
joined_table:
table_reference inner_join_type table_reference ON_SYM expr
{
$$= NEW_PTN PT_joined_table_on(@$, $1, @2, $2, $3, $5);
}
| table_reference inner_join_type table_reference USING
'(' using_list ')'
{
$$= NEW_PTN PT_joined_table_using(@$, $1, @2, $2, $3, $6);
}
| table_reference outer_join_type table_reference ON_SYM expr
{
$$= NEW_PTN PT_joined_table_on(@$, $1, @2, $2, $3, $5);
}
| table_reference outer_join_type table_reference USING '(' using_list ')'
{
$$= NEW_PTN PT_joined_table_using(@$, $1, @2, $2, $3, $6);
}
| table_reference inner_join_type table_reference
%prec CONDITIONLESS_JOIN
{
auto this_cross_join= NEW_PTN PT_cross_join(@$, $1, @2, $2, nullptr);
if ($3 == nullptr)
MYSQL_YYABORT; // OOM
$$= $3->add_cross_join(this_cross_join);
}
| table_reference natural_join_type table_factor
{
$$= NEW_PTN PT_joined_table_using(@$, $1, @2, $2, $3);
}
;
inner_join_type
规则
inner_join_type
规则用于匹配 JOIN
、INNER JOIN
、CROSS JOIN
和 STRAIGHT_JOIN
中的任意一个,Bison 语法如下:
inner_join_type:
JOIN_SYM { $$= JTT_INNER; }
| INNER_SYM JOIN_SYM { $$= JTT_INNER; }
| CROSS JOIN_SYM { $$= JTT_INNER; }
| STRAIGHT_JOIN { $$= JTT_STRAIGHT_INNER; }
outer_join_type
规则
outer_join_type
规则用于匹配 LEFT JOIN
、LEFT OUTER JOIN
、RIGHT JOIN
、RIGHT OUTER JOIN
中的任意一个,其中 opt_outer
匹配可选的 OUTER
关键字,Bison 语法如下:
outer_join_type:
LEFT opt_outer JOIN_SYM { $$= JTT_LEFT; }
| RIGHT opt_outer JOIN_SYM { $$= JTT_RIGHT; }
;
natural_join_type
规则
natural_join_type
规则用于匹配 NATURAL JOIN
、NATURAL INNER JOIN
、NATURAL LEFT JOIN
、NATURAL LEFT OUTER JOIN
、NATURAL RIGHT JOIN
、NATURAL RIGHT OUTER JOIN
中的任意一个,其中 opt_inner
匹配可选的 INNER
关键字,opt_outer
匹配可选的 OUTER
关键字,Bison 语法如下:
natural_join_type:
NATURAL opt_inner JOIN_SYM { $$= JTT_NATURAL_INNER; }
| NATURAL RIGHT opt_outer JOIN_SYM { $$= JTT_NATURAL_RIGHT; }
| NATURAL LEFT opt_outer JOIN_SYM { $$= JTT_NATURAL_LEFT; }
;
opt_inner
规则
opt_inner
规则匹配可选的 INNER
关键字,Bison 规则如下:
opt_inner:
%empty
| INNER_SYM
;
opt_outer
规则
opt_outer
规则匹配可选的 OUTER
关键字,Bison 规则如下:
opt_outer:
%empty
| OUTER_SYM
;
using_list
规则
using_list
规则用于匹配标识符的列表,Bison 语法如下:
using_list:
ident_string_list
;
ident_string_list
规则
ident_string_list
规则用于匹配逗号分隔的任意数量标识符的列表,Bison 语法如下:
ident_string_list:
ident
{
$$= NEW_PTN List<String>;
String *s= NEW_PTN String(const_cast<const char *>($1.str),
$1.length,
system_charset_info);
if ($$ == nullptr || s == nullptr || $$->push_back(s))
MYSQL_YYABORT;
}
| ident_string_list ',' ident
{
String *s= NEW_PTN String(const_cast<const char *>($3.str),
$3.length,
system_charset_info);
if (s == nullptr || $1->push_back(s))
MYSQL_YYABORT;
$$= $1;
}
;
table_factor
规则
table_factor
规则用于匹配各种类型的表语句,包含如下 6 种备选方案:
single_table
规则匹配结果:用于匹配使用名称获取的单个表single_table_parens
规则匹配结果:用于匹配使用任意层括号框柱的single_table
规则匹配结果derived_table
规则匹配结果:用于匹配子查询生成的表joined_table_parens
规则匹配结果:用于匹配使用任意层括号框柱的joined_table
规则匹配结果table_reference_list_parens
规则匹配结果:用于匹配使用任意层括号框柱的,使用逗号分隔的table_reference
规则匹配结果table_function
规则匹配结果:用于匹配JSON_TABLE
函数
Bison 语法如下:
table_factor:
single_table
| single_table_parens
| derived_table { $$ = $1; }
| joined_table_parens
{ $$= NEW_PTN PT_table_factor_joined_table(@$, $1); }
| table_reference_list_parens
{ $$= NEW_PTN PT_table_reference_list_parens(@$, $1); }
| table_function { $$ = $1; }
;
single_table
规则
single_table
规则用于匹配使用名称获取的单个表,仅包含依次匹配 table_ident
规则匹配结果、opt_use_partition
规则匹配结果、opt_table_alias
规则匹配结果和 opt_key_definition
规则匹配结果这一种备选方案,其中:
table_ident
规则用于匹配ident
或ident.ident
,即包含与不包含 schema 的两种表名opt_use_partition
规则用于匹配可选的PARTITION
子句opt_table_alias
规则用于匹配可选的AS
子句用于指定别名opt_key_definition
规则用于匹配可选的USE
子句用于指定索引
Bison 语法如下:
single_table:
table_ident opt_use_partition opt_table_alias opt_key_definition
{
$$= NEW_PTN PT_table_factor_table_ident(@$, $1, $2, $3, $4);
}
;
table_ident
规则
table_ident
规则用于匹配 ident
或 ident.ident
,即包含与不包含 schema 的两种表名,Bison 语法如下:
table_ident:
ident
{
$$= NEW_PTN Table_ident(to_lex_cstring($1));
if ($$ == nullptr)
MYSQL_YYABORT;
}
| ident '.' ident
{
auto schema_name = YYCLIENT_NO_SCHEMA ? LEX_CSTRING{}
: to_lex_cstring($1.str);
$$= NEW_PTN Table_ident(schema_name, to_lex_cstring($3));
if ($$ == nullptr)
MYSQL_YYABORT;
}
;
opt_use_partition
规则
opt_use_partition
规则用于匹配可选的 PARTITION
子句,Bison 语法如下:
opt_use_partition:
%empty { $$= nullptr; }
| use_partition
;
use_partition
规则
use_partition
规则用于匹配 PARTITION
子句,Bison 语法如下:
use_partition:
PARTITION_SYM '(' using_list ')'
{
$$= $3;
}
;
opt_table_alias
规则
opt_table_alias
规则用于匹配可选的 AS
子句用于指定别名,其中 opt_as
规则用于匹配可选的 AS
关键字,Bison 语法如下:
opt_table_alias:
%empty { $$ = NULL_CSTR; }
| opt_as ident { $$ = to_lex_cstring($2); }
;
opt_as
规则
opt_as
规则用于匹配可选的 AS
关键字,Bison 语法如下:
opt_as:
%empty
| AS
;
opt_key_definition
规则
opt_key_definition
规则用于匹配可选的 USE
子句用于指定索引,Bison 语法如下:
opt_key_definition:
opt_index_hints_list
;
opt_index_hints_list
规则
opt_index_hints_list
规则用于匹配可选的 USE
子句用于指定索引,Bison 语法如下:
opt_index_hints_list:
%empty { $$= nullptr; }
| index_hints_list
;
index_hints_list
规则
index_hints_list
规则用于匹配空格分隔的任意数量的 USE
子句,Bison 语法如下:
index_hints_list:
index_hint_definition
| index_hints_list index_hint_definition
{
$2->concat($1);
$$= $2;
}
;
index_hint_definition
规则
index_hint_definition
规则用于匹配 USE
子句,有如下两种备选方案:
- 依次匹配
index_hint_type
规则匹配结果、key_or_index
规则匹配结果和index_hint_clause
规则匹配结果index_hint_type
规则用于匹配FORCE
关键字或IGNORE
关键字key_or_index
规则用于匹配KEY
关键字或INDEX
关键字index_hint_clause
规则用于匹配可选的FOR JOIN
、FOR ORDER BY
或FOR GROUP BY
- 依次匹配
USE
关键字、key_or_index
规则匹配结果和index_hint_clause
规则匹配结果
Bison 语法如下:
index_hint_definition:
index_hint_type key_or_index index_hint_clause
'(' key_usage_list ')'
{
init_index_hints($5, $1, $3);
$$= $5;
}
| USE_SYM key_or_index index_hint_clause
'(' opt_key_usage_list ')'
{
init_index_hints($5, INDEX_HINT_USE, $3);
$$= $5;
}
;
index_hint_type
规则
index_hint_type
规则用于匹配 FORCE
关键字或 IGNORE
关键字,Bison 语法如下:
index_hint_type:
FORCE_SYM { $$= INDEX_HINT_FORCE; }
| IGNORE_SYM { $$= INDEX_HINT_IGNORE; }
;
key_or_index
规则
key_or_index
规则用于匹配 KEY
关键字或 INDEX
关键字,Bison 语法如下:
key_or_index:
KEY_SYM {}
| INDEX_SYM {}
;
index_hint_clause
规则
index_hint_clause
规则用于匹配可选的 FOR JOIN
、FOR ORDER BY
或 FOR GROUP BY
,Bison 语法如下:
index_hint_clause:
%empty
{
$$= old_mode ? INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL;
}
| FOR_SYM JOIN_SYM { $$= INDEX_HINT_MASK_JOIN; }
| FOR_SYM ORDER_SYM BY { $$= INDEX_HINT_MASK_ORDER; }
| FOR_SYM GROUP_SYM BY { $$= INDEX_HINT_MASK_GROUP; }
;
single_table_parens
规则
single_table_parens
规则用于匹配使用任意层括号框柱的 single_table
规则匹配结果,Bison 语法如下:
single_table:
table_ident opt_use_partition opt_table_alias opt_key_definition
{
$$= NEW_PTN PT_table_factor_table_ident(@$, $1, $2, $3, $4);
}
;
joined_table_parens
规则
joined_table_parens
规则用于匹配使用任意层括号框柱的 joined_table
规则匹配结果,Bison 语法如下:
joined_table_parens:
'(' joined_table_parens ')' { $$= $2; }
| '(' joined_table ')' { $$= $2; }
;
table_reference_list_parens
规则
table_reference_list_parens
规则用于匹配使用任意层括号框柱的,使用逗号分隔的 table_reference
规则匹配结果,Bison 语法如下:
table_reference_list_parens:
'(' table_reference_list_parens ')' { $$= $2; }
| '(' table_reference_list ',' table_reference ')'
{
$$= $2;
if ($$.push_back($4))
MYSQL_YYABORT; // OOM
}
;
derived_table
规则
derived_table
规则用于匹配子查询生成的表,有如下两种备选方案:
- 依次匹配
table_subquery
规则匹配结果、opt_table_alias
规则匹配结果和opt_derived_column_list
规则匹配结果table_subquery
规则用于匹配多行子查询opt_table_alias
规则用于匹配可选的AS
子句指定别名opt_derived_column_list
规则用于匹配可选的括号框柱、逗号分隔的列名的列表
- 依次匹配
LATERAL
规则匹配结果、table_subquery
规则匹配结果、opt_table_alias
规则匹配结果和opt_derived_column_list
规则匹配结果`
Bison 语法如下:
derived_table:
table_subquery opt_table_alias opt_derived_column_list
{
/*
The alias is actually not optional at all, but being MySQL we
are friendly and give an informative error message instead of
just 'syntax error'.
*/
if ($2.str == nullptr)
my_message(ER_DERIVED_MUST_HAVE_ALIAS,
ER_THD(YYTHD, ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
$$= NEW_PTN PT_derived_table(@$, false, $1, $2, &$3);
}
| LATERAL_SYM table_subquery opt_table_alias opt_derived_column_list
{
if ($3.str == nullptr)
my_message(ER_DERIVED_MUST_HAVE_ALIAS,
ER_THD(YYTHD, ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
$$= NEW_PTN PT_derived_table(@$, true, $2, $3, &$4);
}
;
opt_derived_column_list
规则
opt_derived_column_list
规则用于匹配可选的括号框柱、逗号分隔的列名的列表,其中 simple_ident_list
规则用于匹配逗号分隔的任意数量标识符的列表,Bison 语法如下:
opt_derived_column_list:
%empty
{
/*
Because () isn't accepted by the rule of
simple_ident_list, we can use an empty array to
designates that the parenthesised list was omitted.
*/
$$.init(YYTHD->mem_root);
}
| '(' simple_ident_list ')'
{
$$= $2;
}
;
simple_ident_list
规则
simple_ident_list
规则用于匹配逗号分隔的任意数量标识符的列表,Bison 语法如下:
simple_ident_list:
ident
{
$$.init(YYTHD->mem_root);
if ($$.push_back(to_lex_cstring($1)))
MYSQL_YYABORT; /* purecov: inspected */
}
| simple_ident_list ',' ident
{
$$= $1;
if ($$.push_back(to_lex_cstring($3)))
MYSQL_YYABORT; /* purecov: inspected */
}
;
table_function
规则
table_function
规则用于匹配 JSON_TABLE
函数,详见 MySQL 参考手册 - 14.17.6 JSON Table Functions。标准语法如下:
JSON_TABLE(
expr,
path COLUMNS (column_list)
) [AS] alias
column_list:
column[, column][, ...]
column:
name FOR ORDINALITY
| name type PATH string path [on_empty] [on_error]
| name type EXISTS PATH string path
| NESTED [PATH] path COLUMNS (column_list)
on_empty:
{NULL | DEFAULT json_string | ERROR} ON EMPTY
on_error:
{NULL | DEFAULT json_string | ERROR} ON ERROR
只有依次匹配 JONS_TABLE
关键字,(
、text_literal
规则匹配结果(字符串字面值)、columns_clause
规则匹配结果、)
和 opt_table_alias
规则匹配结果(可选的 AS
子句指定别名)这一种备选方案,Bison 语法如下:
table_function:
JSON_TABLE_SYM '(' expr ',' text_literal columns_clause ')'
opt_table_alias
{
// Alias isn't optional, follow derived's behavior
if ($8 == NULL_CSTR)
{
my_message(ER_TF_MUST_HAVE_ALIAS,
ER_THD(YYTHD, ER_TF_MUST_HAVE_ALIAS), MYF(0));
MYSQL_YYABORT;
}
$$= NEW_PTN PT_table_factor_function(@$, $3, $5, $6, to_lex_string($8));
}
;
columns_clause
规则
columns_clause
规则用于如下匹配标准语法:
COLUMNS (column_list)
column_list:
column[, column][, ...]
column:
name FOR ORDINALITY
| name type PATH string path [on_empty] [on_error]
| name type EXISTS PATH string path
| NESTED [PATH] path COLUMNS (column_list)
on_empty:
{NULL | DEFAULT json_string | ERROR} ON EMPTY
on_error:
{NULL | DEFAULT json_string | ERROR} ON ERROR
只有依次匹配 COLUMNS
关键字、(
、columns_list
规则匹配结果和 )
这一种备选方案,Bison 语法如下:
columns_clause:
COLUMNS '(' columns_list ')'
{
$$= $3;
}
;
columns_list
规则
columns_list
规则用于匹配如下标准语法:
column[, column][, ...]
column:
name FOR ORDINALITY
| name type PATH string path [on_empty] [on_error]
| name type EXISTS PATH string path
| NESTED [PATH] path COLUMNS (column_list)
on_empty:
{NULL | DEFAULT json_string | ERROR} ON EMPTY
on_error:
{NULL | DEFAULT json_string | ERROR} ON ERROR
在 Bison 语法中匹配任意数量的逗号分隔的 jt_column
规则匹配结果,Bison 语法如下:
columns_list:
jt_column
{
$$= NEW_PTN Mem_root_array<PT_json_table_column *>(YYMEM_ROOT);
if ($$ == nullptr || $$->push_back($1))
MYSQL_YYABORT; // OOM
}
| columns_list ',' jt_column
{
$$= $1;
if ($$->push_back($3))
MYSQL_YYABORT; // OOM
}
;
jt_column
规则
jt_column
规则用于匹配如下标准语法:
name FOR ORDINALITY
| name type PATH string path [on_empty] [on_error]
| name type EXISTS PATH string path
| NESTED [PATH] path COLUMNS (column_list)
on_empty:
{NULL | DEFAULT json_string | ERROR} ON EMPTY
on_error:
{NULL | DEFAULT json_string | ERROR} ON ERROR
在 Bison 语法中包含 3 种备选方案:
ident FOR_SYM ORDINALITY_SYM
:用于匹配第 1 种标准语法ident type opt_collate jt_column_type PATH_SYM text_literal opt_on_empty_or_error_json_table
:用于匹配第 2 种和第 3 种标准语法type
规则用于匹配各种类型,稍后梳理opt_collate
规则用于匹配可选的排序规则jt_column_type
规则用于匹配可选的EXISTS
关键字text_literal
规则用于匹配字符串字面值opt_on_empty_or_error_json_table
规则用于依次匹配可选的ON EMPTY
子句和可选的ON ERROR
子句
NESTED_SYM PATH_SYM text_literal columns_clause
:用于匹配第 4 种标准语法
Bison 语法如下:
jt_column:
ident FOR_SYM ORDINALITY_SYM
{
$$= NEW_PTN PT_json_table_column_for_ordinality(@$, $1);
}
| ident type opt_collate jt_column_type PATH_SYM text_literal
opt_on_empty_or_error_json_table
{
auto column = make_unique_destroy_only<Json_table_column>(
YYMEM_ROOT, $4, $6, $7.error.type, $7.error.default_string,
$7.empty.type, $7.empty.default_string);
if (column == nullptr) MYSQL_YYABORT; // OOM
$$ = NEW_PTN PT_json_table_column_with_path(@$, std::move(column), $1,
$2, $3);
}
| NESTED_SYM PATH_SYM text_literal columns_clause
{
$$= NEW_PTN PT_json_table_column_with_nested_path(@$, $3, $4);
}
;
opt_collate
规则
opt_collate
规则用于匹配可选的排序规则,Bison 语法如下:
opt_collate:
%empty { $$ = nullptr; }
| COLLATE_SYM collation_name { $$ = $2; }
;
collation_name
规则
collation_name
规则用于匹配排序规则名称,Bison 语法如下:
collation_name:
ident_or_text
{
if (!($$= mysqld_collation_get_by_name($1.str)))
MYSQL_YYABORT;
YYLIP->warn_on_deprecated_collation($$);
}
| BINARY_SYM { $$= &my_charset_bin; }
;
jt_column_type
规则
jt_column_type
规则用于匹配可选的 EXISTS
关键字,Bison 语法如下:
jt_column_type:
%empty
{
$$= enum_jt_column::JTC_PATH;
}
| EXISTS
{
$$= enum_jt_column::JTC_EXISTS;
}
;
opt_on_empty_or_error_json_table
规则
opt_on_empty_or_error_json_table
规则用于依次匹配可选的 ON EMPTY
子句和可选的 ON ERROR
子句(当 ON_ERROR
在 ON EMPTY
之前时会抛出警告),其中 opt_on_empty_or_error
规则用于依次匹配可选的 ON EMPTY
子句和可选的 ON ERROR
子句。Bison 语法如下:
// JSON_TABLE extends the syntax by allowing ON ERROR to come before ON EMPTY.
opt_on_empty_or_error_json_table:
opt_on_empty_or_error { $$ = $1; }
| on_error on_empty
{
push_warning(
YYTHD, Sql_condition::SL_WARNING, ER_WARN_DEPRECATED_SYNTAX,
ER_THD(YYTHD, ER_WARN_DEPRECATED_JSON_TABLE_ON_ERROR_ON_EMPTY));
$$.error = $1;
$$.empty = $2;
}
;