# CREATE PACKAGE
#### 功能描述
创建一个新的PACKAGE。
#### 注意事项
- 仅支持在ORA兼容模式数据库中使用PACKAGE。
- 在包头（PACKAGE SPECIFICATION）中声明过的函数或者存储过程，必须在包体（PACKAGE BODY）明确定义。
- 创建存储过程时，仅对CREATE的存储过程或PACKAGE本身加写锁；对于执行过程中的编译以及执行会对函数和函数依赖的PACKAGE加读锁。
- 在实例化中，无法调用含有COMMIT或ROLLBACK的存储过程。
- 不能在触发器中调用PACKAGE函数。
- 不能在外部SQL中直接使用PACKAGE中的变量。
- 不允许在PACKAGE外部调用PACKAGE的私有变量和存储过程。
- 存储过程中不支持的用法，PACKAGE中也不支持使用。例如：在函数（function）中不允许调用COMMIT/ROLLBACK，则PACKAGE的函数（function）中同样无法调用COMMIT/ROLLBACK。
- 不支持Schema与PACKAGE同名。
- 只支持兼容Oracle数据库的存储过程和函数定义。
- 不支持PACKAGE内有同名变量，包括包内同名参数。
- PACKAGE的全局变量为session级，不同session之间PACKAGE的变量不共享。
- PACKAGE中调用自治事务的函数，不允许使用PACKAGE中的游标变量，以及不允许递归的使用PACKAGE中游标变量的函数。
- PACKAGE中不支持声明REF CURSOR变量。
- PACKAGE默认为SECURITY INVOKER权限，如果想将默认行为改为SECURITY DEFINER权限，需要设置GUC参数behavior_compat_options='plsql_security_definer'。
- 被授予CREATE ANY PACKAGE权限的用户，可以在PUBLIC模式和用户模式下创建PACKAGE。
- 如果需要创建带有特殊字符的PACKAGE名，特殊字符中不能含有空格，且需设置GUC参数behavior_compat_options="skip_insert_gs_source"，否则可能引起报错。
- 创建PACKAGE函数时，其参数默认值支持含有PACKAGE内变量，不支持跨PACKAGE变量。
- PACKAGE中函数复杂调用，如：func(x).a，函数调用返回复合类型，支持跨Schema调用，不支持通过database.schema.package.func(x).b的方式调用。
- 在创建PACKAGE内的存储过程时，如果存储过程名称为schema.func或package.func形式，只会获取func的名称，不会对Schema声明以及PACKAGE声明进行获取，如果需要禁止这种行为，可以设置GUC参数behavior_compat_options='forbid_package_function_with_prefix'。
- 不支持view%RowType作为函数参数。
- 不支持存储过程/函数中的INSERT VALUES使用复合类型record。
- 当前形态不支持SAVE EXCEPTIONS（调用的存过中使用）。
  
- 表达式不支持COMMIT/ROLLBACK。
- 对于无参数的函数，不支持省略括号。
  
- 自定义类型变量不支持下推。
  
- 在创建PACKAGE内的存储过程时，如果存储过程的入参包含伪类型（如：anyelement），不支持调用时传入变长类型的参数。
- PACKAGE内创建的游标或者函数带参数游标，可以跨PACKAGE进行类型引用（%RowType）和打开使用，存在以下限制：
  - 暂不支持通过database.schema.package.cursor的方式调用游标。
  
  - 不支持将游标定义为函数参数。
  
  - 当引用游标时，不支持cursor%RowType。
   
- 在PACKAGE SPECIFICATION或PACKAGE BODY SPECIFICATION中声明自治事务PRAGMA AUTONOMOUS_TRANSACTION语法，可成功创建PACKAGE，但自治事务不生效。
- 非初始用户无权对初始用户的PACKAGE进行REPLACE操作。
- 创建PACKAGE时，仅对包头（PACKAGE SPECIFICATION）、包体（PACKAGE BODY）内变量默认值进行有效性检查（检查默认值依赖函数是否存在、是否有效），不执行相关语句，包头、包体变量初始化及包体实例化部分（PACKAGE BODY ANONYMOUS BLOCK）仅在第一次调用时执行一次。
- 在PACKAGE创建、重编译及相关嵌套编译过程中，PACKAGE实例化（包头、包体变量初始化及包体实例化部分）均不会被执行。
 
#### 语法格式
- CREATE PACKAGE SPECIFICATION（创建包头）语法格式。
  ```
  CREATE [ OR REPLACE ] PACKAGE [ schema ] package_name
      [ invoker_rights_clause ] { IS | AS } item_list_1 END [ package_name ];
  ```
  ![](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/figure/zh-cn_image_0000002764469406.png "点击放大")
  - invoker_rights_clause：可以使用AUTHID DEFINER或AUTHID CURRENT_USER进行声明包头的调用者权限，其中，AUTHID DEFINER表示创建者权限，AUTHID CURRENT_USER表示调用者权限。包头内的变量、函数或存储过程按照声明时指定的权限（AUTHID DEFINER或AUTHID CURRENT_USER）执行，而包头内的游标则以调用者权限（AUTHID CURRENT_USER）执行。
  
  - item_list_1：可以是声明的变量或者存储过程以及函数。
  
  - END后的package_name可省略（gs_dump生成的SQL文件，PACKAGE定义会自动补充END后名称），若未指定该package_name，则CREATE PACKAGE SPECIFICATION（创建包头）语法格式的结尾必须添加结束符（/）。
  
  
  ![](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
  PACKAGE SPECIFICATION声明了包内的公有变量、函数以及异常等，可以被外部函数或者存储过程调用。在PACKAGE SPECIFICATION中只能声明存储过程以及函数，不能定义存储过程或者函数。
  
- CREATE PACKAGE BODY（创建包体）语法格式。
  ```
  CREATE [ OR REPLACE ] PACKAGE BODY [ schema ] package_name
      { IS | AS } declare_section [ initialize_section ] END [ package_name ];
  ```
  ![](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/figure/zh-cn_image_0000002764309476.png "点击放大")
  END后的package_name可省略（gs_dump生成的SQL文件，PACKAGE定义会自动补充END后名称），若未指定该package_name，则CREATE PACKAGE BODY（创建包体）语法格式的结尾必须添加结束符（/）。
  ![](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
  - PACKAGE BODY定义了包的私有变量以及函数等。如果变量或者函数没有在PACKAGE SPECIFICATION中声明过，那么这个变量或者函数则为私有变量或者私有函数。
  
  - PACKAGE BODY也可以声明实例化部分，用于初始化PACKAGE。
    
 
#### 示例
- CREATE PACKAGE示例
  ```
  --创建数据库。
  gaussdb=# CREATE DATABASE test DBCOMPATIBILITY 'ORA';
  gaussdb=# \c test
  --创建测试表tbl_test。
  test=# CREATE TABLE tbl_test(uid varchar(6) PRIMARY KEY, area_id varchar(5), level int);
  --创建包头。
  test=# CREATE OR REPLACE PACKAGE pkg_test AS 
      --公有存储过程可以被外部调用。
      PROCEDURE proc_ist_tbl_test(v_uid in varchar, v_area_id varchar, v_level int);  
      PROCEDURE proc_del_tbl_test(v_uid in varchar);
      PROCEDURE proc_upd_tbl_test(v_uid in varchar, v_area_id varchar, v_level int);
  END pkg_test; 
  /
  --创建包体。
  test=# CREATE OR REPLACE PACKAGE BODY pkg_test AS 
      PROCEDURE proc_ist_tbl_test(v_uid in varchar, v_area_id varchar, v_level int) AS
      BEGIN
          INSERT INTO tbl_test VALUES (v_uid, v_area_id, v_level);
      END;    
      PROCEDURE proc_del_tbl_test(v_uid in varchar) AS 
      BEGIN 
          DELETE FROM tbl_test WHERE uid = v_uid;
      END;
      PROCEDURE proc_upd_tbl_test(v_uid in varchar, v_area_id varchar, v_level int) AS
      BEGIN 
          UPDATE tbl_test SET area_id = v_area_id, level = v_level WHERE uid = v_uid;
      END;
      var4 int := 10;
      --实例化开始。
  BEGIN 
      var4 := 10;
      dbe_output.print_line(var4);
  END pkg_test; 
  /
  ```
  
- 调用PACKAGE示例
  ```
  --使用CALL调用PACKAGE的存储过程。
  test=# CALL pkg_test.proc_ist_tbl_test('0A00B1','01001',24);
  test=# SELECT * FROM tbl_test;
    uid   | area_id | level 
  --------+---------+---------
   0A00B1 | 01001   |      24
  (1 row)
  --使用SELECT调用PACKAGE的存储过程。
  test=# SELECT pkg_test.proc_upd_tbl_test('0A00B1','01001','26');
  test=# SELECT * FROM tbl_test;
    uid   | area_id | level 
  --------+---------+-------
   0A00B1 | 01001   |    26
  (1 row)
  --匿名块调用PACKAGE的存储过程。
  test=# BEGIN 
  pkg_test.proc_del_tbl_test('0A00B1'); 
  END; 
  /
  test=# SELECT * FROM tbl_test;
   uid | area_id | level 
  -----+---------+-------
  (0 rows)
  --删除。
  test=# DROP TABLE tbl_test;
  test=# DROP PACKAGE pkg_test;
  --切换至默认数据库并删除test数据库（请根据实际情况修改数据库名）。
  test=# \c postgres
  gaussdb=# DROP DATABASE test;
  ```
  
 
#### 相关链接
[ALTER PACKAGE](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/gaussdb-08-0199.html)，[DROP PACKAGE](https://support.huaweicloud.com/distributed-ref-v10-gaussdb/gaussdb-08-0311.html)
