PostgreSQL查询引擎——SELECT STATEMENTS SelectStmt

news2024/11/20 13:26:26
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;
}	     	 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/352340.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA线程池的使用

一、池化思想和JAVA线程池 池化是很重要的思想&#xff1b;池化的好处是提供缓冲和统一的管理。这个笔者在本人的数据库连接池的博客中已经提到过了&#xff08;JAVA常用数据库连接池_王者之路001的博客-CSDN博客 &#xff09;。 线程池是另一种池化思想的运用&#xff0c;把…

MySQL 派生表产生关联索引auto_key0导致SQL非常的慢

相同的SQL在maridb运行0.5秒&#xff0c;在MySQL8.0.26中运行要19秒 官方MySQL在处理子查时&#xff0c;优化器有个优化参数derived_merge&#xff0c;MySQL7开启添加&#xff0c;默认on.很多情况可以自动优化派生表&#xff0c;避免创建临时索引auto_key0和生成临时表数据做…

C++入门:函数重载

目录 一. 函数重载的概念和分类 1.1 什么是函数重载 1.2 函数重载的分类 1.3 关于函数重载的几点注意事项 二. C实现函数重载的底层逻辑&#xff08;为什么C可以实现函数重载而C语言不能&#xff09; 2.1 编译器编译程序的过程 2.2 为什么C可以实现函数重载而C语言不能 …

内网安装管家婆软件如何实现外网访问?内网穿透的几种方案教程

管家婆软件从网络架构上分两种版本&#xff1a;web&#xff08;浏览器http端口&#xff09;访问的版本和客户端&#xff08;211固定端口sqlserver数据库&#xff09;访问的版本。公司库管经常用仓库登录管家婆&#xff0c;一旦需要在公司外部登陆访问管家婆客户端&#xff0c;就…

微信中如何接入机器人才比较正常

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂。 前言 为什么会有这个话题?大家都知道最近有个AI机器人很火,那就是AI机器人,关于它的介绍,大家可以自行百度去,我这边就不多介绍了。 好多人嫌网页版玩的不过瘾,就把这个机器人接入到了QQ上,接入到了钉钉上,TG …

Go语言基础知识学习笔记

环境准备 下载安装Golang&#xff1a;https://golang.google.cn/dl/ 因为国外下载速度较慢&#xff0c;我们需要配置国内代理 # 开启包管理工具 go env -w GO111MODULEon # 设置代理 go env -w GOPROXYhttps://goproxy.cn,direct # 设置不走 proxy 的私有仓库&#xff0c;多…

Ajax?阿贾克斯?

一、Ajax简介 AJAX Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 AJAX 不是新的编程语言&#xff0c;而是一种使用现有标准的创新方法。 AJAX 最大的优点是在不重新加载整个页面的情况下&#xff0c;可以与服务器交换数据并更新部分网…

供应链挑战迎刃而解!桑迪亚国家实验室使出“量子杀手锏”

桑迪亚国家实验室的科学家Alicia Magann&#xff08;右&#xff09;&#xff0c;Kenneth Rudinger&#xff08;左上&#xff09;&#xff0c;Mohan Sarovar&#xff08;左下&#xff09;和Matthew Grace&#xff08;未附图&#xff09;开发了基于反馈的量子优化算法&#xff08…

“太极”如何利用混部资源,助力腾讯广告降本增效

编者按&#xff1a;近年来&#xff0c; 随着大模型在NLP领域横扫各种大数据磅单取得巨大成功之后&#xff0c;大数据加大模型成为了AI领域建模的标准范式。搜索、广告、推荐的建模也不例外&#xff0c;动辄千亿参数&#xff0c;上T大小的模型成为各大预估场景的标配&#xff0c…

人脸识别——景联文科技提供3D头模数据采集业务!

“拿起手机刷脸解锁、上下班考勤、支付订单&#xff0c;刷脸已极大地便利了我们的生活。清华大学新闻学院教授沈阳表示&#xff0c;中国人平均每天要暴露在各种摄像头下超过500次。人脸识别已成了我们生活中重要的一部分。由于2D人脸识别容易受到姿态、表情、光照等因素影响&am…

痛苦面具,140天备战阿里巴巴,一个疏忽让我前功尽弃...

面试是走的内推途径&#xff0c;因为内推的简历通过率远高于其他方式;我的内推的途径有&#xff1a;联系我在字节跳动工作的一个大学学长。 在线面试&#xff0c;有个线上文本编辑器&#xff0c;类似leetcode那种&#xff0c;可以在线编程。然而有点紧张&#xff0c;视频面试网…

C#开发的OpenRA游戏加载界面的实现

C#开发的OpenRA游戏加载界面的实现 游戏的UI是一个游戏必备, 但是游戏的UI都是自己处理的,不能使用像Windows自带的UI。 这样游戏的UI,其实也是使用游戏的方式来显示的, 只不过使用了低帧率的方式来显示。 比如OpenRA游戏界面,就会显示如下: 游戏的界面有很多,先从一个简…

2023美赛F题全部代码+数据+结果 数学建模

2023年美赛F题全部思路 数据代码都已完成 全部内容见链接&#xff1a;https://www.jdmm.cc/file/2708700/ 1.根据文献选的GGDP的指标&#xff0c;发现GGDP与水资源等有关&#xff0c;由此可以筛选出影响GGDP的所有因子&#xff0c;并可以用所有因子利用层次分析法建立评价体…

小白指南:手把手教你用低代码开发一个应用页面

一、什么是低代码开发 在了解低代码开发之前&#xff0c;我们先看看使用低代码开发的效果。 低代码开发效果示例 低代码开发是DevEco Studio为HarmonyOS开发者提供的可视化页面的开发方式&#xff0c;具备丰富的UI页面编辑能力&#xff0c;开发者可以在图形化的用户界面上自由拖…

项目质量要怎么保持? 如何借助系统软件进行管理

对于任何项目型的企业总是很关心项目成本的话题&#xff0c;但不知从什么时候开始&#xff0c;高质量等于高成本成了各个企业的一种潜意识。 如果交付的项目产品不符合质量标准&#xff0c;即使企业使用最好的项目管理工具或者每个里程碑都达到并在预算范围内完成项目&#xf…

基于springboot的餐饮管理系统

摘 要本设计以真实场景的菜品信息及相关餐桌预定为设计依据&#xff0c;结合了餐饮管理系统的需求及反映的问题&#xff0c;对系统做出合理的需求分析和界面设计。同时本系统使用了JAVA语言、Springboot框架以及MYSQL作为后台数据库进行开发。从系统描述、系统设计及系统实现等…

【Kubernetes】第二篇 - 购买阿里云 ECS 实例

一&#xff0c;前言 上一篇&#xff0c;简单介绍了 CI/CD 的概念以及 ECS 服务规划&#xff0c;搭建整套服务需要三台服务器&#xff0c;配置如下&#xff1a; ECS 配置启动服务说明2核4GJenkins Nexus Dockerci-server2核4GDocker Kubernetesk8s-master1核1GDocker Kube…

Outcome VS. Output:研发效能提升中,谁会更胜一筹?

2007 年&#xff0c;网景通信公司&#xff08;Netscape&#xff09;的联合创始人 Marc Andreessen 在博客 The Pmarca Guide to Startups 中提出 「Product/Market Fit」 &#xff0c;他写道&#xff0c; 「这意味着在一个良好的市场中&#xff0c;拥有能够满足该市场的产品。」…

SYN480R 解码

目录1.空载情况下2.当有按键被按下3.数据帧分析4.同步码5.数据码6.对24位数据帧分析1.空载情况下 在空载情况下&#xff0c;syn480r 输出引脚&#xff0c;输出的是杂乱无序的波形 2.当有按键被按下 按下按键&#xff0c;会连续输出相同的脉冲波形&#xff0c;放大分析 3.数据…

ParallelsDesktop安装【亲测可行】

我这边安装的是macos最新系统 (Ventura13.2) 本文参考这篇文章安装&#xff0c;但是你完全按照这篇文章会报错&#xff0c;具体可行操作记录如下 一、下载软件和补丁 1、点这里去下载补丁18.0.1 2、点这里去下载对应版本的ParallelsDesktop18.0.1&#xff0c;安装上到试用这里…