
# CREATE PACKAGE
#### 功能描述
创建一个新的PACKAGE。
#### 注意事项
- 在package specification中声明过的函数或者存储过程，必须在package body中找到定义。
- 在实例化中，无法调用带有commit/rollback的存储过程。
- 创建存储过程时，仅对CREATE的存储过程或PACKAGE本身加写锁，仅对执行过程中编译、执行会对函数和函数依赖的PACKAGE均加读锁。
- 不能在Trigger中调用package函数。
- 不能在外部SQL中直接使用package当中的变量。
- 不允许在package外部调用package的私有变量和存储过程。
- 不支持其它存储过程不支持的用法，例如，在function中不允许调用commit/rollback，则package的function中同样无法调用commit/rollback。
- 不支持schema与package同名。
- 只支持A风格的存储过程和函数定义。
- 不支持package内有同名变量，包括包内同名参数。
- package的全局变量为session级，不同session之间package的变量不共享。
- package中调用自治事务的函数，不允许使用package中的cursor变量，以及递归的使用package中cursor变量的函数。
- 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创建时依赖未定义对象，如参数behavior_compat_options='plpgsql_dependency'打开，创建可执行，通过WARNING提示；如参数未打开，package创建不可执行。
- 如package中A风格函数已被视图直接依赖，且参数behavior_compat_options='plpgsql_dependency'打开，再次创建包体后视图可正常访问；如参数未打开，视图访问失败。
- 创建package函数时，其参数默认值不支持含有变量。
- 包头在PG_OBJECT的类型为'S'（SPECIFICATION简称），包体在PG_OBJECT中的类型为'B'（BODY简称），当创建的PACKAGE对象失效时，可以通过PG_OBJECT中的VALID字段来查找PACKAGE失效对象的OID，并且使用"ALTER PACKAGE PKG_NAME COMPILE"来重新编译PACKAGE，使其有效。
- 在创建package内的函数时，如果函数名字为schema.func或package.func形式，则只会取func的名字，前面的Schema声明或者Package声明无效，如果需要默认禁用这种行为，可以设置guc参数behavior_compat_options='forbid_package_function_with_prefix'
 
#### 语法格式
- CREATE PACKAGE SPECIFICATION语法格式。
  ```
  CREATE [ OR REPLACE ] PACKAGE [ schema ] package_name
      [ invoker_rights_clause ] { IS | AS } item_list_1 END package_name;
  invoker_rights_clause可以被声明为AUTHID DEFINER或者AUTHID CURRENT_USER，分别为定义者权限和调用者权限。
  item_list_1可以为声明的变量或者存储过程以及函数。
  ```
  PACKAGE SPECIFICATION（包头）声明了包内的公有变量、函数、异常等，可以被外部函数或者存储过程调用。在PACKAGE SPECIFICATION中只能声明存储过程，函数，不能定义存储过程或者函数。
  
- CREATE PACKAGE BODY语法格式。
  ```
  CREATE [ OR REPLACE ] PACKAGE BODY [ schema ] package_name
      { IS | AS } declare_section [ initialize_section ] END package_name;
  ```
  PACKAGE BODY(包体内)定义了包的私有变量，函数等。如果变量或者函数没有在PACKAGE SPECIFICATION中声明过，那么这个变量或者函数则为私有变量或者函数。
  PACKAGE BODY也可以声明实例化部分，用来初始化package，详见示例。
  
 
#### 示例
- CREATE PACKAGE SPECIFICATION示例：
  ```
  gaussdb=# CREATE OR REPLACE PACKAGE emp_bonus IS
  var1 int:=1;--公有变量。
  var2 int:=2;
  PROCEDURE testpro1(var3 int);--公有存储过程，可以被外部调用。
  END emp_bonus;
  /
  ```
  
- CREATE PACKAGE BODY示例：
  ```
  gaussdb=# drop table if exists test1;
  gaussdb=# create or replace package body emp_bonus is
  var3 int:=3;
  var4 int:=4;
  procedure testpro1(var3 int)
  is
  begin
  create table if not exists test1(col1 int);
  insert into test1 values(var1);
  insert into test1 values(var4);
  end;
  begin  --实例化开始。
  var4:=9;
  testpro1(var4);
  end emp_bonus;
  /
  ```
  
- ALTER PACKAGE OWNER示例：
  ```
  --将PACKAGE emp_bonus的所属者改为omm。
  gaussdb=# ALTER PACKAGE emp_bonus OWNER TO omm;
  ```
  
- 调用PACKAGE示例：
  ```
  --使用call调用package存储过程。
  gaussdb=# call emp_bonus.testpro1(1); 
  --使用select调用package存储过程。
  gaussdb=# select emp_bonus.testpro1(1); 
  --匿名块里调用package存储过程。
  gaussdb=# begin
  emp_bonus.testpro1(1);
  end;
  /
  ```
  
 
