Coverage Report

Created: 2025-07-03 06:49

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