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.8 2009/12/15 04:57:46 rhaas Exp $
17+ * $PostgreSQL: pgsql/contrib/pg_stat_statements/pg_stat_statements.c,v 1.9 2009/12/1520: 04:49 tgl Exp $
1818 *
1919 *-------------------------------------------------------------------------
2020 */
3232#include "storage/fd.h"
3333#include "storage/ipc.h"
3434#include "storage/spin.h"
35+ #include "tcop/utility.h"
3536#include "utils/builtins.h"
3637#include "utils/hsearch.h"
3738#include "utils/guc.h"
@@ -113,6 +114,7 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
113114static ExecutorStart_hook_type prev_ExecutorStart = NULL ;
114115static ExecutorRun_hook_type prev_ExecutorRun = NULL ;
115116static ExecutorEnd_hook_type prev_ExecutorEnd = NULL ;
117+ static ProcessUtility_hook_type prev_ProcessUtility = NULL ;
116118
117119/* Links to shared memory state */
118120static pgssSharedState * pgss = NULL ;
@@ -124,7 +126,7 @@ typedef enum
124126{
125127PGSS_TRACK_NONE ,/* track no statements */
126128PGSS_TRACK_TOP ,/* only top level statements */
127- PGSS_TRACK_ALL , /* all statements, including nested ones */
129+ PGSS_TRACK_ALL /* all statements, including nested ones */
128130}PGSSTrackLevel ;
129131
130132static const struct config_enum_entry track_options []= {
@@ -136,6 +138,7 @@ static const struct config_enum_entry track_options[] = {
136138
137139static int pgss_max ;/* max # statements to track */
138140static int pgss_track ;/* tracking level */
141+ static bool pgss_track_utility ;/* whether to track utility commands */
139142static bool pgss_save ;/* whether to save stats across shutdown */
140143
141144
@@ -161,10 +164,12 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc,
161164ScanDirection direction ,
162165long count );
163166static void pgss_ExecutorEnd (QueryDesc * queryDesc );
167+ static void pgss_ProcessUtility (Node * parsetree ,
168+ const char * queryString ,ParamListInfo params ,bool isTopLevel ,
169+ DestReceiver * dest ,char * completionTag );
164170static uint32 pgss_hash_fn (const void * key ,Size keysize );
165171static 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 );
172+ static void pgss_store (const char * query ,double total_time ,uint64 rows );
168173static Size pgss_memsize (void );
169174static pgssEntry * entry_alloc (pgssHashKey * key );
170175static void entry_dealloc (void );
@@ -214,6 +219,16 @@ _PG_init(void)
214219NULL ,
215220NULL );
216221
222+ DefineCustomBoolVariable ("pg_stat_statements.track_utility" ,
223+ "Selects whether utility commands are tracked by pg_stat_statements." ,
224+ NULL ,
225+ & pgss_track_utility ,
226+ true,
227+ PGC_SUSET ,
228+ 0 ,
229+ NULL ,
230+ NULL );
231+
217232DefineCustomBoolVariable ("pg_stat_statements.save" ,
218233"Save pg_stat_statements statistics across server shutdowns." ,
219234NULL ,
@@ -245,6 +260,8 @@ _PG_init(void)
245260ExecutorRun_hook = pgss_ExecutorRun ;
246261prev_ExecutorEnd = ExecutorEnd_hook ;
247262ExecutorEnd_hook = pgss_ExecutorEnd ;
263+ prev_ProcessUtility = ProcessUtility_hook ;
264+ ProcessUtility_hook = pgss_ProcessUtility ;
248265}
249266
250267/*
@@ -254,10 +271,11 @@ void
254271_PG_fini (void )
255272{
256273/* Uninstall hooks. */
274+ shmem_startup_hook = prev_shmem_startup_hook ;
257275ExecutorStart_hook = prev_ExecutorStart ;
258276ExecutorRun_hook = prev_ExecutorRun ;
259277ExecutorEnd_hook = prev_ExecutorEnd ;
260- shmem_startup_hook = prev_shmem_startup_hook ;
278+ ProcessUtility_hook = prev_ProcessUtility ;
261279}
262280
263281/*
@@ -539,7 +557,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
539557InstrEndLoop (queryDesc -> totaltime );
540558
541559pgss_store (queryDesc -> sourceText ,
542- queryDesc -> totaltime ,
560+ queryDesc -> totaltime -> total ,
543561queryDesc -> estate -> es_processed );
544562}
545563
@@ -549,6 +567,61 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
549567standard_ExecutorEnd (queryDesc );
550568}
551569
570+ /*
571+ * ProcessUtility hook
572+ */
573+ static void
574+ pgss_ProcessUtility (Node * parsetree ,const char * queryString ,
575+ ParamListInfo params ,bool isTopLevel ,
576+ DestReceiver * dest ,char * completionTag )
577+ {
578+ if (pgss_track_utility && pgss_enabled ())
579+ {
580+ instr_time start ;
581+ instr_time duration ;
582+ uint64 rows = 0 ;
583+
584+ INSTR_TIME_SET_CURRENT (start );
585+
586+ nested_level ++ ;
587+ PG_TRY ();
588+ {
589+ if (prev_ProcessUtility )
590+ prev_ProcessUtility (parsetree ,queryString ,params ,
591+ isTopLevel ,dest ,completionTag );
592+ else
593+ standard_ProcessUtility (parsetree ,queryString ,params ,
594+ isTopLevel ,dest ,completionTag );
595+ nested_level -- ;
596+ }
597+ PG_CATCH ();
598+ {
599+ nested_level -- ;
600+ PG_RE_THROW ();
601+ }
602+ PG_END_TRY ();
603+
604+ INSTR_TIME_SET_CURRENT (duration );
605+ INSTR_TIME_SUBTRACT (duration ,start );
606+
607+ /* parse command tag to retrieve the number of affected rows. */
608+ if (completionTag &&
609+ sscanf (completionTag ,"COPY " UINT64_FORMAT ,& rows )!= 1 )
610+ rows = 0 ;
611+
612+ pgss_store (queryString ,INSTR_TIME_GET_DOUBLE (duration ),rows );
613+ }
614+ else
615+ {
616+ if (prev_ProcessUtility )
617+ prev_ProcessUtility (parsetree ,queryString ,params ,
618+ isTopLevel ,dest ,completionTag );
619+ else
620+ standard_ProcessUtility (parsetree ,queryString ,params ,
621+ isTopLevel ,dest ,completionTag );
622+ }
623+ }
624+
552625/*
553626 * Calculate hash value for a key
554627 */
@@ -587,7 +660,7 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize)
587660 * Store some statistics for a statement.
588661 */
589662static void
590- pgss_store (const char * query ,const Instrumentation * instr , uint32 rows )
663+ pgss_store (const char * query ,double total_time , uint64 rows )
591664{
592665pgssHashKey key ;
593666double usage ;
@@ -631,7 +704,7 @@ pgss_store(const char *query, const Instrumentation *instr, uint32 rows)
631704
632705SpinLockAcquire (& e -> mutex );
633706e -> counters .calls += 1 ;
634- e -> counters .total_time += instr -> total ;
707+ e -> counters .total_time += total_time ;
635708e -> counters .rows += rows ;
636709e -> counters .usage += usage ;
637710SpinLockRelease (& e -> mutex );