PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeTidscan.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nodeTidscan.c
4  * Routines to support direct tid scans of relations
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/executor/nodeTidscan.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *
18  * ExecTidScan scans a relation using tids
19  * ExecInitTidScan creates and initializes state info.
20  * ExecReScanTidScan rescans the tid relation.
21  * ExecEndTidScan releases all storage.
22  */
23 #include "postgres.h"
24 
25 #include "access/sysattr.h"
26 #include "catalog/pg_type.h"
27 #include "executor/execdebug.h"
28 #include "executor/nodeTidscan.h"
29 #include "optimizer/clauses.h"
30 #include "storage/bufmgr.h"
31 #include "utils/array.h"
32 #include "utils/rel.h"
33 
34 
35 #define IsCTIDVar(node) \
36  ((node) != NULL && \
37  IsA((node), Var) && \
38  ((Var *) (node))->varattno == SelfItemPointerAttributeNumber && \
39  ((Var *) (node))->varlevelsup == 0)
40 
41 /* one element in tss_tidexprs */
42 typedef struct TidExpr
43 {
44  ExprState *exprstate; /* ExprState for a TID-yielding subexpr */
45  bool isarray; /* if true, it yields tid[] not just tid */
46  CurrentOfExpr *cexpr; /* alternatively, we can have CURRENT OF */
47 } TidExpr;
48 
49 static void TidExprListCreate(TidScanState *tidstate);
50 static void TidListEval(TidScanState *tidstate);
51 static int itemptr_comparator(const void *a, const void *b);
52 static TupleTableSlot *TidNext(TidScanState *node);
53 
54 
55 /*
56  * Extract the qual subexpressions that yield TIDs to search for,
57  * and compile them into ExprStates if they're ordinary expressions.
58  *
59  * CURRENT OF is a special case that we can't compile usefully;
60  * just drop it into the TidExpr list as-is.
61  */
62 static void
64 {
65  TidScan *node = (TidScan *) tidstate->ss.ps.plan;
66  ListCell *l;
67 
68  tidstate->tss_tidexprs = NIL;
69  tidstate->tss_isCurrentOf = false;
70 
71  foreach(l, node->tidquals)
72  {
73  Expr *expr = (Expr *) lfirst(l);
74  TidExpr *tidexpr = (TidExpr *) palloc0(sizeof(TidExpr));
75 
76  if (is_opclause(expr))
77  {
78  Node *arg1;
79  Node *arg2;
80 
81  arg1 = get_leftop(expr);
82  arg2 = get_rightop(expr);
83  if (IsCTIDVar(arg1))
84  tidexpr->exprstate = ExecInitExpr((Expr *) arg2,
85  &tidstate->ss.ps);
86  else if (IsCTIDVar(arg2))
87  tidexpr->exprstate = ExecInitExpr((Expr *) arg1,
88  &tidstate->ss.ps);
89  else
90  elog(ERROR, "could not identify CTID variable");
91  tidexpr->isarray = false;
92  }
93  else if (expr && IsA(expr, ScalarArrayOpExpr))
94  {
95  ScalarArrayOpExpr *saex = (ScalarArrayOpExpr *) expr;
96 
97  Assert(IsCTIDVar(linitial(saex->args)));
98  tidexpr->exprstate = ExecInitExpr(lsecond(saex->args),
99  &tidstate->ss.ps);
100  tidexpr->isarray = true;
101  }
102  else if (expr && IsA(expr, CurrentOfExpr))
103  {
104  CurrentOfExpr *cexpr = (CurrentOfExpr *) expr;
105 
106  tidexpr->cexpr = cexpr;
107  tidstate->tss_isCurrentOf = true;
108  }
109  else
110  elog(ERROR, "could not identify CTID expression");
111 
112  tidstate->tss_tidexprs = lappend(tidstate->tss_tidexprs, tidexpr);
113  }
114 
115  /* CurrentOfExpr could never appear OR'd with something else */
116  Assert(list_length(tidstate->tss_tidexprs) == 1 ||
117  !tidstate->tss_isCurrentOf);
118 }
119 
120 /*
121  * Compute the list of TIDs to be visited, by evaluating the expressions
122  * for them.
123  *
124  * (The result is actually an array, not a list.)
125  */
126 static void
128 {
129  ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
130  BlockNumber nblocks;
131  ItemPointerData *tidList;
132  int numAllocTids;
133  int numTids;
134  ListCell *l;
135 
136  /*
137  * We silently discard any TIDs that are out of range at the time of scan
138  * start. (Since we hold at least AccessShareLock on the table, it won't
139  * be possible for someone to truncate away the blocks we intend to
140  * visit.)
141  */
142  nblocks = RelationGetNumberOfBlocks(tidstate->ss.ss_currentRelation);
143 
144  /*
145  * We initialize the array with enough slots for the case that all quals
146  * are simple OpExprs or CurrentOfExprs. If there are any
147  * ScalarArrayOpExprs, we may have to enlarge the array.
148  */
149  numAllocTids = list_length(tidstate->tss_tidexprs);
150  tidList = (ItemPointerData *)
151  palloc(numAllocTids * sizeof(ItemPointerData));
152  numTids = 0;
153 
154  foreach(l, tidstate->tss_tidexprs)
155  {
156  TidExpr *tidexpr = (TidExpr *) lfirst(l);
157  ItemPointer itemptr;
158  bool isNull;
159 
160  if (tidexpr->exprstate && !tidexpr->isarray)
161  {
162  itemptr = (ItemPointer)
164  econtext,
165  &isNull));
166  if (!isNull &&
167  ItemPointerIsValid(itemptr) &&
168  ItemPointerGetBlockNumber(itemptr) < nblocks)
169  {
170  if (numTids >= numAllocTids)
171  {
172  numAllocTids *= 2;
173  tidList = (ItemPointerData *)
174  repalloc(tidList,
175  numAllocTids * sizeof(ItemPointerData));
176  }
177  tidList[numTids++] = *itemptr;
178  }
179  }
180  else if (tidexpr->exprstate && tidexpr->isarray)
181  {
182  Datum arraydatum;
183  ArrayType *itemarray;
184  Datum *ipdatums;
185  bool *ipnulls;
186  int ndatums;
187  int i;
188 
189  arraydatum = ExecEvalExprSwitchContext(tidexpr->exprstate,
190  econtext,
191  &isNull);
192  if (isNull)
193  continue;
194  itemarray = DatumGetArrayTypeP(arraydatum);
195  deconstruct_array(itemarray,
196  TIDOID, sizeof(ItemPointerData), false, 's',
197  &ipdatums, &ipnulls, &ndatums);
198  if (numTids + ndatums > numAllocTids)
199  {
200  numAllocTids = numTids + ndatums;
201  tidList = (ItemPointerData *)
202  repalloc(tidList,
203  numAllocTids * sizeof(ItemPointerData));
204  }
205  for (i = 0; i < ndatums; i++)
206  {
207  if (!ipnulls[i])
208  {
209  itemptr = (ItemPointer) DatumGetPointer(ipdatums[i]);
210  if (ItemPointerIsValid(itemptr) &&
211  ItemPointerGetBlockNumber(itemptr) < nblocks)
212  tidList[numTids++] = *itemptr;
213  }
214  }
215  pfree(ipdatums);
216  pfree(ipnulls);
217  }
218  else
219  {
220  ItemPointerData cursor_tid;
221 
222  Assert(tidexpr->cexpr);
223  if (execCurrentOf(tidexpr->cexpr, econtext,
225  &cursor_tid))
226  {
227  if (numTids >= numAllocTids)
228  {
229  numAllocTids *= 2;
230  tidList = (ItemPointerData *)
231  repalloc(tidList,
232  numAllocTids * sizeof(ItemPointerData));
233  }
234  tidList[numTids++] = cursor_tid;
235  }
236  }
237  }
238 
239  /*
240  * Sort the array of TIDs into order, and eliminate duplicates.
241  * Eliminating duplicates is necessary since we want OR semantics across
242  * the list. Sorting makes it easier to detect duplicates, and as a bonus
243  * ensures that we will visit the heap in the most efficient way.
244  */
245  if (numTids > 1)
246  {
247  int lastTid;
248  int i;
249 
250  /* CurrentOfExpr could never appear OR'd with something else */
251  Assert(!tidstate->tss_isCurrentOf);
252 
253  qsort((void *) tidList, numTids, sizeof(ItemPointerData),
255  lastTid = 0;
256  for (i = 1; i < numTids; i++)
257  {
258  if (!ItemPointerEquals(&tidList[lastTid], &tidList[i]))
259  tidList[++lastTid] = tidList[i];
260  }
261  numTids = lastTid + 1;
262  }
263 
264  tidstate->tss_TidList = tidList;
265  tidstate->tss_NumTids = numTids;
266  tidstate->tss_TidPtr = -1;
267 }
268 
269 /*
270  * qsort comparator for ItemPointerData items
271  */
272 static int
273 itemptr_comparator(const void *a, const void *b)
274 {
275  const ItemPointerData *ipa = (const ItemPointerData *) a;
276  const ItemPointerData *ipb = (const ItemPointerData *) b;
281 
282  if (ba < bb)
283  return -1;
284  if (ba > bb)
285  return 1;
286  if (oa < ob)
287  return -1;
288  if (oa > ob)
289  return 1;
290  return 0;
291 }
292 
293 /* ----------------------------------------------------------------
294  * TidNext
295  *
296  * Retrieve a tuple from the TidScan node's currentRelation
297  * using the tids in the TidScanState information.
298  *
299  * ----------------------------------------------------------------
300  */
301 static TupleTableSlot *
303 {
304  EState *estate;
305  ScanDirection direction;
306  Snapshot snapshot;
307  Relation heapRelation;
308  HeapTuple tuple;
309  TupleTableSlot *slot;
311  ItemPointerData *tidList;
312  int numTids;
313  bool bBackward;
314 
315  /*
316  * extract necessary information from tid scan node
317  */
318  estate = node->ss.ps.state;
319  direction = estate->es_direction;
320  snapshot = estate->es_snapshot;
321  heapRelation = node->ss.ss_currentRelation;
322  slot = node->ss.ss_ScanTupleSlot;
323 
324  /*
325  * First time through, compute the list of TIDs to be visited
326  */
327  if (node->tss_TidList == NULL)
328  TidListEval(node);
329 
330  tidList = node->tss_TidList;
331  numTids = node->tss_NumTids;
332 
333  /*
334  * We use node->tss_htup as the tuple pointer; note this can't just be a
335  * local variable here, as the scan tuple slot will keep a pointer to it.
336  */
337  tuple = &(node->tss_htup);
338 
339  /*
340  * Initialize or advance scan position, depending on direction.
341  */
342  bBackward = ScanDirectionIsBackward(direction);
343  if (bBackward)
344  {
345  if (node->tss_TidPtr < 0)
346  {
347  /* initialize for backward scan */
348  node->tss_TidPtr = numTids - 1;
349  }
350  else
351  node->tss_TidPtr--;
352  }
353  else
354  {
355  if (node->tss_TidPtr < 0)
356  {
357  /* initialize for forward scan */
358  node->tss_TidPtr = 0;
359  }
360  else
361  node->tss_TidPtr++;
362  }
363 
364  while (node->tss_TidPtr >= 0 && node->tss_TidPtr < numTids)
365  {
366  tuple->t_self = tidList[node->tss_TidPtr];
367 
368  /*
369  * For WHERE CURRENT OF, the tuple retrieved from the cursor might
370  * since have been updated; if so, we should fetch the version that is
371  * current according to our snapshot.
372  */
373  if (node->tss_isCurrentOf)
374  heap_get_latest_tid(heapRelation, snapshot, &tuple->t_self);
375 
376  if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
377  {
378  /*
379  * store the scanned tuple in the scan tuple slot of the scan
380  * state. Eventually we will only do this and not return a tuple.
381  * Note: we pass 'false' because tuples returned by amgetnext are
382  * pointers onto disk pages and were not created with palloc() and
383  * so should not be pfree()'d.
384  */
385  ExecStoreTuple(tuple, /* tuple to store */
386  slot, /* slot to store in */
387  buffer, /* buffer associated with tuple */
388  false); /* don't pfree */
389 
390  /*
391  * At this point we have an extra pin on the buffer, because
392  * ExecStoreTuple incremented the pin count. Drop our local pin.
393  */
394  ReleaseBuffer(buffer);
395 
396  return slot;
397  }
398  /* Bad TID or failed snapshot qual; try next */
399  if (bBackward)
400  node->tss_TidPtr--;
401  else
402  node->tss_TidPtr++;
403  }
404 
405  /*
406  * if we get here it means the tid scan failed so we are at the end of the
407  * scan..
408  */
409  return ExecClearTuple(slot);
410 }
411 
412 /*
413  * TidRecheck -- access method routine to recheck a tuple in EvalPlanQual
414  */
415 static bool
417 {
418  /*
419  * XXX shouldn't we check here to make sure tuple matches TID list? In
420  * runtime-key case this is not certain, is it? However, in the WHERE
421  * CURRENT OF case it might not match anyway ...
422  */
423  return true;
424 }
425 
426 
427 /* ----------------------------------------------------------------
428  * ExecTidScan(node)
429  *
430  * Scans the relation using tids and returns
431  * the next qualifying tuple in the direction specified.
432  * We call the ExecScan() routine and pass it the appropriate
433  * access method functions.
434  *
435  * Conditions:
436  * -- the "cursor" maintained by the AMI is positioned at the tuple
437  * returned previously.
438  *
439  * Initial States:
440  * -- the relation indicated is opened for scanning so that the
441  * "cursor" is positioned before the first qualifying tuple.
442  * -- tidPtr is -1.
443  * ----------------------------------------------------------------
444  */
447 {
448  return ExecScan(&node->ss,
451 }
452 
453 /* ----------------------------------------------------------------
454  * ExecReScanTidScan(node)
455  * ----------------------------------------------------------------
456  */
457 void
459 {
460  if (node->tss_TidList)
461  pfree(node->tss_TidList);
462  node->tss_TidList = NULL;
463  node->tss_NumTids = 0;
464  node->tss_TidPtr = -1;
465 
466  ExecScanReScan(&node->ss);
467 }
468 
469 /* ----------------------------------------------------------------
470  * ExecEndTidScan
471  *
472  * Releases any storage allocated through C routines.
473  * Returns nothing.
474  * ----------------------------------------------------------------
475  */
476 void
478 {
479  /*
480  * Free the exprcontext
481  */
482  ExecFreeExprContext(&node->ss.ps);
483 
484  /*
485  * clear out tuple table slots
486  */
489 
490  /*
491  * close the heap relation.
492  */
494 }
495 
496 /* ----------------------------------------------------------------
497  * ExecInitTidScan
498  *
499  * Initializes the tid scan's state information, creates
500  * scan keys, and opens the base and tid relations.
501  *
502  * Parameters:
503  * node: TidNode node produced by the planner.
504  * estate: the execution state initialized in InitPlan.
505  * ----------------------------------------------------------------
506  */
507 TidScanState *
508 ExecInitTidScan(TidScan *node, EState *estate, int eflags)
509 {
510  TidScanState *tidstate;
511  Relation currentRelation;
512 
513  /*
514  * create state structure
515  */
516  tidstate = makeNode(TidScanState);
517  tidstate->ss.ps.plan = (Plan *) node;
518  tidstate->ss.ps.state = estate;
519 
520  /*
521  * Miscellaneous initialization
522  *
523  * create expression context for node
524  */
525  ExecAssignExprContext(estate, &tidstate->ss.ps);
526 
527  /*
528  * initialize child expressions
529  */
530  tidstate->ss.ps.qual =
531  ExecInitQual(node->scan.plan.qual, (PlanState *) tidstate);
532 
533  TidExprListCreate(tidstate);
534 
535  /*
536  * tuple table initialization
537  */
538  ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
539  ExecInitScanTupleSlot(estate, &tidstate->ss);
540 
541  /*
542  * mark tid list as not computed yet
543  */
544  tidstate->tss_TidList = NULL;
545  tidstate->tss_NumTids = 0;
546  tidstate->tss_TidPtr = -1;
547 
548  /*
549  * open the base relation and acquire appropriate lock on it.
550  */
551  currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
552 
553  tidstate->ss.ss_currentRelation = currentRelation;
554  tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
555 
556  /*
557  * get the scan type from the relation descriptor.
558  */
559  ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation));
560 
561  /*
562  * Initialize result tuple type and projection info.
563  */
564  ExecAssignResultTypeFromTL(&tidstate->ss.ps);
565  ExecAssignScanProjectionInfo(&tidstate->ss);
566 
567  /*
568  * all done.
569  */
570  return tidstate;
571 }
CurrentOfExpr * cexpr
Definition: nodeTidscan.c:46
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define NIL
Definition: pg_list.h:69
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
List * qual
Definition: plannodes.h:135
TupleTableSlot * ExecTidScan(TidScanState *node)
Definition: nodeTidscan.c:446
Plan plan
Definition: plannodes.h:317
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:280
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
Definition: execTuples.c:842
Index scanrelid
Definition: plannodes.h:318
static TupleTableSlot * TidNext(TidScanState *node)
Definition: nodeTidscan.c:302
#define RelationGetDescr(relation)
Definition: rel.h:429
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
Definition: heapam.c:1862
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:121
ExprContext * ps_ExprContext
Definition: execnodes.h:833
bool isarray
Definition: nodeTidscan.c:45
List * tidquals
Definition: plannodes.h:465
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
void heap_get_latest_tid(Relation relation, Snapshot snapshot, ItemPointer tid)
Definition: heapam.c:2167
#define InvalidBuffer
Definition: buf.h:25
Definition: nodes.h:509
static bool TidRecheck(TidScanState *node, TupleTableSlot *slot)
Definition: nodeTidscan.c:416
Snapshot es_snapshot
Definition: execnodes.h:409
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1050
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
Relation ss_currentRelation
Definition: execnodes.h:1048
EState * state
Definition: execnodes.h:805
static void TidListEval(TidScanState *tidstate)
Definition: nodeTidscan.c:127
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:516
#define lsecond(l)
Definition: pg_list.h:116
ScanDirection es_direction
Definition: execnodes.h:408
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:160
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:440
HeapTupleData tss_htup
Definition: execnodes.h:1330
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:48
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:388
PlanState ps
Definition: execnodes.h:1047
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:389
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:832
#define TIDOID
Definition: pg_type.h:332
void pfree(void *pointer)
Definition: mcxt.c:950
#define linitial(l)
Definition: pg_list.h:111
TidScanState * ExecInitTidScan(TidScan *node, EState *estate, int eflags)
Definition: nodeTidscan.c:508
#define ERROR
Definition: elog.h:43
ScanState ss
Definition: execnodes.h:1324
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:235
#define is_opclause(clause)
Definition: clauses.h:20
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
Node * get_leftop(const Expr *clause)
Definition: clauses.c:199
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:603
List * tss_tidexprs
Definition: execnodes.h:1325
ItemPointerData t_self
Definition: htup.h:65
ItemPointerData * tss_TidList
Definition: execnodes.h:1329
ScanDirection
Definition: sdir.h:22
bool tss_isCurrentOf
Definition: execnodes.h:1326
void ExecEndTidScan(TidScanState *node)
Definition: nodeTidscan.c:477
List * lappend(List *list, void *datum)
Definition: list.c:128
static int itemptr_comparator(const void *a, const void *b)
Definition: nodeTidscan.c:273
static void TidExprListCreate(TidScanState *tidstate)
Definition: nodeTidscan.c:63
void * palloc0(Size size)
Definition: mcxt.c:878
uintptr_t Datum
Definition: postgres.h:372
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
Plan * plan
Definition: execnodes.h:803
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:207
Scan scan
Definition: plannodes.h:464
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:418
static int list_length(const List *l)
Definition: pg_list.h:89
void ExecCloseScanRelation(Relation scanrel)
Definition: execUtils.c:661
#define IsCTIDVar(node)
Definition: nodeTidscan.c:35
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:963
Node * get_rightop(const Expr *clause)
Definition: clauses.c:216
bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Oid table_oid, ItemPointer current_tid)
Definition: execCurrent.c:41
ExprState * qual
Definition: execnodes.h:817
#define DatumGetPointer(X)
Definition: postgres.h:555
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3475
HeapScanDesc ss_currentScanDesc
Definition: execnodes.h:1049
void * palloc(Size size)
Definition: mcxt.c:849
int i
void ExecScanReScan(ScanState *node)
Definition: execScan.c:327
void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
Definition: execUtils.c:540
ExprState * exprstate
Definition: nodeTidscan.c:44
struct TidExpr TidExpr
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
#define qsort(a, b, c, d)
Definition: port.h:440
void ExecReScanTidScan(TidScanState *node)
Definition: nodeTidscan.c:458
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:417
#define DatumGetArrayTypeP(X)
Definition: array.h:242