Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * nodeIndexscan.c
4 : * Routines to support indexed 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/nodeIndexscan.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : /*
16 : * INTERFACE ROUTINES
17 : * ExecIndexScan scans a relation using an index
18 : * IndexNext retrieve next tuple using index
19 : * IndexNextWithReorder same, but recheck ORDER BY expressions
20 : * ExecInitIndexScan creates and initializes state info.
21 : * ExecReScanIndexScan rescans the indexed relation.
22 : * ExecEndIndexScan releases all storage.
23 : * ExecIndexMarkPos marks scan position.
24 : * ExecIndexRestrPos restores scan position.
25 : * ExecIndexScanEstimate estimates DSM space needed for parallel index scan
26 : * ExecIndexScanInitializeDSM initialize DSM for parallel indexscan
27 : * ExecIndexScanReInitializeDSM reinitialize DSM for fresh scan
28 : * ExecIndexScanInitializeWorker attach to DSM info in parallel worker
29 : */
30 : #include "postgres.h"
31 :
32 : #include "access/nbtree.h"
33 : #include "access/relscan.h"
34 : #include "access/tableam.h"
35 : #include "catalog/pg_am.h"
36 : #include "executor/execdebug.h"
37 : #include "executor/nodeIndexscan.h"
38 : #include "lib/pairingheap.h"
39 : #include "miscadmin.h"
40 : #include "nodes/nodeFuncs.h"
41 : #include "utils/array.h"
42 : #include "utils/datum.h"
43 : #include "utils/lsyscache.h"
44 : #include "utils/memutils.h"
45 : #include "utils/rel.h"
46 :
47 : /*
48 : * When an ordering operator is used, tuples fetched from the index that
49 : * need to be reordered are queued in a pairing heap, as ReorderTuples.
50 : */
51 : typedef struct
52 : {
53 : pairingheap_node ph_node;
54 : HeapTuple htup;
55 : Datum *orderbyvals;
56 : bool *orderbynulls;
57 : } ReorderTuple;
58 :
59 : static TupleTableSlot *IndexNext(IndexScanState *node);
60 : static TupleTableSlot *IndexNextWithReorder(IndexScanState *node);
61 : static void EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext);
62 : static bool IndexRecheck(IndexScanState *node, TupleTableSlot *slot);
63 : static int cmp_orderbyvals(const Datum *adist, const bool *anulls,
64 : const Datum *bdist, const bool *bnulls,
65 : IndexScanState *node);
66 : static int reorderqueue_cmp(const pairingheap_node *a,
67 : const pairingheap_node *b, void *arg);
68 : static void reorderqueue_push(IndexScanState *node, TupleTableSlot *slot,
69 : Datum *orderbyvals, bool *orderbynulls);
70 : static HeapTuple reorderqueue_pop(IndexScanState *node);
71 :
72 :
73 : /* ----------------------------------------------------------------
74 : * IndexNext
75 : *
76 : * Retrieve a tuple from the IndexScan node's currentRelation
77 : * using the index specified in the IndexScanState information.
78 : * ----------------------------------------------------------------
79 : */
80 : static TupleTableSlot *
7430 tgl 81 CBC 868995 : IndexNext(IndexScanState *node)
82 : {
83 : EState *estate;
84 : ExprContext *econtext;
85 : ScanDirection direction;
86 : IndexScanDesc scandesc;
87 : TupleTableSlot *slot;
88 :
89 : /*
90 : * extract necessary information from index scan node
91 : */
92 868995 : estate = node->ss.ps.state;
93 :
94 : /*
95 : * Determine which direction to scan the index in based on the plan's scan
96 : * direction and the current direction of execution.
97 : */
67 drowley 98 GNC 868995 : direction = ScanDirectionCombine(estate->es_direction,
99 : ((IndexScan *) node->ss.ps.plan)->indexorderdir);
6558 tgl 100 CBC 868995 : scandesc = node->iss_ScanDesc;
7430 tgl 101 GIC 868995 : econtext = node->ss.ps.ps_ExprContext;
7430 tgl 102 CBC 868995 : slot = node->ss.ss_ScanTupleSlot;
103 :
2223 rhaas 104 GIC 868995 : if (scandesc == NULL)
105 : {
106 : /*
107 : * We reach here if the index scan is not parallel, or if we're
1725 heikki.linnakangas 108 ECB : * serially executing an index scan that was planned to be parallel.
109 : */
2223 rhaas 110 GIC 50080 : scandesc = index_beginscan(node->ss.ss_currentRelation,
111 : node->iss_RelationDesc,
112 : estate->es_snapshot,
113 : node->iss_NumScanKeys,
2223 rhaas 114 ECB : node->iss_NumOrderByKeys);
115 :
2223 rhaas 116 GIC 50080 : node->iss_ScanDesc = scandesc;
117 :
118 : /*
119 : * If no run-time keys to calculate or they are ready, go ahead and
2223 rhaas 120 ECB : * pass the scankeys to the index AM.
121 : */
2223 rhaas 122 CBC 50080 : if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
123 50080 : index_rescan(scandesc,
2223 rhaas 124 GIC 50080 : node->iss_ScanKeys, node->iss_NumScanKeys,
125 50080 : node->iss_OrderByKeys, node->iss_NumOrderByKeys);
126 : }
127 :
128 : /*
4198 tgl 129 ECB : * ok, now that we have what we need, fetch the next tuple.
130 : */
1490 andres 131 CBC 870576 : while (index_getnext_slot(scandesc, direction, slot))
132 : {
2084 andres 133 GIC 704343 : CHECK_FOR_INTERRUPTS();
134 :
135 : /*
136 : * If the index was lossy, we have to recheck the index quals using
4198 tgl 137 ECB : * the fetched tuple.
138 : */
5474 tgl 139 CBC 704343 : if (scandesc->xs_recheck)
5474 tgl 140 ECB : {
5474 tgl 141 GIC 169590 : econtext->ecxt_scantuple = slot;
1896 andres 142 169590 : if (!ExecQualAndReset(node->indexqualorig, econtext))
4217 tgl 143 ECB : {
144 : /* Fails recheck, so drop it and loop back for another */
4217 tgl 145 GIC 1581 : InstrCountFiltered2(node, 1);
146 1581 : continue;
147 : }
5474 tgl 148 ECB : }
149 :
6558 tgl 150 GIC 702762 : return slot;
151 : }
152 :
153 : /*
154 : * if we get here it means the index scan failed so we are at the end of
2886 heikki.linnakangas 155 ECB : * the scan..
156 : */
2886 heikki.linnakangas 157 GIC 166230 : node->iss_ReachedEnd = true;
158 166230 : return ExecClearTuple(slot);
159 : }
160 :
161 : /* ----------------------------------------------------------------
162 : * IndexNextWithReorder
163 : *
164 : * Like IndexNext, but this version can also re-check ORDER BY
165 : * expressions, and reorder the tuples as necessary.
166 : * ----------------------------------------------------------------
2886 heikki.linnakangas 167 ECB : */
168 : static TupleTableSlot *
2886 heikki.linnakangas 169 GIC 41331 : IndexNextWithReorder(IndexScanState *node)
170 : {
171 : EState *estate;
172 : ExprContext *econtext;
2886 heikki.linnakangas 173 ECB : IndexScanDesc scandesc;
174 : TupleTableSlot *slot;
2886 heikki.linnakangas 175 GIC 41331 : ReorderTuple *topmost = NULL;
176 : bool was_exact;
177 : Datum *lastfetched_vals;
178 : bool *lastfetched_nulls;
2886 heikki.linnakangas 179 ECB : int cmp;
180 :
2223 rhaas 181 GIC 41331 : estate = node->ss.ps.state;
182 :
183 : /*
184 : * Only forward scan is supported with reordering. Note: we can get away
185 : * with just Asserting here because the system will not try to run the
186 : * plan backwards if ExecSupportsBackwardScan() says it won't work.
187 : * Currently, that is guaranteed because no index AMs support both
188 : * amcanorderbyop and amcanbackward; if any ever do,
189 : * ExecSupportsBackwardScan() will need to consider indexorderbys
2880 tgl 190 ECB : * explicitly.
191 : */
2886 heikki.linnakangas 192 GIC 41331 : Assert(!ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir));
2223 rhaas 193 CBC 41331 : Assert(ScanDirectionIsForward(estate->es_direction));
2880 tgl 194 ECB :
2886 heikki.linnakangas 195 CBC 41331 : scandesc = node->iss_ScanDesc;
2886 heikki.linnakangas 196 GIC 41331 : econtext = node->ss.ps.ps_ExprContext;
1451 andres 197 CBC 41331 : slot = node->ss.ss_ScanTupleSlot;
198 :
2223 rhaas 199 GIC 41331 : if (scandesc == NULL)
200 : {
201 : /*
202 : * We reach here if the index scan is not parallel, or if we're
1725 heikki.linnakangas 203 ECB : * serially executing an index scan that was planned to be parallel.
204 : */
2223 rhaas 205 GIC 23 : scandesc = index_beginscan(node->ss.ss_currentRelation,
206 : node->iss_RelationDesc,
207 : estate->es_snapshot,
208 : node->iss_NumScanKeys,
2223 rhaas 209 ECB : node->iss_NumOrderByKeys);
210 :
2223 rhaas 211 GIC 23 : node->iss_ScanDesc = scandesc;
212 :
213 : /*
214 : * If no run-time keys to calculate or they are ready, go ahead and
2223 rhaas 215 ECB : * pass the scankeys to the index AM.
216 : */
2223 rhaas 217 CBC 23 : if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
218 23 : index_rescan(scandesc,
2223 rhaas 219 GIC 23 : node->iss_ScanKeys, node->iss_NumScanKeys,
220 23 : node->iss_OrderByKeys, node->iss_NumOrderByKeys);
221 : }
222 :
2886 heikki.linnakangas 223 ECB : for (;;)
224 : {
2084 andres 225 GIC 43928 : CHECK_FOR_INTERRUPTS();
226 :
227 : /*
228 : * Check the reorder queue first. If the topmost tuple in the queue
229 : * has an ORDER BY value smaller than (or equal to) the value last
2886 heikki.linnakangas 230 ECB : * returned by the index, we can return it now.
231 : */
2886 heikki.linnakangas 232 CBC 43928 : if (!pairingheap_is_empty(node->iss_ReorderQueue))
233 : {
234 5125 : topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
2886 heikki.linnakangas 235 ECB :
2886 heikki.linnakangas 236 CBC 10247 : if (node->iss_ReachedEnd ||
237 5122 : cmp_orderbyvals(topmost->orderbyvals,
238 5122 : topmost->orderbynulls,
2886 heikki.linnakangas 239 GIC 5122 : scandesc->xs_orderbyvals,
240 5122 : scandesc->xs_orderbynulls,
241 : node) <= 0)
242 : {
1418 tgl 243 ECB : HeapTuple tuple;
244 :
2886 heikki.linnakangas 245 GIC 2538 : tuple = reorderqueue_pop(node);
2886 heikki.linnakangas 246 ECB :
247 : /* Pass 'true', as the tuple in the queue is a palloc'd copy */
1451 andres 248 GIC 2538 : ExecForceStoreHeapTuple(tuple, slot, true);
2886 heikki.linnakangas 249 2538 : return slot;
2886 heikki.linnakangas 250 ECB : }
251 : }
2886 heikki.linnakangas 252 GIC 38803 : else if (node->iss_ReachedEnd)
2886 heikki.linnakangas 253 ECB : {
254 : /* Queue is empty, and no more tuples from index. We're done. */
1451 andres 255 GIC 9 : return ExecClearTuple(slot);
256 : }
257 :
258 : /*
2886 heikki.linnakangas 259 ECB : * Fetch next tuple from the index.
260 : */
2886 heikki.linnakangas 261 GIC 41381 : next_indextuple:
1490 andres 262 43451 : if (!index_getnext_slot(scandesc, ForwardScanDirection, slot))
263 : {
264 : /*
265 : * No more tuples from the index. But we still need to drain any
2886 heikki.linnakangas 266 ECB : * remaining tuples from the queue before we're done.
267 : */
2886 heikki.linnakangas 268 GIC 9 : node->iss_ReachedEnd = true;
269 9 : continue;
270 : }
271 :
272 : /*
273 : * If the index was lossy, we have to recheck the index quals and
2886 heikki.linnakangas 274 ECB : * ORDER BY expressions using the fetched tuple.
275 : */
2886 heikki.linnakangas 276 CBC 43442 : if (scandesc->xs_recheck)
2886 heikki.linnakangas 277 ECB : {
2886 heikki.linnakangas 278 GIC 4563 : econtext->ecxt_scantuple = slot;
1896 andres 279 4563 : if (!ExecQualAndReset(node->indexqualorig, econtext))
2886 heikki.linnakangas 280 ECB : {
281 : /* Fails recheck, so drop it and loop back for another */
2886 heikki.linnakangas 282 CBC 2070 : InstrCountFiltered2(node, 1);
2084 andres 283 ECB : /* allow this loop to be cancellable */
2084 andres 284 GIC 2070 : CHECK_FOR_INTERRUPTS();
2886 heikki.linnakangas 285 2070 : goto next_indextuple;
286 : }
2886 heikki.linnakangas 287 ECB : }
288 :
2886 heikki.linnakangas 289 CBC 41372 : if (scandesc->xs_recheckorderby)
2886 heikki.linnakangas 290 ECB : {
2886 heikki.linnakangas 291 CBC 2650 : econtext->ecxt_scantuple = slot;
2886 heikki.linnakangas 292 GIC 2650 : ResetExprContext(econtext);
293 2650 : EvalOrderByExpressions(node, econtext);
294 :
295 : /*
296 : * Was the ORDER BY value returned by the index accurate? The
297 : * recheck flag means that the index can return inaccurate values,
298 : * but then again, the value returned for any particular tuple
299 : * could also be exactly correct. Compare the value returned by
300 : * the index with the recalculated value. (If the value returned
301 : * by the index happened to be exact right, we can often avoid
2886 heikki.linnakangas 302 ECB : * pushing the tuple to the queue, just to pop it back out again.)
303 : */
2886 heikki.linnakangas 304 CBC 2650 : cmp = cmp_orderbyvals(node->iss_OrderByValues,
305 2650 : node->iss_OrderByNulls,
2886 heikki.linnakangas 306 GIC 2650 : scandesc->xs_orderbyvals,
2886 heikki.linnakangas 307 CBC 2650 : scandesc->xs_orderbynulls,
2886 heikki.linnakangas 308 EUB : node);
2886 heikki.linnakangas 309 CBC 2650 : if (cmp < 0)
2886 heikki.linnakangas 310 LBC 0 : elog(ERROR, "index returned tuples in wrong order");
2886 heikki.linnakangas 311 GIC 2650 : else if (cmp == 0)
2886 heikki.linnakangas 312 CBC 65 : was_exact = true;
2886 heikki.linnakangas 313 ECB : else
2886 heikki.linnakangas 314 CBC 2585 : was_exact = false;
2886 heikki.linnakangas 315 GIC 2650 : lastfetched_vals = node->iss_OrderByValues;
316 2650 : lastfetched_nulls = node->iss_OrderByNulls;
317 : }
2886 heikki.linnakangas 318 ECB : else
319 : {
2886 heikki.linnakangas 320 CBC 38722 : was_exact = true;
2886 heikki.linnakangas 321 GIC 38722 : lastfetched_vals = scandesc->xs_orderbyvals;
322 38722 : lastfetched_nulls = scandesc->xs_orderbynulls;
323 : }
324 :
325 : /*
326 : * Can we return this tuple immediately, or does it need to be pushed
327 : * to the reorder queue? If the ORDER BY expression values returned
328 : * by the index were inaccurate, we can't return it yet, because the
329 : * next tuple from the index might need to come before this one. Also,
330 : * we can't return it yet if there are any smaller tuples in the queue
2878 bruce 331 ECB : * already.
332 : */
2886 heikki.linnakangas 333 CBC 41415 : if (!was_exact || (topmost && cmp_orderbyvals(lastfetched_vals,
2886 heikki.linnakangas 334 ECB : lastfetched_nulls,
2886 heikki.linnakangas 335 GIC 43 : topmost->orderbyvals,
336 43 : topmost->orderbynulls,
337 : node) > 0))
2886 heikki.linnakangas 338 ECB : {
339 : /* Put this tuple to the queue */
1490 andres 340 GIC 2588 : reorderqueue_push(node, slot, lastfetched_vals, lastfetched_nulls);
2886 heikki.linnakangas 341 2588 : continue;
342 : }
343 : else
2886 heikki.linnakangas 344 ECB : {
345 : /* Can return this tuple immediately. */
2886 heikki.linnakangas 346 GIC 38784 : return slot;
347 : }
348 : }
349 :
350 : /*
351 : * if we get here it means the index scan failed so we are at the end of
352 : * the scan..
353 : */
354 : return ExecClearTuple(slot);
355 : }
356 :
357 : /*
358 : * Calculate the expressions in the ORDER BY clause, based on the heap tuple.
2886 heikki.linnakangas 359 ECB : */
360 : static void
2886 heikki.linnakangas 361 GIC 2650 : EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
362 : {
363 : int i;
364 : ListCell *l;
2886 heikki.linnakangas 365 ECB : MemoryContext oldContext;
366 :
2886 heikki.linnakangas 367 CBC 2650 : oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
2886 heikki.linnakangas 368 ECB :
2886 heikki.linnakangas 369 GIC 2650 : i = 0;
2886 heikki.linnakangas 370 CBC 5300 : foreach(l, node->indexorderbyorig)
371 : {
372 2650 : ExprState *orderby = (ExprState *) lfirst(l);
373 :
374 5300 : node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
2886 heikki.linnakangas 375 ECB : econtext,
2271 andres 376 GIC 2650 : &node->iss_OrderByNulls[i]);
2886 heikki.linnakangas 377 2650 : i++;
2886 heikki.linnakangas 378 ECB : }
379 :
2886 heikki.linnakangas 380 GIC 2650 : MemoryContextSwitchTo(oldContext);
381 2650 : }
382 :
383 : /*
384 : * IndexRecheck -- access method routine to recheck a tuple in EvalPlanQual
4913 tgl 385 ECB : */
386 : static bool
4913 tgl 387 GIC 39 : IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
388 : {
389 : ExprContext *econtext;
390 :
391 : /*
4913 tgl 392 ECB : * extract necessary information from index scan node
393 : */
4913 tgl 394 GIC 39 : econtext = node->ss.ps.ps_ExprContext;
4913 tgl 395 ECB :
396 : /* Does the tuple meet the indexqual condition? */
4913 tgl 397 GIC 39 : econtext->ecxt_scantuple = slot;
1896 andres 398 39 : return ExecQualAndReset(node->indexqualorig, econtext);
399 : }
400 :
401 :
402 : /*
403 : * Compare ORDER BY expression values.
2886 heikki.linnakangas 404 ECB : */
405 : static int
2886 heikki.linnakangas 406 GIC 14610 : cmp_orderbyvals(const Datum *adist, const bool *anulls,
407 : const Datum *bdist, const bool *bnulls,
408 : IndexScanState *node)
409 : {
410 : int i;
2886 heikki.linnakangas 411 ECB : int result;
412 :
2886 heikki.linnakangas 413 CBC 14705 : for (i = 0; i < node->iss_NumOrderByKeys; i++)
414 : {
2886 heikki.linnakangas 415 GIC 14610 : SortSupport ssup = &node->iss_SortSupport[i];
416 :
417 : /*
418 : * Handle nulls. We only need to support NULLS LAST ordering, because
419 : * match_pathkeys_to_index() doesn't consider indexorderby
2880 tgl 420 ECB : * implementation otherwise.
2880 tgl 421 EUB : */
2886 heikki.linnakangas 422 CBC 14610 : if (anulls[i] && !bnulls[i])
2886 heikki.linnakangas 423 UBC 0 : return 1;
2886 heikki.linnakangas 424 CBC 14610 : else if (!anulls[i] && bnulls[i])
2886 heikki.linnakangas 425 UBC 0 : return -1;
2886 heikki.linnakangas 426 GIC 14610 : else if (anulls[i] && bnulls[i])
2886 heikki.linnakangas 427 LBC 0 : return 0;
2886 heikki.linnakangas 428 ECB :
2886 heikki.linnakangas 429 CBC 14610 : result = ssup->comparator(adist[i], bdist[i], ssup);
2886 heikki.linnakangas 430 GIC 14610 : if (result != 0)
431 14515 : return result;
2886 heikki.linnakangas 432 ECB : }
433 :
2886 heikki.linnakangas 434 GIC 95 : return 0;
435 : }
436 :
437 : /*
438 : * Pairing heap provides getting topmost (greatest) element while KNN provides
439 : * ascending sort. That's why we invert the sort order.
2886 heikki.linnakangas 440 ECB : */
441 : static int
2886 heikki.linnakangas 442 GIC 6795 : reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b,
2886 heikki.linnakangas 443 ECB : void *arg)
444 : {
2886 heikki.linnakangas 445 CBC 6795 : ReorderTuple *rta = (ReorderTuple *) a;
2886 heikki.linnakangas 446 GIC 6795 : ReorderTuple *rtb = (ReorderTuple *) b;
447 6795 : IndexScanState *node = (IndexScanState *) arg;
2886 heikki.linnakangas 448 ECB :
1647 tgl 449 : /* exchange argument order to invert the sort order */
1647 tgl 450 GIC 13590 : return cmp_orderbyvals(rtb->orderbyvals, rtb->orderbynulls,
451 6795 : rta->orderbyvals, rta->orderbynulls,
452 : node);
453 : }
454 :
455 : /*
456 : * Helper function to push a tuple to the reorder queue.
2886 heikki.linnakangas 457 ECB : */
458 : static void
1490 andres 459 GIC 2588 : reorderqueue_push(IndexScanState *node, TupleTableSlot *slot,
2886 heikki.linnakangas 460 ECB : Datum *orderbyvals, bool *orderbynulls)
461 : {
2886 heikki.linnakangas 462 CBC 2588 : IndexScanDesc scandesc = node->iss_ScanDesc;
2886 heikki.linnakangas 463 GIC 2588 : EState *estate = node->ss.ps.state;
464 2588 : MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
465 : ReorderTuple *rt;
2886 heikki.linnakangas 466 ECB : int i;
467 :
2886 heikki.linnakangas 468 CBC 2588 : rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
1490 andres 469 2588 : rt->htup = ExecCopySlotHeapTuple(slot);
2886 heikki.linnakangas 470 2588 : rt->orderbyvals =
471 2588 : (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
472 2588 : rt->orderbynulls =
2886 heikki.linnakangas 473 GIC 2588 : (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
2886 heikki.linnakangas 474 CBC 5176 : for (i = 0; i < node->iss_NumOrderByKeys; i++)
2886 heikki.linnakangas 475 ECB : {
2886 heikki.linnakangas 476 CBC 2588 : if (!orderbynulls[i])
477 2588 : rt->orderbyvals[i] = datumCopy(orderbyvals[i],
2886 heikki.linnakangas 478 GIC 2588 : node->iss_OrderByTypByVals[i],
2886 heikki.linnakangas 479 GBC 2588 : node->iss_OrderByTypLens[i]);
2886 heikki.linnakangas 480 ECB : else
2886 heikki.linnakangas 481 UIC 0 : rt->orderbyvals[i] = (Datum) 0;
2886 heikki.linnakangas 482 CBC 2588 : rt->orderbynulls[i] = orderbynulls[i];
483 : }
484 2588 : pairingheap_add(node->iss_ReorderQueue, &rt->ph_node);
2886 heikki.linnakangas 485 ECB :
2886 heikki.linnakangas 486 GIC 2588 : MemoryContextSwitchTo(oldContext);
487 2588 : }
488 :
489 : /*
490 : * Helper function to pop the next tuple from the reorder queue.
2886 heikki.linnakangas 491 ECB : */
492 : static HeapTuple
2886 heikki.linnakangas 493 GIC 2568 : reorderqueue_pop(IndexScanState *node)
494 : {
495 : HeapTuple result;
496 : ReorderTuple *topmost;
2878 tgl 497 ECB : int i;
498 :
2886 heikki.linnakangas 499 CBC 2568 : topmost = (ReorderTuple *) pairingheap_remove_first(node->iss_ReorderQueue);
2886 heikki.linnakangas 500 ECB :
2886 heikki.linnakangas 501 GIC 2568 : result = topmost->htup;
2878 tgl 502 CBC 5136 : for (i = 0; i < node->iss_NumOrderByKeys; i++)
2878 tgl 503 EUB : {
2878 tgl 504 GIC 2568 : if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
2878 tgl 505 LBC 0 : pfree(DatumGetPointer(topmost->orderbyvals[i]));
2878 tgl 506 ECB : }
2886 heikki.linnakangas 507 CBC 2568 : pfree(topmost->orderbyvals);
2886 heikki.linnakangas 508 GIC 2568 : pfree(topmost->orderbynulls);
2886 heikki.linnakangas 509 CBC 2568 : pfree(topmost);
510 :
2886 heikki.linnakangas 511 GIC 2568 : return result;
512 : }
513 :
514 :
515 : /* ----------------------------------------------------------------
516 : * ExecIndexScan(node)
517 : * ----------------------------------------------------------------
9770 scrappy 518 ECB : */
519 : static TupleTableSlot *
2092 andres 520 CBC 836403 : ExecIndexScan(PlanState *pstate)
521 : {
2092 andres 522 GIC 836403 : IndexScanState *node = castNode(IndexScanState, pstate);
523 :
524 : /*
6385 bruce 525 ECB : * If we have runtime keys and they've not already been set up, do it now.
8274 tgl 526 : */
6344 tgl 527 GIC 836403 : if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
4654 tgl 528 CBC 7504 : ExecReScan((PlanState *) node);
8274 tgl 529 ECB :
2886 heikki.linnakangas 530 GIC 836400 : if (node->iss_NumOrderByKeys > 0)
531 41331 : return ExecScan(&node->ss,
532 : (ExecScanAccessMtd) IndexNextWithReorder,
2886 heikki.linnakangas 533 ECB : (ExecScanRecheckMtd) IndexRecheck);
534 : else
2886 heikki.linnakangas 535 GIC 795069 : return ExecScan(&node->ss,
536 : (ExecScanAccessMtd) IndexNext,
537 : (ExecScanRecheckMtd) IndexRecheck);
538 : }
539 :
540 : /* ----------------------------------------------------------------
541 : * ExecReScanIndexScan(node)
542 : *
543 : * Recalculates the values of any scan keys whose value depends on
544 : * information known at runtime, then rescans the indexed relation.
545 : *
546 : * Updating the scan key was formerly done separately in
547 : * ExecUpdateIndexScanKeys. Integrating it into ReScan makes
548 : * rescans of indices and relations/general streams more uniform.
549 : * ----------------------------------------------------------------
9770 scrappy 550 ECB : */
551 : void
4654 tgl 552 GIC 165861 : ExecReScanIndexScan(IndexScanState *node)
553 : {
554 : /*
555 : * If we are doing runtime key calculations (ie, any of the index key
556 : * values weren't simple Consts), compute the new key values. But first,
557 : * reset the context so we don't leak memory as each outer tuple is
558 : * scanned. Note this assumes that we will recalculate *all* runtime keys
4654 tgl 559 ECB : * on each call.
560 : */
6344 tgl 561 CBC 165861 : if (node->iss_NumRuntimeKeys != 0)
562 : {
4654 563 161429 : ExprContext *econtext = node->iss_RuntimeContext;
4654 tgl 564 ECB :
4654 tgl 565 GIC 161429 : ResetExprContext(econtext);
6558 566 161429 : ExecIndexEvalRuntimeKeys(econtext,
567 : node->iss_RuntimeKeys,
6344 tgl 568 ECB : node->iss_NumRuntimeKeys);
569 : }
6344 tgl 570 GIC 165858 : node->iss_RuntimeKeysReady = true;
7727 tgl 571 ECB :
572 : /* flush the reorder queue */
2876 heikki.linnakangas 573 GIC 165858 : if (node->iss_ReorderQueue)
574 : {
419 akorotkov 575 ECB : HeapTuple tuple;
576 :
2876 heikki.linnakangas 577 CBC 63 : while (!pairingheap_is_empty(node->iss_ReorderQueue))
419 akorotkov 578 ECB : {
419 akorotkov 579 GIC 30 : tuple = reorderqueue_pop(node);
580 30 : heap_freetuple(tuple);
581 : }
582 : }
2876 heikki.linnakangas 583 ECB :
2048 tgl 584 : /* reset index scan */
2244 rhaas 585 CBC 165858 : if (node->iss_ScanDesc)
586 144121 : index_rescan(node->iss_ScanDesc,
587 144121 : node->iss_ScanKeys, node->iss_NumScanKeys,
2244 rhaas 588 GIC 144121 : node->iss_OrderByKeys, node->iss_NumOrderByKeys);
2876 heikki.linnakangas 589 CBC 165858 : node->iss_ReachedEnd = false;
4913 tgl 590 ECB :
4913 tgl 591 GIC 165858 : ExecScanReScan(&node->ss);
6558 592 165858 : }
593 :
594 :
595 : /*
596 : * ExecIndexEvalRuntimeKeys
597 : * Evaluate any runtime key values, and update the scankeys.
6558 tgl 598 ECB : */
599 : void
6558 tgl 600 GIC 204818 : ExecIndexEvalRuntimeKeys(ExprContext *econtext,
601 : IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
602 : {
603 : int j;
604 : MemoryContext oldContext;
4977 tgl 605 ECB :
606 : /* We want to keep the key values in per-tuple memory */
4977 tgl 607 CBC 204818 : oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
608 :
6344 609 418740 : for (j = 0; j < numRuntimeKeys; j++)
6558 tgl 610 ECB : {
6344 tgl 611 GIC 213925 : ScanKey scan_key = runtimeKeys[j].scan_key;
612 213925 : ExprState *key_expr = runtimeKeys[j].key_expr;
613 : Datum scanvalue;
614 : bool isNull;
615 :
616 : /*
617 : * For each run-time key, extract the run-time expression and evaluate
618 : * it with respect to the current context. We then stick the result
619 : * into the proper scan key.
620 : *
621 : * Note: the result of the eval could be a pass-by-ref value that's
622 : * stored in some outer scan's tuple, not in
623 : * econtext->ecxt_per_tuple_memory. We assume that the outer tuple
624 : * will stay put throughout our scan. If this is wrong, we could copy
625 : * the result into our context explicitly, but I think that's not
626 : * necessary.
627 : *
628 : * It's also entirely possible that the result of the eval is a
629 : * toasted value. In this case we should forcibly detoast it, to
630 : * avoid repeat detoastings each time the value is examined by an
4790 bruce 631 ECB : * index support function.
632 : */
4977 tgl 633 GIC 213925 : scanvalue = ExecEvalExpr(key_expr,
4977 tgl 634 ECB : econtext,
635 : &isNull);
6344 tgl 636 CBC 213922 : if (isNull)
4977 tgl 637 ECB : {
4977 tgl 638 GIC 1277 : scan_key->sk_argument = scanvalue;
6344 639 1277 : scan_key->sk_flags |= SK_ISNULL;
640 : }
6344 tgl 641 ECB : else
4977 642 : {
4977 tgl 643 CBC 212645 : if (runtimeKeys[j].key_toastable)
644 1650 : scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
4977 tgl 645 GIC 212645 : scan_key->sk_argument = scanvalue;
6344 646 212645 : scan_key->sk_flags &= ~SK_ISNULL;
647 : }
6344 tgl 648 ECB : }
4977 649 :
4977 tgl 650 GIC 204815 : MemoryContextSwitchTo(oldContext);
6344 651 204815 : }
652 :
653 : /*
654 : * ExecIndexEvalArrayKeys
655 : * Evaluate any array key values, and set up to iterate through arrays.
656 : *
657 : * Returns true if there are array elements to consider; false means there
658 : * is at least one null or empty array, so no match is possible. On true
659 : * result, the scankeys are initialized with the first elements of the arrays.
6344 tgl 660 ECB : */
661 : bool
6344 tgl 662 GIC 12 : ExecIndexEvalArrayKeys(ExprContext *econtext,
6344 tgl 663 ECB : IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
664 : {
6344 tgl 665 GIC 12 : bool result = true;
666 : int j;
667 : MemoryContext oldContext;
6344 tgl 668 ECB :
669 : /* We want to keep the arrays in per-tuple memory */
6344 tgl 670 CBC 12 : oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
671 :
672 24 : for (j = 0; j < numArrayKeys; j++)
6344 tgl 673 ECB : {
6344 tgl 674 GIC 12 : ScanKey scan_key = arrayKeys[j].scan_key;
675 12 : ExprState *array_expr = arrayKeys[j].array_expr;
676 : Datum arraydatum;
677 : bool isNull;
678 : ArrayType *arrayval;
679 : int16 elmlen;
680 : bool elmbyval;
681 : char elmalign;
682 : int num_elems;
683 : Datum *elem_values;
684 : bool *elem_nulls;
685 :
686 : /*
687 : * Compute and deconstruct the array expression. (Notes in
6031 bruce 688 ECB : * ExecIndexEvalRuntimeKeys() apply here too.)
689 : */
6344 tgl 690 GIC 12 : arraydatum = ExecEvalExpr(array_expr,
6344 tgl 691 ECB : econtext,
692 : &isNull);
6344 tgl 693 GBC 12 : if (isNull)
6558 tgl 694 EUB : {
6344 tgl 695 UIC 0 : result = false;
6344 tgl 696 LBC 0 : break; /* no point in evaluating more */
697 : }
6344 tgl 698 CBC 12 : arrayval = DatumGetArrayTypeP(arraydatum);
699 : /* We could cache this data, but not clear it's worth it */
700 12 : get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
701 : &elmlen, &elmbyval, &elmalign);
6344 tgl 702 GIC 12 : deconstruct_array(arrayval,
703 : ARR_ELEMTYPE(arrayval),
6344 tgl 704 ECB : elmlen, elmbyval, elmalign,
705 : &elem_values, &elem_nulls, &num_elems);
6344 tgl 706 GBC 12 : if (num_elems <= 0)
6344 tgl 707 EUB : {
6344 tgl 708 UIC 0 : result = false;
709 0 : break; /* no point in evaluating more */
710 : }
711 :
712 : /*
713 : * Note: we expect the previous array data, if any, to be
714 : * automatically freed by resetting the per-tuple context; hence no
6031 bruce 715 ECB : * pfree's here.
6344 tgl 716 : */
6344 tgl 717 CBC 12 : arrayKeys[j].elem_values = elem_values;
718 12 : arrayKeys[j].elem_nulls = elem_nulls;
719 12 : arrayKeys[j].num_elems = num_elems;
6344 tgl 720 GBC 12 : scan_key->sk_argument = elem_values[0];
6344 tgl 721 GIC 12 : if (elem_nulls[0])
6344 tgl 722 LBC 0 : scan_key->sk_flags |= SK_ISNULL;
6344 tgl 723 ECB : else
6344 tgl 724 GIC 12 : scan_key->sk_flags &= ~SK_ISNULL;
725 12 : arrayKeys[j].next_elem = 1;
6344 tgl 726 ECB : }
727 :
6344 tgl 728 CBC 12 : MemoryContextSwitchTo(oldContext);
729 :
6344 tgl 730 GIC 12 : return result;
731 : }
732 :
733 : /*
734 : * ExecIndexAdvanceArrayKeys
735 : * Advance to the next set of array key values, if any.
736 : *
737 : * Returns true if there is another set of values to consider, false if not.
738 : * On true result, the scankeys are initialized with the next set of values.
6344 tgl 739 ECB : */
740 : bool
6344 tgl 741 CBC 8703 : ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
742 : {
6344 tgl 743 GIC 8703 : bool found = false;
744 : int j;
745 :
746 : /*
747 : * Note we advance the rightmost array key most quickly, since it will
748 : * correspond to the lowest-order index column among the available
749 : * qualifications. This is hypothesized to result in better locality of
5050 bruce 750 ECB : * access in the index.
751 : */
5500 tgl 752 CBC 8715 : for (j = numArrayKeys - 1; j >= 0; j--)
6344 tgl 753 ECB : {
6344 tgl 754 CBC 24 : ScanKey scan_key = arrayKeys[j].scan_key;
755 24 : int next_elem = arrayKeys[j].next_elem;
756 24 : int num_elems = arrayKeys[j].num_elems;
6344 tgl 757 GIC 24 : Datum *elem_values = arrayKeys[j].elem_values;
6344 tgl 758 CBC 24 : bool *elem_nulls = arrayKeys[j].elem_nulls;
759 :
760 24 : if (next_elem >= num_elems)
6344 tgl 761 ECB : {
6344 tgl 762 GIC 12 : next_elem = 0;
763 12 : found = false; /* need to advance next array key */
6558 tgl 764 ECB : }
6344 765 : else
6344 tgl 766 CBC 12 : found = true;
6344 tgl 767 GBC 24 : scan_key->sk_argument = elem_values[next_elem];
6344 tgl 768 GIC 24 : if (elem_nulls[next_elem])
6344 tgl 769 LBC 0 : scan_key->sk_flags |= SK_ISNULL;
6344 tgl 770 ECB : else
6344 tgl 771 CBC 24 : scan_key->sk_flags &= ~SK_ISNULL;
772 24 : arrayKeys[j].next_elem = next_elem + 1;
6344 tgl 773 GIC 24 : if (found)
774 12 : break;
7727 tgl 775 ECB : }
776 :
6344 tgl 777 GIC 8703 : return found;
778 : }
779 :
780 :
781 : /* ----------------------------------------------------------------
782 : * ExecEndIndexScan
783 : * ----------------------------------------------------------------
9770 scrappy 784 ECB : */
785 : void
7430 tgl 786 GIC 59729 : ExecEndIndexScan(IndexScanState *node)
787 : {
788 : Relation indexRelationDesc;
789 : IndexScanDesc indexScanDesc;
790 :
791 : /*
8053 bruce 792 ECB : * extract information from the node
9345 793 : */
6558 tgl 794 GIC 59729 : indexRelationDesc = node->iss_RelationDesc;
795 59729 : indexScanDesc = node->iss_ScanDesc;
796 :
797 : /*
798 : * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext
799 : */
800 : #ifdef NOT_USED
801 : ExecFreeExprContext(&node->ss.ps);
802 : if (node->iss_RuntimeContext)
803 : FreeExprContext(node->iss_RuntimeContext, true);
804 : #endif
805 :
806 : /*
7420 tgl 807 ECB : * clear out tuple table slots
808 : */
1612 andres 809 CBC 59729 : if (node->ss.ps.ps_ResultTupleSlot)
1612 andres 810 GIC 22522 : ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
7420 tgl 811 59729 : ExecClearTuple(node->ss.ss_ScanTupleSlot);
812 :
813 : /*
5798 tgl 814 ECB : * close the index relation (no-op if we didn't open it)
7719 815 : */
5798 tgl 816 CBC 59729 : if (indexScanDesc)
817 49854 : index_endscan(indexScanDesc);
818 59729 : if (indexRelationDesc)
5798 tgl 819 GIC 58546 : index_close(indexRelationDesc, NoLock);
9770 scrappy 820 59729 : }
821 :
822 : /* ----------------------------------------------------------------
823 : * ExecIndexMarkPos
824 : *
825 : * Note: we assume that no caller attempts to set a mark before having read
826 : * at least one tuple. Otherwise, iss_ScanDesc might still be NULL.
827 : * ----------------------------------------------------------------
9770 scrappy 828 ECB : */
829 : void
7430 tgl 830 CBC 3025 : ExecIndexMarkPos(IndexScanState *node)
9770 scrappy 831 ECB : {
1898 tgl 832 GIC 3025 : EState *estate = node->ss.ps.state;
1312 andres 833 CBC 3025 : EPQState *epqstate = estate->es_epq_active;
834 :
1312 andres 835 GIC 3025 : if (epqstate != NULL)
836 : {
837 : /*
838 : * We are inside an EvalPlanQual recheck. If a test tuple exists for
839 : * this relation, then we shouldn't access the index at all. We would
840 : * instead need to save, and later restore, the state of the
841 : * relsubs_done flag, so that re-fetching the test tuple is possible.
842 : * However, given the assumption that no caller sets a mark at the
843 : * start of the scan, we can only get here with relsubs_done[i]
1898 tgl 844 ECB : * already set, and so no state need be saved.
845 : */
1898 tgl 846 CBC 1 : Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
1898 tgl 847 ECB :
1898 tgl 848 GBC 1 : Assert(scanrelid > 0);
1312 andres 849 GIC 1 : if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
1312 andres 850 UIC 0 : epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
1898 tgl 851 ECB : {
1898 tgl 852 EUB : /* Verify the claim above */
1312 andres 853 CBC 1 : if (!epqstate->relsubs_done[scanrelid - 1])
1898 tgl 854 UIC 0 : elog(ERROR, "unexpected ExecIndexMarkPos call in EPQ recheck");
1898 tgl 855 GIC 1 : return;
856 : }
1898 tgl 857 ECB : }
858 :
6558 tgl 859 GIC 3024 : index_markpos(node->iss_ScanDesc);
860 : }
861 :
862 : /* ----------------------------------------------------------------
863 : * ExecIndexRestrPos
864 : * ----------------------------------------------------------------
9770 scrappy 865 ECB : */
866 : void
7430 tgl 867 CBC 27012 : ExecIndexRestrPos(IndexScanState *node)
9770 scrappy 868 ECB : {
1898 tgl 869 GIC 27012 : EState *estate = node->ss.ps.state;
1312 andres 870 CBC 27012 : EPQState *epqstate = estate->es_epq_active;
871 :
1312 andres 872 GIC 27012 : if (estate->es_epq_active != NULL)
1898 tgl 873 EUB : {
874 : /* See comments in ExecIndexMarkPos */
1898 tgl 875 UBC 0 : Index scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
1898 tgl 876 EUB :
1898 tgl 877 UBC 0 : Assert(scanrelid > 0);
1312 andres 878 UIC 0 : if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
879 0 : epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
1898 tgl 880 EUB : {
881 : /* Verify the claim above */
1312 andres 882 UBC 0 : if (!epqstate->relsubs_done[scanrelid - 1])
1898 tgl 883 UIC 0 : elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
884 0 : return;
885 : }
1898 tgl 886 ECB : }
887 :
6558 tgl 888 GIC 27012 : index_restrpos(node->iss_ScanDesc);
889 : }
890 :
891 : /* ----------------------------------------------------------------
892 : * ExecInitIndexScan
893 : *
894 : * Initializes the index scan's state information, creates
895 : * scan keys, and opens the base and index relations.
896 : *
897 : * Note: index scans have 2 sets of state information because
898 : * we have to keep track of the base relation and the
899 : * index relation.
900 : * ----------------------------------------------------------------
9770 scrappy 901 ECB : */
902 : IndexScanState *
6249 tgl 903 GIC 60052 : ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
904 : {
905 : IndexScanState *indexstate;
906 : Relation currentRelation;
907 : LOCKMODE lockmode;
908 :
909 : /*
7430 tgl 910 ECB : * create state structure
9345 bruce 911 : */
7430 tgl 912 CBC 60052 : indexstate = makeNode(IndexScanState);
913 60052 : indexstate->ss.ps.plan = (Plan *) node;
7430 tgl 914 GIC 60052 : indexstate->ss.ps.state = estate;
2092 andres 915 60052 : indexstate->ss.ps.ExecProcNode = ExecIndexScan;
916 :
917 : /*
918 : * Miscellaneous initialization
919 : *
7430 tgl 920 ECB : * create expression context for node
921 : */
7430 tgl 922 GIC 60052 : ExecAssignExprContext(estate, &indexstate->ss.ps);
923 :
924 : /*
1646 tgl 925 ECB : * open the scan relation
926 : */
1878 andres 927 CBC 60052 : currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
1878 andres 928 ECB :
1878 andres 929 GIC 60052 : indexstate->ss.ss_currentRelation = currentRelation;
930 60052 : indexstate->ss.ss_currentScanDesc = NULL; /* no heap scan here */
931 :
932 : /*
1878 andres 933 ECB : * get the scan type from the relation descriptor.
934 : */
1878 andres 935 GIC 60052 : ExecInitScanTupleSlot(estate, &indexstate->ss,
936 : RelationGetDescr(currentRelation),
937 : table_slot_callbacks(currentRelation));
938 :
939 : /*
1612 andres 940 ECB : * Initialize result type and projection.
1878 941 : */
1612 andres 942 GIC 60052 : ExecInitResultTypeTL(&indexstate->ss.ps);
1878 943 60052 : ExecAssignScanProjectionInfo(&indexstate->ss);
944 :
945 : /*
946 : * initialize child expressions
947 : *
948 : * Note: we don't initialize all of the indexqual expression, only the
949 : * sub-parts corresponding to runtime keys (see below). Likewise for
950 : * indexorderby, if any. But the indexqualorig expression is always
951 : * initialized even though it will only be used in some uncommon cases ---
952 : * would be nice to improve that. (Problem is that any SubPlans present
4511 tgl 953 ECB : * in the expression must be found now...)
9345 bruce 954 : */
2217 andres 955 CBC 60052 : indexstate->ss.ps.qual =
956 60052 : ExecInitQual(node->scan.plan.qual, (PlanState *) indexstate);
957 60052 : indexstate->indexqualorig =
958 60052 : ExecInitQual(node->indexqualorig, (PlanState *) indexstate);
2217 andres 959 GIC 60052 : indexstate->indexorderbyorig =
960 60052 : ExecInitExprList(node->indexorderbyorig, (PlanState *) indexstate);
961 :
962 : /*
963 : * If we are just doing EXPLAIN (ie, aren't going to run the plan), stop
964 : * here. This allows an index-advisor plugin to EXPLAIN a plan containing
5624 bruce 965 ECB : * references to nonexistent indexes.
5798 tgl 966 : */
5798 tgl 967 GIC 60052 : if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
968 1183 : return indexstate;
5798 tgl 969 ECB :
1466 970 : /* Open the index relation. */
1466 tgl 971 GIC 58869 : lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
972 58869 : indexstate->iss_RelationDesc = index_open(node->indexid, lockmode);
973 :
974 : /*
7430 tgl 975 ECB : * Initialize index-specific scan state
8053 bruce 976 : */
8274 tgl 977 CBC 58869 : indexstate->iss_RuntimeKeysReady = false;
4511 tgl 978 GIC 58869 : indexstate->iss_RuntimeKeys = NULL;
979 58869 : indexstate->iss_NumRuntimeKeys = 0;
980 :
981 : /*
8053 bruce 982 ECB : * build the index scan keys from the index qualification
983 : */
6344 tgl 984 GIC 58869 : ExecIndexBuildScanKeys((PlanState *) indexstate,
985 : indexstate->iss_RelationDesc,
6344 tgl 986 ECB : node->indexqual,
987 : false,
6344 tgl 988 GIC 58869 : &indexstate->iss_ScanKeys,
989 : &indexstate->iss_NumScanKeys,
990 : &indexstate->iss_RuntimeKeys,
991 : &indexstate->iss_NumRuntimeKeys,
992 : NULL, /* no ArrayKeys */
993 : NULL);
994 :
995 : /*
4511 tgl 996 ECB : * any ORDER BY exprs have to be turned into scankeys in the same way
997 : */
4511 tgl 998 GIC 58869 : ExecIndexBuildScanKeys((PlanState *) indexstate,
999 : indexstate->iss_RelationDesc,
4511 tgl 1000 ECB : node->indexorderby,
1001 : true,
4511 tgl 1002 GIC 58869 : &indexstate->iss_OrderByKeys,
1003 : &indexstate->iss_NumOrderByKeys,
1004 : &indexstate->iss_RuntimeKeys,
1005 : &indexstate->iss_NumRuntimeKeys,
1006 : NULL, /* no ArrayKeys */
1007 : NULL);
4511 tgl 1008 ECB :
1009 : /* Initialize sort support, if we need to re-check ORDER BY exprs */
2886 heikki.linnakangas 1010 CBC 58869 : if (indexstate->iss_NumOrderByKeys > 0)
1011 : {
2886 heikki.linnakangas 1012 GIC 23 : int numOrderByKeys = indexstate->iss_NumOrderByKeys;
1013 : int i;
1014 : ListCell *lco;
1015 : ListCell *lcx;
1016 :
1017 : /*
1018 : * Prepare sort support, and look up the data type for each ORDER BY
2880 tgl 1019 ECB : * expression.
2886 heikki.linnakangas 1020 : */
2884 tgl 1021 CBC 23 : Assert(numOrderByKeys == list_length(node->indexorderbyops));
2880 1022 23 : Assert(numOrderByKeys == list_length(node->indexorderbyorig));
1023 23 : indexstate->iss_SortSupport = (SortSupportData *)
2886 heikki.linnakangas 1024 23 : palloc0(numOrderByKeys * sizeof(SortSupportData));
2880 tgl 1025 23 : indexstate->iss_OrderByTypByVals = (bool *)
2886 heikki.linnakangas 1026 23 : palloc(numOrderByKeys * sizeof(bool));
2880 tgl 1027 23 : indexstate->iss_OrderByTypLens = (int16 *)
2886 heikki.linnakangas 1028 23 : palloc(numOrderByKeys * sizeof(int16));
2884 tgl 1029 GIC 23 : i = 0;
2880 tgl 1030 CBC 46 : forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
2886 heikki.linnakangas 1031 ECB : {
2880 tgl 1032 CBC 23 : Oid orderbyop = lfirst_oid(lco);
1033 23 : Node *orderbyexpr = (Node *) lfirst(lcx);
1034 23 : Oid orderbyType = exprType(orderbyexpr);
2499 tgl 1035 GIC 23 : Oid orderbyColl = exprCollation(orderbyexpr);
1036 23 : SortSupport orderbysort = &indexstate->iss_SortSupport[i];
2499 tgl 1037 ECB :
1038 : /* Initialize sort support */
2499 tgl 1039 GIC 23 : orderbysort->ssup_cxt = CurrentMemoryContext;
2499 tgl 1040 CBC 23 : orderbysort->ssup_collation = orderbyColl;
1041 : /* See cmp_orderbyvals() comments on NULLS LAST */
1042 23 : orderbysort->ssup_nulls_first = false;
1043 : /* ssup_attno is unused here and elsewhere */
1044 23 : orderbysort->ssup_attno = 0;
2499 tgl 1045 ECB : /* No abbreviation */
2499 tgl 1046 GIC 23 : orderbysort->abbreviate = false;
2499 tgl 1047 CBC 23 : PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
2886 heikki.linnakangas 1048 ECB :
2886 heikki.linnakangas 1049 CBC 23 : get_typlenbyval(orderbyType,
1050 23 : &indexstate->iss_OrderByTypLens[i],
2886 heikki.linnakangas 1051 GIC 23 : &indexstate->iss_OrderByTypByVals[i]);
2884 tgl 1052 23 : i++;
1053 : }
2886 heikki.linnakangas 1054 ECB :
1055 : /* allocate arrays to hold the re-calculated distances */
2880 tgl 1056 CBC 23 : indexstate->iss_OrderByValues = (Datum *)
1057 23 : palloc(numOrderByKeys * sizeof(Datum));
2880 tgl 1058 GIC 23 : indexstate->iss_OrderByNulls = (bool *)
1059 23 : palloc(numOrderByKeys * sizeof(bool));
2886 heikki.linnakangas 1060 ECB :
1061 : /* and initialize the reorder queue */
2886 heikki.linnakangas 1062 GIC 23 : indexstate->iss_ReorderQueue = pairingheap_allocate(reorderqueue_cmp,
1063 : indexstate);
1064 : }
1065 :
1066 : /*
1067 : * If we have runtime keys, we need an ExprContext to evaluate them. The
1068 : * node's standard context won't do because we want to reset that context
1069 : * for every tuple. So, build another context just like the other one...
6385 bruce 1070 ECB : * -tgl 7/11/00
1071 : */
6344 tgl 1072 CBC 58869 : if (indexstate->iss_NumRuntimeKeys != 0)
1073 : {
7430 1074 26059 : ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
8306 tgl 1075 ECB :
7430 tgl 1076 CBC 26059 : ExecAssignExprContext(estate, &indexstate->ss.ps);
7430 tgl 1077 GIC 26059 : indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
1078 26059 : indexstate->ss.ps.ps_ExprContext = stdecontext;
1079 : }
9345 bruce 1080 ECB : else
1081 : {
8306 tgl 1082 GIC 32810 : indexstate->iss_RuntimeContext = NULL;
1083 : }
1084 :
1085 : /*
8053 bruce 1086 ECB : * all done.
1087 : */
7430 tgl 1088 GIC 58869 : return indexstate;
1089 : }
1090 :
1091 :
1092 : /*
1093 : * ExecIndexBuildScanKeys
1094 : * Build the index scan keys from the index qualification expressions
1095 : *
1096 : * The index quals are passed to the index AM in the form of a ScanKey array.
1097 : * This routine sets up the ScanKeys, fills in all constant fields of the
1098 : * ScanKeys, and prepares information about the keys that have non-constant
1099 : * comparison values. We divide index qual expressions into five types:
1100 : *
1101 : * 1. Simple operator with constant comparison value ("indexkey op constant").
1102 : * For these, we just fill in a ScanKey containing the constant value.
1103 : *
1104 : * 2. Simple operator with non-constant value ("indexkey op expression").
1105 : * For these, we create a ScanKey with everything filled in except the
1106 : * expression value, and set up an IndexRuntimeKeyInfo struct to drive
1107 : * evaluation of the expression at the right times.
1108 : *
1109 : * 3. RowCompareExpr ("(indexkey, indexkey, ...) op (expr, expr, ...)").
1110 : * For these, we create a header ScanKey plus a subsidiary ScanKey array,
1111 : * as specified in access/skey.h. The elements of the row comparison
1112 : * can have either constant or non-constant comparison values.
1113 : *
1114 : * 4. ScalarArrayOpExpr ("indexkey op ANY (array-expression)"). If the index
1115 : * supports amsearcharray, we handle these the same as simple operators,
1116 : * setting the SK_SEARCHARRAY flag to tell the AM to handle them. Otherwise,
1117 : * we create a ScanKey with everything filled in except the comparison value,
1118 : * and set up an IndexArrayKeyInfo struct to drive processing of the qual.
1119 : * (Note that if we use an IndexArrayKeyInfo struct, the array expression is
1120 : * always treated as requiring runtime evaluation, even if it's a constant.)
1121 : *
1122 : * 5. NullTest ("indexkey IS NULL/IS NOT NULL"). We just fill in the
1123 : * ScanKey properly.
1124 : *
1125 : * This code is also used to prepare ORDER BY expressions for amcanorderbyop
1126 : * indexes. The behavior is exactly the same, except that we have to look up
1127 : * the operator differently. Note that only cases 1 and 2 are currently
1128 : * possible for ORDER BY.
1129 : *
1130 : * Input params are:
1131 : *
1132 : * planstate: executor state node we are working for
1133 : * index: the index we are building scan keys for
1134 : * quals: indexquals (or indexorderbys) expressions
1135 : * isorderby: true if processing ORDER BY exprs, false if processing quals
1136 : * *runtimeKeys: ptr to pre-existing IndexRuntimeKeyInfos, or NULL if none
1137 : * *numRuntimeKeys: number of pre-existing runtime keys
1138 : *
1139 : * Output params are:
1140 : *
1141 : * *scanKeys: receives ptr to array of ScanKeys
1142 : * *numScanKeys: receives number of scankeys
1143 : * *runtimeKeys: receives ptr to array of IndexRuntimeKeyInfos, or NULL if none
1144 : * *numRuntimeKeys: receives number of runtime keys
1145 : * *arrayKeys: receives ptr to array of IndexArrayKeyInfos, or NULL if none
1146 : * *numArrayKeys: receives number of array keys
1147 : *
1148 : * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
1149 : * IndexArrayKeyInfos are not supported.
6558 tgl 1150 ECB : */
1151 : void
4198 tgl 1152 GIC 137858 : ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
1153 : List *quals, bool isorderby,
1154 : ScanKey *scanKeys, int *numScanKeys,
1155 : IndexRuntimeKeyInfo **runtimeKeys, int *numRuntimeKeys,
1156 : IndexArrayKeyInfo **arrayKeys, int *numArrayKeys)
1157 : {
1158 : ListCell *qual_cell;
1159 : ScanKey scan_keys;
1160 : IndexRuntimeKeyInfo *runtime_keys;
1161 : IndexArrayKeyInfo *array_keys;
1162 : int n_scan_keys;
1163 : int n_runtime_keys;
1164 : int max_runtime_keys;
1165 : int n_array_keys;
1166 : int j;
6558 tgl 1167 ECB :
4511 1168 : /* Allocate array for ScanKey structs: one per qual */
4511 tgl 1169 GIC 137858 : n_scan_keys = list_length(quals);
1170 137858 : scan_keys = (ScanKey) palloc(n_scan_keys * sizeof(ScanKeyData));
1171 :
1172 : /*
1173 : * runtime_keys array is dynamically resized as needed. We handle it this
1174 : * way so that the same runtime keys array can be shared between
1175 : * indexquals and indexorderbys, which will be processed in separate calls
1176 : * of this function. Caller must be sure to pass in NULL/0 for first
4382 bruce 1177 ECB : * call.
6283 tgl 1178 : */
4511 tgl 1179 GIC 137858 : runtime_keys = *runtimeKeys;
1180 137858 : n_runtime_keys = max_runtime_keys = *numRuntimeKeys;
1181 :
4511 tgl 1182 ECB : /* Allocate array_keys as large as it could possibly need to be */
6344 1183 : array_keys = (IndexArrayKeyInfo *)
6344 tgl 1184 GIC 137858 : palloc0(n_scan_keys * sizeof(IndexArrayKeyInfo));
1185 137858 : n_array_keys = 0;
1186 :
1187 : /*
1188 : * for each opclause in the given qual, convert the opclause into a single
5050 bruce 1189 ECB : * scan key
6558 tgl 1190 : */
5474 tgl 1191 GIC 137858 : j = 0;
5474 tgl 1192 CBC 221261 : foreach(qual_cell, quals)
6558 tgl 1193 ECB : {
5474 tgl 1194 GIC 83403 : Expr *clause = (Expr *) lfirst(qual_cell);
1195 83403 : ScanKey this_scan_key = &scan_keys[j++];
1196 : Oid opno; /* operator's OID */
1197 : RegProcedure opfuncid; /* operator proc id used in scan */
1198 : Oid opfamily; /* opfamily of index column */
1199 : int op_strategy; /* operator's strategy number */
1200 : Oid op_lefttype; /* operator's declared input types */
1201 : Oid op_righttype;
1202 : Expr *leftop; /* expr on lhs of operator */
1203 : Expr *rightop; /* expr on rhs ... */
1204 : AttrNumber varattno; /* att number used in scan */
1828 teodor 1205 ECB : int indnkeyatts;
6558 tgl 1206 :
1828 teodor 1207 GIC 83403 : indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
6344 tgl 1208 83403 : if (IsA(clause, OpExpr))
6344 tgl 1209 ECB : {
1210 : /* indexkey op const or indexkey op expression */
6344 tgl 1211 GIC 82659 : int flags = 0;
6344 tgl 1212 ECB : Datum scanvalue;
6558 1213 :
5474 tgl 1214 GIC 82659 : opno = ((OpExpr *) clause)->opno;
6344 1215 82659 : opfuncid = ((OpExpr *) clause)->opfuncid;
1216 :
1217 : /*
6344 tgl 1218 ECB : * leftop should be the index key Var, possibly relabeled
1219 : */
6344 tgl 1220 CBC 82659 : leftop = (Expr *) get_leftop(clause);
6558 tgl 1221 EUB :
6344 tgl 1222 GIC 82659 : if (leftop && IsA(leftop, RelabelType))
6344 tgl 1223 LBC 0 : leftop = ((RelabelType *) leftop)->arg;
1224 :
6344 tgl 1225 CBC 82659 : Assert(leftop != NULL);
6558 tgl 1226 ECB :
6344 tgl 1227 GBC 82659 : if (!(IsA(leftop, Var) &&
4198 tgl 1228 GIC 82659 : ((Var *) leftop)->varno == INDEX_VAR))
6344 tgl 1229 LBC 0 : elog(ERROR, "indexqual doesn't have key on left side");
6558 tgl 1230 ECB :
6344 tgl 1231 GBC 82659 : varattno = ((Var *) leftop)->varattno;
1828 teodor 1232 GIC 82659 : if (varattno < 1 || varattno > indnkeyatts)
5474 tgl 1233 UIC 0 : elog(ERROR, "bogus index qualification");
1234 :
1235 : /*
1236 : * We have to look up the operator's strategy number. This
5474 tgl 1237 ECB : * provides a cross-check that the operator does match the index.
1238 : */
5474 tgl 1239 CBC 82659 : opfamily = index->rd_opfamily[varattno - 1];
1240 :
4511 tgl 1241 GIC 82659 : get_op_opfamily_properties(opno, opfamily, isorderby,
1242 : &op_strategy,
1243 : &op_lefttype,
5474 tgl 1244 ECB : &op_righttype);
6558 1245 :
4511 tgl 1246 GIC 82659 : if (isorderby)
1247 99 : flags |= SK_ORDER_BY;
1248 :
1249 : /*
6344 tgl 1250 ECB : * rightop is the constant or variable comparison value
1251 : */
6344 tgl 1252 CBC 82659 : rightop = (Expr *) get_rightop(clause);
6558 tgl 1253 ECB :
6344 tgl 1254 GIC 82659 : if (rightop && IsA(rightop, RelabelType))
6344 tgl 1255 CBC 393 : rightop = ((RelabelType *) rightop)->arg;
1256 :
1257 82659 : Assert(rightop != NULL);
1258 :
6344 tgl 1259 GIC 82659 : if (IsA(rightop, Const))
6344 tgl 1260 ECB : {
1261 : /* OK, simple constant comparison value */
6344 tgl 1262 GBC 51084 : scanvalue = ((Const *) rightop)->constvalue;
6344 tgl 1263 GIC 51084 : if (((Const *) rightop)->constisnull)
6344 tgl 1264 UIC 0 : flags |= SK_ISNULL;
1265 : }
1266 : else
6344 tgl 1267 ECB : {
1268 : /* Need to treat this one as a runtime key */
4511 tgl 1269 CBC 31575 : if (n_runtime_keys >= max_runtime_keys)
1270 : {
1271 27810 : if (max_runtime_keys == 0)
1272 : {
1273 27807 : max_runtime_keys = 8;
1274 : runtime_keys = (IndexRuntimeKeyInfo *)
4511 tgl 1275 GIC 27807 : palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1276 : }
4511 tgl 1277 ECB : else
1278 : {
4511 tgl 1279 CBC 3 : max_runtime_keys *= 2;
1280 : runtime_keys = (IndexRuntimeKeyInfo *)
4511 tgl 1281 GIC 3 : repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
4511 tgl 1282 ECB : }
1283 : }
6344 tgl 1284 CBC 31575 : runtime_keys[n_runtime_keys].scan_key = this_scan_key;
1285 63150 : runtime_keys[n_runtime_keys].key_expr =
1286 31575 : ExecInitExpr(rightop, planstate);
4977 1287 31575 : runtime_keys[n_runtime_keys].key_toastable =
1288 31575 : TypeIsToastable(op_righttype);
6344 tgl 1289 GIC 31575 : n_runtime_keys++;
1290 31575 : scanvalue = (Datum) 0;
1291 : }
1292 :
1293 : /*
6344 tgl 1294 ECB : * initialize the scan key's fields appropriately
1295 : */
6344 tgl 1296 GIC 82659 : ScanKeyEntryInitialize(this_scan_key,
1297 : flags,
1298 : varattno, /* attribute number to scan */
1299 : op_strategy, /* op's strategy */
1300 : op_righttype, /* strategy subtype */
1301 : ((OpExpr *) clause)->inputcollid, /* collation */
1302 : opfuncid, /* reg proc to use */
6344 tgl 1303 ECB : scanvalue); /* constant */
1304 : }
6283 tgl 1305 GIC 744 : else if (IsA(clause, RowCompareExpr))
6283 tgl 1306 ECB : {
1307 : /* (indexkey, indexkey, ...) op (expression, expression, ...) */
6283 tgl 1308 GIC 18 : RowCompareExpr *rc = (RowCompareExpr *) clause;
1309 : ScanKey first_sub_key;
1310 : int n_sub_key;
1311 : ListCell *largs_cell;
1312 : ListCell *rargs_cell;
1313 : ListCell *opnos_cell;
1501 tgl 1314 ECB : ListCell *collids_cell;
1315 :
4511 tgl 1316 GIC 18 : Assert(!isorderby);
4511 tgl 1317 ECB :
1318 : first_sub_key = (ScanKey)
4511 tgl 1319 GIC 18 : palloc(list_length(rc->opnos) * sizeof(ScanKeyData));
1320 18 : n_sub_key = 0;
6283 tgl 1321 ECB :
1322 : /* Scan RowCompare columns and generate subsidiary ScanKey items */
1501 tgl 1323 GIC 54 : forfour(largs_cell, rc->largs, rargs_cell, rc->rargs,
1501 tgl 1324 ECB : opnos_cell, rc->opnos, collids_cell, rc->inputcollids)
6283 1325 : {
4511 tgl 1326 GIC 36 : ScanKey this_sub_key = &first_sub_key[n_sub_key];
6283 1327 36 : int flags = SK_ROW_MEMBER;
1328 : Datum scanvalue;
4404 tgl 1329 ECB : Oid inputcollation;
6283 1330 :
1501 tgl 1331 CBC 36 : leftop = (Expr *) lfirst(largs_cell);
1332 36 : rightop = (Expr *) lfirst(rargs_cell);
1501 tgl 1333 GIC 36 : opno = lfirst_oid(opnos_cell);
1334 36 : inputcollation = lfirst_oid(collids_cell);
1335 :
1336 : /*
6283 tgl 1337 ECB : * leftop should be the index key Var, possibly relabeled
6283 tgl 1338 EUB : */
6283 tgl 1339 GIC 36 : if (leftop && IsA(leftop, RelabelType))
6283 tgl 1340 LBC 0 : leftop = ((RelabelType *) leftop)->arg;
1341 :
6283 tgl 1342 CBC 36 : Assert(leftop != NULL);
6283 tgl 1343 ECB :
6283 tgl 1344 GBC 36 : if (!(IsA(leftop, Var) &&
4198 tgl 1345 GIC 36 : ((Var *) leftop)->varno == INDEX_VAR))
6283 tgl 1346 LBC 0 : elog(ERROR, "indexqual doesn't have key on left side");
1347 :
6283 tgl 1348 GIC 36 : varattno = ((Var *) leftop)->varattno;
1349 :
1350 : /*
1351 : * We have to look up the operator's associated btree support
4977 tgl 1352 ECB : * function
1353 : */
4977 tgl 1354 GBC 36 : if (index->rd_rel->relam != BTREE_AM_OID ||
1828 teodor 1355 CBC 36 : varattno < 1 || varattno > indnkeyatts)
4977 tgl 1356 UIC 0 : elog(ERROR, "bogus RowCompare index qualification");
4977 tgl 1357 CBC 36 : opfamily = index->rd_opfamily[varattno - 1];
1358 :
4511 tgl 1359 GIC 36 : get_op_opfamily_properties(opno, opfamily, isorderby,
1360 : &op_strategy,
1361 : &op_lefttype,
4977 tgl 1362 ECB : &op_righttype);
4977 tgl 1363 EUB :
4977 tgl 1364 GIC 36 : if (op_strategy != rc->rctype)
4977 tgl 1365 LBC 0 : elog(ERROR, "RowCompare index qualification contains wrong operator");
1366 :
4977 tgl 1367 GIC 36 : opfuncid = get_opfamily_proc(opfamily,
1368 : op_lefttype,
4977 tgl 1369 ECB : op_righttype,
4977 tgl 1370 EUB : BTORDER_PROC);
2085 tgl 1371 GIC 36 : if (!RegProcedureIsValid(opfuncid))
2085 tgl 1372 UIC 0 : elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
1373 : BTORDER_PROC, op_lefttype, op_righttype, opfamily);
1374 :
1375 : /*
6283 tgl 1376 ECB : * rightop is the constant or variable comparison value
6283 tgl 1377 EUB : */
6283 tgl 1378 GIC 36 : if (rightop && IsA(rightop, RelabelType))
6283 tgl 1379 LBC 0 : rightop = ((RelabelType *) rightop)->arg;
1380 :
6283 tgl 1381 CBC 36 : Assert(rightop != NULL);
1382 :
6283 tgl 1383 GIC 36 : if (IsA(rightop, Const))
6283 tgl 1384 ECB : {
1385 : /* OK, simple constant comparison value */
6283 tgl 1386 GBC 36 : scanvalue = ((Const *) rightop)->constvalue;
6283 tgl 1387 GIC 36 : if (((Const *) rightop)->constisnull)
6283 tgl 1388 UIC 0 : flags |= SK_ISNULL;
1389 : }
1390 : else
6283 tgl 1391 EUB : {
1392 : /* Need to treat this one as a runtime key */
4511 tgl 1393 UBC 0 : if (n_runtime_keys >= max_runtime_keys)
1394 : {
1395 0 : if (max_runtime_keys == 0)
1396 : {
1397 0 : max_runtime_keys = 8;
1398 : runtime_keys = (IndexRuntimeKeyInfo *)
4511 tgl 1399 UIC 0 : palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1400 : }
4511 tgl 1401 EUB : else
1402 : {
4511 tgl 1403 UBC 0 : max_runtime_keys *= 2;
1404 : runtime_keys = (IndexRuntimeKeyInfo *)
4511 tgl 1405 UIC 0 : repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
4511 tgl 1406 EUB : }
1407 : }
6283 tgl 1408 UBC 0 : runtime_keys[n_runtime_keys].scan_key = this_sub_key;
1409 0 : runtime_keys[n_runtime_keys].key_expr =
1410 0 : ExecInitExpr(rightop, planstate);
4977 1411 0 : runtime_keys[n_runtime_keys].key_toastable =
1412 0 : TypeIsToastable(op_righttype);
6283 tgl 1413 UIC 0 : n_runtime_keys++;
1414 0 : scanvalue = (Datum) 0;
1415 : }
1416 :
1417 : /*
6283 tgl 1418 ECB : * initialize the subsidiary scan key's fields appropriately
1419 : */
6283 tgl 1420 GIC 36 : ScanKeyEntryInitialize(this_sub_key,
1421 : flags,
1422 : varattno, /* attribute number */
1423 : op_strategy, /* op's strategy */
1424 : op_righttype, /* strategy subtype */
1425 : inputcollation, /* collation */
2118 tgl 1426 ECB : opfuncid, /* reg proc to use */
1427 : scanvalue); /* constant */
4511 tgl 1428 GIC 36 : n_sub_key++;
1429 : }
6283 tgl 1430 ECB :
1431 : /* Mark the last subsidiary scankey correctly */
4511 tgl 1432 GIC 18 : first_sub_key[n_sub_key - 1].sk_flags |= SK_ROW_END;
1433 :
1434 : /*
1435 : * We don't use ScanKeyEntryInitialize for the header because it
6031 bruce 1436 ECB : * isn't going to contain a valid sk_func pointer.
6283 tgl 1437 : */
6283 tgl 1438 CBC 180 : MemSet(this_scan_key, 0, sizeof(ScanKeyData));
1439 18 : this_scan_key->sk_flags = SK_ROW_HEADER;
6283 tgl 1440 GIC 18 : this_scan_key->sk_attno = first_sub_key->sk_attno;
6283 tgl 1441 CBC 18 : this_scan_key->sk_strategy = rc->rctype;
1442 : /* sk_subtype, sk_collation, sk_func not used in a header */
1443 18 : this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
1444 : }
6344 tgl 1445 GIC 726 : else if (IsA(clause, ScalarArrayOpExpr))
6558 tgl 1446 ECB : {
6344 1447 : /* indexkey op ANY (array-expression) */
6344 tgl 1448 GIC 375 : ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
4193 1449 375 : int flags = 0;
4193 tgl 1450 ECB : Datum scanvalue;
1451 :
4511 tgl 1452 CBC 375 : Assert(!isorderby);
4511 tgl 1453 ECB :
6344 tgl 1454 CBC 375 : Assert(saop->useOr);
5474 tgl 1455 GIC 375 : opno = saop->opno;
6344 1456 375 : opfuncid = saop->opfuncid;
1457 :
1458 : /*
6344 tgl 1459 ECB : * leftop should be the index key Var, possibly relabeled
1460 : */
6344 tgl 1461 CBC 375 : leftop = (Expr *) linitial(saop->args);
6558 tgl 1462 EUB :
6344 tgl 1463 GIC 375 : if (leftop && IsA(leftop, RelabelType))
6344 tgl 1464 LBC 0 : leftop = ((RelabelType *) leftop)->arg;
1465 :
6344 tgl 1466 CBC 375 : Assert(leftop != NULL);
6344 tgl 1467 ECB :
6344 tgl 1468 GBC 375 : if (!(IsA(leftop, Var) &&
4198 tgl 1469 GIC 375 : ((Var *) leftop)->varno == INDEX_VAR))
6344 tgl 1470 LBC 0 : elog(ERROR, "indexqual doesn't have key on left side");
6344 tgl 1471 ECB :
6344 tgl 1472 GBC 375 : varattno = ((Var *) leftop)->varattno;
1828 teodor 1473 GIC 375 : if (varattno < 1 || varattno > indnkeyatts)
5474 tgl 1474 UIC 0 : elog(ERROR, "bogus index qualification");
1475 :
1476 : /*
1477 : * We have to look up the operator's strategy number. This
5474 tgl 1478 ECB : * provides a cross-check that the operator does match the index.
1479 : */
5474 tgl 1480 CBC 375 : opfamily = index->rd_opfamily[varattno - 1];
1481 :
4511 tgl 1482 GIC 375 : get_op_opfamily_properties(opno, opfamily, isorderby,
1483 : &op_strategy,
1484 : &op_lefttype,
1485 : &op_righttype);
1486 :
1487 : /*
6344 tgl 1488 ECB : * rightop is the constant or variable array value
1489 : */
6344 tgl 1490 CBC 375 : rightop = (Expr *) lsecond(saop->args);
6344 tgl 1491 EUB :
6344 tgl 1492 GIC 375 : if (rightop && IsA(rightop, RelabelType))
6344 tgl 1493 LBC 0 : rightop = ((RelabelType *) rightop)->arg;
1494 :
6344 tgl 1495 CBC 375 : Assert(rightop != NULL);
1496 :
1539 andres 1497 GIC 375 : if (index->rd_indam->amsearcharray)
4193 tgl 1498 ECB : {
1499 : /* Index AM will handle this like a simple operator */
4193 tgl 1500 GIC 363 : flags |= SK_SEARCHARRAY;
1501 363 : if (IsA(rightop, Const))
4193 tgl 1502 ECB : {
1503 : /* OK, simple constant comparison value */
4193 tgl 1504 GBC 357 : scanvalue = ((Const *) rightop)->constvalue;
4193 tgl 1505 GIC 357 : if (((Const *) rightop)->constisnull)
4193 tgl 1506 UIC 0 : flags |= SK_ISNULL;
1507 : }
1508 : else
4193 tgl 1509 ECB : {
1510 : /* Need to treat this one as a runtime key */
4193 tgl 1511 CBC 6 : if (n_runtime_keys >= max_runtime_keys)
1512 : {
1513 6 : if (max_runtime_keys == 0)
1514 : {
1515 6 : max_runtime_keys = 8;
1516 : runtime_keys = (IndexRuntimeKeyInfo *)
4193 tgl 1517 GIC 6 : palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
1518 : }
4193 tgl 1519 EUB : else
1520 : {
4193 tgl 1521 UBC 0 : max_runtime_keys *= 2;
1522 : runtime_keys = (IndexRuntimeKeyInfo *)
4193 tgl 1523 UIC 0 : repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
4193 tgl 1524 ECB : }
1525 : }
4193 tgl 1526 CBC 6 : runtime_keys[n_runtime_keys].scan_key = this_scan_key;
4193 tgl 1527 GIC 12 : runtime_keys[n_runtime_keys].key_expr =
1528 6 : ExecInitExpr(rightop, planstate);
1529 :
1530 : /*
1531 : * Careful here: the runtime expression is not of
1532 : * op_righttype, but rather is an array of same; so
1533 : * TypeIsToastable() isn't helpful. However, we can
4193 tgl 1534 ECB : * assume that all array types are toastable.
1535 : */
4193 tgl 1536 CBC 6 : runtime_keys[n_runtime_keys].key_toastable = true;
4193 tgl 1537 GIC 6 : n_runtime_keys++;
1538 6 : scanvalue = (Datum) 0;
1539 : }
1540 : }
1541 : else
4193 tgl 1542 ECB : {
1543 : /* Executor has to expand the array value */
4193 tgl 1544 CBC 12 : array_keys[n_array_keys].scan_key = this_scan_key;
4193 tgl 1545 GIC 24 : array_keys[n_array_keys].array_expr =
4193 tgl 1546 CBC 12 : ExecInitExpr(rightop, planstate);
4193 tgl 1547 ECB : /* the remaining fields were zeroed by palloc0 */
4193 tgl 1548 GIC 12 : n_array_keys++;
1549 12 : scanvalue = (Datum) 0;
1550 : }
1551 :
1552 : /*
6344 tgl 1553 ECB : * initialize the scan key's fields appropriately
1554 : */
6344 tgl 1555 GIC 375 : ScanKeyEntryInitialize(this_scan_key,
1556 : flags,
1557 : varattno, /* attribute number to scan */
1558 : op_strategy, /* op's strategy */
1559 : op_righttype, /* strategy subtype */
1560 : saop->inputcollid, /* collation */
1561 : opfuncid, /* reg proc to use */
4193 tgl 1562 ECB : scanvalue); /* constant */
1563 : }
5847 tgl 1564 GIC 351 : else if (IsA(clause, NullTest))
5847 tgl 1565 ECB : {
1566 : /* indexkey IS NULL or indexkey IS NOT NULL */
4846 tgl 1567 GIC 351 : NullTest *ntest = (NullTest *) clause;
4846 tgl 1568 ECB : int flags;
1569 :
4511 tgl 1570 GIC 351 : Assert(!isorderby);
1571 :
1572 : /*
5847 tgl 1573 ECB : * argument should be the index key Var, possibly relabeled
1574 : */
4846 tgl 1575 CBC 351 : leftop = ntest->arg;
5847 tgl 1576 EUB :
5847 tgl 1577 GIC 351 : if (leftop && IsA(leftop, RelabelType))
5847 tgl 1578 LBC 0 : leftop = ((RelabelType *) leftop)->arg;
1579 :
5624 bruce 1580 CBC 351 : Assert(leftop != NULL);
5847 tgl 1581 ECB :
5847 tgl 1582 GBC 351 : if (!(IsA(leftop, Var) &&
4198 tgl 1583 GIC 351 : ((Var *) leftop)->varno == INDEX_VAR))
5847 tgl 1584 LBC 0 : elog(ERROR, "NullTest indexqual has wrong key");
1585 :
5847 tgl 1586 GIC 351 : varattno = ((Var *) leftop)->varattno;
1587 :
1588 : /*
5847 tgl 1589 ECB : * initialize the scan key's fields appropriately
1590 : */
4846 tgl 1591 CBC 351 : switch (ntest->nulltesttype)
4846 tgl 1592 ECB : {
4846 tgl 1593 CBC 88 : case IS_NULL:
1594 88 : flags = SK_ISNULL | SK_SEARCHNULL;
1595 88 : break;
1596 263 : case IS_NOT_NULL:
4846 tgl 1597 GBC 263 : flags = SK_ISNULL | SK_SEARCHNOTNULL;
1598 263 : break;
4846 tgl 1599 UIC 0 : default:
1600 0 : elog(ERROR, "unrecognized nulltesttype: %d",
1601 : (int) ntest->nulltesttype);
1602 : flags = 0; /* keep compiler quiet */
1603 : break;
4846 tgl 1604 ECB : }
1605 :
5847 tgl 1606 GIC 351 : ScanKeyEntryInitialize(this_scan_key,
1607 : flags,
1608 : varattno, /* attribute number to scan */
1609 : InvalidStrategy, /* no strategy */
1610 : InvalidOid, /* no strategy subtype */
1611 : InvalidOid, /* no collation */
1612 : InvalidOid, /* no reg proc for this */
1613 : (Datum) 0); /* constant */
5847 tgl 1614 EUB : }
1615 : else
6344 tgl 1616 UIC 0 : elog(ERROR, "unsupported indexqual type: %d",
1617 : (int) nodeTag(clause));
6558 tgl 1618 ECB : }
1619 :
4511 tgl 1620 GIC 137858 : Assert(n_runtime_keys <= max_runtime_keys);
4511 tgl 1621 ECB :
1622 : /* Get rid of any unused arrays */
6344 tgl 1623 CBC 137858 : if (n_array_keys == 0)
6558 tgl 1624 ECB : {
6344 tgl 1625 GIC 137846 : pfree(array_keys);
1626 137846 : array_keys = NULL;
1627 : }
1628 :
1629 : /*
6344 tgl 1630 ECB : * Return info to our caller.
6558 1631 : */
6558 tgl 1632 CBC 137858 : *scanKeys = scan_keys;
6344 1633 137858 : *numScanKeys = n_scan_keys;
1634 137858 : *runtimeKeys = runtime_keys;
6344 tgl 1635 GIC 137858 : *numRuntimeKeys = n_runtime_keys;
6344 tgl 1636 CBC 137858 : if (arrayKeys)
6344 tgl 1637 ECB : {
6344 tgl 1638 GIC 9070 : *arrayKeys = array_keys;
6344 tgl 1639 CBC 9070 : *numArrayKeys = n_array_keys;
6344 tgl 1640 EUB : }
6344 tgl 1641 CBC 128788 : else if (n_array_keys != 0)
6344 tgl 1642 UIC 0 : elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
7170 tgl 1643 GIC 137858 : }
1644 :
1645 : /* ----------------------------------------------------------------
1646 : * Parallel Scan Support
1647 : * ----------------------------------------------------------------
1648 : */
1649 :
1650 : /* ----------------------------------------------------------------
1651 : * ExecIndexScanEstimate
1652 : *
1653 : * Compute the amount of space we'll need in the parallel
1654 : * query DSM, and inform pcxt->estimator about our needs.
1655 : * ----------------------------------------------------------------
2244 rhaas 1656 ECB : */
1657 : void
2244 rhaas 1658 GIC 6 : ExecIndexScanEstimate(IndexScanState *node,
2244 rhaas 1659 ECB : ParallelContext *pcxt)
1660 : {
2244 rhaas 1661 CBC 6 : EState *estate = node->ss.ps.state;
1662 :
1663 6 : node->iss_PscanLen = index_parallelscan_estimate(node->iss_RelationDesc,
2244 rhaas 1664 ECB : estate->es_snapshot);
2244 rhaas 1665 CBC 6 : shm_toc_estimate_chunk(&pcxt->estimator, node->iss_PscanLen);
2244 rhaas 1666 GIC 6 : shm_toc_estimate_keys(&pcxt->estimator, 1);
1667 6 : }
1668 :
1669 : /* ----------------------------------------------------------------
1670 : * ExecIndexScanInitializeDSM
1671 : *
1672 : * Set up a parallel index scan descriptor.
1673 : * ----------------------------------------------------------------
2244 rhaas 1674 ECB : */
1675 : void
2244 rhaas 1676 GIC 6 : ExecIndexScanInitializeDSM(IndexScanState *node,
2244 rhaas 1677 ECB : ParallelContext *pcxt)
1678 : {
2244 rhaas 1679 GIC 6 : EState *estate = node->ss.ps.state;
2244 rhaas 1680 ECB : ParallelIndexScanDesc piscan;
1681 :
2244 rhaas 1682 GIC 6 : piscan = shm_toc_allocate(pcxt->toc, node->iss_PscanLen);
1683 6 : index_parallelscan_initialize(node->ss.ss_currentRelation,
1684 : node->iss_RelationDesc,
2244 rhaas 1685 ECB : estate->es_snapshot,
1686 : piscan);
2244 rhaas 1687 CBC 6 : shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
2244 rhaas 1688 GIC 6 : node->iss_ScanDesc =
1689 6 : index_beginscan_parallel(node->ss.ss_currentRelation,
1690 : node->iss_RelationDesc,
1691 : node->iss_NumScanKeys,
1692 : node->iss_NumOrderByKeys,
1693 : piscan);
1694 :
1695 : /*
1696 : * If no run-time keys to calculate or they are ready, go ahead and pass
2223 rhaas 1697 ECB : * the scankeys to the index AM.
2244 1698 : */
2223 rhaas 1699 CBC 6 : if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
2244 1700 6 : index_rescan(node->iss_ScanDesc,
1701 6 : node->iss_ScanKeys, node->iss_NumScanKeys,
2244 rhaas 1702 GIC 6 : node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1703 6 : }
1704 :
1705 : /* ----------------------------------------------------------------
1706 : * ExecIndexScanReInitializeDSM
1707 : *
1708 : * Reset shared state before beginning a fresh scan.
1709 : * ----------------------------------------------------------------
2048 tgl 1710 ECB : */
1711 : void
2048 tgl 1712 GIC 6 : ExecIndexScanReInitializeDSM(IndexScanState *node,
2048 tgl 1713 ECB : ParallelContext *pcxt)
1714 : {
2048 tgl 1715 GIC 6 : index_parallelrescan(node->iss_ScanDesc);
1716 6 : }
1717 :
1718 : /* ----------------------------------------------------------------
1719 : * ExecIndexScanInitializeWorker
1720 : *
1721 : * Copy relevant information from TOC into planstate.
1722 : * ----------------------------------------------------------------
2244 rhaas 1723 ECB : */
1724 : void
1970 andres 1725 GIC 48 : ExecIndexScanInitializeWorker(IndexScanState *node,
1726 : ParallelWorkerContext *pwcxt)
1727 : {
2244 rhaas 1728 ECB : ParallelIndexScanDesc piscan;
1729 :
1970 andres 1730 CBC 48 : piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
2244 rhaas 1731 GIC 48 : node->iss_ScanDesc =
1732 48 : index_beginscan_parallel(node->ss.ss_currentRelation,
1733 : node->iss_RelationDesc,
1734 : node->iss_NumScanKeys,
1735 : node->iss_NumOrderByKeys,
1736 : piscan);
1737 :
1738 : /*
1739 : * If no run-time keys to calculate or they are ready, go ahead and pass
2223 rhaas 1740 ECB : * the scankeys to the index AM.
2244 1741 : */
2223 rhaas 1742 CBC 48 : if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
2244 1743 48 : index_rescan(node->iss_ScanDesc,
1744 48 : node->iss_ScanKeys, node->iss_NumScanKeys,
2244 rhaas 1745 GIC 48 : node->iss_OrderByKeys, node->iss_NumOrderByKeys);
1746 48 : }
|