LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pgstatfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 531 797 66.6 %
Date: 2023-12-11 14:10:49 Functions: 57 117 48.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14