LCOV - code coverage report
Current view: top level - src/backend/utils/adt - pgstatfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 628 893 70.3 %
Date: 2025-10-19 00:18:21 Functions: 71 136 52.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.16