如何在PostgreSQL中调试plpgsql存储过程(pldebugger, pldbgapi)

3 minute read

背景

PostgreSQL支持多种存储过程语言,例如plpgsql, C, plpython, plperl, pltcl, pljava, 等等。

用户可以使用这些存储过程语言,创建对应的函数或存储过程(returns void)。

那么如何调试PostgreSQL的存储过程呢?社区提供了一个插件pldebugger,可用于调试存储过程。

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

pldebugger介绍

  16 Installation  
  17 ------------  
  18   
  19 - Copy this directory to contrib/ in your PostgreSQL source tree.  
  20   
  21 - Run 'make; make install'  
  22   
  23 - Edit your postgresql.conf file, and modify the shared_preload_libraries config  
  24   option to look like:  
  25   
  26   shared_preload_libraries = '$libdir/plugin_debugger'  
  27   
  28 - Restart PostgreSQL for the new setting to take effect.  
  29   
  30 - Run the following command in the database or databases that you wish to  
  31   debug functions in:  
  32   
  33   CREATE EXTENSION pldbgapi;  
  34   
  35   (on server versions older than 9.1, you must instead run the pldbgapi--1.0.sql  
  36   script directly using psql).  
  37   
  38   
  39 Usage  
  40 -----  
  41   
  42 Connect pgAdmin to the database containing the functions you wish to debug.  
  43 Right-click the function to debug, and select Debugging->Debug to execute and  
  44 debug the function immediately, or select Debugging->Set Global Breakpoint to  
  45 set a breakpoint on the function. This will cause the debugger to wait for  
  46 another session (such as a backend servicing a web app) to execute the function  
  47 and allow you to debug in-context.  
  48   
  49 For further information, please see the pgAdmin documentation.  
  50   
  51   
  52 Troubleshooting  
  53 ---------------  
  54   
  55 The majority of problems we've encountered with the plugin are caused by  
  56 failing to add (or incorrectly adding) the debugger plugin library to the  
  57 shared_preload_libraries configuration directive in postgresql.conf (following  
  58 which, the server *must* be restarted). This will prevent global breakpoints  
  59 working on all platforms, and on some (notably Windows) may prevent the   
  60 pldbgapi.sql script from executing correctly.  
  61   
  62   
  63 Architecture  
  64 ------------  
  65   
  66 The debugger consists of three parts:  
  67   
  68 1. The client. This is typically a GUI displays the source code, current  
  69    stack frame, variables etc, and allows the user to set breakpoints and  
  70    step throught the code. The client can reside on a different host than  
  71    the database server.  
  72   
  73 2. The target backend. This is the backend that runs the code being debugged.  
  74    The plugin_debugger.so library must be loaded into the target backend.  
  75   
  76 3. Debugging proxy. This is another backend process that the client is  
  77    connected to. The API functions, pldbg_* in pldbgapi.so library, are  
  78    run in this backend.  
  79   
  80 The client is to connected to the debugging proxy using a regular libpq  
  81 connection. When a debugging session is active, the proxy is connected  
  82 to the target via a socket. The protocol between the proxy and the target  
  83 backend is not visible to others, and is subject to change. The pldbg_*  
  84 API functions form the public interface to the debugging facility.  
  85   
  86   
  87 debugger client  *------ libpq --------* Proxy backend  
  88   (pgAdmin)                                 *  
  89                                             |  
  90                                   pldebugger socket connection  
  91                                             |  
  92                                             *  
  93 application client *----- libpq -------* Target backend  

如果在编译pldebugger时遇到如下告警,可以修改一下pldbgapi.c

pldbgapi.c: In function ‘pldbg_get_stack’:  
pldbgapi.c:790:25: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘uint64 {aka long unsigned int}’ [-Wformat=]  
   sprintf( callCount, "%d", srf->call_cntr );  
                         ^  
  
修改如下  
  
                /*  
                 * frameString points to a string like:  
                 *      targetName:funcOID:lineNumber:arguments  
                 */  
                sprintf( callCount, "%zu", srf->call_cntr );  

pldebugger安装

1. 编译软件

git clone git://git.postgresql.org/git/pldebugger.git  
  
cd pldebugger  
  
export PATH=/home/digoal/pgsql9.6/bin:$PATH  
  
USE_PGXS=1 make clean  
USE_PGXS=1 make  
USE_PGXS=1 make install  

2. 修改配置

cd $PGDATA  
vi postgresql.conf  
  
shared_preload_libraries = '$libdir/plugin_debugger'  

3. 重启数据库

pg_ctl restart -m fast  

如何调试存储过程

1. 在需要调试存储过程的目标数据库中,安装pldbgapi插件

postgres=# create extension pldbgapi ;  
CREATE EXTENSION  

2. 创建被调试的测试代码(如果已经有目标函数了,请忽略此步骤)

create or replace function debugger_test (i int) returns int as $$    
declare    
v_result int;    
begin    
v_result := 0;    
if i<0 then    
  raise notice 'Please enter i >=0.';    
  raise exception '';    
end if;    
for x in 0..i loop    
v_result := v_result + x;    
end loop;    
return v_result;    
exception    
when others then    
  v_result := 0;    
  return v_result;    
end;    
$$ language plpgsql;   

3. 打开pgAdmin客户端,使用pgAdmin登陆到这个数据库, 右键点击函数,点击调试选项。

pic

pic

参考

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

Flag Counter

digoal’s 大量PostgreSQL文章入口