---
title: openGauss存储过程功能全面升级，支持PACKAGE,PLDEBUGGER等诸多新特性-官方技术文章-鲲鹏社区
description: 本文主要介绍openGauss存储过程PACKAGE、PLDEBUGGER等新特性的应用场景以及使用方法。
keywords: Gauss,存储过程功能,全面升级,PACKAGE,PLDEBUGGER,等诸多新特性,官方技术文章,鲲鹏社区
url: https://www.hikunpeng.com/developer/techArticles/20230913-14?envFlag=1
section: (其他)
---

# openGauss存储过程功能全面升级，支持PACKAGE,PLDEBUGGER等诸多新特性-官方技术文章-鲲鹏社区

URL: https://www.hikunpeng.com/developer/techArticles/20230913-14?envFlag=1
描述: 本文主要介绍openGauss存储过程PACKAGE、PLDEBUGGER等新特性的应用场景以及使用方法。
关键词: Gauss,存储过程功能,全面升级,PACKAGE,PLDEBUGGER,等诸多新特性,官方技术文章,鲲鹏社区

官方技术文章 [了解详情](https://www.hikunpeng.com/zh/developer/techArticles)

openGauss存储过程功能全面升级，支持PACKAGE,PLDEBUGGER等诸多新特性

openGauss存储过程功能全面升级，支持PACKAGE,PLDEBUGGER等诸多新特性

实战经验

发表于 2021/12/17

0

存储过程类似于面向过程语言当中的函数，可以实现面向过程语言当中的声明变量、逻辑判断、条件循环等操作，是一组完成特定功能的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_ | server端调用，打印本session内所有已turn_on的存储过程。 |
| debug_server_info |  |
| 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_ | debug端调用，新增断点。 |
| breakpoint |  |
| DBE_PLDEBUGGER.delete_ | debug端调用，删除断点。 |
| breakpoint |  |
| DBE_PLDEBUGGER.info_ | debug端调用，查看当前的所有断点。 |
| breakpoint |  |
| DBE_PLDEBUGGER.backtrace | debug端调用，查看当前的调用栈。 |
| DBE_PLDEBUGGER.enable_ | debug端调用，激活被禁用的断点。 |
| breakpoint |  |
| DBE_PLDEBUGGER.disable_ | debug端调用，禁用已激活的断点 |
| breakpoint |  |
| DBE_PLDEBUGGER.finish | debug端调用，继续调试，直到断点或返回上一层调用栈。 |
| DBE_PLDEBUGGER.set_var | debug端调用，为变量进行赋值操作。 |

示例：

（1）准备调试

通过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)
```

（2）开始调试

server端执行存储过程，会在存储过程内第一条SQL语句前hang住，等待debug端的调试消息。仅支持直接执行存储过程的调试，不支持通过trigger调用执行的存储过程调试。

```
call test_debug(1);
```

（3）再起一个客户端，作为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)
```

（4）在执行attach的客户端调试，执行下一条statement。

```
SELECT * FROM DBE_PLDEBUGGER.next();
输出结果：
funcoid | funcname | lineno | query
---------+------------+--------+----------------------
16389 | test_debug | 0 | [EXECUTION FINISHED]
(1 row)
```

（5）在执行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)
```

（6）直接执行完成当前正在调试的存储过程。

```
SELECT * FROM DBE_PLDEBUGGER.continue();
输出结果：
funcoid | funcname | lineno | query
---------+------------+--------+----------------------
16389 | test_debug | 0 | [EXECUTION FINISHED]
(1 row)
```

（7）直接退出当前正在调试的存储过程，不执行尚未执行的语句。

```
SELECT * FROM DBE_PLDEBUGGER.abort();
输出结果：
abort
-------
t
(1 row)
```

（8）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)
```

（9）设置断点

```
SELECT * FROM DBE_PLDEBUGGER.info_breakpoints();
输出结果：
breakpointno | funcoid | lineno | query | enable
--------------+---------+--------+---------------------------------+--------
0 | 16389 | 4 | DELETE FROM t1 WHERE a = x; | t
```

（10）查看断点信息

```
SELECT * FROM DBE_PLDEBUGGER.info_breakpoints();
输出结果：
breakpointno | funcoid | lineno | query | enable
--------------+---------+--------+---------------------------------+--------
0 | 16389 | 4 | DELETE FROM t1 WHERE a = x; | t
(1 row)
```

（11）执行至断点

```
SELECT * FROM DBE_PLDEBUGGER.continue();
输出结果：
funcoid | funcname | lineno | query
---------+------------+--------+---------------------------------
16389 | test_debug | 4 | DELETE FROM t1 WHERE a = x;
```

欢迎访问openGauss官方网站

openGauss开源社区官方网站：

https://opengauss.org/ [了解详情](https://opengauss.org)

openGauss组织仓库：

https://gitcode.com/opengauss [了解详情](https://gitcode.com/opengauss)

openGauss镜像仓库：

https://github.com/opengauss-mirror [了解详情](https://github.com/opengauss-mirror)

本页内容
