Skip to content

Commit 355865c

Browse files
committed
Add hooks to allow debugging and performance measurement plugins
to instrument PL/pgSQL. Korry Douglas
1 parent abc3120 commit 355865c

File tree

3 files changed

+105
-3
lines changed

3 files changed

+105
-3
lines changed

src/pl/plpgsql/src/pl_exec.c

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.175 2006/08/14 21:14:41 tgl Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.176 2006/08/15 19:01:17 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -252,6 +252,12 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
252252
*/
253253
exec_set_found(&estate, false);
254254

255+
/*
256+
* Let the instrumentation plugin peek at this function
257+
*/
258+
if (*plugin_ptr && (*plugin_ptr)->func_beg)
259+
((*plugin_ptr)->func_beg)(&estate, func);
260+
255261
/*
256262
* Now call the toplevel block of statements
257263
*/
@@ -387,6 +393,12 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
387393
}
388394
}
389395

396+
/*
397+
* Let the instrumentation plugin peek at this function
398+
*/
399+
if (*plugin_ptr && (*plugin_ptr)->func_end)
400+
((*plugin_ptr)->func_end)(&estate, func);
401+
390402
/* Clean up any leftover temporary memory */
391403
FreeExprContext(estate.eval_econtext);
392404
estate.eval_econtext = NULL;
@@ -580,6 +592,12 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
580592
*/
581593
exec_set_found(&estate, false);
582594

595+
/*
596+
* Let the instrumentation plugin peek at this function
597+
*/
598+
if (*plugin_ptr && (*plugin_ptr)->func_beg)
599+
((*plugin_ptr)->func_beg)(&estate, func);
600+
583601
/*
584602
* Now call the toplevel block of statements
585603
*/
@@ -633,6 +651,12 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
633651
rettup = SPI_copytuple((HeapTuple) (estate.retval));
634652
}
635653

654+
/*
655+
* Let the instrumentation plugin peek at this function
656+
*/
657+
if (*plugin_ptr && (*plugin_ptr)->func_end)
658+
((*plugin_ptr)->func_end)(&estate, func);
659+
636660
/* Clean up any leftover temporary memory */
637661
FreeExprContext(estate.eval_econtext);
638662
estate.eval_econtext = NULL;
@@ -1037,6 +1061,10 @@ exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
10371061
save_estmt = estate->err_stmt;
10381062
estate->err_stmt = stmt;
10391063

1064+
/* Let the plugin know that we are about to execute this statement */
1065+
if (*plugin_ptr && (*plugin_ptr)->stmt_beg)
1066+
((*plugin_ptr)->stmt_beg)(estate, stmt);
1067+
10401068
CHECK_FOR_INTERRUPTS();
10411069

10421070
switch (stmt->cmd_type)
@@ -1122,6 +1150,10 @@ exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
11221150
elog(ERROR, "unrecognized cmdtype: %d", stmt->cmd_type);
11231151
}
11241152

1153+
/* Let the plugin know that we have finished executing this statement */
1154+
if (*plugin_ptr && (*plugin_ptr)->stmt_end)
1155+
((*plugin_ptr)->stmt_end)(estate, stmt);
1156+
11251157
estate->err_stmt = save_estmt;
11261158

11271159
return rc;
@@ -2123,6 +2155,21 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
21232155
* child of simple_eval_estate.
21242156
*/
21252157
estate->eval_econtext = CreateExprContext(simple_eval_estate);
2158+
2159+
/*
2160+
* Let the plugin see this function before we initialize any
2161+
* local PL/pgSQL variables - note that we also give the plugin
2162+
* a few function pointers so it can call back into PL/pgSQL
2163+
* for doing things like variable assignments and stack traces
2164+
*/
2165+
if (*plugin_ptr)
2166+
{
2167+
(*plugin_ptr)->error_callback = plpgsql_exec_error_callback;
2168+
(*plugin_ptr)->assign_expr = exec_assign_expr;
2169+
2170+
if ((*plugin_ptr)->func_setup)
2171+
((*plugin_ptr)->func_setup)(estate, func);
2172+
}
21262173
}
21272174

21282175
/* ----------

src/pl/plpgsql/src/pl_handler.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.30 2006/08/08 19:15:09 tgl Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.31 2006/08/15 19:01:17 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -28,6 +28,8 @@ extern DLLIMPORT bool check_function_bodies;
2828

2929
PG_MODULE_MAGIC;
3030

31+
PLpgSQL_plugin **plugin_ptr = NULL;
32+
3133

3234
/*
3335
* _PG_init() - library load-time initialization
@@ -46,6 +48,9 @@ _PG_init(void)
4648
plpgsql_HashTableInit();
4749
RegisterXactCallback(plpgsql_xact_cb, NULL);
4850

51+
/* Set up a rendezvous point with optional instrumentation plugin */
52+
plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
53+
4954
inited = true;
5055
}
5156

src/pl/plpgsql/src/plpgsql.h

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.79 2006/08/14 21:14:41 tgl Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.80 2006/08/15 19:01:17 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -617,9 +617,57 @@ typedef struct
617617
PLpgSQL_function *err_func; /* current func */
618618
PLpgSQL_stmt *err_stmt; /* current stmt */
619619
const char *err_text; /* additional state info */
620+
void *plugin_info; /* reserved for use by optional plugin */
620621
} PLpgSQL_execstate;
621622

622623

624+
/*
625+
* A PLpgSQL_plugin structure represents an instrumentation plugin.
626+
* To instrument PL/pgSQL, a plugin library must access the rendezvous
627+
* variable "PLpgSQL_plugin" and set it to point to a PLpgSQL_plugin struct.
628+
* Typically the struct could just be static data in the plugin library.
629+
* We expect that a plugin would do this at library load time (_PG_init()).
630+
* It must also be careful to set the rendezvous variable back to NULL
631+
* if it is unloaded (_PG_fini()).
632+
*
633+
* This structure is basically a collection of function pointers --- at
634+
* various interesting points in pl_exec.c, we call these functions
635+
* (if the pointers are non-NULL) to give the plugin a chance to watch
636+
* what we are doing.
637+
*
638+
* func_setup is called when we start a function, before we've initialized
639+
* the local variables defined by the function.
640+
*
641+
* func_beg is called when we start a function, after we've initialized
642+
* the local variables.
643+
*
644+
* func_end is called at the end of a function.
645+
*
646+
* stmt_beg and stmt_end are called before and after (respectively) each
647+
* statement.
648+
*
649+
* Also, immediately before any call to func_setup, PL/pgSQL fills in the
650+
* error_callback and assign_expr fields with pointers to its own
651+
* plpgsql_exec_error_callback and exec_assign_expr functions. This is
652+
* a somewhat ad-hoc expedient to simplify life for debugger plugins.
653+
*/
654+
655+
typedef struct
656+
{
657+
/* Function pointers set up by the plugin */
658+
void (*func_setup) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
659+
void (*func_beg) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
660+
void (*func_end) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
661+
void (*stmt_beg) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt);
662+
void (*stmt_end) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt);
663+
664+
/* Function pointers set by PL/pgSQL itself */
665+
void (*error_callback) (void *arg);
666+
void (*assign_expr) (PLpgSQL_execstate *estate, PLpgSQL_datum *target,
667+
PLpgSQL_expr *expr);
668+
} PLpgSQL_plugin;
669+
670+
623671
/**********************************************************************
624672
* Global variable declarations
625673
**********************************************************************/
@@ -641,6 +689,8 @@ extern PLpgSQL_function *plpgsql_curr_compile;
641689
extern bool plpgsql_check_syntax;
642690
extern MemoryContext compile_tmp_cxt;
643691

692+
extern PLpgSQL_plugin **plugin_ptr;
693+
644694
/**********************************************************************
645695
* Function declarations
646696
**********************************************************************/

0 commit comments

Comments
 (0)