
# CREATE PROCEDURE
#### 功能描述
创建一个新的存储过程。
#### 注意事项
- 如果创建存储过程时参数或返回值带有精度，不进行精度检测。
- 创建存储过程时，存储过程定义中对表对象的操作建议都显示指定模式，否则可能会导致存储过程执行异常。
- 在创建存储过程时，存储过程内部通过SET语句设置current_schema和search_path无效。执行完函数search_path和current_schema与执行函数前的search_path和current_schema保持一致。
- 如果存储过程参数中带有出参，SELECT调用存储过程必须缺省出参，CALL调用存储过程时调用非重载函数必须指定出参，对于重载的package函数，out参数可以缺省，具体信息参见[CALL](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/gaussdb-12-0347.html#ZH-CN_TOPIC_0000002187528380)的示例。
- 存储过程指定package属性时支持重载。
- 在创建procedure时，不能在avg函数外面嵌套其他agg函数，或者其他系统函数。
- 函数定义时如果指定为IMMUTABLE和SHIPPABLE类型，应该尽量避免函数中存在INSERT，UPDATE，DELETE，MERGE和DDL操作，因为上述操作应该由CN判断对应的执行节点，否则执行结果可能产生错误。
- 存储过程中不支持需要return集合的操作。
- 在存储过程内部调用其它无参数的存储过程时，可以省略括号，直接使用存储过程名进行调用。
- 在存储过程内部调用其他有出参的函数，如果在赋值表达式中调用时，被调函数的出参可以省略，给出了也会被忽略。
- 存储过程支持参数注释的查看与导出、导入。
- 存储过程支持介于IS/AS与plsql_body之间的注释的查看与导出、导入。
- 被授予CREATE ANY FUNCTION权限的用户，可以在用户模式下创建/替换存储过程。
- 存储过程默认为SECURITY INVOKER权限，如果想将默认行为改为SECURITY DEFINER权限，需要设置guc参数behavior_compat_options='plsql_security_definer'。
- 如果将定义者权限的存储过程创建到其他用户SCHEMA下，则会以其他用户的权限执行该存储过程，有越权风险，请谨慎使用。
 
#### 语法格式
```
openGauss=# CREATE [ OR REPLACE ] PROCEDURE procedure_name
    [ ( {[ argname ] [ argmode ] argtype [ { DEFAULT | := | = } expression ]}[,...]) ]
    [
       { IMMUTABLE | STABLE | VOLATILE }
       | { SHIPPABLE | NOT SHIPPABLE }
       | {PACKAGE}
       | [ NOT ] LEAKPROOF
       | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }
       | {[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | AUTHID DEFINER | AUTHID CURRENT_USER}
       | COST execution_cost
       | SET configuration_parameter { [ TO | = ] value | FROM CURRENT }
    ][ ... ]
 { IS | AS } 
plsql_body 
/
```
#### 参数说明
- **OR REPLACE**
  当存在同名的存储过程时，替换原来的定义。
  
- **procedure_name**
  创建的存储过程名称，可以带有模式名。
  取值范围：字符串，要符合[标识符命名规范](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/gaussdb-12-0227.html#ZH-CN_TOPIC_0000002187528220__zh-cn_topic_0000002185458746_section14873217506)。
  
- **argmode**
  参数的模式。
  ![](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/public_sys-resources/notice_3.0-zh-cn.png)
  VARIADIC用于声明数组类型的参数。
  取值范围： IN，OUT，INOUT或VARIADIC。缺省值是IN。只有OUT模式的参数后面能跟VARIADIC。并且OUT和INOUT模式的参数不能用在RETURNS TABLE的过程定义中。
  
- **argname**
  参数的名称。
  取值范围：字符串，要符合[标识符命名规范](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/gaussdb-12-0227.html#ZH-CN_TOPIC_0000002187528220__zh-cn_topic_0000002185458746_section14873217506)。
  
- **argtype**
  参数的数据类型。可以使用%ROWTYPE间接引用表的类型，或者使用%TYPE间接引用表或复合类型中某一列的类型。
  取值范围：可用的数据类型。
  
- **expression**
  参数的默认表达式。
  ![](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
  - 推荐使用方式：将所有默认值参数定义在所有非默认值参数后。
    
- **IMMUTABLE、STABLE** 等
  行为约束可选项。各参数的功能与CREATE FUNCTION类似，详细说明见[CREATE FUNCTION](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/gaussdb-12-0361.html#ZH-CN_TOPIC_0000002222888837)
  
- **plsql_body**
  PL/SQL存储过程体。
  ![](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/public_sys-resources/notice_3.0-zh-cn.png)
  当在存储过程体中进行创建用户、修改密码或加解密等涉及密码或密钥相关操作时，系统表及日志中会记录密码或密钥的明文信息。为防止敏感信息泄露，不建议用户在存储过程体中进行涉及密码或密钥等敏感信息的相关操作。
  
![](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
argname和argmode的顺序没有严格要求，推荐按照argname、argmode、argtype的顺序使用。
#### 示例
```
--创建一个存储过程。
openGauss=# CREATE OR REPLACE PROCEDURE prc_add
(
    param1    IN   INTEGER,
    param2    IN OUT  INTEGER
)
AS
BEGIN
   param2:= param1 + param2;
   dbe_output.print_line('result is: '||to_char(param2));
END;
/
--调用此存储过程。
openGauss=# SELECT prc_add(2,3);
--创建一个参数模式为VARIADIC的存储过程。
openGauss=# CREATE OR REPLACE PROCEDURE pro_variadic (var1 VARCHAR2(10) DEFAULT 'hello!',var4 VARIADIC int4[])
AS
BEGIN
    dbe_output.print_line(var1);
END;
/
--执行此存储过程。
openGauss=# SELECT pro_variadic(var1=>'hello', VARIADIC var4=> array[1,2,3,4]);
--创建一个存储过程，将带着调用它的用户的权限执行。
openGauss=# CREATE TABLE tb1(a integer);
openGauss=#  CREATE PROCEDURE insert_data(v integer)      
SECURITY INVOKER
AS
BEGIN
    INSERT INTO tb1 VALUES(v);
END;
/
--调用此存储过程。
openGauss=#  CALL insert_data(1);
--创建带有package属性的存储过程。
openGauss=# create or replace procedure package_func_overload(col int, col2 out varchar)
package
as
declare
    col_type text;
begin
     col2 := '122';
         dbe_output.print_line('two varchar parameters ' || col2);
end;
/
--删除存储过程。
openGauss=# DROP PROCEDURE prc_add;
openGauss=# DROP PROCEDURE pro_variadic;
openGauss=# DROP PROCEDURE insert_data;
openGauss=# DROP PROCEDURE package_func_overload;
```
#### 相关链接
[DROP PROCEDURE](https://support.huaweicloud.com/distributed-devg-v2-gaussdb/gaussdb-12-0405.html#ZH-CN_TOPIC_0000002222888889)
#### 优化建议
- analyse \| analyze
  - 不支持在事务或匿名块中执行analyze 。
  
  - 不支持在函数或存储过程中执行analyze操作。
   
 
