]> granicus.if.org Git - postgresql/commitdiff
Add hooks to allow debugging and performance measurement plugins
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 15 Aug 2006 19:01:17 +0000 (19:01 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 15 Aug 2006 19:01:17 +0000 (19:01 +0000)
to instrument PL/pgSQL.  Korry Douglas

src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_handler.c
src/pl/plpgsql/src/plpgsql.h

index cf445a8a31d31b0a2c86b37ddf4773783b14b131..f8213d4a50fe34304bbc03083570dfbbad4cf6c8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -252,6 +252,12 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
         */
        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
         */
@@ -387,6 +393,12 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
                }
        }
 
+       /*
+        * 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;
@@ -580,6 +592,12 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
         */
        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
         */
@@ -633,6 +651,12 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
                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;
@@ -1037,6 +1061,10 @@ exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
        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)
@@ -1122,6 +1150,10 @@ exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
                        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;
@@ -2123,6 +2155,21 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
         * 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);
+       }
 }
 
 /* ----------
index 22264f5a2837aadc1accf8a09510bc12fdb82e3e..a0f2cb465503b2b04d846854fc547e0ae120d443 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,8 @@ extern DLLIMPORT bool check_function_bodies;
 
 PG_MODULE_MAGIC;
 
+PLpgSQL_plugin **plugin_ptr = NULL;
+
 
 /*
  * _PG_init()                  - library load-time initialization
@@ -46,6 +48,9 @@ _PG_init(void)
        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;
 }
 
index 1d53177f3220537b12fe949311b0a43019df0ccd..206f9b9875e78f6c4c4cfc678911867803b4f359 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -617,9 +617,57 @@ typedef struct
        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
  **********************************************************************/
@@ -641,6 +689,8 @@ extern PLpgSQL_function *plpgsql_curr_compile;
 extern bool plpgsql_check_syntax;
 extern MemoryContext compile_tmp_cxt;
 
+extern PLpgSQL_plugin **plugin_ptr;
+
 /**********************************************************************
  * Function declarations
  **********************************************************************/