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 static void TidListCreate(TidScanState *tidstate);
42 static int itemptr_comparator(const void *a, const void *b);
43 static TupleTableSlot *TidNext(TidScanState *node);
44 
45 
46 /*
47  * Compute the list of TIDs to be visited, by evaluating the expressions
48  * for them.
49  *
50  * (The result is actually an array, not a list.)
51  */
52 static void
54 {
55  List *evalList = tidstate->tss_tidquals;
56  ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
57  BlockNumber nblocks;
58  ItemPointerData *tidList;
59  int numAllocTids;
60  int numTids;
61  ListCell *l;
62 
63  /*
64  * We silently discard any TIDs that are out of range at the time of scan
65  * start. (Since we hold at least AccessShareLock on the table, it won't
66  * be possible for someone to truncate away the blocks we intend to
67  * visit.)
68  */
69  nblocks = RelationGetNumberOfBlocks(tidstate->ss.ss_currentRelation);
70 
71  /*
72  * We initialize the array with enough slots for the case that all quals
73  * are simple OpExprs or CurrentOfExprs. If there are any
74  * ScalarArrayOpExprs, we may have to enlarge the array.
75  */
76  numAllocTids = list_length(evalList);
77  tidList = (ItemPointerData *)
78  palloc(numAllocTids * sizeof(ItemPointerData));
79  numTids = 0;
80  tidstate->tss_isCurrentOf = false;
81 
82  foreach(l, evalList)
83  {
84  ExprState *exstate = (ExprState *) lfirst(l);
85  Expr *expr = exstate->expr;
86  ItemPointer itemptr;
87  bool isNull;
88 
89  if (is_opclause(expr))
90  {
91  FuncExprState *fexstate = (FuncExprState *) exstate;
92  Node *arg1;
93  Node *arg2;
94 
95  arg1 = get_leftop(expr);
96  arg2 = get_rightop(expr);
97  if (IsCTIDVar(arg1))
98  exstate = (ExprState *) lsecond(fexstate->args);
99  else if (IsCTIDVar(arg2))
100  exstate = (ExprState *) linitial(fexstate->args);
101  else
102  elog(ERROR, "could not identify CTID variable");
103 
104  itemptr = (ItemPointer)
106  econtext,
107  &isNull));
108  if (!isNull &&
109  ItemPointerIsValid(itemptr) &&
110  ItemPointerGetBlockNumber(itemptr) < nblocks)
111  {
112  if (numTids >= numAllocTids)
113  {
114  numAllocTids *= 2;
115  tidList = (ItemPointerData *)
116  repalloc(tidList,
117  numAllocTids * sizeof(ItemPointerData));
118  }
119  tidList[numTids++] = *itemptr;
120  }
121  }
122  else if (expr && IsA(expr, ScalarArrayOpExpr))
123  {
124  ScalarArrayOpExprState *saexstate = (ScalarArrayOpExprState *) exstate;
125  Datum arraydatum;
126  ArrayType *itemarray;
127  Datum *ipdatums;
128  bool *ipnulls;
129  int ndatums;
130  int i;
131 
132  exstate = (ExprState *) lsecond(saexstate->fxprstate.args);
133  arraydatum = ExecEvalExprSwitchContext(exstate,
134  econtext,
135  &isNull);
136  if (isNull)
137  continue;
138  itemarray = DatumGetArrayTypeP(arraydatum);
139  deconstruct_array(itemarray,
140  TIDOID, sizeof(ItemPointerData), false, 's',
141  &ipdatums, &ipnulls, &ndatums);
142  if (numTids + ndatums > numAllocTids)
143  {
144  numAllocTids = numTids + ndatums;
145  tidList = (ItemPointerData *)
146  repalloc(tidList,
147  numAllocTids * sizeof(ItemPointerData));
148  }
149  for (i = 0; i < ndatums; i++)
150  {
151  if (!ipnulls[i])
152  {
153  itemptr = (ItemPointer) DatumGetPointer(ipdatums[i]);
154  if (ItemPointerIsValid(itemptr) &&
155  ItemPointerGetBlockNumber(itemptr) < nblocks)
156  tidList[numTids++] = *itemptr;
157  }
158  }
159  pfree(ipdatums);
160  pfree(ipnulls);
161  }
162  else if (expr && IsA(expr, CurrentOfExpr))
163  {
164  CurrentOfExpr *cexpr = (CurrentOfExpr *) expr;
165  ItemPointerData cursor_tid;
166 
167  if (execCurrentOf(cexpr, econtext,
169  &cursor_tid))
170  {
171  if (numTids >= numAllocTids)
172  {
173  numAllocTids *= 2;
174  tidList = (ItemPointerData *)
175  repalloc(tidList,
176  numAllocTids * sizeof(ItemPointerData));
177  }
178  tidList[numTids++] = cursor_tid;
179  tidstate->tss_isCurrentOf = true;
180  }
181  }
182  else
183  elog(ERROR, "could not identify CTID expression");
184  }
185 
186  /*
187  * Sort the array of TIDs into order, and eliminate duplicates.
188  * Eliminating duplicates is necessary since we want OR semantics across
189  * the list. Sorting makes it easier to detect duplicates, and as a bonus
190  * ensures that we will visit the heap in the most efficient way.
191  */
192  if (numTids > 1)
193  {
194  int lastTid;
195  int i;
196 
197  /* CurrentOfExpr could never appear OR'd with something else */
198  Assert(!tidstate->tss_isCurrentOf);
199 
200  qsort((void *) tidList, numTids, sizeof(ItemPointerData),
202  lastTid = 0;
203  for (i = 1; i < numTids; i++)
204  {
205  if (!ItemPointerEquals(&tidList[lastTid], &tidList[i]))
206  tidList[++lastTid] = tidList[i];
207  }
208  numTids = lastTid + 1;
209  }
210 
211  tidstate->tss_TidList = tidList;
212  tidstate->tss_NumTids = numTids;
213  tidstate->tss_TidPtr = -1;
214 }
215 
216 /*
217  * qsort comparator for ItemPointerData items
218  */
219 static int
220 itemptr_comparator(const void *a, const void *b)
221 {
222  const ItemPointerData *ipa = (const ItemPointerData *) a;
223  const ItemPointerData *ipb = (const ItemPointerData *) b;
228 
229  if (ba < bb)
230  return -1;
231  if (ba > bb)
232  return 1;
233  if (oa < ob)
234  return -1;
235  if (oa > ob)
236  return 1;
237  return 0;
238 }
239 
240 /* ----------------------------------------------------------------
241  * TidNext
242  *
243  * Retrieve a tuple from the TidScan node's currentRelation
244  * using the tids in the TidScanState information.
245  *
246  * ----------------------------------------------------------------
247  */
248 static TupleTableSlot *
250 {
251  EState *estate;
252  ScanDirection direction;
253  Snapshot snapshot;
254  Relation heapRelation;
255  HeapTuple tuple;
256  TupleTableSlot *slot;
257  Buffer buffer = InvalidBuffer;
258  ItemPointerData *tidList;
259  int numTids;
260  bool bBackward;
261 
262  /*
263  * extract necessary information from tid scan node
264  */
265  estate = node->ss.ps.state;
266  direction = estate->es_direction;
267  snapshot = estate->es_snapshot;
268  heapRelation = node->ss.ss_currentRelation;
269  slot = node->ss.ss_ScanTupleSlot;
270 
271  /*
272  * First time through, compute the list of TIDs to be visited
273  */
274  if (node->tss_TidList == NULL)
275  TidListCreate(node);
276 
277  tidList = node->tss_TidList;
278  numTids = node->tss_NumTids;
279 
280  tuple = &(node->tss_htup);
281 
282  /*
283  * Initialize or advance scan position, depending on direction.
284  */
285  bBackward = ScanDirectionIsBackward(direction);
286  if (bBackward)
287  {
288  if (node->tss_TidPtr < 0)
289  {
290  /* initialize for backward scan */
291  node->tss_TidPtr = numTids - 1;
292  }
293  else
294  node->tss_TidPtr--;
295  }
296  else
297  {
298  if (node->tss_TidPtr < 0)
299  {
300  /* initialize for forward scan */
301  node->tss_TidPtr = 0;
302  }
303  else
304  node->tss_TidPtr++;
305  }
306 
307  while (node->tss_TidPtr >= 0 && node->tss_TidPtr < numTids)
308  {
309  tuple->t_self = tidList[node->tss_TidPtr];
310 
311  /*
312  * For WHERE CURRENT OF, the tuple retrieved from the cursor might
313  * since have been updated; if so, we should fetch the version that is
314  * current according to our snapshot.
315  */
316  if (node->tss_isCurrentOf)
317  heap_get_latest_tid(heapRelation, snapshot, &tuple->t_self);
318 
319  if (heap_fetch(heapRelation, snapshot, tuple, &buffer, false, NULL))
320  {
321  /*
322  * store the scanned tuple in the scan tuple slot of the scan
323  * state. Eventually we will only do this and not return a tuple.
324  * Note: we pass 'false' because tuples returned by amgetnext are
325  * pointers onto disk pages and were not created with palloc() and
326  * so should not be pfree()'d.
327  */
328  ExecStoreTuple(tuple, /* tuple to store */
329  slot, /* slot to store in */
330  buffer, /* buffer associated with tuple */
331  false); /* don't pfree */
332 
333  /*
334  * At this point we have an extra pin on the buffer, because
335  * ExecStoreTuple incremented the pin count. Drop our local pin.
336  */
337  ReleaseBuffer(buffer);
338 
339  return slot;
340  }
341  /* Bad TID or failed snapshot qual; try next */
342  if (bBackward)
343  node->tss_TidPtr--;
344  else
345  node->tss_TidPtr++;
346  }
347 
348  /*
349  * if we get here it means the tid scan failed so we are at the end of the
350  * scan..
351  */
352  return ExecClearTuple(slot);
353 }
354 
355 /*
356  * TidRecheck -- access method routine to recheck a tuple in EvalPlanQual
357  */
358 static bool
360 {
361  /*
362  * XXX shouldn't we check here to make sure tuple matches TID list? In
363  * runtime-key case this is not certain, is it? However, in the WHERE
364  * CURRENT OF case it might not match anyway ...
365  */
366  return true;
367 }
368 
369 
370 /* ----------------------------------------------------------------
371  * ExecTidScan(node)
372  *
373  * Scans the relation using tids and returns
374  * the next qualifying tuple in the direction specified.
375  * We call the ExecScan() routine and pass it the appropriate
376  * access method functions.
377  *
378  * Conditions:
379  * -- the "cursor" maintained by the AMI is positioned at the tuple
380  * returned previously.
381  *
382  * Initial States:
383  * -- the relation indicated is opened for scanning so that the
384  * "cursor" is positioned before the first qualifying tuple.
385  * -- tidPtr is -1.
386  * ----------------------------------------------------------------
387  */
390 {
391  return ExecScan(&node->ss,
394 }
395 
396 /* ----------------------------------------------------------------
397  * ExecReScanTidScan(node)
398  * ----------------------------------------------------------------
399  */
400 void
402 {
403  if (node->tss_TidList)
404  pfree(node->tss_TidList);
405  node->tss_TidList = NULL;
406  node->tss_NumTids = 0;
407  node->tss_TidPtr = -1;
408 
409  ExecScanReScan(&node->ss);
410 }
411 
412 /* ----------------------------------------------------------------
413  * ExecEndTidScan
414  *
415  * Releases any storage allocated through C routines.
416  * Returns nothing.
417  * ----------------------------------------------------------------
418  */
419 void
421 {
422  /*
423  * Free the exprcontext
424  */
425  ExecFreeExprContext(&node->ss.ps);
426 
427  /*
428  * clear out tuple table slots
429  */
432 
433  /*
434  * close the heap relation.
435  */
437 }
438 
439 /* ----------------------------------------------------------------
440  * ExecInitTidScan
441  *
442  * Initializes the tid scan's state information, creates
443  * scan keys, and opens the base and tid relations.
444  *
445  * Parameters:
446  * node: TidNode node produced by the planner.
447  * estate: the execution state initialized in InitPlan.
448  * ----------------------------------------------------------------
449  */
450 TidScanState *
451 ExecInitTidScan(TidScan *node, EState *estate, int eflags)
452 {
453  TidScanState *tidstate;
454  Relation currentRelation;
455 
456  /*
457  * create state structure
458  */
459  tidstate = makeNode(TidScanState);
460  tidstate->ss.ps.plan = (Plan *) node;
461  tidstate->ss.ps.state = estate;
462 
463  /*
464  * Miscellaneous initialization
465  *
466  * create expression context for node
467  */
468  ExecAssignExprContext(estate, &tidstate->ss.ps);
469 
470  /*
471  * initialize child expressions
472  */
473  tidstate->ss.ps.targetlist = (List *)
475  (PlanState *) tidstate);
476  tidstate->ss.ps.qual = (List *)
477  ExecInitExpr((Expr *) node->scan.plan.qual,
478  (PlanState *) tidstate);
479 
480  tidstate->tss_tidquals = (List *)
481  ExecInitExpr((Expr *) node->tidquals,
482  (PlanState *) tidstate);
483 
484  /*
485  * tuple table initialization
486  */
487  ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
488  ExecInitScanTupleSlot(estate, &tidstate->ss);
489 
490  /*
491  * mark tid list as not computed yet
492  */
493  tidstate->tss_TidList = NULL;
494  tidstate->tss_NumTids = 0;
495  tidstate->tss_TidPtr = -1;
496 
497  /*
498  * open the base relation and acquire appropriate lock on it.
499  */
500  currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
501 
502  tidstate->ss.ss_currentRelation = currentRelation;
503  tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
504 
505  /*
506  * get the scan type from the relation descriptor.
507  */
508  ExecAssignScanType(&tidstate->ss, RelationGetDescr(currentRelation));
509 
510  /*
511  * Initialize result tuple type and projection info.
512  */
513  ExecAssignResultTypeFromTL(&tidstate->ss.ps);
514  ExecAssignScanProjectionInfo(&tidstate->ss);
515 
516  /*
517  * all done.
518  */
519  return tidstate;
520 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
TupleTableSlot * ExecStoreTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer, bool shouldFree)
Definition: execTuples.c:320
List * qual
Definition: plannodes.h:130
TupleTableSlot * ExecTidScan(TidScanState *node)
Definition: nodeTidscan.c:389
Plan plan
Definition: plannodes.h:305
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
Definition: execTuples.c:842
Index scanrelid
Definition: plannodes.h:306
static TupleTableSlot * TidNext(TidScanState *node)
Definition: nodeTidscan.c:249
#define RelationGetDescr(relation)
Definition: rel.h:425
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
Definition: heapam.c:1849
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:121
List * tss_tidquals
Definition: execnodes.h:1509
List * args
Definition: execnodes.h:697
ExprContext * ps_ExprContext
Definition: execnodes.h:1078
List * tidquals
Definition: plannodes.h:452
TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: execTuples.c:439
void heap_get_latest_tid(Relation relation, Snapshot snapshot, ItemPointer tid)
Definition: heapam.c:2154
List * qual
Definition: execnodes.h:1062
#define InvalidBuffer
Definition: buf.h:25
Definition: nodes.h:508
static bool TidRecheck(TidScanState *node, TupleTableSlot *slot)
Definition: nodeTidscan.c:359
List * targetlist
Definition: execnodes.h:1061
Snapshot es_snapshot
Definition: execnodes.h:370
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1291
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3292
Relation ss_currentRelation
Definition: execnodes.h:1289
EState * state
Definition: execnodes.h:1049
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:685
#define lsecond(l)
Definition: pg_list.h:114
Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext, bool *isNull)
Definition: execQual.c:4219
ScanDirection es_direction
Definition: execnodes.h:369
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:430
HeapTupleData tss_htup
Definition: execnodes.h:1514
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:48
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:271
PlanState ps
Definition: execnodes.h:1288
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:272
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1077
#define TIDOID
Definition: pg_type.h:332
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execQual.c:4266
void pfree(void *pointer)
Definition: mcxt.c:992
#define linitial(l)
Definition: pg_list.h:110
TidScanState * ExecInitTidScan(TidScan *node, EState *estate, int eflags)
Definition: nodeTidscan.c:451
#define ERROR
Definition: elog.h:43
ScanState ss
Definition: execnodes.h:1508
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:235
Expr * expr
Definition: execnodes.h:598
#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:198
Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags)
Definition: execUtils.c:772
ItemPointerData t_self
Definition: htup.h:65
ItemPointerData * tss_TidList
Definition: execnodes.h:1513
ScanDirection
Definition: sdir.h:22
bool tss_isCurrentOf
Definition: execnodes.h:1510
void ExecEndTidScan(TidScanState *node)
Definition: nodeTidscan.c:420
static int itemptr_comparator(const void *a, const void *b)
Definition: nodeTidscan.c:220
uintptr_t Datum
Definition: postgres.h:374
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
static void TidListCreate(TidScanState *tidstate)
Definition: nodeTidscan.c:53
Plan * plan
Definition: execnodes.h:1047
#define makeNode(_type_)
Definition: nodes.h:556
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#define lfirst(lc)
Definition: pg_list.h:106
FuncExprState fxprstate
Definition: execnodes.h:761
Scan scan
Definition: plannodes.h:451
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:408
static int list_length(const List *l)
Definition: pg_list.h:89
void ExecCloseScanRelation(Relation scanrel)
Definition: execUtils.c:830
#define IsCTIDVar(node)
Definition: nodeTidscan.c:35
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:76
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021
List * targetlist
Definition: plannodes.h:129
Node * get_rightop(const Expr *clause)
Definition: clauses.c:215
bool execCurrentOf(CurrentOfExpr *cexpr, ExprContext *econtext, Oid table_oid, ItemPointer current_tid)
Definition: execCurrent.c:41
#define DatumGetPointer(X)
Definition: postgres.h:557
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:1290
void * palloc(Size size)
Definition: mcxt.c:891
int i
void ExecScanReScan(ScanState *node)
Definition: execScan.c:327
void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc)
Definition: execUtils.c:709
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:66
#define qsort(a, b, c, d)
Definition: port.h:440
void ExecReScanTidScan(TidScanState *node)
Definition: nodeTidscan.c:401
Definition: pg_list.h:45
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:413
#define DatumGetArrayTypeP(X)
Definition: array.h:242