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