无参数的存储过程示例如下:

  1. (userid VARCHAR2(20),
  2. logdate date default sysdate);
  3. CREATE OR REPLACE PROCEDURE userlogin
  4. IS
  5. BEGIN
  6. INSERT INTO loghistory (userid) VALUES (USER);
  7. END;

存储过程建立完成后,用户通过授权可以在 OBClient 、OceanBase Developer Center 或第三方开发工具中来调用运行。

  1. obclient> select * from loghistory;
  2. Empty set (0.02 sec)
  3. obclient> BEGIN
  4. -> userlogin;
  5. -> END;
  6. -> /
  7. Query OK, 0 rows affected (0.03 sec)
  8. obclient> select * from loghistory;
  9. +--------+-----------+
  10. | USERID | LOGDATE |
  11. +--------+-----------+
  12. | HR | 27-SEP-20 |
  13. +--------+-----------+
  14. 1 row in set (0.00 sec)
  15. obclient> commit;
  16. Query OK, 0 rows affected (0.00 sec)

每个子程序属性只能在子程序声明中出现一次,并可以按任何顺序出现。属性位于子程序的 IS 或 AS 关键字之前。 该属性不能出现在嵌套子程序中。

程序包中只能出现 ACCESSIBLE BY 属性。 独立子程序在其声明中可能具有以下属性。

  • AUTHID 属性

  • ACCESSIBLE BY 子句

AUTHID

定义过程时可以定义 AUTHID 子句,来获取存储过程在运行时被授予哪个用户的权限。权限类型包括以下两种:

  • AUTHID DEFINER(定义者权限):默认情况下,存储过程的权限来自于所有者。

  • AUTHID CURRENT_USER(调用者权限):运行时被授予当前会话用户的权限,这可能和当前登录用户相同或不同(ALTER SESSION SET CURRENT_SCHEMA 可以改变调用者 schema)

如下示例为,用 HR 用户创建过程 userlogin,指定 AUTHID DEFINER。

  1. CREATE OR REPLACE PROCEDURE userlogin
  2. AUTHID DEFINER
  3. IS
  4. BEGIN
  5. INSERT INTO loghistory (userid) VALUES (USER);
  6. END;

HR 用户把 userlogin 的执行权限授予给其他用户,这样 scott 用户可以执行过程。

  1. obclient> select user from dual;
  2. +-------+
  3. | USER |
  4. +-------+
  5. | SCOTT |
  6. +-------+
  7. 1 row in set (0.00 sec)
  8. obclient> select * from loghistory;
  9. ORA-00942: table or view 'SCOTT.LOGHISTORY' does not exist
  10. obclient> select * from hr.loghistory;
  11. ORA-00942: table or view does not exist
  12. obclient> BEGIN
  13. -> hr.userlogin;
  14. -> END;
  15. -> /
  16. Query OK, 0 rows affected (0.02 sec)
  17. obclient> commit;
  18. Query OK, 0 rows affected (0.00 sec)

scott 用户通过运行 HR 用户创建的过程 userlogin 成功插入 hr.loghistory。说明 scott 用户在运行这个存储过程时,拥有的是 HR 的权限。

  1. obclient> select user from dual;
  2. +------+
  3. | USER |
  4. +------+
  5. | HR |
  6. +------+
  7. 1 row in set (0.00 sec)
  8. obclient> select * from hr.loghistory;
  9. | USERID | LOGDATE |
  10. +--------+-----------+
  11. | HR | 27-SEP-20 |
  12. | SCOTT | 27-SEP-20 |
  13. +--------+-----------+
  14. 2 rows in set (0.01 sec)

关于AUTHID CURRENT_USER子句。HR 用户用 AUTHID CURRENT_USER 子句重新定义过程 userlogin。

  1. CREATE OR REPLACE PROCEDURE userlogin
  2. AUTHID CURRENT_USER
  3. IS
  4. BEGIN
  5. INSERT INTO loghistory (userid) VALUES (USER);
  6. END;

scott 用户再次执行 userlogin 报错,因为 scott 没有访问 hr.loghistory 这张表的权限。用 scott 用户创建表 loghistory,可以执行成功,数据实际插入了 scott.loghistory。

ACCESSIBLE BY

ACCESSIBLE BY 可以约束一个对象的调用者。

访问者列表明确列出了可能具有访问权限的单元。 访问者列表可以在子程序包上定义。 除了在包本身(如果有)上可以定义的访问者列表之外,还支持表的自检。 该列表可能仅限制对子程序的访问,而不能扩展访问,以防止非必要的使用内部子程序。 例如,不支持将一个程序包重组为两个程序包:一个程序用于限制少数访问,另一个程序用于公开访问。

ACCESSIBLE BY 子句可用于对象类型、对象类型主体、包和子程序的声明中。

ACCESSIBLE BY 子句可以出现在以下 SQL 语句中:

  • ALTER TYPE 陈述式

  • CREATE FUNCTION 语句

  • 创建过程语句

  • 创建包声明

  • CREATE TYPE BODY 语句

语法如下:

  1. unit_kind:
  2. FUNCTION { $$[0] = SP_FUNCTION; }
  3. | PROCEDURE { $$[0] = SP_PROCEDURE; }
  4. | PACKAGE_P { $$[0] = SP_PACKAGE; }
  5. | TRIGGER { $$[0] = SP_TRIGGER; }
  6. | TYPE { $$[0] = SP_TYPE; }
  7. ;
  8. accessor:
  9. pl_schema_name
  10. {
  11. malloc_non_terminal_node($$, parse_ctx->mem_pool_, T_SP_ACCESSOR, 2, NULL, $1);
  12. }
  13. | unit_kind pl_schema_name
  14. {
  15. ParseNode *accessor_kind = NULL;
  16. malloc_terminal_node(accessor_kind, parse_ctx->mem_pool_, T_SP_ACCESSOR_KIND);
  17. accessor_kind->value_ = $1[0];
  18. malloc_non_terminal_node($$, parse_ctx->mem_pool_, T_SP_ACCESSOR, 2, accessor_kind, $2);
  19. }
  20. ;
  21. accessor_list:
  22. accessor_list ',' accessor
  23. {
  24. malloc_non_terminal_node($$, parse_ctx->mem_pool_, T_LINK_NODE, 2, $1, $3);
  25. }
  26. | accessor
  27. {
  28. $$ = $1;
  29. }
  30. ;
  31. accessible_by:
  32. ACCESSIBLE BY '(' accessor_list ')'
  33. {
  34. ParseNode *accessor_list = NULL;
  35. merge_nodes(accessor_list, parse_ctx->mem_pool_, T_SP_ACCESSOR_LIST, $4);
  36. malloc_non_terminal_node($$, parse_ctx->mem_pool_, T_SP_ACCESSIBLE_BY, 1, accessor_list);
  37. }
  38. ;

OceanBase 数据库支持自治事务。 自治事务独立于父事务存在,单独进行提交或者回滚而不会对父事务产生影响。

根据如下示例创建对象:

  1. -- 创建日志表
  2. CREATE TABLE logtable(
  3. username varchar2(20),
  4. date_time date,
  5. message varchar2(60)
  6. );
  7. CREATE TABLE demotable( N number );
  8. -- 创建拥有自制事务的过程
  9. CREATE OR REPLACE PROCEDURE log_message(p_message varchar2)
  10. AS
  11. PRAGMA AUTONOMOUS_TRANSACTION;
  12. BEGIN
  13. INSERT INTO logtable VALUES ( user, sysdate, p_message );
  14. COMMIT;
  15. END log_message;

接下来操作步骤如下:

  1. 调用 log_message 写日志。

  2. 在事务中插入 demotable。

  3. 调用 log_message 再次写一条日志。

  4. 回滚当前事务。

  1. obclient> SELECT * FROM logtable;
  2. Empty set (0.00 sec)
  3. obclient> SELECT * FROM demotable;
  4. Empty set (0.01 sec)
  5. obclient> BEGIN
  6. -> Log_message ('About to insert into demotable.');
  7. -> INSERT INTO demotable VALUES (1);
  8. -> Log_message ('Rollback the transaction.');
  9. -> ROLLBACK;
  10. -> END;
  11. -> /
  12. Query OK, 0 rows affected (0.05 sec)
  13. obclient> SELECT * FROM logtable;
  14. +----------+-----------+---------------------------------+
  15. | USERNAME | DATE_TIME | MESSAGE |
  16. +----------+-----------+---------------------------------+
  17. | HR | 28-SEP-20 | About to insert into demotable. |
  18. | HR | 28-SEP-20 | Rollback the transaction. |
  19. +----------+-----------+---------------------------------+
  20. 2 rows in set (0.00 sec)

如上示例中,对 demotable 的插入操作被回滚了,拥有自治事务的过程 log_message 只提交了自己的事务,向日志表里写入的数据。

重新创建过程 log_message,去除自治事务属性,查看数据库的行为。

再次执行上述过程:

  1. obclient> SELECT * FROM logtable;
  2. Empty set (0.01 sec)
  3. obclient> SELECT * FROM demotable;
  4. Empty set (0.01 sec)
  5. obclient> BEGIN
  6. -> Log_message ('About to insert into demotable.');
  7. -> INSERT INTO demotable VALUES (1);
  8. -> Log_message ('Rollback the transaction.');
  9. -> ROLLBACK;
  10. -> END;
  11. -> /
  12. Query OK, 0 rows affected (0.04 sec)
  13. obclient> SELECT * FROM logtable;
  14. +----------+-----------+---------------------------------+
  15. | USERNAME | DATE_TIME | MESSAGE |
  16. +----------+-----------+---------------------------------+
  17. | HR | 28-SEP-20 | About to insert into demotable. |
  18. | HR | 28-SEP-20 | Rollback the transaction. |
  19. +----------+-----------+---------------------------------+
  20. 2 rows in set (0.00 sec)
  21. obclient> SELECT * FROM demotable;
  22. +------+
  23. | N |
  24. +------+
  25. | 1 |
  26. +------+