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

Generated by: LCOV version 1.14