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-2021, 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 "funcapi.h"
18 #include "miscadmin.h"
19 #include "pageinspect.h"
20 #include "storage/itemptr.h"
21 #include "utils/array.h"
22 #include "utils/builtins.h"
23 #include "utils/rel.h"
24 #include "utils/pg_lsn.h"
25 #include "utils/varlena.h"
26 
30 
31 #define ItemPointerGetDatum(X) PointerGetDatum(X)
32 
33 
34 Datum
36 {
37  bytea *raw_page = PG_GETARG_BYTEA_P(0);
38  TupleDesc tupdesc;
39  Page page;
40  GISTPageOpaque opaq;
41  HeapTuple resultTuple;
42  Datum values[4];
43  bool nulls[4];
44  Datum flags[16];
45  int nflags = 0;
46  uint16 flagbits;
47 
48  if (!superuser())
49  ereport(ERROR,
50  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
51  errmsg("must be superuser to use raw page functions")));
52 
53  page = get_page_from_raw(raw_page);
54 
56 
57  /* Build a tuple descriptor for our result type */
58  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
59  elog(ERROR, "return type must be a row type");
60 
61  /* Convert the flags bitmask to an array of human-readable names */
62  flagbits = opaq->flags;
63  if (flagbits & F_LEAF)
64  flags[nflags++] = CStringGetTextDatum("leaf");
65  if (flagbits & F_DELETED)
66  flags[nflags++] = CStringGetTextDatum("deleted");
67  if (flagbits & F_TUPLES_DELETED)
68  flags[nflags++] = CStringGetTextDatum("tuples_deleted");
69  if (flagbits & F_FOLLOW_RIGHT)
70  flags[nflags++] = CStringGetTextDatum("follow_right");
71  if (flagbits & F_HAS_GARBAGE)
72  flags[nflags++] = CStringGetTextDatum("has_garbage");
73  flagbits &= ~(F_LEAF | F_DELETED | F_TUPLES_DELETED | F_FOLLOW_RIGHT | F_HAS_GARBAGE);
74  if (flagbits)
75  {
76  /* any flags we don't recognize are printed in hex */
77  flags[nflags++] = DirectFunctionCall1(to_hex32, Int32GetDatum(flagbits));
78  }
79 
80  memset(nulls, 0, sizeof(nulls));
81 
82  values[0] = LSNGetDatum(PageGetLSN(page));
83  values[1] = LSNGetDatum(GistPageGetNSN(page));
84  values[2] = Int64GetDatum(opaq->rightlink);
85  values[3] = PointerGetDatum(construct_array(flags, nflags,
86  TEXTOID,
87  -1, false, TYPALIGN_INT));
88 
89  /* Build and return the result tuple. */
90  resultTuple = heap_form_tuple(tupdesc, values, nulls);
91 
92  return HeapTupleGetDatum(resultTuple);
93 }
94 
95 Datum
97 {
98  bytea *raw_page = PG_GETARG_BYTEA_P(0);
99  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
100  bool randomAccess;
101  TupleDesc tupdesc;
102  Tuplestorestate *tupstore;
103  MemoryContext oldcontext;
104  Page page;
105  OffsetNumber offset;
107 
108  if (!superuser())
109  ereport(ERROR,
110  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
111  errmsg("must be superuser to use raw page functions")));
112 
113  /* check to see if caller supports us returning a tuplestore */
114  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
115  ereport(ERROR,
116  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
117  errmsg("set-valued function called in context that cannot accept a set")));
118  if (!(rsinfo->allowedModes & SFRM_Materialize))
119  ereport(ERROR,
120  (errcode(ERRCODE_SYNTAX_ERROR),
121  errmsg("materialize mode required, but it is not allowed in this context")));
122 
123  /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
125 
126  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
127  elog(ERROR, "return type must be a row type");
128 
129  randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
130  tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
131  rsinfo->returnMode = SFRM_Materialize;
132  rsinfo->setResult = tupstore;
133  rsinfo->setDesc = tupdesc;
134 
135  MemoryContextSwitchTo(oldcontext);
136 
137  page = get_page_from_raw(raw_page);
138 
139  /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
140  if (GistPageIsDeleted(page))
141  elog(NOTICE, "page is deleted");
142  else
143  maxoff = PageGetMaxOffsetNumber(page);
144 
145  for (offset = FirstOffsetNumber;
146  offset <= maxoff;
147  offset++)
148  {
149  Datum values[5];
150  bool nulls[5];
151  ItemId id;
152  IndexTuple itup;
153  bytea *tuple_bytea;
154  int tuple_len;
155 
156  id = PageGetItemId(page, offset);
157 
158  if (!ItemIdIsValid(id))
159  elog(ERROR, "invalid ItemId");
160 
161  itup = (IndexTuple) PageGetItem(page, id);
162  tuple_len = IndexTupleSize(itup);
163 
164  memset(nulls, 0, sizeof(nulls));
165 
166  values[0] = DatumGetInt16(offset);
167  values[1] = ItemPointerGetDatum(&itup->t_tid);
168  values[2] = Int32GetDatum((int) IndexTupleSize(itup));
169 
170  tuple_bytea = (bytea *) palloc(tuple_len + VARHDRSZ);
171  SET_VARSIZE(tuple_bytea, tuple_len + VARHDRSZ);
172  memcpy(VARDATA(tuple_bytea), itup, tuple_len);
173  values[3] = BoolGetDatum(ItemIdIsDead(id));
174  values[4] = PointerGetDatum(tuple_bytea);
175 
176  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
177  }
178 
179  return (Datum) 0;
180 }
181 
182 Datum
184 {
185  bytea *raw_page = PG_GETARG_BYTEA_P(0);
186  Oid indexRelid = PG_GETARG_OID(1);
187  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
188  bool randomAccess;
189  Relation indexRel;
190  TupleDesc tupdesc;
191  Tuplestorestate *tupstore;
192  MemoryContext oldcontext;
193  Page page;
194  OffsetNumber offset;
196 
197  if (!superuser())
198  ereport(ERROR,
199  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
200  errmsg("must be superuser to use raw page functions")));
201 
202  /* check to see if caller supports us returning a tuplestore */
203  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
204  ereport(ERROR,
205  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
206  errmsg("set-valued function called in context that cannot accept a set")));
207  if (!(rsinfo->allowedModes & SFRM_Materialize))
208  ereport(ERROR,
209  (errcode(ERRCODE_SYNTAX_ERROR),
210  errmsg("materialize mode required, but it is not allowed in this context")));
211 
212  /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
214 
215  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
216  elog(ERROR, "return type must be a row type");
217 
218  randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
219  tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
220  rsinfo->returnMode = SFRM_Materialize;
221  rsinfo->setResult = tupstore;
222  rsinfo->setDesc = tupdesc;
223 
224  MemoryContextSwitchTo(oldcontext);
225 
226  /* Open the relation */
227  indexRel = index_open(indexRelid, AccessShareLock);
228 
229  page = get_page_from_raw(raw_page);
230 
231  /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */
232  if (GistPageIsDeleted(page))
233  elog(NOTICE, "page is deleted");
234  else
235  maxoff = PageGetMaxOffsetNumber(page);
236 
237  for (offset = FirstOffsetNumber;
238  offset <= maxoff;
239  offset++)
240  {
241  Datum values[5];
242  bool nulls[5];
243  ItemId id;
244  IndexTuple itup;
245  Datum itup_values[INDEX_MAX_KEYS];
246  bool itup_isnull[INDEX_MAX_KEYS];
247  char *key_desc;
248 
249  id = PageGetItemId(page, offset);
250 
251  if (!ItemIdIsValid(id))
252  elog(ERROR, "invalid ItemId");
253 
254  itup = (IndexTuple) PageGetItem(page, id);
255 
256  index_deform_tuple(itup, RelationGetDescr(indexRel),
257  itup_values, itup_isnull);
258 
259  memset(nulls, 0, sizeof(nulls));
260 
261  values[0] = DatumGetInt16(offset);
262  values[1] = ItemPointerGetDatum(&itup->t_tid);
263  values[2] = Int32GetDatum((int) IndexTupleSize(itup));
264  values[3] = BoolGetDatum(ItemIdIsDead(id));
265 
266  key_desc = BuildIndexValueDescription(indexRel, itup_values, itup_isnull);
267  if (key_desc)
268  values[4] = CStringGetTextDatum(key_desc);
269  else
270  {
271  values[4] = (Datum) 0;
272  nulls[4] = true;
273  }
274 
275  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
276  }
277 
278  relation_close(indexRel, AccessShareLock);
279 
280  return (Datum) 0;
281 }
Datum gist_page_opaque_info(PG_FUNCTION_ARGS)
Definition: gistfuncs.c:35
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define GistPageGetNSN(page)
Definition: gist.h:186
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
#define GistPageIsDeleted(page)
Definition: gist.h:172
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:207
#define VARDATA(PTR)
Definition: postgres.h:315
#define RelationGetDescr(relation)
Definition: rel.h:503
Datum gist_page_items(PG_FUNCTION_ARGS)
Definition: gistfuncs.c:183
#define PointerGetDatum(X)
Definition: postgres.h:600
#define VARHDRSZ
Definition: c.h:627
ItemPointerData t_tid
Definition: itup.h:37
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3319
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:698
#define LSNGetDatum(X)
Definition: pg_lsn.h:22
bool superuser(void)
Definition: superuser.c:46
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
#define ItemPointerGetDatum(X)
Definition: gistfuncs.c:31
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:626
unsigned int Oid
Definition: postgres_ext.h:31
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
Datum gist_page_items_bytea(PG_FUNCTION_ARGS)
Definition: gistfuncs.c:96
#define PG_GETARG_BYTEA_P(n)
Definition: fmgr.h:335
unsigned short uint16
Definition: c.h:440
#define ERROR
Definition: elog.h:46
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define DatumGetInt16(X)
Definition: postgres.h:488
PG_FUNCTION_INFO_V1(gist_page_opaque_info)
void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:437
uint16 flags
Definition: gist.h:81
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1697
#define F_TUPLES_DELETED
Definition: gist.h:48
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:411
int work_mem
Definition: globals.c:124
#define F_HAS_GARBAGE
Definition: gist.h:51
#define BoolGetDatum(X)
Definition: postgres.h:446
#define InvalidOffsetNumber
Definition: off.h:26
#define ereport(elevel,...)
Definition: elog.h:157
#define ItemIdIsValid(itemId)
Definition: itemid.h:86
Datum to_hex32(PG_FUNCTION_ARGS)
Definition: varlena.c:5242
int allowedModes
Definition: execnodes.h:306
#define NOTICE
Definition: elog.h:37
#define F_FOLLOW_RIGHT
Definition: gist.h:50
SetFunctionReturnMode returnMode
Definition: execnodes.h:308
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Page get_page_from_raw(bytea *raw_page)
Definition: rawpage.c:215
#define INDEX_MAX_KEYS
#define PageGetSpecialPointer(page)
Definition: bufpage.h:326
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:234
#define PageGetLSN(page)
Definition: bufpage.h:366
Tuplestorestate * setResult
Definition: execnodes.h:311
static Datum values[MAXATTR]
Definition: bootstrap.c:156
ExprContext * econtext
Definition: execnodes.h:304
#define Int32GetDatum(X)
Definition: postgres.h:523
TupleDesc setDesc
Definition: execnodes.h:312
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define F_LEAF
Definition: gist.h:46
#define elog(elevel,...)
Definition: elog.h:232
GISTPageOpaqueData * GISTPageOpaque
Definition: gist.h:85
#define CStringGetTextDatum(s)
Definition: builtins.h:86
BlockNumber rightlink
Definition: gist.h:80
Definition: c.h:621
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define F_DELETED
Definition: gist.h:47
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:342
char * BuildIndexValueDescription(Relation indexRelation, Datum *values, bool *isnull)
Definition: genam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:132
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define IndexTupleSize(itup)
Definition: itup.h:71