PostgreSQL源码分析——视图查询重写

这里我们分析一下查询重写的过程,主要分析视图的查询重写的过程。通过以下语句进行分析:

create table t1(a int, b int);
insert into t1 values(1,1);
-- 创建视图
create view vt1 as select * from t1;
-- 查询
select * from vt1;
查询重写过程分析

select * from vt1生成一个抽象语法树SelectStmt。其中视图名vt1通过RangeVar节点表示。再由SelectStmt经由语义分析转为查询树Query
语法解析部分的源码主流程如下:

exec_simple_query
--> pg_parse_query--> raw_parser--> base_yyparse
--> pg_analyze_and_rewrite--> parse_analyze--> transformStmt--> transformFromClause--> transformFromClauseItem--> pg_rewrite_query--> QueryRewrite   // 查询重写,视图重写为子查询是在这里发生的。// Step 1: Apply all non-SELECT rules possibly getting 0 or many queries--> RewriteQuery// Step 2: Apply all the RIR rules on each query--> fireRIRrules--> ApplyRetrieveRule  // expand an ON SELECT rule--> fireRIRrules    // Recursively expand any view references inside the view./* Step 3: Determine which, if any, of the resulting queries is supposed to setthe command-result tag; and update the canSetTag fields accordingly. */
--> pg_plan_queries

视图定义的规则展开的关键函数为ApplyRetrieveRule,我们重点分析一下:

/* ApplyRetrieveRule - expand an ON SELECT rule*/
static Query *ApplyRetrieveRule(Query *parsetree, RewriteRule *rule, int rt_index, Relation relation, List *activeRIRs)
{Query	   *rule_action;RangeTblEntry *rte, *subrte;RowMarkClause *rc;// .../** Make a modifiable copy of the view query, and acquire needed locks on* the relations it mentions.  Force at least RowShareLock for all such* rels if there's a FOR [KEY] UPDATE/SHARE clause affecting this view.*/rule_action = copyObject(linitial(rule->actions));AcquireRewriteLocks(rule_action, true, (rc != NULL));/** Recursively expand any view references inside the view.** Note: this must happen after markQueryForLocking.  That way, any UPDATE* permission bits needed for sub-views are initially applied to their* RTE_RELATION RTEs by markQueryForLocking, and then transferred to their* OLD rangetable entries by the action below (in a recursive call of this* routine).*/rule_action = fireRIRrules(rule_action, activeRIRs);  // 规则应用/** Now, plug the view query in as a subselect, converting the relation's* original RTE to a subquery RTE.*/rte = rt_fetch(rt_index, parsetree->rtable);rte->rtekind = RTE_SUBQUERY;  // 视图会通过子查询进行替换,对应的就是由RTE_SUBQUERY替换掉原先的RTE_RELATIONrte->subquery = rule_action;rte->security_barrier = RelationIsSecurityView(relation);/* Clear fields that should not be set in a subquery RTE */rte->relid = InvalidOid;rte->relkind = 0;rte->rellockmode = 0;rte->tablesample = NULL;rte->inh = false;			/* must not be set for a subquery *//** We move the view's permission check data down to its rangetable. The* checks will actually be done against the OLD entry therein.*/subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);Assert(subrte->relid == relation->rd_id);subrte->requiredPerms = rte->requiredPerms;subrte->checkAsUser = rte->checkAsUser;subrte->selectedCols = rte->selectedCols;subrte->insertedCols = rte->insertedCols;subrte->updatedCols = rte->updatedCols;subrte->extraUpdatedCols = rte->extraUpdatedCols;// ...return parsetree;
}

可以看到,最核心的部分就是将RangeTblEntry由视图转换为子查询。

分析完源码,我们再回过头来研究一下其过程:
执行创建视图命令后create view vt1 as select * from t1;,向pg_rewrite系统表中插入了一套数据:

postgres@postgres=# select * from pg_rewrite order by oid desc limit 1;
oid        | 16390
rulename   | _RETURN
ev_class   | 16387   -- 视图vt1的表oid
ev_type    | 1
ev_enabled | O
is_instead | t       -- instead规则
ev_qual    | <>
ev_action  | ({QUERY :commandType 1 :querySource 0 :canSetTag true :utilityStmt <> :resultRelation 0 :hasAggs false :hasWindowFuncs false :hasTargetSRFs false :hasSubLinks false :hasDistinctOn false :hasRecursive false :hasModifyingCTE false :hasForUpdate false :hasRowSecurity false :cteList <> :rtable ({RTE :alias {ALIAS :aliasname old :colnames <>} :eref {ALIAS :aliasname old :colnames ("a" "b")} :rtekind 0 :relid 16387 :relkind v :rellockmode 1 :tablesample <> :lateral false :inh false :inFromCl false :requiredPerms 0 :checkAsUser 0 :selectedCols (b) :insertedCols (b) :updatedCols (b) :extraUpdatedCols (b) :securityQuals <>} {RTE :alias {ALIAS :aliasname new :colnames <>} :eref {ALIAS :aliasname new :colnames ("a" "b")} :rtekind 0 :relid 16387 :relkind v :rellockmode 1 :tablesample <> :lateral false :inh false :inFromCl false :requiredPerms 0 :checkAsUser 0 :selectedCols (b) :insertedCols (b) :updatedCols (b) :extraUpdatedCols (b) :securityQuals <>} {RTE :alias <> :eref {ALIAS :aliasname t1 :colnames ("a" "b")} :rtekind 0 :relid 16384 :relkind r :rellockmode 1 :tablesample <> :lateral false :inh true :inFromCl true :requiredPerms 2 :checkAsUser 0 :selectedCols (b 8 9) :insertedCols (b) :updatedCols (b) :extraUpdatedCols (b) :securityQuals <>}) :jointree {FROMEXPR :fromlist ({RANGETBLREF :rtindex 3}) :quals <>} :targetList ({TARGETENTRY :expr {VAR :varno 3 :varattno 1 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnosyn 3 :varattnosyn 1 :location 26} :resno 1 :resname a :ressortgroupref 0 :resorigtbl 16384 :resorigcol 1 :resjunk false} {TARGETENTRY :expr {VAR :varno 3 :varattno 2 :vartype 23 :vartypmod -1 :varcollid 0 :varlevelsup 0 :varnosyn 3 :varattnosyn 2 :location 26} :resno 2 :resname b :ressortgroupref 0 :resorigtbl 16384 :resorigcol 2 :resjunk false}) :override 0 :onConflict <> :returningList <> :groupClause <> :groupingSets <> :havingQual <> :windowClause <> :distinctClause <> :sortClause <> :limitOffset <> :limitCount <> :limitOption 0 :rowMarks <> :setOperations <> :constraintDeps <> :withCheckOptions <>})

建表以及创建视图后,会向pg_class系统表插入如下的信息。

postgres@postgres=# select oid,relname,relkind,relhasrules,relrewrite from pg_class where relname='vt1';
-[ RECORD 1 ]------
oid         | 16387     -- 表OID
relname     | vt1       -- 视图名  
relkind     | v         -- 表示视图
relhasrules | t         -- 表是否定义了规则
relrewrite  | 0postgres@postgres=# select oid,relname,relkind,relhasrules,relrewrite from pg_class where relname='t1';
-[ RECORD 1 ]------
oid         | 16384     -- 表OID
relname     | t1        -- 表名
relkind     | r         -- 表示是普通表
relhasrules | f         -- 表是否定义了规则
relrewrite  | 0

当执行select * from vt1时,先查pg_class系统表,找到表vt1类型为视图,同时该表定义了规则。查看pg_rewrite系统表,找到该表定义的规则的类型以及行为,应用规则。

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

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

相关文章

鸿蒙实战开发:网络层的艺术——优雅封装与搭建指南(下)

前言 在前两篇文章中,我们深入探讨了网络层的封装和优化技巧。本文将带您走进网络层的实战应用,从架构设计到具体实现,一步步指导您如何使用我们精心构建的网络框架。 一、网络层架构设计 在鸿蒙应用开发中,一个清晰、合理的网络层架构是保证项目可维护性和扩展性的关键…

发那科机器人IO 分配

IO 信号 也称为输入\输出信号&#xff0c;是机器人与外围设备通信的电信号

ROS 1的相机驱动代码迁移到ROS 2的方法

为了将ROS 1的相机驱动代码迁移到ROS 2&#xff0c;你需要对代码进行一系列的修改&#xff0c;包括但不限于更新消息类型、API调用和构建系统。 ### 步骤1&#xff1a;更新消息类型 - sensor_msgs/Image和cv_bridge在ROS 2中是可用的&#xff0c;但是确保你使用的是ROS 2版本的…

[CODE:-5504]没有[SYS.SYSOBJECTS]对象的查询权限

报错解释&#xff1a; 错误代码 [CODE:-5504] 表示用户尝试执行一个涉及到系统表 SYS.SYSOBJECTS 的查询&#xff0c;但是没有获得相应的查询权限。SYS.SYSOBJECTS 是一个系统表&#xff0c;包含了数据库中所有对象的信息&#xff0c;例如表、视图、存储过程等。 解决方法&am…

效率软件大盘点

Hey小伙伴们&#x1f495;&#xff01;知道你们都在追求高效工作生活&#xff0c;今天就来给大家种草五款超实用的国产工作App&#xff0c;让你的效率直线上升&#xff0c;再也不怕被工作追着跑啦&#xff01;&#x1f680; 1️⃣ 【亿可达】 - 软件连接器 &#x1f517; 作为…

电手出软件啦!各种姿势一键重装你的系统

电手的兄弟们你们好啊&#xff0c;很多兄弟都知道&#xff0c;我们老大傲梅是做软件的&#xff0c;例如大伙儿都用过的傲梅分区助手&#xff0c;还有傲梅轻松备份。相信不少兄弟都是用了分区助手才关注到电手的。 而我们电手&#xff0c;在电脑和手机玩机内容方面一直深耕。 跟…

Linux安装并配置Java

1、Linux操作系统安装Java 1.1、下载Java JDK解压包 官方提供的网址&#xff1a; 选择Linux版本 下载列表选择最后一项&#xff0c;通过解压方式安装 倒数第二项是以rpm方式进行安装&#xff0c;另一篇安装MySQL时就是用到rpm方法。 1.2、解压JDK tar -zxvf jdk-8u411-lin…

软件项目管理概述

1.什么是项目&#xff1f; 2.项目管理的定义 3.项目管理的本质 4.项目成功的标志 5.项目管理的基本方法 6.项目的生命周期&#xff08;启动 计划 执行 控制 结束&#xff09; 7.结合生活中的某件事&#xff0c;谈谈项目管理的作用 项目管理在日常生活中扮演着重要的角色&…

CP AUTOSAR标准之LargeDataCOM(AUTOSAR_CP_SWS_LargeDataCOM)

1 简介和功能概述 该规范描述了AUTOSAR基础软件模块LdCom的功能、API和配置。   在AUTOSAR分层架构中,AUTOSAR LdCom模块位于RTE/SwCluC_LdComProxy和PDU路由之间,参见[1,EXP LayeredSoftwareArchitecture]。   AUTOSAR LdCom模块提供了一种替代的交互层机制。通过专注于…

代码随想录算法训练营第二十七天|93.复原IP地址、 78.子集、90.子集II

93.复原IP地址 题目链接&#xff1a;93.复原IP地址 文档讲解&#xff1a;代码随想录 状态&#xff1a;还行&#xff0c;判断字符是否有效卡了好久 思路&#xff1a;通过回溯算法遍历所有可能的分割方式&#xff0c;每个IP地址段必须是0到255之间的整数且不能有前导零&#xff0…

Protobuf详解及入门指南

Protobuf详解及入门指南 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;在分布式系统和跨平台通信中&#xff0c;高效、轻量的序列化协议尤为重要。Google的Pro…

PyMuPDF 操作手册 - 01 从PDF中提取文本

文章目录 一、打开文件二、从 PDF 中提取文本2.1 文本基础操作2.2 文本进阶操作2.2.1 从任何文档中提取文本2.2.2 如何将文本提取为 Markdown2.2.3 如何从页面中提取键值对2.2.4 如何从矩形中提取文本2.2.5 如何以自然阅读顺序提取文本2.2.6 如何从文档中提取表格内容2.2.6.1 提…

MSPM0G3507——定时器简介和功能

分为两种定时器&#xff1a;通用定时器&#xff08;TIMG&#xff09;和高级控制定时器&#xff08;TIMA&#xff09; 在官方手册中可能还出现TIMX&#xff0c;这里TIMX指的是两者通用的功能。 TIMG概述: TIMG模块由16位和32位自动重新加载计数器组成&#xff0c;由可编程预分…

Python 开发者必看,用Flet库打造你的第一个Web应用

大家好&#xff0c;桌面应用程序开发一直是一个热门话题。在python中&#xff0c;使用Tkinter和wxPython虽然功能强大&#xff0c;但它们在现代UI设计和交互体验上显得有些力不从心。而Flet&#xff0c;作为一个新兴的Python库&#xff0c;以其现代化的设计理念和简洁的开发方式…

小程序wx.uploadFile异步问题

问题&#xff1a;小程序上传文件后我需要后端返回的一个值&#xff0c;但这个值总是在最后面导致需要这个值的方法总是报错&#xff0c;打印测试后发现这它是异步的。但直接使用 await来等待也不行。 uploadImg.wxml <view class"upload-wrap"><view clas…

【自撰写】【国际象棋入门】第4课 局面分析初步

第4课 局面分析初步 一、国际象棋的棋局阶段划分 随着对弈的进行&#xff0c;国际象棋棋局可以划分为3个阶段&#xff0c;分别是开局阶段、中局阶段和残局阶段。简单说来&#xff0c;开局阶段主要完成子力的出动和布局&#xff1b;中局阶段涉及到更多的子力协同配合和子力兑换…

镭速是如何做到传输中快速校验大文件的

在信息泛滥的当下&#xff0c;文件传输系统的效率与安全性成为企业和个人用户高度关注的焦点。传统上&#xff0c;文件传输依赖于如MD5或XXHash等单一的完整性校验机制。 然而&#xff0c;在多变的工作环境中&#xff0c;这些传统方法显得不够灵活。镭速&#xff0c;作为大文件…

PostgreSQL源码分析——创建分区表

分区表&#xff0c;可以认为是逻辑上一张表&#xff0c;但实际上是将逻辑上的一张表&#xff0c;分割为了多个物理表&#xff0c;每个物理表是逻辑表中的一部分&#xff0c;组合起来就是一张表。所以在实现分区表时&#xff0c;实际上是创建了多张物理表&#xff0c;但是逻辑上…

【神经网络】深度神经网络

深度神经网络&#xff08;Deep Neural Network&#xff0c;简称DNN&#xff09;是一种模仿人脑神经网络结构和工作原理的机器学习模型。它通过层级化的特征学习和权重调节&#xff0c;能够实现复杂任务的高性能解决方案。深度神经网络由多个神经元层组成&#xff0c;每个神经元…

【尚庭公寓SpringBoot + Vue 项目实战】后台用户信息管理(十七)

【尚庭公寓SpringBoot Vue 项目实战】后台用户信息管理&#xff08;十七&#xff09; 文章目录 【尚庭公寓SpringBoot Vue 项目实战】后台用户信息管理&#xff08;十七&#xff09;1、业务说明2、逻辑模型介绍3、接口开发3.1、根据条件分页查询后台用户列表3.2、根据ID查询后…