Re: Has anyone tried out the PL/pgSQL debugger? - Mailing list pgsql-hackers

From korry.douglas
Subject Re: Has anyone tried out the PL/pgSQL debugger?
Date
Msg-id 46E0381C.1070508@enterprisedb.com
Whole thread Raw
In response to Has anyone tried out the PL/pgSQL debugger?  ("korry.douglas" <korry.douglas@enterprisedb.com>)
List pgsql-hackers
<br /><blockquote cite="mid:7F609BA8-0F18-460D-91F5-C19973E6B4E5@pgedit.com" type="cite">I would still like to see a
simpleexample using psql. I know you would not really use psql for this, but I think it would help a lot with getting
startedfor folks that want to use the debugger. I did not spend lots of time on it, but even after reading pldbgapi.c I
wasnot able to get simple session going (e.g. how to start a session and request the source for a procedure). <br
/></blockquote>Here's a simple example using psql (I will add this to the README file too).  In this example, we are
debugginga PL/pgSQL function named 'testwhere( x int)', just because I happen to have that function in front of me. 
'testwhere(x int )' is called the 'target function' - the backend process that executes testwhere(x int) is called the
'targetprocess'.  Since we are setting a "global" breakpoint, the first backend to trip across the target function will
becomethe target process (you can also set a breakpoint in a specific process if you want to be less annoying).<br
/><br/><tt>--- <br /> --- pldbg_get_target_info() is simply a convenience<br /> --- function that returns various
informationabout <br /> --- a potential target function/trigger. In particular,<br /> --- given a function signature
(orname in the absence <br /> --- of any ambiguity), pldbg_get_target_info() returns<br /> --- the OID of the
function.<br/> ---<br /><br /> test=# SELECT * FROM pldbg_get_target_info( 'testwhere', 'f' );<br />  target | schema |
nargs| argtypes | targetname | argmodes | argnames | targetlang |      fqname      | returnsset | returntype<br />
--------+--------+-------+----------+------------+----------+----------+------------+------------------+------------+------------<br
/>  26149 |   2200 |     1 | 26       | testwhere  |          | {x}      |      16944 | public.testwhere | f         
|        25<br /> (1 row)<br /><br /> ---<br /> --- Create a TCP port (OS-assigned address) where the <br /> --- target
processcan find us.  pldbg_create_listener()<br /> --- returns a handle that we have to give back to the <br /> ---
otherpldbg_xxx() functions (the first argument in <br /> --- the remaining function calls is the handle value<br /> ---
thatwe got from pldbg_create_listener()).<br /> ---<br /></tt><br /><tt>test=# SELECT * FROM
pldbg_create_listener();<br/>  pldbg_create_listener<br /> -----------------------<br />                      1<br />
(1row)<br /><br /> --- <br /> --- Now set a 'global' breakpoint on the target <br /> --- function (whose OID is
26149). The third <br /> --- argument, if given, specifies a line number<br /> --- within the target function.  The
lastargument<br /> --- specifies an (optional) target backend process ID.<br /> ---<br /> --- Since we are not
specifyinga particular backend <br /> --- process, we will trap the first server process to<br /> --- trip over our
breakpoint.<br/> ---<br /><br /> test=# SELECT * from pldbg_set_global_breakpoint(1, 26149, NULL, NULL);<br />
 pldbg_set_global_breakpoint<br/> -----------------------------<br />  t<br /> (1 row)<br /><br /> ---<br /> --- Now we
haveto wait for some other backend to trip<br /> --- over our breakpoint. When that happens, the target<br /> ---
processwill attach to the TCP port we created <br /> --- earlier.<br /> ---<br /><br /> test=# SELECT * FROM
pldbg_wait_for_target(1);<br/>  pldbg_wait_for_target<br /> -----------------------<br />                   8433<br />
(1row)<br /><br /><b>--- Now we can invoke the target function (testwhere() in this<br /> --- example) in some other
clientapplication, perhaps a second<br /> --- psql session.<br /> ---<br /> --- Note that the previous call to
pldbg_wait_for_target()<br/> --- will hang at this point.<br /> ---<br /></b><br /> ---<br /> --- And wait for the
attachedtarget to reach a <br /> --- breakpoint.  It may seem strange to have both<br /> --- pldbg_wait_for_target()
andpldbg_wait_for_breakpoint(),<br /> --- but we need two different functions when we are<br /> --- doing
direct-debugging.<br/> ---<br /> --- When the target reaches a breakpoint, pldbg_wait_for_breakpoint()<br /> ---
returnsthe OID of the function, the line number at which the <br /> --- the target is paused, and the name of the
targetfunction.<br /> --- <br /> test=# SELECT * FROM pldbg_wait_for_breakpoint(1);<br />  func  | linenumber |
targetname<br/> -------+------------+------------<br />  26149 |          5 | testwhere<br /> (1 row)<br /><br />
---<br/> --- When the target has paused, you can retrieve the <br /> --- source code for the target function...<br />
---<br/> test=# SELECT * FROM pldbg_get_source(1, 26149);<br />                       pldbg_get_source<br />
------------------------------------------------------------<br/><br />  declare<br />  \x09result text;<br />
 begin<br/>  \x09select into result proname from pg_proc where oid = x;<br />  \x09return result;<br />  end;<br /><br
/>(1 row)<br /><br /> ---<br /> --- You can also retrieve a list of all local variables<br /> --- and their current
values.<br/> ---<br /> --- You can also retrieve the call stack or a list of <br /> --- breakpoints.  And you can
changethe focus of the <br /> --- debugger to a different stack frame.<br /> ---<br /><br /> test=# SELECT * from
pldbg_get_variables(1);<br/>   name  | varclass | linenumber | isunique | isconst | isnotnull | dtype | value<br />
--------+----------+------------+----------+---------+-----------+-------+-------<br/>  x      | A        |          0
|t        | t       | f         |    26 | 60<br />  result | L        |          2 | t        | f       | f        
|   25 | NULL<br /> (2 rows)<br /><br /> ---<br /> --- To "step into", call pldbg_step_into(); notice that<br /> --- it
returnsa 'breakpoint' tuple to tell you where <br /> --- the target has paused.<br /> ---<br /> --- You could also call
pldbg_step_over(),pldbg_continue(),<br /> --- or pldbg_set_breakpoint() here.  <br /> ---<br /><br /> test=# SELECT *
frompldbg_step_into(1);<br />  func  | linenumber | targetname<br /> -------+------------+------------<br />  26149
|         6 | testwhere<br /> (1 row)<br /><br /> ---<br /> --- If you want to abort the target function, call <br />
---pldbg_abort_target(); the client application will<br /> --- see an error message (ERROR:  canceling statement <br />
---due to user request)<br /> ---<br /> test=# SELECT * FROM pldbg_abort_target(1);<br />  pldbg_abort_target<br />
--------------------<br/>  t<br /> (1 row)<br /></tt><br /><br /> That's a simple example showing the general flow for
in-contextdebugging.<br /><br />              -- Korry<br /><br /> 

pgsql-hackers by date:

Previous
From: Simon Riggs
Date:
Subject: Re: [FEATURE REQUEST] Streaming Onlinebackup (Maybe OFFTOPIC)
Next
From: apoc9009
Date:
Subject: Re: [FEATURE REQUEST] Streaming Onlinebackup (Maybe OFFTOPIC)