LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pgstatfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 528 806 65.5 %
Date: 2023-05-31 02:11:47 Functions: 56 118 47.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pgstatfuncs.c
       4             :  *    Functions for accessing various forms of statistics data
       5             :  *
       6             :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/utils/adt/pgstatfuncs.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/htup_details.h"
      18             : #include "access/xlog.h"
      19             : #include "access/xlogprefetcher.h"
      20             : #include "catalog/pg_authid.h"
      21             : #include "catalog/pg_type.h"
      22             : #include "common/ip.h"
      23             : #include "funcapi.h"
      24             : #include "miscadmin.h"
      25             : #include "pgstat.h"
      26             : #include "postmaster/bgworker_internals.h"
      27             : #include "postmaster/postmaster.h"
      28             : #include "replication/logicallauncher.h"
      29             : #include "storage/proc.h"
      30             : #include "storage/procarray.h"
      31             : #include "utils/acl.h"
      32             : #include "utils/builtins.h"
      33             : #include "utils/inet.h"
      34             : #include "utils/timestamp.h"
      35             : 
      36             : #define UINT32_ACCESS_ONCE(var)      ((uint32)(*((volatile uint32 *)&(var))))
      37             : 
      38             : #define HAS_PGSTAT_PERMISSIONS(role)     (has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))
      39             : 
      40             : #define PG_STAT_GET_RELENTRY_INT64(stat)                        \
      41             : Datum                                                           \
      42             : CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS)                  \
      43             : {                                                               \
      44             :     Oid         relid = PG_GETARG_OID(0);                       \
      45             :     int64       result;                                         \
      46             :     PgStat_StatTabEntry *tabentry;                              \
      47             :                                                                 \
      48             :     if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
      49             :         result = 0;                                             \
      50             :     else                                                        \
      51             :         result = (int64) (tabentry->stat);                       \
      52             :                                                                 \
      53             :     PG_RETURN_INT64(result);                                    \
      54             : }
      55             : 
      56             : /* pg_stat_get_analyze_count */
      57           0 : PG_STAT_GET_RELENTRY_INT64(analyze_count)
      58             : 
      59             : /* pg_stat_get_autoanalyze_count */
      60           0 : PG_STAT_GET_RELENTRY_INT64(autoanalyze_count)
      61             : 
      62             : /* pg_stat_get_autovacuum_count */
      63           0 : PG_STAT_GET_RELENTRY_INT64(autovacuum_count)
      64             : 
      65             : /* pg_stat_get_blocks_fetched */
      66          48 : PG_STAT_GET_RELENTRY_INT64(blocks_fetched)
      67             : 
      68             : /* pg_stat_get_blocks_hit */
      69          96 : PG_STAT_GET_RELENTRY_INT64(blocks_hit)
      70             : 
      71             : /* pg_stat_get_dead_tuples */
      72          68 : PG_STAT_GET_RELENTRY_INT64(dead_tuples)
      73             : 
      74             : /* pg_stat_get_ins_since_vacuum */
      75           0 : PG_STAT_GET_RELENTRY_INT64(ins_since_vacuum)
      76             : 
      77             : /* pg_stat_get_live_tuples */
      78         140 : PG_STAT_GET_RELENTRY_INT64(live_tuples)
      79             : 
      80             : /* pg_stat_get_mods_since_analyze */
      81           0 : PG_STAT_GET_RELENTRY_INT64(mod_since_analyze)
      82             : 
      83             : /* pg_stat_get_numscans */
      84         164 : PG_STAT_GET_RELENTRY_INT64(numscans)
      85             : 
      86             : /* pg_stat_get_tuples_deleted */
      87          68 : PG_STAT_GET_RELENTRY_INT64(tuples_deleted)
      88             : 
      89             : /* pg_stat_get_tuples_fetched */
      90          48 : PG_STAT_GET_RELENTRY_INT64(tuples_fetched)
      91             : 
      92             : /* pg_stat_get_tuples_hot_updated */
      93          12 : PG_STAT_GET_RELENTRY_INT64(tuples_hot_updated)
      94             : 
      95             : /* pg_stat_get_tuples_newpage_updated */
      96           0 : PG_STAT_GET_RELENTRY_INT64(tuples_newpage_updated)
      97             : 
      98             : /* pg_stat_get_tuples_inserted */
      99          92 : PG_STAT_GET_RELENTRY_INT64(tuples_inserted)
     100             : 
     101             : /* pg_stat_get_tuples_returned */
     102          50 : PG_STAT_GET_RELENTRY_INT64(tuples_returned)
     103             : 
     104             : /* pg_stat_get_tuples_updated */
     105          68 : PG_STAT_GET_RELENTRY_INT64(tuples_updated)
     106             : 
     107             : /* pg_stat_get_vacuum_count */
     108        7532 : PG_STAT_GET_RELENTRY_INT64(vacuum_count)
     109             : 
     110             : #define PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat)                  \
     111             : Datum                                                           \
     112             : CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS)                  \
     113             : {                                                               \
     114             :     Oid         relid = PG_GETARG_OID(0);                       \
     115             :     TimestampTz result;                                         \
     116             :     PgStat_StatTabEntry *tabentry;                              \
     117             :                                                                 \
     118             :     if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
     119             :         result = 0;                                             \
     120             :     else                                                        \
     121             :         result = tabentry->stat;                             \
     122             :                                                                 \
     123             :     if (result == 0)                                            \
     124             :         PG_RETURN_NULL();                                       \
     125             :     else                                                        \
     126             :         PG_RETURN_TIMESTAMPTZ(result);                          \
     127             : }
     128             : 
     129             : /* pg_stat_get_last_analyze_time */
     130           0 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_analyze_time)
     131             : 
     132             : /* pg_stat_get_last_autoanalyze_time */
     133           0 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_autoanalyze_time)
     134             : 
     135             : /* pg_stat_get_last_autovacuum_time */
     136           0 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_autovacuum_time)
     137             : 
     138             : /* pg_stat_get_last_vacuum_time */
     139           0 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_vacuum_time)
     140             : 
     141             : /* pg_stat_get_lastscan */
     142          84 : PG_STAT_GET_RELENTRY_TIMESTAMPTZ(lastscan)
     143             : 
     144             : Datum
     145         278 : pg_stat_get_function_calls(PG_FUNCTION_ARGS)
     146             : {
     147         278 :     Oid         funcid = PG_GETARG_OID(0);
     148             :     PgStat_StatFuncEntry *funcentry;
     149             : 
     150         278 :     if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
     151         124 :         PG_RETURN_NULL();
     152         154 :     PG_RETURN_INT64(funcentry->numcalls);
     153             : }
     154             : 
     155             : /* convert counter from microsec to millisec for display */
     156             : #define PG_STAT_GET_FUNCENTRY_FLOAT8_MS(stat)                       \
     157             : Datum                                                               \
     158             : CppConcat(pg_stat_get_function_,stat)(PG_FUNCTION_ARGS)             \
     159             : {                                                                   \
     160             :     Oid         funcid = PG_GETARG_OID(0);                          \
     161             :     double      result;                                             \
     162             :     PgStat_StatFuncEntry *funcentry;                                \
     163             :                                                                     \
     164             :     if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)  \
     165             :         PG_RETURN_NULL();                                           \
     166             :     result = ((double) funcentry->stat) / 1000.0;                    \
     167             :     PG_RETURN_FLOAT8(result);                                       \
     168             : }
     169             : 
     170             : /* pg_stat_get_function_total_time */
     171         154 : PG_STAT_GET_FUNCENTRY_FLOAT8_MS(total_time)
     172             : 
     173             : /* pg_stat_get_function_self_time */
     174         154 : PG_STAT_GET_FUNCENTRY_FLOAT8_MS(self_time)
     175             : 
     176             : Datum
     177          86 : pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
     178             : {
     179             :     FuncCallContext *funcctx;
     180             :     int        *fctx;
     181             : 
     182             :     /* stuff done only on the first call of the function */
     183          86 :     if (SRF_IS_FIRSTCALL())
     184             :     {
     185             :         /* create a function context for cross-call persistence */
     186           6 :         funcctx = SRF_FIRSTCALL_INIT();
     187             : 
     188           6 :         fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
     189             :                                   sizeof(int));
     190           6 :         funcctx->user_fctx = fctx;
     191             : 
     192           6 :         fctx[0] = 0;
     193             :     }
     194             : 
     195             :     /* stuff done on every call of the function */
     196          86 :     funcctx = SRF_PERCALL_SETUP();
     197          86 :     fctx = funcctx->user_fctx;
     198             : 
     199          86 :     fctx[0] += 1;
     200             : 
     201             :     /*
     202             :      * We recheck pgstat_fetch_stat_numbackends() each time through, just in
     203             :      * case the local status data has been refreshed since we started.  It's
     204             :      * plenty cheap enough if not.  If a refresh does happen, we'll likely
     205             :      * miss or duplicate some backend IDs, but we're content not to crash.
     206             :      * (Refreshing midway through such a query would be problematic usage
     207             :      * anyway, since the backend IDs we've already returned might no longer
     208             :      * refer to extant sessions.)
     209             :      */
     210          86 :     if (fctx[0] <= pgstat_fetch_stat_numbackends())
     211             :     {
     212             :         /* do when there is more left to send */
     213          80 :         LocalPgBackendStatus *local_beentry = pgstat_fetch_stat_local_beentry(fctx[0]);
     214             : 
     215          80 :         SRF_RETURN_NEXT(funcctx, Int32GetDatum(local_beentry->backend_id));
     216             :     }
     217             :     else
     218             :     {
     219             :         /* do when there is no more left */
     220           6 :         SRF_RETURN_DONE(funcctx);
     221             :     }
     222             : }
     223             : 
     224             : /*
     225             :  * Returns command progress information for the named command.
     226             :  */
     227             : Datum
     228          14 : pg_stat_get_progress_info(PG_FUNCTION_ARGS)
     229             : {
     230             : #define PG_STAT_GET_PROGRESS_COLS   PGSTAT_NUM_PROGRESS_PARAM + 3
     231          14 :     int         num_backends = pgstat_fetch_stat_numbackends();
     232             :     int         curr_backend;
     233          14 :     char       *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
     234             :     ProgressCommandType cmdtype;
     235          14 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
     236             : 
     237             :     /* Translate command name into command type code. */
     238          14 :     if (pg_strcasecmp(cmd, "VACUUM") == 0)
     239           0 :         cmdtype = PROGRESS_COMMAND_VACUUM;
     240          14 :     else if (pg_strcasecmp(cmd, "ANALYZE") == 0)
     241           0 :         cmdtype = PROGRESS_COMMAND_ANALYZE;
     242          14 :     else if (pg_strcasecmp(cmd, "CLUSTER") == 0)
     243           0 :         cmdtype = PROGRESS_COMMAND_CLUSTER;
     244          14 :     else if (pg_strcasecmp(cmd, "CREATE INDEX") == 0)
     245           0 :         cmdtype = PROGRESS_COMMAND_CREATE_INDEX;
     246          14 :     else if (pg_strcasecmp(cmd, "BASEBACKUP") == 0)
     247           2 :         cmdtype = PROGRESS_COMMAND_BASEBACKUP;
     248          12 :     else if (pg_strcasecmp(cmd, "COPY") == 0)
     249          12 :         cmdtype = PROGRESS_COMMAND_COPY;
     250             :     else
     251           0 :         ereport(ERROR,
     252             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     253             :                  errmsg("invalid command name: \"%s\"", cmd)));
     254             : 
     255          14 :     InitMaterializedSRF(fcinfo, 0);
     256             : 
     257             :     /* 1-based index */
     258         134 :     for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
     259             :     {
     260             :         LocalPgBackendStatus *local_beentry;
     261             :         PgBackendStatus *beentry;
     262         120 :         Datum       values[PG_STAT_GET_PROGRESS_COLS] = {0};
     263         120 :         bool        nulls[PG_STAT_GET_PROGRESS_COLS] = {0};
     264             :         int         i;
     265             : 
     266         120 :         local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
     267         120 :         beentry = &local_beentry->backendStatus;
     268             : 
     269             :         /*
     270             :          * Report values for only those backends which are running the given
     271             :          * command.
     272             :          */
     273         120 :         if (beentry->st_progress_command != cmdtype)
     274         106 :             continue;
     275             : 
     276             :         /* Value available to all callers */
     277          14 :         values[0] = Int32GetDatum(beentry->st_procpid);
     278          14 :         values[1] = ObjectIdGetDatum(beentry->st_databaseid);
     279             : 
     280             :         /* show rest of the values including relid only to role members */
     281          14 :         if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     282             :         {
     283          14 :             values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
     284         294 :             for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
     285         280 :                 values[i + 3] = Int64GetDatum(beentry->st_progress_param[i]);
     286             :         }
     287             :         else
     288             :         {
     289           0 :             nulls[2] = true;
     290           0 :             for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
     291           0 :                 nulls[i + 3] = true;
     292             :         }
     293             : 
     294          14 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
     295             :     }
     296             : 
     297          14 :     return (Datum) 0;
     298             : }
     299             : 
     300             : /*
     301             :  * Returns activity of PG backends.
     302             :  */
     303             : Datum
     304        1118 : pg_stat_get_activity(PG_FUNCTION_ARGS)
     305             : {
     306             : #define PG_STAT_GET_ACTIVITY_COLS   31
     307        1118 :     int         num_backends = pgstat_fetch_stat_numbackends();
     308             :     int         curr_backend;
     309        1118 :     int         pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
     310        1118 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
     311             : 
     312        1118 :     InitMaterializedSRF(fcinfo, 0);
     313             : 
     314             :     /* 1-based index */
     315        9280 :     for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
     316             :     {
     317             :         /* for each row */
     318        8164 :         Datum       values[PG_STAT_GET_ACTIVITY_COLS] = {0};
     319        8164 :         bool        nulls[PG_STAT_GET_ACTIVITY_COLS] = {0};
     320             :         LocalPgBackendStatus *local_beentry;
     321             :         PgBackendStatus *beentry;
     322             :         PGPROC     *proc;
     323        8164 :         const char *wait_event_type = NULL;
     324        8164 :         const char *wait_event = NULL;
     325             : 
     326             :         /* Get the next one in the list */
     327        8164 :         local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
     328        8164 :         beentry = &local_beentry->backendStatus;
     329             : 
     330             :         /* If looking for specific PID, ignore all the others */
     331        8164 :         if (pid != -1 && beentry->st_procpid != pid)
     332           6 :             continue;
     333             : 
     334             :         /* Values available to all callers */
     335        8158 :         if (beentry->st_databaseid != InvalidOid)
     336        2166 :             values[0] = ObjectIdGetDatum(beentry->st_databaseid);
     337             :         else
     338        5992 :             nulls[0] = true;
     339             : 
     340        8158 :         values[1] = Int32GetDatum(beentry->st_procpid);
     341             : 
     342        8158 :         if (beentry->st_userid != InvalidOid)
     343        3652 :             values[2] = ObjectIdGetDatum(beentry->st_userid);
     344             :         else
     345        4506 :             nulls[2] = true;
     346             : 
     347        8158 :         if (beentry->st_appname)
     348        8158 :             values[3] = CStringGetTextDatum(beentry->st_appname);
     349             :         else
     350           0 :             nulls[3] = true;
     351             : 
     352        8158 :         if (TransactionIdIsValid(local_beentry->backend_xid))
     353          28 :             values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
     354             :         else
     355        8130 :             nulls[15] = true;
     356             : 
     357        8158 :         if (TransactionIdIsValid(local_beentry->backend_xmin))
     358        1164 :             values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
     359             :         else
     360        6994 :             nulls[16] = true;
     361             : 
     362             :         /* Values only available to role member or pg_read_all_stats */
     363        8158 :         if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     364        8076 :         {
     365             :             SockAddr    zero_clientaddr;
     366             :             char       *clipped_activity;
     367             : 
     368        8076 :             switch (beentry->st_state)
     369             :             {
     370         104 :                 case STATE_IDLE:
     371         104 :                     values[4] = CStringGetTextDatum("idle");
     372         104 :                     break;
     373        2430 :                 case STATE_RUNNING:
     374        2430 :                     values[4] = CStringGetTextDatum("active");
     375        2430 :                     break;
     376          22 :                 case STATE_IDLEINTRANSACTION:
     377          22 :                     values[4] = CStringGetTextDatum("idle in transaction");
     378          22 :                     break;
     379           0 :                 case STATE_FASTPATH:
     380           0 :                     values[4] = CStringGetTextDatum("fastpath function call");
     381           0 :                     break;
     382           0 :                 case STATE_IDLEINTRANSACTION_ABORTED:
     383           0 :                     values[4] = CStringGetTextDatum("idle in transaction (aborted)");
     384           0 :                     break;
     385           0 :                 case STATE_DISABLED:
     386           0 :                     values[4] = CStringGetTextDatum("disabled");
     387           0 :                     break;
     388        5520 :                 case STATE_UNDEFINED:
     389        5520 :                     nulls[4] = true;
     390        5520 :                     break;
     391             :             }
     392             : 
     393        8076 :             clipped_activity = pgstat_clip_activity(beentry->st_activity_raw);
     394        8076 :             values[5] = CStringGetTextDatum(clipped_activity);
     395        8076 :             pfree(clipped_activity);
     396             : 
     397             :             /* leader_pid */
     398        8076 :             nulls[29] = true;
     399             : 
     400        8076 :             proc = BackendPidGetProc(beentry->st_procpid);
     401             : 
     402        8076 :             if (proc == NULL && (beentry->st_backendType != B_BACKEND))
     403             :             {
     404             :                 /*
     405             :                  * For an auxiliary process, retrieve process info from
     406             :                  * AuxiliaryProcs stored in shared-memory.
     407             :                  */
     408        3372 :                 proc = AuxiliaryPidGetProc(beentry->st_procpid);
     409             :             }
     410             : 
     411             :             /*
     412             :              * If a PGPROC entry was retrieved, display wait events and lock
     413             :              * group leader or apply leader information if any.  To avoid
     414             :              * extra overhead, no extra lock is being held, so there is no
     415             :              * guarantee of consistency across multiple rows.
     416             :              */
     417        8076 :             if (proc != NULL)
     418             :             {
     419             :                 uint32      raw_wait_event;
     420             :                 PGPROC     *leader;
     421             : 
     422        8076 :                 raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
     423        8076 :                 wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
     424        8076 :                 wait_event = pgstat_get_wait_event(raw_wait_event);
     425             : 
     426        8076 :                 leader = proc->lockGroupLeader;
     427             : 
     428             :                 /*
     429             :                  * Show the leader only for active parallel workers.  This
     430             :                  * leaves the field as NULL for the leader of a parallel group
     431             :                  * or the leader of parallel apply workers.
     432             :                  */
     433        8076 :                 if (leader && leader->pid != beentry->st_procpid)
     434             :                 {
     435           0 :                     values[29] = Int32GetDatum(leader->pid);
     436           0 :                     nulls[29] = false;
     437             :                 }
     438        8076 :                 else if (beentry->st_backendType == B_BG_WORKER)
     439             :                 {
     440        1140 :                     int         leader_pid = GetLeaderApplyWorkerPid(beentry->st_procpid);
     441             : 
     442        1140 :                     if (leader_pid != InvalidPid)
     443             :                     {
     444           0 :                         values[29] = Int32GetDatum(leader_pid);
     445           0 :                         nulls[29] = false;
     446             :                     }
     447             :                 }
     448             :             }
     449             : 
     450        8076 :             if (wait_event_type)
     451        6932 :                 values[6] = CStringGetTextDatum(wait_event_type);
     452             :             else
     453        1144 :                 nulls[6] = true;
     454             : 
     455        8076 :             if (wait_event)
     456        6932 :                 values[7] = CStringGetTextDatum(wait_event);
     457             :             else
     458        1144 :                 nulls[7] = true;
     459             : 
     460             :             /*
     461             :              * Don't expose transaction time for walsenders; it confuses
     462             :              * monitoring, particularly because we don't keep the time up-to-
     463             :              * date.
     464             :              */
     465        8076 :             if (beentry->st_xact_start_timestamp != 0 &&
     466        1188 :                 beentry->st_backendType != B_WAL_SENDER)
     467        1186 :                 values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
     468             :             else
     469        6890 :                 nulls[8] = true;
     470             : 
     471        8076 :             if (beentry->st_activity_start_timestamp != 0)
     472        2490 :                 values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
     473             :             else
     474        5586 :                 nulls[9] = true;
     475             : 
     476        8076 :             if (beentry->st_proc_start_timestamp != 0)
     477        8076 :                 values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
     478             :             else
     479           0 :                 nulls[10] = true;
     480             : 
     481        8076 :             if (beentry->st_state_start_timestamp != 0)
     482        2556 :                 values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
     483             :             else
     484        5520 :                 nulls[11] = true;
     485             : 
     486             :             /* A zeroed client addr means we don't know */
     487        8076 :             memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
     488        8076 :             if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
     489             :                        sizeof(zero_clientaddr)) == 0)
     490             :             {
     491        5582 :                 nulls[12] = true;
     492        5582 :                 nulls[13] = true;
     493        5582 :                 nulls[14] = true;
     494             :             }
     495             :             else
     496             :             {
     497        2494 :                 if (beentry->st_clientaddr.addr.ss_family == AF_INET ||
     498        2480 :                     beentry->st_clientaddr.addr.ss_family == AF_INET6)
     499          14 :                 {
     500             :                     char        remote_host[NI_MAXHOST];
     501             :                     char        remote_port[NI_MAXSERV];
     502             :                     int         ret;
     503             : 
     504          14 :                     remote_host[0] = '\0';
     505          14 :                     remote_port[0] = '\0';
     506          14 :                     ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
     507          14 :                                              beentry->st_clientaddr.salen,
     508             :                                              remote_host, sizeof(remote_host),
     509             :                                              remote_port, sizeof(remote_port),
     510             :                                              NI_NUMERICHOST | NI_NUMERICSERV);
     511          14 :                     if (ret == 0)
     512             :                     {
     513          14 :                         clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
     514          14 :                         values[12] = DirectFunctionCall1(inet_in,
     515             :                                                          CStringGetDatum(remote_host));
     516          14 :                         if (beentry->st_clienthostname &&
     517          14 :                             beentry->st_clienthostname[0])
     518          14 :                             values[13] = CStringGetTextDatum(beentry->st_clienthostname);
     519             :                         else
     520           0 :                             nulls[13] = true;
     521          14 :                         values[14] = Int32GetDatum(atoi(remote_port));
     522             :                     }
     523             :                     else
     524             :                     {
     525           0 :                         nulls[12] = true;
     526           0 :                         nulls[13] = true;
     527           0 :                         nulls[14] = true;
     528             :                     }
     529             :                 }
     530        2480 :                 else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
     531             :                 {
     532             :                     /*
     533             :                      * Unix sockets always reports NULL for host and -1 for
     534             :                      * port, so it's possible to tell the difference to
     535             :                      * connections we have no permissions to view, or with
     536             :                      * errors.
     537             :                      */
     538        2480 :                     nulls[12] = true;
     539        2480 :                     nulls[13] = true;
     540        2480 :                     values[14] = Int32GetDatum(-1);
     541             :                 }
     542             :                 else
     543             :                 {
     544             :                     /* Unknown address type, should never happen */
     545           0 :                     nulls[12] = true;
     546           0 :                     nulls[13] = true;
     547           0 :                     nulls[14] = true;
     548             :                 }
     549             :             }
     550             :             /* Add backend type */
     551        8076 :             if (beentry->st_backendType == B_BG_WORKER)
     552             :             {
     553             :                 const char *bgw_type;
     554             : 
     555        1140 :                 bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
     556        1140 :                 if (bgw_type)
     557        1140 :                     values[17] = CStringGetTextDatum(bgw_type);
     558             :                 else
     559           0 :                     nulls[17] = true;
     560             :             }
     561             :             else
     562        6936 :                 values[17] =
     563        6936 :                     CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType));
     564             : 
     565             :             /* SSL information */
     566        8076 :             if (beentry->st_ssl)
     567             :             {
     568          14 :                 values[18] = BoolGetDatum(true);    /* ssl */
     569          14 :                 values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
     570          14 :                 values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
     571          14 :                 values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
     572             : 
     573          14 :                 if (beentry->st_sslstatus->ssl_client_dn[0])
     574          12 :                     values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_client_dn);
     575             :                 else
     576           2 :                     nulls[22] = true;
     577             : 
     578          14 :                 if (beentry->st_sslstatus->ssl_client_serial[0])
     579          12 :                     values[23] = DirectFunctionCall3(numeric_in,
     580             :                                                      CStringGetDatum(beentry->st_sslstatus->ssl_client_serial),
     581             :                                                      ObjectIdGetDatum(InvalidOid),
     582             :                                                      Int32GetDatum(-1));
     583             :                 else
     584           2 :                     nulls[23] = true;
     585             : 
     586          14 :                 if (beentry->st_sslstatus->ssl_issuer_dn[0])
     587          12 :                     values[24] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
     588             :                 else
     589           2 :                     nulls[24] = true;
     590             :             }
     591             :             else
     592             :             {
     593        8062 :                 values[18] = BoolGetDatum(false);   /* ssl */
     594        8062 :                 nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = true;
     595             :             }
     596             : 
     597             :             /* GSSAPI information */
     598        8076 :             if (beentry->st_gss)
     599             :             {
     600           0 :                 values[25] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */
     601           0 :                 values[26] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ);
     602           0 :                 values[27] = BoolGetDatum(beentry->st_gssstatus->gss_enc);    /* GSS Encryption in use */
     603           0 :                 values[28] = BoolGetDatum(beentry->st_gssstatus->gss_delegation); /* GSS credentials
     604             :                                                                                  * delegated */
     605             :             }
     606             :             else
     607             :             {
     608        8076 :                 values[25] = BoolGetDatum(false);   /* gss_auth */
     609        8076 :                 nulls[26] = true;   /* No GSS principal */
     610        8076 :                 values[27] = BoolGetDatum(false);   /* GSS Encryption not in
     611             :                                                      * use */
     612        8076 :                 values[28] = BoolGetDatum(false);   /* GSS credentials not
     613             :                                                      * delegated */
     614             :             }
     615        8076 :             if (beentry->st_query_id == 0)
     616        8066 :                 nulls[30] = true;
     617             :             else
     618          10 :                 values[30] = UInt64GetDatum(beentry->st_query_id);
     619             :         }
     620             :         else
     621             :         {
     622             :             /* No permissions to view data about this session */
     623          82 :             values[5] = CStringGetTextDatum("<insufficient privilege>");
     624          82 :             nulls[4] = true;
     625          82 :             nulls[6] = true;
     626          82 :             nulls[7] = true;
     627          82 :             nulls[8] = true;
     628          82 :             nulls[9] = true;
     629          82 :             nulls[10] = true;
     630          82 :             nulls[11] = true;
     631          82 :             nulls[12] = true;
     632          82 :             nulls[13] = true;
     633          82 :             nulls[14] = true;
     634          82 :             nulls[17] = true;
     635          82 :             nulls[18] = true;
     636          82 :             nulls[19] = true;
     637          82 :             nulls[20] = true;
     638          82 :             nulls[21] = true;
     639          82 :             nulls[22] = true;
     640          82 :             nulls[23] = true;
     641          82 :             nulls[24] = true;
     642          82 :             nulls[25] = true;
     643          82 :             nulls[26] = true;
     644          82 :             nulls[27] = true;
     645          82 :             nulls[28] = true;
     646          82 :             nulls[29] = true;
     647          82 :             nulls[30] = true;
     648             :         }
     649             : 
     650        8158 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
     651             : 
     652             :         /* If only a single backend was requested, and we found it, break. */
     653        8158 :         if (pid != -1)
     654           2 :             break;
     655             :     }
     656             : 
     657        1118 :     return (Datum) 0;
     658             : }
     659             : 
     660             : 
     661             : Datum
     662         802 : pg_backend_pid(PG_FUNCTION_ARGS)
     663             : {
     664         802 :     PG_RETURN_INT32(MyProcPid);
     665             : }
     666             : 
     667             : 
     668             : Datum
     669          80 : pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
     670             : {
     671          80 :     int32       beid = PG_GETARG_INT32(0);
     672             :     PgBackendStatus *beentry;
     673             : 
     674          80 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     675           0 :         PG_RETURN_NULL();
     676             : 
     677          80 :     PG_RETURN_INT32(beentry->st_procpid);
     678             : }
     679             : 
     680             : 
     681             : Datum
     682           0 : pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
     683             : {
     684           0 :     int32       beid = PG_GETARG_INT32(0);
     685             :     PgBackendStatus *beentry;
     686             : 
     687           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     688           0 :         PG_RETURN_NULL();
     689             : 
     690           0 :     PG_RETURN_OID(beentry->st_databaseid);
     691             : }
     692             : 
     693             : 
     694             : Datum
     695           0 : pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
     696             : {
     697           0 :     int32       beid = PG_GETARG_INT32(0);
     698             :     PgBackendStatus *beentry;
     699             : 
     700           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     701           0 :         PG_RETURN_NULL();
     702             : 
     703           0 :     PG_RETURN_OID(beentry->st_userid);
     704             : }
     705             : 
     706             : Datum
     707           0 : pg_stat_get_backend_subxact(PG_FUNCTION_ARGS)
     708             : {
     709             : #define PG_STAT_GET_SUBXACT_COLS    2
     710             :     TupleDesc   tupdesc;
     711             :     Datum       values[PG_STAT_GET_SUBXACT_COLS];
     712             :     bool        nulls[PG_STAT_GET_SUBXACT_COLS];
     713           0 :     int32       beid = PG_GETARG_INT32(0);
     714             :     LocalPgBackendStatus *local_beentry;
     715             : 
     716             :     /* Initialise values and NULL flags arrays */
     717           0 :     MemSet(values, 0, sizeof(values));
     718           0 :     MemSet(nulls, 0, sizeof(nulls));
     719             : 
     720             :     /* Initialise attributes information in the tuple descriptor */
     721           0 :     tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBXACT_COLS);
     722           0 :     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subxact_count",
     723             :                        INT4OID, -1, 0);
     724           0 :     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "subxact_overflow",
     725             :                        BOOLOID, -1, 0);
     726             : 
     727           0 :     BlessTupleDesc(tupdesc);
     728             : 
     729           0 :     if ((local_beentry = pgstat_fetch_stat_local_beentry(beid)) != NULL)
     730             :     {
     731             :         /* Fill values and NULLs */
     732           0 :         values[0] = Int32GetDatum(local_beentry->backend_subxact_count);
     733           0 :         values[1] = BoolGetDatum(local_beentry->backend_subxact_overflowed);
     734             :     }
     735             :     else
     736             :     {
     737           0 :         nulls[0] = true;
     738           0 :         nulls[1] = true;
     739             :     }
     740             : 
     741             :     /* Returns the record as Datum */
     742           0 :     PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
     743             : }
     744             : 
     745             : Datum
     746           0 : pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
     747             : {
     748           0 :     int32       beid = PG_GETARG_INT32(0);
     749             :     PgBackendStatus *beentry;
     750             :     const char *activity;
     751             :     char       *clipped_activity;
     752             :     text       *ret;
     753             : 
     754           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     755           0 :         activity = "<backend information not available>";
     756           0 :     else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     757           0 :         activity = "<insufficient privilege>";
     758           0 :     else if (*(beentry->st_activity_raw) == '\0')
     759           0 :         activity = "<command string not enabled>";
     760             :     else
     761           0 :         activity = beentry->st_activity_raw;
     762             : 
     763           0 :     clipped_activity = pgstat_clip_activity(activity);
     764           0 :     ret = cstring_to_text(activity);
     765           0 :     pfree(clipped_activity);
     766             : 
     767           0 :     PG_RETURN_TEXT_P(ret);
     768             : }
     769             : 
     770             : Datum
     771           0 : pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)
     772             : {
     773           0 :     int32       beid = PG_GETARG_INT32(0);
     774             :     PgBackendStatus *beentry;
     775             :     PGPROC     *proc;
     776           0 :     const char *wait_event_type = NULL;
     777             : 
     778           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     779           0 :         wait_event_type = "<backend information not available>";
     780           0 :     else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     781           0 :         wait_event_type = "<insufficient privilege>";
     782           0 :     else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
     783           0 :         wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
     784             : 
     785           0 :     if (!wait_event_type)
     786           0 :         PG_RETURN_NULL();
     787             : 
     788           0 :     PG_RETURN_TEXT_P(cstring_to_text(wait_event_type));
     789             : }
     790             : 
     791             : Datum
     792           0 : pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)
     793             : {
     794           0 :     int32       beid = PG_GETARG_INT32(0);
     795             :     PgBackendStatus *beentry;
     796             :     PGPROC     *proc;
     797           0 :     const char *wait_event = NULL;
     798             : 
     799           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     800           0 :         wait_event = "<backend information not available>";
     801           0 :     else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     802           0 :         wait_event = "<insufficient privilege>";
     803           0 :     else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
     804           0 :         wait_event = pgstat_get_wait_event(proc->wait_event_info);
     805             : 
     806           0 :     if (!wait_event)
     807           0 :         PG_RETURN_NULL();
     808             : 
     809           0 :     PG_RETURN_TEXT_P(cstring_to_text(wait_event));
     810             : }
     811             : 
     812             : 
     813             : Datum
     814           0 : pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
     815             : {
     816           0 :     int32       beid = PG_GETARG_INT32(0);
     817             :     TimestampTz result;
     818             :     PgBackendStatus *beentry;
     819             : 
     820           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     821           0 :         PG_RETURN_NULL();
     822             : 
     823           0 :     else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     824           0 :         PG_RETURN_NULL();
     825             : 
     826           0 :     result = beentry->st_activity_start_timestamp;
     827             : 
     828             :     /*
     829             :      * No time recorded for start of current query -- this is the case if the
     830             :      * user hasn't enabled query-level stats collection.
     831             :      */
     832           0 :     if (result == 0)
     833           0 :         PG_RETURN_NULL();
     834             : 
     835           0 :     PG_RETURN_TIMESTAMPTZ(result);
     836             : }
     837             : 
     838             : 
     839             : Datum
     840           0 : pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
     841             : {
     842           0 :     int32       beid = PG_GETARG_INT32(0);
     843             :     TimestampTz result;
     844             :     PgBackendStatus *beentry;
     845             : 
     846           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     847           0 :         PG_RETURN_NULL();
     848             : 
     849           0 :     else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     850           0 :         PG_RETURN_NULL();
     851             : 
     852           0 :     result = beentry->st_xact_start_timestamp;
     853             : 
     854           0 :     if (result == 0)            /* not in a transaction */
     855           0 :         PG_RETURN_NULL();
     856             : 
     857           0 :     PG_RETURN_TIMESTAMPTZ(result);
     858             : }
     859             : 
     860             : 
     861             : Datum
     862           0 : pg_stat_get_backend_start(PG_FUNCTION_ARGS)
     863             : {
     864           0 :     int32       beid = PG_GETARG_INT32(0);
     865             :     TimestampTz result;
     866             :     PgBackendStatus *beentry;
     867             : 
     868           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     869           0 :         PG_RETURN_NULL();
     870             : 
     871           0 :     else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     872           0 :         PG_RETURN_NULL();
     873             : 
     874           0 :     result = beentry->st_proc_start_timestamp;
     875             : 
     876           0 :     if (result == 0)            /* probably can't happen? */
     877           0 :         PG_RETURN_NULL();
     878             : 
     879           0 :     PG_RETURN_TIMESTAMPTZ(result);
     880             : }
     881             : 
     882             : 
     883             : Datum
     884           0 : pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
     885             : {
     886           0 :     int32       beid = PG_GETARG_INT32(0);
     887             :     PgBackendStatus *beentry;
     888             :     SockAddr    zero_clientaddr;
     889             :     char        remote_host[NI_MAXHOST];
     890             :     int         ret;
     891             : 
     892           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     893           0 :         PG_RETURN_NULL();
     894             : 
     895           0 :     else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     896           0 :         PG_RETURN_NULL();
     897             : 
     898             :     /* A zeroed client addr means we don't know */
     899           0 :     memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
     900           0 :     if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
     901             :                sizeof(zero_clientaddr)) == 0)
     902           0 :         PG_RETURN_NULL();
     903             : 
     904           0 :     switch (beentry->st_clientaddr.addr.ss_family)
     905             :     {
     906           0 :         case AF_INET:
     907             :         case AF_INET6:
     908           0 :             break;
     909           0 :         default:
     910           0 :             PG_RETURN_NULL();
     911             :     }
     912             : 
     913           0 :     remote_host[0] = '\0';
     914           0 :     ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
     915           0 :                              beentry->st_clientaddr.salen,
     916             :                              remote_host, sizeof(remote_host),
     917             :                              NULL, 0,
     918             :                              NI_NUMERICHOST | NI_NUMERICSERV);
     919           0 :     if (ret != 0)
     920           0 :         PG_RETURN_NULL();
     921             : 
     922           0 :     clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
     923             : 
     924           0 :     PG_RETURN_DATUM(DirectFunctionCall1(inet_in,
     925             :                                         CStringGetDatum(remote_host)));
     926             : }
     927             : 
     928             : Datum
     929           0 : pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
     930             : {
     931           0 :     int32       beid = PG_GETARG_INT32(0);
     932             :     PgBackendStatus *beentry;
     933             :     SockAddr    zero_clientaddr;
     934             :     char        remote_port[NI_MAXSERV];
     935             :     int         ret;
     936             : 
     937           0 :     if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
     938           0 :         PG_RETURN_NULL();
     939             : 
     940           0 :     else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
     941           0 :         PG_RETURN_NULL();
     942             : 
     943             :     /* A zeroed client addr means we don't know */
     944           0 :     memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
     945           0 :     if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
     946             :                sizeof(zero_clientaddr)) == 0)
     947           0 :         PG_RETURN_NULL();
     948             : 
     949           0 :     switch (beentry->st_clientaddr.addr.ss_family)
     950             :     {
     951           0 :         case AF_INET:
     952             :         case AF_INET6:
     953           0 :             break;
     954           0 :         case AF_UNIX:
     955           0 :             PG_RETURN_INT32(-1);
     956           0 :         default:
     957           0 :             PG_RETURN_NULL();
     958             :     }
     959             : 
     960           0 :     remote_port[0] = '\0';
     961           0 :     ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
     962           0 :                              beentry->st_clientaddr.salen,
     963             :                              NULL, 0,
     964             :                              remote_port, sizeof(remote_port),
     965             :                              NI_NUMERICHOST | NI_NUMERICSERV);
     966           0 :     if (ret != 0)
     967           0 :         PG_RETURN_NULL();
     968             : 
     969           0 :     PG_RETURN_DATUM(DirectFunctionCall1(int4in,
     970             :                                         CStringGetDatum(remote_port)));
     971             : }
     972             : 
     973             : 
     974             : Datum
     975           0 : pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
     976             : {
     977           0 :     Oid         dbid = PG_GETARG_OID(0);
     978             :     int32       result;
     979           0 :     int         tot_backends = pgstat_fetch_stat_numbackends();
     980             :     int         beid;
     981             : 
     982           0 :     result = 0;
     983           0 :     for (beid = 1; beid <= tot_backends; beid++)
     984             :     {
     985           0 :         LocalPgBackendStatus *local_beentry = pgstat_fetch_stat_local_beentry(beid);
     986             : 
     987           0 :         if (local_beentry->backendStatus.st_databaseid == dbid)
     988           0 :             result++;
     989             :     }
     990             : 
     991           0 :     PG_RETURN_INT32(result);
     992             : }
     993             : 
     994             : 
     995             : #define PG_STAT_GET_DBENTRY_INT64(stat)                         \
     996             : Datum                                                           \
     997             : CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS)               \
     998             : {                                                               \
     999             :     Oid         dbid = PG_GETARG_OID(0);                        \
    1000             :     int64       result;                                         \
    1001             :     PgStat_StatDBEntry *dbentry;                                \
    1002             :                                                                 \
    1003             :     if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)    \
    1004             :         result = 0;                                             \
    1005             :     else                                                        \
    1006             :         result = (int64) (dbentry->stat);                        \
    1007             :                                                                 \
    1008             :     PG_RETURN_INT64(result);                                    \
    1009             : }
    1010             : 
    1011             : /* pg_stat_get_db_blocks_fetched */
    1012           0 : PG_STAT_GET_DBENTRY_INT64(blocks_fetched)
    1013             : 
    1014             : /* pg_stat_get_db_blocks_hit */
    1015           0 : PG_STAT_GET_DBENTRY_INT64(blocks_hit)
    1016             : 
    1017             : /* pg_stat_get_db_conflict_bufferpin */
    1018           2 : PG_STAT_GET_DBENTRY_INT64(conflict_bufferpin)
    1019             : 
    1020             : /* pg_stat_get_db_conflict_lock */
    1021           2 : PG_STAT_GET_DBENTRY_INT64(conflict_lock)
    1022             : 
    1023             : /* pg_stat_get_db_conflict_snapshot */
    1024           2 : PG_STAT_GET_DBENTRY_INT64(conflict_snapshot)
    1025             : 
    1026             : /* pg_stat_get_db_conflict_startup_deadlock */
    1027           2 : PG_STAT_GET_DBENTRY_INT64(conflict_startup_deadlock)
    1028             : 
    1029             : /* pg_stat_get_db_conflict_tablespace */
    1030           2 : PG_STAT_GET_DBENTRY_INT64(conflict_tablespace)
    1031             : 
    1032             : /* pg_stat_get_db_deadlocks */
    1033           2 : PG_STAT_GET_DBENTRY_INT64(deadlocks)
    1034             : 
    1035             : /* pg_stat_get_db_sessions */
    1036          12 : PG_STAT_GET_DBENTRY_INT64(sessions)
    1037             : 
    1038             : /* pg_stat_get_db_sessions_abandoned */
    1039           0 : PG_STAT_GET_DBENTRY_INT64(sessions_abandoned)
    1040             : 
    1041             : /* pg_stat_get_db_sessions_fatal */
    1042           0 : PG_STAT_GET_DBENTRY_INT64(sessions_fatal)
    1043             : 
    1044             : /* pg_stat_get_db_sessions_killed */
    1045           0 : PG_STAT_GET_DBENTRY_INT64(sessions_killed)
    1046             : 
    1047             : /* pg_stat_get_db_temp_bytes */
    1048           0 : PG_STAT_GET_DBENTRY_INT64(temp_bytes)
    1049             : 
    1050             : /* pg_stat_get_db_temp_files */
    1051           0 : PG_STAT_GET_DBENTRY_INT64(temp_files)
    1052             : 
    1053             : /* pg_stat_get_db_tuples_deleted */
    1054           0 : PG_STAT_GET_DBENTRY_INT64(tuples_deleted)
    1055             : 
    1056             : /* pg_stat_get_db_tuples_fetched */
    1057           0 : PG_STAT_GET_DBENTRY_INT64(tuples_fetched)
    1058             : 
    1059             : /* pg_stat_get_db_tuples_inserted */
    1060           0 : PG_STAT_GET_DBENTRY_INT64(tuples_inserted)
    1061             : 
    1062             : /* pg_stat_get_db_tuples_returned */
    1063           0 : PG_STAT_GET_DBENTRY_INT64(tuples_returned)
    1064             : 
    1065             : /* pg_stat_get_db_tuples_updated */
    1066           0 : PG_STAT_GET_DBENTRY_INT64(tuples_updated)
    1067             : 
    1068             : /* pg_stat_get_db_xact_commit */
    1069           0 : PG_STAT_GET_DBENTRY_INT64(xact_commit)
    1070             : 
    1071             : /* pg_stat_get_db_xact_rollback */
    1072           0 : PG_STAT_GET_DBENTRY_INT64(xact_rollback)
    1073             : 
    1074             : /* pg_stat_get_db_conflict_logicalslot */
    1075          12 : PG_STAT_GET_DBENTRY_INT64(conflict_logicalslot)
    1076             : 
    1077             : Datum
    1078          12 : pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
    1079             : {
    1080          12 :     Oid         dbid = PG_GETARG_OID(0);
    1081             :     TimestampTz result;
    1082             :     PgStat_StatDBEntry *dbentry;
    1083             : 
    1084          12 :     if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
    1085           0 :         result = 0;
    1086             :     else
    1087          12 :         result = dbentry->stat_reset_timestamp;
    1088             : 
    1089          12 :     if (result == 0)
    1090           0 :         PG_RETURN_NULL();
    1091             :     else
    1092          12 :         PG_RETURN_TIMESTAMPTZ(result);
    1093             : }
    1094             : 
    1095             : 
    1096             : Datum
    1097           2 : pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)
    1098             : {
    1099           2 :     Oid         dbid = PG_GETARG_OID(0);
    1100             :     int64       result;
    1101             :     PgStat_StatDBEntry *dbentry;
    1102             : 
    1103           2 :     if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
    1104           0 :         result = 0;
    1105             :     else
    1106           2 :         result = (int64) (dbentry->conflict_tablespace +
    1107           2 :                           dbentry->conflict_lock +
    1108           2 :                           dbentry->conflict_snapshot +
    1109           2 :                           dbentry->conflict_logicalslot +
    1110           2 :                           dbentry->conflict_bufferpin +
    1111           2 :                           dbentry->conflict_startup_deadlock);
    1112             : 
    1113           2 :     PG_RETURN_INT64(result);
    1114             : }
    1115             : 
    1116             : Datum
    1117           0 : pg_stat_get_db_checksum_failures(PG_FUNCTION_ARGS)
    1118             : {
    1119           0 :     Oid         dbid = PG_GETARG_OID(0);
    1120             :     int64       result;
    1121             :     PgStat_StatDBEntry *dbentry;
    1122             : 
    1123           0 :     if (!DataChecksumsEnabled())
    1124           0 :         PG_RETURN_NULL();
    1125             : 
    1126           0 :     if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
    1127           0 :         result = 0;
    1128             :     else
    1129           0 :         result = (int64) (dbentry->checksum_failures);
    1130             : 
    1131           0 :     PG_RETURN_INT64(result);
    1132             : }
    1133             : 
    1134             : Datum
    1135           0 : pg_stat_get_db_checksum_last_failure(PG_FUNCTION_ARGS)
    1136             : {
    1137           0 :     Oid         dbid = PG_GETARG_OID(0);
    1138             :     TimestampTz result;
    1139             :     PgStat_StatDBEntry *dbentry;
    1140             : 
    1141           0 :     if (!DataChecksumsEnabled())
    1142           0 :         PG_RETURN_NULL();
    1143             : 
    1144           0 :     if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
    1145           0 :         result = 0;
    1146             :     else
    1147           0 :         result = dbentry->last_checksum_failure;
    1148             : 
    1149           0 :     if (result == 0)
    1150           0 :         PG_RETURN_NULL();
    1151             :     else
    1152           0 :         PG_RETURN_TIMESTAMPTZ(result);
    1153             : }
    1154             : 
    1155             : /* convert counter from microsec to millisec for display */
    1156             : #define PG_STAT_GET_DBENTRY_FLOAT8_MS(stat)                     \
    1157             : Datum                                                           \
    1158             : CppConcat(pg_stat_get_db_,stat)(PG_FUNCTION_ARGS)               \
    1159             : {                                                               \
    1160             :     Oid         dbid = PG_GETARG_OID(0);                        \
    1161             :     double      result;                                         \
    1162             :     PgStat_StatDBEntry *dbentry;                                \
    1163             :                                                                 \
    1164             :     if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)    \
    1165             :         result = 0;                                             \
    1166             :     else                                                        \
    1167             :         result = ((double) dbentry->stat) / 1000.0;              \
    1168             :                                                                 \
    1169             :     PG_RETURN_FLOAT8(result);                                   \
    1170             : }
    1171             : 
    1172             : /* pg_stat_get_db_active_time */
    1173           0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(active_time)
    1174             : 
    1175             : /* pg_stat_get_db_blk_read_time */
    1176           0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_read_time)
    1177             : 
    1178             : /* pg_stat_get_db_blk_write_time */
    1179           0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(blk_write_time)
    1180             : 
    1181             : /* pg_stat_get_db_idle_in_transaction_time */
    1182           0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(idle_in_transaction_time)
    1183             : 
    1184             : /* pg_stat_get_db_session_time */
    1185           0 : PG_STAT_GET_DBENTRY_FLOAT8_MS(session_time)
    1186             : 
    1187             : Datum
    1188           8 : pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
    1189             : {
    1190           8 :     PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
    1191             : }
    1192             : 
    1193             : Datum
    1194          20 : pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
    1195             : {
    1196          20 :     PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
    1197             : }
    1198             : 
    1199             : Datum
    1200           0 : pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
    1201             : {
    1202           0 :     PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
    1203             : }
    1204             : 
    1205             : Datum
    1206           0 : pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
    1207             : {
    1208           0 :     PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_written_clean);
    1209             : }
    1210             : 
    1211             : Datum
    1212           0 : pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
    1213             : {
    1214           0 :     PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->maxwritten_clean);
    1215             : }
    1216             : 
    1217             : Datum
    1218           0 : pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
    1219             : {
    1220             :     /* time is already in msec, just convert to double for presentation */
    1221           0 :     PG_RETURN_FLOAT8((double)
    1222             :                      pgstat_fetch_stat_checkpointer()->checkpoint_write_time);
    1223             : }
    1224             : 
    1225             : Datum
    1226           0 : pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
    1227             : {
    1228             :     /* time is already in msec, just convert to double for presentation */
    1229           0 :     PG_RETURN_FLOAT8((double)
    1230             :                      pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
    1231             : }
    1232             : 
    1233             : Datum
    1234          32 : pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
    1235             : {
    1236          32 :     PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
    1237             : }
    1238             : 
    1239             : Datum
    1240           0 : pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
    1241             : {
    1242           0 :     PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_backend);
    1243             : }
    1244             : 
    1245             : Datum
    1246           0 : pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
    1247             : {
    1248           0 :     PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_fsync_backend);
    1249             : }
    1250             : 
    1251             : Datum
    1252           0 : pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
    1253             : {
    1254           0 :     PG_RETURN_INT64(pgstat_fetch_stat_bgwriter()->buf_alloc);
    1255             : }
    1256             : 
    1257             : /*
    1258             : * When adding a new column to the pg_stat_io view, add a new enum value
    1259             : * here above IO_NUM_COLUMNS.
    1260             : */
    1261             : typedef enum io_stat_col
    1262             : {
    1263             :     IO_COL_INVALID = -1,
    1264             :     IO_COL_BACKEND_TYPE,
    1265             :     IO_COL_OBJECT,
    1266             :     IO_COL_CONTEXT,
    1267             :     IO_COL_READS,
    1268             :     IO_COL_READ_TIME,
    1269             :     IO_COL_WRITES,
    1270             :     IO_COL_WRITE_TIME,
    1271             :     IO_COL_WRITEBACKS,
    1272             :     IO_COL_WRITEBACK_TIME,
    1273             :     IO_COL_EXTENDS,
    1274             :     IO_COL_EXTEND_TIME,
    1275             :     IO_COL_CONVERSION,
    1276             :     IO_COL_HITS,
    1277             :     IO_COL_EVICTIONS,
    1278             :     IO_COL_REUSES,
    1279             :     IO_COL_FSYNCS,
    1280             :     IO_COL_FSYNC_TIME,
    1281             :     IO_COL_RESET_TIME,
    1282             :     IO_NUM_COLUMNS,
    1283             : } io_stat_col;
    1284             : 
    1285             : /*
    1286             :  * When adding a new IOOp, add a new io_stat_col and add a case to this
    1287             :  * function returning the corresponding io_stat_col.
    1288             :  */
    1289             : static io_stat_col
    1290       43680 : pgstat_get_io_op_index(IOOp io_op)
    1291             : {
    1292       43680 :     switch (io_op)
    1293             :     {
    1294        3360 :         case IOOP_EVICT:
    1295        3360 :             return IO_COL_EVICTIONS;
    1296        6720 :         case IOOP_EXTEND:
    1297        6720 :             return IO_COL_EXTENDS;
    1298        6720 :         case IOOP_FSYNC:
    1299        6720 :             return IO_COL_FSYNCS;
    1300        3360 :         case IOOP_HIT:
    1301        3360 :             return IO_COL_HITS;
    1302        6720 :         case IOOP_READ:
    1303        6720 :             return IO_COL_READS;
    1304        3360 :         case IOOP_REUSE:
    1305        3360 :             return IO_COL_REUSES;
    1306        6720 :         case IOOP_WRITE:
    1307        6720 :             return IO_COL_WRITES;
    1308        6720 :         case IOOP_WRITEBACK:
    1309        6720 :             return IO_COL_WRITEBACKS;
    1310             :     }
    1311             : 
    1312           0 :     elog(ERROR, "unrecognized IOOp value: %d", io_op);
    1313             :     pg_unreachable();
    1314             : }
    1315             : 
    1316             : /*
    1317             :  * Get the number of the column containing IO times for the specified IOOp.
    1318             :  * This function encodes our assumption that IO time for an IOOp is displayed
    1319             :  * in the view in the column directly after the IOOp counts. If an op has no
    1320             :  * associated time, IO_COL_INVALID is returned.
    1321             :  */
    1322             : static io_stat_col
    1323       26880 : pgstat_get_io_time_index(IOOp io_op)
    1324             : {
    1325       26880 :     switch (io_op)
    1326             :     {
    1327       16800 :         case IOOP_READ:
    1328             :         case IOOP_WRITE:
    1329             :         case IOOP_WRITEBACK:
    1330             :         case IOOP_EXTEND:
    1331             :         case IOOP_FSYNC:
    1332       16800 :             return pgstat_get_io_op_index(io_op) + 1;
    1333       10080 :         case IOOP_EVICT:
    1334             :         case IOOP_HIT:
    1335             :         case IOOP_REUSE:
    1336       10080 :             return IO_COL_INVALID;
    1337             :     }
    1338             : 
    1339           0 :     elog(ERROR, "unrecognized IOOp value: %d", io_op);
    1340             :     pg_unreachable();
    1341             : }
    1342             : 
    1343             : static inline double
    1344       12768 : pg_stat_us_to_ms(PgStat_Counter val_ms)
    1345             : {
    1346       12768 :     return val_ms * (double) 0.001;
    1347             : }
    1348             : 
    1349             : Datum
    1350         112 : pg_stat_get_io(PG_FUNCTION_ARGS)
    1351             : {
    1352             :     ReturnSetInfo *rsinfo;
    1353             :     PgStat_IO  *backends_io_stats;
    1354             :     Datum       reset_time;
    1355             : 
    1356         112 :     InitMaterializedSRF(fcinfo, 0);
    1357         112 :     rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    1358             : 
    1359         112 :     backends_io_stats = pgstat_fetch_stat_io();
    1360             : 
    1361         112 :     reset_time = TimestampTzGetDatum(backends_io_stats->stat_reset_timestamp);
    1362             : 
    1363        1680 :     for (int bktype = 0; bktype < BACKEND_NUM_TYPES; bktype++)
    1364             :     {
    1365        1568 :         Datum       bktype_desc = CStringGetTextDatum(GetBackendTypeDesc(bktype));
    1366        1568 :         PgStat_BktypeIO *bktype_stats = &backends_io_stats->stats[bktype];
    1367             : 
    1368             :         /*
    1369             :          * In Assert builds, we can afford an extra loop through all of the
    1370             :          * counters checking that only expected stats are non-zero, since it
    1371             :          * keeps the non-Assert code cleaner.
    1372             :          */
    1373             :         Assert(pgstat_bktype_io_stats_valid(bktype_stats, bktype));
    1374             : 
    1375             :         /*
    1376             :          * For those BackendTypes without IO Operation stats, skip
    1377             :          * representing them in the view altogether.
    1378             :          */
    1379        1568 :         if (!pgstat_tracks_io_bktype(bktype))
    1380         560 :             continue;
    1381             : 
    1382        3024 :         for (int io_obj = 0; io_obj < IOOBJECT_NUM_TYPES; io_obj++)
    1383             :         {
    1384        2016 :             const char *obj_name = pgstat_get_io_object_name(io_obj);
    1385             : 
    1386       10080 :             for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
    1387             :             {
    1388        8064 :                 const char *context_name = pgstat_get_io_context_name(io_context);
    1389             : 
    1390        8064 :                 Datum       values[IO_NUM_COLUMNS] = {0};
    1391        8064 :                 bool        nulls[IO_NUM_COLUMNS] = {0};
    1392             : 
    1393             :                 /*
    1394             :                  * Some combinations of BackendType, IOObject, and IOContext
    1395             :                  * are not valid for any type of IOOp. In such cases, omit the
    1396             :                  * entire row from the view.
    1397             :                  */
    1398        8064 :                 if (!pgstat_tracks_io_object(bktype, io_obj, io_context))
    1399        4704 :                     continue;
    1400             : 
    1401        3360 :                 values[IO_COL_BACKEND_TYPE] = bktype_desc;
    1402        3360 :                 values[IO_COL_CONTEXT] = CStringGetTextDatum(context_name);
    1403        3360 :                 values[IO_COL_OBJECT] = CStringGetTextDatum(obj_name);
    1404        3360 :                 values[IO_COL_RESET_TIME] = TimestampTzGetDatum(reset_time);
    1405             : 
    1406             :                 /*
    1407             :                  * Hard-code this to the value of BLCKSZ for now. Future
    1408             :                  * values could include XLOG_BLCKSZ, once WAL IO is tracked,
    1409             :                  * and constant multipliers, once non-block-oriented IO (e.g.
    1410             :                  * temporary file IO) is tracked.
    1411             :                  */
    1412        3360 :                 values[IO_COL_CONVERSION] = Int64GetDatum(BLCKSZ);
    1413             : 
    1414       30240 :                 for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
    1415             :                 {
    1416       26880 :                     int         op_idx = pgstat_get_io_op_index(io_op);
    1417       26880 :                     int         time_idx = pgstat_get_io_time_index(io_op);
    1418             : 
    1419             :                     /*
    1420             :                      * Some combinations of BackendType and IOOp, of IOContext
    1421             :                      * and IOOp, and of IOObject and IOOp are not tracked. Set
    1422             :                      * these cells in the view NULL.
    1423             :                      */
    1424       26880 :                     if (pgstat_tracks_io_op(bktype, io_obj, io_context, io_op))
    1425             :                     {
    1426       21056 :                         PgStat_Counter count =
    1427             :                             bktype_stats->counts[io_obj][io_context][io_op];
    1428             : 
    1429       21056 :                         values[op_idx] = Int64GetDatum(count);
    1430             :                     }
    1431             :                     else
    1432        5824 :                         nulls[op_idx] = true;
    1433             : 
    1434             :                     /* not every operation is timed */
    1435       26880 :                     if (time_idx == IO_COL_INVALID)
    1436       10080 :                         continue;
    1437             : 
    1438       16800 :                     if (!nulls[op_idx])
    1439             :                     {
    1440       12768 :                         PgStat_Counter time =
    1441             :                             bktype_stats->times[io_obj][io_context][io_op];
    1442             : 
    1443       12768 :                         values[time_idx] = Float8GetDatum(pg_stat_us_to_ms(time));
    1444             :                     }
    1445             :                     else
    1446        4032 :                         nulls[time_idx] = true;
    1447             :                 }
    1448             : 
    1449        3360 :                 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
    1450             :                                      values, nulls);
    1451             :             }
    1452             :         }
    1453             :     }
    1454             : 
    1455         112 :     return (Datum) 0;
    1456             : }
    1457             : 
    1458             : /*
    1459             :  * Returns statistics of WAL activity
    1460             :  */
    1461             : Datum
    1462          84 : pg_stat_get_wal(PG_FUNCTION_ARGS)
    1463             : {
    1464             : #define PG_STAT_GET_WAL_COLS    9
    1465             :     TupleDesc   tupdesc;
    1466          84 :     Datum       values[PG_STAT_GET_WAL_COLS] = {0};
    1467          84 :     bool        nulls[PG_STAT_GET_WAL_COLS] = {0};
    1468             :     char        buf[256];
    1469             :     PgStat_WalStats *wal_stats;
    1470             : 
    1471             :     /* Initialise attributes information in the tuple descriptor */
    1472          84 :     tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_WAL_COLS);
    1473          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "wal_records",
    1474             :                        INT8OID, -1, 0);
    1475          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "wal_fpi",
    1476             :                        INT8OID, -1, 0);
    1477          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 3, "wal_bytes",
    1478             :                        NUMERICOID, -1, 0);
    1479          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_buffers_full",
    1480             :                        INT8OID, -1, 0);
    1481          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 5, "wal_write",
    1482             :                        INT8OID, -1, 0);
    1483          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 6, "wal_sync",
    1484             :                        INT8OID, -1, 0);
    1485          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 7, "wal_write_time",
    1486             :                        FLOAT8OID, -1, 0);
    1487          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 8, "wal_sync_time",
    1488             :                        FLOAT8OID, -1, 0);
    1489          84 :     TupleDescInitEntry(tupdesc, (AttrNumber) 9, "stats_reset",
    1490             :                        TIMESTAMPTZOID, -1, 0);
    1491             : 
    1492          84 :     BlessTupleDesc(tupdesc);
    1493             : 
    1494             :     /* Get statistics about WAL activity */
    1495          84 :     wal_stats = pgstat_fetch_stat_wal();
    1496             : 
    1497             :     /* Fill values and NULLs */
    1498          84 :     values[0] = Int64GetDatum(wal_stats->wal_records);
    1499          84 :     values[1] = Int64GetDatum(wal_stats->wal_fpi);
    1500             : 
    1501             :     /* Convert to numeric. */
    1502          84 :     snprintf(buf, sizeof buf, UINT64_FORMAT, wal_stats->wal_bytes);
    1503          84 :     values[2] = DirectFunctionCall3(numeric_in,
    1504             :                                     CStringGetDatum(buf),
    1505             :                                     ObjectIdGetDatum(0),
    1506             :                                     Int32GetDatum(-1));
    1507             : 
    1508          84 :     values[3] = Int64GetDatum(wal_stats->wal_buffers_full);
    1509          84 :     values[4] = Int64GetDatum(wal_stats->wal_write);
    1510          84 :     values[5] = Int64GetDatum(wal_stats->wal_sync);
    1511             : 
    1512             :     /* Convert counters from microsec to millisec for display */
    1513          84 :     values[6] = Float8GetDatum(((double) wal_stats->wal_write_time) / 1000.0);
    1514          84 :     values[7] = Float8GetDatum(((double) wal_stats->wal_sync_time) / 1000.0);
    1515             : 
    1516          84 :     values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
    1517             : 
    1518             :     /* Returns the record as Datum */
    1519          84 :     PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
    1520             : }
    1521             : 
    1522             : /*
    1523             :  * Returns statistics of SLRU caches.
    1524             :  */
    1525             : Datum
    1526         112 : pg_stat_get_slru(PG_FUNCTION_ARGS)
    1527             : {
    1528             : #define PG_STAT_GET_SLRU_COLS   9
    1529         112 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    1530             :     int         i;
    1531             :     PgStat_SLRUStats *stats;
    1532             : 
    1533         112 :     InitMaterializedSRF(fcinfo, 0);
    1534             : 
    1535             :     /* request SLRU stats from the cumulative stats system */
    1536         112 :     stats = pgstat_fetch_slru();
    1537             : 
    1538         112 :     for (i = 0;; i++)
    1539         896 :     {
    1540             :         /* for each row */
    1541        1008 :         Datum       values[PG_STAT_GET_SLRU_COLS] = {0};
    1542        1008 :         bool        nulls[PG_STAT_GET_SLRU_COLS] = {0};
    1543             :         PgStat_SLRUStats stat;
    1544             :         const char *name;
    1545             : 
    1546        1008 :         name = pgstat_get_slru_name(i);
    1547             : 
    1548        1008 :         if (!name)
    1549         112 :             break;
    1550             : 
    1551         896 :         stat = stats[i];
    1552             : 
    1553         896 :         values[0] = PointerGetDatum(cstring_to_text(name));
    1554         896 :         values[1] = Int64GetDatum(stat.blocks_zeroed);
    1555         896 :         values[2] = Int64GetDatum(stat.blocks_hit);
    1556         896 :         values[3] = Int64GetDatum(stat.blocks_read);
    1557         896 :         values[4] = Int64GetDatum(stat.blocks_written);
    1558         896 :         values[5] = Int64GetDatum(stat.blocks_exists);
    1559         896 :         values[6] = Int64GetDatum(stat.flush);
    1560         896 :         values[7] = Int64GetDatum(stat.truncate);
    1561         896 :         values[8] = TimestampTzGetDatum(stat.stat_reset_timestamp);
    1562             : 
    1563         896 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
    1564             :     }
    1565             : 
    1566         112 :     return (Datum) 0;
    1567             : }
    1568             : 
    1569             : #define PG_STAT_GET_XACT_RELENTRY_INT64(stat)           \
    1570             : Datum                                                   \
    1571             : CppConcat(pg_stat_get_xact_,stat)(PG_FUNCTION_ARGS)     \
    1572             : {                                                       \
    1573             :     Oid         relid = PG_GETARG_OID(0);               \
    1574             :     int64       result;                                 \
    1575             :     PgStat_TableStatus *tabentry;                       \
    1576             :                                                         \
    1577             :     if ((tabentry = find_tabstat_entry(relid)) == NULL) \
    1578             :         result = 0;                                     \
    1579             :     else                                                \
    1580             :         result = (int64) (tabentry->counts.stat);        \
    1581             :                                                         \
    1582             :     PG_RETURN_INT64(result);                            \
    1583             : }
    1584             : 
    1585             : /* pg_stat_get_xact_numscans */
    1586           0 : PG_STAT_GET_XACT_RELENTRY_INT64(numscans)
    1587             : 
    1588             : /* pg_stat_get_xact_tuples_returned */
    1589           0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_returned)
    1590             : 
    1591             : /* pg_stat_get_xact_tuples_fetched */
    1592           0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_fetched)
    1593             : 
    1594             : /* pg_stat_get_xact_tuples_hot_updated */
    1595           0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_hot_updated)
    1596             : 
    1597             : /* pg_stat_get_xact_tuples_newpage_updated */
    1598           0 : PG_STAT_GET_XACT_RELENTRY_INT64(tuples_newpage_updated)
    1599             : 
    1600             : /* pg_stat_get_xact_blocks_fetched */
    1601           0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_fetched)
    1602             : 
    1603             : /* pg_stat_get_xact_blocks_hit */
    1604           0 : PG_STAT_GET_XACT_RELENTRY_INT64(blocks_hit)
    1605             : 
    1606             : Datum
    1607          48 : pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)
    1608             : {
    1609          48 :     Oid         relid = PG_GETARG_OID(0);
    1610             :     int64       result;
    1611             :     PgStat_TableStatus *tabentry;
    1612             :     PgStat_TableXactStatus *trans;
    1613             : 
    1614          48 :     if ((tabentry = find_tabstat_entry(relid)) == NULL)
    1615          12 :         result = 0;
    1616             :     else
    1617             :     {
    1618          36 :         result = tabentry->counts.tuples_inserted;
    1619             :         /* live subtransactions' counts aren't in tuples_inserted yet */
    1620          84 :         for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
    1621          48 :             result += trans->tuples_inserted;
    1622             :     }
    1623             : 
    1624          48 :     PG_RETURN_INT64(result);
    1625             : }
    1626             : 
    1627             : Datum
    1628           0 : pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS)
    1629             : {
    1630           0 :     Oid         relid = PG_GETARG_OID(0);
    1631             :     int64       result;
    1632             :     PgStat_TableStatus *tabentry;
    1633             :     PgStat_TableXactStatus *trans;
    1634             : 
    1635           0 :     if ((tabentry = find_tabstat_entry(relid)) == NULL)
    1636           0 :         result = 0;
    1637             :     else
    1638             :     {
    1639           0 :         result = tabentry->counts.tuples_updated;
    1640             :         /* live subtransactions' counts aren't in tuples_updated yet */
    1641           0 :         for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
    1642           0 :             result += trans->tuples_updated;
    1643             :     }
    1644             : 
    1645           0 :     PG_RETURN_INT64(result);
    1646             : }
    1647             : 
    1648             : Datum
    1649           0 : pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)
    1650             : {
    1651           0 :     Oid         relid = PG_GETARG_OID(0);
    1652             :     int64       result;
    1653             :     PgStat_TableStatus *tabentry;
    1654             :     PgStat_TableXactStatus *trans;
    1655             : 
    1656           0 :     if ((tabentry = find_tabstat_entry(relid)) == NULL)
    1657           0 :         result = 0;
    1658             :     else
    1659             :     {
    1660           0 :         result = tabentry->counts.tuples_deleted;
    1661             :         /* live subtransactions' counts aren't in tuples_deleted yet */
    1662           0 :         for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
    1663           0 :             result += trans->tuples_deleted;
    1664             :     }
    1665             : 
    1666           0 :     PG_RETURN_INT64(result);
    1667             : }
    1668             : 
    1669             : Datum
    1670          24 : pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
    1671             : {
    1672          24 :     Oid         funcid = PG_GETARG_OID(0);
    1673             :     PgStat_FunctionCounts *funcentry;
    1674             : 
    1675          24 :     if ((funcentry = find_funcstat_entry(funcid)) == NULL)
    1676           6 :         PG_RETURN_NULL();
    1677          18 :     PG_RETURN_INT64(funcentry->numcalls);
    1678             : }
    1679             : 
    1680             : #define PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(stat)              \
    1681             : Datum                                                           \
    1682             : CppConcat(pg_stat_get_xact_function_,stat)(PG_FUNCTION_ARGS)    \
    1683             : {                                                               \
    1684             :     Oid         funcid = PG_GETARG_OID(0);                      \
    1685             :     PgStat_FunctionCounts *funcentry;                           \
    1686             :                                                                 \
    1687             :     if ((funcentry = find_funcstat_entry(funcid)) == NULL)      \
    1688             :         PG_RETURN_NULL();                                       \
    1689             :     PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->stat));  \
    1690             : }
    1691             : 
    1692             : /* pg_stat_get_xact_function_total_time */
    1693           0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(total_time)
    1694             : 
    1695             : /* pg_stat_get_xact_function_self_time */
    1696           0 : PG_STAT_GET_XACT_FUNCENTRY_FLOAT8_MS(self_time)
    1697             : 
    1698             : /* Get the timestamp of the current statistics snapshot */
    1699             : Datum
    1700          60 : pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
    1701             : {
    1702             :     bool        have_snapshot;
    1703             :     TimestampTz ts;
    1704             : 
    1705          60 :     ts = pgstat_get_stat_snapshot_timestamp(&have_snapshot);
    1706             : 
    1707          60 :     if (!have_snapshot)
    1708          36 :         PG_RETURN_NULL();
    1709             : 
    1710          24 :     PG_RETURN_TIMESTAMPTZ(ts);
    1711             : }
    1712             : 
    1713             : /* Discard the active statistics snapshot */
    1714             : Datum
    1715          14 : pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
    1716             : {
    1717          14 :     pgstat_clear_snapshot();
    1718             : 
    1719          14 :     PG_RETURN_VOID();
    1720             : }
    1721             : 
    1722             : 
    1723             : /* Force statistics to be reported at the next occasion */
    1724             : Datum
    1725         402 : pg_stat_force_next_flush(PG_FUNCTION_ARGS)
    1726             : {
    1727         402 :     pgstat_force_next_flush();
    1728             : 
    1729         402 :     PG_RETURN_VOID();
    1730             : }
    1731             : 
    1732             : 
    1733             : /* Reset all counters for the current database */
    1734             : Datum
    1735          26 : pg_stat_reset(PG_FUNCTION_ARGS)
    1736             : {
    1737          26 :     pgstat_reset_counters();
    1738             : 
    1739          26 :     PG_RETURN_VOID();
    1740             : }
    1741             : 
    1742             : /*
    1743             :  * Reset some shared cluster-wide counters
    1744             :  *
    1745             :  * When adding a new reset target, ideally the name should match that in
    1746             :  * pgstat_kind_infos, if relevant.
    1747             :  */
    1748             : Datum
    1749          30 : pg_stat_reset_shared(PG_FUNCTION_ARGS)
    1750             : {
    1751          30 :     char       *target = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1752             : 
    1753          30 :     if (strcmp(target, "archiver") == 0)
    1754           8 :         pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
    1755          22 :     else if (strcmp(target, "bgwriter") == 0)
    1756             :     {
    1757             :         /*
    1758             :          * Historically checkpointer was part of bgwriter, continue to reset
    1759             :          * both for now.
    1760             :          */
    1761           8 :         pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
    1762           8 :         pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
    1763             :     }
    1764          14 :     else if (strcmp(target, "io") == 0)
    1765           6 :         pgstat_reset_of_kind(PGSTAT_KIND_IO);
    1766           8 :     else if (strcmp(target, "recovery_prefetch") == 0)
    1767           0 :         XLogPrefetchResetStats();
    1768           8 :     else if (strcmp(target, "wal") == 0)
    1769           8 :         pgstat_reset_of_kind(PGSTAT_KIND_WAL);
    1770             :     else
    1771           0 :         ereport(ERROR,
    1772             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1773             :                  errmsg("unrecognized reset target: \"%s\"", target),
    1774             :                  errhint("Target must be \"archiver\", \"bgwriter\", \"io\", \"recovery_prefetch\", or \"wal\".")));
    1775             : 
    1776          30 :     PG_RETURN_VOID();
    1777             : }
    1778             : 
    1779             : /* Reset a single counter in the current database */
    1780             : Datum
    1781           6 : pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
    1782             : {
    1783           6 :     Oid         taboid = PG_GETARG_OID(0);
    1784             : 
    1785           6 :     pgstat_reset(PGSTAT_KIND_RELATION, MyDatabaseId, taboid);
    1786             : 
    1787           6 :     PG_RETURN_VOID();
    1788             : }
    1789             : 
    1790             : Datum
    1791           4 : pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
    1792             : {
    1793           4 :     Oid         funcoid = PG_GETARG_OID(0);
    1794             : 
    1795           4 :     pgstat_reset(PGSTAT_KIND_FUNCTION, MyDatabaseId, funcoid);
    1796             : 
    1797           4 :     PG_RETURN_VOID();
    1798             : }
    1799             : 
    1800             : /* Reset SLRU counters (a specific one or all of them). */
    1801             : Datum
    1802          12 : pg_stat_reset_slru(PG_FUNCTION_ARGS)
    1803             : {
    1804          12 :     char       *target = NULL;
    1805             : 
    1806          12 :     if (PG_ARGISNULL(0))
    1807           6 :         pgstat_reset_of_kind(PGSTAT_KIND_SLRU);
    1808             :     else
    1809             :     {
    1810           6 :         target = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1811           6 :         pgstat_reset_slru(target);
    1812             :     }
    1813             : 
    1814          12 :     PG_RETURN_VOID();
    1815             : }
    1816             : 
    1817             : /* Reset replication slots stats (a specific one or all of them). */
    1818             : Datum
    1819          12 : pg_stat_reset_replication_slot(PG_FUNCTION_ARGS)
    1820             : {
    1821          12 :     char       *target = NULL;
    1822             : 
    1823          12 :     if (PG_ARGISNULL(0))
    1824           4 :         pgstat_reset_of_kind(PGSTAT_KIND_REPLSLOT);
    1825             :     else
    1826             :     {
    1827           8 :         target = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1828           8 :         pgstat_reset_replslot(target);
    1829             :     }
    1830             : 
    1831          10 :     PG_RETURN_VOID();
    1832             : }
    1833             : 
    1834             : /* Reset subscription stats (a specific one or all of them) */
    1835             : Datum
    1836          20 : pg_stat_reset_subscription_stats(PG_FUNCTION_ARGS)
    1837             : {
    1838             :     Oid         subid;
    1839             : 
    1840          20 :     if (PG_ARGISNULL(0))
    1841             :     {
    1842             :         /* Clear all subscription stats */
    1843           4 :         pgstat_reset_of_kind(PGSTAT_KIND_SUBSCRIPTION);
    1844             :     }
    1845             :     else
    1846             :     {
    1847          16 :         subid = PG_GETARG_OID(0);
    1848             : 
    1849          16 :         if (!OidIsValid(subid))
    1850           0 :             ereport(ERROR,
    1851             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    1852             :                      errmsg("invalid subscription OID %u", subid)));
    1853          16 :         pgstat_reset(PGSTAT_KIND_SUBSCRIPTION, InvalidOid, subid);
    1854             :     }
    1855             : 
    1856          20 :     PG_RETURN_VOID();
    1857             : }
    1858             : 
    1859             : Datum
    1860          46 : pg_stat_get_archiver(PG_FUNCTION_ARGS)
    1861             : {
    1862             :     TupleDesc   tupdesc;
    1863          46 :     Datum       values[7] = {0};
    1864          46 :     bool        nulls[7] = {0};
    1865             :     PgStat_ArchiverStats *archiver_stats;
    1866             : 
    1867             :     /* Initialise attributes information in the tuple descriptor */
    1868          46 :     tupdesc = CreateTemplateTupleDesc(7);
    1869          46 :     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
    1870             :                        INT8OID, -1, 0);
    1871          46 :     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
    1872             :                        TEXTOID, -1, 0);
    1873          46 :     TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
    1874             :                        TIMESTAMPTZOID, -1, 0);
    1875          46 :     TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
    1876             :                        INT8OID, -1, 0);
    1877          46 :     TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
    1878             :                        TEXTOID, -1, 0);
    1879          46 :     TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
    1880             :                        TIMESTAMPTZOID, -1, 0);
    1881          46 :     TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
    1882             :                        TIMESTAMPTZOID, -1, 0);
    1883             : 
    1884          46 :     BlessTupleDesc(tupdesc);
    1885             : 
    1886             :     /* Get statistics about the archiver process */
    1887          46 :     archiver_stats = pgstat_fetch_stat_archiver();
    1888             : 
    1889             :     /* Fill values and NULLs */
    1890          46 :     values[0] = Int64GetDatum(archiver_stats->archived_count);
    1891          46 :     if (*(archiver_stats->last_archived_wal) == '\0')
    1892          30 :         nulls[1] = true;
    1893             :     else
    1894          16 :         values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
    1895             : 
    1896          46 :     if (archiver_stats->last_archived_timestamp == 0)
    1897          30 :         nulls[2] = true;
    1898             :     else
    1899          16 :         values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
    1900             : 
    1901          46 :     values[3] = Int64GetDatum(archiver_stats->failed_count);
    1902          46 :     if (*(archiver_stats->last_failed_wal) == '\0')
    1903          30 :         nulls[4] = true;
    1904             :     else
    1905          16 :         values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
    1906             : 
    1907          46 :     if (archiver_stats->last_failed_timestamp == 0)
    1908          30 :         nulls[5] = true;
    1909             :     else
    1910          16 :         values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
    1911             : 
    1912          46 :     if (archiver_stats->stat_reset_timestamp == 0)
    1913           0 :         nulls[6] = true;
    1914             :     else
    1915          46 :         values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
    1916             : 
    1917             :     /* Returns the record as Datum */
    1918          46 :     PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
    1919             : }
    1920             : 
    1921             : /*
    1922             :  * Get the statistics for the replication slot. If the slot statistics is not
    1923             :  * available, return all-zeroes stats.
    1924             :  */
    1925             : Datum
    1926          86 : pg_stat_get_replication_slot(PG_FUNCTION_ARGS)
    1927             : {
    1928             : #define PG_STAT_GET_REPLICATION_SLOT_COLS 10
    1929          86 :     text       *slotname_text = PG_GETARG_TEXT_P(0);
    1930             :     NameData    slotname;
    1931             :     TupleDesc   tupdesc;
    1932          86 :     Datum       values[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
    1933          86 :     bool        nulls[PG_STAT_GET_REPLICATION_SLOT_COLS] = {0};
    1934             :     PgStat_StatReplSlotEntry *slotent;
    1935             :     PgStat_StatReplSlotEntry allzero;
    1936             : 
    1937             :     /* Initialise attributes information in the tuple descriptor */
    1938          86 :     tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_REPLICATION_SLOT_COLS);
    1939          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "slot_name",
    1940             :                        TEXTOID, -1, 0);
    1941          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "spill_txns",
    1942             :                        INT8OID, -1, 0);
    1943          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 3, "spill_count",
    1944             :                        INT8OID, -1, 0);
    1945          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 4, "spill_bytes",
    1946             :                        INT8OID, -1, 0);
    1947          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stream_txns",
    1948             :                        INT8OID, -1, 0);
    1949          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stream_count",
    1950             :                        INT8OID, -1, 0);
    1951          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stream_bytes",
    1952             :                        INT8OID, -1, 0);
    1953          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 8, "total_txns",
    1954             :                        INT8OID, -1, 0);
    1955          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 9, "total_bytes",
    1956             :                        INT8OID, -1, 0);
    1957          86 :     TupleDescInitEntry(tupdesc, (AttrNumber) 10, "stats_reset",
    1958             :                        TIMESTAMPTZOID, -1, 0);
    1959          86 :     BlessTupleDesc(tupdesc);
    1960             : 
    1961          86 :     namestrcpy(&slotname, text_to_cstring(slotname_text));
    1962          86 :     slotent = pgstat_fetch_replslot(slotname);
    1963          86 :     if (!slotent)
    1964             :     {
    1965             :         /*
    1966             :          * If the slot is not found, initialise its stats. This is possible if
    1967             :          * the create slot message is lost.
    1968             :          */
    1969           4 :         memset(&allzero, 0, sizeof(PgStat_StatReplSlotEntry));
    1970           4 :         slotent = &allzero;
    1971             :     }
    1972             : 
    1973          86 :     values[0] = CStringGetTextDatum(NameStr(slotname));
    1974          86 :     values[1] = Int64GetDatum(slotent->spill_txns);
    1975          86 :     values[2] = Int64GetDatum(slotent->spill_count);
    1976          86 :     values[3] = Int64GetDatum(slotent->spill_bytes);
    1977          86 :     values[4] = Int64GetDatum(slotent->stream_txns);
    1978          86 :     values[5] = Int64GetDatum(slotent->stream_count);
    1979          86 :     values[6] = Int64GetDatum(slotent->stream_bytes);
    1980          86 :     values[7] = Int64GetDatum(slotent->total_txns);
    1981          86 :     values[8] = Int64GetDatum(slotent->total_bytes);
    1982             : 
    1983          86 :     if (slotent->stat_reset_timestamp == 0)
    1984          44 :         nulls[9] = true;
    1985             :     else
    1986          42 :         values[9] = TimestampTzGetDatum(slotent->stat_reset_timestamp);
    1987             : 
    1988             :     /* Returns the record as Datum */
    1989          86 :     PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
    1990             : }
    1991             : 
    1992             : /*
    1993             :  * Get the subscription statistics for the given subscription. If the
    1994             :  * subscription statistics is not available, return all-zeros stats.
    1995             :  */
    1996             : Datum
    1997          58 : pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
    1998             : {
    1999             : #define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 4
    2000          58 :     Oid         subid = PG_GETARG_OID(0);
    2001             :     TupleDesc   tupdesc;
    2002          58 :     Datum       values[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
    2003          58 :     bool        nulls[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
    2004             :     PgStat_StatSubEntry *subentry;
    2005             :     PgStat_StatSubEntry allzero;
    2006             : 
    2007             :     /* Get subscription stats */
    2008          58 :     subentry = pgstat_fetch_stat_subscription(subid);
    2009             : 
    2010             :     /* Initialise attributes information in the tuple descriptor */
    2011          58 :     tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
    2012          58 :     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "subid",
    2013             :                        OIDOID, -1, 0);
    2014          58 :     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "apply_error_count",
    2015             :                        INT8OID, -1, 0);
    2016          58 :     TupleDescInitEntry(tupdesc, (AttrNumber) 3, "sync_error_count",
    2017             :                        INT8OID, -1, 0);
    2018          58 :     TupleDescInitEntry(tupdesc, (AttrNumber) 4, "stats_reset",
    2019             :                        TIMESTAMPTZOID, -1, 0);
    2020          58 :     BlessTupleDesc(tupdesc);
    2021             : 
    2022          58 :     if (!subentry)
    2023             :     {
    2024             :         /* If the subscription is not found, initialise its stats */
    2025           0 :         memset(&allzero, 0, sizeof(PgStat_StatSubEntry));
    2026           0 :         subentry = &allzero;
    2027             :     }
    2028             : 
    2029             :     /* subid */
    2030          58 :     values[0] = ObjectIdGetDatum(subid);
    2031             : 
    2032             :     /* apply_error_count */
    2033          58 :     values[1] = Int64GetDatum(subentry->apply_error_count);
    2034             : 
    2035             :     /* sync_error_count */
    2036          58 :     values[2] = Int64GetDatum(subentry->sync_error_count);
    2037             : 
    2038             :     /* stats_reset */
    2039          58 :     if (subentry->stat_reset_timestamp == 0)
    2040          20 :         nulls[3] = true;
    2041             :     else
    2042          38 :         values[3] = TimestampTzGetDatum(subentry->stat_reset_timestamp);
    2043             : 
    2044             :     /* Returns the record as Datum */
    2045          58 :     PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
    2046             : }
    2047             : 
    2048             : /*
    2049             :  * Checks for presence of stats for object with provided kind, database oid,
    2050             :  * object oid.
    2051             :  *
    2052             :  * This is useful for tests, but not really anything else. Therefore not
    2053             :  * documented.
    2054             :  */
    2055             : Datum
    2056         168 : pg_stat_have_stats(PG_FUNCTION_ARGS)
    2057             : {
    2058         168 :     char       *stats_type = text_to_cstring(PG_GETARG_TEXT_P(0));
    2059         168 :     Oid         dboid = PG_GETARG_OID(1);
    2060         168 :     Oid         objoid = PG_GETARG_OID(2);
    2061         168 :     PgStat_Kind kind = pgstat_get_kind_from_str(stats_type);
    2062             : 
    2063         162 :     PG_RETURN_BOOL(pgstat_have_entry(kind, dboid, objoid));
    2064             : }

Generated by: LCOV version 1.14