HeapTuple tuple; char *values[NCOLUMNS]; char values_buf[NCOLUMNS][NCHARS]; int i; double tuple_percent; double dead_tuple_percent; double free_percent; /* free/reusable space in % */
TupleDesc tupdesc;
AttInMetadata *attinmeta;
/* 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");
/* *Rejectattemptstoreadnon-localtemporaryrelations;wewouldbe *likelytogetwrongdatasincewehavenovisibilityintotheowning *session'slocalbuffers.
*/ if (RELATION_IS_OTHER_TEMP(rel))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot access temporary tables of other sessions")));
if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) ||
rel->rd_rel->relkind == RELKIND_SEQUENCE)
{ return pgstat_heap(rel, fcinfo);
} elseif (rel->rd_rel->relkind == RELKIND_INDEX)
{ /* see pgstatindex_impl */ if (!rel->rd_index->indisvalid)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("index \"%s\" is not valid",
RelationGetRelationName(rel))));
switch (rel->rd_rel->relam)
{ case BTREE_AM_OID: return pgstat_index(rel, BTREE_METAPAGE + 1,
pgstat_btree_page, fcinfo); case HASH_AM_OID: return pgstat_index(rel, HASH_METAPAGE + 1,
pgstat_hash_page, fcinfo); case GIST_AM_OID: return pgstat_index(rel, GIST_ROOT_BLKNO + 1,
pgstat_gist_page, fcinfo); case GIN_AM_OID:
err = "gin index"; break; case SPGIST_AM_OID:
err = "spgist index"; break; case BRIN_AM_OID:
err = "brin index"; break; default:
err = "unknown index"; break;
}
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("index \"%s\" (%s) is not supported",
RelationGetRelationName(rel), err)));
} else
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot get tuple-level statistics for relation \"%s\"",
RelationGetRelationName(rel)),
errdetail_relkind_not_supported(rel->rd_rel->relkind)));
}
return0; /* should not happen */
}
/* *pgstat_heap--returnslive/deadtuplesinfoinaheap
*/ static Datum
pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
{
TableScanDesc scan;
HeapScanDesc hscan;
HeapTuple tuple;
BlockNumber nblocks;
BlockNumber block = 0; /* next block to count free space in */
BlockNumber tupblock;
Buffer buffer;
pgstattuple_type stat = {0};
SnapshotData SnapshotDirty;
/* *SequencesalwaysuseheapAM,buttheydon'tshowthatinthecatalogs.
*/ if (rel->rd_rel->relkind != RELKIND_SEQUENCE &&
rel->rd_rel->relam != HEAP_TABLE_AM_OID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("only heap AM is supported")));
/* Disable syncscan because we assume we scan from block zero upwards */
scan = table_beginscan_strat(rel, SnapshotAny, 0, NULL, true, false);
hscan = (HeapScanDesc) scan;
InitDirtySnapshot(SnapshotDirty);
nblocks = hscan->rs_nblocks; /* # blocks to be scanned */
/* scan the relation */ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
CHECK_FOR_INTERRUPTS();
/* must hold a buffer lock to call HeapTupleSatisfiesVisibility */
LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
/* Page is valid, see what to do with it */ if (PageIsNew(page))
{ /* fully empty page */
stat->free_space += BLCKSZ;
} elseif (PageGetSpecialSize(page) == MAXALIGN(sizeof(BTPageOpaqueData)))
{
BTPageOpaque opaque;
/* prepare access strategy for this index */
bstrategy = GetAccessStrategy(BAS_BULKREAD);
blkno = start; for (;;)
{ /* Get the current relation length */
LockRelationForExtension(rel, ExclusiveLock);
nblocks = RelationGetNumberOfBlocks(rel);
UnlockRelationForExtension(rel, ExclusiveLock);
/* Quit if we've scanned the whole relation */ if (blkno >= nblocks)
{
stat.table_len = (uint64) nblocks * BLCKSZ;
break;
}
for (; blkno < nblocks; blkno++)
{
CHECK_FOR_INTERRUPTS();