
# 包（Package）
包（Package）是一组相关的子程序，包括包所使用的游标和变量，一起存储在数据库中，以便作为一个单元继续使用。打包的子程序可以由应用程序或用户显式调用。具有以下特点：
- 促进模块化编程：通过将相关的函数和存储过程封装在一个Package中，可以更容易地实现模块化编程。模块化可以提高代码的可读性和可维护性。
- 断开依赖链：对某个数据库对象的修改（如表结构的更改）不会导致依赖于该对象的所有其他对象（如存储过程、函数、视图等）变得无效，从而避免了代价较高的重编译过程。
- 性能优化：Package在数据库中是以编译形式存储的，当Package被调用时，数据库不需要再次编译代码，从而提高了执行效率。
- 命名空间管理：Package提供了一种命名空间，可以避免不同模块之间的命名冲突。在同一个Package内，可以有不同的函数和过程，即使它们在其他上下文中有相同的名称也不会冲突。
- 安全性：通过Package可以更好地控制对数据库对象的访问。
#### 创建包
创建包需要两部分内容，包头和包体。包头需要声明所有公共结构，而包体需要定义包的所有结构，包括公共部分和私有部分。
如下示例中，创建emp表，和pkg_emp_mgr包。包中有三个存储过程。
- pkg_emp_mgr.emp_add往emp表中插入员工信息。
- pkg_emp_mgr.emp_del作用是删除emp表中员工信息。
- pkg_emp_mgr.emp_res的作用是修改emp表中信息。
```
--PACKAGE仅支持在ORA兼容性数据库中使用。
gaussdb=# CREATE DATABASE ora_testdb DBCOMPATIBILITY 'ORA';
CREATE DATABASE
gaussdb=# \c ora_testdb
Non-SSL connection (SSL connection is recommended when requiring high-security)
You are now connected to database "ora_testdb" as user "omm".
```
```
--创建emp表。
ora_testdb=# CREATE TABLE emp(
    id INT,             -- 员工编号 
    name VARCHAR(50),   -- 员工姓名
    depno INT,          -- 部门编号
    sal FLOAT           -- 工资
);
NOTICE:  The 'DISTRIBUTE BY' clause is not specified. Using 'id' as the distribution column by default.
HINT:  Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column.
CREATE TABLE
--创建包头。
ora_testdb=# CREATE OR REPLACE PACKAGE pkg_emp_mgr AS 
    PROCEDURE emp_add(v_id INT, v_name VARCHAR, v_depno INT, v_sal FLOAT);
    PROCEDURE emp_del(v_id INT);
    PROCEDURE emp_res(v_id INT, v_depno INT, v_sal VARCHAR);
END pkg_emp_mgr;
/
--创建包体。
ora_testdb=# CREATE OR REPLACE PACKAGE BODY pkg_emp_mgr AS 
    PROCEDURE emp_add(v_id INT, v_name VARCHAR, v_depno INT, v_sal FLOAT) AS 
    BEGIN
        INSERT INTO emp VALUES (v_id, v_name, v_depno, v_sal);
    END;
    PROCEDURE emp_del(v_id INT) AS 
    BEGIN
        DELETE FROM emp WHERE id = v_id;
    END;
    PROCEDURE emp_res(v_id INT, v_depno INT, v_sal VARCHAR) AS
    BEGIN
        UPDATE emp SET depno = v_depno, sal = v_sal WHERE id = v_id;
    END;
END pkg_emp_mgr;
/
```
```
--调用pkg_emp_mgr.emp_add。
ora_testdb=# CALL pkg_emp_mgr.emp_add(1, 'scott', 10, 4000.00);
ora_testdb=# CALL pkg_emp_mgr.emp_add(2, 'july', 20, 3000.00);
--查询表数据。
ora_testdb=# SELECT * FROM emp;
 id | name  | depno | sal  
----+-------+-------+------
  1 | scott |    10 | 4000
  2 | july  |    20 | 3000
(2 rows)
--调用pkg_emp_mgr.emp_res。
ora_testdb=# CALL pkg_emp_mgr.emp_res(2, 30, 6000.00);
--查询数据。
ora_testdb=# SELECT * FROM emp;
 id | name  | depno | sal  
----+-------+-------+------
  1 | scott |    10 | 4000
  2 | july  |    30 | 6000
(2 rows)
--调用pkg_emp_mgr.emp_del。
ora_testdb=# CALL pkg_emp_mgr.emp_del(2);
--查询数据。
ora_testdb=# SELECT * FROM emp;
 id | name  | depno | sal  
----+-------+-------+------
  1 | scott |    10 | 4000
(1 row)
```
```
--删除包。
ora_testdb=# DROP PACKAGE pkg_emp_mgr;
NOTICE:  drop cascades to 3 other objects
DETAIL:  drop cascades to function public.emp_add(integer,character varying,integer,double precision)
drop cascades to function public.emp_del(integer)
drop cascades to function public.emp_res(integer,integer,character varying)
DROP PACKAGE
--删除表。
ora_testdb=# DROP TABLE emp;
DROP TABLE
--删除数据库。
ora_testdb=# \c postgres
Non-SSL connection (SSL connection is recommended when requiring high-security)
You are now connected to database "postgres" as user "omm".
gaussdb=# DROP DATABASE ora_testdb;
DROP DATABASE
```
