pg_stat_activity_state_query.v5.patch

application/octet-stream

Filename: pg_stat_activity_state_query.v5.patch
Type: application/octet-stream
Part: 0
Message: Re: IDLE in transaction introspection

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v5
File+
doc/src/sgml/monitoring.sgml 0 0
src/backend/catalog/system_views.sql 0 0
src/backend/postmaster/autovacuum.c 0 0
src/backend/postmaster/pgstat.c 0 0
src/backend/tcop/postgres.c 0 0
src/backend/utils/adt/pgstatfuncs.c 0 0
src/include/catalog/pg_proc.h 0 0
src/include/c.h 0 0
src/include/pgstat.h 0 0
src/test/regress/expected/rules.out 0 0
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
new file mode 100644
index a12a9a2..e5c2615
*** a/doc/src/sgml/monitoring.sgml
--- b/doc/src/sgml/monitoring.sgml
*************** postgres: <replaceable>user</> <replacea
*** 243,261 ****
      <tbody>
       <row>
        <entry><structname>pg_stat_activity</><indexterm><primary>pg_stat_activity</primary></indexterm></entry>
!       <entry>One row per server process, showing database OID, database
!       name, process <acronym>ID</>, user OID, user name, application name,
!       client's address, host name (if available), and port number, times at
!       which the server process, current transaction, and current query began
!       execution, process's waiting status, and text of the current query.
!       The columns that report data on the current query are available unless
!       the parameter <varname>track_activities</varname> 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.  The client's host name will be available only if
!       <xref linkend="guc-log-hostname"> is set or if the user's host name
!       needed to be looked up during <filename>pg_hba.conf</filename>
!       processing.
       </entry>
       </row>
  
--- 243,253 ----
      <tbody>
       <row>
        <entry><structname>pg_stat_activity</><indexterm><primary>pg_stat_activity</primary></indexterm></entry>
!       <entry><para>One row per server process, showing information related to
!       each connection made to the database server (one connection per process).
!       If the <varname>track_activites</varname> parameter is on (it is by default),
!       it is possible to monitor query / state information of all running processes
!       (if permissions allow).</para><para>See <xref linkend="pg-stat-activity-view"> for more details.</para>
       </entry>
       </row>
  
*************** postgres: <replaceable>user</> <replacea
*** 480,485 ****
--- 472,642 ----
     </tgroup>
    </table>
  
+   <table id="pg-stat-activity-view" xreflabel="pg_stat_activity">
+    <title>pg_stat_activity view</title>
+ 
+    <tgroup cols="3">
+     <thead>
+     <row>
+       <entry>Column</entry>
+       <entry>Type</entry>
+       <entry>Description</entry>
+      </row>
+     </thead>
+ 
+    <tbody>
+     <row>
+      <entry><structname>datid</></entry>
+      <entry><structname>OID</></entry>
+      <entry>The <structname>OID</> of the database the backend is connected to</entry>
+     </row>
+     <row>
+      <entry><structname>datname</></entry>
+      <entry><structname>name</></entry>
+      <entry>The name of the database that the backend is connected to</entry>
+     </row>
+     <row>
+      <entry><structname>pid</></entry>
+      <entry><structname>integer</></entry>
+      <entry>The process ID of the postgres backend</entry>
+     </row>
+     <row>
+      <entry><structname>usesysid</></entry>
+      <entry><structname>OID</></entry>
+      <entry>The id of the user.  Links to <structname>pg_user</> <structname>usesysid</> column</entry>
+     </row>
+     <row>
+      <entry><structname>usename</></entry>
+      <entry><structname>name</></entry>
+      <entry>The postgres username logged into the backend</entry>
+     </row>
+     <row>
+      <entry><structname>application_name</></entry>
+      <entry><structname>text</></entry>
+      <entry>The name of the application that has initiated the connection to the backend.
+      This field may or may not be set, it is up to the client-application developer to
+      set this and is not a required option.</entry>
+     </row>
+     <row>
+      <entry><structname>client_addr</></entry>
+      <entry><structname>inet</></entry>
+      <entry>The origination address (remote IP) of the client connected to the backend.
+      If this field is not set, it indicates that the client is either:
+      <itemizedlist spacing="compact" mark="bullet">
+       <listitem><para>Connected via unix sockets on the server machine (i.e. the psql default
+       connection method)</para></listitem>
+       <listitem><para>An internal process (i.e. autovacuum)</para></listitem>
+      </itemizedlist>
+      </entry>
+     </row>
+     <row>
+      <entry><structname>client_hostname</></entry>
+      <entry><structname>text</></entry>
+      <entry>If available, the hostname of the client as reported by a reverse-lookup of
+      the client_addr.  This field will only be set when the postgresql.conf
+      <xref linkend="guc-log-hostname"> setting is enabled.</entry>
+     </row>
+     <row>
+      <entry><structname>client_port</></entry>
+      <entry><structname>integer</></entry>
+      <entry>The origin TCP port that the client is using for communication to the backend</entry>
+     </row>
+     <row>
+      <entry><structname>backend_start</></entry>
+      <entry><structname>timestamp with time zone</></entry>
+      <entry>The <structname>timestamp</> that signifies when this particular process
+      <structname>pid</> was started up.  i.e. When the client connected to the server</entry>
+     </row>
+     <row>
+      <entry><structname>xact_start</></entry>
+      <entry><structname>timestamp with time zone</></entry>
+      <entry>The <structname>timestamp</> that signifies the beginning of the current transaction. If
+      the client is using autocommit for transactions, this value will be equal to the
+      <structname>query_start</> column.</entry>
+     </row>
+     <row>
+      <entry><structname>query_start</></entry>
+      <entry><structname>timestamp with time zone</></entry>
+      <entry>The <structname>timestamp</> that signifies when the currently active query started</entry>
+     </row>
+     <row>
+      <entry><structname>state_change</></entry>
+      <entry><structname>timestamp with time zone</></entry>
+      <entry>The <structname>timestamp</> that signifies when the 'state' column was last changed</entry>
+     </row>
+     <row>
+      <entry><structname>waiting</></entry>
+      <entry><structname>boolean</></entry>
+      <entry>Boolean indicating if a backend is currently waiting on a lock</entry>
+     </row>
+     <row>
+      <entry><structname>state</></entry>
+      <entry><structname>text</></entry>
+      <entry>This is the 'state' of the currently running query, it can be one of:
+        <variablelist>
+          <varlistentry>
+            <term>active</term>
+            <listitem>
+              <para>
+                The <structname>query</> is actively running
+              </para>
+            </listitem>
+            </varlistentry>
+            <varlistentry>
+              <term>idle</term>
+            <listitem>
+              <para>
+                There is no query executing on the backend process
+              </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>idle in transaction</term>
+            <listitem>
+              <para>
+                The backend is in a transaction, but is currently not executing a specific query.
+                This state usually occurs when the application has initiated a transaction and
+                [possibly] executed some number of queries; without issuing a COMMIT / END / ROLLBACK,
+                the application is not in active use of a transaction, but the transaction is still
+                open.
+              </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>fastpath function call</term>
+            <listitem>
+              <para>
+                executing a fast-path function
+              </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>idle in transaction (aborted)</term>
+            <listitem>
+              <para>
+                This state is similar to the above <structname>idle in transaction</>, however, one of the
+                statements in the transaction caused an error.
+              </para>
+            </listitem>
+          </varlistentry>
+        </variablelist>
+       NB: The <structname>waiting</> and <structname>state</> columns are independent.  If a query is in the
+       <structname>active</> state, it may or may not be <structname>waiting</>.  If a query is <structname>active</>
+       and <structname>waiting</> is true, it means that the query is being executed, but is being blocked by a lock
+       somewhere in the system.  This is a distinctly different state than <structname>idle in transaction</> which
+       refers to the backend being idle after having initiated an explicit transaction
+      </entry>
+     </row>
+     <row>
+      <entry><structname>query</></entry>
+      <entry><structname>text</></entry>
+      <entry>This is the most recent query that the backend has executed.  This could mean either the currently executing
+      query (if <structname>state</> is active), or the query that was previously executed (all other states).</entry>
+     </row>
+    </tbody>
+    </tgroup>
+   </table>
+ 
    <para>
     The per-index statistics are particularly useful to determine which
     indexes are being used and how effective they are.
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
new file mode 100644
index 50ba20c..e25914b
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
*************** CREATE VIEW pg_stat_activity AS
*** 520,526 ****
      SELECT
              S.datid AS datid,
              D.datname AS datname,
!             S.procpid,
              S.usesysid,
              U.rolname AS usename,
              S.application_name,
--- 520,526 ----
      SELECT
              S.datid AS datid,
              D.datname AS datname,
!             S.pid,
              S.usesysid,
              U.rolname AS usename,
              S.application_name,
*************** CREATE VIEW pg_stat_activity AS
*** 530,544 ****
              S.backend_start,
              S.xact_start,
              S.query_start,
              S.waiting,
!             S.current_query
      FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U
      WHERE S.datid = D.oid AND
              S.usesysid = U.oid;
  
  CREATE VIEW pg_stat_replication AS
      SELECT
!             S.procpid,
              S.usesysid,
              U.rolname AS usename,
              S.application_name,
--- 530,546 ----
              S.backend_start,
              S.xact_start,
              S.query_start,
+             S.state_change,
              S.waiting,
!             S.state,
!             S.query
      FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U
      WHERE S.datid = D.oid AND
              S.usesysid = U.oid;
  
  CREATE VIEW pg_stat_replication AS
      SELECT
!             S.pid,
              S.usesysid,
              U.rolname AS usename,
              S.application_name,
*************** CREATE VIEW pg_stat_replication AS
*** 556,562 ****
      FROM pg_stat_get_activity(NULL) AS S, pg_authid U,
              pg_stat_get_wal_senders() AS W
      WHERE S.usesysid = U.oid AND
!             S.procpid = W.procpid;
  
  CREATE VIEW pg_stat_database AS
      SELECT
--- 558,564 ----
      FROM pg_stat_get_activity(NULL) AS S, pg_authid U,
              pg_stat_get_wal_senders() AS W
      WHERE S.usesysid = U.oid AND
!             S.pid = W.pid;
  
  CREATE VIEW pg_stat_database AS
      SELECT
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
new file mode 100644
index f858a6d..d54ad37
*** a/src/backend/postmaster/autovacuum.c
--- b/src/backend/postmaster/autovacuum.c
*************** autovac_report_activity(autovac_table *t
*** 2781,2787 ****
  	/* Set statement_timestamp() to current time for pg_stat_activity */
  	SetCurrentStatementStartTimestamp();
  
! 	pgstat_report_activity(activity);
  }
  
  /*
--- 2781,2787 ----
  	/* Set statement_timestamp() to current time for pg_stat_activity */
  	SetCurrentStatementStartTimestamp();
  
! 	pgstat_report_activity(STATE_RUNNING,activity);
  }
  
  /*
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
new file mode 100644
index 323d42b..ba6aff1
*** a/src/backend/postmaster/pgstat.c
--- b/src/backend/postmaster/pgstat.c
*************** pgstat_bestart(void)
*** 2410,2421 ****
--- 2410,2423 ----
  	beentry->st_procpid = MyProcPid;
  	beentry->st_proc_start_timestamp = proc_start_timestamp;
  	beentry->st_activity_start_timestamp = 0;
+ 	beentry->st_state_start_timestamp = 0;
  	beentry->st_xact_start_timestamp = 0;
  	beentry->st_databaseid = MyDatabaseId;
  	beentry->st_userid = userid;
  	beentry->st_clientaddr = clientaddr;
  	beentry->st_clienthostname[0] = '\0';
  	beentry->st_waiting = false;
+     beentry->st_state=STATE_UNDEFINED;
  	beentry->st_appname[0] = '\0';
  	beentry->st_activity[0] = '\0';
  	/* Also make sure the last byte in each string area is always 0 */
*************** pgstat_beshutdown_hook(int code, Datum a
*** 2479,2485 ****
   * ----------
   */
  void
! pgstat_report_activity(const char *cmd_str)
  {
  	volatile PgBackendStatus *beentry = MyBEEntry;
  	TimestampTz start_timestamp;
--- 2481,2487 ----
   * ----------
   */
  void
! pgstat_report_activity(int state, const char *cmd_str)
  {
  	volatile PgBackendStatus *beentry = MyBEEntry;
  	TimestampTz start_timestamp;
*************** pgstat_report_activity(const char *cmd_s
*** 2496,2514 ****
  	 */
  	start_timestamp = GetCurrentStatementStartTimestamp();
  
- 	len = strlen(cmd_str);
- 	len = pg_mbcliplen(cmd_str, len, pgstat_track_activity_query_size - 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++;
  
! 	beentry->st_activity_start_timestamp = start_timestamp;
! 	memcpy((char *) beentry->st_activity, cmd_str, len);
! 	beentry->st_activity[len] = '\0';
  
  	beentry->st_changecount++;
  	Assert((beentry->st_changecount & 1) == 0);
--- 2498,2521 ----
  	 */
  	start_timestamp = GetCurrentStatementStartTimestamp();
  
  	/*
  	 * 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++;
  
!     beentry->st_state = state;
!     beentry->st_state_start_timestamp = GetCurrentTimestamp();
! 
!     if ( cmd_str != NULL )
!     {
!         len = strlen(cmd_str);
!         len = pg_mbcliplen(cmd_str, len, pgstat_track_activity_query_size - 1);
!         memcpy((char *) beentry->st_activity, cmd_str, len);
!         beentry->st_activity[len] = '\0';
!         beentry->st_activity_start_timestamp = start_timestamp;
!     }
  
  	beentry->st_changecount++;
  	Assert((beentry->st_changecount & 1) == 0);
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
new file mode 100644
index 59a287f..1cf16c2
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
*************** exec_simple_query(const char *query_stri
*** 809,815 ****
  	 */
  	debug_query_string = query_string;
  
! 	pgstat_report_activity(query_string);
  
  	TRACE_POSTGRESQL_QUERY_START(query_string);
  
--- 809,815 ----
  	 */
  	debug_query_string = query_string;
  
! 	pgstat_report_activity(STATE_RUNNING,query_string);
  
  	TRACE_POSTGRESQL_QUERY_START(query_string);
  
*************** exec_parse_message(const char *query_str
*** 1134,1140 ****
  	 */
  	debug_query_string = query_string;
  
! 	pgstat_report_activity(query_string);
  
  	set_ps_display("PARSE", false);
  
--- 1134,1140 ----
  	 */
  	debug_query_string = query_string;
  
! 	pgstat_report_activity(STATE_RUNNING,query_string);
  
  	set_ps_display("PARSE", false);
  
*************** exec_bind_message(StringInfo input_messa
*** 1429,1435 ****
  	 */
  	debug_query_string = psrc->query_string;
  
! 	pgstat_report_activity(psrc->query_string);
  
  	set_ps_display("BIND", false);
  
--- 1429,1435 ----
  	 */
  	debug_query_string = psrc->query_string;
  
! 	pgstat_report_activity(STATE_RUNNING,psrc->query_string);
  
  	set_ps_display("BIND", false);
  
*************** exec_execute_message(const char *portal_
*** 1836,1842 ****
  	 */
  	debug_query_string = sourceText;
  
! 	pgstat_report_activity(sourceText);
  
  	set_ps_display(portal->commandTag, false);
  
--- 1836,1842 ----
  	 */
  	debug_query_string = sourceText;
  
! 	pgstat_report_activity(STATE_RUNNING,sourceText);
  
  	set_ps_display(portal->commandTag, false);
  
*************** PostgresMain(int argc, char *argv[], con
*** 3811,3822 ****
  			if (IsAbortedTransactionBlockState())
  			{
  				set_ps_display("idle in transaction (aborted)", false);
! 				pgstat_report_activity("<IDLE> in transaction (aborted)");
  			}
  			else if (IsTransactionOrTransactionBlock())
  			{
  				set_ps_display("idle in transaction", false);
! 				pgstat_report_activity("<IDLE> in transaction");
  			}
  			else
  			{
--- 3811,3822 ----
  			if (IsAbortedTransactionBlockState())
  			{
  				set_ps_display("idle in transaction (aborted)", false);
! 				pgstat_report_activity(STATE_IDLEINTRANSACTION_ABRT,NULL);
  			}
  			else if (IsTransactionOrTransactionBlock())
  			{
  				set_ps_display("idle in transaction", false);
! 				pgstat_report_activity(STATE_IDLEINTRANSACTION,NULL);
  			}
  			else
  			{
*************** PostgresMain(int argc, char *argv[], con
*** 3824,3830 ****
  				pgstat_report_stat(false);
  
  				set_ps_display("idle", false);
! 				pgstat_report_activity("<IDLE>");
  			}
  
  			ReadyForQuery(whereToSendOutput);
--- 3824,3830 ----
  				pgstat_report_stat(false);
  
  				set_ps_display("idle", false);
! 				pgstat_report_activity(STATE_IDLE,NULL);
  			}
  
  			ReadyForQuery(whereToSendOutput);
*************** PostgresMain(int argc, char *argv[], con
*** 3944,3950 ****
  				SetCurrentStatementStartTimestamp();
  
  				/* Report query to various monitoring facilities. */
! 				pgstat_report_activity("<FASTPATH> function call");
  				set_ps_display("<FASTPATH>", false);
  
  				/* start an xact for this function invocation */
--- 3944,3950 ----
  				SetCurrentStatementStartTimestamp();
  
  				/* Report query to various monitoring facilities. */
! 				pgstat_report_activity(STATE_FASTPATH,NULL);
  				set_ps_display("<FASTPATH>", false);
  
  				/* start an xact for this function invocation */
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
new file mode 100644
index b4986d8..af6791f
*** a/src/backend/utils/adt/pgstatfuncs.c
--- b/src/backend/utils/adt/pgstatfuncs.c
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 507,513 ****
  
  		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
  
! 		tupdesc = CreateTemplateTupleDesc(12, false);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid",
  						   OIDOID, -1, 0);
  		/* This should have been called 'pid';  can't change it. 2011-06-11 */
--- 507,513 ----
  
  		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
  
! 		tupdesc = CreateTemplateTupleDesc(14, false);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid",
  						   OIDOID, -1, 0);
  		/* This should have been called 'pid';  can't change it. 2011-06-11 */
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 517,537 ****
  						   OIDOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "application_name",
  						   TEXTOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "current_query",
  						   TEXTOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "waiting",
  						   BOOLOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "act_start",
  						   TIMESTAMPTZOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 8, "query_start",
  						   TIMESTAMPTZOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 9, "backend_start",
  						   TIMESTAMPTZOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 10, "client_addr",
  						   INETOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 11, "client_hostname",
  						   TEXTOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 12, "client_port",
  						   INT4OID, -1, 0);
  
  		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
--- 517,541 ----
  						   OIDOID, -1, 0);
  		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "application_name",
  						   TEXTOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "state",
  						   TEXTOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "query",
! 						   TEXTOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "waiting",
  						   BOOLOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 8, "act_start",
  						   TIMESTAMPTZOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 9, "query_start",
  						   TIMESTAMPTZOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 10, "backend_start",
  						   TIMESTAMPTZOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 11, "state_change",
! 						   TIMESTAMPTZOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 12, "client_addr",
  						   INETOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 13, "client_hostname",
  						   TEXTOID, -1, 0);
! 		TupleDescInitEntry(tupdesc, (AttrNumber) 14, "client_port",
  						   INT4OID, -1, 0);
  
  		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 584,591 ****
  	if (funcctx->call_cntr < funcctx->max_calls)
  	{
  		/* for each row */
! 		Datum		values[12];
! 		bool		nulls[12];
  		HeapTuple	tuple;
  		PgBackendStatus *beentry;
  		SockAddr	zero_clientaddr;
--- 588,595 ----
  	if (funcctx->call_cntr < funcctx->max_calls)
  	{
  		/* for each row */
! 		Datum		values[14];
! 		bool		nulls[14];
  		HeapTuple	tuple;
  		PgBackendStatus *beentry;
  		SockAddr	zero_clientaddr;
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 610,617 ****
  			for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
  				nulls[i] = true;
  
! 			nulls[4] = false;
! 			values[4] = CStringGetTextDatum("<backend information not available>");
  
  			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
  			SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
--- 614,621 ----
  			for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
  				nulls[i] = true;
  
! 			nulls[5] = false;
! 			values[5] = CStringGetTextDatum("<backend information not available>");
  
  			tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
  			SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 629,668 ****
  		/* Values only available to same user or superuser */
  		if (superuser() || beentry->st_userid == GetUserId())
  		{
  			if (*(beentry->st_activity) == '\0')
  			{
! 				values[4] = CStringGetTextDatum("<command string not enabled>");
  			}
  			else
  			{
! 				values[4] = CStringGetTextDatum(beentry->st_activity);
! 			}
! 
! 			values[5] = BoolGetDatum(beentry->st_waiting);
  
  			if (beentry->st_xact_start_timestamp != 0)
! 				values[6] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
  			else
! 				nulls[6] = true;
  
  			if (beentry->st_activity_start_timestamp != 0)
! 				values[7] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
  			else
! 				nulls[7] = true;
  
  			if (beentry->st_proc_start_timestamp != 0)
! 				values[8] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
  			else
! 				nulls[8] = true;
  
  			/* A zeroed client addr means we don't know */
  			memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
  			if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
  					   sizeof(zero_clientaddr) == 0))
  			{
- 				nulls[9] = true;
- 				nulls[10] = true;
  				nulls[11] = true;
  			}
  			else
  			{
--- 633,711 ----
  		/* Values only available to same user or superuser */
  		if (superuser() || beentry->st_userid == GetUserId())
  		{
+             if ( beentry->st_state == -1)
+             {
+                 nulls[4] = true;
+             }
+             else
+             {
+                 switch(beentry->st_state)
+                 {
+                     case STATE_UNDEFINED:
+                         values[4] = CStringGetTextDatum("");
+                         break;
+                     case STATE_IDLE:
+                         values[4] = CStringGetTextDatum("idle");
+                         break;
+                     case STATE_RUNNING:
+                         values[4] = CStringGetTextDatum("active");
+                         break;
+                     case STATE_IDLEINTRANSACTION:
+                         values[4] = CStringGetTextDatum("idle in transaction");
+                         break;
+                     case STATE_FASTPATH:
+                         values[4] = CStringGetTextDatum("fastpath function call");
+                         break;
+                     case STATE_IDLEINTRANSACTION_ABRT:
+                         values[4] = CStringGetTextDatum("idle in transaction (aborted)");
+                         break;
+                 }
+             }
  			if (*(beentry->st_activity) == '\0')
  			{
!                 if ( beentry->st_state >= 0 )
!                 {
!                     values[5] = CStringGetTextDatum("");
!                 }
!                 else
!                 {
! 				    values[5] = CStringGetTextDatum("<command string not enabled>");
!                 }
  			}
  			else
  			{
! 				values[5] = CStringGetTextDatum(beentry->st_activity);
!             }
! 			values[6] = BoolGetDatum(beentry->st_waiting);
  
  			if (beentry->st_xact_start_timestamp != 0)
! 				values[7] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
  			else
! 				nulls[7] = true;
  
  			if (beentry->st_activity_start_timestamp != 0)
! 				values[8] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
  			else
! 				nulls[8] = true;
  
  			if (beentry->st_proc_start_timestamp != 0)
! 				values[9] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
  			else
! 				nulls[9] = true;
! 
! 			if (beentry->st_state_start_timestamp != 0)
! 				values[10] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
! 			else
! 				nulls[10] = true;
  
  			/* A zeroed client addr means we don't know */
  			memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
  			if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
  					   sizeof(zero_clientaddr) == 0))
  			{
  				nulls[11] = true;
+ 				nulls[12] = true;
+ 				nulls[13] = true;
  			}
  			else
  			{
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 686,704 ****
  					if (ret == 0)
  					{
  						clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
! 						values[9] = DirectFunctionCall1(inet_in,
  											   CStringGetDatum(remote_host));
  						if (beentry->st_clienthostname)
! 							values[10] = CStringGetTextDatum(beentry->st_clienthostname);
  						else
! 							nulls[10] = true;
! 						values[11] = Int32GetDatum(atoi(remote_port));
  					}
  					else
  					{
- 						nulls[9] = true;
- 						nulls[10] = true;
  						nulls[11] = true;
  					}
  				}
  				else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
--- 729,747 ----
  					if (ret == 0)
  					{
  						clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
! 						values[11] = DirectFunctionCall1(inet_in,
  											   CStringGetDatum(remote_host));
  						if (beentry->st_clienthostname)
! 							values[12] = CStringGetTextDatum(beentry->st_clienthostname);
  						else
! 							nulls[12] = true;
! 						values[13] = Int32GetDatum(atoi(remote_port));
  					}
  					else
  					{
  						nulls[11] = true;
+ 						nulls[12] = true;
+ 						nulls[13] = true;
  					}
  				}
  				else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
*************** pg_stat_get_activity(PG_FUNCTION_ARGS)
*** 709,738 ****
  					 * connections we have no permissions to view, or with
  					 * errors.
  					 */
! 					nulls[9] = true;
! 					nulls[10] = true;
! 					values[11] = DatumGetInt32(-1);
  				}
  				else
  				{
  					/* Unknown address type, should never happen */
- 					nulls[9] = true;
- 					nulls[10] = true;
  					nulls[11] = true;
  				}
  			}
  		}
  		else
  		{
  			/* No permissions to view data about this session */
! 			values[4] = CStringGetTextDatum("<insufficient privilege>");
! 			nulls[5] = true;
  			nulls[6] = true;
  			nulls[7] = true;
  			nulls[8] = true;
  			nulls[9] = true;
  			nulls[10] = true;
  			nulls[11] = true;
  		}
  
  		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
--- 752,783 ----
  					 * connections we have no permissions to view, or with
  					 * errors.
  					 */
! 					nulls[11] = true;
! 					nulls[12] = true;
! 					values[13] = DatumGetInt32(-1);
  				}
  				else
  				{
  					/* Unknown address type, should never happen */
  					nulls[11] = true;
+ 					nulls[12] = true;
+ 					nulls[13] = true;
  				}
  			}
  		}
  		else
  		{
  			/* No permissions to view data about this session */
! 			values[5] = CStringGetTextDatum("<insufficient privilege>");
! 			nulls[4] = true;
  			nulls[6] = true;
  			nulls[7] = true;
  			nulls[8] = true;
  			nulls[9] = true;
  			nulls[10] = true;
  			nulls[11] = true;
+ 			nulls[12] = true;
+ 			nulls[13] = true;
  		}
  
  		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
diff --git a/src/include/c.h b/src/include/c.h
new file mode 100644
index 7396adb..6ddec4c
*** a/src/include/c.h
--- b/src/include/c.h
*************** typedef NameData *Name;
*** 708,713 ****
--- 708,719 ----
  #define STATUS_EOF				(-2)
  #define STATUS_FOUND			(1)
  #define STATUS_WAITING			(2)
+ #define STATE_UNDEFINED         (-1)
+ #define STATE_IDLE              (0)
+ #define STATE_RUNNING           (1)
+ #define STATE_IDLEINTRANSACTION (2)
+ #define STATE_FASTPATH          (3)
+ #define STATE_IDLEINTRANSACTION_ABRT (4)
  
  
  /* gettext domain name mangling */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index 355c61a..9994468
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DATA(insert OID = 3057 ( pg_stat_get_aut
*** 2573,2581 ****
  DESCR("statistics: number of auto analyzes for a table");
  DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 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 0 f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,16,1184,1184,1184,869,25,23}" "{i,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,procpid,usesysid,application_name,current_query,waiting,xact_start,query_start,backend_start,client_addr,client_hostname,client_port}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
  DESCR("statistics: information about currently active backends");
! DATA(insert OID = 3099 (  pg_stat_get_wal_senders	PGNSP PGUID 12 1 10 0 0 f f f f t s 0 0 2249 "" "{23,25,25,25,25,25,23,25}" "{o,o,o,o,o,o,o,o}" "{procpid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
  DESCR("statistics: information about currently active replication");
  DATA(insert OID = 2026 (  pg_backend_pid				PGNSP PGUID 12 1 0 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");
--- 2573,2581 ----
  DESCR("statistics: number of auto analyzes for a table");
  DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 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 0 f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
  DESCR("statistics: information about currently active backends");
! DATA(insert OID = 3099 (  pg_stat_get_wal_senders	PGNSP PGUID 12 1 10 0 0 f f f f t s 0 0 2249 "" "{23,25,25,25,25,25,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
  DESCR("statistics: information about currently active replication");
  DATA(insert OID = 2026 (  pg_backend_pid				PGNSP PGUID 12 1 0 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");
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
new file mode 100644
index b8c6d82..5ce8eb2
*** a/src/include/pgstat.h
--- b/src/include/pgstat.h
*************** typedef struct PgBackendStatus
*** 622,627 ****
--- 622,628 ----
  	TimestampTz st_proc_start_timestamp;
  	TimestampTz st_xact_start_timestamp;
  	TimestampTz st_activity_start_timestamp;
+     TimestampTz st_state_start_timestamp;
  
  	/* Database OID, owning user's OID, connection client address */
  	Oid			st_databaseid;
*************** typedef struct PgBackendStatus
*** 632,637 ****
--- 633,641 ----
  	/* Is backend currently waiting on an lmgr lock? */
  	bool		st_waiting;
  
+     /* current state integer */
+     int       st_state;
+ 
  	/* application name; MUST be null-terminated */
  	char	   *st_appname;
  
*************** extern void pgstat_report_recovery_confl
*** 715,721 ****
  extern void pgstat_initialize(void);
  extern void pgstat_bestart(void);
  
! 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);
--- 719,725 ----
  extern void pgstat_initialize(void);
  extern void pgstat_bestart(void);
  
! extern void pgstat_report_activity(int state, 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);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
new file mode 100644
index 454e1f9..d26881f
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
*************** SELECT viewname, definition FROM pg_view
*** 1292,1304 ****
   pg_seclabels                    | ((((((((SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (rel.relkind = 'r'::"char") THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text ELSE NULL::text END AS objtype, rel.relnamespace AS objnamespace, CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'column'::text AS objtype, rel.relnamespace AS objnamespace, ((CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END || '.'::text) || (att.attname)::text) AS objname, l.provider, l.label FROM (((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid <> 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (pro.proisagg = true) THEN 'aggregate'::text WHEN (pro.proisagg = false) THEN 'function'::text ELSE NULL::text END AS objtype, pro.pronamespace AS objnamespace, (((CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text)) END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text ELSE 'type'::text END AS objtype, typ.typnamespace AS objnamespace, CASE WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'large object'::text AS objtype, NULL::oid AS objnamespace, (l.objoid)::text AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0))) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'language'::text AS objtype, NULL::oid AS objnamespace, quote_ident((lan.lanname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'schema'::text AS objtype, nsp.oid AS objnamespace, quote_ident((nsp.nspname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'database'::text AS objtype, NULL::oid AS objnamespace, quote_ident((dat.datname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_database dat ON (((l.classoid = dat.tableoid) AND (l.objoid = dat.oid))))) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'tablespace'::text AS objtype, NULL::oid AS objnamespace, quote_ident((spc.spcname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_tablespace spc ON (((l.classoid = spc.tableoid) AND (l.objoid = spc.oid))))) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'role'::text AS objtype, NULL::oid AS objnamespace, quote_ident((rol.rolname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_authid rol ON (((l.classoid = rol.tableoid) AND (l.objoid = rol.oid))));
   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.rolreplication AS userepl, 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.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, s.xact_start, s.query_start, s.waiting, s.current_query FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, application_name, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_hostname, client_port), 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, pg_stat_get_vacuum_count(c.oid) AS vacuum_count, pg_stat_get_autovacuum_count(c.oid) AS autovacuum_count, pg_stat_get_analyze_count(c.oid) AS analyze_count, pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count 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_fsync_backend() AS buffers_backend_fsync, pg_stat_get_buf_alloc() AS buffers_alloc, pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
   pg_stat_database                | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted, pg_stat_get_db_conflict_all(d.oid) AS conflicts, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM pg_database d;
   pg_stat_database_conflicts      | SELECT d.oid AS datid, d.datname, pg_stat_get_db_conflict_tablespace(d.oid) AS confl_tablespace, pg_stat_get_db_conflict_lock(d.oid) AS confl_lock, pg_stat_get_db_conflict_snapshot(d.oid) AS confl_snapshot, pg_stat_get_db_conflict_bufferpin(d.oid) AS confl_bufferpin, pg_stat_get_db_conflict_startup_deadlock(d.oid) AS confl_deadlock FROM pg_database d;
!  pg_stat_replication             | SELECT s.procpid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, w.state, w.sent_location, w.write_location, w.flush_location, w.replay_location, w.sync_priority, w.sync_state FROM pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, application_name, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_hostname, client_port), pg_authid u, pg_stat_get_wal_senders() w(procpid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) WHERE ((s.usesysid = u.oid) AND (s.procpid = w.procpid));
   pg_stat_sys_indexes             | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE ((pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_indexes.schemaname ~ '^pg_toast'::text));
   pg_stat_sys_tables              | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.n_tup_hot_upd, pg_stat_all_tables.n_live_tup, pg_stat_all_tables.n_dead_tup, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze, pg_stat_all_tables.vacuum_count, pg_stat_all_tables.autovacuum_count, pg_stat_all_tables.analyze_count, pg_stat_all_tables.autoanalyze_count FROM pg_stat_all_tables WHERE ((pg_stat_all_tables.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_tables.schemaname ~ '^pg_toast'::text));
   pg_stat_user_functions          | SELECT p.oid AS funcid, n.nspname AS schemaname, p.proname AS funcname, pg_stat_get_function_calls(p.oid) AS calls, (pg_stat_get_function_time(p.oid) / 1000) AS total_time, (pg_stat_get_function_self_time(p.oid) / 1000) AS self_time FROM (pg_proc p LEFT JOIN pg_namespace n ON ((n.oid = p.pronamespace))) WHERE ((p.prolang <> (12)::oid) AND (pg_stat_get_function_calls(p.oid) IS NOT NULL));
--- 1292,1304 ----
   pg_seclabels                    | ((((((((SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (rel.relkind = 'r'::"char") THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text WHEN (rel.relkind = 'f'::"char") THEN 'foreign table'::text ELSE NULL::text END AS objtype, rel.relnamespace AS objnamespace, CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'column'::text AS objtype, rel.relnamespace AS objnamespace, ((CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END || '.'::text) || (att.attname)::text) AS objname, l.provider, l.label FROM (((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid <> 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (pro.proisagg = true) THEN 'aggregate'::text WHEN (pro.proisagg = false) THEN 'function'::text ELSE NULL::text END AS objtype, pro.pronamespace AS objnamespace, (((CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text)) END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text ELSE 'type'::text END AS objtype, typ.typnamespace AS objnamespace, CASE WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'large object'::text AS objtype, NULL::oid AS objnamespace, (l.objoid)::text AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) WHERE ((l.classoid = ('pg_largeobject'::regclass)::oid) AND (l.objsubid = 0))) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'language'::text AS objtype, NULL::oid AS objnamespace, quote_ident((lan.lanname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'schema'::text AS objtype, nsp.oid AS objnamespace, quote_ident((nsp.nspname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'database'::text AS objtype, NULL::oid AS objnamespace, quote_ident((dat.datname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_database dat ON (((l.classoid = dat.tableoid) AND (l.objoid = dat.oid))))) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'tablespace'::text AS objtype, NULL::oid AS objnamespace, quote_ident((spc.spcname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_tablespace spc ON (((l.classoid = spc.tableoid) AND (l.objoid = spc.oid))))) UNION ALL SELECT l.objoid, l.classoid, 0 AS objsubid, 'role'::text AS objtype, NULL::oid AS objnamespace, quote_ident((rol.rolname)::text) AS objname, l.provider, l.label FROM (pg_shseclabel l JOIN pg_authid rol ON (((l.classoid = rol.tableoid) AND (l.objoid = rol.oid))));
   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.rolreplication AS userepl, 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.pid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, s.xact_start, s.query_start, s.state_change, s.waiting, s.state, s.query FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port), 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, pg_stat_get_vacuum_count(c.oid) AS vacuum_count, pg_stat_get_autovacuum_count(c.oid) AS autovacuum_count, pg_stat_get_analyze_count(c.oid) AS analyze_count, pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count 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_fsync_backend() AS buffers_backend_fsync, pg_stat_get_buf_alloc() AS buffers_alloc, pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
   pg_stat_database                | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted, pg_stat_get_db_conflict_all(d.oid) AS conflicts, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM pg_database d;
   pg_stat_database_conflicts      | SELECT d.oid AS datid, d.datname, pg_stat_get_db_conflict_tablespace(d.oid) AS confl_tablespace, pg_stat_get_db_conflict_lock(d.oid) AS confl_lock, pg_stat_get_db_conflict_snapshot(d.oid) AS confl_snapshot, pg_stat_get_db_conflict_bufferpin(d.oid) AS confl_bufferpin, pg_stat_get_db_conflict_startup_deadlock(d.oid) AS confl_deadlock FROM pg_database d;
!  pg_stat_replication             | SELECT s.pid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, w.state, w.sent_location, w.write_location, w.flush_location, w.replay_location, w.sync_priority, w.sync_state FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port), pg_authid u, pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) WHERE ((s.usesysid = u.oid) AND (s.pid = w.pid));
   pg_stat_sys_indexes             | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE ((pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_indexes.schemaname ~ '^pg_toast'::text));
   pg_stat_sys_tables              | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.n_tup_hot_upd, pg_stat_all_tables.n_live_tup, pg_stat_all_tables.n_dead_tup, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze, pg_stat_all_tables.vacuum_count, pg_stat_all_tables.autovacuum_count, pg_stat_all_tables.analyze_count, pg_stat_all_tables.autoanalyze_count FROM pg_stat_all_tables WHERE ((pg_stat_all_tables.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_tables.schemaname ~ '^pg_toast'::text));
   pg_stat_user_functions          | SELECT p.oid AS funcid, n.nspname AS schemaname, p.proname AS funcname, pg_stat_get_function_calls(p.oid) AS calls, (pg_stat_get_function_time(p.oid) / 1000) AS total_time, (pg_stat_get_function_self_time(p.oid) / 1000) AS self_time FROM (pg_proc p LEFT JOIN pg_namespace n ON ((n.oid = p.pronamespace))) WHERE ((p.prolang <> (12)::oid) AND (pg_stat_get_function_calls(p.oid) IS NOT NULL));