Commit d85cb272 authored by Bruce Momjian's avatar Bruce Momjian

ProcessUtility_hook:

Add ProcessUtility_hook() to handle all DDL to contrib/pg_stat_statements.

Itagaki Takahiro
parent 29fd97d9
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* Copyright (c) 2008-2009, PostgreSQL Global Development Group * Copyright (c) 2008-2009, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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 @@ ...@@ -24,6 +24,7 @@
#include "access/hash.h" #include "access/hash.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/copy.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "executor/instrument.h" #include "executor/instrument.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
...@@ -32,6 +33,7 @@ ...@@ -32,6 +33,7 @@
#include "storage/fd.h" #include "storage/fd.h"
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/spin.h" #include "storage/spin.h"
#include "tcop/utility.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
#include "utils/guc.h" #include "utils/guc.h"
...@@ -113,6 +115,7 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL; ...@@ -113,6 +115,7 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
static ExecutorStart_hook_type prev_ExecutorStart = NULL; static ExecutorStart_hook_type prev_ExecutorStart = NULL;
static ExecutorRun_hook_type prev_ExecutorRun = NULL; static ExecutorRun_hook_type prev_ExecutorRun = NULL;
static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; static ExecutorEnd_hook_type prev_ExecutorEnd = NULL;
static ProcessUtility_hook_type prev_ProcessUtility = NULL;
/* Links to shared memory state */ /* Links to shared memory state */
static pgssSharedState *pgss = NULL; static pgssSharedState *pgss = NULL;
...@@ -124,10 +127,11 @@ typedef enum ...@@ -124,10 +127,11 @@ typedef enum
{ {
PGSS_TRACK_NONE, /* track no statements */ PGSS_TRACK_NONE, /* track no statements */
PGSS_TRACK_TOP, /* only top level 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; } PGSSTrackLevel;
static const struct config_enum_entry track_options[] = { static const struct config_enum_entry track_options[] =
{
{"none", PGSS_TRACK_NONE, false}, {"none", PGSS_TRACK_NONE, false},
{"top", PGSS_TRACK_TOP, false}, {"top", PGSS_TRACK_TOP, false},
{"all", PGSS_TRACK_ALL, false}, {"all", PGSS_TRACK_ALL, false},
...@@ -136,6 +140,7 @@ static const struct config_enum_entry track_options[] = { ...@@ -136,6 +140,7 @@ static const struct config_enum_entry track_options[] = {
static int pgss_max; /* max # statements to track */ static int pgss_max; /* max # statements to track */
static int pgss_track; /* tracking level */ 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 */ static bool pgss_save; /* whether to save stats across shutdown */
...@@ -146,7 +151,9 @@ 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 ----*/ /*---- Function declarations ----*/
void _PG_init(void); void _PG_init(void);
#ifdef NOT_USED
void _PG_fini(void); void _PG_fini(void);
#endif
Datum pg_stat_statements_reset(PG_FUNCTION_ARGS); Datum pg_stat_statements_reset(PG_FUNCTION_ARGS);
Datum pg_stat_statements(PG_FUNCTION_ARGS); Datum pg_stat_statements(PG_FUNCTION_ARGS);
...@@ -161,10 +168,12 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc, ...@@ -161,10 +168,12 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, ScanDirection direction,
long count); long count);
static void pgss_ExecutorEnd(QueryDesc *queryDesc); 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 uint32 pgss_hash_fn(const void *key, Size keysize);
static int pgss_match_fn(const void *key1, const void *key2, Size keysize); static int pgss_match_fn(const void *key1, const void *key2, Size keysize);
static void pgss_store(const char *query, static void pgss_store(const char *query, double total_time, uint64 rows);
const Instrumentation *instr, uint32 rows);
static Size pgss_memsize(void); static Size pgss_memsize(void);
static pgssEntry *entry_alloc(pgssHashKey *key); static pgssEntry *entry_alloc(pgssHashKey *key);
static void entry_dealloc(void); static void entry_dealloc(void);
...@@ -214,6 +223,16 @@ _PG_init(void) ...@@ -214,6 +223,16 @@ _PG_init(void)
NULL, NULL,
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", DefineCustomBoolVariable("pg_stat_statements.save",
"Save pg_stat_statements statistics across server shutdowns.", "Save pg_stat_statements statistics across server shutdowns.",
NULL, NULL,
...@@ -245,8 +264,11 @@ _PG_init(void) ...@@ -245,8 +264,11 @@ _PG_init(void)
ExecutorRun_hook = pgss_ExecutorRun; ExecutorRun_hook = pgss_ExecutorRun;
prev_ExecutorEnd = ExecutorEnd_hook; prev_ExecutorEnd = ExecutorEnd_hook;
ExecutorEnd_hook = pgss_ExecutorEnd; ExecutorEnd_hook = pgss_ExecutorEnd;
prev_ProcessUtility = ProcessUtility_hook;
ProcessUtility_hook = pgss_ProcessUtility;
} }
#ifdef NOT_USED
/* /*
* Module unload callback * Module unload callback
*/ */
...@@ -257,8 +279,10 @@ _PG_fini(void) ...@@ -257,8 +279,10 @@ _PG_fini(void)
ExecutorStart_hook = prev_ExecutorStart; ExecutorStart_hook = prev_ExecutorStart;
ExecutorRun_hook = prev_ExecutorRun; ExecutorRun_hook = prev_ExecutorRun;
ExecutorEnd_hook = prev_ExecutorEnd; ExecutorEnd_hook = prev_ExecutorEnd;
ProcessUtility_hook = prev_ProcessUtility;
shmem_startup_hook = prev_shmem_startup_hook; shmem_startup_hook = prev_shmem_startup_hook;
} }
#endif
/* /*
* shmem_startup hook: allocate or attach to shared memory, * shmem_startup hook: allocate or attach to shared memory,
...@@ -539,7 +563,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) ...@@ -539,7 +563,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
InstrEndLoop(queryDesc->totaltime); InstrEndLoop(queryDesc->totaltime);
pgss_store(queryDesc->sourceText, pgss_store(queryDesc->sourceText,
queryDesc->totaltime, queryDesc->totaltime->total,
queryDesc->estate->es_processed); queryDesc->estate->es_processed);
} }
...@@ -549,6 +573,59 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) ...@@ -549,6 +573,59 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
standard_ExecutorEnd(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 * Calculate hash value for a key
*/ */
...@@ -587,7 +664,7 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize) ...@@ -587,7 +664,7 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize)
* Store some statistics for a statement. * Store some statistics for a statement.
*/ */
static void static void
pgss_store(const char *query, const Instrumentation *instr, uint32 rows) pgss_store(const char *query, double total_time, uint64 rows)
{ {
pgssHashKey key; pgssHashKey key;
double usage; double usage;
...@@ -631,7 +708,7 @@ pgss_store(const char *query, const Instrumentation *instr, uint32 rows) ...@@ -631,7 +708,7 @@ pgss_store(const char *query, const Instrumentation *instr, uint32 rows)
SpinLockAcquire(&e->mutex); SpinLockAcquire(&e->mutex);
e->counters.calls += 1; e->counters.calls += 1;
e->counters.total_time += instr->total; e->counters.total_time += total_time;
e->counters.rows += rows; e->counters.rows += rows;
e->counters.usage += usage; e->counters.usage += usage;
SpinLockRelease(&e->mutex); SpinLockRelease(&e->mutex);
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgstatstatements.sgml,v 1.2 2009/05/18 11:08:24 petere Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/pgstatstatements.sgml,v 1.3 2009/12/01 01:08:46 momjian Exp $ -->
<sect1 id="pgstatstatements"> <sect1 id="pgstatstatements">
<title>pg_stat_statements</title> <title>pg_stat_statements</title>
...@@ -174,6 +174,23 @@ ...@@ -174,6 +174,23 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<varname>pg_stat_statements.track_ddl</varname> (<type>boolean</type>)
</term>
<listitem>
<para>
<varname>pg_stat_statements.track_ddl</varname> controls whether DDL
commands are counted by the module.
Specify <literal>on</> to track DDL commands, which excludes <command>SELECT</>,
<command>INSERT</>, <command>UPDATE</> and <command>DELETE</> statements.
The default value is <literal>on</>.
Only superusers can change this setting.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<varname>pg_stat_statements.save</varname> (<type>boolean</type>) <varname>pg_stat_statements.save</varname> (<type>boolean</type>)
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -58,6 +58,9 @@
#include "utils/syscache.h" #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. * Verify user has ownership of specified relation, else ereport.
* *
...@@ -244,6 +247,10 @@ check_xact_readonly(Node *parsetree) ...@@ -244,6 +247,10 @@ check_xact_readonly(Node *parsetree)
* completionTag is only set nonempty if we want to return a nondefault status. * 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. * 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 void
ProcessUtility(Node *parsetree, ProcessUtility(Node *parsetree,
...@@ -260,6 +267,20 @@ ProcessUtility(Node *parsetree, ...@@ -260,6 +267,20 @@ ProcessUtility(Node *parsetree,
if (completionTag) if (completionTag)
completionTag[0] = '\0'; 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)) switch (nodeTag(parsetree))
{ {
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -17,9 +17,18 @@
#include "tcop/tcopprot.h" #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, extern void ProcessUtility(Node *parsetree, const char *queryString,
ParamListInfo params, bool isTopLevel, ParamListInfo params, bool isTopLevel,
DestReceiver *dest, char *completionTag); 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); extern bool UtilityReturnsTuples(Node *parsetree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment