PostgreSQL Source Code  git master
gistfuncs.c
Go to the documentation of this file.
1 /*
2  * gistfuncs.c
3  * Functions to investigate the content of GiST indexes
4  *
5  * Copyright (c) 2014-2022, PostgreSQL Global Development Group
6  *
7  * IDENTIFICATION
8  * contrib/pageinspect/gistfuncs.c
9  */
10 #include "postgres.h"
11 
12 #include "access/gist.h"
13 #include "access/gist_private.h"
14 #include "access/htup.h"
15 #include "access/relation.h"
16 #include "catalog/namespace.h"
17 #include "catalog/pg_am_d.h"
18 #include "funcapi.h"
19 #include "miscadmin.h"
20 #include "pageinspect.h"
21 #include "storage/itemptr.h"
22 #include "utils/array.h"
23 #include "utils/builtins.h"
24 #include "utils/rel.h"
25 #include "utils/pg_lsn.h"
26 #include "utils/varlena.h"
27 
31 
32 #define IS_GIST(r) ((r)->rd_rel->relam == GIST_AM_OID)
33 
34 #define ItemPointerGetDatum(X) PointerGetDatum(X)
35 
36 
37 Datum
39 {
40  bytea *raw_page = PG_GETARG_BYTEA_P(0);
41  TupleDesc tupdesc;
42  Page page;
43  GISTPageOpaque opaq;
44  HeapTuple resultTuple;
45  Datum values[4];
46  bool nulls[4];
47  Datum flags[16];
48  int nflags = 0;
49  uint16 flagbits;
50 
51  if (!superuser())
52  ereport(ERROR,
53  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
54  errmsg("must be superuser to use raw page functions")));
55 
56  page = get_page_from_raw(raw_page);
57 
58  if (PageIsNew(page))
60 
61  /* verify the special space has the expected size */
62  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
63  ereport(ERROR,
64  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
65  errmsg("input page is not a valid %s page", "GiST"),
66  errdetail("Expected special size %d, got %d.",
67  (int) MAXALIGN(sizeof(GISTPageOpaqueData)),
68  (int) PageGetSpecialSize(page))));
69 
70  opaq = GistPageGetOpaque(page);
71  if (opaq->gist_page_id != GIST_PAGE_ID)
72  ereport(ERROR,
73  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
74  errmsg("input page is not a valid %s page", "GiST"),
75  errdetail("Expected %08x, got %08x.",
77  opaq->gist_page_id)));
78 
79  /* Build a tuple descriptor for our result type */
80  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
81  elog(ERROR, "return type must be a row type");
82 
83  /* Convert the flags bitmask to an array of human-readable names */
84  flagbits = opaq->flags;
85  if (flagbits & F_LEAF)
86  flags[nflags++] = CStringGetTextDatum("leaf");
87  if (flagbits & F_DELETED)
88  flags[nflags++] = CStringGetTextDatum("deleted");
89  if (flagbits & F_TUPLES_DELETED)
90  flags[nflags++] = CStringGetTextDatum("tuples_deleted");
91  if (flagbits & F_FOLLOW_RIGHT)
92  flags[nflags++] = CStringGetTextDatum("follow_right");
93  if (flagbits & F_HAS_GARBAGE)
94  flags[nflags++] = CStringGetTextDatum("has_garbage");
96  if (flagbits)
97  {
98  /* any flags we don't recognize are printed in hex */
99  flags[nflags++] = DirectFunctionCall1(to_hex32, Int32GetDatum(flagbits));
100  }
101 
102  memset(nulls, 0, sizeof(nulls));
103 
104  values[0] = LSNGetDatum(PageGetLSN(page));
105  values[1] = LSNGetDatum(GistPageGetNSN(page));
106  values[2] = Int64GetDatum(opaq->rightlink);
107  values[3] = PointerGetDatum(construct_array_builtin(flags, nflags, TEXTOID));
108 
109  /* Build and return the result tuple. */
110  resultTuple = heap_form_tuple(tupdesc, values, nulls);
111 
112  return HeapTupleGetDatum(resultTuple);
113 }
114 
115 Datum
117 {
118  bytea *raw_page = PG_GETARG_BYTEA_P(0);
119  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
120  Page page;
121  GISTPageOpaque opaq;
122  OffsetNumber offset;
124 
125  if (!superuser())
126  ereport(ERROR,
127  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
128  errmsg("must be superuser to use raw page functions")));
129 
130  InitMaterializedSRF(fcinfo, 0);
131 
132  page = get_page_from_raw(raw_page);
133 
134  if (PageIsNew(page))
135  PG_RETURN_NULL();
136 
137  /* verify the special space has the expected size */
138  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
139  ereport(ERROR,
140  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
141  errmsg("input page is not a valid %s page", "GiST"),
142  errdetail("Expected special size %d, got %d.",
143  (int) MAXALIGN(sizeof(GISTPageOpaqueData)),
144  (int) PageGetSpecialSize(page))));
145 
146  opaq = GistPageGetOpaque(page);
147  if (opaq->gist_page_id != GIST_PAGE_ID)
148  ereport(ERROR,
149  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
150  errmsg("input page is not a valid %s page", "GiST"),
151  errdetail("Expected %08x, got %08x.",
152  GIST_PAGE_ID,
153  opaq->gist_page_id)));
154 
155  /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
156  if (GistPageIsDeleted(page))
157  elog(NOTICE, "page is deleted");
158  else
159  maxoff = PageGetMaxOffsetNumber(page);
160 
161  for (offset = FirstOffsetNumber;
162  offset <= maxoff;
163  offset++)
164  {
165  Datum values[5];
166  bool nulls[5];
167  ItemId id;
168  IndexTuple itup;
169  bytea *tuple_bytea;
170  int tuple_len;
171 
172  id = PageGetItemId(page, offset);
173 
174  if (!ItemIdIsValid(id))
175  elog(ERROR, "invalid ItemId");
176 
177  itup = (IndexTuple) PageGetItem(page, id);
178  tuple_len = IndexTupleSize(itup);
179 
180  memset(nulls, 0, sizeof(nulls));
181 
182  values[0] = DatumGetInt16(offset);
183  values[1] = ItemPointerGetDatum(&itup->t_tid);
184  values[2] = Int32GetDatum((int) IndexTupleSize(itup));
185 
186  tuple_bytea = (bytea *) palloc(tuple_len + VARHDRSZ);
187  SET_VARSIZE(tuple_bytea, tuple_len + VARHDRSZ);
188  memcpy(VARDATA(tuple_bytea), itup, tuple_len);
189  values[3] = BoolGetDatum(ItemIdIsDead(id));
190  values[4] = PointerGetDatum(tuple_bytea);
191 
192  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
193  }
194 
195  return (Datum) 0;
196 }
197 
198 Datum
200 {
201  bytea *raw_page = PG_GETARG_BYTEA_P(0);
202  Oid indexRelid = PG_GETARG_OID(1);
203  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
204  Relation indexRel;
205  Page page;
206  OffsetNumber offset;
208 
209  if (!superuser())
210  ereport(ERROR,
211  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
212  errmsg("must be superuser to use raw page functions")));
213 
214  InitMaterializedSRF(fcinfo, 0);
215 
216  /* Open the relation */
217  indexRel = index_open(indexRelid, AccessShareLock);
218 
219  if (!IS_GIST(indexRel))
220  ereport(ERROR,
221  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
222  errmsg("\"%s\" is not a %s index",
223  RelationGetRelationName(indexRel), "GiST")));
224 
225  page = get_page_from_raw(raw_page);
226 
227  if (PageIsNew(page))
228  {
229  index_close(indexRel, AccessShareLock);
230  PG_RETURN_NULL();
231  }
232 
233  /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
234  if (GistPageIsDeleted(page))
235  elog(NOTICE, "page is deleted");
236  else
237  maxoff = PageGetMaxOffsetNumber(page);
238 
239  for (offset = FirstOffsetNumber;
240  offset <= maxoff;
241  offset++)
242  {
243  Datum values[5];
244  bool nulls[5];
245  ItemId id;
246  IndexTuple itup;
247  Datum itup_values[INDEX_MAX_KEYS];
248  bool itup_isnull[INDEX_MAX_KEYS];
249  char *key_desc;
250 
251  id = PageGetItemId(page, offset);
252 
253  if (!ItemIdIsValid(id))
254  elog(ERROR, "invalid ItemId");
255 
256  itup = (IndexTuple) PageGetItem(page, id);
257 
258  index_deform_tuple(itup, RelationGetDescr(indexRel),
259  itup_values, itup_isnull);
260 
261  memset(nulls, 0, sizeof(nulls));
262 
263  values[0] = DatumGetInt16(offset);
264  values[1] = ItemPointerGetDatum(&itup->t_tid);
265  values[2] = Int32GetDatum((int) IndexTupleSize(itup));
266  values[3] = BoolGetDatum(ItemIdIsDead(id));
267 
268  key_desc = BuildIndexValueDescription(indexRel, itup_values, itup_isnull);
269  if (key_desc)
270  values[4] = CStringGetTextDatum(key_desc);
271  else
272  {
273  values[4] = (Datum) 0;
274  nulls[4] = true;
275  }
276 
277  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
278  }
279 
280  relation_close(indexRel, AccessShareLock);
281 
282  return (Datum) 0;
283 }
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3363
static Datum values[MAXATTR]
Definition: bootstrap.c:156
Pointer Page
Definition: bufpage.h:78
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:351
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:240
static bool PageIsNew(Page page)
Definition: bufpage.h:230
static XLogRecPtr PageGetLSN(Page page)
Definition: bufpage.h:383
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:369
static uint16 PageGetSpecialSize(Page page)
Definition: bufpage.h:313
#define CStringGetTextDatum(s)
Definition: builtins.h:88
unsigned short uint16
Definition: c.h:441
#define MAXALIGN(LEN)
Definition: c.h:747
#define VARHDRSZ
Definition: c.h:628
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1749
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_BYTEA_P(n)
Definition: fmgr.h:335
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
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
char * BuildIndexValueDescription(Relation indexRelation, Datum *values, bool *isnull)
Definition: genam.c:177
#define F_TUPLES_DELETED
Definition: gist.h:48
#define GIST_PAGE_ID
Definition: gist.h:109
#define F_LEAF
Definition: gist.h:46
#define F_FOLLOW_RIGHT
Definition: gist.h:49
#define GistPageIsDeleted(page)
Definition: gist.h:170
#define GistPageGetOpaque(page)
Definition: gist.h:165
#define F_HAS_GARBAGE
Definition: gist.h:50
#define F_DELETED
Definition: gist.h:47
#define GistPageGetNSN(page)
Definition: gist.h:184
PG_FUNCTION_INFO_V1(gist_page_opaque_info)
Datum gist_page_items_bytea(PG_FUNCTION_ARGS)
Definition: gistfuncs.c:116
#define IS_GIST(r)
Definition: gistfuncs.c:32
#define ItemPointerGetDatum(X)
Definition: gistfuncs.c:34
Datum gist_page_items(PG_FUNCTION_ARGS)
Definition: gistfuncs.c:199
Datum gist_page_opaque_info(PG_FUNCTION_ARGS)
Definition: gistfuncs.c:38
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:158
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:456
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
#define ItemIdIsValid(itemId)
Definition: itemid.h:86
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
#define AccessShareLock
Definition: lockdefs.h:36
void * palloc(Size size)
Definition: mcxt.c:1199
#define InvalidOffsetNumber
Definition: off.h:26
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
Page get_page_from_raw(bytea *raw_page)
Definition: rawpage.c:215
#define INDEX_MAX_KEYS
static Datum LSNGetDatum(XLogRecPtr X)
Definition: pg_lsn.h:28
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
uintptr_t Datum
Definition: postgres.h:412
#define VARDATA(PTR)
Definition: postgres.h:316
static Datum BoolGetDatum(bool X)
Definition: postgres.h:450
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:343
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:560
static int16 DatumGetInt16(Datum X)
Definition: postgres.h:510
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:527
#define RelationGetRelationName(relation)
Definition: rel.h:535
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
uint16 gist_page_id
Definition: gist.h:80
BlockNumber rightlink
Definition: gist.h:78
uint16 flags
Definition: gist.h:79
ItemPointerData t_tid
Definition: itup.h:37
TupleDesc setDesc
Definition: execnodes.h:332
Tuplestorestate * setResult
Definition: execnodes.h:331
Definition: c.h:623
bool superuser(void)
Definition: superuser.c:46
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
Datum to_hex32(PG_FUNCTION_ARGS)
Definition: varlena.c:5187