]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/pgstatfuncs.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / pgstatfuncs.c
index adab948e0dc04db2afda7fb83d11c434f42593f8..a987d0d62143a629491b3878d6389fdc220f5e6b 100644 (file)
@@ -3,7 +3,7 @@
  * pgstatfuncs.c
  *       Functions for accessing the statistics collector data
  *
- * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  */
 #include "postgres.h"
 
+#include "access/htup_details.h"
+#include "catalog/pg_type.h"
+#include "common/ip.h"
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "pgstat.h"
-#include "catalog/pg_type.h"
+#include "storage/proc.h"
+#include "storage/procarray.h"
+#include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/inet.h"
-#include "libpq/ip.h"
-
-/* bogus ... these externs should be in a header file */
-extern Datum pg_stat_get_numscans(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_tuples_returned(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_tuples_updated(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_live_tuples(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_dead_tuples(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_blocks_hit(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_vacuum_count(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_analyze_count(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS);
-
-extern Datum pg_stat_get_function_calls(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_function_time(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_function_self_time(PG_FUNCTION_ARGS);
-
-extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_activity(PG_FUNCTION_ARGS);
-extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_waiting(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_backend_client_port(PG_FUNCTION_ARGS);
-
-extern Datum pg_stat_get_db_numbackends(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS);
-
-extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_buf_alloc(PG_FUNCTION_ARGS);
-
-extern Datum pg_stat_get_xact_numscans(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS);
-
-extern Datum pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_function_time(PG_FUNCTION_ARGS);
-extern Datum pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS);
-
-extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS);
-extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
-extern Datum pg_stat_reset_shared(PG_FUNCTION_ARGS);
-extern Datum pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS);
-extern Datum pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS);
+#include "utils/timestamp.h"
+
+#define UINT32_ACCESS_ONCE(var)                 ((uint32)(*((volatile uint32 *)&(var))))
 
 /* Global bgwriter statistics, from bgwriter.c */
 extern PgStat_MsgBgWriter bgwriterStats;
@@ -248,6 +176,22 @@ pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)
 }
 
 
+Datum
+pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS)
+{
+       Oid                     relid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatTabEntry *tabentry;
+
+       if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
+               result = 0;
+       else
+               result = (int64) (tabentry->changes_since_analyze);
+
+       PG_RETURN_INT64(result);
+}
+
+
 Datum
 pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
 {
@@ -356,7 +300,7 @@ pg_stat_get_vacuum_count(PG_FUNCTION_ARGS)
 {
        Oid                     relid = PG_GETARG_OID(0);
        int64           result;
-       PgStat_StatTabEntry     *tabentry;
+       PgStat_StatTabEntry *tabentry;
 
        if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
                result = 0;
@@ -371,7 +315,7 @@ pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS)
 {
        Oid                     relid = PG_GETARG_OID(0);
        int64           result;
-       PgStat_StatTabEntry     *tabentry;
+       PgStat_StatTabEntry *tabentry;
 
        if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
                result = 0;
@@ -386,7 +330,7 @@ pg_stat_get_analyze_count(PG_FUNCTION_ARGS)
 {
        Oid                     relid = PG_GETARG_OID(0);
        int64           result;
-       PgStat_StatTabEntry     *tabentry;
+       PgStat_StatTabEntry *tabentry;
 
        if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
                result = 0;
@@ -401,7 +345,7 @@ pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS)
 {
        Oid                     relid = PG_GETARG_OID(0);
        int64           result;
-       PgStat_StatTabEntry     *tabentry;
+       PgStat_StatTabEntry *tabentry;
 
        if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
                result = 0;
@@ -423,14 +367,15 @@ pg_stat_get_function_calls(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_function_time(PG_FUNCTION_ARGS)
+pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
 {
        Oid                     funcid = PG_GETARG_OID(0);
        PgStat_StatFuncEntry *funcentry;
 
        if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
                PG_RETURN_NULL();
-       PG_RETURN_INT64(funcentry->f_time);
+       /* convert counter from microsec to millisec for display */
+       PG_RETURN_FLOAT8(((double) funcentry->f_total_time) / 1000.0);
 }
 
 Datum
@@ -441,7 +386,8 @@ pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
 
        if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
                PG_RETURN_NULL();
-       PG_RETURN_INT64(funcentry->f_time_self);
+       /* convert counter from microsec to millisec for display */
+       PG_RETURN_FLOAT8(((double) funcentry->f_self_time) / 1000.0);
 }
 
 Datum
@@ -484,116 +430,190 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
        }
 }
 
+/*
+ * Returns command progress information for the named command.
+ */
 Datum
-pg_stat_get_activity(PG_FUNCTION_ARGS)
-{
-       FuncCallContext *funcctx;
+pg_stat_get_progress_info(PG_FUNCTION_ARGS)
+{
+#define PG_STAT_GET_PROGRESS_COLS      PGSTAT_NUM_PROGRESS_PARAM + 3
+       int                     num_backends = pgstat_fetch_stat_numbackends();
+       int                     curr_backend;
+       char       *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
+       ProgressCommandType cmdtype;
+       TupleDesc       tupdesc;
+       Tuplestorestate *tupstore;
+       ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+       MemoryContext per_query_ctx;
+       MemoryContext oldcontext;
+
+       /* check to see if caller supports us returning a tuplestore */
+       if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("set-valued function called in context that cannot accept a set")));
+       if (!(rsinfo->allowedModes & SFRM_Materialize))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("materialize mode required, but it is not " \
+                                               "allowed in this context")));
+
+       /* Build a tuple descriptor for our result type */
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       /* Translate command name into command type code. */
+       if (pg_strcasecmp(cmd, "VACUUM") == 0)
+               cmdtype = PROGRESS_COMMAND_VACUUM;
+       else
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("invalid command name: \"%s\"", cmd)));
 
-       if (SRF_IS_FIRSTCALL())
+       per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+       oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+       tupstore = tuplestore_begin_heap(true, false, work_mem);
+       rsinfo->returnMode = SFRM_Materialize;
+       rsinfo->setResult = tupstore;
+       rsinfo->setDesc = tupdesc;
+       MemoryContextSwitchTo(oldcontext);
+
+       /* 1-based index */
+       for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
        {
-               MemoryContext oldcontext;
-               TupleDesc       tupdesc;
+               LocalPgBackendStatus *local_beentry;
+               PgBackendStatus *beentry;
+               Datum           values[PG_STAT_GET_PROGRESS_COLS];
+               bool            nulls[PG_STAT_GET_PROGRESS_COLS];
+               int                     i;
 
-               funcctx = SRF_FIRSTCALL_INIT();
+               MemSet(values, 0, sizeof(values));
+               MemSet(nulls, 0, sizeof(nulls));
+
+               local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
+
+               if (!local_beentry)
+                       continue;
 
-               oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
-               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);
-               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_port", INT4OID, -1, 0);
-
-               funcctx->tuple_desc = BlessTupleDesc(tupdesc);
-
-               funcctx->user_fctx = palloc0(sizeof(int));
-               if (PG_ARGISNULL(0))
+               beentry = &local_beentry->backendStatus;
+
+               /*
+                * Report values for only those backends which are running the given
+                * command.
+                */
+               if (!beentry || beentry->st_progress_command != cmdtype)
+                       continue;
+
+               /* Value available to all callers */
+               values[0] = Int32GetDatum(beentry->st_procpid);
+               values[1] = ObjectIdGetDatum(beentry->st_databaseid);
+
+               /* show rest of the values including relid only to role members */
+               if (has_privs_of_role(GetUserId(), beentry->st_userid))
                {
-                       /* Get all backends */
-                       funcctx->max_calls = pgstat_fetch_stat_numbackends();
+                       values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
+                       for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
+                               values[i + 3] = Int64GetDatum(beentry->st_progress_param[i]);
                }
                else
                {
-                       /*
-                        * Get one backend - locate by pid.
-                        *
-                        * We lookup the backend early, so we can return zero rows if it
-                        * doesn't exist, instead of returning a single row full of NULLs.
-                        */
-                       int                     pid = PG_GETARG_INT32(0);
-                       int                     i;
-                       int                     n = pgstat_fetch_stat_numbackends();
-
-                       for (i = 1; i <= n; i++)
-                       {
-                               PgBackendStatus *be = pgstat_fetch_stat_beentry(i);
-
-                               if (be)
-                               {
-                                       if (be->st_procpid == pid)
-                                       {
-                                               *(int *) (funcctx->user_fctx) = i;
-                                               break;
-                                       }
-                               }
-                       }
-
-                       if (*(int *) (funcctx->user_fctx) == 0)
-                               /* Pid not found, return zero rows */
-                               funcctx->max_calls = 0;
-                       else
-                               funcctx->max_calls = 1;
+                       nulls[2] = true;
+                       for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
+                               nulls[i + 3] = true;
                }
 
-               MemoryContextSwitchTo(oldcontext);
+               tuplestore_putvalues(tupstore, tupdesc, values, nulls);
        }
 
-       /* stuff done on every call of the function */
-       funcctx = SRF_PERCALL_SETUP();
+       /* clean up and return the tuplestore */
+       tuplestore_donestoring(tupstore);
 
-       if (funcctx->call_cntr < funcctx->max_calls)
+       return (Datum) 0;
+}
+
+/*
+ * Returns activity of PG backends.
+ */
+Datum
+pg_stat_get_activity(PG_FUNCTION_ARGS)
+{
+#define PG_STAT_GET_ACTIVITY_COLS      23
+       int                     num_backends = pgstat_fetch_stat_numbackends();
+       int                     curr_backend;
+       int                     pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
+       ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+       TupleDesc       tupdesc;
+       Tuplestorestate *tupstore;
+       MemoryContext per_query_ctx;
+       MemoryContext oldcontext;
+
+       /* check to see if caller supports us returning a tuplestore */
+       if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("set-valued function called in context that cannot accept a set")));
+       if (!(rsinfo->allowedModes & SFRM_Materialize))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("materialize mode required, but it is not " \
+                                               "allowed in this context")));
+
+       /* Build a tuple descriptor for our result type */
+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+       oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+       tupstore = tuplestore_begin_heap(true, false, work_mem);
+       rsinfo->returnMode = SFRM_Materialize;
+       rsinfo->setResult = tupstore;
+       rsinfo->setDesc = tupdesc;
+
+       MemoryContextSwitchTo(oldcontext);
+
+       /* 1-based index */
+       for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
        {
                /* for each row */
-               Datum           values[11];
-               bool            nulls[11];
-               HeapTuple       tuple;
+               Datum           values[PG_STAT_GET_ACTIVITY_COLS];
+               bool            nulls[PG_STAT_GET_ACTIVITY_COLS];
+               LocalPgBackendStatus *local_beentry;
                PgBackendStatus *beentry;
-               SockAddr        zero_clientaddr;
+               PGPROC     *proc;
+               const char *wait_event_type;
+               const char *wait_event;
 
                MemSet(values, 0, sizeof(values));
                MemSet(nulls, 0, sizeof(nulls));
 
-               if (*(int *) (funcctx->user_fctx) > 0)
-               {
-                       /* Get specific pid slot */
-                       beentry = pgstat_fetch_stat_beentry(*(int *) (funcctx->user_fctx));
-               }
-               else
-               {
-                       /* Get the next one in the list */
-                       beentry = pgstat_fetch_stat_beentry(funcctx->call_cntr + 1);            /* 1-based index */
-               }
-               if (!beentry)
+               /* Get the next one in the list */
+               local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
+               if (!local_beentry)
                {
                        int                     i;
 
-                       for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++)
+                       /* Ignore missing entries if looking for specific PID */
+                       if (pid != -1)
+                               continue;
+
+                       for (i = 0; i < lengthof(nulls); i++)
                                nulls[i] = true;
 
-                       nulls[4] = false;
-                       values[4] = CStringGetTextDatum("<backend information not available>");
+                       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));
+                       tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+                       continue;
                }
 
+               beentry = &local_beentry->backendStatus;
+
+               /* If looking for specific PID, ignore all the others */
+               if (pid != -1 && beentry->st_procpid != pid)
+                       continue;
+
                /* Values available to all callers */
                values[0] = ObjectIdGetDatum(beentry->st_databaseid);
                values[1] = Int32GetDatum(beentry->st_procpid);
@@ -603,42 +623,117 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                else
                        nulls[3] = true;
 
-               /* Values only available to same user or superuser */
-               if (superuser() || beentry->st_userid == GetUserId())
+               if (TransactionIdIsValid(local_beentry->backend_xid))
+                       values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
+               else
+                       nulls[15] = true;
+
+               if (TransactionIdIsValid(local_beentry->backend_xmin))
+                       values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
+               else
+                       nulls[16] = true;
+
+               if (beentry->st_ssl)
                {
-                       if (*(beentry->st_activity) == '\0')
+                       values[17] = BoolGetDatum(true);        /* ssl */
+                       values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
+                       values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
+                       values[20] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
+                       values[21] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
+                       values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
+               }
+               else
+               {
+                       values[17] = BoolGetDatum(false);       /* ssl */
+                       nulls[18] = nulls[19] = nulls[20] = nulls[21] = nulls[22] = true;
+               }
+
+               /* Values only available to role member */
+               if (has_privs_of_role(GetUserId(), beentry->st_userid))
+               {
+                       SockAddr        zero_clientaddr;
+
+                       switch (beentry->st_state)
                        {
-                               values[4] = CStringGetTextDatum("<command string not enabled>");
+                               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_ABORTED:
+                                       values[4] = CStringGetTextDatum("idle in transaction (aborted)");
+                                       break;
+                               case STATE_DISABLED:
+                                       values[4] = CStringGetTextDatum("disabled");
+                                       break;
+                               case STATE_UNDEFINED:
+                                       nulls[4] = true;
+                                       break;
+                       }
+
+                       values[5] = CStringGetTextDatum(beentry->st_activity);
+
+                       proc = BackendPidGetProc(beentry->st_procpid);
+                       if (proc != NULL)
+                       {
+                               uint32          raw_wait_event;
+
+                               raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
+                               wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
+                               wait_event = pgstat_get_wait_event(raw_wait_event);
+
                        }
                        else
                        {
-                               values[4] = CStringGetTextDatum(beentry->st_activity);
+                               wait_event_type = NULL;
+                               wait_event = NULL;
                        }
 
-                       values[5] = BoolGetDatum(beentry->st_waiting);
+                       if (wait_event_type)
+                               values[6] = CStringGetTextDatum(wait_event_type);
+                       else
+                               nulls[6] = true;
+
+                       if (wait_event)
+                               values[7] = CStringGetTextDatum(wait_event);
+                       else
+                               nulls[7] = true;
 
                        if (beentry->st_xact_start_timestamp != 0)
-                               values[6] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
+                               values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
                        else
-                               nulls[6] = true;
+                               nulls[8] = true;
 
                        if (beentry->st_activity_start_timestamp != 0)
-                               values[7] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
+                               values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
                        else
-                               nulls[7] = true;
+                               nulls[9] = true;
 
                        if (beentry->st_proc_start_timestamp != 0)
-                               values[8] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
+                               values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
                        else
-                               nulls[8] = true;
+                               nulls[10] = true;
+
+                       if (beentry->st_state_start_timestamp != 0)
+                               values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
+                       else
+                               nulls[11] = 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))
+                                          sizeof(zero_clientaddr)) == 0)
                        {
-                               nulls[9] = true;
-                               nulls[10] = true;
+                               nulls[12] = true;
+                               nulls[13] = true;
+                               nulls[14] = true;
                        }
                        else
                        {
@@ -659,17 +754,23 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                                                                                         remote_host, sizeof(remote_host),
                                                                                         remote_port, sizeof(remote_port),
                                                                                         NI_NUMERICHOST | NI_NUMERICSERV);
-                                       if (ret)
+                                       if (ret == 0)
                                        {
-                                               nulls[9] = true;
-                                               nulls[10] = true;
+                                               clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
+                                               values[12] = DirectFunctionCall1(inet_in,
+                                                                                          CStringGetDatum(remote_host));
+                                               if (beentry->st_clienthostname &&
+                                                       beentry->st_clienthostname[0])
+                                                       values[13] = CStringGetTextDatum(beentry->st_clienthostname);
+                                               else
+                                                       nulls[13] = true;
+                                               values[14] = Int32GetDatum(atoi(remote_port));
                                        }
                                        else
                                        {
-                                               clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
-                                               values[9] = DirectFunctionCall1(inet_in,
-                                                                                          CStringGetDatum(remote_host));
-                                               values[10] = Int32GetDatum(atoi(remote_port));
+                                               nulls[12] = true;
+                                               nulls[13] = true;
+                                               nulls[14] = true;
                                        }
                                }
                                else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
@@ -680,38 +781,46 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
                                         * connections we have no permissions to view, or with
                                         * errors.
                                         */
-                                       nulls[9] = true;
-                                       values[10] = DatumGetInt32(-1);
+                                       nulls[12] = true;
+                                       nulls[13] = true;
+                                       values[14] = DatumGetInt32(-1);
                                }
                                else
                                {
                                        /* Unknown address type, should never happen */
-                                       nulls[9] = true;
-                                       nulls[10] = true;
+                                       nulls[12] = true;
+                                       nulls[13] = true;
+                                       nulls[14] = true;
                                }
                        }
                }
                else
                {
                        /* No permissions to view data about this session */
-                       values[4] = CStringGetTextDatum("<insufficient privilege>");
-                       nulls[5] = true;
+                       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;
+                       nulls[14] = true;
                }
 
-               tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+               tuplestore_putvalues(tupstore, tupdesc, values, nulls);
 
-               SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
-       }
-       else
-       {
-               /* nothing left */
-               SRF_RETURN_DONE(funcctx);
+               /* If only a single backend was requested, and we found it, break. */
+               if (pid != -1)
+                       break;
        }
+
+       /* clean up and return the tuplestore */
+       tuplestore_donestoring(tupstore);
+
+       return (Datum) 0;
 }
 
 
@@ -770,7 +879,7 @@ pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
 
        if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
                activity = "<backend information not available>";
-       else if (!superuser() && beentry->st_userid != GetUserId())
+       else if (!has_privs_of_role(GetUserId(), beentry->st_userid))
                activity = "<insufficient privilege>";
        else if (*(beentry->st_activity) == '\0')
                activity = "<command string not enabled>";
@@ -780,23 +889,46 @@ pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
        PG_RETURN_TEXT_P(cstring_to_text(activity));
 }
 
-
 Datum
-pg_stat_get_backend_waiting(PG_FUNCTION_ARGS)
+pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)
 {
        int32           beid = PG_GETARG_INT32(0);
-       bool            result;
        PgBackendStatus *beentry;
+       PGPROC     *proc;
+       const char *wait_event_type = NULL;
 
        if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
-               PG_RETURN_NULL();
+               wait_event_type = "<backend information not available>";
+       else if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+               wait_event_type = "<insufficient privilege>";
+       else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
+               wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
 
-       if (!superuser() && beentry->st_userid != GetUserId())
+       if (!wait_event_type)
                PG_RETURN_NULL();
 
-       result = beentry->st_waiting;
+       PG_RETURN_TEXT_P(cstring_to_text(wait_event_type));
+}
+
+Datum
+pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)
+{
+       int32           beid = PG_GETARG_INT32(0);
+       PgBackendStatus *beentry;
+       PGPROC     *proc;
+       const char *wait_event = NULL;
+
+       if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
+               wait_event = "<backend information not available>";
+       else if (!has_privs_of_role(GetUserId(), beentry->st_userid))
+               wait_event = "<insufficient privilege>";
+       else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
+               wait_event = pgstat_get_wait_event(proc->wait_event_info);
+
+       if (!wait_event)
+               PG_RETURN_NULL();
 
-       PG_RETURN_BOOL(result);
+       PG_RETURN_TEXT_P(cstring_to_text(wait_event));
 }
 
 
@@ -810,7 +942,7 @@ pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
        if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
                PG_RETURN_NULL();
 
-       if (!superuser() && beentry->st_userid != GetUserId())
+       if (!has_privs_of_role(GetUserId(), beentry->st_userid))
                PG_RETURN_NULL();
 
        result = beentry->st_activity_start_timestamp;
@@ -836,7 +968,7 @@ pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
        if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
                PG_RETURN_NULL();
 
-       if (!superuser() && beentry->st_userid != GetUserId())
+       if (!has_privs_of_role(GetUserId(), beentry->st_userid))
                PG_RETURN_NULL();
 
        result = beentry->st_xact_start_timestamp;
@@ -858,7 +990,7 @@ pg_stat_get_backend_start(PG_FUNCTION_ARGS)
        if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
                PG_RETURN_NULL();
 
-       if (!superuser() && beentry->st_userid != GetUserId())
+       if (!has_privs_of_role(GetUserId(), beentry->st_userid))
                PG_RETURN_NULL();
 
        result = beentry->st_proc_start_timestamp;
@@ -882,13 +1014,13 @@ pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
        if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
                PG_RETURN_NULL();
 
-       if (!superuser() && beentry->st_userid != GetUserId())
+       if (!has_privs_of_role(GetUserId(), beentry->st_userid))
                PG_RETURN_NULL();
 
        /* 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))
+                          sizeof(zero_clientaddr)) == 0)
                PG_RETURN_NULL();
 
        switch (beentry->st_clientaddr.addr.ss_family)
@@ -908,7 +1040,7 @@ pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
                                                         remote_host, sizeof(remote_host),
                                                         NULL, 0,
                                                         NI_NUMERICHOST | NI_NUMERICSERV);
-       if (ret)
+       if (ret != 0)
                PG_RETURN_NULL();
 
        clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
@@ -929,13 +1061,13 @@ pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
        if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
                PG_RETURN_NULL();
 
-       if (!superuser() && beentry->st_userid != GetUserId())
+       if (!has_privs_of_role(GetUserId(), beentry->st_userid))
                PG_RETURN_NULL();
 
        /* 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))
+                          sizeof(zero_clientaddr)) == 0)
                PG_RETURN_NULL();
 
        switch (beentry->st_clientaddr.addr.ss_family)
@@ -957,7 +1089,7 @@ pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
                                                         NULL, 0,
                                                         remote_port, sizeof(remote_port),
                                                         NI_NUMERICHOST | NI_NUMERICSERV);
-       if (ret)
+       if (ret != 0)
                PG_RETURN_NULL();
 
        PG_RETURN_DATUM(DirectFunctionCall1(int4in,
@@ -1129,6 +1261,197 @@ pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
        PG_RETURN_INT64(result);
 }
 
+Datum
+pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       TimestampTz result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = dbentry->stat_reset_timestamp;
+
+       if (result == 0)
+               PG_RETURN_NULL();
+       else
+               PG_RETURN_TIMESTAMPTZ(result);
+}
+
+Datum
+pg_stat_get_db_temp_files(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = dbentry->n_temp_files;
+
+       PG_RETURN_INT64(result);
+}
+
+
+Datum
+pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = dbentry->n_temp_bytes;
+
+       PG_RETURN_INT64(result);
+}
+
+Datum
+pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = (int64) (dbentry->n_conflict_tablespace);
+
+       PG_RETURN_INT64(result);
+}
+
+Datum
+pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = (int64) (dbentry->n_conflict_lock);
+
+       PG_RETURN_INT64(result);
+}
+
+Datum
+pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = (int64) (dbentry->n_conflict_snapshot);
+
+       PG_RETURN_INT64(result);
+}
+
+Datum
+pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = (int64) (dbentry->n_conflict_bufferpin);
+
+       PG_RETURN_INT64(result);
+}
+
+Datum
+pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = (int64) (dbentry->n_conflict_startup_deadlock);
+
+       PG_RETURN_INT64(result);
+}
+
+Datum
+pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = (int64) (
+                                                 dbentry->n_conflict_tablespace +
+                                                 dbentry->n_conflict_lock +
+                                                 dbentry->n_conflict_snapshot +
+                                                 dbentry->n_conflict_bufferpin +
+                                                 dbentry->n_conflict_startup_deadlock);
+
+       PG_RETURN_INT64(result);
+}
+
+Datum
+pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       int64           result;
+       PgStat_StatDBEntry *dbentry;
+
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = (int64) (dbentry->n_deadlocks);
+
+       PG_RETURN_INT64(result);
+}
+
+Datum
+pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       double          result;
+       PgStat_StatDBEntry *dbentry;
+
+       /* convert counter from microsec to millisec for display */
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = ((double) dbentry->n_block_read_time) / 1000.0;
+
+       PG_RETURN_FLOAT8(result);
+}
+
+Datum
+pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS)
+{
+       Oid                     dbid = PG_GETARG_OID(0);
+       double          result;
+       PgStat_StatDBEntry *dbentry;
+
+       /* convert counter from microsec to millisec for display */
+       if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+               result = 0;
+       else
+               result = ((double) dbentry->n_block_write_time) / 1000.0;
+
+       PG_RETURN_FLOAT8(result);
+}
+
 Datum
 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
 {
@@ -1159,6 +1482,26 @@ pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
        PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
 }
 
+Datum
+pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
+{
+       /* time is already in msec, just convert to double for presentation */
+       PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_write_time);
+}
+
+Datum
+pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
+{
+       /* time is already in msec, just convert to double for presentation */
+       PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_sync_time);
+}
+
+Datum
+pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
+{
+       PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
 {
@@ -1342,14 +1685,14 @@ pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_xact_function_time(PG_FUNCTION_ARGS)
+pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS)
 {
        Oid                     funcid = PG_GETARG_OID(0);
        PgStat_BackendFunctionEntry *funcentry;
 
        if ((funcentry = find_funcstat_entry(funcid)) == NULL)
                PG_RETURN_NULL();
-       PG_RETURN_INT64(INSTR_TIME_GET_MICROSEC(funcentry->f_counts.f_time));
+       PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_total_time));
 }
 
 Datum
@@ -1360,10 +1703,17 @@ pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)
 
        if ((funcentry = find_funcstat_entry(funcid)) == NULL)
                PG_RETURN_NULL();
-       PG_RETURN_INT64(INSTR_TIME_GET_MICROSEC(funcentry->f_counts.f_time_self));
+       PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_self_time));
 }
 
 
+/* Get the timestamp of the current statistics snapshot */
+Datum
+pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
+{
+       PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stats_timestamp);
+}
+
 /* Discard the active statistics snapshot */
 Datum
 pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
@@ -1394,7 +1744,7 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
        PG_RETURN_VOID();
 }
 
-/* Reset a single counter in the current database */
+/* Reset a single counter in the current database */
 Datum
 pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
 {
@@ -1414,3 +1764,70 @@ pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
 
        PG_RETURN_VOID();
 }
+
+Datum
+pg_stat_get_archiver(PG_FUNCTION_ARGS)
+{
+       TupleDesc       tupdesc;
+       Datum           values[7];
+       bool            nulls[7];
+       PgStat_ArchiverStats *archiver_stats;
+
+       /* Initialise values and NULL flags arrays */
+       MemSet(values, 0, sizeof(values));
+       MemSet(nulls, 0, sizeof(nulls));
+
+       /* Initialise attributes information in the tuple descriptor */
+       tupdesc = CreateTemplateTupleDesc(7, false);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
+                                          INT8OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
+                                          TIMESTAMPTZOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
+                                          INT8OID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
+                                          TIMESTAMPTZOID, -1, 0);
+       TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
+                                          TIMESTAMPTZOID, -1, 0);
+
+       BlessTupleDesc(tupdesc);
+
+       /* Get statistics about the archiver process */
+       archiver_stats = pgstat_fetch_stat_archiver();
+
+       /* Fill values and NULLs */
+       values[0] = Int64GetDatum(archiver_stats->archived_count);
+       if (*(archiver_stats->last_archived_wal) == '\0')
+               nulls[1] = true;
+       else
+               values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
+
+       if (archiver_stats->last_archived_timestamp == 0)
+               nulls[2] = true;
+       else
+               values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
+
+       values[3] = Int64GetDatum(archiver_stats->failed_count);
+       if (*(archiver_stats->last_failed_wal) == '\0')
+               nulls[4] = true;
+       else
+               values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
+
+       if (archiver_stats->last_failed_timestamp == 0)
+               nulls[5] = true;
+       else
+               values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
+
+       if (archiver_stats->stat_reset_timestamp == 0)
+               nulls[6] = true;
+       else
+               values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
+
+       /* Returns the record as Datum */
+       PG_RETURN_DATUM(HeapTupleGetDatum(
+                                                                  heap_form_tuple(tupdesc, values, nulls)));
+}