【MogDB】MogDB5.2.0重磅发布第十篇-支持PLSQL嵌套子程序

一、前言

在ORACLE的PLSQL中,支持在procedure、function及匿名块中,嵌套定义procedure和function,编写这样的代码,算是一种低耦合高内聚的风格。在openGauss 6.0及之前的版本,并不支持嵌套子程序(预计7.0版本会支持),但通过实测,MogDB 5.2.0支持的场景比openGauss 7.0(截止到2024年12月19号的代码)要多。

二、什么是PLSQL嵌套子程序

plsql-subprograms

在ORACLE的官方文档里,将子程序分为三种,我简单描述一下

  • 独立子程序
    通过create procedure/function创建的程序单元
  • 包子程序
    存在于package对象内的procedure/function
  • 嵌套子程序
    在plsql块中声明的procedure/function

ORACLE风格的create function/procedure/package在openGauss 2.1版本都是支持的,也就是说,独立子程序以及包子程序早就已经支持,仅缺嵌套子程序。

对于plsql语言的procedure/function,本身就会具有一个plsql块,因此嵌套子程序可能出现在以下几种语法中

  • create procedure/function 的声明内,声明一个或多个procedure/function
  • package 内的procedure/function的声明内,声明一个或多个procedure/function
  • 匿名块的声明内,声明一个或多个procedure/function
  • 嵌套子程序内,声明一个或多个procedure/function

从语法上看,大概如下

declare
x int;
--子程序开始procedure a isbeginnull;end;
--子程序结束
begina;
end;

一般来说,declare…begin…end是一个plsql块的固定结构,只是在oracle语法的function/procedure中,可以省去declare这个关键字。由此我们可以发现,嵌套子程序是位于plsql块中,begin前面的一个声明,而plsql嵌套子程序本身也具有一个plsql块,因此仅从语法上看,嵌套子程序是可以无限套娃的,比如

declareprocedure a isprocedure b isprocedure c is beginnull;end;beginnull;end;beginnull;end;
begina;
end;

为什么特意提这一点?如果对语法没有敏感度,稍不注意,就很容易把这个功能做成仅支持一层嵌套。而openGauss到6.0也仍然不支持嵌套子程序,说明这个功能是具有相当的难度的,元数据放哪、怎么放、怎么记录嵌套关系、怎么解决重载问题、怎么解决生效范围的问题、怎么解决并发执行时的编译冲突问题、怎么管理缓存等等。如果没想明白这些问题,仅仅只是做一个形似的功能,很容易在实际的生产使用中出现各种奇奇怪怪的问题。

三、一些典型的使用场景

1、固定组合的长表达式

create procedure test_p is
function n2p(i number) return varchar2 
is
beginreturn to_char(i*100,'FM99999999999999999990.00')||'%';
end;
begininsert into t_test1 select a,b,n2p(c/e),n2p((d-e)/e),n2p(e) from t_test;
end;

以上例子常见于报表生成,经常会有需要将一个数值转换成百分比的形式,比如占比、增长率之类的,而数值转百分比的这个表达式有一点点长,如果要使用很多次,就会让代码显得很冗余而且很长。而且这个转换的格式还不一定在所有场景通用,所以可以只放在本procedure中,让这个procedure也不用依赖于其他逻辑对象。

2、框架化流程

CREATE TABLE doc_list (BIZ_TYPE VARCHAR2(3),DOC_NO VARCHAR2(200),STATUS VARCHAR2(1));CREATE OR REPLACE PACKAGE TEST_SUBPRO ASPROCEDURE biz_a(I_DOC_NO VARCHAR2); --业务A处理流程PROCEDURE biz_b(I_DOC_NO VARCHAR2); --业务B处理流程PROCEDURE main; --入口
END TEST_SUBPRO;
/CREATE OR REPLACE PACKAGE BODY TEST_SUBPRO ASPROCEDURE biz_a(I_DOC_NO VARCHAR2) IS--单据处理的开始过程PROCEDURE BEGIN_PRO(I_DOC_NO VARCHAR2) ISBEGINNULL;END;--单据处理的结束过程PROCEDURE END_PRO(I_DOC_NO VARCHAR2) ISBEGINNULL;END;BEGINBEGIN_PRO(I_DOC_NO);END_PRO(I_DOC_NO);END;PROCEDURE biz_b(I_DOC_NO VARCHAR2) IS--单据处理的开始过程PROCEDURE BEGIN_PRO(I_DOC_NO VARCHAR2) ISBEGINNULL;END;--单据处理的结束过程PROCEDURE END_PRO(I_DOC_NO VARCHAR2) ISBEGINNULL;END;BEGINBEGIN_PRO(I_DOC_NO);END_PRO(I_DOC_NO);END;PROCEDURE main ISBEGINFOR rec IN (SELECT * FROM doc_list WHERE status = 'N') LOOP--    根据所有未处理的单据,按不同的类型分别处理IF rec.biz_type = 'A' THENbiz_a(REC.doc_no);ELSIF rec.biz_type = 'B' THENbiz_a(REC.doc_no);END IF;END LOOP;END;
END TEST_SUBPRO;

以上模拟了一种通用业务流程处理框架,对于每一种业务,都有开始过程和结束过程(可能还有"预处理-处理-完成"形式的流程),但是每种业务自己分步的流程可能有些区别,不能共用。此处嵌套子程序的使用,能让每一种业务只需要有一个procedure暴露出来,程序结构清晰。

当然,嵌套子程序远不止这两种使用场景,此处只是列出最常见的两种。
只要嵌套子程序的功能是完整的,那么开发者就可以充分发挥自己的想象力来让自己的plsql代码更整洁易维护。

四、国产数据库比较

目前虽然有很多国产数据库也支持了PLSQL嵌套子程序,但是有些支持得并不完整,下面来做下对比

数据库是否支持在匿名块中使用是否支持在procedure中使用是否支持在function中使用是否支持在PACKAGE内的procedure中使用是否支持在PACKAGE内的function中使用是否支持在嵌套子程序内使用是否支持在PACKAGE内的不同procedure里重名是否支持在同一个procedure内重载是否正确处理内外层的重载关系是否正确处理和系统函数的重载关系是否支持前向声明支持百分比备注
DM8YYYYYYYYYYY100%
崖山 23.2.4YYYYYYYNYNN80%
OCEANBASE 4.1???????????文档有提支持嵌套子程序
KINGBASE 9YYYYYYYYYYY100%
POLARDB-O 2.0???????????文档有提支持嵌套子程序
TDSQL-PG(Oracle兼容版)???????????文档无相关描述
UXDB???????????文档无相关描述
神通(openGauss版)???????????无公开文档
海盒???????????无公开文档
瀚高 6.0.4???????????文档无相关描述
GAUSSDB 503.1.0.SPC1700NNNNNNNNNNN0%
OPENGAUSS 6.0NNNNNNNNNNN0%
OPENGAUSS 7.0(31ae9e8a 20241219)YYYNNNNYNYY50%基于2024年12月19号源码手动编译,非发布版本
GBASE 8cNNNNNNNNNNN0%
VASTBASE G100 V2.2 BUILD 16YYYYYNYYNYN70%
MogDB 5.2.0YYYYYYYYYYY100%

测试用例

--是否支持在匿名块中使用
declare
procedure a is 
begin
null;
end;
begin
a();
end;
/--是否支持在procedure中使用
create procedure test_p is
procedure a is 
beginnull;
end;
begin
a();
end;
/
call test_p();--是否支持在function中使用
create function test_f  return int is
procedure a is 
beginnull;
end;
begin
a();
return 1;
end;
/
select test_f() from dual;
--是否支持在PACKAGE内的procedure中使用
drop package TEST_PKG;
create package test_pkg is
procedure test_p;
end;
/
create package BODY test_pkg is
procedure test_p is
procedure a is 
beginnull;
end;
begin
a();
end;
end;
/call test_pkg.test_p();--是否支持在PACKAGE内的function中使用
create package test_pkg2 is
function test_f return int;
end;
/
create package BODY test_pkg2 is
function test_f return int is
procedure a is 
beginnull;
end;
begin
a();
return 1;
end;
end;
/
select test_pkg2.test_f() from DUAL;--是否支持在嵌套子程序内使用
declareprocedure a isprocedure b isprocedure c is beginnull;end;beginnull;end;beginnull;end;
begina;
end;
/--是否支持在PACKAGE内的不同procedure里重名
CREATE OR REPLACE PACKAGE TEST_SUBPRO ASPROCEDURE biz_a(I_DOC_NO VARCHAR2); PROCEDURE biz_b(I_DOC_NO VARCHAR2); PROCEDURE main(i_biz_type varchar2,I_DOC_NO VARCHAR2); 
END TEST_SUBPRO;
/CREATE OR REPLACE PACKAGE BODY TEST_SUBPRO ASPROCEDURE biz_a(I_DOC_NO VARCHAR2) ISPROCEDURE BEGIN_PRO(I_DOC_NO VARCHAR2) ISBEGINNULL;END;PROCEDURE END_PRO(I_DOC_NO VARCHAR2) ISBEGINNULL;END;BEGINBEGIN_PRO(I_DOC_NO);END_PRO(I_DOC_NO);END;PROCEDURE biz_b(I_DOC_NO VARCHAR2) IS--单据处理的开始过程PROCEDURE BEGIN_PRO(I_DOC_NO VARCHAR2) ISBEGINNULL;END;--单据处理的结束过程PROCEDURE END_PRO(I_DOC_NO VARCHAR2) ISBEGINNULL;END;BEGINBEGIN_PRO(I_DOC_NO);END_PRO(I_DOC_NO);END;PROCEDURE main(i_biz_type varchar2,I_DOC_NO VARCHAR2) ISBEGIN--    根据所有未处理的单据,按不同的类型分别处理IF i_biz_type = 'A' THENbiz_a(I_DOC_NO);ELSIF i_biz_type = 'B' THENbiz_a(I_DOC_NO);END IF;END;
END TEST_SUBPRO;
/--是否支持在同一个procedure内重载
create procedure test_p2 is
procedure p1 is
begindbms_output.put_line(1);
end;
procedure p1(a int) is
begindbms_output.put_line(2);
end;
beginp1();p1(1);dbms_output.put_line(3);
end;
/
call test_p2();--是否正确处理内外层的重载关系
declare
procedure p1 is
procedure p1 is
begin
dbms_output.put_line(1);
end;
begin
p1;
dbms_output.put_line(2);
end;
begin
p1;
dbms_output.put_line(3);
end;
/--是否正确处理和系统函数的重载关系
declare 
x varchar(20);
function substr(i date,f varchar) return varchar is
beginreturn to_char(i,f);
end;
function substr(i varchar,c int) return varchar is
beginreturn i||c;
end;
beginx:=substr(sysdate,'yyyy');x:=substr(x,1);dbms_output.put_line(x);
end;
/--是否支持前向声明
declare
procedure a ;
procedure b is
begina();
end;
procedure a is 
beginnull;
end;
beginnull;
end;
/

五、总结

MogDB 5.2.0版本正式推出的plsql嵌套子程序功能,是从MogDB3.0版本时期开始立项开发,经历了非常长的时间,因为这个功能对openGauss的现有框架来说,必须要做一些突破,改掉openGauss中一些不合理的代码,并且结合MogDB 5.2.0版本对plsql的各种底层原理的优化,才让PLSQL嵌套子程序功能变得完整且可扩展,不惧未来更多新功能的冲击。

  • 本文作者: DarkAthena
  • 本文链接: https://www.darkathena.top/archives/mogdb-5.2.0-support-plsql-nested-subprogram
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处

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

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

相关文章

文件上传绕过最新版安全狗

更多网安思路,可前往无问社区 http分块传输绕过 http分块传输⼀直是⼀个很经典的绕过⽅式,只是在近⼏年分块传输⼀直被卡的很死,很多waf都开始加 ⼊了检测功能,所以的话,分块传输这⾥也不是很好使,但是配…

深度学习论文: RemDet: Rethinking Efficient Model Design for UAV Object Detection

深度学习论文: RemDet: Rethinking Efficient Model Design for UAV Object Detection RemDet: Rethinking Efficient Model Design for UAV Object Detection PDF:https://arxiv.org/abs/2412.10040 PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: …

详细讲解axios封装与api接口封装管理

一、axios封装 axios是基于promise的http客户端,用于浏览器和nodejs发送http请求 ,对它进行封装主要是为了统一管理请求配置和处理请求和响应的通用逻辑等。以下是常用的封装逻辑和要点 1:引入axios相关依赖 首先引用项目中的axios库&…

搭建Elastic search群集

一、实验环境 二、实验步骤 Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎Elasticsearch目录文件: /etc/elasticsearch/elasticsearch.yml#配置文件 /etc/elasticsearch/jvm.options#java虚拟机 /etc/init.d/elasticsearch#服务启动脚本 /e…

正点原子串口例程解读

首先是串口初始化,这里初始化的是usart3 void esp8266_init(void) {huart_wifi.InstanceESP8266; //uart3huart_wifi.Init.BaudRate115200; // 设置波特率为115200huart_wifi.Init.WordLengthUART_WORDLENGTH_8B; // 设置数据位长度为8位huart_wifi.Init.StopBi…

Flink SQL 支持 kafka 开启 kerberos 权限控制.

一. 背景. 最近在验证kafka 开启kerberos的情况下, flink任务的支持情况. 但是验证的时候发现一个互斥的情况. 在读取数据的时候, 在开启kafka gruop id的权限控制的时候, flink sql 即使设置了gruop id , 竟然还能读取数据. 这个和预期不符. 所以才较真验证了一下. 二. kafk…

KVM虚拟机管理脚本

思路: 在/opt/kvm下创建一个磁盘文件,做差异镜像,创建一个虚拟机配置文件,做虚拟机模版 [rootnode01 ~]# ls /opt/kvm/ vm_base.qcow2 vm_base.xml创建虚拟机的步骤:首先创建虚拟机的差异镜像,然后复制虚…

Null value was assigned to a property of primitive type setter of 的原因与解决方案

Null value was assigned to a property of primitive type setter of 的原因与解决方案 org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of com.xxx.xxx.DealerUser.dealerId数据库表结构 实体类 当数据库的dealer…

latex常见问题汇总

文章目录 单行多图显示双栏插入图片 单行多图显示 \begin{figure}[t!] % case 1\centering\setlength{\tabcolsep}{0.5pt} % 图片之间的距离为0.5 point\begin{tabular}{ccc}\includegraphics[width0.30\linewidth, height0.33\linewidth]{pic/xuLun/thin.png} &\includeg…

读取百度api存入csv

读取百度api存入csv 1、将获取到的json数据映射Java实体类如下 所用的依赖 <!-- Jackson--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.2</ver…

【数据结构与算法】排序算法(下)——计数排序与排序总结

写在前面 书接上文&#xff1a;【数据结构与算法】排序算法(中)——交换排序之快速排序 文章主要讲解计数排序的细节与分析源码。之后进行四大排序的总结。 文章目录 写在前面一、计数排序(非比较排序)代码的实现&#xff1a; 二、排序总结 2.1、稳定性 3.2、排序算法复杂度及…

2034 C. Trapped in the Witch‘s Labyrinth

题意 一个矩阵&#xff0c;每个元素标有方向&#xff0c;人可以从任意一个位置出发&#xff0c;如果该位置永远走不到边缘&#xff0c;则被认为被困住了&#xff0c;统计这种位置的个数。 矩阵有?&#xff0c;其能代表某一种方向。 比如 3 3 ?U? R?L RDL答案是5 解决方…

Multi移动端开发

Multi移动端开发 安装环境 安装功能 VS2022安装 【ASP.NET和Web开发】、【.NET Multi-platform App UI开发】、【.NET桌面开发】 配置程序源 【工具】–>【选项】–>【NuGet包管理器】–>【程序包源】&#xff0c;添加如下&#xff1a; 名称&#xff1a;MES_APP 源&…

若依plus apifox导入接口显示为空

项目已经正常启动 访问接口有些没问题&#xff0c;有些有问题 其他模块都可以正常导入 解决&#xff1a;

音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现

音视频入门基础&#xff1a;AAC专题系列文章&#xff1a; 音视频入门基础&#xff1a;AAC专题&#xff08;1&#xff09;——AAC官方文档下载 音视频入门基础&#xff1a;AAC专题&#xff08;2&#xff09;——使用FFmpeg命令生成AAC裸流文件 音视频入门基础&#xff1a;AAC…

英文学术会议海报poster模板【可编辑】

英文学术会议海报poster模板【可编辑】 下载链接&#xff1a;学术会议海报poster模板【可编辑】 横版海报 竖版海报 下载链接&#xff1a;学术会议海报poster模板【可编辑】 提供了一套学术海报的PPT模板&#xff0c;适用于学术会议、研讨会等场合。 竖版&#xff0c;包含11…

Ubuntu 20.04 安装 LNMP

1. 更新系统 sudo apt update sudo apt upgrade2. 安装 Nginx sudo apt install nginx3. 安装 MariaDB (作为 MySQL 的替代) sudo apt install mariadb-server mariadb-client初始化 MariaDB 数据库&#xff08;可选&#xff09; sudo mysql_secure_installation4. 安装 PH…

机器学习之KNN算法预测数据和数据可视化

机器学习及KNN算法 目录 机器学习及KNN算法机器学习基本概念概念理解步骤为什么要学习机器学习需要准备的库 KNN算法概念算法导入常用距离公式算法优缺点优点&#xff1a;缺点︰ 数据可视化二维界面三维界面 KNeighborsClassifier 和KNeighborsRegressor理解查看KNeighborsRegr…

【VSCode】工作区及设置

【VSCode】工作区及设置 VSCode介绍工作区设置 VSCode介绍 Visual Studio Code&#xff08;简称VSCode&#xff09;是一个由微软开发的免费、开源的代码编辑器&#xff0c;以下是VSCode的一些功能及特性&#xff1a; 编辑器核心&#xff1a; 多文档界面&#xff1a;VSCode允许…

Jmeter自学【8】- 使用JMeter模拟设备通过MQTT发送数据

今天使用jmeter推送数据到MQTT&#xff0c;给大家分享一下操作流程。 一、安装JMeter 参考文档&#xff1a;Jmeter自学【1】- Jmeter安装、配置 二、安装MQTT插件 1、下载插件 我的Jmeter版本是5.6.3&#xff0c;用到的插件是&#xff1a;mqtt-xmeter-2.0.2-jar-with-depe…