#include "access/genam.h"
#include "access/gin.h"
+#if PG_VERSION_NUM >= 90400
+#include "utils/snapmgr.h"
+#endif
#if PG_VERSION_NUM >= 90100
#include "access/gin_private.h"
#endif
static Relation
gist_index_open(RangeVar *relvar) {
-#if PG_VERSION_NUM <= 90100
+#if PG_VERSION_NUM < 90200
Oid relOid = RangeVarGetRelid(relvar, false);
#else
Oid relOid = RangeVarGetRelid(relvar, NoLock, false);
static Relation
gin_index_open(RangeVar *relvar) {
-#if PG_VERSION_NUM <= 90100
+#if PG_VERSION_NUM < 90200
Oid relOid = RangeVarGetRelid(relvar, false);
#else
Oid relOid = RangeVarGetRelid(relvar, NoLock, false);
if ( GinIsPostingTree(itup) ) {
BlockNumber rootblkno = GinGetPostingTree(itup);
+#if PG_VERSION_NUM >= 90400
+ GinBtreeData btree;
+ GinBtreeStack *stack;
+ ItemPointerData minItem;
+ int nlist;
+ ItemPointer list;
+#else
GinPostingTreeScan *gdi;
Buffer entrybuffer;
+#endif
Page page;
+ uint32 predictNumber;
LockBuffer(st->buffer, GIN_UNLOCK);
-#if PG_VERSION_NUM >= 90100
+#if PG_VERSION_NUM >= 90400
+ stack = ginScanBeginPostingTree(&btree, st->index, rootblkno);
+ page = BufferGetPage(stack->buffer);
+ ItemPointerSetMin(&minItem);
+ list = GinDataLeafPageGetItems(page, &nlist, minItem);
+ pfree(list);
+ predictNumber = stack->predictNumber;
+#elif PG_VERSION_NUM >= 90100
gdi = ginPrepareScanPostingTree(st->index, rootblkno, TRUE);
entrybuffer = ginScanBeginPostingTree(gdi);
+ page = BufferGetPage(entrybuffer);
+ predictNumber = gdi->stack->predictNumber;
#else
gdi = prepareScanPostingTree(st->index, rootblkno, TRUE);
entrybuffer = scanBeginPostingTree(gdi);
+ page = BufferGetPage(entrybuffer);
+ predictNumber = gdi->stack->predictNumber;
#endif
- page = BufferGetPage(entrybuffer);
- st->dvalues[1] = Int32GetDatum( gdi->stack->predictNumber * GinPageGetOpaque(page)->maxoff );
+ st->dvalues[1] = Int32GetDatum( predictNumber * GinPageGetOpaque(page)->maxoff );
+#if PG_VERSION_NUM < 90400
LockBuffer(entrybuffer, GIN_UNLOCK);
freeGinBtreeStack(gdi->stack);
pfree(gdi);
+#else
+ LockBuffer(stack->buffer, GIN_UNLOCK);
+ freeGinBtreeStack(stack);
+#endif
} else {
st->dvalues[1] = Int32GetDatum( GinGetNPosting(itup) );
LockBuffer(st->buffer, GIN_UNLOCK);
fmgr_info( F_TS_MATCH_VQ , &key.sk_func );
#if PG_VERSION_NUM >= 90100
+#if PG_VERSION_NUM >= 90400
+ scan = index_beginscan_bitmap(index, SnapshotSelf, 1);
+#else
scan = index_beginscan_bitmap(index, SnapshotNow, 1);
+#endif
index_rescan(scan, &key, 1, NULL, 0);
count = index_getbitmap(scan, bitmap);
leafPages = 0,
emptyPages = 0,
deletedPages = 0;
- double usedSpace = 0.0;
+ double usedSpace = 0.0,
+ usedLeafSpace = 0.0,
+ usedInnerSpace = 0.0;
char res[1024];
int bufferSize = -1;
int64 innerTuples = 0,
totalPages = RelationGetNumberOfBlocks(index);
- for (blkno = SPGIST_HEAD_BLKNO; blkno < totalPages; blkno++)
+ for (blkno = SPGIST_ROOT_BLKNO; blkno < totalPages; blkno++)
{
Buffer buffer;
Page page;
pageFree = PageGetExactFreeSpace(page);
usedSpace += bufferSize - pageFree;
+ if (SpGistPageIsLeaf(page))
+ usedLeafSpace += bufferSize - pageFree;
+ else
+ usedInnerSpace += bufferSize - pageFree;
if (pageFree == bufferSize)
emptyPages++;
"leafPages: %u\n"
"emptyPages: %u\n"
"usedSpace: %.2f kbytes\n"
+ "usedInnerSpace: %.2f kbytes\n"
+ "usedLeafSpace: %.2f kbytes\n"
"freeSpace: %.2f kbytes\n"
"fillRatio: %.2f%%\n"
"leafTuples: " INT64_FORMAT "\n"
"innerRedirects: " INT64_FORMAT,
totalPages, deletedPages, innerPages, leafPages, emptyPages,
usedSpace / 1024.0,
+ usedInnerSpace / 1024.0,
+ usedLeafSpace / 1024.0,
(((double) bufferSize) * ((double) totalPages) - usedSpace) / 1024,
100.0 * (usedSpace / (((double) bufferSize) * ((double) totalPages))),
leafTuples, innerTuples, nAllTheSame,
MemoryContextSwitchTo(oldcontext);
- ItemPointerSet(&ipd, SPGIST_HEAD_BLKNO, FirstOffsetNumber);
+ ItemPointerSet(&ipd, SPGIST_ROOT_BLKNO, FirstOffsetNumber);
prst->stack = NIL;
pushSPGistPrint(funcctx, prst, &ipd, 1);
*tid = node->t_tid;
prst->dvalues[3] = PointerGetDatum(tid);
prst->nulls[3] = ' ';
- if (prst->state.attPrefixType.attbyval != VOIDOID && innerTuple->prefixSize > 0) {
+ if (prst->state.attPrefixType.attbyval == false && innerTuple->prefixSize > 0) {
prst->dvalues[4] = datumCopy(SGITDATUM(innerTuple, &prst->state),
prst->state.attPrefixType.attbyval, prst->state.attPrefixType.attlen);
prst->nulls[4] = ' ';
} else
prst->nulls[4] = 'n';
- if (prst->state.attLabelType.attbyval != VOIDOID && !IndexTupleHasNulls(node)) {
+ if (prst->state.attLabelType.attbyval == false && !IndexTupleHasNulls(node)) {
prst->dvalues[5] = datumCopy(SGNTDATUM(node, &prst->state),
prst->state.attLabelType.attbyval, prst->state.attLabelType.attlen);
prst->nulls[5] = ' ';
#endif
}
+
+PG_FUNCTION_INFO_V1(gin_statpage);
+Datum gin_statpage(PG_FUNCTION_ARGS);
+Datum
+gin_statpage(PG_FUNCTION_ARGS)
+{
+#if PG_VERSION_NUM < 90400
+ elog(NOTICE, "Function is not working under PgSQL < 9.4");
+
+ PG_RETURN_TEXT_P(CStringGetTextDatum("???"));
+#else
+ text *name = PG_GETARG_TEXT_P(0);
+ RangeVar *relvar;
+ Relation index;
+ BlockNumber blkno;
+ char res[1024];
+ uint32 totalPages,
+ entryPages = 0,
+ dataPages = 0,
+ dataInnerPages = 0,
+ dataLeafPages = 0,
+ entryInnerPages = 0,
+ entryLeafPages = 0
+ ;
+ uint64 dataInnerFreeSpace = 0,
+ dataLeafFreeSpace = 0,
+ dataInnerTuplesCount = 0,
+ dataLeafIptrsCount = 0,
+ entryInnerFreeSpace = 0,
+ entryLeafFreeSpace = 0,
+ entryInnerTuplesCount = 0,
+ entryLeafTuplesCount = 0,
+ entryPostingSize = 0,
+ entryPostingCount = 0,
+ entryAttrSize = 0
+ ;
+
+ relvar = makeRangeVarFromNameList(textToQualifiedNameList(name));
+ index = relation_openrv(relvar, AccessExclusiveLock);
+
+ if (index->rd_rel->relkind != RELKIND_INDEX ||
+ index->rd_rel->relam != GIN_AM_OID)
+ elog(ERROR, "relation \"%s\" is not an SPGiST index",
+ RelationGetRelationName(index));
+
+ totalPages = RelationGetNumberOfBlocks(index);
+
+ for (blkno = GIN_ROOT_BLKNO; blkno < totalPages; blkno++)
+ {
+ Buffer buffer;
+ Page page;
+ PageHeader header;
+
+ buffer = ReadBuffer(index, blkno);
+ LockBuffer(buffer, BUFFER_LOCK_SHARE);
+
+ page = BufferGetPage(buffer);
+ header = (PageHeader)page;
+
+ if (GinPageIsData(page))
+ {
+ dataPages++;
+ if (GinPageIsLeaf(page))
+ {
+ ItemPointerData minItem;
+ int nlist;
+
+ dataLeafPages++;
+ dataLeafFreeSpace += header->pd_upper - header->pd_lower;
+ ItemPointerSetMin(&minItem);
+ pfree(GinDataLeafPageGetItems(page, &nlist, minItem));
+ dataLeafIptrsCount += nlist;
+ }
+ else
+ {
+ dataInnerPages++;
+ dataInnerFreeSpace += header->pd_upper - header->pd_lower;
+ dataInnerTuplesCount += GinPageGetOpaque(page)->maxoff;
+ }
+ }
+ else
+ {
+ IndexTuple itup;
+ OffsetNumber i, maxoff;
+
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ entryPages++;
+ if (GinPageIsLeaf(page))
+ {
+ entryLeafPages++;
+ entryLeafFreeSpace += header->pd_upper - header->pd_lower;
+ entryLeafTuplesCount += maxoff;
+ }
+ else
+ {
+ entryInnerPages++;
+ entryInnerFreeSpace += header->pd_upper - header->pd_lower;
+ entryInnerTuplesCount += maxoff;
+ }
+
+ for (i = 1; i <= maxoff; i++)
+ {
+ itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
+
+ if (GinPageIsLeaf(page))
+ {
+ GinPostingList *list = (GinPostingList *)GinGetPosting(itup);
+ entryPostingCount += GinGetNPosting(itup);
+ entryPostingSize += SizeOfGinPostingList(list);
+ entryAttrSize += GinGetPostingOffset(itup) - IndexInfoFindDataOffset((itup)->t_info);
+ }
+ else
+ {
+ entryAttrSize += IndexTupleSize(itup) - IndexInfoFindDataOffset((itup)->t_info);
+ }
+ }
+ }
+
+ UnlockReleaseBuffer(buffer);
+ }
+
+ index_close(index, AccessExclusiveLock);
+ totalPages--;
+
+ snprintf(res, sizeof(res),
+ "totalPages: %u\n"
+ "dataPages: %u\n"
+ "dataInnerPages: %u\n"
+ "dataLeafPages: %u\n"
+ "dataInnerFreeSpace: " INT64_FORMAT "\n"
+ "dataLeafFreeSpace: " INT64_FORMAT "\n"
+ "dataInnerTuplesCount: " INT64_FORMAT "\n"
+ "dataLeafIptrsCount: " INT64_FORMAT "\n"
+ "entryPages: %u\n"
+ "entryInnerPages: %u\n"
+ "entryLeafPages: %u\n"
+ "entryInnerFreeSpace: " INT64_FORMAT "\n"
+ "entryLeafFreeSpace: " INT64_FORMAT "\n"
+ "entryInnerTuplesCount: " INT64_FORMAT "\n"
+ "entryLeafTuplesCount: " INT64_FORMAT "\n"
+ "entryPostingSize: " INT64_FORMAT "\n"
+ "entryPostingCount: " INT64_FORMAT "\n"
+ "entryAttrSize: " INT64_FORMAT "\n"
+ ,
+ totalPages,
+ dataPages,
+ dataInnerPages,
+ dataLeafPages,
+ dataInnerFreeSpace,
+ dataLeafFreeSpace,
+ dataInnerTuplesCount,
+ dataLeafIptrsCount,
+ entryPages,
+ entryInnerPages,
+ entryLeafPages,
+ entryInnerFreeSpace,
+ entryLeafFreeSpace,
+ entryInnerTuplesCount,
+ entryLeafTuplesCount,
+ entryPostingSize,
+ entryPostingCount,
+ entryAttrSize
+ );
+
+ PG_RETURN_TEXT_P(CStringGetTextDatum(res));
+#endif
+}
+