openGauss数据库Package原理分析FAQ

news2024/10/5 18:27:22

FAQ的形式分析OpenGauss中package实现基础关键逻辑。

下面四个问题基本将市面上基于postgresql实现package的方法分成了几类。

例如问题一:

  • openGauss使用包所在的namespace作为包函数的namespace。
  • IvorySQL使用包本身的oid作为包函数的namespace。
  • 还有db创建一个新的namespace作为包函数的namespace。

这里对openGauss的实现做一些分析和记录。

问题一:包函数使用谁的namespace?

结论

  1. 包函数的pronamespace直接使用包创建所在的namespace。
  2. 通过在pg_proc中新增列、并调整系统表约束来区分普通函数和包函数。
    • 其中opengaussdb新增了propackageid来指向当前函数所属的包。
    • 其中opengaussdb修改了原有约束,从三元组唯一约束(proname,proargtypes,pronamespace)变成了Oid唯一约束。
  3. 其他开源实现例如Ivorydb的方案也有不同,Ivorydb使用PkgID直接当做函数的namespace的oid使用,在使用时PkgID等价与一个NamespaceID。

列区别
在这里插入图片描述
约束区别
在这里插入图片描述

用例

create schema dams_ci;
create or replace package dams_ci.emp_bonus13 is
  var5 int:=42;
  var6 int:=43;
  procedure testpro1();
end emp_bonus13;
/
create or replace package body dams_ci.emp_bonus13 is
var1 int:=46;
var2 int:=47;
procedure testpro1()
is
begin
  raise notice 'testpro1 var5: %', var5;
  var5 := var5 + 1;
end;
end emp_bonus13;
/

openGauss=# select proname,pronamespace from pg_proc where proname = 'testpro1';
 proname  | pronamespace 
----------+--------------
 testpro1 |        16389
(1 row)

openGauss=# select * from pg_namespace where oid = 16389;
 nspname | nspowner | nsptimeline | nspacl | in_redistribution | nspblockchain | nspcollation 
---------+----------+-------------+--------+-------------------+---------------+--------------
 dams_ci |       10 |           0 |        | n                 | f             |             
(1 row)

问题二:包函数寻找的逻辑?

形如上述实例:

openGauss=# call dams_ci.emp_bonus13.testpro1();
NOTICE:  testpro1 var5: 42

在调用时使用了call a.b.c的形式,即call schema.pkgname.obj,在实际使用中,也会使用到aa.ba.b.c.d的形式,所有.的解析都集中在DeconstructQualifiedName函数中,总结OpenGaussdb的解析逻辑:
在这里插入图片描述

code

void DeconstructQualifiedName(const List* names, char** nspname_p, char** objname_p, char **pkgname_p)
{
    char* catalogname = NULL;
    char* schemaname = NULL;
    char* objname = NULL;
    char* pkgname = NULL;
    Oid nspoid = InvalidOid;
    switch (list_length(names)) {
        case 1:
            objname = strVal(linitial(names));
            break;

		// a.b的场景
        case 2:
            objname = strVal(lsecond(names));
            schemaname = strVal(linitial(names));
            if (nspname_p != NULL) {
                nspoid = get_namespace_oid(schemaname, true);
            }   
            pkgname = strVal(linitial(names));
            if (!OidIsValid(PackageNameGetOid(pkgname, nspoid))) {
                pkgname = strVal(lsecond(names));
                if (OidIsValid(PackageNameGetOid(pkgname, nspoid))) {
                    schemaname = strVal(linitial(names));
                    objname = pkgname;
                    pkgname = NULL;
                } else {
                    pkgname = NULL;
                }
            } else {
                schemaname = NULL;
            }
            break;

		// a.b.c的场景
        case 3:
            objname = strVal(lthird(names));
            pkgname = strVal(lsecond(names));
            schemaname = strVal(linitial(names));
            if (nspname_p != NULL) {
                nspoid = get_namespace_oid(schemaname, true);
            }   
            if (!OidIsValid(PackageNameGetOid(pkgname, nspoid))) {
                catalogname = strVal(linitial(names));
                schemaname = strVal(lsecond(names));
                pkgname = NULL;
                break;
            }
            break;

		// a.b.c.d的场景,情况少比较简单
		// catalogname是库名,pg特有的叫法
        case 4:
            catalogname = strVal(linitial(names));
            schemaname = strVal(lsecond(names));
            pkgname = strVal(lthird(names));
            objname = strVal(lfourth(names));
            /*
             * We check the catalog name and then ignore it.
             */
            if (strcmp(catalogname, get_and_check_db_name(u_sess->proc_cxt.MyDatabaseId, true)) != 0)
                ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        errmsg("cross-database references are not implemented: %s", NameListToString(names))));
            break;
        default:
            ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                    errmsg("improper qualified name (too many dotted names): %s", NameListToString(names))));
            break;
    }

    *nspname_p = schemaname;
    *objname_p = objname;
    if (pkgname_p != NULL)
        *pkgname_p = pkgname;
}

问题三:包SPEC变量编译的流程?

用例

create or replace package dams_ci.emp_bonus14 is
  var5 int:=42;
  var6 int:=43;
  procedure testpro1();
end emp_bonus14;
/

SPEC编译位置

注意pl_gram.y改名了,在这里src/common/pl/plpgsql/src/gram.y

CreatePackageCommand
	PackageSpecCreate
		PG_TRY
			plpgsql_package_validator(pkgOid, true, true)
				plpgsql_pkg_compile(packageOid, true, isSpec, isCreate)
					PG_TRY
						do_pkg_compile
							plpgsql_yyparse  // 开始编译 src/common/pl/plpgsql/src/gram.y
					PG_CATCH
					PG_END_TRY
		PG_CATCH
		PG_END_TRY

SPEC编译文本,注意和用例的差异
这是准本进入gram.y的文本。

PACKAGE  
DECLARE  
  var5 int:=42;
  var6 int:=43;
  procedure testpro1();
end

SPEC编译流程
src/common/pl/plpgsql/src/gram.y

pl_package_spec : K_PACKAGE { SetErrorState(); } decl_sect K_END

K_DECLARE → decl_start + decl_start → decl_sect

// 编译 var5 int:=42;
T_WORD → decl_varname → decl_varname_list -\
decl_const      ---------------------------|
decl_collate    ---------------------------|
decl_notnull    ---------------------------|
decl_defval    ----------------------------|
                                           v
                                    decl_statement 

编译完了,结果保存在curr_compile

curr_compile = 
{datums_alloc = 0, 
 datums_pkg_alloc = 256, plpgsql_nDatums = 0, 
 plpgsql_pkg_nDatums = 2, 
 datums_last = 2, 
 datums_pkg_last = 0, plpgsql_error_funcname = 0x0,
 plpgsql_error_pkgname = 0x7fb9fc9bbca8 "emp_bonus14", 
 plpgsql_parse_result = 0x0, 
 plpgsql_parse_error_result = 0x0, 
 plpgsql_Datums = 0x7fb9fc401e60, 
 plpgsql_curr_compile = 0x0,
 datum_need_free = 0x7fb9fc9989f0, 
 plpgsql_DumpExecTree = false, 
 plpgsql_pkg_DumpExecTree = false, 
 ns_top = 0x7fb9fbae3e88, 
 plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL,
 yyscanner = 0x0, 
 core_yy = 0x7fb9fbccfb78, 
 scanorig = 0x0, 
 plpgsql_yyleng = 0, 
 num_pushbacks = 0, 
 pushback_token = {0, 258, 0 <repeats 98 times>},
 cur_line_start = 0x7524070 "INSTANTIATION DECLARE BEGIN NULL; END", 
 cur_line_end = 0x0, 
 cur_line_num = 1, 
 goto_labels = 0x0, 
 plpgsql_check_syntax = false,
 plpgsql_curr_compile_package = 0x7fb9fc138f58,     <<<<<<<<<当前编译的包
 compile_tmp_cxt = 0x7fb9fbce7818, 
 compile_cxt = 0x7fb9fbae84b0}

然后把编出来的declare变量记录到pkg中,后面就可以使用了。

do_pkg_compile
  pkg->ndatums = curr_compile->plpgsql_pkg_nDatums;                                                 
  pkg->datums = (PLpgSQL_datum**)palloc(sizeof(PLpgSQL_datum*) * curr_compile->plpgsql_pkg_nDatums);
  pkg->datum_need_free = (bool*)palloc(sizeof(bool) * curr_compile->plpgsql_pkg_nDatums);           
  pkg->datums_alloc = pkg->ndatums;                                                                 

问题四:依赖包的编译如何实现?

用例

create schema dams_ci;
-- 被依赖包 emp_bonus14
create or replace package dams_ci.emp_bonus14 is
  var5 int:=42;
  var6 int:=43;
  procedure testpro1();
end emp_bonus14;
/

-- 依赖emp_bonus14的变量
create or replace package dams_ci.emp_bonus141231234 is
  var5 int:= dams_ci.emp_bonus14.var5;
  procedure testpro1();
end emp_bonus141231234;
/
create or replace package body dams_ci.emp_bonus141231234 is
  procedure testpro1()
  is
  begin
    raise notice 'testpro1 var5: %', var5;
  end;
end emp_bonus141231234;
/

call dams_ci.emp_bonus141231234.testpro1();

上述用例中,emp_bonus141231234包使用的变量var5的值从emp_bonus14包中获取,形成依赖关系。

在执行时编译emp_bonus141231234会处理依赖关系:

call dams_ci.emp_bonus141231234.testpro1()分析

plpgsql_call_handler
  PackageInstantiation
    plpgsql_package_validator
      plpgsql_pkg_compile
        do_pkg_compile
          plpgsql_yyparse
            read_sql_expression
              read_sql_construct
                read_sql_construct6
                  plpgsql_yylex
                    plpgsql_parse_tripword         // !!!这里解析 dams_ci.emp_bonus14.var5
                      plpgsql_pkg_add_unknown_var_to_namespace
                        GetPackageDatum
                          compilePackageSpec
                            plpgsql_package_validator
                              plpgsql_pkg_compile
                                do_pkg_compile     // !!!这里开始编译依赖包emp_bonus14
 
 
 *** *** ***
 
 do_pkg_compile这里会把emp_bonus14包拎出来变成字符串:
 PACKAGE  DECLARE  var5 int:=42;\n  var6 int:=43;\n  procedure testpro1();\nend 
 进入gram.y转一圈,出来就有变量和值了。

也是延迟编译的流程,用到谁编谁。

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

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

相关文章

微信小程序vue+nodejs校园快递物流取件及上门服务系统uniapp

系统分为用户和管理员两个角色 用户的主要功能有&#xff1a; 1.用户注册和登陆系统 2.用户查看系统的公告信息 3.用户在线快递下单&#xff0c;支付订单&#xff0c;在线订购快递取件 4.用户在线预约快递&#xff0c;填写快递预约信息 5.用户个人中心在线充值 6.用户个人中心修…

c++学习——概述、命名空间注意事项

C语言在c语言的基础上添加了面向对象编程和泛型编程的支持。 第一个helloworld #define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;//标准命名空间int main() {//cout是标准的输出流对象&#xff0c;打印字符串//endl是刷新缓冲区&#xff0c;…

软件详细设计总复习(一)【太原理工大学】

实验内容重点看&#xff0c;无需死记&#xff0c;它更是一种设计思想。要理解一种设计模式出现的意义是什么&#xff0c;它又是如何方便我们使用的&#xff1f;目的无非就是解耦、易扩充。题目问到优缺点&#xff0c;你只要知道该模式的设计思想就完全可以用自己的话概述&#…

chatgpt赋能Python-python3绘制图形

Python3绘制图形 – 让数据更加生动 作为一种可视化数据的工具&#xff0c;图形在数据分析和展示中扮演着重要的角色。Python3作为一种高效的编程语言&#xff0c;在图形方面也有自己的实现方式&#xff0c;让我们一起来了解Python3的图形绘制。 什么是Python3图形绘制&#…

chatgpt赋能Python-python3_取余

Python3 取余 在Python3中&#xff0c;取余运算是使用%符号进行实现的。它可以用于整数和浮点数&#xff0c;并返回一个余数。Python3是一种开放源码、高级编程语言。它是一种解释型语言&#xff0c;由于其简洁的语法和易于阅读的特性而受到广泛的欢迎。 取余基础 取余运算就…

ContOS7单机安装Hadoop

安装Hadoop 1&#xff0c;准备环节 因为Hadoop是由java编写的&#xff0c;所以需要Java的环境支持&#xff0c;作为开发者我们需要安装jdk。 安装jdk的教程http://t.csdn.cn/6qJKg 下载Hadoop的安装包 Hadoop官网&#xff1a;http://hadoop.apache.org/ Hadoop版本下载地…

【连续介质力学】张量的偏微分、球张量和偏张量

张量的偏微分 张量的一阶微分&#xff0c;定义&#xff1a; ∂ A ∂ A A , A ∂ A i j ∂ A k l ( e ^ i ⨂ e ^ j ⨂ e ^ k ⨂ e ^ l ) δ i k δ j l ( e ^ i ⨂ e ^ j ⨂ e ^ k ⨂ e ^ l ) I \frac{\partial A}{\partial A} A_{,A}\frac{\partial A_{ij}}{\partial A…

C++ map用法总结(整理)

1&#xff0c;map简介 map是STL的一个关联容器&#xff0c;它提供一对一的hash。 第一个可以称为关键字(key)&#xff0c;每个关键字只能在map中出现一次&#xff1b;第二个可能称为该关键字的值(value)&#xff1b; map以模板(泛型)方式实现&#xff0c;可以存储任意类型的…

算法26:暴力递归

目录 题目1&#xff1a;给你一个字符串&#xff0c;要求打印打印出这个字符串的全部子序列&#xff08;子序列不能重复&#xff09; 题目2&#xff1a;打印一个字符串的全部排列。 题目3&#xff1a;针对题目2&#xff0c;要求去除重复元素 题目4&#xff1a;给定一个字符串…

【靶机】vulnhub靶机billu

靶机下载地址&#xff1a;https://download.vulnhub.com/billu/Billu_b0x.zip 一、环境搭建 1.1 实验环境设计 使用vmware导入靶机&#xff0c;模式为nat模式即可&#xff0c;同时开启kali作为攻击机&#xff0c;对靶机进行渗透&#xff0c;要确定两台主机在同一网段。 Kali…

[Python从零到壹] 六十六.图像识别及经典案例篇之基于机器学习的图像分类

五月太忙&#xff0c;还是写一篇吧&#xff01; 欢迎大家来到“Python从零到壹”&#xff0c;在这里我将分享约200篇Python系列文章&#xff0c;带大家一起去学习和玩耍&#xff0c;看看Python这个有趣的世界。所有文章都将结合案例、代码和作者的经验讲解&#xff0c;真心想把…

opencv_c++学习(十五)

一、图像的模板匹配 顾名思义&#xff0c;模板匹配是在一幅图像中寻找一个相同或相似的对象&#xff0c;如上图所示。 matchTemplate(lnputArray image, lnputArray templ,OutputArray result, int method, lnputArray mask noArray())image:待模板匹配的原图像&#xff0c;图…

【Spring/MySQL数据库系列】数据库事务的特点与隔离级别

⭐️前面的话⭐️ 本文已经收录到《Spring框架全家桶系列》专栏&#xff0c;本文将介绍有关数据库事务的特点以及隔离级别。 &#x1f4d2;博客主页&#xff1a;未见花闻的博客主页 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4…

数值计算 - 利用机器计算的基本方式

离散化方法 设f(x)是定义在[a,b]上的连续函数&#xff0c;当它们的表达式很复杂&#xff0c;甚至写不出来时&#xff0c;我们可以选择若干个离散点 求出f(x)在这些点处的函数值或函数值的近似值 从而得到一个如下的函数值列表&#xff1a; ⚠️提示&#xff1a;对于一个实际的…

Android源码环境搭建

Android源码环境搭建 参考&#xff1a; Android源码环境搭建 1.安装Ubuntu16.4 系统 2.openjdk 8 的安装 sudo apt-get install openjdk-8-jdk使用java -version检查版本 3.安装所有的软件包 sudo apt-get install git-core gnupg flex bison gperf build-essential zip c…

Shell基础学习---3、Read读取控制台输入、函数、正则表达式入门

1、Read读取控制台输入 1、基本语法 read &#xff08;选项&#xff09; &#xff08;参数&#xff09; 选项说明-p指定读取值的提示符-t指定读取值等待的时间(秒) 如果-t不加表示一直等待 参数说明变量指定读取值的变量名 2、案例实操 2、函数 2.1 系统函数 2.1.1 bas…

【数据库】SQLServer报修表,维修表,反馈表三表连查

大家好&#xff0c;我是雷工&#xff01; 最近参与的一个SCADA项目&#xff0c;客户要求增加设备维保的功能&#xff0c;对设备的报修&#xff0c;维修&#xff0c;反馈过程进行记录查询&#xff0c;进一步提升企业的信息化能力。 该过程的实现是通过创建三个表分别记录报修-维…

uniapp 用css画五边形(app 小程序),长方形中间斜线分割成两部分

效果图 css .scoreLabel{ background: $yxs-theme-color; width: 64rpx; height: 69rpx; line-height: 32rpx; font-size: 28rpx; font-family: DINPro; f…

chatgpt赋能Python-python3_9安装scrapy

Python3.9安装Scrapy——加速数据抓取的利器 在现代数字化时代&#xff0c;数据抓取和数据挖掘的重要性越来越受到重视。作为一种高效的爬虫框架&#xff0c;Scrapy能够实现快速的页面抓取和数据解析&#xff0c;并帮助我们快速获取所需数据。本篇文章将会为大家介绍如何在Pyt…

【零基础学web前端】CSS学习,字体属性,文本属性,背景属性,圆角矩形属性

前言: 大家好,我是良辰丫,在上一篇文章中我们了解了CSS引入方式,CSS基础选择器,CSS复合选择器,今天我们继续学习CSS的相关知识点.&#x1f49e;&#x1f49e; &#x1f9d1;个人主页&#xff1a;良辰针不戳 &#x1f4d6;所属专栏&#xff1a;零基础学web前端 &#x1f34e;励志…