*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.175 2006/08/14 21:14:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.176 2006/08/15 19:01:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
exec_set_found(&estate, false);
+ /*
+ * Let the instrumentation plugin peek at this function
+ */
+ if (*plugin_ptr && (*plugin_ptr)->func_beg)
+ ((*plugin_ptr)->func_beg)(&estate, func);
+
/*
* Now call the toplevel block of statements
*/
}
}
+ /*
+ * Let the instrumentation plugin peek at this function
+ */
+ if (*plugin_ptr && (*plugin_ptr)->func_end)
+ ((*plugin_ptr)->func_end)(&estate, func);
+
/* Clean up any leftover temporary memory */
FreeExprContext(estate.eval_econtext);
estate.eval_econtext = NULL;
*/
exec_set_found(&estate, false);
+ /*
+ * Let the instrumentation plugin peek at this function
+ */
+ if (*plugin_ptr && (*plugin_ptr)->func_beg)
+ ((*plugin_ptr)->func_beg)(&estate, func);
+
/*
* Now call the toplevel block of statements
*/
rettup = SPI_copytuple((HeapTuple) (estate.retval));
}
+ /*
+ * Let the instrumentation plugin peek at this function
+ */
+ if (*plugin_ptr && (*plugin_ptr)->func_end)
+ ((*plugin_ptr)->func_end)(&estate, func);
+
/* Clean up any leftover temporary memory */
FreeExprContext(estate.eval_econtext);
estate.eval_econtext = NULL;
save_estmt = estate->err_stmt;
estate->err_stmt = stmt;
+ /* Let the plugin know that we are about to execute this statement */
+ if (*plugin_ptr && (*plugin_ptr)->stmt_beg)
+ ((*plugin_ptr)->stmt_beg)(estate, stmt);
+
CHECK_FOR_INTERRUPTS();
switch (stmt->cmd_type)
elog(ERROR, "unrecognized cmdtype: %d", stmt->cmd_type);
}
+ /* Let the plugin know that we have finished executing this statement */
+ if (*plugin_ptr && (*plugin_ptr)->stmt_end)
+ ((*plugin_ptr)->stmt_end)(estate, stmt);
+
estate->err_stmt = save_estmt;
return rc;
* child of simple_eval_estate.
*/
estate->eval_econtext = CreateExprContext(simple_eval_estate);
+
+ /*
+ * Let the plugin see this function before we initialize any
+ * local PL/pgSQL variables - note that we also give the plugin
+ * a few function pointers so it can call back into PL/pgSQL
+ * for doing things like variable assignments and stack traces
+ */
+ if (*plugin_ptr)
+ {
+ (*plugin_ptr)->error_callback = plpgsql_exec_error_callback;
+ (*plugin_ptr)->assign_expr = exec_assign_expr;
+
+ if ((*plugin_ptr)->func_setup)
+ ((*plugin_ptr)->func_setup)(estate, func);
+ }
}
/* ----------
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.30 2006/08/08 19:15:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.31 2006/08/15 19:01:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
PG_MODULE_MAGIC;
+PLpgSQL_plugin **plugin_ptr = NULL;
+
/*
* _PG_init() - library load-time initialization
plpgsql_HashTableInit();
RegisterXactCallback(plpgsql_xact_cb, NULL);
+ /* Set up a rendezvous point with optional instrumentation plugin */
+ plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
+
inited = true;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.79 2006/08/14 21:14:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.80 2006/08/15 19:01:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
PLpgSQL_function *err_func; /* current func */
PLpgSQL_stmt *err_stmt; /* current stmt */
const char *err_text; /* additional state info */
+ void *plugin_info; /* reserved for use by optional plugin */
} PLpgSQL_execstate;
+/*
+ * A PLpgSQL_plugin structure represents an instrumentation plugin.
+ * To instrument PL/pgSQL, a plugin library must access the rendezvous
+ * variable "PLpgSQL_plugin" and set it to point to a PLpgSQL_plugin struct.
+ * Typically the struct could just be static data in the plugin library.
+ * We expect that a plugin would do this at library load time (_PG_init()).
+ * It must also be careful to set the rendezvous variable back to NULL
+ * if it is unloaded (_PG_fini()).
+ *
+ * This structure is basically a collection of function pointers --- at
+ * various interesting points in pl_exec.c, we call these functions
+ * (if the pointers are non-NULL) to give the plugin a chance to watch
+ * what we are doing.
+ *
+ * func_setup is called when we start a function, before we've initialized
+ * the local variables defined by the function.
+ *
+ * func_beg is called when we start a function, after we've initialized
+ * the local variables.
+ *
+ * func_end is called at the end of a function.
+ *
+ * stmt_beg and stmt_end are called before and after (respectively) each
+ * statement.
+ *
+ * Also, immediately before any call to func_setup, PL/pgSQL fills in the
+ * error_callback and assign_expr fields with pointers to its own
+ * plpgsql_exec_error_callback and exec_assign_expr functions. This is
+ * a somewhat ad-hoc expedient to simplify life for debugger plugins.
+ */
+
+typedef struct
+{
+ /* Function pointers set up by the plugin */
+ void (*func_setup) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
+ void (*func_beg) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
+ void (*func_end) (PLpgSQL_execstate *estate, PLpgSQL_function *func);
+ void (*stmt_beg) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt);
+ void (*stmt_end) (PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt);
+
+ /* Function pointers set by PL/pgSQL itself */
+ void (*error_callback) (void *arg);
+ void (*assign_expr) (PLpgSQL_execstate *estate, PLpgSQL_datum *target,
+ PLpgSQL_expr *expr);
+} PLpgSQL_plugin;
+
+
/**********************************************************************
* Global variable declarations
**********************************************************************/
extern bool plpgsql_check_syntax;
extern MemoryContext compile_tmp_cxt;
+extern PLpgSQL_plugin **plugin_ptr;
+
/**********************************************************************
* Function declarations
**********************************************************************/