暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL plpgsql debug - 黑屏|text|文本 模式调试存储过程

digoal 2020-07-15
1023

作者

digoal

日期

2020-07-15

标签

PostgreSQL , plpgsql , 函数 , 存储过程 , 调试 , debug


背景

pgadmin plpgsql存储过程调试依赖pldebugger插件:

https://git.postgresql.org/gitweb/?p=pldebugger.git;a=summary

实际上不需要pldebugger以及pgadmin图形化模式, 在text模式下也能调试存储过程.

如果不需要控制, 只是打印一下执行过程中的变量, 直接raise就可以.

例子:

```
create or replace function test() returns void as $$
declare
begin
for i in 1..10 loop
raise notice 'i: %', i;
end loop;
end;
$$ language plpgsql strict;

postgres=# select test();
NOTICE: i: 1
NOTICE: i: 2
NOTICE: i: 3
NOTICE: i: 4
NOTICE: i: 5
NOTICE: i: 6
NOTICE: i: 7
NOTICE: i: 8
NOTICE: i: 9
NOTICE: i: 10
test


(1 row)
```

如果需要加入控制, 可以使用如下设计方法:

1、断点控制表

每条记录代表一个断点, 通过更新状态字段的内容, 开或者关代表启用和停用断点.

2、断点控制函数

读取断点控制表的状态, 响应断点状态.

3、被调试函数

植入断点控制函数

开发者执行通过修改断点控制表的值来控制断点,

打印变量

例子:

外部控制表

create table bk ( n name primary key, -- 断点名称 status boolean default true -- true表示开启断点, false表示退出断点 );

内部控制表

create table bk_tmp ( -- 临时状态, 用于断点重复出现的情况 n name primary key, -- 断点名称 status boolean default true -- true表示开启断点, false表示退出断点 );

断点函数

```
create or replace function bkf(name) returns void as $$
declare
v_stat1 boolean;
v_stat2 boolean;
begin
select status into v_stat1 from bk where n=$1;
select status into v_stat2 from bk_tmp where n=$1;
if v_stat1 is null then
raise notice 'The % bk name not set, or bk deleted, will skip this bk and continue!', $1;
return;
end if;

if (v_stat1 is not null and v_stat2 is null) then
insert into bk_tmp values ($1) on conflict (n) do nothing;
end if;

loop
select status into v_stat1 from bk where n=$1; -- 查看当前断点状态
select status into v_stat2 from bk_tmp where n=$1; -- 查看当前断点状态

if v_stat1 <> v_stat2 then  -- 用户退出断点   
  update bk_tmp set status=v_stat1 where n=$1;   
  return;  -- 返回   
end if;

if v_stat1 is null then   -- 用户删除断点  
  delete from bk_tmp where n=$1;  
  raise notice 'The % bk deleted, exit this bk!', $1;  
  return;  
end if;

perform pg_sleep(1);  -- 睡眠

end loop;
end;
$$ language plpgsql strict;
```

打印变量 -- 可以支持, 需要查询pl stack context的接口.

修改变量 -- 可以支持, 需要修改pl stack context的接口.

暂时不支持以上两个接口, 所以打印应该放在主函数内.

调试如下函数, 植入断点, 在断点前打印你想了解的变量, 或者修改你想了解的变量.

create or replace function testf (int, int) returns boolean as $$ declare res int :=0; begin for i in $1..$2 loop res := i+res; raise notice 'res: %', res; -- 打印变量 perform bkf('testbk'); -- 使用testbk这个断点名称 end loop; if res >10000 then return true; else return false; end if; end; $$ language plpgsql strict;

在外部控制表插入断点名称

insert into bk values ('testbk');

执行函数, 查看断点效果

select testf(1,100);

效果如下:

postgres=# select testf(1,100); NOTICE: res: 1 中断 -- 遇到断点

update bk set status =not status where n='testbk'; -- 继续

继续 NOTICE: res: 3 中断

update bk set status =not status where n='testbk'; -- 继续

继续 NOTICE: res: 6 中断

delete from bk where n='testbk'; -- 删除断点

删除断点后得到如下效果:

```
...
NOTICE: The testbk bk deleted, exit this bk!
NOTICE: res: 21
NOTICE: The testbk bk name not set, or bk deleted, will skip this bk and continue!
NOTICE: res: 28
NOTICE: The testbk bk name not set, or bk deleted, will skip this bk and continue!
NOTICE: res: 36
...
NOTICE: res: 5050
NOTICE: The testbk bk name not set, or bk deleted, will skip this bk and continue!
testf


f
(1 row)
```

PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

9.9元购买3个月阿里云RDS PostgreSQL实例

PostgreSQL 解决方案集合

德哥 / digoal's github - 公益是一辈子的事.

digoal's wechat

文章转载自digoal,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论