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: