openGauss 存储功能全面升级,支持 PACKAGE、PLDEBUGGER 等诸多新特性
-
存储过程类似于面向过程语言当中的函数,可以实现面向过程语言当中的声明变量、逻辑判断、条件循环等操作,是一组完成特定功能的SQL语句集合。
-
在 openGauss 2.1 之前的版本中,存储过程支持了定义变量、条件循环、逻辑判断等基本功能,但是没有面向对象语言中类的形式,因此无法对存储过程中的变量以及函数进行封装,也无法在存储过程内使用全局变量。在以前的版本中没有支持类似gdb的功能,用户调试存储过程只能够使用raise info等打印变量的方式。并且在之前的版本当中,存储过程发生异常后,没有自治事务,记录错误日志不便。
-
而在新的版本当中,通过支持 PACKAGE、存储过程调试/PLDEBUGGER、自治事务等新功能,解决了上述问题。下面将介绍新特性的应用场景以及使用方法。
特性一:PACKAGE
package是一组相关存储过程、函数、变量、常量、游标等PL/SQL程序的组合,具有面向对象的特点,可以对PL/SQL程序设计元素进行封装。package中的函数具有统一性,创建、删除、修改都统一进行。
package包含包头(Package Specification)和Package Body两个部分,其中包头所包含的声明可以被外部函数、匿名块等访问,而在包体中包含的声明不能被外部函数、匿名块等访问,只能被包体内函数和存储过程等访问。
下面可以看一组简单的例子理解一下:
CREATE TABLE tab1(col1 int); CREATE OR REPLACE PACKAGE PCK1 --包头,在包头内声明的变量存储过程等都为公有的,可以被外部访问 IS public_var1 int:=1; --在包头声明的公有变量public_var1,可以被外部访问 procedure public_proc1(col1 int,col2 int); --只在包头内声明的存储过程,因此为公有的,可以被外部访问。 END PCK1; / CREATE OR REPLACE PACKAGE BODY PCK1 --指定了PACKAGE BODY关键字 IS private_var1 int:=1; --在包体内声明的私有变量private_var1,不能被外部访问 procedure private_proc1(col1 int,col2 int) --只在包体内定义的存储过程为私有存储过程 is begin raise notice 'col1 + col2 = %',col1+col2; insert into tab1 values(col1+col2); end; procedure public_proc1(col1 int,col2 int)--只在包体内定义的存储过程为私有存储过程 is begin private_proc1(1,2); end; --需与包头保持一致 END PCK1; / > --package中的函数调用方式与存储过程调用方式一样 > call pck1.public_proc1(1,2);
特性二、PLDEBUGGER
DBE_PLDEBUGGER用于调试存储过程,类似于GDB的功能,可以使用单步调试,设置断点、打印调用堆栈等功能,方便了存储过程的调试,减小了存储过程的开发难度。详细的使用方法以及说明可以参考在本文末提供的 [PLDEBUGGER接口及示例]
特性三、自治事务
自治事务(Autonomous Transaction),在主事务执行过程中新启的独立的事务。自治事务的提交和回滚不会影响主事务已提交的数据,同时自治事务也不受主事务影响。
自治事务在存储过程、函数和匿名块中定义,用PRAGMA AUTONOMOUS_TRANSACTION关键字来声明。
自治事务一般用于存储过程发生异常后,处理日志的时候。
下面可以看一个简单的示例:
create table t2(a int, b int); insert into t2 values(1,2); select * from t2; --创建包含自治事务的存储过程 CREATE OR REPLACE PROCEDURE autonomous_proc1(a int, b int) AS DECLARE num3 int := a; num4 int := b; PRAGMA AUTONOMOUS_TRANSACTION; --声明此存储过程为一个自治事务的存储过程 BEGIN insert into t2 values(num3, num4); dbe_output.print_line('just use call.'); END; / --创建调用自治事务存储过程的普通存储过程 CREATE OR REPLACE PROCEDURE proc1(a int, b int) AS DECLARE c int:=0; BEGIN dbe_output.print_line('just no use call.'); insert into t2 values(5, 6);--异常后回滚 c:=c/0; exception when others then autonomous_proc1(a,b); END; / --调用普通存储过程 select proc1(11,22); select * from t2 order by a; 输出结果: a | b ----+---- 1 | 2 11 | 22 (2 rows)
pldebugger 接口及示例
接口名称 | 描述 |
DBE_PLDEBUGGER.turn_on | server端调用,标记存储过程可以调试,调用后执行该存储过程时会hang住等待调试信息。 |
DBE_PLDEBUGGER.turn_off | server端调用,标记存储过程关闭调试。 |
DBE_PLDEBUGGER.local_ debug_server_info | server端调用,打印本session内所有已turn_on的存储过程。 |
DBE_PLDEBUGGER.attach | debug端调用,关联到正在调试存储过程。 |
DBE_PLDEBUGGER.info_locals | debug端调用,打印正在调试的存储过程中的变量当前值。 |
DBE_PLDEBUGGER.next | debug端调用,单步执行。 |
DBE_PLDEBUGGER.continue | debug端调用,继续执行,直到断点或存储过程结束。 |
DBE_PLDEBUGGER.abort | debug端调用,停止调试,server端报错长跳转。 |
DBE_PLDEBUGGER.print_var | debug端调用,打印正在调试的存储过程中指定的变量当前值。 |
DBE_PLDEBUGGER.info_code | debug和server端都可以调用,打印指定存储过程的源语句和各行对应的行号。 |
DBE_PLDEBUGGER.step | debug端调用,单步进入执行。 |
DBE_PLDEBUGGER.add_ breakpoint | debug端调用,新增断点。 |
DBE_PLDEBUGGER.delete_ breakpoint | debug端调用,删除断点。 |
DBE_PLDEBUGGER.info_ breakpoint | debug端调用,查看当前的所有断点。 |
DBE_PLDEBUGGER.backtrace | debug端调用,查看当前的调用栈。 |
DBE_PLDEBUGGER.enable_ breakpoint | debug端调用,激活被禁用的断点。 |
DBE_PLDEBUGGER.disable_ breakpoint | debug端调用,禁用已激活的断点 |
DBE_PLDEBUGGER.finish | debug端调用,继续调试,直到断点或返回上一层调用栈。 |
DBE_PLDEBUGGER.set_var | debug端调用,为变量进行赋值操作。 |
示例
-
准备调试
通过PG_PROC,查找到待调试存储过程的oid,并执行DBE_PLDEBUGGER.turn_on(oid)。本客户端就会作为server端使用
CREATE OR REPLACE PROCEDURE test_debug ( IN x INT) AS BEGIN INSERT INTO t1 (a) VALUES (x); DELETE FROM t1 WHERE a = x; END; / 输出结果: CREATE PROCEDURE SELECT OID FROM PG_PROC WHERE PRONAME='test_debug'; 输出结果: oid ------- 16389 (1 row) SELECT * FROM DBE_PLDEBUGGER.turn_on(16389); 输出结果: nodename | port ----------+------ datanode | 0 (1 row)
-
开始调试
server端执行存储过程,会在存储过程内第一条SQL语句前hang住,等待debug端发送的调试消息。仅支持直接执行存储过程的调试,不支持通过trigger调用执行的存储过程调试。
call test_debug(1);
-
再起一个客户端,作为debug端,通过turn_on返回的数据,调用DBE_PLDEBUGGER.attach关联到该存储过程上进行调试。
SELECT * FROM DBE_PLDEBUGGER.attach('datanode',0); 输出结果: funcoid | funcname | lineno | query ---------+------------+--------+---------------------------------- 16389 | test_debug | 3 | INSERT INTO t1 (a) VALUES (x); (1 row)
-
在执行 attach 的客户端调试,执行下一条 statement。
SELECT * FROM DBE_PLDEBUGGER.next(); 输出结果: funcoid | funcname | lineno | query ---------+------------+--------+---------------------- 16389 | test_debug | 0 | [EXECUTION FINISHED] (1 row)
-
在执行 attach 的客户端调试,可以执行以下变量操作
SELECT * FROM DBE_PLDEBUGGER.info_locals(); --打印全部变量 输出结果: varname | vartype | value | package_name | isconst ---------+---------+-------+--------------+--------- x | int4 | 1 | | f (1 row) SELECT * FROM DBE_PLDEBUGGER.set_var('x', 2); --变量赋值 输出结果: set_var --------- t (1 row) SELECT * FROM DBE_PLDEBUGGER.print_var('x'); --打印单个变量 输出结果: varname | vartype | value | package_name | isconst ---------+---------+-------+--------------+--------- x | int4 | 2 | | f (1 row)
-
直接执行完成当前正在调试的存储过程。
SELECT * FROM DBE_PLDEBUGGER.continue(); 输出结果: funcoid | funcname | lineno | query ---------+------------+--------+---------------------- 16389 | test_debug | 0 | [EXECUTION FINISHED] (1 row)
-
直接退出当前正在调试的存储过程,不执行尚未执行的语句。
SELECT * FROM DBE_PLDEBUGGER.abort(); 输出结果: abort ------- t (1 row)
-
client端查看代码信息并识别可以设置断点行号。
SELECT * FROM DBE_PLDEBUGGER.info_code(16389); 输出结果: lineno | query | canbreak --------+-----------------------------------------------------------+---------- | CREATE OR REPLACE PROCEDURE public.test_debug( IN x INT) | f 1 | AS DECLARE | f 2 | BEGIN | f 3 | INSERT INTO t1 (a) VALUES (x); | t 4 | DELETE FROM t1 WHERE a = x; | t 5 | END; | f 6 | / | f (7 rows)
-
设置断点
SELECT * FROM DBE_PLDEBUGGER.info_breakpoints(); 输出结果: breakpointno | funcoid | lineno | query | enable --------------+---------+--------+---------------------------------+-------- 0 | 16389 | 4 | DELETE FROM t1 WHERE a = x; | t
-
查看断点信息
SELECT * FROM DBE_PLDEBUGGER.info_breakpoints(); 输出结果: breakpointno | funcoid | lineno | query | enable --------------+---------+--------+---------------------------------+-------- 0 | 16389 | 4 | DELETE FROM t1 WHERE a = x; | t (1 row)
-
执行至断点
SELECT * FROM DBE_PLDEBUGGER.continue(); 输出结果: funcoid | funcname | lineno | query ---------+------------+--------+--------------------------------- 16389 | test_debug | 4 | DELETE FROM t1 WHERE a = x;

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
研究发现,数亿WIFI芯片存在数据窃取和流量操纵风险
WOT全球技术创新大会2022,门票6折抢购中!购票立减2320元! 据Security Affairs网站报道,来自姆施塔特大学、布雷西亚大学、CNIT 和安全移动网络实验室的一组研究人员发现了WiFi芯片中的安全漏洞,攻击者可利用这些漏洞通过定位设备的蓝牙组件来提取密码并操纵WiFi芯片上的流量。 根据专家发表的研究论文,现今的移动设备使用独立的无线芯片来管理蓝牙、Wi-Fi 和 LTE 等无线技术。但是,这些芯片共享组件和资源,例如相同的天线或无线频谱,以提高设备的效率,从而降低能耗和通信延迟。 研究人员表示,攻击者可以用这些共享资源跨无线芯片边界发起横向提权攻击。WiFi芯片会加密网络流量并保存当前的WiFi凭证,从而为攻击者提供更多信息。此外,攻击者可以在WiFi芯片上执行代码,即使它没有连接到无线网络。 根据论文,研究人员展示了数十亿台设备中的Broadcom、Cypress 和 Silicon Labs 芯片的实际共存攻击,可以此实现WiFi代码执行、内存读取和拒绝服务。在设计的攻击场景中,研究人员首先在蓝牙或 WiFi 芯片上执行代码,然后利用共享内存资源对同一设备上的...
- 下一篇
Bean Searcher 发布 v3.1.3 版本
Bean Searcher 发布 v3.1.3版本,具体更新内容如下: Bean Searcher 无@DbIgnore也自动忽略实体类中的静态字段 Bean Searcher Boot Starter 使用 Searcher 类型注入检索器时,默认注入 MapSearcher,不再报错 提高兼容性,SpringBoot 最低版本支持到 v1.4+
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS关闭SELinux安全模块
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS8编译安装MySQL8.0.19