Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeTidscan.c
4 : * Routines to support direct tid scans of relations
5 : *
6 : * Portions Copyright (c) 1996-2023, 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 "access/tableam.h"
27 : #include "catalog/pg_type.h"
28 : #include "executor/execdebug.h"
29 : #include "executor/nodeTidscan.h"
30 : #include "lib/qunique.h"
31 : #include "miscadmin.h"
32 : #include "nodes/nodeFuncs.h"
33 : #include "storage/bufmgr.h"
34 : #include "utils/array.h"
35 : #include "utils/rel.h"
36 :
37 :
38 : /*
39 : * It's sufficient to check varattno to identify the CTID variable, as any
40 : * Var in the relation scan qual must be for our table. (Even if it's a
41 : * parameterized scan referencing some other table's CTID, the other table's
42 : * Var would have become a Param by the time it gets here.)
43 : */
44 : #define IsCTIDVar(node) \
45 : ((node) != NULL && \
46 : IsA((node), Var) && \
47 : ((Var *) (node))->varattno == SelfItemPointerAttributeNumber)
48 :
49 : /* one element in tss_tidexprs */
50 : typedef struct TidExpr
51 : {
52 : ExprState *exprstate; /* ExprState for a TID-yielding subexpr */
53 : bool isarray; /* if true, it yields tid[] not just tid */
54 : CurrentOfExpr *cexpr; /* alternatively, we can have CURRENT OF */
55 : } TidExpr;
56 :
57 : static void TidExprListCreate(TidScanState *tidstate);
58 : static void TidListEval(TidScanState *tidstate);
59 : static int itemptr_comparator(const void *a, const void *b);
60 : static TupleTableSlot *TidNext(TidScanState *node);
61 :
62 :
63 : /*
64 : * Extract the qual subexpressions that yield TIDs to search for,
65 : * and compile them into ExprStates if they're ordinary expressions.
66 : *
67 : * CURRENT OF is a special case that we can't compile usefully;
68 : * just drop it into the TidExpr list as-is.
69 : */
70 : static void
2217 andres 71 GIC 359 : TidExprListCreate(TidScanState *tidstate)
72 : {
73 359 : TidScan *node = (TidScan *) tidstate->ss.ps.plan;
74 : ListCell *l;
75 :
2217 andres 76 CBC 359 : tidstate->tss_tidexprs = NIL;
2217 andres 77 GIC 359 : tidstate->tss_isCurrentOf = false;
2217 andres 78 ECB :
2217 andres 79 GIC 730 : foreach(l, node->tidquals)
80 : {
2217 andres 81 CBC 371 : Expr *expr = (Expr *) lfirst(l);
82 371 : TidExpr *tidexpr = (TidExpr *) palloc0(sizeof(TidExpr));
83 :
84 371 : if (is_opclause(expr))
85 : {
2217 andres 86 ECB : Node *arg1;
87 : Node *arg2;
88 :
2217 andres 89 CBC 136 : arg1 = get_leftop(expr);
2217 andres 90 GIC 136 : arg2 = get_rightop(expr);
91 136 : if (IsCTIDVar(arg1))
92 112 : tidexpr->exprstate = ExecInitExpr((Expr *) arg2,
93 : &tidstate->ss.ps);
2217 andres 94 CBC 24 : else if (IsCTIDVar(arg2))
95 24 : tidexpr->exprstate = ExecInitExpr((Expr *) arg1,
2217 andres 96 ECB : &tidstate->ss.ps);
97 : else
2217 andres 98 UIC 0 : elog(ERROR, "could not identify CTID variable");
2217 andres 99 CBC 136 : tidexpr->isarray = false;
2217 andres 100 ECB : }
2217 andres 101 GIC 235 : else if (expr && IsA(expr, ScalarArrayOpExpr))
102 15 : {
2217 andres 103 GBC 15 : ScalarArrayOpExpr *saex = (ScalarArrayOpExpr *) expr;
2217 andres 104 ECB :
2217 andres 105 GIC 15 : Assert(IsCTIDVar(linitial(saex->args)));
2217 andres 106 CBC 15 : tidexpr->exprstate = ExecInitExpr(lsecond(saex->args),
2217 andres 107 ECB : &tidstate->ss.ps);
2217 andres 108 CBC 15 : tidexpr->isarray = true;
109 : }
110 220 : else if (expr && IsA(expr, CurrentOfExpr))
111 220 : {
2217 andres 112 GIC 220 : CurrentOfExpr *cexpr = (CurrentOfExpr *) expr;
2217 andres 113 ECB :
2217 andres 114 GIC 220 : tidexpr->cexpr = cexpr;
2217 andres 115 CBC 220 : tidstate->tss_isCurrentOf = true;
2217 andres 116 ECB : }
117 : else
2217 andres 118 UIC 0 : elog(ERROR, "could not identify CTID expression");
2217 andres 119 ECB :
2217 andres 120 CBC 371 : tidstate->tss_tidexprs = lappend(tidstate->tss_tidexprs, tidexpr);
121 : }
122 :
2217 andres 123 EUB : /* CurrentOfExpr could never appear OR'd with something else */
2217 andres 124 GIC 359 : Assert(list_length(tidstate->tss_tidexprs) == 1 ||
2217 andres 125 ECB : !tidstate->tss_isCurrentOf);
2217 andres 126 GIC 359 : }
127 :
128 : /*
7135 tgl 129 ECB : * Compute the list of TIDs to be visited, by evaluating the expressions
130 : * for them.
6343 131 : *
132 : * (The result is actually an array, not a list.)
133 : */
134 : static void
2217 andres 135 GIC 314 : TidListEval(TidScanState *tidstate)
136 : {
7135 tgl 137 314 : ExprContext *econtext = tidstate->ss.ps.ps_ExprContext;
138 : TableScanDesc scan;
139 : ItemPointerData *tidList;
6343 tgl 140 ECB : int numAllocTids;
141 : int numTids;
6892 neilc 142 : ListCell *l;
143 :
144 : /*
145 : * Start scan on-demand - initializing a scan isn't free (e.g. heap stats
146 : * the size of the table), so it makes sense to delay that until needed -
147 : * the node might never get executed.
148 : */
1423 andres 149 GIC 314 : if (tidstate->ss.ss_currentScanDesc == NULL)
150 311 : tidstate->ss.ss_currentScanDesc =
1157 fujii 151 311 : table_beginscan_tid(tidstate->ss.ss_currentRelation,
1060 tgl 152 311 : tidstate->ss.ps.state->es_snapshot);
1423 andres 153 314 : scan = tidstate->ss.ss_currentScanDesc;
5457 tgl 154 ECB :
6343 155 : /*
6031 bruce 156 : * We initialize the array with enough slots for the case that all quals
5781 tgl 157 : * are simple OpExprs or CurrentOfExprs. If there are any
158 : * ScalarArrayOpExprs, we may have to enlarge the array.
159 : */
2217 andres 160 GIC 314 : numAllocTids = list_length(tidstate->tss_tidexprs);
161 : tidList = (ItemPointerData *)
6343 tgl 162 314 : palloc(numAllocTids * sizeof(ItemPointerData));
163 314 : numTids = 0;
164 :
2217 andres 165 CBC 604 : foreach(l, tidstate->tss_tidexprs)
166 : {
167 320 : TidExpr *tidexpr = (TidExpr *) lfirst(l);
7135 tgl 168 ECB : ItemPointer itemptr;
169 : bool isNull;
170 :
2217 andres 171 GIC 320 : if (tidexpr->exprstate && !tidexpr->isarray)
8538 bruce 172 ECB : {
173 : itemptr = (ItemPointer)
2217 andres 174 GIC 115 : DatumGetPointer(ExecEvalExprSwitchContext(tidexpr->exprstate,
175 : econtext,
2271 andres 176 ECB : &isNull));
1423 andres 177 GIC 115 : if (isNull)
1423 andres 178 UIC 0 : continue;
1423 andres 179 ECB :
180 : /*
181 : * We silently discard any TIDs that the AM considers invalid
182 : * (E.g. for heap, they could be out of range at the time of scan
1423 andres 183 EUB : * start. Since we hold at least AccessShareLock on the table, it
184 : * won't be possible for someone to truncate away the blocks we
185 : * intend to visit.).
186 : */
1423 andres 187 GIC 115 : if (!table_tuple_tid_valid(scan, itemptr))
1423 andres 188 UIC 0 : continue;
189 :
1423 andres 190 GIC 115 : if (numTids >= numAllocTids)
191 : {
1423 andres 192 CBC 3 : numAllocTids *= 2;
1423 andres 193 EUB : tidList = (ItemPointerData *)
1423 andres 194 GIC 3 : repalloc(tidList,
1423 andres 195 ECB : numAllocTids * sizeof(ItemPointerData));
196 : }
1423 andres 197 CBC 115 : tidList[numTids++] = *itemptr;
198 : }
2217 199 205 : else if (tidexpr->exprstate && tidexpr->isarray)
6343 tgl 200 GIC 12 : {
201 : Datum arraydatum;
6343 tgl 202 ECB : ArrayType *itemarray;
203 : Datum *ipdatums;
204 : bool *ipnulls;
205 : int ndatums;
206 : int i;
207 :
2217 andres 208 GIC 12 : arraydatum = ExecEvalExprSwitchContext(tidexpr->exprstate,
209 : econtext,
210 : &isNull);
6343 tgl 211 12 : if (isNull)
6343 tgl 212 UIC 0 : continue;
6343 tgl 213 CBC 12 : itemarray = DatumGetArrayTypeP(arraydatum);
282 peter 214 GNC 12 : deconstruct_array_builtin(itemarray, TIDOID, &ipdatums, &ipnulls, &ndatums);
6343 tgl 215 GBC 12 : if (numTids + ndatums > numAllocTids)
6343 tgl 216 ECB : {
6343 tgl 217 CBC 9 : numAllocTids = numTids + ndatums;
6343 tgl 218 ECB : tidList = (ItemPointerData *)
6343 tgl 219 GIC 9 : repalloc(tidList,
6343 tgl 220 ECB : numAllocTids * sizeof(ItemPointerData));
221 : }
6343 tgl 222 CBC 36 : for (i = 0; i < ndatums; i++)
223 : {
1423 andres 224 GIC 24 : if (ipnulls[i])
1423 andres 225 LBC 0 : continue;
226 :
1423 andres 227 CBC 24 : itemptr = (ItemPointer) DatumGetPointer(ipdatums[i]);
1423 andres 228 EUB :
1423 andres 229 GIC 24 : if (!table_tuple_tid_valid(scan, itemptr))
1423 andres 230 LBC 0 : continue;
231 :
1423 andres 232 CBC 24 : tidList[numTids++] = *itemptr;
6343 tgl 233 EUB : }
6343 tgl 234 GIC 12 : pfree(ipdatums);
6343 tgl 235 CBC 12 : pfree(ipnulls);
236 : }
2217 andres 237 ECB : else
5781 tgl 238 : {
239 : ItemPointerData cursor_tid;
240 :
2217 andres 241 GIC 193 : Assert(tidexpr->cexpr);
242 163 : if (execCurrentOf(tidexpr->cexpr, econtext,
2118 tgl 243 193 : RelationGetRelid(tidstate->ss.ss_currentRelation),
5781 tgl 244 ECB : &cursor_tid))
245 : {
5781 tgl 246 CBC 138 : if (numTids >= numAllocTids)
247 : {
5781 tgl 248 UIC 0 : numAllocTids *= 2;
5781 tgl 249 ECB : tidList = (ItemPointerData *)
5781 tgl 250 UIC 0 : repalloc(tidList,
5781 tgl 251 EUB : numAllocTids * sizeof(ItemPointerData));
252 : }
5781 tgl 253 GBC 138 : tidList[numTids++] = cursor_tid;
254 : }
255 : }
6343 tgl 256 ECB : }
257 :
258 : /*
259 : * Sort the array of TIDs into order, and eliminate duplicates.
260 : * Eliminating duplicates is necessary since we want OR semantics across
261 : * the list. Sorting makes it easier to detect duplicates, and as a bonus
262 : * ensures that we will visit the heap in the most efficient way.
263 : */
6343 tgl 264 GIC 284 : if (numTids > 1)
265 : {
266 : /* CurrentOfExpr could never appear OR'd with something else */
5646 tgl 267 CBC 15 : Assert(!tidstate->tss_isCurrentOf);
268 :
61 peter 269 GNC 15 : qsort(tidList, numTids, sizeof(ItemPointerData),
6343 tgl 270 ECB : itemptr_comparator);
1249 tmunro 271 GIC 15 : numTids = qunique(tidList, numTids, sizeof(ItemPointerData),
1249 tmunro 272 ECB : itemptr_comparator);
273 : }
7135 tgl 274 :
7135 tgl 275 GIC 284 : tidstate->tss_TidList = tidList;
276 284 : tidstate->tss_NumTids = numTids;
277 284 : tidstate->tss_TidPtr = -1;
8538 bruce 278 CBC 284 : }
8538 bruce 279 ECB :
6343 tgl 280 : /*
281 : * qsort comparator for ItemPointerData items
282 : */
283 : static int
6343 tgl 284 GIC 39 : itemptr_comparator(const void *a, const void *b)
285 : {
286 39 : const ItemPointerData *ipa = (const ItemPointerData *) a;
6343 tgl 287 CBC 39 : const ItemPointerData *ipb = (const ItemPointerData *) b;
6031 bruce 288 GIC 39 : BlockNumber ba = ItemPointerGetBlockNumber(ipa);
6031 bruce 289 CBC 39 : BlockNumber bb = ItemPointerGetBlockNumber(ipb);
6343 tgl 290 39 : OffsetNumber oa = ItemPointerGetOffsetNumber(ipa);
291 39 : OffsetNumber ob = ItemPointerGetOffsetNumber(ipb);
6343 tgl 292 ECB :
6343 tgl 293 CBC 39 : if (ba < bb)
6343 tgl 294 LBC 0 : return -1;
6343 tgl 295 GIC 39 : if (ba > bb)
6343 tgl 296 LBC 0 : return 1;
6343 tgl 297 GBC 39 : if (oa < ob)
6343 tgl 298 CBC 12 : return -1;
6343 tgl 299 GBC 27 : if (oa > ob)
6343 tgl 300 CBC 27 : return 1;
6343 tgl 301 LBC 0 : return 0;
6343 tgl 302 ECB : }
303 :
8538 bruce 304 EUB : /* ----------------------------------------------------------------
305 : * TidNext
306 : *
307 : * Retrieve a tuple from the TidScan node's currentRelation
308 : * using the tids in the TidScanState information.
309 : *
310 : * ----------------------------------------------------------------
311 : */
312 : static TupleTableSlot *
7430 tgl 313 GIC 573 : TidNext(TidScanState *node)
314 : {
315 : EState *estate;
8397 bruce 316 ECB : ScanDirection direction;
317 : Snapshot snapshot;
318 : TableScanDesc scan;
319 : Relation heapRelation;
320 : TupleTableSlot *slot;
321 : ItemPointerData *tidList;
322 : int numTids;
323 : bool bBackward;
324 :
325 : /*
326 : * extract necessary information from tid scan node
327 : */
7430 tgl 328 GIC 573 : estate = node->ss.ps.state;
8538 bruce 329 573 : direction = estate->es_direction;
330 573 : snapshot = estate->es_snapshot;
7430 tgl 331 CBC 573 : heapRelation = node->ss.ss_currentRelation;
332 573 : slot = node->ss.ss_ScanTupleSlot;
8538 bruce 333 ECB :
7135 tgl 334 : /*
335 : * First time through, compute the list of TIDs to be visited
336 : */
7135 tgl 337 GIC 573 : if (node->tss_TidList == NULL)
2217 andres 338 314 : TidListEval(node);
339 :
1423 andres 340 CBC 543 : scan = node->ss.ss_currentScanDesc;
7135 tgl 341 543 : tidList = node->tss_TidList;
7135 tgl 342 GIC 543 : numTids = node->tss_NumTids;
7135 tgl 343 ECB :
8053 bruce 344 : /*
6343 tgl 345 : * Initialize or advance scan position, depending on direction.
346 : */
8538 bruce 347 GIC 543 : bBackward = ScanDirectionIsBackward(direction);
348 543 : if (bBackward)
349 : {
6343 tgl 350 CBC 3 : if (node->tss_TidPtr < 0)
8538 bruce 351 ECB : {
352 : /* initialize for backward scan */
7430 tgl 353 LBC 0 : node->tss_TidPtr = numTids - 1;
354 : }
355 : else
6343 tgl 356 GBC 3 : node->tss_TidPtr--;
357 : }
358 : else
8538 bruce 359 ECB : {
6343 tgl 360 GIC 540 : if (node->tss_TidPtr < 0)
361 : {
362 : /* initialize for forward scan */
7430 tgl 363 CBC 284 : node->tss_TidPtr = 0;
364 : }
365 : else
6343 366 256 : node->tss_TidPtr++;
367 : }
368 :
369 558 : while (node->tss_TidPtr >= 0 && node->tss_TidPtr < numTids)
370 : {
1476 andres 371 GIC 277 : ItemPointerData tid = tidList[node->tss_TidPtr];
5646 tgl 372 ECB :
373 : /*
374 : * For WHERE CURRENT OF, the tuple retrieved from the cursor might
375 : * since have been updated; if so, we should fetch the version that is
376 : * current according to our snapshot.
377 : */
5646 tgl 378 GIC 277 : if (node->tss_isCurrentOf)
1417 andres 379 138 : table_tuple_get_latest_tid(scan, &tid);
380 :
1417 andres 381 CBC 277 : if (table_tuple_fetch_row_version(heapRelation, &tid, snapshot, slot))
6343 tgl 382 262 : return slot;
383 :
6343 tgl 384 ECB : /* Bad TID or failed snapshot qual; try next */
8538 bruce 385 CBC 15 : if (bBackward)
7430 tgl 386 UIC 0 : node->tss_TidPtr--;
387 : else
7430 tgl 388 CBC 15 : node->tss_TidPtr++;
2084 andres 389 EUB :
2084 andres 390 GIC 15 : CHECK_FOR_INTERRUPTS();
8538 bruce 391 ECB : }
392 :
8053 393 : /*
394 : * if we get here it means the tid scan failed so we are at the end of the
395 : * scan..
396 : */
8538 bruce 397 GIC 281 : return ExecClearTuple(slot);
398 : }
399 :
4913 tgl 400 ECB : /*
401 : * TidRecheck -- access method routine to recheck a tuple in EvalPlanQual
402 : */
403 : static bool
4913 tgl 404 UIC 0 : TidRecheck(TidScanState *node, TupleTableSlot *slot)
405 : {
406 : /*
4913 tgl 407 EUB : * XXX shouldn't we check here to make sure tuple matches TID list? In
408 : * runtime-key case this is not certain, is it? However, in the WHERE
409 : * CURRENT OF case it might not match anyway ...
410 : */
4913 tgl 411 UIC 0 : return true;
412 : }
413 :
4913 tgl 414 EUB :
415 : /* ----------------------------------------------------------------
416 : * ExecTidScan(node)
417 : *
418 : * Scans the relation using tids and returns
419 : * the next qualifying tuple in the direction specified.
420 : * We call the ExecScan() routine and pass it the appropriate
421 : * access method functions.
422 : *
423 : * Conditions:
424 : * -- the "cursor" maintained by the AMI is positioned at the tuple
425 : * returned previously.
426 : *
427 : * Initial States:
428 : * -- the relation indicated is opened for scanning so that the
429 : * "cursor" is positioned before the first qualifying tuple.
430 : * -- tss_TidPtr is -1.
431 : * ----------------------------------------------------------------
432 : */
433 : static TupleTableSlot *
2092 andres 434 GIC 564 : ExecTidScan(PlanState *pstate)
435 : {
436 564 : TidScanState *node = castNode(TidScanState, pstate);
2092 andres 437 ECB :
4913 tgl 438 GIC 564 : return ExecScan(&node->ss,
4913 tgl 439 ECB : (ExecScanAccessMtd) TidNext,
440 : (ExecScanRecheckMtd) TidRecheck);
8538 bruce 441 : }
442 :
443 : /* ----------------------------------------------------------------
444 : * ExecReScanTidScan(node)
445 : * ----------------------------------------------------------------
446 : */
447 : void
4654 tgl 448 GIC 9 : ExecReScanTidScan(TidScanState *node)
449 : {
7135 450 9 : if (node->tss_TidList)
7135 tgl 451 CBC 3 : pfree(node->tss_TidList);
7135 tgl 452 GIC 9 : node->tss_TidList = NULL;
7135 tgl 453 CBC 9 : node->tss_NumTids = 0;
7430 454 9 : node->tss_TidPtr = -1;
4913 tgl 455 ECB :
1423 andres 456 : /* not really necessary, but seems good form */
1423 andres 457 CBC 9 : if (node->ss.ss_currentScanDesc)
1423 andres 458 GIC 3 : table_rescan(node->ss.ss_currentScanDesc, NULL);
459 :
4913 tgl 460 CBC 9 : ExecScanReScan(&node->ss);
8538 bruce 461 9 : }
462 :
8538 bruce 463 ECB : /* ----------------------------------------------------------------
464 : * ExecEndTidScan
465 : *
466 : * Releases any storage allocated through C routines.
467 : * Returns nothing.
468 : * ----------------------------------------------------------------
469 : */
470 : void
7430 tgl 471 GIC 299 : ExecEndTidScan(TidScanState *node)
472 : {
1423 andres 473 299 : if (node->ss.ss_currentScanDesc)
1423 andres 474 CBC 275 : table_endscan(node->ss.ss_currentScanDesc);
475 :
7719 tgl 476 ECB : /*
7420 477 : * Free the exprcontext
478 : */
7430 tgl 479 GIC 299 : ExecFreeExprContext(&node->ss.ps);
480 :
481 : /*
7430 tgl 482 ECB : * clear out tuple table slots
483 : */
1612 andres 484 GIC 299 : if (node->ss.ps.ps_ResultTupleSlot)
485 293 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
7430 tgl 486 299 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
8538 bruce 487 CBC 299 : }
8538 bruce 488 ECB :
489 : /* ----------------------------------------------------------------
490 : * ExecInitTidScan
491 : *
492 : * Initializes the tid scan's state information, creates
493 : * scan keys, and opens the base and tid relations.
494 : *
495 : * Parameters:
496 : * node: TidScan node produced by the planner.
497 : * estate: the execution state initialized in InitPlan.
498 : * ----------------------------------------------------------------
499 : */
500 : TidScanState *
6249 tgl 501 GIC 359 : ExecInitTidScan(TidScan *node, EState *estate, int eflags)
502 : {
503 : TidScanState *tidstate;
8538 bruce 504 ECB : Relation currentRelation;
505 :
506 : /*
507 : * create state structure
508 : */
7430 tgl 509 GIC 359 : tidstate = makeNode(TidScanState);
510 359 : tidstate->ss.ps.plan = (Plan *) node;
511 359 : tidstate->ss.ps.state = estate;
2092 andres 512 CBC 359 : tidstate->ss.ps.ExecProcNode = ExecTidScan;
8538 bruce 513 ECB :
8053 514 : /*
7430 tgl 515 : * Miscellaneous initialization
516 : *
517 : * create expression context for node
518 : */
7430 tgl 519 GIC 359 : ExecAssignExprContext(estate, &tidstate->ss.ps);
520 :
521 : /*
7135 tgl 522 ECB : * mark tid list as not computed yet
523 : */
7135 tgl 524 GIC 359 : tidstate->tss_TidList = NULL;
525 359 : tidstate->tss_NumTids = 0;
526 359 : tidstate->tss_TidPtr = -1;
8538 bruce 527 ECB :
8053 528 : /*
1646 tgl 529 : * open the scan relation
530 : */
3634 tgl 531 GIC 359 : currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
532 :
7430 533 359 : tidstate->ss.ss_currentRelation = currentRelation;
2118 tgl 534 CBC 359 : tidstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
535 :
8053 bruce 536 ECB : /*
537 : * get the scan type from the relation descriptor.
538 : */
1878 andres 539 GIC 359 : ExecInitScanTupleSlot(estate, &tidstate->ss,
540 : RelationGetDescr(currentRelation),
541 : table_slot_callbacks(currentRelation));
8538 bruce 542 ECB :
543 : /*
544 : * Initialize result type and projection.
545 : */
1612 andres 546 GIC 359 : ExecInitResultTypeTL(&tidstate->ss.ps);
7370 tgl 547 359 : ExecAssignScanProjectionInfo(&tidstate->ss);
548 :
1878 andres 549 ECB : /*
550 : * initialize child expressions
551 : */
1878 andres 552 GIC 359 : tidstate->ss.ps.qual =
553 359 : ExecInitQual(node->scan.plan.qual, (PlanState *) tidstate);
554 :
1878 andres 555 CBC 359 : TidExprListCreate(tidstate);
1878 andres 556 ECB :
557 : /*
8053 bruce 558 : * all done.
559 : */
7430 tgl 560 GIC 359 : return tidstate;
561 : }
|