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 */
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"
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;
113115static ExecutorStart_hook_type prev_ExecutorStart = NULL ;
114116static ExecutorRun_hook_type prev_ExecutorRun = NULL ;
115117static ExecutorEnd_hook_type prev_ExecutorEnd = NULL ;
118+ static ProcessUtility_hook_type prev_ProcessUtility = NULL ;
116119
117120/* Links to shared memory state */
118121static pgssSharedState * pgss = NULL ;
@@ -124,10 +127,11 @@ typedef enum
124127{
125128PGSS_TRACK_NONE ,/* track no statements */
126129PGSS_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
137141static int pgss_max ;/* max # statements to track */
138142static int pgss_track ;/* tracking level */
143+ static bool pgss_track_ddl ;/* whether to track ddl commands */
139144static 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
148153void _PG_init (void );
154+ #ifdef NOT_USED
149155void _PG_fini (void );
156+ #endif
150157
151158Datum pg_stat_statements_reset (PG_FUNCTION_ARGS );
152159Datum pg_stat_statements (PG_FUNCTION_ARGS );
@@ -161,10 +168,12 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc,
161168ScanDirection direction ,
162169long count );
163170static 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 );
164174static uint32 pgss_hash_fn (const void * key ,Size keysize );
165175static 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 );
168177static Size pgss_memsize (void );
169178static pgssEntry * entry_alloc (pgssHashKey * key );
170179static void entry_dealloc (void );
@@ -214,6 +223,16 @@ _PG_init(void)
214223NULL ,
215224NULL );
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+
217236DefineCustomBoolVariable ("pg_stat_statements.save" ,
218237"Save pg_stat_statements statistics across server shutdowns." ,
219238NULL ,
@@ -245,8 +264,11 @@ _PG_init(void)
245264ExecutorRun_hook = pgss_ExecutorRun ;
246265prev_ExecutorEnd = ExecutorEnd_hook ;
247266ExecutorEnd_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)
257279ExecutorStart_hook = prev_ExecutorStart ;
258280ExecutorRun_hook = prev_ExecutorRun ;
259281ExecutorEnd_hook = prev_ExecutorEnd ;
282+ ProcessUtility_hook = prev_ProcessUtility ;
260283shmem_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)
539563InstrEndLoop (queryDesc -> totaltime );
540564
541565pgss_store (queryDesc -> sourceText ,
542- queryDesc -> totaltime ,
566+ queryDesc -> totaltime -> total ,
543567queryDesc -> estate -> es_processed );
544568}
545569
@@ -549,6 +573,59 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
549573standard_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 */
589666static void
590- pgss_store (const char * query ,const Instrumentation * instr , uint32 rows )
667+ pgss_store (const char * query ,double total_time , uint64 rows )
591668{
592669pgssHashKey key ;
593670double usage ;
@@ -631,7 +708,7 @@ pgss_store(const char *query, const Instrumentation *instr, uint32 rows)
631708
632709SpinLockAcquire (& e -> mutex );
633710e -> counters .calls += 1 ;
634- e -> counters .total_time += instr -> total ;
711+ e -> counters .total_time += total_time ;
635712e -> counters .rows += rows ;
636713e -> counters .usage += usage ;
637714SpinLockRelease (& e -> mutex );