SelectStmt: select_no_parens %prec UMINUS
| select_with_parens %prec UMINUS
select_with_parens:
'(' select_no_parens ')' { $$ = $2; }
| '(' select_with_parens ')' { $$ = $2; }
复制
该规则返回单个SelectStmt节点或它们的树,表示集合操作树(set-operation tree)。The rule returns either a single SelectStmt node or a tree of them, representing a set-operation tree. 当sub-SELECT位于a_expr内并且有多余的括号时,会出现歧义:括号是属于子SELECT还是属于周围的a_exp?我们不在乎,但bison想知道。There is an ambiguity when a sub-SELECT is within an a_expr and there are excess parentheses: do the parentheses belong to the sub-SELECT or to the surrounding a_expr? We don’t really care, but bison wants to know. 为了解决歧义,我们会谨慎地定义语法,以便尽可能长时间地推迟决策:只要我们能继续在sub-SELECT中吸收括号,我们就会这样做,只有当不再可能这样做时,我们才会决定括号属于表达式。To resolve the ambiguity, we are careful to define the grammar so that the decision is staved off as long as possible: as long as we can keep absorbing parentheses into the sub-SELECT, we will do so, and only when it’s no longer possible to do that will we decide that parens belong to the expression. 例如,在“SELECT(((SELECT 2))+3)”中,额外的括号被视为sub-select的一部分。“SELECT (((SELECT 2)) UNION SELECT 2)”显示了这样做的必要性。如果我们将“((SELECT 2))”解析为a_expr,那么当我们看到UNION时再返回SELECT视点就太晚了。For example, in “SELECT (((SELECT 2)) + 3)” the extra parentheses are treated as part of the sub-select. The necessity of doing it that way is shown by “SELECT (((SELECT 2)) UNION SELECT 2)”. Had we parsed “((SELECT 2))” as an a_expr, it’d be too late to go back to the SELECT viewpoint when we see the UNION.
此方法通过定义一个非终端select_with_parens来实现,它表示至少有一个外层括号的select,并注意在表达式语法中使用select_wwith_parens,never ‘(’ SelectStmt ‘)’。然后我们将有shift-reduce冲突,我们可以解决这些冲突,以便始终将’(’ <select> ')'视为select_with_parens。为了解决冲突,与select_with_parens productions冲突的productions被手动赋予低于“)”优先级的优先级,从而确保我们移动“)”(然后减少为select_wwith_parens),而不是试图将内部<select>非终结符减少为其他值。我们使用UMINUS优先级,这是一个相当随意的选择。为了能够无歧义地定义select_with_parens本身,我们需要一个非终端select_no_parens,它表示一个没有最外层括号的select结构。这有点乏味,但它有效。在非表达式上下文中,我们使用SelectStmt,它可以表示带或不带外括号的SELECT。This approach is implemented by defining a nonterminal select_with_parens, which represents a SELECT with at least one outer layer of parentheses, and being careful to use select_with_parens, never ‘(’ SelectStmt ‘)’, in the expression grammar. We will then have shift-reduce conflicts which we can resolve in favor of always treating ‘(’ <select> ‘)’ as a select_with_parens. To resolve the conflicts, the productions that conflict with the select_with_parens productions are manually given precedences lower than the precedence of ‘)’, thereby ensuring that we shift ‘)’ (and then reduce to select_with_parens) rather than trying to reduce the inner nonterminal to something else. We use UMINUS precedence for this, which is a fairly arbitrary choice. To be able to define select_with_parens itself without ambiguity, we need a nonterminal select_no_parens that represents a SELECT structure with no outermost parentheses. This is a little bit tedious, but it works. In non-expression contexts, we use SelectStmt which can represent a SELECT with or without outer parentheses.
select_no_parens
simple_select
select_no_parens:
simple_select { $$ = $1; }
复制
此规则解析集合操作(set operations)中可能出现的SELECT语句,包括UNION、INTERSECT和EXCEPT。'(‘和’)‘可用于指定集合操作的顺序。如果没有’(‘和)’,我们希望操作按照此文件开头的优先级规范进行排序。与select_no_parens一样,simple_select不能有外括号,但可以有带括号的子句。This rule parses SELECT statements that can appear within set operations, including UNION, INTERSECT and EXCEPT. ‘(’ and ‘)’ can be used to specify the ordering of the set operations. Without ‘(’ and ‘)’ we want the operations to be ordered per the precedence specs at the head of this file. As with select_no_parens, simple_select cannot have outer parentheses, but can have parenthesized subclauses.
请注意,排序子句不能包含在此级别–SQL需要 Note that sort clauses cannot be included at this level — SQL requires
SELECT foo UNION SELECT bar ORDER BY baz
要解析为
(SELECT foo UNION SELECT bar) ORDER BY baz
而不是
SELECT foo UNION (SELECT bar ORDER BY baz)
对于WITH、for UPDATE和LIMIT也是如此。因此,这些子句被描述为select_no_parens生成的一部分,而不是simple_select。这并不限制功能,因为您可以在括号内重新引入这些子句。注意:只有最左边的组件SelectStmt应该具有INTO。然而,语法没有检查这一点;解析分析必须检查它。Likewise for WITH, FOR UPDATE and LIMIT. Therefore, those clauses are described as part of the select_no_parens production, not simple_select. This does not limit functionality, because you can reintroduce these clauses inside parentheses. NOTE: only the leftmost component SelectStmt should have INTO. However, this is not checked by the grammar; parse analysis must check it.
simple_select:
SELECT opt_all_clause
opt_target_list into_clause from_clause where_clause group_clause having_clause window_clause
{ SelectStmt *n = makeNode(SelectStmt);
n->targetList = $3; n->intoClause = $4; n->fromClause = $5; n->whereClause = $6; n->groupClause = $7; n->havingClause = $8; n->windowClause = $9;
$$ = (Node *)n;
}
| SELECT
distinct_clause target_list into_clause from_clause where_clause group_clause having_clause window_clause
{ SelectStmt *n = makeNode(SelectStmt);
n->distinctClause = $2; n->targetList = $3; n->intoClause = $4; n->fromClause = $5; n->whereClause = $6; n->groupClause = $7; n->havingClause = $8; n->windowClause = $9;
$$ = (Node *)n;
}
| values_clause { $$ = $1; }
| TABLE relation_expr * same as SELECT * FROM relation_expr */
{
ColumnRef *cr = makeNode(ColumnRef); cr->fields = list_make1(makeNode(A_Star)); cr->location = -1;
ResTarget *rt = makeNode(ResTarget); rt->name = NULL; rt->indirection = NIL; rt->val = (Node *)cr; rt->location = -1;
SelectStmt *n = makeNode(SelectStmt); n->targetList = list_make1(rt); n->fromClause = list_make1($2);
$$ = (Node *)n;
}
| select_clause UNION all_or_distinct select_clause 集合操作(set operations) UNION
{ $$ = makeSetOp(SETOP_UNION, $3, $1, $4); }
| select_clause INTERSECT all_or_distinct select_clause / 集合操作(set operations) SETOP_INTERSECT
{ $$ = makeSetOp(SETOP_INTERSECT, $3, $1, $4); }
| select_clause EXCEPT all_or_distinct select_clause // 集合操作(set operations) SETOP_EXCEPT
{ $$ = makeSetOp(SETOP_EXCEPT, $3, $1, $4); }
复制
insertSelectOptions
select_no_parens的其他规则主要是处理sort_clause、opt_sort_clause、select_limit、opt_select_limit、for_locking_clause、opt_for_locking_clause、with_clause等规则,使用insertSelectOptions函数将这些语句生成的节点插入到SelectStmt对应的成员中。
select_clause:
simple_select { $$ = $1; }
| select_with_parens { $$ = $1; }
select_no_parens:
select_clause sort_clause
{ insertSelectOptions((SelectStmt *) $1, $2, NIL, NULL, NULL, NULL, yyscanner); $$ = $1; }
| select_clause opt_sort_clause for_locking_clause opt_select_limit
{ insertSelectOptions((SelectStmt *) $1, $2, $3, list_nth($4, 0), list_nth($4, 1), NULL, yyscanner); $$ = $1; }
| select_clause opt_sort_clause select_limit opt_for_locking_clause
{ insertSelectOptions((SelectStmt *) $1, $2, $4, list_nth($3, 0), list_nth($3, 1), NULL, yyscanner); $$ = $1; }
| with_clause select_clause
{ insertSelectOptions((SelectStmt *) $2, NULL, NIL, NULL, NULL, $1, yyscanner); $$ = $2; }
| with_clause select_clause sort_clause
{ insertSelectOptions((SelectStmt *) $2, $3, NIL, NULL, NULL, $1, yyscanner); $$ = $2; }
| with_clause select_clause opt_sort_clause for_locking_clause opt_select_limit
{ insertSelectOptions((SelectStmt *) $2, $3, $4, list_nth($5, 0), list_nth($5, 1), $1, yyscanner); $$ = $2; }
| with_clause select_clause opt_sort_clause select_limit opt_for_locking_clause
{ insertSelectOptions((SelectStmt *) $2, $3, $5, list_nth($4, 0), list_nth($4, 1), $1, yyscanner); $$ = $2; }
复制
insertSelectOptions() Insert ORDER BY, etc into an already-constructed SelectStmt. This routine is just to avoid duplicating code in SelectStmt productions. 主要包含sortClause【ORDER BY】、lockingClause【FOR UPDATE | FOR NO KEY UPDATE | FOR SHARE | FOR KEY SHARE】、limitOffset、limitCount、withClause【WITH | WITH_LA | WITH RECURSIVE】子句结构体。
/* insertSelectOptions() Insert ORDER BY, etc into an already-constructed SelectStmt. This routine is just to avoid duplicating code in SelectStmt productions. */
static void insertSelectOptions(SelectStmt *stmt, List *sortClause, List *lockingClause, Node *limitOffset, Node *limitCount, WithClause *withClause, core_yyscan_t yyscanner) {
/* Tests here are to reject constructs like (SELECT foo ORDER BY bar) ORDER BY baz */
if (sortClause) { // 不允许多重ORDER BY
if (stmt->sortClause) ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple ORDER BY clauses not allowed"), parser_errposition(exprLocation((Node *) sortClause))));
stmt->sortClause = sortClause;
}
/* We can handle multiple locking clauses, though */
stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause);
if (limitOffset){ // 不允许多重OFFSET
if (stmt->limitOffset) ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg("multiple OFFSET clauses not allowed"),parser_errposition(exprLocation(limitOffset))));
stmt->limitOffset = limitOffset;
}
if (limitCount){ // 不允许多重LIMIT
if (stmt->limitCount) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple LIMIT clauses not allowed"), parser_errposition(exprLocation(limitCount))));
stmt->limitCount = limitCount;
}
if (withClause){ // 不允许多重WITH
if (stmt->withClause)
ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple WITH clauses not allowed"), parser_errposition(exprLocation((Node *) withClause))));
stmt->withClause = withClause;
}
}
复制
transformStmt
从如下transformStmt函数可以看出,对于SelectStmt的处理分为了三种情况:ValuesClause;集合操作(set operations)【select_clause UNION/INTERSECT/EXCEPT all_or_distinct select_clause】;其他正常SelectStmt。
Query *transformStmt(ParseState *pstate, Node *parseTree){
Query *result;
switch (nodeTag(parseTree)){
...
case T_SelectStmt:{
SelectStmt *n = (SelectStmt *) parseTree;
if (n->valuesLists)
result = transformValuesClause(pstate, n);
else if (n->op == SETOP_NONE)
result = transformSelectStmt(pstate, n);
else
result = transformSetOperationStmt(pstate, n);
}
break;
...
}
result->querySource = QSRC_ORIGINAL; /* Mark as original query until we learn differently */
result->canSetTag = true;
return result;
}
复制
欢迎关注微信公众号肥叔菌PostgreSQL数据库专栏:
PostgreSQL数据库守护进程——Postmaster总体流程
PostgreSQL数据库守护进程——读取控制文件
PostgreSQL数据库守护进程——RemovePgTempFiles删除临时文件
PostgreSQL数据库守护进程——RemovePromoteSignalFiles
PostgreSQL数据库信号处理——kill backend
PostgreSQL数据库PMsignal——后端进程\Postmaster信号通信
PostgreSQL数据库后端进程——inter-process latch
PostgreSQL数据库后端进程——监视postmaster death
PostgreSQL数据库后台进程——一等公民
PostgreSQL数据库后台进程——后台一等公民进程保活
PostgreSQL数据库头胎——后台一等公民进程StartupDataBase启动
PostgreSQL数据库头胎——后台一等公民进程StartupDataBase信号通知
PostgreSQL数据库头胎——StarupXLOG函数恢复模式和目标
PostgreSQL数据库状态pmState——PM_STARTUP状态
PostgreSQL数据库复制——Setting Up Asynchronous Replication
PostgreSQL数据库复制——后台一等公民进程WalReceiver启动函数
PostgreSQL数据库复制——后台一等公民进程WalReceiver获知连接
PostgreSQL数据库复制——后台一等公民进程WalReceiver&startup交互
PostgreSQL数据库复制——后台一等公民进程WalReceiver ready_to_display
PostgreSQL数据库复制——后台一等公民进程WalReceiver提取信息
PostgreSQL数据库复制——后台一等公民进程WalReceiver收发逻辑
PostgreSQL数据库复制——后台一等公民进程WalReceiver pg_stat_wal_receiver视图
PostgreSQL数据库复制——walsender后端启动
PostgreSQL数据库守护进程——后台二等公民进程第一波启动maybe_start_bgworkers
PostgreSQL数据库参数——简述GUC
PostgreSQL数据库网络层——libpq连接参数
PostgreSQL数据库动态共享内存管理器——dynamic shared memory segment
PostgreSQL数据库WAL——资源管理器RMGR
PostgreSQL数据库WAL——备机回放checkpoint WAL
PostgreSQL数据库事务系统——phenomena
PostgreSQL数据库统计信息——analyze命令
PostgreSQL数据库统计信息——analyze大致流程
PostgreSQL数据库统计信息——analyze执行函数
PostgreSQL数据库统计信息——查找继承子表find_all_inheritors
PostgreSQL数据库统计信息——analyze流程对不同表的处理
PostgreSQL数据库统计信息——examine_attribute单列预分析
PostgreSQL数据库统计信息——acquire_sample_rows采样函数
PostgreSQL数据库统计信息——acquire_inherited_sample_rows采样函数
PostgreSQL数据库统计信息——计算统计数据
PostgreSQL数据库统计信息——compute_scalar_stats计算统计数
PostgreSQL数据库统计信息——analyze统计信息收集
PostgreSQL数据库统计信息——统计信息系统表
PostgreSQL守护进程(Postmaster)——辅助进程PgStat主流程
PostgreSQL守护进程(Postmaster)——辅助进程PgStat统计消息
PostgreSQL数据库查询监控技术——pg_stat_activity简介
PostgreSQL查询引擎——编译调试
PostgreSQL查询引擎——SELECT STATEMENTS
PostgreSQL查询引擎——Transform Values Clause
PostgreSQL查询引擎——Transform Select
PostgreSQL查询引擎——Transform Set Operation
PostgreSQL查询引擎——select * from where = transform流程
PostgreSQL查询引擎——Productions Expressions Grammar之columnref
PostgreSQL查询引擎——Transform Expressions之columnref
PostgreSQL查询引擎——Productions Expressions Grammar之CaseExpr
PostgreSQL查询引擎——Productions Expressions Grammar之AexprConst
PostgreSQL查询引擎——Transform Expressions之const
PostgreSQL查询引擎——Productions Expressions Grammar之GROUPING
PostgreSQL查询引擎——Restricted Expressions Grammar之表达式类型强转
PostgreSQL查询引擎——Transform Expressions之TypeCast
PostgreSQL查询引擎——Restricted Expressions Grammar之运算符
PostgreSQL查询引擎——create table xxx(...)基础建表流程
PostgreSQL查询引擎——create table xxx(...)基础建表transformCreateStmt
PostgreSQL数据库查询执行——T_VariableSetStmt
PostgreSQL数据库查询执行——T_TransactionStmt
PostgreSQL数据库查询执行——Parallel Query
PostgreSQL数据库查询执行——SeqScan节点执行
PostgreSQL数据库查询执行——Using GDB To Trace Into a Parallel Worker Spawned By Postmaster During a Large Query
PostgreSQL数据库查询执行——Parallel SeqScan节点执行
PostgreSQL数据库可插拔存储引擎——pg_am系统表
PostgreSQL数据库可插拔存储引擎——Table Access Manager
PostgreSQL数据库可插拔存储引擎——GetTableAmRoutine函数
PostgreSQL数据库可插拔存储引擎——Table scan callbacks
PostgreSQL数据库HeapAM——TupleTableSlot类型
PostgreSQL数据库HeapAM——HeapAM Scan
PostgreSQL数据库HeapAM——HeapAM Parallel table scan
PostgreSQL数据库HeapAM——synchronized scan machinery
PostgreSQL数据库缓冲区管理器——概述
PostgreSQL数据库缓冲区管理器——本地缓冲区管理
PostgreSQL数据库缓冲区管理器——Shared Buffer Pool初始化
PostgreSQL数据库存储介质管理器——SMGR
PostgreSQL数据库存储介质管理器——磁盘管理器
PostgreSQL数据库目录——目录操作封装
PostgreSQL虚拟文件描述符VFD机制——FD LRU池
PostgreSQL虚拟文件描述符VFD机制——FD LRU池其他函数
PostgreSQL数据库FDW——The Internals of PostgreSQL
PostgreSQL数据库FDW——WIP PostgreSQL Sharding
PostgreSQL数据库FDW——Parquet S3 Foreign Data Wrapper
PostgreSQL数据库FDW——Parquet S3 ParquetReader类
PostgreSQL数据库FDW——Parquet S3 ReaderCacheEntry
PostgreSQL数据库FDW——Parquet S3 ParallelCoordinator
PostgreSQL数据库FDW——Parquet S3 DefaultParquetReader类
PostgreSQL数据库FDW——Parquet S3 CachingParquetReader类
PostgreSQL数据库FDW——Parquet S3 ParquetS3FdwExecutionState类
PostgreSQL数据库FDW——Parquet S3 MultifileMergeExecutionStateBaseS3类
PostgreSQL数据库FDW——Parquet S3 读取parquet文件用例
PostgreSQL数据库使用——between and以及日期的使用
PostgreSQL数据库使用——iRedMail定时备份数据库脚本
PostgreSQL数据库使用——iRedMail初始化数据库脚本
PostgreSQL数据库使用——iRedMail创建用户脚本
PostgreSQL数据库插件——定时任务pg_cron
PostgreSQL数据库故障分析——invalid byte sequence for encoding
ETCD、Zookeeper和Consul 分布式数据库的魔法银弹
PostgreSQL数据库高可用——patroni介绍[翻译]
PostgreSQL数据库高可用——patroni配置[翻译]
PostgreSQL数据库高可用——patroni REST API[翻译]
PostgreSQL数据库高可用——将独立集群转换为Patroni集群[翻译]
PostgreSQL数据库高可用——patroni源码学习
PostgreSQL数据库高可用——patroni源码学习——abstract_main
PostgreSQL数据库高可用——patroni源码AbstractPatroniDaemon类
PostgreSQL数据库高可用——patroni源码Patroni子类简介
PostgreSQL数据库高可用——patroni源码PatroniLogger类
PostgreSQL数据库高可用——patroni RestApiServer
PostgreSQL数据库高可用——patroni源码DCS类
PostgreSQL数据库高可用——patroni源码AbstractEtcd类
PostgreSQL数据库高可用——patroni源码EtcdClient类
PostgreSQL数据库高可用——patroni源码Etcd
PostgreSQL数据库高可用——patroni源码学习——Ha类概述
PostgreSQL数据库高可用——Patroni AsyncExecutor类
PostgreSQL数据库高可用——Patroni PostmasterProcess类
PostgreSQL数据库备份恢复迁移——Barman Before you start[翻译]
PostgreSQL数据库备份恢复迁移——Barman Introduction[翻译]
Postgres-XL数据库GTM——概念
Postgres-XL数据库GTM——事务管理
Postgres-XL数据库GTM——GTM and Global Transaction Management[翻译]
Postgres-XL数据库GTM——Master & Standby启动流程
Postgres-XL数据库GTM——Master & Standby子线程
Postgres-XL数据库GTM——Node管理器
Greenplum数据库统计信息——analyze命令 Greenplum数据库统计信息——分布式采样 Greenplum数据库统计信息——auto-analyze特性 Greenplum数据库Hash分布——计算哈希值和映射segment Greenplum数据库Hash分布——GUC gp_use_legacy_hashops Greenplum数据库数据分片策略Hash分布——执行器行为 Greenplum数据库过滤投影——ExecScan执行逻辑 Greenplum数据库外部表——Scan执行节点 Greenplum数据库外部表——fileam封装 Greenplum数据库外部表——external_getnext获取元组 Greenplum数据库外部表——url_curl创建销毁 Greenplum数据库外部协议——Define EXTPROTOCOL Greenplum数据库外部协议——GPHDFS实现协议 Greenplum数据库外部协议——GPHDFS gphdfs_fopen HashData数据库外部表——GPHDFS实现简介 Greenplum数据库高可用——FTS进程 Greenplum数据库高可用——FTS进程ftsConnect Greenplum数据库高可用——FTS进程触发轮询 Greenplum数据库高可用——FTS进程ftsPoll\Send\Receive Greenplum数据库高可用——FTS Pull模型 Greenplum数据库高可用——FTS HandleFtsWalRepProbe函数 Greenplum数据库高可用——FTS HandleFtsWalRepSyncRepOff函数 Greenplum数据库高可用——FTS HandleFtsWalRepPromote函数 Greenplum数据库高可用——FTS processRetry函数 Greenplum数据库高可用——FTS processResponse函数 Greenplum数据库高可用——FTS updateConfiguration更新系统表 Greenplum Python专用库gppylib学习——logging模块 Greenplum Python专用库gppylib学习——GpArray
Greenplum Python专用库gppylib学习——base.py
Greenplum Python工具库gpload学习——gpload类
Greenplum数据库源码分析——Standby Master操作工具分析
Greenplum数据库故障分析——利用GDB调试多线程core文件
Greenplum数据库故障分析——semop(id=,num=11) failed:invalid argument
Greenplum数据库故障分析——能对数据库base文件夹进行软连接嘛
Greenplum数据库故障分析——UDP Packet Lost(packet reassembles failed)
Greenplum数据库故障分析——版本升级后gpstart -a为何返回失败
Greenplum数据库故障分析——can not listen port
HAWQ数据库技术解析——内部架构
HAWQ数据库技术解析——filesystem interface
HAWQ数据库技术解析——HDFS filesystem
HAWQ数据库技术解析(一)——HAWQ简介[转载]