#include "postgres.h"
#include "access/gin_private.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "catalog/namespace.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "utils/builtins.h"
#include "utils/rel.h"
Go to the source code of this file.
Data Structures | |
struct | BTIndexStat |
struct | GinIndexStat |
Defines | |
#define | IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX) |
#define | IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID) |
#define | IS_GIN(r) ((r)->rd_rel->relam == GIN_AM_OID) |
#define | CHECK_PAGE_OFFSET_RANGE(pg, offnum) |
#define | CHECK_RELATION_BLOCK_RANGE(rel, blkno) |
Typedefs | |
typedef struct BTIndexStat | BTIndexStat |
typedef struct GinIndexStat | GinIndexStat |
Functions | |
Datum | pgstatindex (PG_FUNCTION_ARGS) |
Datum | pg_relpages (PG_FUNCTION_ARGS) |
Datum | pgstatginindex (PG_FUNCTION_ARGS) |
PG_FUNCTION_INFO_V1 (pgstatindex) | |
PG_FUNCTION_INFO_V1 (pg_relpages) | |
PG_FUNCTION_INFO_V1 (pgstatginindex) |
#define CHECK_PAGE_OFFSET_RANGE | ( | pg, | ||
offnum | ||||
) |
{ \ if ( !(FirstOffsetNumber <= (offnum) && \ (offnum) <= PageGetMaxOffsetNumber(pg)) ) \ elog(ERROR, "page offset number out of range"); }
Definition at line 54 of file pgstatindex.c.
#define CHECK_RELATION_BLOCK_RANGE | ( | rel, | ||
blkno | ||||
) |
{ \ if ( RelationGetNumberOfBlocks(rel) <= (BlockNumber) (blkno) ) \ elog(ERROR, "block number out of range"); }
Definition at line 60 of file pgstatindex.c.
#define IS_BTREE | ( | r | ) | ((r)->rd_rel->relam == BTREE_AM_OID) |
Definition at line 51 of file pgstatindex.c.
Referenced by pgstatindex().
#define IS_GIN | ( | r | ) | ((r)->rd_rel->relam == GIN_AM_OID) |
Definition at line 52 of file pgstatindex.c.
Referenced by pgstatginindex().
#define IS_INDEX | ( | r | ) | ((r)->rd_rel->relkind == RELKIND_INDEX) |
Definition at line 50 of file pgstatindex.c.
Referenced by pgstatginindex(), and pgstatindex().
typedef struct BTIndexStat BTIndexStat |
typedef struct GinIndexStat GinIndexStat |
PG_FUNCTION_INFO_V1 | ( | pgstatindex | ) |
PG_FUNCTION_INFO_V1 | ( | pg_relpages | ) |
PG_FUNCTION_INFO_V1 | ( | pgstatginindex | ) |
Datum pg_relpages | ( | PG_FUNCTION_ARGS | ) |
Definition at line 290 of file pgstatindex.c.
References AccessShareLock, ereport, errcode(), errmsg(), ERROR, makeRangeVarFromNameList(), PG_GETARG_TEXT_P, PG_RETURN_INT64, relation_close(), relation_openrv(), RelationGetNumberOfBlocks, superuser(), and textToQualifiedNameList().
{ text *relname = PG_GETARG_TEXT_P(0); int64 relpages; Relation rel; RangeVar *relrv; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); /* note: this will work OK on non-local temp tables */ relpages = RelationGetNumberOfBlocks(rel); relation_close(rel, AccessShareLock); PG_RETURN_INT64(relpages); }
Datum pgstatginindex | ( | PG_FUNCTION_ARGS | ) |
Definition at line 321 of file pgstatindex.c.
References AccessShareLock, BufferGetPage, elog, ereport, errcode(), errmsg(), ERROR, get_call_result_type(), GIN_METAPAGE_BLKNO, GIN_SHARE, GinPageGetMeta, GinMetaPageData::ginVersion, heap_form_tuple(), HeapTupleGetDatum, Int32GetDatum, Int64GetDatum(), IS_GIN, IS_INDEX, LockBuffer(), GinMetaPageData::nPendingHeapTuples, GinMetaPageData::nPendingPages, NULL, GinIndexStat::pending_pages, GinIndexStat::pending_tuples, PG_GETARG_OID, PG_RETURN_DATUM, ReadBuffer(), relation_close(), RELATION_IS_OTHER_TEMP, relation_open(), RelationGetRelationName, superuser(), TYPEFUNC_COMPOSITE, UInt32GetDatum, UnlockReleaseBuffer(), values, and GinIndexStat::version.
{ Oid relid = PG_GETARG_OID(0); Relation rel; Buffer buffer; Page page; GinMetaPageData *metadata; GinIndexStat stats; HeapTuple tuple; TupleDesc tupleDesc; Datum values[3]; bool nulls[3] = {false, false, false}; Datum result; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); rel = relation_open(relid, AccessShareLock); if (!IS_INDEX(rel) || !IS_GIN(rel)) elog(ERROR, "relation \"%s\" is not a GIN index", RelationGetRelationName(rel)); /* * Reject attempts to read non-local temporary relations; we would be * likely to get wrong data since we have no visibility into the owning * session's local buffers. */ if (RELATION_IS_OTHER_TEMP(rel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary indexes of other sessions"))); /* * Read metapage */ buffer = ReadBuffer(rel, GIN_METAPAGE_BLKNO); LockBuffer(buffer, GIN_SHARE); page = BufferGetPage(buffer); metadata = GinPageGetMeta(page); stats.version = metadata->ginVersion; stats.pending_pages = metadata->nPendingPages; stats.pending_tuples = metadata->nPendingHeapTuples; UnlockReleaseBuffer(buffer); relation_close(rel, AccessShareLock); /* * Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); values[0] = Int32GetDatum(stats.version); values[1] = UInt32GetDatum(stats.pending_pages); values[2] = Int64GetDatum(stats.pending_tuples); /* * Build and return the tuple */ tuple = heap_form_tuple(tupleDesc, values, nulls); result = HeapTupleGetDatum(tuple); PG_RETURN_DATUM(result); }
Datum pgstatindex | ( | PG_FUNCTION_ARGS | ) |
Definition at line 107 of file pgstatindex.c.
References AccessShareLock, BAS_BULKREAD, BTMetaPageData::btm_level, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTPageGetMeta, BTPageOpaqueData::btpo_next, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, BuildTupleFromCStrings(), CHECK_FOR_INTERRUPTS, BTIndexStat::deleted_pages, elog, BTIndexStat::empty_pages, ereport, errcode(), errmsg(), ERROR, BTIndexStat::fragments, BTIndexStat::free_space, get_call_result_type(), GetAccessStrategy(), HeapTupleGetDatum, BTIndexStat::internal_pages, IS_BTREE, IS_INDEX, BTIndexStat::leaf_pages, BTIndexStat::level, LockBuffer(), MAIN_FORKNUM, makeRangeVarFromNameList(), BTIndexStat::max_avail, NULL, P_IGNORE, P_ISDELETED, P_ISLEAF, P_ISROOT, P_NONE, PageGetFreeSpace(), PageGetSpecialPointer, palloc(), PG_GETARG_TEXT_P, PG_RETURN_DATUM, RBM_NORMAL, ReadBufferExtended(), relation_close(), RELATION_IS_OTHER_TEMP, relation_openrv(), RelationGetNumberOfBlocks, RelationGetRelationName, ReleaseBuffer(), BTIndexStat::root_blkno, BTIndexStat::root_pages, snprintf(), superuser(), textToQualifiedNameList(), TupleDescGetAttInMetadata(), TYPEFUNC_COMPOSITE, values, and BTIndexStat::version.
{ text *relname = PG_GETARG_TEXT_P(0); Relation rel; RangeVar *relrv; Datum result; BlockNumber nblocks; BlockNumber blkno; BTIndexStat indexStat; BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD); if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to use pgstattuple functions")))); relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); rel = relation_openrv(relrv, AccessShareLock); if (!IS_INDEX(rel) || !IS_BTREE(rel)) elog(ERROR, "relation \"%s\" is not a btree index", RelationGetRelationName(rel)); /* * Reject attempts to read non-local temporary relations; we would be * likely to get wrong data since we have no visibility into the owning * session's local buffers. */ if (RELATION_IS_OTHER_TEMP(rel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot access temporary tables of other sessions"))); /* * Read metapage */ { Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL, bstrategy); Page page = BufferGetPage(buffer); BTMetaPageData *metad = BTPageGetMeta(page); indexStat.version = metad->btm_version; indexStat.level = metad->btm_level; indexStat.root_blkno = metad->btm_root; ReleaseBuffer(buffer); } /* -- init counters -- */ indexStat.root_pages = 0; indexStat.internal_pages = 0; indexStat.leaf_pages = 0; indexStat.empty_pages = 0; indexStat.deleted_pages = 0; indexStat.max_avail = 0; indexStat.free_space = 0; indexStat.fragments = 0; /* * Scan all blocks except the metapage */ nblocks = RelationGetNumberOfBlocks(rel); for (blkno = 1; blkno < nblocks; blkno++) { Buffer buffer; Page page; BTPageOpaque opaque; CHECK_FOR_INTERRUPTS(); /* Read and lock buffer */ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy); LockBuffer(buffer, BUFFER_LOCK_SHARE); page = BufferGetPage(buffer); opaque = (BTPageOpaque) PageGetSpecialPointer(page); /* Determine page type, and update totals */ if (P_ISLEAF(opaque)) { int max_avail; max_avail = BLCKSZ - (BLCKSZ - ((PageHeader) page)->pd_special + SizeOfPageHeaderData); indexStat.max_avail += max_avail; indexStat.free_space += PageGetFreeSpace(page); indexStat.leaf_pages++; /* * If the next leaf is on an earlier block, it means a * fragmentation. */ if (opaque->btpo_next != P_NONE && opaque->btpo_next < blkno) indexStat.fragments++; } else if (P_ISDELETED(opaque)) indexStat.deleted_pages++; else if (P_IGNORE(opaque)) indexStat.empty_pages++; else if (P_ISROOT(opaque)) indexStat.root_pages++; else indexStat.internal_pages++; /* Unlock and release buffer */ LockBuffer(buffer, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buffer); } relation_close(rel, AccessShareLock); /*---------------------------- * Build a result tuple *---------------------------- */ { TupleDesc tupleDesc; int j; char *values[10]; HeapTuple tuple; /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); j = 0; values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.version); values[j] = palloc(32); snprintf(values[j++], 32, "%d", indexStat.level); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, (indexStat.root_pages + indexStat.leaf_pages + indexStat.internal_pages + indexStat.deleted_pages + indexStat.empty_pages) * BLCKSZ); values[j] = palloc(32); snprintf(values[j++], 32, "%u", indexStat.root_blkno); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, indexStat.internal_pages); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, indexStat.leaf_pages); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, indexStat.empty_pages); values[j] = palloc(32); snprintf(values[j++], 32, INT64_FORMAT, indexStat.deleted_pages); values[j] = palloc(32); if (indexStat.max_avail > 0) snprintf(values[j++], 32, "%.2f", 100.0 - (double) indexStat.free_space / (double) indexStat.max_avail * 100.0); else snprintf(values[j++], 32, "NaN"); values[j] = palloc(32); if (indexStat.leaf_pages > 0) snprintf(values[j++], 32, "%.2f", (double) indexStat.fragments / (double) indexStat.leaf_pages * 100.0); else snprintf(values[j++], 32, "NaN"); tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc), values); result = HeapTupleGetDatum(tuple); } PG_RETURN_DATUM(result); }