PostgreSQL Source Code  git master
btreefuncs.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "access/relation.h"
#include "catalog/namespace.h"
#include "catalog/pg_am.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "pageinspect.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/rel.h"
#include "utils/varlena.h"
Include dependency graph for btreefuncs.c:

Go to the source code of this file.

Data Structures

struct  BTPageStat
 
struct  user_args
 

Macros

#define IS_INDEX(r)   ((r)->rd_rel->relkind == RELKIND_INDEX)
 
#define IS_BTREE(r)   ((r)->rd_rel->relam == BTREE_AM_OID)
 
#define DatumGetItemPointer(X)   ((ItemPointer) DatumGetPointer(X))
 
#define ItemPointerGetDatum(X)   PointerGetDatum(X)
 
#define CHECK_RELATION_BLOCK_RANGE(rel, blkno)
 
#define BT_METAP_COLS_V1_8   9
 

Typedefs

typedef struct BTPageStat BTPageStat
 

Functions

 PG_FUNCTION_INFO_V1 (bt_metap)
 
 PG_FUNCTION_INFO_V1 (bt_page_items_1_9)
 
 PG_FUNCTION_INFO_V1 (bt_page_items)
 
 PG_FUNCTION_INFO_V1 (bt_page_items_bytea)
 
 PG_FUNCTION_INFO_V1 (bt_page_stats_1_9)
 
 PG_FUNCTION_INFO_V1 (bt_page_stats)
 
static void GetBTPageStatistics (BlockNumber blkno, Buffer buffer, BTPageStat *stat)
 
static Datum bt_page_stats_internal (PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 
Datum bt_page_stats_1_9 (PG_FUNCTION_ARGS)
 
Datum bt_page_stats (PG_FUNCTION_ARGS)
 
static Datum bt_page_print_tuples (struct user_args *uargs)
 
static Datum bt_page_items_internal (PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
 
Datum bt_page_items_1_9 (PG_FUNCTION_ARGS)
 
Datum bt_page_items (PG_FUNCTION_ARGS)
 
Datum bt_page_items_bytea (PG_FUNCTION_ARGS)
 
Datum bt_metap (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ BT_METAP_COLS_V1_8

#define BT_METAP_COLS_V1_8   9

Definition at line 679 of file btreefuncs.c.

◆ CHECK_RELATION_BLOCK_RANGE

#define CHECK_RELATION_BLOCK_RANGE (   rel,
  blkno 
)
Value:
{ \
if ( RelationGetNumberOfBlocks(rel) <= (BlockNumber) (blkno) ) \
elog(ERROR, "block number out of range"); }
uint32 BlockNumber
Definition: block.h:31
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:156
#define ERROR
Definition: elog.h:39

Definition at line 56 of file btreefuncs.c.

◆ DatumGetItemPointer

#define DatumGetItemPointer (   X)    ((ItemPointer) DatumGetPointer(X))

Definition at line 52 of file btreefuncs.c.

◆ IS_BTREE

#define IS_BTREE (   r)    ((r)->rd_rel->relam == BTREE_AM_OID)

Definition at line 51 of file btreefuncs.c.

◆ IS_INDEX

#define IS_INDEX (   r)    ((r)->rd_rel->relkind == RELKIND_INDEX)

Definition at line 50 of file btreefuncs.c.

◆ ItemPointerGetDatum

#define ItemPointerGetDatum (   X)    PointerGetDatum(X)

Definition at line 53 of file btreefuncs.c.

Typedef Documentation

◆ BTPageStat

typedef struct BTPageStat BTPageStat

Function Documentation

◆ bt_metap()

Datum bt_metap ( PG_FUNCTION_ARGS  )

Definition at line 690 of file btreefuncs.c.

691 {
693  Datum result;
694  Relation rel;
695  RangeVar *relrv;
696  BTMetaPageData *metad;
697  TupleDesc tupleDesc;
698  int j;
699  char *values[9];
700  Buffer buffer;
701  Page page;
702  HeapTuple tuple;
703 
704  if (!superuser())
705  ereport(ERROR,
706  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
707  errmsg("must be superuser to use pageinspect functions")));
708 
710  rel = relation_openrv(relrv, AccessShareLock);
711 
712  if (!IS_INDEX(rel) || !IS_BTREE(rel))
713  ereport(ERROR,
714  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
715  errmsg("\"%s\" is not a %s index",
716  RelationGetRelationName(rel), "btree")));
717 
718  /*
719  * Reject attempts to read non-local temporary relations; we would be
720  * likely to get wrong data since we have no visibility into the owning
721  * session's local buffers.
722  */
723  if (RELATION_IS_OTHER_TEMP(rel))
724  ereport(ERROR,
725  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
726  errmsg("cannot access temporary tables of other sessions")));
727 
728  buffer = ReadBuffer(rel, 0);
729  LockBuffer(buffer, BUFFER_LOCK_SHARE);
730 
731  page = BufferGetPage(buffer);
732  metad = BTPageGetMeta(page);
733 
734  /* Build a tuple descriptor for our result type */
735  if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
736  elog(ERROR, "return type must be a row type");
737 
738  /*
739  * We need a kluge here to detect API versions prior to 1.8. Earlier
740  * versions incorrectly used int4 for certain columns.
741  *
742  * There is no way to reliably avoid the problems created by the old
743  * function definition at this point, so insist that the user update the
744  * extension.
745  */
746  if (tupleDesc->natts < BT_METAP_COLS_V1_8)
747  ereport(ERROR,
748  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
749  errmsg("function has wrong number of declared columns"),
750  errhint("To resolve the problem, update the \"pageinspect\" extension to the latest version.")));
751 
752  j = 0;
753  values[j++] = psprintf("%d", metad->btm_magic);
754  values[j++] = psprintf("%d", metad->btm_version);
755  values[j++] = psprintf(INT64_FORMAT, (int64) metad->btm_root);
756  values[j++] = psprintf(INT64_FORMAT, (int64) metad->btm_level);
757  values[j++] = psprintf(INT64_FORMAT, (int64) metad->btm_fastroot);
758  values[j++] = psprintf(INT64_FORMAT, (int64) metad->btm_fastlevel);
759 
760  /*
761  * Get values of extended metadata if available, use default values
762  * otherwise. Note that we rely on the assumption that btm_allequalimage
763  * is initialized to zero with indexes that were built on versions prior
764  * to Postgres 13 (just like _bt_metaversion()).
765  */
766  if (metad->btm_version >= BTREE_NOVAC_VERSION)
767  {
769  (int64) metad->btm_last_cleanup_num_delpages);
771  values[j++] = metad->btm_allequalimage ? "t" : "f";
772  }
773  else
774  {
775  values[j++] = "0";
776  values[j++] = "-1";
777  values[j++] = "f";
778  }
779 
781  values);
782 
783  result = HeapTupleGetDatum(tuple);
784 
785  UnlockReleaseBuffer(buffer);
787 
788  PG_RETURN_DATUM(result);
789 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define IS_BTREE(r)
Definition: btreefuncs.c:51
#define BT_METAP_COLS_V1_8
Definition: btreefuncs.c:679
#define IS_INDEX(r)
Definition: btreefuncs.c:50
int Buffer
Definition: buf.h:23
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3954
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4172
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:712
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:106
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:280
Pointer Page
Definition: bufpage.h:78
#define INT64_FORMAT
Definition: c.h:484
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2135
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2086
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
int j
Definition: isn.c:74
#define AccessShareLock
Definition: lockdefs.h:36
RangeVar * makeRangeVarFromNameList(List *names)
Definition: namespace.c:3105
#define BTPageGetMeta(p)
Definition: nbtree.h:121
#define BTREE_NOVAC_VERSION
Definition: nbtree.h:152
NameData relname
Definition: pg_class.h:38
uintptr_t Datum
Definition: postgres.h:412
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define RelationGetRelationName(relation)
Definition: rel.h:535
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:656
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: relation.c:138
uint32 btm_last_cleanup_num_delpages
Definition: nbtree.h:114
uint32 btm_level
Definition: nbtree.h:108
float8 btm_last_cleanup_num_heap_tuples
Definition: nbtree.h:116
BlockNumber btm_fastroot
Definition: nbtree.h:109
uint32 btm_version
Definition: nbtree.h:106
uint32 btm_magic
Definition: nbtree.h:105
BlockNumber btm_root
Definition: nbtree.h:107
bool btm_allequalimage
Definition: nbtree.h:118
uint32 btm_fastlevel
Definition: nbtree.h:110
Definition: c.h:623
bool superuser(void)
Definition: superuser.c:46
List * textToQualifiedNameList(text *textval)
Definition: varlena.c:3654

References AccessShareLock, BT_METAP_COLS_V1_8, BTMetaPageData::btm_allequalimage, BTMetaPageData::btm_fastlevel, BTMetaPageData::btm_fastroot, BTMetaPageData::btm_last_cleanup_num_delpages, BTMetaPageData::btm_last_cleanup_num_heap_tuples, BTMetaPageData::btm_level, BTMetaPageData::btm_magic, BTMetaPageData::btm_root, BTMetaPageData::btm_version, BTPageGetMeta, BTREE_NOVAC_VERSION, BUFFER_LOCK_SHARE, BufferGetPage(), BuildTupleFromCStrings(), elog(), ereport, errcode(), errhint(), errmsg(), ERROR, get_call_result_type(), HeapTupleGetDatum(), INT64_FORMAT, IS_BTREE, IS_INDEX, j, LockBuffer(), makeRangeVarFromNameList(), TupleDescData::natts, user_args::page, PG_GETARG_TEXT_PP, PG_RETURN_DATUM, psprintf(), ReadBuffer(), relation_close(), RELATION_IS_OTHER_TEMP, relation_openrv(), RelationGetRelationName, relname, superuser(), textToQualifiedNameList(), TupleDescGetAttInMetadata(), TYPEFUNC_COMPOSITE, UnlockReleaseBuffer(), and values.

◆ bt_page_items()

Datum bt_page_items ( PG_FUNCTION_ARGS  )

Definition at line 570 of file btreefuncs.c.

571 {
573 }
static Datum bt_page_items_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
Definition: btreefuncs.c:449
@ PAGEINSPECT_V1_8
Definition: pageinspect.h:23

References bt_page_items_internal(), and PAGEINSPECT_V1_8.

◆ bt_page_items_1_9()

Datum bt_page_items_1_9 ( PG_FUNCTION_ARGS  )

Definition at line 563 of file btreefuncs.c.

564 {
566 }
@ PAGEINSPECT_V1_9
Definition: pageinspect.h:24

References bt_page_items_internal(), and PAGEINSPECT_V1_9.

◆ bt_page_items_bytea()

Datum bt_page_items_bytea ( PG_FUNCTION_ARGS  )

Definition at line 585 of file btreefuncs.c.

586 {
587  bytea *raw_page = PG_GETARG_BYTEA_P(0);
588  Datum result;
589  FuncCallContext *fctx;
590  struct user_args *uargs;
591 
592  if (!superuser())
593  ereport(ERROR,
594  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
595  errmsg("must be superuser to use raw page functions")));
596 
597  if (SRF_IS_FIRSTCALL())
598  {
599  BTPageOpaque opaque;
600  MemoryContext mctx;
601  TupleDesc tupleDesc;
602 
603  fctx = SRF_FIRSTCALL_INIT();
605 
606  uargs = palloc(sizeof(struct user_args));
607 
608  uargs->page = get_page_from_raw(raw_page);
609 
610  if (PageIsNew(uargs->page))
611  {
612  MemoryContextSwitchTo(mctx);
613  PG_RETURN_NULL();
614  }
615 
616  uargs->offset = FirstOffsetNumber;
617 
618  /* verify the special space has the expected size */
619  if (PageGetSpecialSize(uargs->page) != MAXALIGN(sizeof(BTPageOpaqueData)))
620  ereport(ERROR,
621  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
622  errmsg("input page is not a valid %s page", "btree"),
623  errdetail("Expected special size %d, got %d.",
624  (int) MAXALIGN(sizeof(BTPageOpaqueData)),
625  (int) PageGetSpecialSize(uargs->page))));
626 
627  opaque = BTPageGetOpaque(uargs->page);
628 
629  if (P_ISMETA(opaque))
630  ereport(ERROR,
631  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
632  errmsg("block is a meta page")));
633 
634  if (P_ISLEAF(opaque) && opaque->btpo_level != 0)
635  ereport(ERROR,
636  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
637  errmsg("block is not a valid btree leaf page")));
638 
639  if (P_ISDELETED(opaque))
640  elog(NOTICE, "page is deleted");
641 
642  if (!P_ISDELETED(opaque))
643  fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
644  else
645  {
646  /* Don't interpret BTDeletedPageData as index tuples */
647  elog(NOTICE, "page from block is deleted");
648  fctx->max_calls = 0;
649  }
650  uargs->leafpage = P_ISLEAF(opaque);
651  uargs->rightmost = P_RIGHTMOST(opaque);
652 
653  /* Build a tuple descriptor for our result type */
654  if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
655  elog(ERROR, "return type must be a row type");
656  tupleDesc = BlessTupleDesc(tupleDesc);
657 
658  uargs->tupd = tupleDesc;
659 
660  fctx->user_fctx = uargs;
661 
662  MemoryContextSwitchTo(mctx);
663  }
664 
665  fctx = SRF_PERCALL_SETUP();
666  uargs = fctx->user_fctx;
667 
668  if (fctx->call_cntr < fctx->max_calls)
669  {
670  result = bt_page_print_tuples(uargs);
671  uargs->offset++;
672  SRF_RETURN_NEXT(fctx, result);
673  }
674 
675  SRF_RETURN_DONE(fctx);
676 }
static Datum bt_page_print_tuples(struct user_args *uargs)
Definition: btreefuncs.c:306
static bool PageIsNew(Page page)
Definition: bufpage.h:230
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:369
static uint16 PageGetSpecialSize(Page page)
Definition: bufpage.h:313
#define MAXALIGN(LEN)
Definition: c.h:747
int errdetail(const char *fmt,...)
Definition: elog.c:1202
#define NOTICE
Definition: elog.h:35
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2071
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_BYTEA_P(n)
Definition: fmgr.h:335
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:303
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:307
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:305
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:327
void * palloc(Size size)
Definition: mcxt.c:1199
#define P_ISLEAF(opaque)
Definition: nbtree.h:220
#define P_ISMETA(opaque)
Definition: nbtree.h:223
#define BTPageGetOpaque(page)
Definition: nbtree.h:73
#define P_ISDELETED(opaque)
Definition: nbtree.h:222
#define P_RIGHTMOST(opaque)
Definition: nbtree.h:219
#define FirstOffsetNumber
Definition: off.h:27
Page get_page_from_raw(bytea *raw_page)
Definition: rawpage.c:215
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
uint32 btpo_level
Definition: nbtree.h:66
void * user_fctx
Definition: funcapi.h:82
uint64 max_calls
Definition: funcapi.h:74
uint64 call_cntr
Definition: funcapi.h:65
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
OffsetNumber offset
Definition: btreefuncs.c:293
TupleDesc tupd
Definition: btreefuncs.c:296
bool leafpage
Definition: btreefuncs.c:294
Page page
Definition: btreefuncs.c:292
bool rightmost
Definition: btreefuncs.c:295

References BlessTupleDesc(), bt_page_print_tuples(), BTPageGetOpaque, BTPageOpaqueData::btpo_level, FuncCallContext::call_cntr, elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, FirstOffsetNumber, get_call_result_type(), get_page_from_raw(), user_args::leafpage, FuncCallContext::max_calls, MAXALIGN, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, NOTICE, user_args::offset, P_ISDELETED, P_ISLEAF, P_ISMETA, P_RIGHTMOST, user_args::page, PageGetMaxOffsetNumber(), PageGetSpecialSize(), PageIsNew(), palloc(), PG_GETARG_BYTEA_P, PG_RETURN_NULL, user_args::rightmost, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, superuser(), user_args::tupd, TYPEFUNC_COMPOSITE, and FuncCallContext::user_fctx.

◆ bt_page_items_internal()

static Datum bt_page_items_internal ( PG_FUNCTION_ARGS  ,
enum pageinspect_version  ext_version 
)
static

Definition at line 449 of file btreefuncs.c.

450 {
452  int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1));
453  Datum result;
454  FuncCallContext *fctx;
455  MemoryContext mctx;
456  struct user_args *uargs;
457 
458  if (!superuser())
459  ereport(ERROR,
460  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
461  errmsg("must be superuser to use pageinspect functions")));
462 
463  if (SRF_IS_FIRSTCALL())
464  {
465  RangeVar *relrv;
466  Relation rel;
467  Buffer buffer;
468  BTPageOpaque opaque;
469  TupleDesc tupleDesc;
470 
471  fctx = SRF_FIRSTCALL_INIT();
472 
474  rel = relation_openrv(relrv, AccessShareLock);
475 
476  if (!IS_INDEX(rel) || !IS_BTREE(rel))
477  ereport(ERROR,
478  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
479  errmsg("\"%s\" is not a %s index",
480  RelationGetRelationName(rel), "btree")));
481 
482  /*
483  * Reject attempts to read non-local temporary relations; we would be
484  * likely to get wrong data since we have no visibility into the
485  * owning session's local buffers.
486  */
487  if (RELATION_IS_OTHER_TEMP(rel))
488  ereport(ERROR,
489  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
490  errmsg("cannot access temporary tables of other sessions")));
491 
492  if (blkno < 0 || blkno > MaxBlockNumber)
493  ereport(ERROR,
494  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
495  errmsg("invalid block number")));
496 
497  if (blkno == 0)
498  ereport(ERROR,
499  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
500  errmsg("block 0 is a meta page")));
501 
502  CHECK_RELATION_BLOCK_RANGE(rel, blkno);
503 
504  buffer = ReadBuffer(rel, blkno);
505  LockBuffer(buffer, BUFFER_LOCK_SHARE);
506 
507  /*
508  * We copy the page into local storage to avoid holding pin on the
509  * buffer longer than we must, and possibly failing to release it at
510  * all if the calling query doesn't fetch all rows.
511  */
513 
514  uargs = palloc(sizeof(struct user_args));
515 
516  uargs->page = palloc(BLCKSZ);
517  memcpy(uargs->page, BufferGetPage(buffer), BLCKSZ);
518 
519  UnlockReleaseBuffer(buffer);
521 
522  uargs->offset = FirstOffsetNumber;
523 
524  opaque = BTPageGetOpaque(uargs->page);
525 
526  if (!P_ISDELETED(opaque))
527  fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
528  else
529  {
530  /* Don't interpret BTDeletedPageData as index tuples */
531  elog(NOTICE, "page from block " INT64_FORMAT " is deleted", blkno);
532  fctx->max_calls = 0;
533  }
534  uargs->leafpage = P_ISLEAF(opaque);
535  uargs->rightmost = P_RIGHTMOST(opaque);
536 
537  /* Build a tuple descriptor for our result type */
538  if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
539  elog(ERROR, "return type must be a row type");
540  tupleDesc = BlessTupleDesc(tupleDesc);
541 
542  uargs->tupd = tupleDesc;
543 
544  fctx->user_fctx = uargs;
545 
546  MemoryContextSwitchTo(mctx);
547  }
548 
549  fctx = SRF_PERCALL_SETUP();
550  uargs = fctx->user_fctx;
551 
552  if (fctx->call_cntr < fctx->max_calls)
553  {
554  result = bt_page_print_tuples(uargs);
555  uargs->offset++;
556  SRF_RETURN_NEXT(fctx, result);
557  }
558 
559  SRF_RETURN_DONE(fctx);
560 }
#define MaxBlockNumber
Definition: block.h:35
#define CHECK_RELATION_BLOCK_RANGE(rel, blkno)
Definition: btreefuncs.c:56
#define PG_GETARG_UINT32(n)
Definition: fmgr.h:270
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283

References AccessShareLock, BlessTupleDesc(), bt_page_print_tuples(), BTPageGetOpaque, BUFFER_LOCK_SHARE, BufferGetPage(), FuncCallContext::call_cntr, CHECK_RELATION_BLOCK_RANGE, elog(), ereport, errcode(), errmsg(), ERROR, FirstOffsetNumber, get_call_result_type(), INT64_FORMAT, IS_BTREE, IS_INDEX, user_args::leafpage, LockBuffer(), makeRangeVarFromNameList(), FuncCallContext::max_calls, MaxBlockNumber, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, NOTICE, user_args::offset, P_ISDELETED, P_ISLEAF, P_RIGHTMOST, user_args::page, PageGetMaxOffsetNumber(), PAGEINSPECT_V1_8, palloc(), PG_GETARG_INT64, PG_GETARG_TEXT_PP, PG_GETARG_UINT32, ReadBuffer(), relation_close(), RELATION_IS_OTHER_TEMP, relation_openrv(), RelationGetRelationName, relname, user_args::rightmost, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, superuser(), textToQualifiedNameList(), user_args::tupd, TYPEFUNC_COMPOSITE, UnlockReleaseBuffer(), and FuncCallContext::user_fctx.

Referenced by bt_page_items(), and bt_page_items_1_9().

◆ bt_page_print_tuples()

static Datum bt_page_print_tuples ( struct user_args uargs)
static

Definition at line 306 of file btreefuncs.c.

307 {
308  Page page = uargs->page;
309  OffsetNumber offset = uargs->offset;
310  bool leafpage = uargs->leafpage;
311  bool rightmost = uargs->rightmost;
312  bool ispivottuple;
313  Datum values[9];
314  bool nulls[9];
315  HeapTuple tuple;
316  ItemId id;
317  IndexTuple itup;
318  int j;
319  int off;
320  int dlen;
321  char *dump,
322  *datacstring;
323  char *ptr;
324  ItemPointer htid;
325 
326  id = PageGetItemId(page, offset);
327 
328  if (!ItemIdIsValid(id))
329  elog(ERROR, "invalid ItemId");
330 
331  itup = (IndexTuple) PageGetItem(page, id);
332 
333  j = 0;
334  memset(nulls, 0, sizeof(nulls));
335  values[j++] = DatumGetInt16(offset);
336  values[j++] = ItemPointerGetDatum(&itup->t_tid);
337  values[j++] = Int32GetDatum((int) IndexTupleSize(itup));
340 
341  ptr = (char *) itup + IndexInfoFindDataOffset(itup->t_info);
342  dlen = IndexTupleSize(itup) - IndexInfoFindDataOffset(itup->t_info);
343 
344  /*
345  * Make sure that "data" column does not include posting list or pivot
346  * tuple representation of heap TID(s).
347  *
348  * Note: BTreeTupleIsPivot() won't work reliably on !heapkeyspace indexes
349  * (those built before BTREE_VERSION 4), but we have no way of determining
350  * if this page came from a !heapkeyspace index. We may only have a bytea
351  * nbtree page image to go on, so in general there is no metapage that we
352  * can check.
353  *
354  * That's okay here because BTreeTupleIsPivot() can only return false for
355  * a !heapkeyspace pivot, never true for a !heapkeyspace non-pivot. Since
356  * heap TID isn't part of the keyspace in a !heapkeyspace index anyway,
357  * there cannot possibly be a pivot tuple heap TID representation that we
358  * fail to make an adjustment for. A !heapkeyspace index can have
359  * BTreeTupleIsPivot() return true (due to things like suffix truncation
360  * for INCLUDE indexes in Postgres v11), but when that happens
361  * BTreeTupleGetHeapTID() can be trusted to work reliably (i.e. return
362  * NULL).
363  *
364  * Note: BTreeTupleIsPosting() always works reliably, even with
365  * !heapkeyspace indexes.
366  */
367  if (BTreeTupleIsPosting(itup))
368  dlen -= IndexTupleSize(itup) - BTreeTupleGetPostingOffset(itup);
369  else if (BTreeTupleIsPivot(itup) && BTreeTupleGetHeapTID(itup) != NULL)
370  dlen -= MAXALIGN(sizeof(ItemPointerData));
371 
372  if (dlen < 0 || dlen > INDEX_SIZE_MASK)
373  elog(ERROR, "invalid tuple length %d for tuple at offset number %u",
374  dlen, offset);
375  dump = palloc0(dlen * 3 + 1);
376  datacstring = dump;
377  for (off = 0; off < dlen; off++)
378  {
379  if (off > 0)
380  *dump++ = ' ';
381  sprintf(dump, "%02x", *(ptr + off) & 0xff);
382  dump += 2;
383  }
384  values[j++] = CStringGetTextDatum(datacstring);
385  pfree(datacstring);
386 
387  /*
388  * We need to work around the BTreeTupleIsPivot() !heapkeyspace limitation
389  * again. Deduce whether or not tuple must be a pivot tuple based on
390  * whether or not the page is a leaf page, as well as the page offset
391  * number of the tuple.
392  */
393  ispivottuple = (!leafpage || (!rightmost && offset == P_HIKEY));
394 
395  /* LP_DEAD bit can never be set for pivot tuples, so show a NULL there */
396  if (!ispivottuple)
397  values[j++] = BoolGetDatum(ItemIdIsDead(id));
398  else
399  {
400  Assert(!ItemIdIsDead(id));
401  nulls[j++] = true;
402  }
403 
404  htid = BTreeTupleGetHeapTID(itup);
405  if (ispivottuple && !BTreeTupleIsPivot(itup))
406  {
407  /* Don't show bogus heap TID in !heapkeyspace pivot tuple */
408  htid = NULL;
409  }
410 
411  if (htid)
412  values[j++] = ItemPointerGetDatum(htid);
413  else
414  nulls[j++] = true;
415 
416  if (BTreeTupleIsPosting(itup))
417  {
418  /* Build an array of item pointers */
419  ItemPointer tids;
420  Datum *tids_datum;
421  int nposting;
422 
423  tids = BTreeTupleGetPosting(itup);
424  nposting = BTreeTupleGetNPosting(itup);
425  tids_datum = (Datum *) palloc(nposting * sizeof(Datum));
426  for (int i = 0; i < nposting; i++)
427  tids_datum[i] = ItemPointerGetDatum(&tids[i]);
428  values[j++] = PointerGetDatum(construct_array_builtin(tids_datum, nposting, TIDOID));
429  pfree(tids_datum);
430  }
431  else
432  nulls[j++] = true;
433 
434  /* Build and return the result tuple */
435  tuple = heap_form_tuple(uargs->tupd, values, nulls);
436 
437  return HeapTupleGetDatum(tuple);
438 }
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3363
#define ItemPointerGetDatum(X)
Definition: btreefuncs.c:53
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
#define CStringGetTextDatum(s)
Definition: builtins.h:88
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
int i
Definition: isn.c:73
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
#define ItemIdIsValid(itemId)
Definition: itemid.h:86
#define IndexTupleHasVarwidths(itup)
Definition: itup.h:72
#define IndexTupleHasNulls(itup)
Definition: itup.h:71
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
static Size IndexInfoFindDataOffset(unsigned short t_info)
Definition: itup.h:98
#define INDEX_SIZE_MASK
Definition: itup.h:65
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1306
void * palloc0(Size size)
Definition: mcxt.c:1230
static uint16 BTreeTupleGetNPosting(IndexTuple posting)
Definition: nbtree.h:512
static bool BTreeTupleIsPivot(IndexTuple itup)
Definition: nbtree.h:474
#define P_HIKEY
Definition: nbtree.h:368
static ItemPointer BTreeTupleGetPosting(IndexTuple posting)
Definition: nbtree.h:531
static uint32 BTreeTupleGetPostingOffset(IndexTuple posting)
Definition: nbtree.h:523
static bool BTreeTupleIsPosting(IndexTuple itup)
Definition: nbtree.h:486
static ItemPointer BTreeTupleGetHeapTID(IndexTuple itup)
Definition: nbtree.h:632
uint16 OffsetNumber
Definition: off.h:24
#define sprintf
Definition: port.h:240
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
static Datum BoolGetDatum(bool X)
Definition: postgres.h:450
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:560
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:510
ItemPointerData t_tid
Definition: itup.h:37
unsigned short t_info
Definition: itup.h:49

References Assert(), BoolGetDatum(), BTreeTupleGetHeapTID(), BTreeTupleGetNPosting(), BTreeTupleGetPosting(), BTreeTupleGetPostingOffset(), BTreeTupleIsPivot(), BTreeTupleIsPosting(), construct_array_builtin(), CStringGetTextDatum, DatumGetInt16(), elog(), ERROR, heap_form_tuple(), HeapTupleGetDatum(), i, INDEX_SIZE_MASK, IndexInfoFindDataOffset(), IndexTupleHasNulls, IndexTupleHasVarwidths, IndexTupleSize, Int32GetDatum(), ItemIdIsDead, ItemIdIsValid, ItemPointerGetDatum, j, user_args::leafpage, MAXALIGN, user_args::offset, P_HIKEY, user_args::page, PageGetItem(), PageGetItemId(), palloc(), palloc0(), pfree(), PointerGetDatum(), user_args::rightmost, sprintf, IndexTupleData::t_info, IndexTupleData::t_tid, user_args::tupd, and values.

Referenced by bt_page_items_bytea(), and bt_page_items_internal().

◆ bt_page_stats()

Datum bt_page_stats ( PG_FUNCTION_ARGS  )

Definition at line 281 of file btreefuncs.c.

282 {
284 }
static Datum bt_page_stats_internal(PG_FUNCTION_ARGS, enum pageinspect_version ext_version)
Definition: btreefuncs.c:186

References bt_page_stats_internal(), and PAGEINSPECT_V1_8.

◆ bt_page_stats_1_9()

Datum bt_page_stats_1_9 ( PG_FUNCTION_ARGS  )

Definition at line 274 of file btreefuncs.c.

275 {
277 }

References bt_page_stats_internal(), and PAGEINSPECT_V1_9.

◆ bt_page_stats_internal()

static Datum bt_page_stats_internal ( PG_FUNCTION_ARGS  ,
enum pageinspect_version  ext_version 
)
static

Definition at line 186 of file btreefuncs.c.

187 {
189  int64 blkno = (ext_version == PAGEINSPECT_V1_8 ? PG_GETARG_UINT32(1) : PG_GETARG_INT64(1));
190  Buffer buffer;
191  Relation rel;
192  RangeVar *relrv;
193  Datum result;
194  HeapTuple tuple;
195  TupleDesc tupleDesc;
196  int j;
197  char *values[11];
199 
200  if (!superuser())
201  ereport(ERROR,
202  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
203  errmsg("must be superuser to use pageinspect functions")));
204 
206  rel = relation_openrv(relrv, AccessShareLock);
207 
208  if (!IS_INDEX(rel) || !IS_BTREE(rel))
209  ereport(ERROR,
210  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
211  errmsg("\"%s\" is not a %s index",
212  RelationGetRelationName(rel), "btree")));
213 
214  /*
215  * Reject attempts to read non-local temporary relations; we would be
216  * likely to get wrong data since we have no visibility into the owning
217  * session's local buffers.
218  */
219  if (RELATION_IS_OTHER_TEMP(rel))
220  ereport(ERROR,
221  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
222  errmsg("cannot access temporary tables of other sessions")));
223 
224  if (blkno < 0 || blkno > MaxBlockNumber)
225  ereport(ERROR,
226  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
227  errmsg("invalid block number")));
228 
229  if (blkno == 0)
230  ereport(ERROR,
231  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
232  errmsg("block 0 is a meta page")));
233 
234  CHECK_RELATION_BLOCK_RANGE(rel, blkno);
235 
236  buffer = ReadBuffer(rel, blkno);
237  LockBuffer(buffer, BUFFER_LOCK_SHARE);
238 
239  /* keep compiler quiet */
240  stat.btpo_prev = stat.btpo_next = InvalidBlockNumber;
241  stat.btpo_flags = stat.free_size = stat.avg_item_size = 0;
242 
243  GetBTPageStatistics(blkno, buffer, &stat);
244 
245  UnlockReleaseBuffer(buffer);
247 
248  /* Build a tuple descriptor for our result type */
249  if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
250  elog(ERROR, "return type must be a row type");
251 
252  j = 0;
253  values[j++] = psprintf("%u", stat.blkno);
254  values[j++] = psprintf("%c", stat.type);
255  values[j++] = psprintf("%u", stat.live_items);
256  values[j++] = psprintf("%u", stat.dead_items);
257  values[j++] = psprintf("%u", stat.avg_item_size);
258  values[j++] = psprintf("%u", stat.page_size);
259  values[j++] = psprintf("%u", stat.free_size);
260  values[j++] = psprintf("%u", stat.btpo_prev);
261  values[j++] = psprintf("%u", stat.btpo_next);
262  values[j++] = psprintf("%u", stat.btpo_level);
263  values[j++] = psprintf("%d", stat.btpo_flags);
264 
266  values);
267 
268  result = HeapTupleGetDatum(tuple);
269 
270  PG_RETURN_DATUM(result);
271 }
#define InvalidBlockNumber
Definition: block.h:33
static void GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat *stat)
Definition: btreefuncs.c:91
#define stat
Definition: win32_port.h:286

References AccessShareLock, BUFFER_LOCK_SHARE, BuildTupleFromCStrings(), CHECK_RELATION_BLOCK_RANGE, elog(), ereport, errcode(), errmsg(), ERROR, get_call_result_type(), GetBTPageStatistics(), HeapTupleGetDatum(), InvalidBlockNumber, IS_BTREE, IS_INDEX, j, LockBuffer(), makeRangeVarFromNameList(), MaxBlockNumber, PAGEINSPECT_V1_8, PG_GETARG_INT64, PG_GETARG_TEXT_PP, PG_GETARG_UINT32, PG_RETURN_DATUM, psprintf(), ReadBuffer(), relation_close(), RELATION_IS_OTHER_TEMP, relation_openrv(), RelationGetRelationName, relname, stat, superuser(), textToQualifiedNameList(), TupleDescGetAttInMetadata(), TYPEFUNC_COMPOSITE, UnlockReleaseBuffer(), and values.

Referenced by bt_page_stats(), and bt_page_stats_1_9().

◆ GetBTPageStatistics()

static void GetBTPageStatistics ( BlockNumber  blkno,
Buffer  buffer,
BTPageStat stat 
)
static

Definition at line 91 of file btreefuncs.c.

92 {
93  Page page = BufferGetPage(buffer);
94  PageHeader phdr = (PageHeader) page;
95  OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
96  BTPageOpaque opaque = BTPageGetOpaque(page);
97  int item_size = 0;
98  int off;
99 
100  stat->blkno = blkno;
101 
102  stat->max_avail = BLCKSZ - (BLCKSZ - phdr->pd_special + SizeOfPageHeaderData);
103 
104  stat->dead_items = stat->live_items = 0;
105 
106  stat->page_size = PageGetPageSize(page);
107 
108  /* page type (flags) */
109  if (P_ISDELETED(opaque))
110  {
111  /* We divide deleted pages into leaf ('d') or internal ('D') */
112  if (P_ISLEAF(opaque) || !P_HAS_FULLXID(opaque))
113  stat->type = 'd';
114  else
115  stat->type = 'D';
116 
117  /*
118  * Report safexid in a deleted page.
119  *
120  * Handle pg_upgrade'd deleted pages that used the previous safexid
121  * representation in btpo_level field (this used to be a union type
122  * called "bpto").
123  */
124  if (P_HAS_FULLXID(opaque))
125  {
126  FullTransactionId safexid = BTPageGetDeleteXid(page);
127 
128  elog(DEBUG2, "deleted page from block %u has safexid %u:%u",
129  blkno, EpochFromFullTransactionId(safexid),
130  XidFromFullTransactionId(safexid));
131  }
132  else
133  elog(DEBUG2, "deleted page from block %u has safexid %u",
134  blkno, opaque->btpo_level);
135 
136  /* Don't interpret BTDeletedPageData as index tuples */
137  maxoff = InvalidOffsetNumber;
138  }
139  else if (P_IGNORE(opaque))
140  stat->type = 'e';
141  else if (P_ISLEAF(opaque))
142  stat->type = 'l';
143  else if (P_ISROOT(opaque))
144  stat->type = 'r';
145  else
146  stat->type = 'i';
147 
148  /* btpage opaque data */
149  stat->btpo_prev = opaque->btpo_prev;
150  stat->btpo_next = opaque->btpo_next;
151  stat->btpo_level = opaque->btpo_level;
152  stat->btpo_flags = opaque->btpo_flags;
153  stat->btpo_cycleid = opaque->btpo_cycleid;
154 
155  /* count live and dead tuples, and free space */
156  for (off = FirstOffsetNumber; off <= maxoff; off++)
157  {
158  IndexTuple itup;
159 
160  ItemId id = PageGetItemId(page, off);
161 
162  itup = (IndexTuple) PageGetItem(page, id);
163 
164  item_size += IndexTupleSize(itup);
165 
166  if (!ItemIdIsDead(id))
167  stat->live_items++;
168  else
169  stat->dead_items++;
170  }
171  stat->free_size = PageGetFreeSpace(page);
172 
173  if ((stat->live_items + stat->dead_items) > 0)
174  stat->avg_item_size = item_size / (stat->live_items + stat->dead_items);
175  else
176  stat->avg_item_size = 0;
177 }
Size PageGetFreeSpace(Page page)
Definition: bufpage.c:907
PageHeaderData * PageHeader
Definition: bufpage.h:170
static Size PageGetPageSize(Page page)
Definition: bufpage.h:273
#define SizeOfPageHeaderData
Definition: bufpage.h:213
#define DEBUG2
Definition: elog.h:29
#define P_HAS_FULLXID(opaque)
Definition: nbtree.h:228
static FullTransactionId BTPageGetDeleteXid(Page page)
Definition: nbtree.h:260
#define P_ISROOT(opaque)
Definition: nbtree.h:221
#define P_IGNORE(opaque)
Definition: nbtree.h:225
#define InvalidOffsetNumber
Definition: off.h:26
BlockNumber btpo_next
Definition: nbtree.h:65
BlockNumber btpo_prev
Definition: nbtree.h:64
uint16 btpo_flags
Definition: nbtree.h:67
BTCycleId btpo_cycleid
Definition: nbtree.h:68
LocationIndex pd_special
Definition: bufpage.h:164
#define EpochFromFullTransactionId(x)
Definition: transam.h:47
#define XidFromFullTransactionId(x)
Definition: transam.h:48

References BTPageGetDeleteXid(), BTPageGetOpaque, BTPageOpaqueData::btpo_cycleid, BTPageOpaqueData::btpo_flags, BTPageOpaqueData::btpo_level, BTPageOpaqueData::btpo_next, BTPageOpaqueData::btpo_prev, BufferGetPage(), DEBUG2, elog(), EpochFromFullTransactionId, FirstOffsetNumber, IndexTupleSize, InvalidOffsetNumber, ItemIdIsDead, P_HAS_FULLXID, P_IGNORE, P_ISDELETED, P_ISLEAF, P_ISROOT, PageGetFreeSpace(), PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), PageGetPageSize(), PageHeaderData::pd_special, SizeOfPageHeaderData, and XidFromFullTransactionId.

Referenced by bt_page_stats_internal().

◆ PG_FUNCTION_INFO_V1() [1/6]

PG_FUNCTION_INFO_V1 ( bt_metap  )

◆ PG_FUNCTION_INFO_V1() [2/6]

PG_FUNCTION_INFO_V1 ( bt_page_items  )

◆ PG_FUNCTION_INFO_V1() [3/6]

PG_FUNCTION_INFO_V1 ( bt_page_items_1_9  )

◆ PG_FUNCTION_INFO_V1() [4/6]

PG_FUNCTION_INFO_V1 ( bt_page_items_bytea  )

◆ PG_FUNCTION_INFO_V1() [5/6]

PG_FUNCTION_INFO_V1 ( bt_page_stats  )

◆ PG_FUNCTION_INFO_V1() [6/6]

PG_FUNCTION_INFO_V1 ( bt_page_stats_1_9  )