Skip to content

Commit d85cb27

Browse files
committed
ProcessUtility_hook:
Add ProcessUtility_hook() to handle all DDL to contrib/pg_stat_statements. Itagaki Takahiro
1 parent 29fd97d commit d85cb27

File tree

4 files changed

+135
-11
lines changed

4 files changed

+135
-11
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* Copyright (c) 2008-2009, PostgreSQL Global Development Group
1515
*
1616
* IDENTIFICATION
17-
* $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.5 2009/07/27 04:09:55 tgl Exp $
17+
* $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.6 2009/12/01 01:08:45 momjian Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -24,6 +24,7 @@
2424

2525
#include "access/hash.h"
2626
#include "catalog/pg_type.h"
27+
#include "commands/copy.h"
2728
#include "executor/executor.h"
2829
#include "executor/instrument.h"
2930
#include "mb/pg_wchar.h"
@@ -32,6 +33,7 @@
3233
#include "storage/fd.h"
3334
#include "storage/ipc.h"
3435
#include "storage/spin.h"
36+
#include "tcop/utility.h"
3537
#include "utils/builtins.h"
3638
#include "utils/hsearch.h"
3739
#include "utils/guc.h"
@@ -113,6 +115,7 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
113115
static ExecutorStart_hook_type prev_ExecutorStart = NULL;
114116
static ExecutorRun_hook_type prev_ExecutorRun = NULL;
115117
static ExecutorEnd_hook_type prev_ExecutorEnd = NULL;
118+
static ProcessUtility_hook_type prev_ProcessUtility = NULL;
116119

117120
/* Links to shared memory state */
118121
static pgssSharedState *pgss = NULL;
@@ -124,10 +127,11 @@ typedef enum
124127
{
125128
PGSS_TRACK_NONE, /* track no statements */
126129
PGSS_TRACK_TOP, /* only top level statements */
127-
PGSS_TRACK_ALL, /* all statements, including nested ones */
130+
PGSS_TRACK_ALL /* all statements, including nested ones */
128131
} PGSSTrackLevel;
129132

130-
static const struct config_enum_entry track_options[] = {
133+
static const struct config_enum_entry track_options[] =
134+
{
131135
{"none", PGSS_TRACK_NONE, false},
132136
{"top", PGSS_TRACK_TOP, false},
133137
{"all", PGSS_TRACK_ALL, false},
@@ -136,6 +140,7 @@ static const struct config_enum_entry track_options[] = {
136140

137141
static int pgss_max; /* max # statements to track */
138142
static int pgss_track; /* tracking level */
143+
static bool pgss_track_ddl; /* whether to track ddl commands */
139144
static bool pgss_save; /* whether to save stats across shutdown */
140145

141146

@@ -146,7 +151,9 @@ static bool pgss_save; /* whether to save stats across shutdown */
146151
/*---- Function declarations ----*/
147152

148153
void _PG_init(void);
154+
#ifdef NOT_USED
149155
void _PG_fini(void);
156+
#endif
150157

151158
Datum pg_stat_statements_reset(PG_FUNCTION_ARGS);
152159
Datum pg_stat_statements(PG_FUNCTION_ARGS);
@@ -161,10 +168,12 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc,
161168
ScanDirection direction,
162169
long count);
163170
static void pgss_ExecutorEnd(QueryDesc *queryDesc);
171+
static void pgss_ProcessUtility(Node *parsetree,
172+
const char *queryString, ParamListInfo params, bool isTopLevel,
173+
DestReceiver *dest, char *completionTag);
164174
static uint32 pgss_hash_fn(const void *key, Size keysize);
165175
static int pgss_match_fn(const void *key1, const void *key2, Size keysize);
166-
static void pgss_store(const char *query,
167-
const Instrumentation *instr, uint32 rows);
176+
static void pgss_store(const char *query, double total_time, uint64 rows);
168177
static Size pgss_memsize(void);
169178
static pgssEntry *entry_alloc(pgssHashKey *key);
170179
static void entry_dealloc(void);
@@ -214,6 +223,16 @@ _PG_init(void)
214223
NULL,
215224
NULL);
216225

226+
DefineCustomBoolVariable("pg_stat_statements.track_ddl",
227+
"Selects whether DDL commands are tracked by pg_stat_statements.",
228+
NULL,
229+
&pgss_track_ddl,
230+
true,
231+
PGC_SUSET,
232+
0,
233+
NULL,
234+
NULL);
235+
217236
DefineCustomBoolVariable("pg_stat_statements.save",
218237
"Save pg_stat_statements statistics across server shutdowns.",
219238
NULL,
@@ -245,8 +264,11 @@ _PG_init(void)
245264
ExecutorRun_hook = pgss_ExecutorRun;
246265
prev_ExecutorEnd = ExecutorEnd_hook;
247266
ExecutorEnd_hook = pgss_ExecutorEnd;
267+
prev_ProcessUtility = ProcessUtility_hook;
268+
ProcessUtility_hook = pgss_ProcessUtility;
248269
}
249270

271+
#ifdef NOT_USED
250272
/*
251273
* Module unload callback
252274
*/
@@ -257,8 +279,10 @@ _PG_fini(void)
257279
ExecutorStart_hook = prev_ExecutorStart;
258280
ExecutorRun_hook = prev_ExecutorRun;
259281
ExecutorEnd_hook = prev_ExecutorEnd;
282+
ProcessUtility_hook = prev_ProcessUtility;
260283
shmem_startup_hook = prev_shmem_startup_hook;
261284
}
285+
#endif
262286

263287
/*
264288
* shmem_startup hook: allocate or attach to shared memory,
@@ -539,7 +563,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
539563
InstrEndLoop(queryDesc->totaltime);
540564

541565
pgss_store(queryDesc->sourceText,
542-
queryDesc->totaltime,
566+
queryDesc->totaltime->total,
543567
queryDesc->estate->es_processed);
544568
}
545569

@@ -549,6 +573,59 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
549573
standard_ExecutorEnd(queryDesc);
550574
}
551575

576+
/*
577+
* ProcessUtility hook
578+
*/
579+
static void
580+
pgss_ProcessUtility(Node *parsetree, const char *queryString,
581+
ParamListInfo params, bool isTopLevel,
582+
DestReceiver *dest, char *completionTag)
583+
{
584+
if (pgss_track_ddl && isTopLevel && pgss_enabled())
585+
{
586+
instr_time start;
587+
instr_time duration;
588+
uint64 rows = 0;
589+
590+
INSTR_TIME_SET_CURRENT(start);
591+
592+
nested_level++;
593+
PG_TRY();
594+
{
595+
if (prev_ProcessUtility)
596+
prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
597+
else if ((nodeTag(parsetree)) == T_CopyStmt)
598+
{
599+
rows = DoCopy((CopyStmt *) parsetree, queryString);
600+
if (completionTag)
601+
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
602+
"COPY " UINT64_FORMAT, rows);
603+
}
604+
else
605+
standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
606+
nested_level--;
607+
}
608+
PG_CATCH();
609+
{
610+
nested_level--;
611+
PG_RE_THROW();
612+
}
613+
PG_END_TRY();
614+
615+
INSTR_TIME_SET_CURRENT(duration);
616+
INSTR_TIME_SUBTRACT(duration, start);
617+
618+
pgss_store(queryString, INSTR_TIME_GET_DOUBLE(duration), rows);
619+
}
620+
else
621+
{
622+
if (prev_ProcessUtility)
623+
prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
624+
else
625+
standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
626+
}
627+
}
628+
552629
/*
553630
* Calculate hash value for a key
554631
*/
@@ -587,7 +664,7 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize)
587664
* Store some statistics for a statement.
588665
*/
589666
static void
590-
pgss_store(const char *query, const Instrumentation *instr, uint32 rows)
667+
pgss_store(const char *query, double total_time, uint64 rows)
591668
{
592669
pgssHashKey key;
593670
double usage;
@@ -631,7 +708,7 @@ pgss_store(const char *query, const Instrumentation *instr, uint32 rows)
631708

632709
SpinLockAcquire(&e->mutex);
633710
e->counters.calls += 1;
634-
e->counters.total_time += instr->total;
711+
e->counters.total_time += total_time;
635712
e->counters.rows += rows;
636713
e->counters.usage += usage;
637714
SpinLockRelease(&e->mutex);

doc/src/sgml/pgstatstatements.sgml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgstatstatements.sgml,v 1.2 2009/05/18 11:08:24 petere Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/pgstatstatements.sgml,v 1.3 2009/12/01 01:08:46 momjian Exp $ -->
22

33
<sect1 id="pgstatstatements">
44
<title>pg_stat_statements</title>
@@ -174,6 +174,23 @@
174174
</listitem>
175175
</varlistentry>
176176

177+
<varlistentry>
178+
<term>
179+
<varname>pg_stat_statements.track_ddl</varname> (<type>boolean</type>)
180+
</term>
181+
182+
<listitem>
183+
<para>
184+
<varname>pg_stat_statements.track_ddl</varname> controls whether DDL
185+
commands are counted by the module.
186+
Specify <literal>on</> to track DDL commands, which excludes <command>SELECT</>,
187+
<command>INSERT</>, <command>UPDATE</> and <command>DELETE</> statements.
188+
The default value is <literal>on</>.
189+
Only superusers can change this setting.
190+
</para>
191+
</listitem>
192+
</varlistentry>
193+
177194
<varlistentry>
178195
<term>
179196
<varname>pg_stat_statements.save</varname> (<type>boolean</type>)

src/backend/tcop/utility.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.318 2009/11/20 20:38:11 tgl Exp $
13+
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.319 2009/12/01 01:08:46 momjian Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -58,6 +58,9 @@
5858
#include "utils/syscache.h"
5959

6060

61+
/* Hooks for plugins to get control in ProcessUtility() */
62+
ProcessUtility_hook_type ProcessUtility_hook = NULL;
63+
6164
/*
6265
* Verify user has ownership of specified relation, else ereport.
6366
*
@@ -244,6 +247,10 @@ check_xact_readonly(Node *parsetree)
244247
* completionTag is only set nonempty if we want to return a nondefault status.
245248
*
246249
* completionTag may be NULL if caller doesn't want a status string.
250+
*
251+
* We provide a function hook variable that lets loadable plugins
252+
* get control when ProcessUtility is called. Such a plugin would
253+
* normally call standard_ProcessUtility().
247254
*/
248255
void
249256
ProcessUtility(Node *parsetree,
@@ -260,6 +267,20 @@ ProcessUtility(Node *parsetree,
260267
if (completionTag)
261268
completionTag[0] = '\0';
262269

270+
if (ProcessUtility_hook)
271+
(*ProcessUtility_hook) (parsetree, queryString, params, isTopLevel, dest, completionTag);
272+
else
273+
standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag);
274+
}
275+
276+
void
277+
standard_ProcessUtility(Node *parsetree,
278+
const char *queryString,
279+
ParamListInfo params,
280+
bool isTopLevel,
281+
DestReceiver *dest,
282+
char *completionTag)
283+
{
263284
switch (nodeTag(parsetree))
264285
{
265286
/*

src/include/tcop/utility.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.35 2009/01/01 17:24:01 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.36 2009/12/01 01:08:46 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -17,9 +17,18 @@
1717
#include "tcop/tcopprot.h"
1818

1919

20+
/* Hook for plugins to get control in ProcessUtility() */
21+
typedef void (*ProcessUtility_hook_type) (Node *parsetree,
22+
const char *queryString, ParamListInfo params, bool isTopLevel,
23+
DestReceiver *dest, char *completionTag);
24+
extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;
25+
2026
extern void ProcessUtility(Node *parsetree, const char *queryString,
2127
ParamListInfo params, bool isTopLevel,
2228
DestReceiver *dest, char *completionTag);
29+
extern void standard_ProcessUtility(Node *parsetree, const char *queryString,
30+
ParamListInfo params, bool isTopLevel,
31+
DestReceiver *dest, char *completionTag);
2332

2433
extern bool UtilityReturnsTuples(Node *parsetree);
2534

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy