DBE_PLDEBUGGER Schema
DBE_PLDEBUGGER Schema下的系统函数用于调试存储过程,仅管理员有权限执行这些调试接口,但无修改和创建新函数的权限。目前支持的接口及其描述如下所示。
- 当在函数体中创建用户时,调用attach、next、continue、info_code、step、info_breakpoint、backtrace、finish中会返回密码的明文。因此不建议用户在函数体中创建用户。
- 仅支持在CN节点上调试存储过程,并且调试端和被调试端需连接在同一CN节点。
- 调试端和被调试端需连接在同一database,否则使用函数oid获取函数信息的接口将不可用。
- 用户在当前会话使用dbe_pldebugger.turn_on函数开启存储过程调试后,当前会话的所有PL/SQL类型存储过程将不能下推至DN节点。因此,请在调试结束后,及时使用dbe_pldebugger.turn_off函数关闭当前会话的存储过程。
- 不支持直接调试触发器,不支持EXECUTE DIRECT ON将语句下发至DN节点触发调试。
- 在使用dbe_pldebugger.turn_on函数开启存储过程调试前生成的预编译语句可能无法被调试。
- dbe_pldebugger.error_*类型函数,只能在报错断住时才能使用。
- 当存储过程调试时,如果被调试的存储过程中涉及加锁的操作,请注意在调试端勿执行可能导致死锁的操作。
对应权限角色为gs_role_pldebugger,可以由管理员用户通过如下命令将debugger权限赋权给该用户。
GRANT gs_role_pldebugger to user;
需要有两个客户端连接数据库,一个客户端负责执行调试接口作为debug端,另一个客户端执行调试函数,控制server端存储过程执行。示例如下:
- 准备调试
通过PG_PROC,查找到待调试存储过程的oid,并执行DBE_PLDEBUGGER.turn_on(oid)。本客户端会作为server端使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
gaussdb=# CREATE OR REPLACE PROCEDURE test_debug ( IN x INT) AS BEGIN INSERT INTO t1 (a) VALUES (x); DELETE FROM t1 WHERE a = x; END; / CREATE PROCEDURE gaussdb=# SELECT OID FROM PG_PROC WHERE PRONAME='test_debug'; oid ------- 16389 (1 row) gaussdb=# SELECT * FROM DBE_PLDEBUGGER.turn_on(16389); nodename | port ----------+------ datanode | 0 (1 row)
- 开始调试
server端执行存储过程,会在存储过程内第一条SQL语句前hang住,等待debug端发送的调试消息。仅支持直接执行存储过程的调试,不支持通过trigger调用执行的存储过程调试。
1
gaussdb=# call test_debug(1);
再起一个客户端,作为debug端,通过turn_on返回的数据,调用DBE_PLDEBUGGER.attach关联到该存储过程上进行调试。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.attach('datanode',0); funcoid | funcname | lineno | query ---------+------------+--------+---------------------------------- 16389 | test_debug | 3 | INSERT INTO t1 (a) VALUES (x); (1 row)
在执行attach的客户端调试,执行下一条statement。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.next(); funcoid | funcname | lineno | query ---------+------------+--------+---------------------- 16389 | test_debug | 0 | [EXECUTION FINISHED] (1 row)
在执行attach的客户端调试,可以执行以下变量操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.info_locals(); --打印全部变量 varname | vartype | value | isconst ---------+---------+-------+--------- x | int4 | 1 | f (1 row) gaussdb=# SELECT * FROM DBE_PLDEBUGGER.set_var('x', 2); --变量赋值 set_var --------- t (1 row) gaussdb=# SELECT * FROM DBE_PLDEBUGGER.print_var('x'); --打印单个变量 varname | vartype | value | isconst ---------+---------+-------+--------- x | int4 | 2 | f (1 row)
直接执行完成当前正在调试的存储过程。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.continue(); funcoid | funcname | lineno | query ---------+------------+--------+---------------------- 16389 | test_debug | 0 | [EXECUTION FINISHED] (1 row)
当存储过程报错时,会出现以下提示,此时进入报错断住逻辑。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.continue(); funcoid | funcname | lineno | query ---------+------------+--------+------------------------------- 16389 | test_debug | 0 | [EXECUTION HAS ERROR OCCURRED!] (1 row)
此时进入报错断住逻辑,可以调用error_info_locals,error_backtrace,error_end,print_var接口查看信息,其他接口不能再使用,需要使用error_end结束当前报错断住。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.error_end(); funcoid | funcname | lineno | query ---------+------------+--------+------------------ 16389 | test_debug | 0 | [END HANG ERROR!] (1 row)
直接退出当前正在调试的存储过程(报错断住逻辑不可用),不执行尚未执行的语句。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.abort(); abort ------- t (1 row)
client端查看代码信息并识别可以设置断点行号。
1 2 3 4 5 6 7 8 9 10 11
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.info_code(16389); lineno | query | canbreak --------+-----------------------------------------------------------+---------- | CREATE OR REPLACE PROCEDURE public.test_debug( IN x INT) | f 1 | AS DECLARE | f 2 | BEGIN | f 3 | INSERT INTO t1 (a) VALUES (x); | t 4 | DELETE FROM t1 WHERE a = x; | t 5 | END; | f 6 | / | f (7 rows)
设置断点。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.add_breakpoint(16389,4); breakpointno -------------- 0 (1 row)
查看断点信息。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.info_breakpoints(); breakpointno | funcoid | lineno | query | enable --------------+---------+--------+---------------------------------+-------- 0 | 16389 | 4 | DELETE FROM t1 WHERE a = x; | t (1 row)
执行至断点。
1 2 3 4 5
gaussdb=# SELECT * FROM DBE_PLDEBUGGER.continue(); funcoid | funcname | lineno | query ---------+------------+--------+--------------------------------- 16389 | test_debug | 4 | DELETE FROM t1 WHERE a = x; (1 row)
存储过程执行结束后,调试会自动退出,再进行调试需要重新attach关联。如果server端不需要继续调试,可执行turn_off关闭,或退出session。具体调试接口如表1所示。
表1 DBE_PLDEBUGGER 接口名称
描述
server端调用,标记存储过程可以调试,调用后执行该存储过程时会hang住等待调试信息。
server端调用,标记存储过程关闭调试。
server端调用,打印本session内所有已turn_on的存储过程。
debug端调用,关联到正在调试存储过程。
debug端调用,打印正在调试的存储过程中的变量当前值。
debug端调用,单步执行。
debug端调用,继续执行,直到断点或存储过程结束。
debug端调用,停止调试,server端报错长跳转。
debug端调用,打印正在调试的存储过程中指定的变量当前值。
debug和server端都可以调用,打印指定存储过程的源语句和各行对应的行号。
debug端调用,单步进入执行。
debug端调用,新增断点。
debug端调用,删除断点。
debug端调用,查看当前的所有断点。
debug端调用,查看当前的调用栈。
debug端调用,激活被禁用的断点。
debug端调用,禁用已激活的断点。
debug端调用,继续调试,直到断点或返回上一层调用栈。
debug端调用,为变量进行赋值操作。
- DBE_PLDEBUGGER.turn_on
- DBE_PLDEBUGGER.turn_off
- DBE_PLDEBUGGER.local_debug_server_info
- DBE_PLDEBUGGER.attach
- DBE_PLDEBUGGER.info_locals
- DBE_PLDEBUGGER.next
- DBE_PLDEBUGGER.continue
- DBE_PLDEBUGGER.abort
- DBE_PLDEBUGGER.print_var
- DBE_PLDEBUGGER.info_code
- DBE_PLDEBUGGER.step
- DBE_PLDEBUGGER.add_breakpoint
- DBE_PLDEBUGGER.delete_breakpoint
- DBE_PLDEBUGGER.info_breakpoints
- DBE_PLDEBUGGER.backtrace
- DBE_PLDEBUGGER.enable_breakpoint
- DBE_PLDEBUGGER.disable_breakpoint
- DBE_PLDEBUGGER.finish
- DBE_PLDEBUGGER.set_var
- DBE_PLDEBUGGER.backtrace
- DBE_PLDEBUGGER.error_end
- DBE_PLDEBUGGER.error_info_locals