当前位置: 首页 > news >正文

PostgreSQL查询引擎——SELECT STATEMENTS SelectStmt

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 BYif (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){ // 不允许多重OFFSETif (stmt->limitOffset) ereport(ERROR,(errcode(ERRCODE_SYNTAX_ERROR),errmsg("multiple OFFSET clauses not allowed"),parser_errposition(exprLocation(limitOffset))));stmt->limitOffset = limitOffset;}if (limitCount){ // 不允许多重LIMITif (stmt->limitCount) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple LIMIT clauses not allowed"), parser_errposition(exprLocation(limitCount))));stmt->limitCount = limitCount;}if (withClause){ // 不允许多重WITHif (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);elseresult = transformSetOperationStmt(pstate, n);}break;   ...}	result->querySource = QSRC_ORIGINAL; /* Mark as original query until we learn differently */result->canSetTag = true;return result;
}	     	 

相关文章:

PostgreSQL查询引擎——SELECT STATEMENTS SelectStmt

SelectStmt: select_no_parens %prec UMINUS| select_with_parens %prec UMINUS select_with_parens:( select_no_parens ) { $$ $2; }| ( select_with_parens ) { $$ $2; } 该规则返回单个SelectStmt节点或它们的树&#xff0c;表示集合操作树(set-operation tree…...

零信任-易安联零信任介绍(11)

​目录 ​易安联零信任公司介绍 易安联零信任发展路线 易安联零信任产品介绍 易安联零信任架构 易安联零信任解决方案 易安联零信任发展展望 易安联零信任公司介绍 易安联是一家专业从事网络信息安全产品研发与销售&#xff0c;是行业内领先的“零信任”解决方案提供商&…...

C++ STL——map和set的使用

文章目录1. 关联式容器1.1 键值对1.2 树形结构的关联式容器2. set2.1 set的介绍2.2 set的插入2.3 set的删除和查找2.4 lower_bound和upper_bound3. multiset3.1 count4. map4.1 map的介绍4.2 map的插入4.3 map的遍历4.4 map的[ ]5. multimap1. 关联式容器 我们之前学的vector、…...

【Python】thread使用

目录1、Condition条件变量使用2、event通信3、Semaphore信号量使用4、setDaemon设置守护线程5、threadPool_map使用6、threadPool使用7、threadingTimer1、Condition条件变量使用 # encoding:utf-8 Condition 提供了一种多线程通信机制&#xff0c; 假如线程 1 需要数据&#…...

计网传输层协议:UDP和TCP

文章目录一. 应用层和传输层的联系二. UDP协议三. TCP协议1. TCP报头介绍2. TCP实现可靠传输的核心机制2.1 确认应答2.2 超时重传3. 连接管理(三次握手, 四次挥手)3.1 建立连接(三次握手)3.2 断开连接(四次挥手)4. 滑动窗口5. 流量控制6.拥塞控制7. 延时应答8. 捎带应答9. 面向…...

一文讲明TCP网络编程、Socket套接字的讲解使用、网络编程案例

文章目录1 Socket讲解2 基于Socket的TCP编程3 客户端Socket的工作过程包含以下四个基本的步骤3.1 客户端创建Socket对象4 服务器程序的工作过程包含以下四个基本的步骤&#xff1a;4.1 服务器建立ServerSocket对象5 案例实现 客户端和服务端通信5.1 代码实现5.2 实现结果6 更多…...

Java中print和println的区别

1 问题在最开始学习Java的时候学到soutenter键可以输出结果&#xff0c;显示的是System.out.println()&#xff1b;而在Python中是直接使用print。那么在Java中print和println有什么区别&#xff1f;2 方法Print输出会自动将括号中的内容转换成字符串输出&#xff0c;如果括号中…...

RocketMq使用规范(纯技术和实战建议)

概述&#xff1a; 使用规范主要从&#xff0c;生产、可靠性、和消费为轴线定义使用规范&#xff1b;kafka使用核心&#xff1a;削峰、解耦、向下游并行广播通知&#xff08;无可靠性保证&#xff09;和分布式事务&#xff0c;本规范仅从削峰、解耦、向下游并行广播通知论述&am…...

matlab离散系统仿真分析——电机

目录 1.电机模型 2.数字PID控制 3.MATLAB数字仿真分析 3.1matlab程序 3.2 仿真结果 4. SIMULINK仿真分析 4.1simulink模型 4.2仿真结果 1.电机模型 即&#xff1a; 其中&#xff1a;J 0.0067&#xff1b;B 0.10 2.数字PID控制 首先我们来看一下连续PID&#xff1…...

一文学会进程控制

目录进程的诞生fork函数fork的本质fork的常规用法fork调用失败的原因进程的死亡进程退出的场景常见的进程退出方法正常终止&#xff08;代码跑完&#xff09;echo $?main函数返回调用exit调用_exitexit和_exit的区别进程等待进程等待的重要性进程等待的函数waitwaitpid进程退出…...

5.2 BGP水平分割

5.2.2实验2&#xff1a;BGP水平分割 1. 实验目的 熟悉BGP水平分割的应用场景掌握BGP水平分割的配置方法 2. 实验拓扑 实验拓扑如图5-2所示&#xff1a; 图5-2&#xff1a;BGP水平分割 3. 实验步骤 &#xff08;1&#xff09;配置IP地址 R1的配置 <Huawei>…...

华为OD机试 - TLV 编码 | 备考思路,刷题要点,答疑 【新解法】

最近更新的博客 【新解法】华为OD机试 - 关联子串 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 停车场最大距离 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试 - 任务调度 | 备考思路,刷题要点,答疑,od Base 提供【新解法】华为OD机试…...

【C语言每日一题】——猜名次

【C语言每日一题】——猜名次&#x1f60e;前言&#x1f64c;猜名次&#x1f64c;解题思路分享&#xff1a;&#x1f60d;解题源码分享&#xff1a;&#x1f60d;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神…...

Agilent E4982A、Keysight E4982A、LCR 表,1 MHz 至 3 GHz

Agilent E4982A、Keysight E4982A、HP E4982A LCR 表&#xff0c;1 MHz 至 3 GHz 产品概览 KEYSIGHT E4982A&#xff08;安捷伦&#xff09; Keysight E4982A LCR 表为需要高频&#xff08;1 MHz 至 3 GHz&#xff09;阻抗测试的无源元件制造行业提供一流的性能&#xff0c…...

SAP 系统的配置传输

在SAP项目的实施过程中&#xff0c;经常会遇到关于配置传输的问题。即我们在某个client下面做系统配置&#xff0c;配好了之后再传到其他系统之中。 配置传输分为两种情况&#xff1a;同服务器配置传输&#xff0c;异服务器配置传输。同服务器配置传输&#xff1a; 在DEV配置cl…...

华为OD机试 - 喊七(Python)

喊七 题目 喊 7,是一个传统的聚会游戏, N 个人围成一圈,按顺时针从1 - 7编号, 编号为1的人从1开始喊数, 下一个人喊得数字是上一个人喊得数字+1, 但是当将要喊出数字7的倍数或者含有7的话, 不能喊出,而是要喊过。 假定N个人都没有失误。 当喊道数字k时, 可以统计每…...

Docker下快速搭建RabbitMQ单例及集群

引子生命在于折腾&#xff0c;为上数据实时化用到了消息传送的内容&#xff0c;当时也和总公司人员商量选型&#xff0c;kafka不能区分分公司就暂定用了RbtMQ刚好个人也在研究容器及分布式部署相关内容就在docker上实践单机 docker&#xff08;要想快 先看问题 避免踩坑&#x…...

python代码写开心消消乐

♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放,树高千尺,落叶归根人生不易,人间真情 目录 一.python是什么 二.游戏代码效果呈现 三.主代...

【郭东白架构课 模块一:生存法则】09|法则四:为什么要顺应技术的生命周期?

你好&#xff0c;我是郭东白。今天我们来讲架构师的第四条生存法则&#xff0c;那就是尊重技术的生命周期。 人类的各种活动都要遵循事物的客观生命周期。不论是农业社会种田打渔&#xff0c;还是资本社会投资创业&#xff0c;行动太早或太晚&#xff0c;都会颗粒无收。技术也…...

Linux之进程控制

一.进程创建 1.1 fork函数 我们创建进程的方式有./xxx和fork()两种 在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 #include <unistd.h> pid_t fork(void); 返回值&#xff1a;自进程…...

手把手教你搞定移远EC200U/EC25的Linux驱动:从硬件检查到串口映射的保姆级教程

手把手教你搞定移远EC200U/EC25的Linux驱动&#xff1a;从硬件检查到串口映射的保姆级教程 刚接触移远4G模块的开发者&#xff0c;往往会在Linux驱动适配环节遇到各种"坑"。本文将以EC200U和EC25为例&#xff0c;带你完整走通从硬件检查到功能稳定的全流程。不同于零…...

AI环境管理框架AEnvironment:解决多模型开发部署难题

1. 项目概述与核心价值最近在折腾一个挺有意思的项目&#xff0c;叫inclusionAI/AEnvironment。乍一看这个名字&#xff0c;可能有点抽象&#xff0c;但如果你正在做AI应用开发&#xff0c;特别是涉及到多模型、多环境、复杂依赖管理的场景&#xff0c;这个项目很可能就是你一直…...

不花一分钱,10分钟搞定,2026销售录音总结怎么写每月省18小时多拿18成单率

我测评过不下20款AI录音转写总结工具&#xff0c;针对销售做每月客户拜访录音总结这个场景&#xff0c;听脑AI是同类工具中最值得用的。不花一分钱就能上手核心功能&#xff0c;10分钟就能搞定过去大半天的活&#xff0c;我接触过的几十位销售朋友反馈&#xff0c;用了之后每月…...

EdgeChains:基于Java响应式编程构建生产级大语言模型应用框架

1. 项目概述&#xff1a;当大模型需要“记忆”与“逻辑”如果你最近在折腾大语言模型&#xff08;LLM&#xff09;的应用&#xff0c;比如想做个智能客服、文档问答或者知识库助手&#xff0c;大概率会遇到一个核心瓶颈&#xff1a;LLM本身是个“健忘症患者”&#xff0c;它无法…...

告别电脑轰鸣声:FanControl中文版让你的电脑安静如图书馆

告别电脑轰鸣声&#xff1a;FanControl中文版让你的电脑安静如图书馆 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending…...

基于WebRTC VAD与Web Audio API实现浏览器端智能音频闪避

1. 项目概述与核心价值最近在折腾一个本地音频处理的小工具&#xff0c;目标是实现一个能实时分析音频、自动调整音量的“智能耳机”。听起来是不是有点玄乎&#xff1f;其实核心就是一个基于WebRTC VAD&#xff08;语音活动检测&#xff09;和Web Audio API的JavaScript库&…...

降AI检测率用什么工具好?率零最低2元/千字,适合本科论文降AI!

一、前言&#xff1a;2026 年毕业必须通过aigc检测 2026年各高校对学术论文的AIGC疑似度的审查全面变严&#xff0c;均发布了具体AIGC检测报告和数值要求&#xff0c;211和985高校规定本科论文AI率要低于20%&#xff0c;硕士要求 AI 率不高于15%。普通高校一般要求AI率控制在 …...

校园小情书微信小程序源码 _ 社区小程序前后端开源 _ 校园表白墙交友小程序

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 校园小情书微信小程序源码 | 社区小程序前后端开源 | 校园表白墙交友小程序 功能&#xff1a; 表白墙 卖舍友 步数旅行 步数排行榜 情侣脸 漫画脸 个人主页 私信 站内消息 今日话题 评…...

魔兽世界API与宏命令工具:提升游戏体验的终极解决方案

魔兽世界API与宏命令工具&#xff1a;提升游戏体验的终极解决方案 【免费下载链接】wow_api Documents of wow API -- 魔兽世界API资料以及宏工具 项目地址: https://gitcode.com/gh_mirrors/wo/wow_api 在魔兽世界的广阔世界中&#xff0c;插件开发和宏命令是每位玩家提…...

在F1C100s上跑GBA游戏:手把手教你用Buildroot配置SDL和移植gpsp模拟器

在F1C100s上跑GBA游戏&#xff1a;手把手教你用Buildroot配置SDL和移植gpsp模拟器 复古游戏模拟器一直是嵌入式开发者的热门话题之一。全志F1C100s作为一款性价比极高的ARM9芯片&#xff0c;凭借其低功耗和丰富的接口资源&#xff0c;成为DIY游戏掌机的理想选择。本文将带你从零…...