From: Bruce Momjian Date: Tue, 1 Dec 2009 01:08:46 +0000 (+0000) Subject: ProcessUtility_hook: X-Git-Tag: REL8_5_ALPHA3~74 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d85cb27293a2bafb2f6f8c5d965cc8af33c4bf48;p=postgresql ProcessUtility_hook: Add ProcessUtility_hook() to handle all DDL to contrib/pg_stat_statements. Itagaki Takahiro --- diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index bf7d7f94fc..e1011f3fe0 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -14,7 +14,7 @@ * Copyright (c) 2008-2009, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.5 2009/07/27 04:09:55 tgl Exp $ + * $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.6 2009/12/01 01:08:45 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,7 @@ #include "access/hash.h" #include "catalog/pg_type.h" +#include "commands/copy.h" #include "executor/executor.h" #include "executor/instrument.h" #include "mb/pg_wchar.h" @@ -32,6 +33,7 @@ #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" @@ -113,6 +115,7 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL; 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; @@ -124,10 +127,11 @@ typedef enum { PGSS_TRACK_NONE, /* track no statements */ PGSS_TRACK_TOP, /* only top level statements */ - PGSS_TRACK_ALL, /* all statements, including nested ones */ + PGSS_TRACK_ALL /* all statements, including nested ones */ } PGSSTrackLevel; -static const struct config_enum_entry track_options[] = { +static const struct config_enum_entry track_options[] = +{ {"none", PGSS_TRACK_NONE, false}, {"top", PGSS_TRACK_TOP, false}, {"all", PGSS_TRACK_ALL, false}, @@ -136,6 +140,7 @@ static const struct config_enum_entry track_options[] = { static int pgss_max; /* max # statements to track */ static int pgss_track; /* tracking level */ +static bool pgss_track_ddl; /* whether to track ddl commands */ static bool pgss_save; /* whether to save stats across shutdown */ @@ -146,7 +151,9 @@ static bool pgss_save; /* whether to save stats across shutdown */ /*---- 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); @@ -161,10 +168,12 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc, 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, - const Instrumentation *instr, uint32 rows); +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); @@ -214,6 +223,16 @@ _PG_init(void) NULL, NULL); + DefineCustomBoolVariable("pg_stat_statements.track_ddl", + "Selects whether DDL commands are tracked by pg_stat_statements.", + NULL, + &pgss_track_ddl, + true, + PGC_SUSET, + 0, + NULL, + NULL); + DefineCustomBoolVariable("pg_stat_statements.save", "Save pg_stat_statements statistics across server shutdowns.", NULL, @@ -245,8 +264,11 @@ _PG_init(void) 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 */ @@ -257,8 +279,10 @@ _PG_fini(void) 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, @@ -539,7 +563,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) InstrEndLoop(queryDesc->totaltime); pgss_store(queryDesc->sourceText, - queryDesc->totaltime, + queryDesc->totaltime->total, queryDesc->estate->es_processed); } @@ -549,6 +573,59 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) standard_ExecutorEnd(queryDesc); } +/* + * ProcessUtility hook + */ +static void +pgss_ProcessUtility(Node *parsetree, const char *queryString, + ParamListInfo params, bool isTopLevel, + DestReceiver *dest, char *completionTag) +{ + if (pgss_track_ddl && isTopLevel && pgss_enabled()) + { + instr_time start; + instr_time duration; + uint64 rows = 0; + + INSTR_TIME_SET_CURRENT(start); + + nested_level++; + PG_TRY(); + { + if (prev_ProcessUtility) + prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); + else if ((nodeTag(parsetree)) == T_CopyStmt) + { + rows = DoCopy((CopyStmt *) parsetree, queryString); + if (completionTag) + snprintf(completionTag, COMPLETION_TAG_BUFSIZE, + "COPY " UINT64_FORMAT, rows); + } + 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); + + 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 */ @@ -587,7 +664,7 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize) * Store some statistics for a statement. */ static void -pgss_store(const char *query, const Instrumentation *instr, uint32 rows) +pgss_store(const char *query, double total_time, uint64 rows) { pgssHashKey key; double usage; @@ -631,7 +708,7 @@ pgss_store(const char *query, const Instrumentation *instr, uint32 rows) SpinLockAcquire(&e->mutex); e->counters.calls += 1; - e->counters.total_time += instr->total; + e->counters.total_time += total_time; e->counters.rows += rows; e->counters.usage += usage; SpinLockRelease(&e->mutex); diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml index 67e7256a4e..ffa2702537 100644 --- a/doc/src/sgml/pgstatstatements.sgml +++ b/doc/src/sgml/pgstatstatements.sgml @@ -1,4 +1,4 @@ - + pg_stat_statements @@ -174,6 +174,23 @@ + + + pg_stat_statements.track_ddl (boolean) + + + + + pg_stat_statements.track_ddl controls whether DDL + commands are counted by the module. + Specify on to track DDL 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 --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 42071bfb6c..67333b1796 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.318 2009/11/20 20:38:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.319 2009/12/01 01:08:46 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -58,6 +58,9 @@ #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. * @@ -244,6 +247,10 @@ check_xact_readonly(Node *parsetree) * 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, @@ -260,6 +267,20 @@ ProcessUtility(Node *parsetree, if (completionTag) completionTag[0] = '\0'; + 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) +{ switch (nodeTag(parsetree)) { /* diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h index d609b0ac4e..ce3ee1fb05 100644 --- a/src/include/tcop/utility.h +++ b/src/include/tcop/utility.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.35 2009/01/01 17:24:01 momjian Exp $ + * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.36 2009/12/01 01:08:46 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -17,9 +17,18 @@ #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);