diff options
Diffstat (limited to 'src/backend/utils/adt/pgstatfuncs.c')
-rw-r--r-- | src/backend/utils/adt/pgstatfuncs.c | 2392 |
1 files changed, 2392 insertions, 0 deletions
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c new file mode 100644 index 0000000..6fc2196 --- /dev/null +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -0,0 +1,2392 @@ +/*------------------------------------------------------------------------- + * + * pgstatfuncs.c + * Functions for accessing the statistics collector data + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/pgstatfuncs.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/xlog.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_type.h" +#include "common/ip.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "pgstat.h" +#include "postmaster/bgworker_internals.h" +#include "postmaster/postmaster.h" +#include "replication/slot.h" +#include "storage/proc.h" +#include "storage/procarray.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/inet.h" +#include "utils/timestamp.h" + +#define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var)))) + +#define HAS_PGSTAT_PERMISSIONS(role) (is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role)) + +/* Global bgwriter statistics, from bgwriter.c */ +extern PgStat_MsgBgWriter bgwriterStats; + +Datum +pg_stat_get_numscans(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->numscans); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_tuples_returned(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->tuples_returned); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->tuples_fetched); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->tuples_inserted); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_tuples_updated(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->tuples_updated); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->tuples_deleted); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->tuples_hot_updated); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_live_tuples(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->n_live_tuples); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_dead_tuples(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->n_dead_tuples); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->changes_since_analyze); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_ins_since_vacuum(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->inserts_since_vacuum); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->blocks_fetched); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_blocks_hit(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->blocks_hit); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + TimestampTz result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = tabentry->vacuum_timestamp; + + if (result == 0) + PG_RETURN_NULL(); + else + PG_RETURN_TIMESTAMPTZ(result); +} + +Datum +pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + TimestampTz result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = tabentry->autovac_vacuum_timestamp; + + if (result == 0) + PG_RETURN_NULL(); + else + PG_RETURN_TIMESTAMPTZ(result); +} + +Datum +pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + TimestampTz result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = tabentry->analyze_timestamp; + + if (result == 0) + PG_RETURN_NULL(); + else + PG_RETURN_TIMESTAMPTZ(result); +} + +Datum +pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + TimestampTz result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = tabentry->autovac_analyze_timestamp; + + if (result == 0) + PG_RETURN_NULL(); + else + PG_RETURN_TIMESTAMPTZ(result); +} + +Datum +pg_stat_get_vacuum_count(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->vacuum_count); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->autovac_vacuum_count); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_analyze_count(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->analyze_count); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->autovac_analyze_count); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_function_calls(PG_FUNCTION_ARGS) +{ + Oid funcid = PG_GETARG_OID(0); + PgStat_StatFuncEntry *funcentry; + + if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL) + PG_RETURN_NULL(); + PG_RETURN_INT64(funcentry->f_numcalls); +} + +Datum +pg_stat_get_function_total_time(PG_FUNCTION_ARGS) +{ + Oid funcid = PG_GETARG_OID(0); + PgStat_StatFuncEntry *funcentry; + + if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL) + PG_RETURN_NULL(); + /* convert counter from microsec to millisec for display */ + PG_RETURN_FLOAT8(((double) funcentry->f_total_time) / 1000.0); +} + +Datum +pg_stat_get_function_self_time(PG_FUNCTION_ARGS) +{ + Oid funcid = PG_GETARG_OID(0); + PgStat_StatFuncEntry *funcentry; + + if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL) + PG_RETURN_NULL(); + /* convert counter from microsec to millisec for display */ + PG_RETURN_FLOAT8(((double) funcentry->f_self_time) / 1000.0); +} + +Datum +pg_stat_get_backend_idset(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + int *fctx; + int32 result; + + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + /* create a function context for cross-call persistence */ + funcctx = SRF_FIRSTCALL_INIT(); + + fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx, + 2 * sizeof(int)); + funcctx->user_fctx = fctx; + + fctx[0] = 0; + fctx[1] = pgstat_fetch_stat_numbackends(); + } + + /* stuff done on every call of the function */ + funcctx = SRF_PERCALL_SETUP(); + fctx = funcctx->user_fctx; + + fctx[0] += 1; + result = fctx[0]; + + if (result <= fctx[1]) + { + /* do when there is more left to send */ + SRF_RETURN_NEXT(funcctx, Int32GetDatum(result)); + } + else + { + /* do when there is no more left */ + SRF_RETURN_DONE(funcctx); + } +} + +/* + * Returns command progress information for the named command. + */ +Datum +pg_stat_get_progress_info(PG_FUNCTION_ARGS) +{ +#define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3 + int num_backends = pgstat_fetch_stat_numbackends(); + int curr_backend; + char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0)); + ProgressCommandType cmdtype; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not allowed in this context"))); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + /* Translate command name into command type code. */ + if (pg_strcasecmp(cmd, "VACUUM") == 0) + cmdtype = PROGRESS_COMMAND_VACUUM; + else if (pg_strcasecmp(cmd, "ANALYZE") == 0) + cmdtype = PROGRESS_COMMAND_ANALYZE; + else if (pg_strcasecmp(cmd, "CLUSTER") == 0) + cmdtype = PROGRESS_COMMAND_CLUSTER; + else if (pg_strcasecmp(cmd, "CREATE INDEX") == 0) + cmdtype = PROGRESS_COMMAND_CREATE_INDEX; + else if (pg_strcasecmp(cmd, "BASEBACKUP") == 0) + cmdtype = PROGRESS_COMMAND_BASEBACKUP; + else if (pg_strcasecmp(cmd, "COPY") == 0) + cmdtype = PROGRESS_COMMAND_COPY; + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid command name: \"%s\"", cmd))); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + MemoryContextSwitchTo(oldcontext); + + /* 1-based index */ + for (curr_backend = 1; curr_backend <= num_backends; curr_backend++) + { + LocalPgBackendStatus *local_beentry; + PgBackendStatus *beentry; + Datum values[PG_STAT_GET_PROGRESS_COLS]; + bool nulls[PG_STAT_GET_PROGRESS_COLS]; + int i; + + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + local_beentry = pgstat_fetch_stat_local_beentry(curr_backend); + + if (!local_beentry) + continue; + + beentry = &local_beentry->backendStatus; + + /* + * Report values for only those backends which are running the given + * command. + */ + if (!beentry || beentry->st_progress_command != cmdtype) + continue; + + /* Value available to all callers */ + values[0] = Int32GetDatum(beentry->st_procpid); + values[1] = ObjectIdGetDatum(beentry->st_databaseid); + + /* show rest of the values including relid only to role members */ + if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + { + values[2] = ObjectIdGetDatum(beentry->st_progress_command_target); + for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++) + values[i + 3] = Int64GetDatum(beentry->st_progress_param[i]); + } + else + { + nulls[2] = true; + for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++) + nulls[i + 3] = true; + } + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + return (Datum) 0; +} + +/* + * Returns activity of PG backends. + */ +Datum +pg_stat_get_activity(PG_FUNCTION_ARGS) +{ +#define PG_STAT_GET_ACTIVITY_COLS 30 + int num_backends = pgstat_fetch_stat_numbackends(); + int curr_backend; + int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0); + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not allowed in this context"))); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + MemoryContextSwitchTo(oldcontext); + + /* 1-based index */ + for (curr_backend = 1; curr_backend <= num_backends; curr_backend++) + { + /* for each row */ + Datum values[PG_STAT_GET_ACTIVITY_COLS]; + bool nulls[PG_STAT_GET_ACTIVITY_COLS]; + LocalPgBackendStatus *local_beentry; + PgBackendStatus *beentry; + PGPROC *proc; + const char *wait_event_type = NULL; + const char *wait_event = NULL; + + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + /* Get the next one in the list */ + local_beentry = pgstat_fetch_stat_local_beentry(curr_backend); + if (!local_beentry) + { + int i; + + /* Ignore missing entries if looking for specific PID */ + if (pid != -1) + continue; + + for (i = 0; i < lengthof(nulls); i++) + nulls[i] = true; + + nulls[5] = false; + values[5] = CStringGetTextDatum("<backend information not available>"); + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + continue; + } + + beentry = &local_beentry->backendStatus; + + /* If looking for specific PID, ignore all the others */ + if (pid != -1 && beentry->st_procpid != pid) + continue; + + /* Values available to all callers */ + if (beentry->st_databaseid != InvalidOid) + values[0] = ObjectIdGetDatum(beentry->st_databaseid); + else + nulls[0] = true; + + values[1] = Int32GetDatum(beentry->st_procpid); + + if (beentry->st_userid != InvalidOid) + values[2] = ObjectIdGetDatum(beentry->st_userid); + else + nulls[2] = true; + + if (beentry->st_appname) + values[3] = CStringGetTextDatum(beentry->st_appname); + else + nulls[3] = true; + + if (TransactionIdIsValid(local_beentry->backend_xid)) + values[15] = TransactionIdGetDatum(local_beentry->backend_xid); + else + nulls[15] = true; + + if (TransactionIdIsValid(local_beentry->backend_xmin)) + values[16] = TransactionIdGetDatum(local_beentry->backend_xmin); + else + nulls[16] = true; + + /* Values only available to role member or pg_read_all_stats */ + if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + { + SockAddr zero_clientaddr; + char *clipped_activity; + + switch (beentry->st_state) + { + case STATE_IDLE: + values[4] = CStringGetTextDatum("idle"); + break; + case STATE_RUNNING: + values[4] = CStringGetTextDatum("active"); + break; + case STATE_IDLEINTRANSACTION: + values[4] = CStringGetTextDatum("idle in transaction"); + break; + case STATE_FASTPATH: + values[4] = CStringGetTextDatum("fastpath function call"); + break; + case STATE_IDLEINTRANSACTION_ABORTED: + values[4] = CStringGetTextDatum("idle in transaction (aborted)"); + break; + case STATE_DISABLED: + values[4] = CStringGetTextDatum("disabled"); + break; + case STATE_UNDEFINED: + nulls[4] = true; + break; + } + + clipped_activity = pgstat_clip_activity(beentry->st_activity_raw); + values[5] = CStringGetTextDatum(clipped_activity); + pfree(clipped_activity); + + /* leader_pid */ + nulls[28] = true; + + proc = BackendPidGetProc(beentry->st_procpid); + + if (proc == NULL && (beentry->st_backendType != B_BACKEND)) + { + /* + * For an auxiliary process, retrieve process info from + * AuxiliaryProcs stored in shared-memory. + */ + proc = AuxiliaryPidGetProc(beentry->st_procpid); + } + + /* + * If a PGPROC entry was retrieved, display wait events and lock + * group leader information if any. To avoid extra overhead, no + * extra lock is being held, so there is no guarantee of + * consistency across multiple rows. + */ + if (proc != NULL) + { + uint32 raw_wait_event; + PGPROC *leader; + + raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info); + wait_event_type = pgstat_get_wait_event_type(raw_wait_event); + wait_event = pgstat_get_wait_event(raw_wait_event); + + leader = proc->lockGroupLeader; + + /* + * Show the leader only for active parallel workers. This + * leaves the field as NULL for the leader of a parallel + * group. + */ + if (leader && leader->pid != beentry->st_procpid) + { + values[28] = Int32GetDatum(leader->pid); + nulls[28] = false; + } + } + + if (wait_event_type) + values[6] = CStringGetTextDatum(wait_event_type); + else + nulls[6] = true; + + if (wait_event) + values[7] = CStringGetTextDatum(wait_event); + else + nulls[7] = true; + + /* + * Don't expose transaction time for walsenders; it confuses + * monitoring, particularly because we don't keep the time up-to- + * date. + */ + if (beentry->st_xact_start_timestamp != 0 && + beentry->st_backendType != B_WAL_SENDER) + values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp); + else + nulls[8] = true; + + if (beentry->st_activity_start_timestamp != 0) + values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp); + else + nulls[9] = true; + + if (beentry->st_proc_start_timestamp != 0) + values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp); + else + nulls[10] = true; + + if (beentry->st_state_start_timestamp != 0) + values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp); + else + nulls[11] = true; + + /* A zeroed client addr means we don't know */ + memset(&zero_clientaddr, 0, sizeof(zero_clientaddr)); + if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr, + sizeof(zero_clientaddr)) == 0) + { + nulls[12] = true; + nulls[13] = true; + nulls[14] = true; + } + else + { + if (beentry->st_clientaddr.addr.ss_family == AF_INET +#ifdef HAVE_IPV6 + || beentry->st_clientaddr.addr.ss_family == AF_INET6 +#endif + ) + { + char remote_host[NI_MAXHOST]; + char remote_port[NI_MAXSERV]; + int ret; + + remote_host[0] = '\0'; + remote_port[0] = '\0'; + ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr, + beentry->st_clientaddr.salen, + remote_host, sizeof(remote_host), + remote_port, sizeof(remote_port), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret == 0) + { + clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host); + values[12] = DirectFunctionCall1(inet_in, + CStringGetDatum(remote_host)); + if (beentry->st_clienthostname && + beentry->st_clienthostname[0]) + values[13] = CStringGetTextDatum(beentry->st_clienthostname); + else + nulls[13] = true; + values[14] = Int32GetDatum(atoi(remote_port)); + } + else + { + nulls[12] = true; + nulls[13] = true; + nulls[14] = true; + } + } + else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX) + { + /* + * Unix sockets always reports NULL for host and -1 for + * port, so it's possible to tell the difference to + * connections we have no permissions to view, or with + * errors. + */ + nulls[12] = true; + nulls[13] = true; + values[14] = Int32GetDatum(-1); + } + else + { + /* Unknown address type, should never happen */ + nulls[12] = true; + nulls[13] = true; + nulls[14] = true; + } + } + /* Add backend type */ + if (beentry->st_backendType == B_BG_WORKER) + { + const char *bgw_type; + + bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid); + if (bgw_type) + values[17] = CStringGetTextDatum(bgw_type); + else + nulls[17] = true; + } + else + values[17] = + CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType)); + + /* SSL information */ + if (beentry->st_ssl) + { + values[18] = BoolGetDatum(true); /* ssl */ + values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version); + values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher); + values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits); + + if (beentry->st_sslstatus->ssl_client_dn[0]) + values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_client_dn); + else + nulls[22] = true; + + if (beentry->st_sslstatus->ssl_client_serial[0]) + values[23] = DirectFunctionCall3(numeric_in, + CStringGetDatum(beentry->st_sslstatus->ssl_client_serial), + ObjectIdGetDatum(InvalidOid), + Int32GetDatum(-1)); + else + nulls[23] = true; + + if (beentry->st_sslstatus->ssl_issuer_dn[0]) + values[24] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn); + else + nulls[24] = true; + } + else + { + values[18] = BoolGetDatum(false); /* ssl */ + nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = true; + } + + /* GSSAPI information */ + if (beentry->st_gss) + { + values[25] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */ + values[26] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ); + values[27] = BoolGetDatum(beentry->st_gssstatus->gss_enc); /* GSS Encryption in use */ + } + else + { + values[25] = BoolGetDatum(false); /* gss_auth */ + nulls[26] = true; /* No GSS principal */ + values[27] = BoolGetDatum(false); /* GSS Encryption not in + * use */ + } + if (beentry->st_query_id == 0) + nulls[29] = true; + else + values[29] = UInt64GetDatum(beentry->st_query_id); + } + else + { + /* No permissions to view data about this session */ + values[5] = CStringGetTextDatum("<insufficient privilege>"); + nulls[4] = true; + nulls[6] = true; + nulls[7] = true; + nulls[8] = true; + nulls[9] = true; + nulls[10] = true; + nulls[11] = true; + nulls[12] = true; + nulls[13] = true; + nulls[14] = true; + nulls[17] = true; + nulls[18] = true; + nulls[19] = true; + nulls[20] = true; + nulls[21] = true; + nulls[22] = true; + nulls[23] = true; + nulls[24] = true; + nulls[25] = true; + nulls[26] = true; + nulls[27] = true; + nulls[28] = true; + nulls[29] = true; + } + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + + /* If only a single backend was requested, and we found it, break. */ + if (pid != -1) + break; + } + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + return (Datum) 0; +} + + +Datum +pg_backend_pid(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT32(MyProcPid); +} + + +Datum +pg_stat_get_backend_pid(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + PgBackendStatus *beentry; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + PG_RETURN_INT32(beentry->st_procpid); +} + + +Datum +pg_stat_get_backend_dbid(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + PgBackendStatus *beentry; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + PG_RETURN_OID(beentry->st_databaseid); +} + + +Datum +pg_stat_get_backend_userid(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + PgBackendStatus *beentry; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + PG_RETURN_OID(beentry->st_userid); +} + + +Datum +pg_stat_get_backend_activity(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + PgBackendStatus *beentry; + const char *activity; + char *clipped_activity; + text *ret; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + activity = "<backend information not available>"; + else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + activity = "<insufficient privilege>"; + else if (*(beentry->st_activity_raw) == '\0') + activity = "<command string not enabled>"; + else + activity = beentry->st_activity_raw; + + clipped_activity = pgstat_clip_activity(activity); + ret = cstring_to_text(activity); + pfree(clipped_activity); + + PG_RETURN_TEXT_P(ret); +} + +Datum +pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + PgBackendStatus *beentry; + PGPROC *proc; + const char *wait_event_type = NULL; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + wait_event_type = "<backend information not available>"; + else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + wait_event_type = "<insufficient privilege>"; + else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL) + wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info); + + if (!wait_event_type) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(cstring_to_text(wait_event_type)); +} + +Datum +pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + PgBackendStatus *beentry; + PGPROC *proc; + const char *wait_event = NULL; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + wait_event = "<backend information not available>"; + else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + wait_event = "<insufficient privilege>"; + else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL) + wait_event = pgstat_get_wait_event(proc->wait_event_info); + + if (!wait_event) + PG_RETURN_NULL(); + + PG_RETURN_TEXT_P(cstring_to_text(wait_event)); +} + + +Datum +pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + TimestampTz result; + PgBackendStatus *beentry; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + PG_RETURN_NULL(); + + result = beentry->st_activity_start_timestamp; + + /* + * No time recorded for start of current query -- this is the case if the + * user hasn't enabled query-level stats collection. + */ + if (result == 0) + PG_RETURN_NULL(); + + PG_RETURN_TIMESTAMPTZ(result); +} + + +Datum +pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + TimestampTz result; + PgBackendStatus *beentry; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + PG_RETURN_NULL(); + + result = beentry->st_xact_start_timestamp; + + if (result == 0) /* not in a transaction */ + PG_RETURN_NULL(); + + PG_RETURN_TIMESTAMPTZ(result); +} + + +Datum +pg_stat_get_backend_start(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + TimestampTz result; + PgBackendStatus *beentry; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + PG_RETURN_NULL(); + + result = beentry->st_proc_start_timestamp; + + if (result == 0) /* probably can't happen? */ + PG_RETURN_NULL(); + + PG_RETURN_TIMESTAMPTZ(result); +} + + +Datum +pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + PgBackendStatus *beentry; + SockAddr zero_clientaddr; + char remote_host[NI_MAXHOST]; + int ret; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + PG_RETURN_NULL(); + + /* A zeroed client addr means we don't know */ + memset(&zero_clientaddr, 0, sizeof(zero_clientaddr)); + if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr, + sizeof(zero_clientaddr)) == 0) + PG_RETURN_NULL(); + + switch (beentry->st_clientaddr.addr.ss_family) + { + case AF_INET: +#ifdef HAVE_IPV6 + case AF_INET6: +#endif + break; + default: + PG_RETURN_NULL(); + } + + remote_host[0] = '\0'; + ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr, + beentry->st_clientaddr.salen, + remote_host, sizeof(remote_host), + NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) + PG_RETURN_NULL(); + + clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host); + + PG_RETURN_INET_P(DirectFunctionCall1(inet_in, + CStringGetDatum(remote_host))); +} + +Datum +pg_stat_get_backend_client_port(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + PgBackendStatus *beentry; + SockAddr zero_clientaddr; + char remote_port[NI_MAXSERV]; + int ret; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid)) + PG_RETURN_NULL(); + + /* A zeroed client addr means we don't know */ + memset(&zero_clientaddr, 0, sizeof(zero_clientaddr)); + if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr, + sizeof(zero_clientaddr)) == 0) + PG_RETURN_NULL(); + + switch (beentry->st_clientaddr.addr.ss_family) + { + case AF_INET: +#ifdef HAVE_IPV6 + case AF_INET6: +#endif + break; + case AF_UNIX: + PG_RETURN_INT32(-1); + default: + PG_RETURN_NULL(); + } + + remote_port[0] = '\0'; + ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr, + beentry->st_clientaddr.salen, + NULL, 0, + remote_port, sizeof(remote_port), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) + PG_RETURN_NULL(); + + PG_RETURN_DATUM(DirectFunctionCall1(int4in, + CStringGetDatum(remote_port))); +} + + +Datum +pg_stat_get_db_numbackends(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int32 result; + int tot_backends = pgstat_fetch_stat_numbackends(); + int beid; + + result = 0; + for (beid = 1; beid <= tot_backends; beid++) + { + PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid); + + if (beentry && beentry->st_databaseid == dbid) + result++; + } + + PG_RETURN_INT32(result); +} + + +Datum +pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_xact_commit); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_xact_rollback); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_blocks_fetched); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_blocks_hit); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_tuples_returned); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_tuples_fetched); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_tuples_inserted); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_tuples_updated); + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_tuples_deleted); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + TimestampTz result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = dbentry->stat_reset_timestamp; + + if (result == 0) + PG_RETURN_NULL(); + else + PG_RETURN_TIMESTAMPTZ(result); +} + +Datum +pg_stat_get_db_temp_files(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = dbentry->n_temp_files; + + PG_RETURN_INT64(result); +} + + +Datum +pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = dbentry->n_temp_bytes; + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_conflict_tablespace); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_conflict_lock); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_conflict_snapshot); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_conflict_bufferpin); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_conflict_startup_deadlock); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_conflict_tablespace + + dbentry->n_conflict_lock + + dbentry->n_conflict_snapshot + + dbentry->n_conflict_bufferpin + + dbentry->n_conflict_startup_deadlock); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_deadlocks); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_checksum_failures(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result; + PgStat_StatDBEntry *dbentry; + + if (!DataChecksumsEnabled()) + PG_RETURN_NULL(); + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = (int64) (dbentry->n_checksum_failures); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_checksum_last_failure(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + TimestampTz result; + PgStat_StatDBEntry *dbentry; + + if (!DataChecksumsEnabled()) + PG_RETURN_NULL(); + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = dbentry->last_checksum_failure; + + if (result == 0) + PG_RETURN_NULL(); + else + PG_RETURN_TIMESTAMPTZ(result); +} + +Datum +pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + double result; + PgStat_StatDBEntry *dbentry; + + /* convert counter from microsec to millisec for display */ + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = ((double) dbentry->n_block_read_time) / 1000.0; + + PG_RETURN_FLOAT8(result); +} + +Datum +pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + double result; + PgStat_StatDBEntry *dbentry; + + /* convert counter from microsec to millisec for display */ + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL) + result = 0; + else + result = ((double) dbentry->n_block_write_time) / 1000.0; + + PG_RETURN_FLOAT8(result); +} + +Datum +pg_stat_get_db_session_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + double result = 0.0; + PgStat_StatDBEntry *dbentry; + + /* convert counter from microsec to millisec for display */ + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = ((double) dbentry->total_session_time) / 1000.0; + + PG_RETURN_FLOAT8(result); +} + +Datum +pg_stat_get_db_active_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + double result = 0.0; + PgStat_StatDBEntry *dbentry; + + /* convert counter from microsec to millisec for display */ + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = ((double) dbentry->total_active_time) / 1000.0; + + PG_RETURN_FLOAT8(result); +} + +Datum +pg_stat_get_db_idle_in_transaction_time(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + double result = 0.0; + PgStat_StatDBEntry *dbentry; + + /* convert counter from microsec to millisec for display */ + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = ((double) dbentry->total_idle_in_xact_time) / 1000.0; + + PG_RETURN_FLOAT8(result); +} + +Datum +pg_stat_get_db_sessions(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result = 0; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = (int64) (dbentry->n_sessions); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_sessions_abandoned(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result = 0; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = (int64) (dbentry->n_sessions_abandoned); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_sessions_fatal(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result = 0; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = (int64) (dbentry->n_sessions_fatal); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_db_sessions_killed(PG_FUNCTION_ARGS) +{ + Oid dbid = PG_GETARG_OID(0); + int64 result = 0; + PgStat_StatDBEntry *dbentry; + + if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL) + result = (int64) (dbentry->n_sessions_killed); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints); +} + +Datum +pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->requested_checkpoints); +} + +Datum +pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->buf_written_checkpoints); +} + +Datum +pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->buf_written_clean); +} + +Datum +pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean); +} + +Datum +pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS) +{ + /* time is already in msec, just convert to double for presentation */ + PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_write_time); +} + +Datum +pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS) +{ + /* time is already in msec, just convert to double for presentation */ + PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_sync_time); +} + +Datum +pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS) +{ + PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stat_reset_timestamp); +} + +Datum +pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend); +} + +Datum +pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->buf_fsync_backend); +} + +Datum +pg_stat_get_buf_alloc(PG_FUNCTION_ARGS) +{ + PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc); +} + +/* + * Returns statistics of WAL activity + */ +Datum +pg_stat_get_wal(PG_FUNCTION_ARGS) +{ +#define PG_STAT_GET_WAL_COLS 9 + TupleDesc tupdesc; + Datum values[PG_STAT_GET_WAL_COLS]; + bool nulls[PG_STAT_GET_WAL_COLS]; + char buf[256]; + PgStat_WalStats *wal_stats; + + /* Initialise values and NULL flags arrays */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + /* Initialise attributes information in the tuple descriptor */ + tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_WAL_COLS); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "wal_records", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "wal_fpi", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "wal_bytes", + NUMERICOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_buffers_full", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "wal_write", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "wal_sync", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "wal_write_time", + FLOAT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 8, "wal_sync_time", + FLOAT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 9, "stats_reset", + TIMESTAMPTZOID, -1, 0); + + BlessTupleDesc(tupdesc); + + /* Get statistics about WAL activity */ + wal_stats = pgstat_fetch_stat_wal(); + + /* Fill values and NULLs */ + values[0] = Int64GetDatum(wal_stats->wal_records); + values[1] = Int64GetDatum(wal_stats->wal_fpi); + + /* Convert to numeric. */ + snprintf(buf, sizeof buf, UINT64_FORMAT, wal_stats->wal_bytes); + values[2] = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + + values[3] = Int64GetDatum(wal_stats->wal_buffers_full); + values[4] = Int64GetDatum(wal_stats->wal_write); + values[5] = Int64GetDatum(wal_stats->wal_sync); + + /* Convert counters from microsec to millisec for display */ + values[6] = Float8GetDatum(((double) wal_stats->wal_write_time) / 1000.0); + values[7] = Float8GetDatum(((double) wal_stats->wal_sync_time) / 1000.0); + + values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp); + + /* Returns the record as Datum */ + PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); +} + +/* + * Returns statistics of SLRU caches. + */ +Datum +pg_stat_get_slru(PG_FUNCTION_ARGS) +{ +#define PG_STAT_GET_SLRU_COLS 9 + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + int i; + PgStat_SLRUStats *stats; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not allowed in this context"))); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + MemoryContextSwitchTo(oldcontext); + + /* request SLRU stats from the stat collector */ + stats = pgstat_fetch_slru(); + + for (i = 0;; i++) + { + /* for each row */ + Datum values[PG_STAT_GET_SLRU_COLS]; + bool nulls[PG_STAT_GET_SLRU_COLS]; + PgStat_SLRUStats stat; + const char *name; + + name = pgstat_slru_name(i); + + if (!name) + break; + + stat = stats[i]; + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + values[0] = PointerGetDatum(cstring_to_text(name)); + values[1] = Int64GetDatum(stat.blocks_zeroed); + values[2] = Int64GetDatum(stat.blocks_hit); + values[3] = Int64GetDatum(stat.blocks_read); + values[4] = Int64GetDatum(stat.blocks_written); + values[5] = Int64GetDatum(stat.blocks_exists); + values[6] = Int64GetDatum(stat.flush); + values[7] = Int64GetDatum(stat.truncate); + values[8] = TimestampTzGetDatum(stat.stat_reset_timestamp); + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + return (Datum) 0; +} + +Datum +pg_stat_get_xact_numscans(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->t_counts.t_numscans); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->t_counts.t_tuples_returned); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->t_counts.t_tuples_fetched); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + PgStat_TableXactStatus *trans; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + { + result = tabentry->t_counts.t_tuples_inserted; + /* live subtransactions' counts aren't in t_tuples_inserted yet */ + for (trans = tabentry->trans; trans != NULL; trans = trans->upper) + result += trans->tuples_inserted; + } + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + PgStat_TableXactStatus *trans; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + { + result = tabentry->t_counts.t_tuples_updated; + /* live subtransactions' counts aren't in t_tuples_updated yet */ + for (trans = tabentry->trans; trans != NULL; trans = trans->upper) + result += trans->tuples_updated; + } + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + PgStat_TableXactStatus *trans; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + { + result = tabentry->t_counts.t_tuples_deleted; + /* live subtransactions' counts aren't in t_tuples_deleted yet */ + for (trans = tabentry->trans; trans != NULL; trans = trans->upper) + result += trans->tuples_deleted; + } + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->t_counts.t_tuples_hot_updated); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->t_counts.t_blocks_fetched); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 result; + PgStat_TableStatus *tabentry; + + if ((tabentry = find_tabstat_entry(relid)) == NULL) + result = 0; + else + result = (int64) (tabentry->t_counts.t_blocks_hit); + + PG_RETURN_INT64(result); +} + +Datum +pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS) +{ + Oid funcid = PG_GETARG_OID(0); + PgStat_BackendFunctionEntry *funcentry; + + if ((funcentry = find_funcstat_entry(funcid)) == NULL) + PG_RETURN_NULL(); + PG_RETURN_INT64(funcentry->f_counts.f_numcalls); +} + +Datum +pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS) +{ + Oid funcid = PG_GETARG_OID(0); + PgStat_BackendFunctionEntry *funcentry; + + if ((funcentry = find_funcstat_entry(funcid)) == NULL) + PG_RETURN_NULL(); + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_total_time)); +} + +Datum +pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS) +{ + Oid funcid = PG_GETARG_OID(0); + PgStat_BackendFunctionEntry *funcentry; + + if ((funcentry = find_funcstat_entry(funcid)) == NULL) + PG_RETURN_NULL(); + PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_self_time)); +} + + +/* Get the timestamp of the current statistics snapshot */ +Datum +pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS) +{ + PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stats_timestamp); +} + +/* Discard the active statistics snapshot */ +Datum +pg_stat_clear_snapshot(PG_FUNCTION_ARGS) +{ + pgstat_clear_snapshot(); + + PG_RETURN_VOID(); +} + + +/* Reset all counters for the current database */ +Datum +pg_stat_reset(PG_FUNCTION_ARGS) +{ + pgstat_reset_counters(); + + PG_RETURN_VOID(); +} + +/* Reset some shared cluster-wide counters */ +Datum +pg_stat_reset_shared(PG_FUNCTION_ARGS) +{ + char *target = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + pgstat_reset_shared_counters(target); + + PG_RETURN_VOID(); +} + +/* Reset a single counter in the current database */ +Datum +pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS) +{ + Oid taboid = PG_GETARG_OID(0); + + pgstat_reset_single_counter(taboid, RESET_TABLE); + + PG_RETURN_VOID(); +} + +Datum +pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS) +{ + Oid funcoid = PG_GETARG_OID(0); + + pgstat_reset_single_counter(funcoid, RESET_FUNCTION); + + PG_RETURN_VOID(); +} + +/* Reset SLRU counters (a specific one or all of them). */ +Datum +pg_stat_reset_slru(PG_FUNCTION_ARGS) +{ + char *target = NULL; + + if (!PG_ARGISNULL(0)) + target = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + pgstat_reset_slru_counter(target); + + PG_RETURN_VOID(); +} + +/* Reset replication slots stats (a specific one or all of them). */ +Datum +pg_stat_reset_replication_slot(PG_FUNCTION_ARGS) +{ + char *target = NULL; + + if (!PG_ARGISNULL(0)) + { + ReplicationSlot *slot; + + target = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + /* + * Check if the slot exists with the given name. It is possible that + * by the time this message is executed the slot is dropped but at + * least this check will ensure that the given name is for a valid + * slot. + */ + slot = SearchNamedReplicationSlot(target, true); + + if (!slot) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("replication slot \"%s\" does not exist", + target))); + + /* + * Nothing to do for physical slots as we collect stats only for + * logical slots. + */ + if (SlotIsPhysical(slot)) + PG_RETURN_VOID(); + } + + pgstat_reset_replslot_counter(target); + + PG_RETURN_VOID(); +} + +Datum +pg_stat_get_archiver(PG_FUNCTION_ARGS) +{ + TupleDesc tupdesc; + Datum values[7]; + bool nulls[7]; + PgStat_ArchiverStats *archiver_stats; + + /* Initialise values and NULL flags arrays */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + /* Initialise attributes information in the tuple descriptor */ + tupdesc = CreateTemplateTupleDesc(7); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time", + TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time", + TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset", + TIMESTAMPTZOID, -1, 0); + + BlessTupleDesc(tupdesc); + + /* Get statistics about the archiver process */ + archiver_stats = pgstat_fetch_stat_archiver(); + + /* Fill values and NULLs */ + values[0] = Int64GetDatum(archiver_stats->archived_count); + if (*(archiver_stats->last_archived_wal) == '\0') + nulls[1] = true; + else + values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal); + + if (archiver_stats->last_archived_timestamp == 0) + nulls[2] = true; + else + values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp); + + values[3] = Int64GetDatum(archiver_stats->failed_count); + if (*(archiver_stats->last_failed_wal) == '\0') + nulls[4] = true; + else + values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal); + + if (archiver_stats->last_failed_timestamp == 0) + nulls[5] = true; + else + values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp); + + if (archiver_stats->stat_reset_timestamp == 0) + nulls[6] = true; + else + values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp); + + /* Returns the record as Datum */ + PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); +} + +/* + * Get the statistics for the replication slot. If the slot statistics is not + * available, return all-zeroes stats. + */ +Datum +pg_stat_get_replication_slot(PG_FUNCTION_ARGS) +{ +#define PG_STAT_GET_REPLICATION_SLOT_COLS 10 + text *slotname_text; + NameData slotname; + TupleDesc tupdesc; + Datum values[PG_STAT_GET_REPLICATION_SLOT_COLS]; + bool nulls[PG_STAT_GET_REPLICATION_SLOT_COLS]; + PgStat_StatReplSlotEntry *slotent; + PgStat_StatReplSlotEntry allzero; + + /* + * Function was accidentally marked as non-strict, can't change that post + * release. + */ + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + slotname_text = PG_GETARG_TEXT_P(0); + + /* Initialise values and NULL flags arrays */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + + /* Initialise attributes information in the tuple descriptor */ + tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_REPLICATION_SLOT_COLS); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "slot_name", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "spill_txns", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "spill_count", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "spill_bytes", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stream_txns", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stream_count", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stream_bytes", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 8, "total_txns", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 9, "total_bytes", + INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 10, "stats_reset", + TIMESTAMPTZOID, -1, 0); + BlessTupleDesc(tupdesc); + + namestrcpy(&slotname, text_to_cstring(slotname_text)); + slotent = pgstat_fetch_replslot(slotname); + if (!slotent) + { + /* + * If the slot is not found, initialise its stats. This is possible if + * the create slot message is lost. + */ + memset(&allzero, 0, sizeof(PgStat_StatReplSlotEntry)); + slotent = &allzero; + } + + values[0] = CStringGetTextDatum(NameStr(slotname)); + values[1] = Int64GetDatum(slotent->spill_txns); + values[2] = Int64GetDatum(slotent->spill_count); + values[3] = Int64GetDatum(slotent->spill_bytes); + values[4] = Int64GetDatum(slotent->stream_txns); + values[5] = Int64GetDatum(slotent->stream_count); + values[6] = Int64GetDatum(slotent->stream_bytes); + values[7] = Int64GetDatum(slotent->total_txns); + values[8] = Int64GetDatum(slotent->total_bytes); + + if (slotent->stat_reset_timestamp == 0) + nulls[9] = true; + else + values[9] = TimestampTzGetDatum(slotent->stat_reset_timestamp); + + /* Returns the record as Datum */ + PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); +} |