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(flags, nflags,
108  TEXTOID,
109  -1, false, TYPALIGN_INT));
110 
111  /* Build and return the result tuple. */
112  resultTuple = heap_form_tuple(tupdesc, values, nulls);
113 
114  return HeapTupleGetDatum(resultTuple);
115 }
116 
117 Datum
119 {
120  bytea *raw_page = PG_GETARG_BYTEA_P(0);
121  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
122  Page page;
123  GISTPageOpaque opaq;
124  OffsetNumber offset;
126 
127  if (!superuser())
128  ereport(ERROR,
129  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
130  errmsg("must be superuser to use raw page functions")));
131 
132  SetSingleFuncCall(fcinfo, 0);
133 
134  page = get_page_from_raw(raw_page);
135 
136  if (PageIsNew(page))
137  PG_RETURN_NULL();
138 
139  /* verify the special space has the expected size */
140  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
141  ereport(ERROR,
142  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
143  errmsg("input page is not a valid %s page", "GiST"),
144  errdetail("Expected special size %d, got %d.",
145  (int) MAXALIGN(sizeof(GISTPageOpaqueData)),
146  (int) PageGetSpecialSize(page))));
147 
148  opaq = GistPageGetOpaque(page);
149  if (opaq->gist_page_id != GIST_PAGE_ID)
150  ereport(ERROR,
151  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
152  errmsg("input page is not a valid %s page", "GiST"),
153  errdetail("Expected %08x, got %08x.",
154  GIST_PAGE_ID,
155  opaq->gist_page_id)));
156 
157  /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
158  if (GistPageIsDeleted(page))
159  elog(NOTICE, "page is deleted");
160  else
161  maxoff = PageGetMaxOffsetNumber(page);
162 
163  for (offset = FirstOffsetNumber;
164  offset <= maxoff;
165  offset++)
166  {
167  Datum values[5];
168  bool nulls[5];
169  ItemId id;
170  IndexTuple itup;
171  bytea *tuple_bytea;
172  int tuple_len;
173 
174  id = PageGetItemId(page, offset);
175 
176  if (!ItemIdIsValid(id))
177  elog(ERROR, "invalid ItemId");
178 
179  itup = (IndexTuple) PageGetItem(page, id);
180  tuple_len = IndexTupleSize(itup);
181 
182  memset(nulls, 0, sizeof(nulls));
183 
184  values[0] = DatumGetInt16(offset);
185  values[1] = ItemPointerGetDatum(&itup->t_tid);
186  values[2] = Int32GetDatum((int) IndexTupleSize(itup));
187 
188  tuple_bytea = (bytea *) palloc(tuple_len + VARHDRSZ);
189  SET_VARSIZE(tuple_bytea, tuple_len + VARHDRSZ);
190  memcpy(VARDATA(tuple_bytea), itup, tuple_len);
191  values[3] = BoolGetDatum(ItemIdIsDead(id));
192  values[4] = PointerGetDatum(tuple_bytea);
193 
194  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
195  }
196 
197  return (Datum) 0;
198 }
199 
200 Datum
202 {
203  bytea *raw_page = PG_GETARG_BYTEA_P(0);
204  Oid indexRelid = PG_GETARG_OID(1);
205  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
206  Relation indexRel;
207  Page page;
208  OffsetNumber offset;
210 
211  if (!superuser())
212  ereport(ERROR,
213  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
214  errmsg("must be superuser to use raw page functions")));
215 
216  SetSingleFuncCall(fcinfo, 0);
217 
218  /* Open the relation */
219  indexRel = index_open(indexRelid, AccessShareLock);
220 
221  if (!IS_GIST(indexRel))
222  ereport(ERROR,
223  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
224  errmsg("\"%s\" is not a %s index",
225  RelationGetRelationName(indexRel), "GiST")));
226 
227  page = get_page_from_raw(raw_page);
228 
229  if (PageIsNew(page))
230  {
231  index_close(indexRel, AccessShareLock);
232  PG_RETURN_NULL();
233  }
234 
235  /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
236  if (GistPageIsDeleted(page))
237  elog(NOTICE, "page is deleted");
238  else
239  maxoff = PageGetMaxOffsetNumber(page);
240 
241  for (offset = FirstOffsetNumber;
242  offset <= maxoff;
243  offset++)
244  {
245  Datum values[5];
246  bool nulls[5];
247  ItemId id;
248  IndexTuple itup;
249  Datum itup_values[INDEX_MAX_KEYS];
250  bool itup_isnull[INDEX_MAX_KEYS];
251  char *key_desc;
252 
253  id = PageGetItemId(page, offset);
254 
255  if (!ItemIdIsValid(id))
256  elog(ERROR, "invalid ItemId");
257 
258  itup = (IndexTuple) PageGetItem(page, id);
259 
260  index_deform_tuple(itup, RelationGetDescr(indexRel),
261  itup_values, itup_isnull);
262 
263  memset(nulls, 0, sizeof(nulls));
264 
265  values[0] = DatumGetInt16(offset);
266  values[1] = ItemPointerGetDatum(&itup->t_tid);
267  values[2] = Int32GetDatum((int) IndexTupleSize(itup));
268  values[3] = BoolGetDatum(ItemIdIsDead(id));
269 
270  key_desc = BuildIndexValueDescription(indexRel, itup_values, itup_isnull);
271  if (key_desc)
272  values[4] = CStringGetTextDatum(key_desc);
273  else
274  {
275  values[4] = (Datum) 0;
276  nulls[4] = true;
277  }
278 
279  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
280  }
281 
282  relation_close(indexRel, AccessShareLock);
283 
284  return (Datum) 0;
285 }
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3319
static Datum values[MAXATTR]
Definition: bootstrap.c:156
Pointer Page
Definition: bufpage.h:78
#define PageGetSpecialSize(page)
Definition: bufpage.h:299
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:356
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:234
#define PageGetItem(page, itemId)
Definition: bufpage.h:339
#define PageIsNew(page)
Definition: bufpage.h:228
#define PageGetLSN(page)
Definition: bufpage.h:365
#define CStringGetTextDatum(s)
Definition: builtins.h:85
unsigned short uint16
Definition: c.h:440
#define MAXALIGN(LEN)
Definition: c.h:757
#define VARHDRSZ
Definition: c.h:627
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define NOTICE
Definition: elog.h:29
#define ereport(elevel,...)
Definition: elog.h:143
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1683
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:631
#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 SetSingleFuncCall(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
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
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:118
#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:201
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:437
#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:1068
#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
#define LSNGetDatum(X)
Definition: pg_lsn.h:22
uintptr_t Datum
Definition: postgres.h:411
#define VARDATA(PTR)
Definition: postgres.h:315
#define BoolGetDatum(X)
Definition: postgres.h:446
#define Int32GetDatum(X)
Definition: postgres.h:523
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:342
#define DatumGetInt16(X)
Definition: postgres.h:488
#define PointerGetDatum(X)
Definition: postgres.h:600
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:515
#define RelationGetRelationName(relation)
Definition: rel.h:523
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:317
Tuplestorestate * setResult
Definition: execnodes.h:316
Definition: c.h:622
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:5190