Add support for an application_name parameter, which is displayed in
authorTom Lane
Sat, 28 Nov 2009 23:38:08 +0000 (23:38 +0000)
committerTom Lane
Sat, 28 Nov 2009 23:38:08 +0000 (23:38 +0000)
pg_stat_activity and recorded in log entries.

Dave Page, reviewed by Andres Freund

16 files changed:
doc/src/sgml/config.sgml
doc/src/sgml/libpq.sgml
doc/src/sgml/monitoring.sgml
src/backend/catalog/system_views.sql
src/backend/postmaster/pgstat.c
src/backend/utils/adt/pgstatfuncs.c
src/backend/utils/error/elog.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/pgstat.h
src/include/utils/guc.h
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/libpq-int.h
src/test/regress/expected/rules.out

index 2cb006fa7524d8f839ff5bde71e09cbbd7252b51..d5f55e0539bd6e9d45fd71caa183a005b518d952 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
   Server Configuration
@@ -2882,6 +2882,26 @@ local0.*    /var/log/postgresql
 
      
 
+     
+      application_name (string)
+      
+       application_name configuration parameter
+      
+      
+       
+        The application_name can be any string of less than
+        NAMEDATALEN characters (64 characters in a standard build).
+        It is typically set by an application upon connection to the server.
+        The name will be displayed in the pg_stat_activity view
+        and included in CSV log entries.  It can also be included in regular
+        log entries via the  parameter.
+        Only printable ASCII characters may be used in the
+        application_name value. Other characters will be
+        replaced with question marks (?).
+       
+      
+     
+
      
       debug_print_parse (boolean)
       debug_print_rewritten (boolean)
@@ -3049,7 +3069,7 @@ local0.*    /var/log/postgresql
          that are replaced with status information as outlined below.
          Unrecognized escapes are ignored. Other
          characters are copied straight to the log line. Some escapes are
-         only recognized by session processes, and do not apply to
+         only recognized by session processes, and are ignored by
          background processes such as the main server process.
          This parameter can only be set in the postgresql.conf
          file or on the server command line. The default is an empty string.
@@ -3064,6 +3084,11 @@ local0.*    /var/log/postgresql
              
             
            
+            
+             %a
+             Application name
+             yes
+            
             
              %u
              User name
@@ -3287,19 +3312,35 @@ FROM pg_stat_activity;
      Using CSV-Format Log Output
 
        
-        Including csvlog in the log_destination list 
-        provides a convenient way to import log files into a database table. 
+        Including csvlog in the log_destination list
+        provides a convenient way to import log files into a database table.
         This option emits log lines in comma-separated-value format,
-        with these columns: timestamp with milliseconds, user name, database
-        name, process ID, host:port number, session ID, per-session or -process line
-        number, command tag, session start time, virtual transaction ID,
-        regular transaction id, error severity, SQL state code, error message,
-        error message detail, hint, internal query that led to the error (if
-        any), character count of the error position thereof, error context,
+        with these columns:
+        timestamp with milliseconds,
+        user name,
+        database name,
+        process ID,
+        client host:port number,
+        session ID,
+        per-session line number,
+        command tag,
+        session start time,
+        virtual transaction ID,
+        regular transaction ID,
+        error severity,
+        SQL state code,
+        error message,
+        error message detail,
+        hint,
+        internal query that led to the error (if any),
+        character count of the error position therein,
+        error context,
         user query that led to the error (if any and enabled by
-        log_min_error_statement), character count of the error
-        position thereof, location of the error in the PostgreSQL source code
-        (if log_error_verbosity is set to verbose).
+        log_min_error_statement),
+        character count of the error position therein,
+        location of the error in the PostgreSQL source code
+        (if log_error_verbosity is set to verbose),
+        and application name.
         Here is a sample table definition for storing CSV-format log output:
 
 
@@ -3327,6 +3368,7 @@ CREATE TABLE postgres_log
   query text,
   query_pos integer,
   location text,
+  application_name text,
   PRIMARY KEY (session_id, session_line_num)
 );
 
index 85ba6dadd1ddfed2e8ddfe19cb5e2866727261f1..b93e381b1e65b907a56b779f532671e3ed07f33e 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  <application>libpq</application> - C Library
          
         
 
+        
+         application_name
+         
+          
+           Specifies a value for the 
+           configuration parameter.
+          
+         
+        
+
+        
+         fallback_application_name
+         
+          
+           Specifies a fallback value for the 
+           linkend="guc-application-name"> configuration parameter.
+           This value will be used if no value has been given for
+           application_name via a connection parameter or the
+           PGAPPNAME environment variable.  Specifying
+           a fallback name is useful in generic utility programs that
+           wish to set a default application name but allow it to be
+           overridden by the user.
+          
+         
+        
+
         
          tty
          
@@ -5672,7 +5698,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGHOST
       
-      PGHOST behaves the same as 
+      PGHOST behaves the same as the 
       linkend="libpq-connect-host"> connection parameter.
      
     
@@ -5682,7 +5708,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGHOSTADDR
       
-      PGHOSTADDR behaves the same as 
+      PGHOSTADDR behaves the same as the 
       linkend="libpq-connect-hostaddr"> connection parameter.
       This can be set instead of or in addition to PGHOST
       to avoid DNS lookup overhead.
@@ -5694,7 +5720,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGPORT
       
-      PGPORT behaves the same as 
+      PGPORT behaves the same as the 
       linkend="libpq-connect-port"> connection parameter.
      
     
@@ -5704,7 +5730,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGDATABASE
       
-      PGDATABASE behaves the same as 
+      PGDATABASE behaves the same as the 
       linkend="libpq-connect-dbname"> connection parameter.
       
     
@@ -5714,9 +5740,8 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGUSER
       
-      PGUSER behaves the same as 
+      PGUSER behaves the same as the 
       linkend="libpq-connect-user"> connection parameter.
-      database.
      
     
 
@@ -5725,12 +5750,12 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGPASSWORD
       
-      PGPASSWORD behaves the same as 
+      PGPASSWORD behaves the same as the 
       linkend="libpq-connect-password"> connection parameter.
       Use of this environment variable
-      is not recommended for security reasons (some operating systems
+      is not recommended for security reasons, as some operating systems
       allow non-root users to see process environment variables via
-      ps); instead consider using the
+      ps; instead consider using the
       ~/.pgpass file (see ).
      
     
@@ -5751,7 +5776,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGSERVICE
       
-      PGSERVICE behaves the same as 
+      PGSERVICE behaves the same as the 
       linkend="libpq-connect-service"> connection parameter.
      
     
@@ -5777,17 +5802,27 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGOPTIONS
       
-      PGOPTIONS behaves the same as 
+      PGOPTIONS behaves the same as the 
       linkend="libpq-connect-options"> connection parameter.
      
     
 
+    
+     
+      
+       PGAPPNAME
+      
+      PGAPPNAME behaves the same as the 
+      linkend="libpq-connect-application-name"> connection parameter.
+     
+    
+
     
      
       
        PGSSLMODE
       
-      PGSSLMODE behaves the same as 
+      PGSSLMODE behaves the same as the 
       linkend="libpq-connect-sslmode"> connection parameter.
      
     
@@ -5797,7 +5832,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGREQUIRESSL
       
-      PGREQUIRESSL behaves the same as 
+      PGREQUIRESSL behaves the same as the 
       linkend="libpq-connect-requiressl"> connection parameter.
      
     
@@ -5807,7 +5842,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGSSLCERT
       
-      PGSSLCERT behaves the same as 
+      PGSSLCERT behaves the same as the 
       linkend="libpq-connect-sslcert"> connection parameter.
      
     
@@ -5817,7 +5852,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGSSLKEY
       
-      PGSSLKEY behaves the same as 
+      PGSSLKEY behaves the same as the 
       linkend="libpq-connect-sslkey"> connection parameter.
      
     
@@ -5827,7 +5862,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGSSLROOTCERT
       
-      PGSSLROOTCERT  behaves the same as 
+      PGSSLROOTCERT  behaves the same as the 
       linkend="libpq-connect-sslrootcert"> connection parameter.
      
     
@@ -5837,7 +5872,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGSSLCRL
       
-      PGSSLCRL  behaves the same as 
+      PGSSLCRL  behaves the same as the 
       linkend="libpq-connect-sslcrl"> connection parameter.
      
     
@@ -5847,7 +5882,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGKRBSRVNAME
       
-      PGKRBSRVNAME  behaves the same as 
+      PGKRBSRVNAME  behaves the same as the 
       linkend="libpq-connect-krbsrvname"> connection parameter.
      
     
@@ -5857,7 +5892,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGGSSLIB
       
-      PGGSSLIB behaves the same as 
+      PGGSSLIB behaves the same as the 
       linkend="libpq-connect-gsslib"> connection parameter.
      
     
@@ -5867,7 +5902,7 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
       
        PGCONNECT_TIMEOUT
       
-      PGCONNECT_TIMEOUT  behaves the same as 
+      PGCONNECT_TIMEOUT  behaves the same as the 
       linkend="libpq-connect-connect-timeout"> connection parameter.
      
     
index 7bd21a74b427d773208aa4cbda0aad6c38ea5049..94fbce63ad6c2df311aceada97df9de722fadb8b 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  Monitoring Database Activity
@@ -238,12 +238,12 @@ postgres: user database host 
       name, process ID, user OID, user name, current query,
       query's waiting status, time at which the current transaction and
       current query began execution, time at which the process was
-      started, and client's address and port number.  The columns that
-      report data on the current query are available unless the parameter
-      track_activities has been turned off.
-      Furthermore, these columns are only visible if the user examining
-      the view is a superuser or the same as the user owning the process
-      being reported on.
+      started, client's address and port number, and application name.
+      The columns that report data on the current query are available unless
+      the parameter track_activities has been turned off.
+      Furthermore, these columns and the application name are only visible if
+      the user examining the view is a superuser or the same as the user
+      owning the process being reported on.
      
      
 
index c2fbfcdf0a3ab48a8aacec6019d530f20f436645..5bf76478166b2af231c8f31fec240d791a828e17 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1996-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.61 2009/10/07 22:14:18 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.62 2009/11/28 23:38:07 tgl Exp $
  */
 
 CREATE VIEW pg_roles AS 
@@ -339,7 +339,8 @@ CREATE VIEW pg_stat_activity AS
             S.query_start,
             S.backend_start,
             S.client_addr,
-            S.client_port
+            S.client_port,
+            S.application_name
     FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U
     WHERE S.datid = D.oid AND 
             S.usesysid = U.oid;
index fac2100e831af35ac54c909973af434bb79bb5c7..4fa2d9fd63763b3546ad6f1ca123fc2752ce73e4 100644 (file)
@@ -13,7 +13,7 @@
  *
  * Copyright (c) 2001-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.192 2009/10/02 22:49:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.193 2009/11/28 23:38:07 tgl Exp $
  * ----------
  */
 #include "postgres.h"
@@ -2073,6 +2073,7 @@ pgstat_fetch_global(void)
 
 static PgBackendStatus *BackendStatusArray = NULL;
 static PgBackendStatus *MyBEEntry = NULL;
+static char *BackendAppnameBuffer = NULL;
 static char *BackendActivityBuffer = NULL;
 
 
@@ -2084,14 +2085,17 @@ BackendStatusShmemSize(void)
 {
    Size        size;
 
-   size = add_size(mul_size(sizeof(PgBackendStatus), MaxBackends),
+   size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+   size = add_size(size,
+                   mul_size(NAMEDATALEN, MaxBackends));
+   size = add_size(size,
                    mul_size(pgstat_track_activity_query_size, MaxBackends));
    return size;
 }
 
 /*
- * Initialize the shared status array and activity string buffer during
- * postmaster startup.
+ * Initialize the shared status array and activity/appname string buffers
+ * during postmaster startup.
  */
 void
 CreateSharedBackendStatus(void)
@@ -2114,6 +2118,24 @@ CreateSharedBackendStatus(void)
        MemSet(BackendStatusArray, 0, size);
    }
 
+   /* Create or attach to the shared appname buffer */
+   size = mul_size(NAMEDATALEN, MaxBackends);
+   BackendAppnameBuffer = (char *)
+       ShmemInitStruct("Backend Application Name Buffer", size, &found);
+
+   if (!found)
+   {
+       MemSet(BackendAppnameBuffer, 0, size);
+
+       /* Initialize st_appname pointers. */
+       buffer = BackendAppnameBuffer;
+       for (i = 0; i < MaxBackends; i++)
+       {
+           BackendStatusArray[i].st_appname = buffer;
+           buffer += NAMEDATALEN;
+       }
+   }
+
    /* Create or attach to the shared activity buffer */
    size = mul_size(pgstat_track_activity_query_size, MaxBackends);
    BackendActivityBuffer = (char *)
@@ -2159,7 +2181,8 @@ pgstat_initialize(void)
  * pgstat_bestart() -
  *
  * Initialize this backend's entry in the PgBackendStatus array.
- * Called from InitPostgres.  MyDatabaseId and session userid must be set
+ * Called from InitPostgres.
+ * MyDatabaseId, session userid, and application_name must be set
  * (hence, this cannot be combined with pgstat_initialize).
  * ----------
  */
@@ -2214,12 +2237,18 @@ pgstat_bestart(void)
    beentry->st_userid = userid;
    beentry->st_clientaddr = clientaddr;
    beentry->st_waiting = false;
+   beentry->st_appname[0] = '\0';
    beentry->st_activity[0] = '\0';
-   /* Also make sure the last byte in the string area is always 0 */
+   /* Also make sure the last byte in each string area is always 0 */
+   beentry->st_appname[NAMEDATALEN - 1] = '\0';
    beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0';
 
    beentry->st_changecount++;
    Assert((beentry->st_changecount & 1) == 0);
+
+   /* Update app name to current GUC setting */
+   if (application_name)
+       pgstat_report_appname(application_name);
 }
 
 /*
@@ -2302,6 +2331,38 @@ pgstat_report_activity(const char *cmd_str)
    Assert((beentry->st_changecount & 1) == 0);
 }
 
+/* ----------
+ * pgstat_report_appname() -
+ *
+ * Called to update our application name.
+ * ----------
+ */
+void
+pgstat_report_appname(const char *appname)
+{
+   volatile PgBackendStatus *beentry = MyBEEntry;
+   int         len;
+
+   if (!beentry)
+       return;
+
+   /* This should be unnecessary if GUC did its job, but be safe */
+   len = pg_mbcliplen(appname, strlen(appname), NAMEDATALEN - 1);
+
+   /*
+    * Update my status entry, following the protocol of bumping
+    * st_changecount before and after.  We use a volatile pointer here to
+    * ensure the compiler doesn't try to get cute.
+    */
+   beentry->st_changecount++;
+
+   memcpy((char *) beentry->st_appname, appname, len);
+   beentry->st_appname[len] = '\0';
+
+   beentry->st_changecount++;
+   Assert((beentry->st_changecount & 1) == 0);
+}
+
 /*
  * Report current transaction start timestamp as the specified value.
  * Zero means there is no active transaction.
@@ -2364,7 +2425,8 @@ pgstat_read_current_status(void)
    volatile PgBackendStatus *beentry;
    PgBackendStatus *localtable;
    PgBackendStatus *localentry;
-   char       *localactivity;
+   char       *localappname,
+              *localactivity;
    int         i;
 
    Assert(!pgStatRunningInCollector);
@@ -2376,6 +2438,9 @@ pgstat_read_current_status(void)
    localtable = (PgBackendStatus *)
        MemoryContextAlloc(pgStatLocalContext,
                           sizeof(PgBackendStatus) * MaxBackends);
+   localappname = (char *)
+       MemoryContextAlloc(pgStatLocalContext,
+                          NAMEDATALEN * MaxBackends);
    localactivity = (char *)
        MemoryContextAlloc(pgStatLocalContext,
                           pgstat_track_activity_query_size * MaxBackends);
@@ -2405,6 +2470,8 @@ pgstat_read_current_status(void)
                 * strcpy is safe even if the string is modified concurrently,
                 * because there's always a \0 at the end of the buffer.
                 */
+               strcpy(localappname, (char *) beentry->st_appname);
+               localentry->st_appname = localappname;
                strcpy(localactivity, (char *) beentry->st_activity);
                localentry->st_activity = localactivity;
            }
@@ -2422,6 +2489,7 @@ pgstat_read_current_status(void)
        if (localentry->st_procpid > 0)
        {
            localentry++;
+           localappname += NAMEDATALEN;
            localactivity += pgstat_track_activity_query_size;
            localNumBackends++;
        }
index 89fb28a402b88f438d84330e5f10b42f77f1870a..6d93c5cf751a9e6e45afd45d18ad82be7cc92fd1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.54 2009/06/11 14:49:04 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.55 2009/11/28 23:38:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -416,7 +416,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
-       tupdesc = CreateTemplateTupleDesc(10, false);
+       tupdesc = CreateTemplateTupleDesc(11, false);
        TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid", OIDOID, -1, 0);
        TupleDescInitEntry(tupdesc, (AttrNumber) 2, "procpid", INT4OID, -1, 0);
        TupleDescInitEntry(tupdesc, (AttrNumber) 3, "usesysid", OIDOID, -1, 0);
@@ -427,6 +427,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
        TupleDescInitEntry(tupdesc, (AttrNumber) 8, "backend_start", TIMESTAMPTZOID, -1, 0);
        TupleDescInitEntry(tupdesc, (AttrNumber) 9, "client_addr", INETOID, -1, 0);
        TupleDescInitEntry(tupdesc, (AttrNumber) 10, "client_port", INT4OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 11, "application_name", TEXTOID, -1, 0);
 
        funcctx->tuple_desc = BlessTupleDesc(tupdesc);
 
@@ -478,8 +479,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
    if (funcctx->call_cntr < funcctx->max_calls)
    {
        /* for each row */
-       Datum       values[10];
-       bool        nulls[10];
+       Datum       values[11];
+       bool        nulls[11];
        HeapTuple   tuple;
        PgBackendStatus *beentry;
        SockAddr    zero_clientaddr;
@@ -599,6 +600,12 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                    nulls[9] = true;
                }
            }
+
+           /* application name */
+           if (beentry->st_appname)
+               values[10] = CStringGetTextDatum(beentry->st_appname);
+           else
+               nulls[10] = true;
        }
        else
        {
@@ -610,6 +617,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
            nulls[7] = true;
            nulls[8] = true;
            nulls[9] = true;
+           nulls[10] = true;
        }
 
        tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
index 5f30e7837565f634975ca7e0057ca44ad7e34240..59fa07a379aa10cdbdcb25b4d25f9541284499f9 100644 (file)
@@ -42,7 +42,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.218 2009/10/17 00:24:50 mha Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.219 2009/11/28 23:38:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,6 +68,7 @@
 #include "storage/ipc.h"
 #include "storage/proc.h"
 #include "tcop/tcopprot.h"
+#include "utils/guc.h"
 #include "utils/memutils.h"
 #include "utils/ps_status.h"
 
@@ -1798,6 +1799,16 @@ log_line_prefix(StringInfo buf, ErrorData *edata)
        /* process the option */
        switch (Log_line_prefix[i])
        {
+           case 'a':
+               if (MyProcPort)
+               {
+                   const char *appname = application_name;
+
+                   if (appname == NULL || *appname == '\0')
+                       appname = _("[unknown]");
+                   appendStringInfo(buf, "%s", appname);
+               }
+               break;
            case 'u':
                if (MyProcPort)
                {
@@ -2103,6 +2114,11 @@ write_csvlog(ErrorData *edata)
        appendCSVLiteral(&buf, msgbuf.data);
        pfree(msgbuf.data);
    }
+   appendStringInfoCharMacro(&buf, ',');
+
+   /* application name */
+   if (application_name)
+       appendCSVLiteral(&buf, application_name);
 
    appendStringInfoChar(&buf, '\n');
 
index 33f38a20c48649d9a9eb645168227a3bcc97f8a2..04ba14c2dbb858b7860fa9cae5cc6a766e2aef9b 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut .
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.523 2009/10/21 20:38:58 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.524 2009/11/28 23:38:07 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -168,6 +168,7 @@ static bool assign_maxconnections(int newval, bool doit, GucSource source);
 static bool assign_autovacuum_max_workers(int newval, bool doit, GucSource source);
 static bool assign_effective_io_concurrency(int newval, bool doit, GucSource source);
 static const char *assign_pgstat_temp_directory(const char *newval, bool doit, GucSource source);
+static const char *assign_application_name(const char *newval, bool doit, GucSource source);
 
 static char *config_enum_get_options(struct config_enum * record,
                        const char *prefix, const char *suffix,
@@ -378,6 +379,8 @@ char       *pgstat_temp_directory;
 
 char      *default_do_language;
 
+char      *application_name;
+
 int            tcp_keepalives_idle;
 int            tcp_keepalives_interval;
 int            tcp_keepalives_count;
@@ -2534,6 +2537,16 @@ static struct config_string ConfigureNamesString[] =
        "plpgsql", NULL, NULL
    },
 
+   {
+       {"application_name", PGC_USERSET, LOGGING,
+        gettext_noop("Sets the application name to be reported in statistics and logs."),
+        NULL,
+        GUC_IS_NAME | GUC_NOT_IN_SAMPLE
+       },
+       &application_name,
+       "", assign_application_name, NULL
+   },
+
    /* End-of-list marker */
    {
        {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
@@ -7717,4 +7730,28 @@ assign_pgstat_temp_directory(const char *newval, bool doit, GucSource source)
        return newval;
 }
 
+static const char *
+assign_application_name(const char *newval, bool doit, GucSource source)
+{
+   if (doit)
+   {
+       /* Only allow clean ASCII chars in the application name */
+       char       *repval = guc_strdup(ERROR, newval);
+       char       *p;
+
+       for (p = repval; *p; p++)
+       {
+           if (*p < 32 || *p > 126)
+               *p = '?';
+       }
+
+       /* Update the pg_stat_activity view */
+       pgstat_report_appname(repval);
+
+       return repval;
+   }
+   else
+       return newval;
+}
+
 #include "guc-file.c"
index 4c5f1590de4c08e083f6466e6387a7fa697784e5..f2accd263e6d423e7ca0d77e1e589eb5c29d9e3b 100644 (file)
 #log_duration = off
 #log_hostname = off
 #log_line_prefix = ''          # special values:
+                   #   %a = application name
                    #   %u = user name
                    #   %d = database name
                    #   %r = remote host and port
index 4be0e0fce68ee8f4100d8a99fa50c00a71d6b43a..61b7ccd822bc69051acf46f1da9a52b22ea96d61 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.551 2009/11/20 20:38:11 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.552 2009/11/28 23:38:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 200911201
+#define CATALOG_VERSION_NO 200911281
 
 #endif
index cd249d841b849bb0b5161a086aaf869b8d3ee184..f0988892c74abb14c07ea66a27558ec2428aaa68 100644 (file)
@@ -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/catalog/pg_proc.h,v 1.552 2009/10/09 21:02:56 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.553 2009/11/28 23:38:07 tgl Exp $
  *
  * NOTES
  *   The script catalog/genbki.sh reads this file and generates .bki
@@ -2999,7 +2999,7 @@ DATA(insert OID = 2784 (  pg_stat_get_last_autoanalyze_time PGNSP PGUID 12 1 0 0
 DESCR("statistics: last auto analyze time for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset        PGNSP PGUID 12 1 100 0 f f f t t s 0 0 23 "" _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity         PGNSP PGUID 12 1 100 0 f f f f t s 1 0 2249 "23" "{23,26,23,26,25,16,1184,1184,1184,869,23}" "{i,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,procpid,usesysid,current_query,waiting,xact_start,query_start,backend_start,client_addr,client_port}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity         PGNSP PGUID 12 1 100 0 f f f f t s 1 0 2249 "23" "{23,26,23,26,25,16,1184,1184,1184,869,23,25}" "{i,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,procpid,usesysid,current_query,waiting,xact_start,query_start,backend_start,client_addr,client_port,application_name}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 2026 (  pg_backend_pid               PGNSP PGUID 12 1 0 0 f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ ));
 DESCR("statistics: current backend PID");
index 7fa25175f44fdf742591fed0cdcbda8cf26fed9b..7c4efb9f3bdbd58b449f248205b4f226d8514ccb 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 2001-2009, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.83 2009/06/11 14:49:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.84 2009/11/28 23:38:08 tgl Exp $
  * ----------
  */
 #ifndef PGSTAT_H
@@ -564,6 +564,9 @@ typedef struct PgBackendStatus
    /* Is backend currently waiting on an lmgr lock? */
    bool        st_waiting;
 
+   /* application name; MUST be null-terminated */
+   char       *st_appname;
+
    /* current command string; MUST be null-terminated */
    char       *st_activity;
 } PgBackendStatus;
@@ -641,7 +644,8 @@ extern void pgstat_report_analyze(Relation rel,
 extern void pgstat_initialize(void);
 extern void pgstat_bestart(void);
 
-extern void pgstat_report_activity(const char *what);
+extern void pgstat_report_activity(const char *cmd_str);
+extern void pgstat_report_appname(const char *appname);
 extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
 extern void pgstat_report_waiting(bool waiting);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
index ad76d06ffc83c9ba764c217fc6b4217af565c570..53704ec38bbf0bec610129fd81110c01f76a6efb 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 2000-2009, PostgreSQL Global Development Group
  * Written by Peter Eisentraut .
  *
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.108 2009/10/13 14:18:40 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.109 2009/11/28 23:38:08 tgl Exp $
  *--------------------------------------------------------------------
  */
 #ifndef GUC_H
@@ -183,6 +183,8 @@ extern char *external_pid_file;
 
 extern char *default_do_language;
 
+extern char *application_name;
+
 extern int tcp_keepalives_idle;
 extern int tcp_keepalives_interval;
 extern int tcp_keepalives_count;
index 1be948505e5bce0159c7aa95d38f1336fd8aa4f0..f218dbe2c8298a0ebb599432d48507370a5bd470 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.377 2009/09/27 03:43:10 tgl Exp $
+ *   $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.378 2009/11/28 23:38:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -164,6 +164,12 @@ static const PQconninfoOption PQconninfoOptions[] = {
    {"options", "PGOPTIONS", DefaultOption, NULL,
    "Backend-Debug-Options", "D", 40},
 
+   {"application_name", "PGAPPNAME", NULL, NULL,
+   "Application-Name", "", 64},
+
+   {"fallback_application_name", NULL, NULL, NULL,
+   "Fallback-Application-Name", "", 64},
+
 #ifdef USE_SSL
 
    /*
@@ -256,6 +262,7 @@ static int parseServiceInfo(PQconninfoOption *options,
 static char *pwdfMatchesString(char *buf, char *token);
 static char *PasswordFromFile(char *hostname, char *port, char *dbname,
                 char *username);
+static PostgresPollingStatusType pqAppnamePoll(PGconn *conn);
 static void default_threadlock(int acquire);
 
 
@@ -416,6 +423,10 @@ connectOptions1(PGconn *conn, const char *conninfo)
    conn->pgtty = tmp ? strdup(tmp) : NULL;
    tmp = conninfo_getval(connOptions, "options");
    conn->pgoptions = tmp ? strdup(tmp) : NULL;
+   tmp = conninfo_getval(connOptions, "application_name");
+   conn->appname = tmp ? strdup(tmp) : NULL;
+   tmp = conninfo_getval(connOptions, "fallback_application_name");
+   conn->fbappname = tmp ? strdup(tmp) : NULL;
    tmp = conninfo_getval(connOptions, "dbname");
    conn->dbName = tmp ? strdup(tmp) : NULL;
    tmp = conninfo_getval(connOptions, "user");
@@ -1064,7 +1075,7 @@ PQconnectPoll(PGconn *conn)
        case CONNECTION_MADE:
            break;
 
-           /* We allow pqSetenvPoll to decide whether to proceed. */
+           /* pqSetenvPoll/pqAppnamePoll will decide whether to proceed. */
        case CONNECTION_SETENV:
            break;
 
@@ -1888,6 +1899,12 @@ keep_going:                      /* We will come back to here until there is
                conn->addrlist = NULL;
                conn->addr_cur = NULL;
 
+               /*
+                * Note: To avoid changing the set of application-visible
+                * connection states, v2 environment setup and v3 application
+                * name setup both happen in the CONNECTION_SETENV state.
+                */
+
                /* Fire up post-connection housekeeping if needed */
                if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
                {
@@ -1896,6 +1913,13 @@ keep_going:                      /* We will come back to here until there is
                    conn->next_eo = EnvironmentOptions;
                    return PGRES_POLLING_WRITING;
                }
+               else if (conn->sversion >= 80500 &&
+                        (conn->appname || conn->fbappname))
+               {
+                   conn->status = CONNECTION_SETENV;
+                   conn->appname_state = APPNAME_STATE_CMD_SEND;
+                   return PGRES_POLLING_WRITING;
+               }
 
                /* Otherwise, we are open for business! */
                conn->status = CONNECTION_OK;
@@ -1903,42 +1927,49 @@ keep_going:                     /* We will come back to here until there is
            }
 
        case CONNECTION_SETENV:
+           {
+               PostgresPollingStatusType ret;
 
-           /*
-            * Do post-connection housekeeping (only needed in protocol 2.0).
-            *
-            * We pretend that the connection is OK for the duration of these
-            * queries.
-            */
-           conn->status = CONNECTION_OK;
+               /*
+                * Do post-connection housekeeping (only needed in protocol
+                * 2.0), or send the application name in PG8.5+.
+                *
+                * We pretend that the connection is OK for the duration of
+                * these queries.
+                */
+               conn->status = CONNECTION_OK;
 
-           switch (pqSetenvPoll(conn))
-           {
-               case PGRES_POLLING_OK:  /* Success */
-                   break;
+               if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
+                   ret = pqSetenvPoll(conn);
+               else                /* must be here to send app name */
+                   ret = pqAppnamePoll(conn);
 
-               case PGRES_POLLING_READING:     /* Still going */
-                   conn->status = CONNECTION_SETENV;
-                   return PGRES_POLLING_READING;
+               switch (ret)
+               {
+                   case PGRES_POLLING_OK:  /* Success */
+                       break;
 
-               case PGRES_POLLING_WRITING:     /* Still going */
-                   conn->status = CONNECTION_SETENV;
-                   return PGRES_POLLING_WRITING;
+                   case PGRES_POLLING_READING:     /* Still going */
+                       conn->status = CONNECTION_SETENV;
+                       return PGRES_POLLING_READING;
 
-               default:
-                   goto error_return;
-           }
+                   case PGRES_POLLING_WRITING:     /* Still going */
+                       conn->status = CONNECTION_SETENV;
+                       return PGRES_POLLING_WRITING;
 
-           /* We are open for business! */
-           conn->status = CONNECTION_OK;
-           return PGRES_POLLING_OK;
+                   default:
+                       goto error_return;
+               }
+
+               /* We are open for business! */
+               conn->status = CONNECTION_OK;
+               return PGRES_POLLING_OK;
+           }
 
        default:
            appendPQExpBuffer(&conn->errorMessage,
-                             libpq_gettext(
-                                           "invalid connection state %c, "
-                                "probably indicative of memory corruption\n"
-                                           ),
+                             libpq_gettext("invalid connection state %d, "
+                                "probably indicative of memory corruption\n"),
                              conn->status);
            goto error_return;
    }
@@ -2000,6 +2031,7 @@ makeEmptyPGconn(void)
    conn->options_valid = false;
    conn->nonblocking = false;
    conn->setenv_state = SETENV_STATE_IDLE;
+   conn->appname_state = APPNAME_STATE_IDLE;
    conn->client_encoding = PG_SQL_ASCII;
    conn->std_strings = false;  /* unless server says differently */
    conn->verbosity = PQERRORS_DEFAULT;
@@ -2082,6 +2114,10 @@ freePGconn(PGconn *conn)
        free(conn->connect_timeout);
    if (conn->pgoptions)
        free(conn->pgoptions);
+   if (conn->appname)
+       free(conn->appname);
+   if (conn->fbappname)
+       free(conn->fbappname);
    if (conn->dbName)
        free(conn->dbName);
    if (conn->pguser)
@@ -4005,6 +4041,129 @@ pqGetHomeDirectory(char *buf, int bufsize)
 #endif
 }
 
+/*
+ *     pqAppnamePoll
+ *
+ * Polls the process of passing the application name to the backend.
+ *
+ * Ideally, we'd include the appname in the startup packet, but that would
+ * cause old backends to reject the unknown parameter.  So we send it in a
+ * separate query after we have determined the backend version.  Once there
+ * is no interest in pre-8.5 backends, this should be folded into the startup
+ * packet logic.
+ */
+static PostgresPollingStatusType
+pqAppnamePoll(PGconn *conn)
+{
+   PGresult   *res;
+
+   if (conn == NULL || conn->status == CONNECTION_BAD)
+       return PGRES_POLLING_FAILED;
+
+   /* Check whether there is any data for us */
+   switch (conn->appname_state)
+   {
+           /* This is a reading state. */
+       case APPNAME_STATE_CMD_WAIT:
+       {
+           /* Load waiting data */
+           int         n = pqReadData(conn);
+
+           if (n < 0)
+               goto error_return;
+           if (n == 0)
+               return PGRES_POLLING_READING;
+
+           break;
+       }
+
+           /* This is a writing state, so we just proceed. */
+       case APPNAME_STATE_CMD_SEND:
+           break;
+
+           /* Should we raise an error if called when not active? */
+       case APPNAME_STATE_IDLE:
+           return PGRES_POLLING_OK;
+
+       default:
+           printfPQExpBuffer(&conn->errorMessage,
+                             libpq_gettext("invalid appname state %d, "
+                                           "probably indicative of memory corruption\n"),
+                             conn->appname_state);
+           goto error_return;
+   }
+
+   /* We will loop here until there is nothing left to do in this call. */
+   for (;;)
+   {
+       switch (conn->appname_state)
+       {
+           case APPNAME_STATE_CMD_SEND:
+           {
+               const char *val;
+               char    escVal[NAMEDATALEN*2 + 1];
+               char    setQuery[NAMEDATALEN*2 + 26 + 1];
+
+               /* Use appname if present, otherwise use fallback */
+               val = conn->appname ? conn->appname : conn->fbappname;
+
+               /*
+                * Escape the data as needed.  We can truncate to NAMEDATALEN,
+                * so there's no need to cope with malloc.
+                */
+               PQescapeStringConn(conn, escVal, val, NAMEDATALEN, NULL);
+
+               sprintf(setQuery, "SET application_name = '%s'", escVal);
+
+               if (!PQsendQuery(conn, setQuery))
+                   goto error_return;
+
+               conn->appname_state = APPNAME_STATE_CMD_WAIT;
+               break;
+           }
+
+           case APPNAME_STATE_CMD_WAIT:
+           {
+               if (PQisBusy(conn))
+                   return PGRES_POLLING_READING;
+
+               res = PQgetResult(conn);
+
+               if (res)
+               {
+                   if (PQresultStatus(res) != PGRES_COMMAND_OK)
+                   {
+                       PQclear(res);
+                       goto error_return;
+                   }
+                   PQclear(res);
+                   /* Keep reading until PQgetResult returns NULL */
+               }
+               else
+               {
+                   /* Query finished, so we're done */
+                   conn->appname_state = APPNAME_STATE_IDLE;
+                   return PGRES_POLLING_OK;
+               }
+               break;
+           }
+
+           default:
+               printfPQExpBuffer(&conn->errorMessage,
+                                 libpq_gettext("invalid appname state %d, "
+                                               "probably indicative of memory corruption\n"),
+                                 conn->appname_state);
+               goto error_return;
+       }
+   }
+
+   /* Unreachable */
+
+error_return:
+   conn->appname_state = APPNAME_STATE_IDLE;
+   return PGRES_POLLING_FAILED;
+}
+
 /*
  * To keep the API consistent, the locking stubs are always provided, even
  * if they are not required.
index d93ba4d25e230657863770f23f0f7351827e0293..a496aebbba33296e316d0af748d64248b06e6fab 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.144 2009/07/24 17:58:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.145 2009/11/28 23:38:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -244,6 +244,14 @@ typedef enum
    SETENV_STATE_IDLE
 } PGSetenvStatusType;
 
+/* PGAppnameStatusType defines the state of the PQAppname state machine */
+typedef enum
+{
+   APPNAME_STATE_CMD_SEND,     /* About to send the appname */
+   APPNAME_STATE_CMD_WAIT,     /* Waiting for above send to complete */
+   APPNAME_STATE_IDLE
+} PGAppnameStatusType;
+
 /* Typedef for the EnvironmentOptions[] array */
 typedef struct PQEnvironmentOption
 {
@@ -295,6 +303,8 @@ struct pg_conn
                                 * displayed (OBSOLETE, NOT USED) */
    char       *connect_timeout;    /* connection timeout (numeric string) */
    char       *pgoptions;      /* options to start the backend with */
+   char       *appname;        /* application name */
+   char       *fbappname;      /* fallback application name */
    char       *dbName;         /* database name */
    char       *pguser;         /* Postgres username and password, if any */
    char       *pgpass;
@@ -349,6 +359,7 @@ struct pg_conn
    struct addrinfo *addr_cur;  /* the one currently being tried */
    int         addrlist_family;    /* needed to know how to free addrlist */
    PGSetenvStatusType setenv_state;    /* for 2.0 protocol only */
+   PGAppnameStatusType appname_state;
    const PQEnvironmentOption *next_eo;
 
    /* Miscellaneous stuff */
index 9561a2355940d9a39d0b06b3078fd6e7ff12b512..a4025436a90daac8ec6b726e6270f58e035efbfc 100644 (file)
@@ -1289,7 +1289,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
  pg_rules                 | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
  pg_settings              | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline);
  pg_shadow                | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin;
- pg_stat_activity         | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.current_query, s.waiting, s.xact_start, s.query_start, s.backend_start, s.client_addr, s.client_port FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
+ pg_stat_activity         | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.current_query, s.waiting, s.xact_start, s.query_start, s.backend_start, s.client_addr, s.client_port, s.application_name FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port, application_name), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
  pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
  pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_tuples_hot_updated(c.oid) AS n_tup_hot_upd, pg_stat_get_live_tuples(c.oid) AS n_live_tup, pg_stat_get_dead_tuples(c.oid) AS n_dead_tup, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
  pg_stat_bgwriter         | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_buf_written_backend() AS buffers_backend, pg_stat_get_buf_alloc() AS buffers_alloc;