diff -cprN head/contrib/pg_stat_statements/pg_stat_statements.c work/contrib/pg_stat_statements/pg_stat_statements.c
*** head/contrib/pg_stat_statements/pg_stat_statements.c 2009-12-01 11:31:11.000000000 +0900
--- work/contrib/pg_stat_statements/pg_stat_statements.c 2009-12-03 15:58:32.193677809 +0900
***************
*** 32,37 ****
--- 32,38 ----
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/spin.h"
+ #include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/guc.h"
*************** static shmem_startup_hook_type prev_shme
*** 113,118 ****
--- 114,120 ----
static ExecutorStart_hook_type prev_ExecutorStart = NULL;
static ExecutorRun_hook_type prev_ExecutorRun = NULL;
static ExecutorEnd_hook_type prev_ExecutorEnd = NULL;
+ static ProcessUtility_hook_type prev_ProcessUtility = NULL;
/* Links to shared memory state */
static pgssSharedState *pgss = NULL;
*************** typedef enum
*** 124,133 ****
{
PGSS_TRACK_NONE, /* track no statements */
PGSS_TRACK_TOP, /* only top level statements */
! PGSS_TRACK_ALL, /* all statements, including nested ones */
} PGSSTrackLevel;
! static const struct config_enum_entry track_options[] = {
{"none", PGSS_TRACK_NONE, false},
{"top", PGSS_TRACK_TOP, false},
{"all", PGSS_TRACK_ALL, false},
--- 126,136 ----
{
PGSS_TRACK_NONE, /* track no statements */
PGSS_TRACK_TOP, /* only top level statements */
! PGSS_TRACK_ALL /* all statements, including nested ones */
} PGSSTrackLevel;
! static const struct config_enum_entry track_options[] =
! {
{"none", PGSS_TRACK_NONE, false},
{"top", PGSS_TRACK_TOP, false},
{"all", PGSS_TRACK_ALL, false},
*************** static const struct config_enum_entry tr
*** 136,141 ****
--- 139,145 ----
static int pgss_max; /* max # statements to track */
static int pgss_track; /* tracking level */
+ static bool pgss_track_utility; /* whether to track utility commands */
static bool pgss_save; /* whether to save stats across shutdown */
*************** static bool pgss_save; /* whether to s
*** 146,152 ****
--- 150,158 ----
/*---- Function declarations ----*/
void _PG_init(void);
+ #ifdef NOT_USED
void _PG_fini(void);
+ #endif
Datum pg_stat_statements_reset(PG_FUNCTION_ARGS);
Datum pg_stat_statements(PG_FUNCTION_ARGS);
*************** static void pgss_ExecutorRun(QueryDesc *
*** 161,170 ****
ScanDirection direction,
long count);
static void pgss_ExecutorEnd(QueryDesc *queryDesc);
static uint32 pgss_hash_fn(const void *key, Size keysize);
static int pgss_match_fn(const void *key1, const void *key2, Size keysize);
! static void pgss_store(const char *query,
! const Instrumentation *instr, uint32 rows);
static Size pgss_memsize(void);
static pgssEntry *entry_alloc(pgssHashKey *key);
static void entry_dealloc(void);
--- 167,178 ----
ScanDirection direction,
long count);
static void pgss_ExecutorEnd(QueryDesc *queryDesc);
+ static void pgss_ProcessUtility(Node *parsetree,
+ const char *queryString, ParamListInfo params, bool isTopLevel,
+ DestReceiver *dest, char *completionTag);
static uint32 pgss_hash_fn(const void *key, Size keysize);
static int pgss_match_fn(const void *key1, const void *key2, Size keysize);
! static void pgss_store(const char *query, double total_time, uint64 rows);
static Size pgss_memsize(void);
static pgssEntry *entry_alloc(pgssHashKey *key);
static void entry_dealloc(void);
*************** _PG_init(void)
*** 214,219 ****
--- 222,237 ----
NULL,
NULL);
+ DefineCustomBoolVariable("pg_stat_statements.track_utility",
+ "Selects whether utility commands are tracked by pg_stat_statements.",
+ NULL,
+ &pgss_track_utility,
+ true,
+ PGC_SUSET,
+ 0,
+ NULL,
+ NULL);
+
DefineCustomBoolVariable("pg_stat_statements.save",
"Save pg_stat_statements statistics across server shutdowns.",
NULL,
*************** _PG_init(void)
*** 245,252 ****
--- 263,273 ----
ExecutorRun_hook = pgss_ExecutorRun;
prev_ExecutorEnd = ExecutorEnd_hook;
ExecutorEnd_hook = pgss_ExecutorEnd;
+ prev_ProcessUtility = ProcessUtility_hook;
+ ProcessUtility_hook = pgss_ProcessUtility;
}
+ #ifdef NOT_USED
/*
* Module unload callback
*/
*************** _PG_fini(void)
*** 257,264 ****
--- 278,287 ----
ExecutorStart_hook = prev_ExecutorStart;
ExecutorRun_hook = prev_ExecutorRun;
ExecutorEnd_hook = prev_ExecutorEnd;
+ ProcessUtility_hook = prev_ProcessUtility;
shmem_startup_hook = prev_shmem_startup_hook;
}
+ #endif
/*
* shmem_startup hook: allocate or attach to shared memory,
*************** pgss_ExecutorEnd(QueryDesc *queryDesc)
*** 539,545 ****
InstrEndLoop(queryDesc->totaltime);
pgss_store(queryDesc->sourceText,
! queryDesc->totaltime,
queryDesc->estate->es_processed);
}
--- 562,568 ----
InstrEndLoop(queryDesc->totaltime);
pgss_store(queryDesc->sourceText,
! queryDesc->totaltime->total,
queryDesc->estate->es_processed);
}
*************** pgss_ExecutorEnd(QueryDesc *queryDesc)
*** 550,555 ****
--- 573,633 ----
}
/*
+ * ProcessUtility hook
+ */
+ static void
+ pgss_ProcessUtility(Node *parsetree, const char *queryString,
+ ParamListInfo params, bool isTopLevel,
+ DestReceiver *dest, char *completionTag)
+ {
+ if (pgss_track_utility && pgss_enabled())
+ {
+ instr_time start;
+ instr_time duration;
+ uint64 rows = 0;
+ Oid oid;
+
+ INSTR_TIME_SET_CURRENT(start);
+
+ nested_level++;
+ PG_TRY();
+ {
+ if (prev_ProcessUtility)
+ prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+ else
+ standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+ nested_level--;
+ }
+ PG_CATCH();
+ {
+ nested_level--;
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+
+ INSTR_TIME_SET_CURRENT(duration);
+ INSTR_TIME_SUBTRACT(duration, start);
+
+ /* parse command tag to retrieve the number of affected rows. */
+ if (completionTag &&
+ sscanf(completionTag, "COPY " UINT64_FORMAT, &rows) != 1 &&
+ sscanf(completionTag, "INSERT %u " UINT64_FORMAT, &oid, &rows) != 2 &&
+ sscanf(completionTag, "UPDATE " UINT64_FORMAT, &rows) != 1 &&
+ sscanf(completionTag, "DELETE " UINT64_FORMAT, &rows) != 1)
+ rows = 0;
+
+ pgss_store(queryString, INSTR_TIME_GET_DOUBLE(duration), rows);
+ }
+ else
+ {
+ if (prev_ProcessUtility)
+ prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+ else
+ standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+ }
+ }
+
+ /*
* Calculate hash value for a key
*/
static uint32
*************** pgss_match_fn(const void *key1, const vo
*** 587,593 ****
* Store some statistics for a statement.
*/
static void
! pgss_store(const char *query, const Instrumentation *instr, uint32 rows)
{
pgssHashKey key;
double usage;
--- 665,671 ----
* Store some statistics for a statement.
*/
static void
! pgss_store(const char *query, double total_time, uint64 rows)
{
pgssHashKey key;
double usage;
*************** pgss_store(const char *query, const Inst
*** 631,637 ****
SpinLockAcquire(&e->mutex);
e->counters.calls += 1;
! e->counters.total_time += instr->total;
e->counters.rows += rows;
e->counters.usage += usage;
SpinLockRelease(&e->mutex);
--- 709,715 ----
SpinLockAcquire(&e->mutex);
e->counters.calls += 1;
! e->counters.total_time += total_time;
e->counters.rows += rows;
e->counters.usage += usage;
SpinLockRelease(&e->mutex);
diff -cprN head/doc/src/sgml/pgstatstatements.sgml work/doc/src/sgml/pgstatstatements.sgml
*** head/doc/src/sgml/pgstatstatements.sgml 2009-12-01 11:31:11.000000000 +0900
--- work/doc/src/sgml/pgstatstatements.sgml 2009-12-03 15:46:39.570991107 +0900
***************
*** 176,181 ****
--- 176,198 ----
+ pg_stat_statements.track_utility (boolean)
+
+
+
+
+ pg_stat_statements.track_utility controls whether
+ utility commands are counted by the module.
+ Specify on> to track utility commands, which excludes
+ SELECT>, INSERT>, UPDATE> and
+ DELETE> statements. The default value is on>.
+ Only superusers can change this setting.
+
+
+
+
+
+
pg_stat_statements.save (boolean)
diff -cprN head/src/backend/tcop/utility.c work/src/backend/tcop/utility.c
*** head/src/backend/tcop/utility.c 2009-12-01 11:31:12.000000000 +0900
--- work/src/backend/tcop/utility.c 2009-12-03 15:30:58.080722572 +0900
***************
*** 58,63 ****
--- 58,66 ----
#include "utils/syscache.h"
+ /* Hooks for plugins to get control in ProcessUtility() */
+ ProcessUtility_hook_type ProcessUtility_hook = NULL;
+
/*
* Verify user has ownership of specified relation, else ereport.
*
*************** check_xact_readonly(Node *parsetree)
*** 244,249 ****
--- 247,256 ----
* completionTag is only set nonempty if we want to return a nondefault status.
*
* completionTag may be NULL if caller doesn't want a status string.
+ *
+ * We provide a function hook variable that lets loadable plugins
+ * get control when ProcessUtility is called. Such a plugin would
+ * normally call standard_ProcessUtility().
*/
void
ProcessUtility(Node *parsetree,
*************** ProcessUtility(Node *parsetree,
*** 257,262 ****
--- 264,283 ----
check_xact_readonly(parsetree);
+ if (ProcessUtility_hook)
+ (*ProcessUtility_hook) (parsetree, queryString, params, isTopLevel, dest, completionTag);
+ else
+ standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
+ }
+
+ void
+ standard_ProcessUtility(Node *parsetree,
+ const char *queryString,
+ ParamListInfo params,
+ bool isTopLevel,
+ DestReceiver *dest,
+ char *completionTag)
+ {
if (completionTag)
completionTag[0] = '\0';
diff -cprN head/src/include/tcop/utility.h work/src/include/tcop/utility.h
*** head/src/include/tcop/utility.h 2009-12-01 11:31:13.000000000 +0900
--- work/src/include/tcop/utility.h 2009-12-03 15:29:27.339986023 +0900
***************
*** 17,25 ****
--- 17,34 ----
#include "tcop/tcopprot.h"
+ /* Hook for plugins to get control in ProcessUtility() */
+ typedef void (*ProcessUtility_hook_type) (Node *parsetree,
+ const char *queryString, ParamListInfo params, bool isTopLevel,
+ DestReceiver *dest, char *completionTag);
+ extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
+
extern void ProcessUtility(Node *parsetree, const char *queryString,
ParamListInfo params, bool isTopLevel,
DestReceiver *dest, char *completionTag);
+ extern void standard_ProcessUtility(Node *parsetree, const char *queryString,
+ ParamListInfo params, bool isTopLevel,
+ DestReceiver *dest, char *completionTag);
extern bool UtilityReturnsTuples(Node *parsetree);