PostgreSQL源码分析——CREATE SERVER

我们分析一下外部数据包装器中创建外部服务器的CREATE SERVER命令的实现源码。前面已经分析过很多DDL的语法实现。这里简单描述一下大致过程。

主流程如下所示:

exec_simple_query(query_string);
--> pg_parse_query(query_string);--> raw_parser(query_string, RAW_PARSE_DEFAULT);--> base_yyparse(yyscanner);
--> pg_analyze_and_rewrite_fixedparams(parsetree, query_string, NULL, 0, NULL);
--> pg_plan_queries(querytree_list, query_string,	CURSOR_OPT_PARALLEL_OK, NULL);
--> PortalStart(portal, NULL, 0, InvalidSnapshot);
--> PortalRun(portal, FETCH_ALL, true, true, receiver, receiver, &qc);--> standard_ProcessUtility(pstmt, queryString, readOnlyTree,context, params, queryEnv,	dest, qc);--> CreateForeignServer((CreateForeignServerStmt *) parsetree);--> table_open(ForeignServerRelationId, RowExclusiveLock);--> get_foreign_server_oid(stmt->servername, true);--> transformGenericOptions(ForeignServerRelationId, PointerGetDatum(NULL), stmt->options, fdw->fdwvalidator);--> CatalogTupleInsert(rel, tuple);--> table_close(rel, RowExclusiveLock);
--> PortalDrop(portal, false);
语法解析层面

gram.y语法定义:

/***************************************************		QUERY:*             CREATE SERVER name [TYPE] [VERSION] [OPTIONS]****************************************************/CreateForeignServerStmt: CREATE SERVER name opt_type opt_foreign_server_versionFOREIGN DATA_P WRAPPER name create_generic_options{CreateForeignServerStmt *n = makeNode(CreateForeignServerStmt);n->servername = $3;n->servertype = $4;n->version = $5;n->fdwname = $9;n->options = $10;n->if_not_exists = false;$$ = (Node *) n;}| CREATE SERVER IF_P NOT EXISTS name opt_type opt_foreign_server_versionFOREIGN DATA_P WRAPPER name create_generic_options{CreateForeignServerStmt *n = makeNode(CreateForeignServerStmt);n->servername = $6;n->servertype = $7;n->version = $8;n->fdwname = $12;n->options = $13;n->if_not_exists = true;$$ = (Node *) n;};opt_type:TYPE_P Sconst			{ $$ = $2; }| /*EMPTY*/				{ $$ = NULL; };foreign_server_version:VERSION_P Sconst		{ $$ = $2; }|	VERSION_P NULL_P		{ $$ = NULL; };opt_foreign_server_version:foreign_server_version	{ $$ = $1; }| /*EMPTY*/				{ $$ = NULL; };
create foreign server实现

下面是创建外部服务器的主要实现函数,核心就是向pg_foreign_server系统表中插入一条记录。

postgres=# select * from pg_foreign_server ;oid  |     srvname      | srvowner | srvfdw | srvtype | srvversion | srvacl |                    srvoptions                    
-------+------------------+----------+--------+---------+------------+--------+--------------------------------------------------16820 | s1               |       10 |  16811 |         |            |        | 16825 | foreign_pgserver |       10 |  16815 |         |            |        | {host=192.168.109.133,port=6432,dbname=postgres}
(2 rows)

具体实现如下:

  1. 需要现在外部服务器命名唯一,不能与已有名重复
  2. 解析options
/* Create a foreign server */
ObjectAddress CreateForeignServer(CreateForeignServerStmt *stmt)
{Relation	rel;Datum		srvoptions;Datum		values[Natts_pg_foreign_server];bool		nulls[Natts_pg_foreign_server];HeapTuple	tuple;Oid			srvId;Oid			ownerId;AclResult	aclresult;ObjectAddress myself;ObjectAddress referenced;ForeignDataWrapper *fdw;rel = table_open(ForeignServerRelationId, RowExclusiveLock);/* For now the owner cannot be specified on create. Use effective user ID. */ownerId = GetUserId();/* Check that there is no other foreign server by this name.  If there is* one, do nothing if IF NOT EXISTS was specified. */srvId = get_foreign_server_oid(stmt->servername, true);if (OidIsValid(srvId)){if (stmt->if_not_exists){/* If we are in an extension script, insist that the pre-existing* object be a member of the extension, to avoid security risks. */ObjectAddressSet(myself, ForeignServerRelationId, srvId);checkMembershipInCurrentExtension(&myself);/* OK to skip */ereport(NOTICE,(errcode(ERRCODE_DUPLICATE_OBJECT),errmsg("server \"%s\" already exists, skipping",stmt->servername)));table_close(rel, RowExclusiveLock);return InvalidObjectAddress;}elseereport(ERROR,(errcode(ERRCODE_DUPLICATE_OBJECT),errmsg("server \"%s\" already exists",stmt->servername)));}/* Check that the FDW exists and that we have USAGE on it. Also get the* actual FDW for option validation etc. */fdw = GetForeignDataWrapperByName(stmt->fdwname, false);aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);if (aclresult != ACLCHECK_OK)aclcheck_error(aclresult, OBJECT_FDW, fdw->fdwname);/* Insert tuple into pg_foreign_server. */memset(values, 0, sizeof(values));memset(nulls, false, sizeof(nulls));srvId = GetNewOidWithIndex(rel, ForeignServerOidIndexId, Anum_pg_foreign_server_oid);values[Anum_pg_foreign_server_oid - 1] = ObjectIdGetDatum(srvId);values[Anum_pg_foreign_server_srvname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);/* Add server type if supplied */if (stmt->servertype)values[Anum_pg_foreign_server_srvtype - 1] = CStringGetTextDatum(stmt->servertype);elsenulls[Anum_pg_foreign_server_srvtype - 1] = true;/* Add server version if supplied */if (stmt->version)values[Anum_pg_foreign_server_srvversion - 1] = CStringGetTextDatum(stmt->version);elsenulls[Anum_pg_foreign_server_srvversion - 1] = true;/* Start with a blank acl */nulls[Anum_pg_foreign_server_srvacl - 1] = true;/* Add server options */srvoptions = transformGenericOptions(ForeignServerRelationId, PointerGetDatum(NULL), stmt->options, fdw->fdwvalidator);if (PointerIsValid(DatumGetPointer(srvoptions)))values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;elsenulls[Anum_pg_foreign_server_srvoptions - 1] = true;tuple = heap_form_tuple(rel->rd_att, values, nulls);CatalogTupleInsert(rel, tuple);heap_freetuple(tuple);/* record dependencies */myself.classId = ForeignServerRelationId;myself.objectId = srvId;myself.objectSubId = 0;referenced.classId = ForeignDataWrapperRelationId;referenced.objectId = fdw->fdwid;referenced.objectSubId = 0;recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);/* dependency on extension */recordDependencyOnCurrentExtension(&myself, false);/* Post creation hook for new foreign server */InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);table_close(rel, RowExclusiveLock);return myself;
}
drop server的流程

drop server主流程如下:

exec_simple_query(query_string);
--> pg_parse_query(query_string);--> raw_parser(query_string, RAW_PARSE_DEFAULT);--> base_yyparse(yyscanner);
--> pg_analyze_and_rewrite_fixedparams(parsetree, query_string, NULL, 0, NULL);
--> pg_plan_queries(querytree_list, query_string,	CURSOR_OPT_PARALLEL_OK, NULL);
--> PortalStart(portal, NULL, 0, InvalidSnapshot);
--> PortalRun(portal, FETCH_ALL, true, true, receiver, receiver, &qc);--> standard_ProcessUtility(pstmt, queryString, readOnlyTree,context, params, queryEnv,	dest, qc);--> ExecDropStmt((DropStmt *) parsetree, isTopLevel);--> RemoveObjects(stmt);--> get_object_address(stmt->removeType, object, &relation, AccessExclusiveLock, stmt->missing_ok);--> get_object_address_unqualified(objtype, castNode(String, object), missing_ok);--> performMultipleDeletions(objects, stmt->behavior, 0);--> deleteObjectsInList(targetObjects, &depRel, flags);--> deleteOneObject(thisobj, depRel, flags);--> doDeletion(object, flags);--> DropObjectById(object);
--> PortalDrop(portal, false);
语法定义
DropStmt:  DROP drop_type_name name_list opt_drop_behavior{DropStmt *n = makeNode(DropStmt);n->removeType = $2;n->missing_ok = false;n->objects = $3;n->behavior = $4;n->concurrent = false;$$ = (Node *) n;}drop_type_name:ACCESS METHOD							{ $$ = OBJECT_ACCESS_METHOD; }| EVENT TRIGGER							{ $$ = OBJECT_EVENT_TRIGGER; }| EXTENSION								{ $$ = OBJECT_EXTENSION; }| FOREIGN DATA_P WRAPPER				{ $$ = OBJECT_FDW; }| opt_procedural LANGUAGE				{ $$ = OBJECT_LANGUAGE; }| PUBLICATION							{ $$ = OBJECT_PUBLICATION; }| SCHEMA								{ $$ = OBJECT_SCHEMA; }| SERVER								{ $$ = OBJECT_FOREIGN_SERVER; };opt_drop_behavior:CASCADE						{ $$ = DROP_CASCADE; }| RESTRICT					{ $$ = DROP_RESTRICT; }| /* EMPTY */				{ $$ = DROP_RESTRICT; /* default */ };

执行删除对象:

/** Drop one or more objects.** We don't currently handle all object types here.  Relations, for example,* require special handling, because (for example) indexes have additional* locking requirements.** We look up all the objects first, and then delete them in a single* performMultipleDeletions() call.  This avoids unnecessary DROP RESTRICT* errors if there are dependencies between them.*/
void RemoveObjects(DropStmt *stmt)
{ObjectAddresses *objects;ListCell   *cell1;objects = new_object_addresses();foreach(cell1, stmt->objects){ObjectAddress address;Node	   *object = lfirst(cell1);Relation	relation = NULL;Oid			namespaceId;/* Get an ObjectAddress for the object. */address = get_object_address(stmt->removeType,object,&relation,AccessExclusiveLock,stmt->missing_ok);/** Issue NOTICE if supplied object was not found.  Note this is only* relevant in the missing_ok case, because otherwise* get_object_address would have thrown an error.*/if (!OidIsValid(address.objectId)){Assert(stmt->missing_ok);does_not_exist_skipping(stmt->removeType, object);continue;}/** Although COMMENT ON FUNCTION, SECURITY LABEL ON FUNCTION, etc. are* happy to operate on an aggregate as on any other function, we have* historically not allowed this for DROP FUNCTION.*/if (stmt->removeType == OBJECT_FUNCTION){if (get_func_prokind(address.objectId) == PROKIND_AGGREGATE)ereport(ERROR,(errcode(ERRCODE_WRONG_OBJECT_TYPE),errmsg("\"%s\" is an aggregate function",NameListToString(castNode(ObjectWithArgs, object)->objname)),errhint("Use DROP AGGREGATE to drop aggregate functions.")));}/* Check permissions. */namespaceId = get_object_namespace(&address);if (!OidIsValid(namespaceId) ||!pg_namespace_ownercheck(namespaceId, GetUserId()))check_object_ownership(GetUserId(), stmt->removeType, address,object, relation);/** Make note if a temporary namespace has been accessed in this* transaction.*/if (OidIsValid(namespaceId) && isTempNamespace(namespaceId))MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;/* Release any relcache reference count, but keep lock until commit. */if (relation)table_close(relation, NoLock);add_exact_object_address(&address, objects);}/* Here we really delete them. */performMultipleDeletions(objects, stmt->behavior, 0);free_object_addresses(objects);
}

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

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

相关文章

Java基础 - 练习(二)打印菱形

Java基础练习 打印菱形&#xff0c;先上代码&#xff1a; // 方法一&#xff1a;基础&#xff0c;好理解 public static void diamond() {//控制行数for (int i 1; i < 4; i) {//空格的个数for (int k 1; k < 4 - i; k) {System.out.print(" ");}//控制星星…

使用Python连接MySQL数据库

1.导入包 import pymysql2.设置连接信息 pymsql中connect方法可以设置连接的信息 conn pymysql.connect(hostmHost, # 主机号port3306, # 端口号usermUser, # 用户名passwordmPwd, # 密码databasemDatabase # 数据库名称 )3.创建表 cursor()方法可以执行sql语句&…

如何构建构建一个AI驱动的通用爬虫

我最近开始研究网络爬虫&#xff0c;并且考虑到AI领域的一切发展&#xff0c;我认为尝试构建一个可以迭代导航网络直到找到它所寻找的内容的“通用”爬虫会很有趣。这是一个正在进行中的工作&#xff0c;但我想分享一下我目前的进展。 规格 给定一个起始URL和一个高级目标&…

vcruntime140_1.dll文件【安装包】【压缩包】【文件】【下载】

安装程序时有时候出现 类似无法启动程序&#xff0c;缺少vcruntime140_1.dll的提示&#xff0c;我们找到该文件并放到对应目录就可以&#xff1b;获取方法有很多&#xff0c;下面介绍两种&#xff1a;&#xff08;方法二更简便&#xff0c;不过建议两种方法都试试&#xff09; …

Swift开发——索引器扩展

扩展用于向已存在的类型(例如,类、结构体、枚举和协议等)中添加新的功能,扩展甚至可以向系统类型(包括无法查阅代码的类型)中添加新的功能,但是扩展不能覆盖原类型中已有的方法,扩展也不能向类中添加新的存储属性。 01、索引器扩展 扩展可为类、结构体等类型添加索引器。程序段…

golan的雪花id

今天记录一下 golang的雪花id golang的雪花id 还是比较简单的&#xff0c;其包含的含义以及组成我这就不讲了&#xff0c;好多大佬都有文章写过&#xff0c;我直接上怎么用 先 引入包 go get "github.com/bwmarrin/snowflake" 代码块 func main() {// 设置一个时…

单介子方程二十四

XXFXXdXuXWXπXXWXeXyXeXbXπXpXXVXXpXπXbXeXyXeXWXXπXWXuXdXXFXXEXyXαXiXXαXiXrXkXtXyXXpXVXXdXuXWXπXXWXeXyXeXbXπXpXXVXXpXπXbXeXyXeXWXXπXWXuXdXXVXpXXyXtXkXrXiXαXXiXαXyXEXXFXXEXyXαXiXXαXiXrXkXtXyXXpXVXXdXuXWXπXXWXeXyXeXbXπXpXXVXXpXπXbXeXyXeXWXXπX…

基于S32K144驱动NSD8308

文章目录 1.前言2.芯片介绍2.1 芯片简介2.2 硬件特性2.3 软件资源2.4 芯片资料 3.测试环境4.软件驱动4.1 SPI4.2 寄存器4.3 SPI ON/OFF控制4.4 PWM控制 5.测试情况 1.前言 最近有些客户在前期调试NSD8308时&#xff0c;软件上遇到一些问题&#xff0c;正好笔者手上有一套NSD83…

Linux---系统的初步学习【 项目三 磁盘管理与文件系统】

项目三 磁盘管理与文件系统 3.1 项目知识准备 3.1.1 硬盘 ​ 如果从存储数据的介质上来区分&#xff0c;硬盘可分为机械硬盘&#xff08;Hard Disk Dirve&#xff0c;HHD&#xff09;和固态硬盘&#xff08;Solid State Disk&#xff0c;SSD&#xff09;&#xff0c;机械硬盘…

[保姆级教程]uniapp实现页面路由配置

文章目录 新建目录新建页面配置页面路由修改tabBar地址其他&#xff1a;在package.json中的pages配置详细 新建目录 先点击src–》新建–》目录 输入名称&#xff0c;并以此类推完成所有新建目录 新建页面 右击目录&#xff0c;点击新建–》vue文件 弹出弹框&#xff0c;…

电路笔记 : 嘉立创EDA 导入、查找、设计管理器(快速寻找网络标签)功能+DRC错误检查和处理

导入功能 查找功能 可查找多种类型&#xff0c;如原件名称、网络标签等 设计管理器 图层查看 DRC错误 规则设置 线距问题 大多数PCB制造商能够可靠地生产5 mil间距的走线和间隙。这是一个常见的标准&#xff0c;适合大多数消费级和工业级电子产品。在5 mil以上的间距&#xff…

嵌入式中间件_3.嵌入式中间件的一般架构

根据嵌入式中间件的不同类型和其应用对象的不同&#xff0c;其架构也有所不同&#xff0c;通常嵌入式中间件没有统一的架构&#xff0c;这里仅仅列举两种中间件架构。 1.消息中间件 1.1消息中间件原理架构 消息中间件是消息传输过程中保存消息的一种容器。它将消息从它的源中…

科技的成就(六十)

559、汉明码 1950 年 4 月&#xff0c;著名的纠错码汉明码诞生。理查德汉明发布论文“Error Detecting and Error Correcting Codes”&#xff0c;提出汉明码。汉明码是一种线性纠错码&#xff0c;用于检测转移数据时发生的错误并予以修正&#xff0c;最多可以检测到 2 位错误或…

VirtualStudio配置QT开发环境

环境 VirtualStudio2022Qt5.12.10 安装msvc工具链&#xff08;这一步不是必须的&#xff09; 打开virtual studio&#xff0c;打开Virtual Studio Installer界面选择要安装的msvc版本&#xff0c;点击安装 安装VirtualStudio扩展 在线安装 打开virtual Studio&#xff0c;…

玄机平台流量特征分析-常见攻击事

前言 熟悉常见的攻击流量特征&#xff0c;我们就可以通过主机的一个流量情况来判断主机遭受了何种攻击。这里来看看玄机平台的一道题目。 步骤1.1 这里需要我们找出恶意扫描者&#xff0c;也就是黑客的ip。下载好附件之后用wiresharke打开&#xff0c;直接筛选http协议的流量…

手写精简版TinyHttpd项目(一)

前言&#xff1a; 我们在之前的TinyHttpd的精读(可以在首页去查看)中已经是基本的了解了显示一个网页的基本过程&#xff0c;那么我们学习后可以通过手写一个精简版的进行巩固下。 0.新工程的建立 我们也可以顺带复习下如何通过cmake在ubuntu下新建一个工程(记得提前下载cmake…

【前端面经】数组算法题解

目录 题目一&#xff1a;两数之和题目二&#xff1a;最长无重复字符子串题目三&#xff1a;合并两个有序数组题目四&#xff1a;寻找数组中的峰值 题目一&#xff1a;两数之和 描述&#xff1a;给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目…

MyBatis逆向工程和MyBatisX插件的使用

文章目录 1.ORM思维2.逆向工程3.MyBatisX插件的使用 1.ORM思维 ORM&#xff08;Object-Relational Mapping&#xff0c;对象-关系映射&#xff09;是一种将数据库和面向对象编程语言中的对象之间进行转换的技术。它将对象和关系数据库的概念进行映射&#xff0c;最后我们就可以…

MySQL数据库与基本操作(增删改查)

一、数据库的基本概念 数据库要学习的四个基本概念&#xff0c;主要是&#xff1a;数据、数据库系统、数据库、数据管理系统。数据&#xff08;Date&#xff09;是描述事物的记录&#xff0c;数据库系统&#xff08;DBS&#xff09;&#xff0c;数据库管理系统&#xff08;DBMS…

微信小程序,分享和反馈功能

<button type"primary" open-type"share">分享</button> <button type"primary" open-type"feedback">反馈</button>