LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeIndexscan.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 89.6 % 558 500 17 26 15 18 288 1 193 25 287 3
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 22 22 21 1 21
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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 *
      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                 :      */
      98 GNC      868995 :     direction = ScanDirectionCombine(estate->es_direction,
      99                 :                                      ((IndexScan *) node->ss.ps.plan)->indexorderdir);
     100 CBC      868995 :     scandesc = node->iss_ScanDesc;
     101 GIC      868995 :     econtext = node->ss.ps.ps_ExprContext;
     102 CBC      868995 :     slot = node->ss.ss_ScanTupleSlot;
     103                 : 
     104 GIC      868995 :     if (scandesc == NULL)
     105                 :     {
     106                 :         /*
     107                 :          * We reach here if the index scan is not parallel, or if we're
     108 ECB             :          * serially executing an index scan that was planned to be parallel.
     109                 :          */
     110 GIC       50080 :         scandesc = index_beginscan(node->ss.ss_currentRelation,
     111                 :                                    node->iss_RelationDesc,
     112                 :                                    estate->es_snapshot,
     113                 :                                    node->iss_NumScanKeys,
     114 ECB             :                                    node->iss_NumOrderByKeys);
     115                 : 
     116 GIC       50080 :         node->iss_ScanDesc = scandesc;
     117                 : 
     118                 :         /*
     119                 :          * If no run-time keys to calculate or they are ready, go ahead and
     120 ECB             :          * pass the scankeys to the index AM.
     121                 :          */
     122 CBC       50080 :         if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
     123           50080 :             index_rescan(scandesc,
     124 GIC       50080 :                          node->iss_ScanKeys, node->iss_NumScanKeys,
     125           50080 :                          node->iss_OrderByKeys, node->iss_NumOrderByKeys);
     126                 :     }
     127                 : 
     128                 :     /*
     129 ECB             :      * ok, now that we have what we need, fetch the next tuple.
     130                 :      */
     131 CBC      870576 :     while (index_getnext_slot(scandesc, direction, slot))
     132                 :     {
     133 GIC      704343 :         CHECK_FOR_INTERRUPTS();
     134                 : 
     135                 :         /*
     136                 :          * If the index was lossy, we have to recheck the index quals using
     137 ECB             :          * the fetched tuple.
     138                 :          */
     139 CBC      704343 :         if (scandesc->xs_recheck)
     140 ECB             :         {
     141 GIC      169590 :             econtext->ecxt_scantuple = slot;
     142          169590 :             if (!ExecQualAndReset(node->indexqualorig, econtext))
     143 ECB             :             {
     144                 :                 /* Fails recheck, so drop it and loop back for another */
     145 GIC        1581 :                 InstrCountFiltered2(node, 1);
     146            1581 :                 continue;
     147                 :             }
     148 ECB             :         }
     149                 : 
     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
     155 ECB             :      * the scan..
     156                 :      */
     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                 :  * ----------------------------------------------------------------
     167 ECB             :  */
     168                 : static TupleTableSlot *
     169 GIC       41331 : IndexNextWithReorder(IndexScanState *node)
     170                 : {
     171                 :     EState     *estate;
     172                 :     ExprContext *econtext;
     173 ECB             :     IndexScanDesc scandesc;
     174                 :     TupleTableSlot *slot;
     175 GIC       41331 :     ReorderTuple *topmost = NULL;
     176                 :     bool        was_exact;
     177                 :     Datum      *lastfetched_vals;
     178                 :     bool       *lastfetched_nulls;
     179 ECB             :     int         cmp;
     180                 : 
     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
     190 ECB             :      * explicitly.
     191                 :      */
     192 GIC       41331 :     Assert(!ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir));
     193 CBC       41331 :     Assert(ScanDirectionIsForward(estate->es_direction));
     194 ECB             : 
     195 CBC       41331 :     scandesc = node->iss_ScanDesc;
     196 GIC       41331 :     econtext = node->ss.ps.ps_ExprContext;
     197 CBC       41331 :     slot = node->ss.ss_ScanTupleSlot;
     198                 : 
     199 GIC       41331 :     if (scandesc == NULL)
     200                 :     {
     201                 :         /*
     202                 :          * We reach here if the index scan is not parallel, or if we're
     203 ECB             :          * serially executing an index scan that was planned to be parallel.
     204                 :          */
     205 GIC          23 :         scandesc = index_beginscan(node->ss.ss_currentRelation,
     206                 :                                    node->iss_RelationDesc,
     207                 :                                    estate->es_snapshot,
     208                 :                                    node->iss_NumScanKeys,
     209 ECB             :                                    node->iss_NumOrderByKeys);
     210                 : 
     211 GIC          23 :         node->iss_ScanDesc = scandesc;
     212                 : 
     213                 :         /*
     214                 :          * If no run-time keys to calculate or they are ready, go ahead and
     215 ECB             :          * pass the scankeys to the index AM.
     216                 :          */
     217 CBC          23 :         if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
     218              23 :             index_rescan(scandesc,
     219 GIC          23 :                          node->iss_ScanKeys, node->iss_NumScanKeys,
     220              23 :                          node->iss_OrderByKeys, node->iss_NumOrderByKeys);
     221                 :     }
     222                 : 
     223 ECB             :     for (;;)
     224                 :     {
     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
     230 ECB             :          * returned by the index, we can return it now.
     231                 :          */
     232 CBC       43928 :         if (!pairingheap_is_empty(node->iss_ReorderQueue))
     233                 :         {
     234            5125 :             topmost = (ReorderTuple *) pairingheap_first(node->iss_ReorderQueue);
     235 ECB             : 
     236 CBC       10247 :             if (node->iss_ReachedEnd ||
     237            5122 :                 cmp_orderbyvals(topmost->orderbyvals,
     238            5122 :                                 topmost->orderbynulls,
     239 GIC        5122 :                                 scandesc->xs_orderbyvals,
     240            5122 :                                 scandesc->xs_orderbynulls,
     241                 :                                 node) <= 0)
     242                 :             {
     243 ECB             :                 HeapTuple   tuple;
     244                 : 
     245 GIC        2538 :                 tuple = reorderqueue_pop(node);
     246 ECB             : 
     247                 :                 /* Pass 'true', as the tuple in the queue is a palloc'd copy */
     248 GIC        2538 :                 ExecForceStoreHeapTuple(tuple, slot, true);
     249            2538 :                 return slot;
     250 ECB             :             }
     251                 :         }
     252 GIC       38803 :         else if (node->iss_ReachedEnd)
     253 ECB             :         {
     254                 :             /* Queue is empty, and no more tuples from index.  We're done. */
     255 GIC           9 :             return ExecClearTuple(slot);
     256                 :         }
     257                 : 
     258                 :         /*
     259 ECB             :          * Fetch next tuple from the index.
     260                 :          */
     261 GIC       41381 : next_indextuple:
     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
     266 ECB             :              * remaining tuples from the queue before we're done.
     267                 :              */
     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
     274 ECB             :          * ORDER BY expressions using the fetched tuple.
     275                 :          */
     276 CBC       43442 :         if (scandesc->xs_recheck)
     277 ECB             :         {
     278 GIC        4563 :             econtext->ecxt_scantuple = slot;
     279            4563 :             if (!ExecQualAndReset(node->indexqualorig, econtext))
     280 ECB             :             {
     281                 :                 /* Fails recheck, so drop it and loop back for another */
     282 CBC        2070 :                 InstrCountFiltered2(node, 1);
     283 ECB             :                 /* allow this loop to be cancellable */
     284 GIC        2070 :                 CHECK_FOR_INTERRUPTS();
     285            2070 :                 goto next_indextuple;
     286                 :             }
     287 ECB             :         }
     288                 : 
     289 CBC       41372 :         if (scandesc->xs_recheckorderby)
     290 ECB             :         {
     291 CBC        2650 :             econtext->ecxt_scantuple = slot;
     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
     302 ECB             :              * pushing the tuple to the queue, just to pop it back out again.)
     303                 :              */
     304 CBC        2650 :             cmp = cmp_orderbyvals(node->iss_OrderByValues,
     305            2650 :                                   node->iss_OrderByNulls,
     306 GIC        2650 :                                   scandesc->xs_orderbyvals,
     307 CBC        2650 :                                   scandesc->xs_orderbynulls,
     308 EUB             :                                   node);
     309 CBC        2650 :             if (cmp < 0)
     310 LBC           0 :                 elog(ERROR, "index returned tuples in wrong order");
     311 GIC        2650 :             else if (cmp == 0)
     312 CBC          65 :                 was_exact = true;
     313 ECB             :             else
     314 CBC        2585 :                 was_exact = false;
     315 GIC        2650 :             lastfetched_vals = node->iss_OrderByValues;
     316            2650 :             lastfetched_nulls = node->iss_OrderByNulls;
     317                 :         }
     318 ECB             :         else
     319                 :         {
     320 CBC       38722 :             was_exact = true;
     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
     331 ECB             :          * already.
     332                 :          */
     333 CBC       41415 :         if (!was_exact || (topmost && cmp_orderbyvals(lastfetched_vals,
     334 ECB             :                                                       lastfetched_nulls,
     335 GIC          43 :                                                       topmost->orderbyvals,
     336              43 :                                                       topmost->orderbynulls,
     337                 :                                                       node) > 0))
     338 ECB             :         {
     339                 :             /* Put this tuple to the queue */
     340 GIC        2588 :             reorderqueue_push(node, slot, lastfetched_vals, lastfetched_nulls);
     341            2588 :             continue;
     342                 :         }
     343                 :         else
     344 ECB             :         {
     345                 :             /* Can return this tuple immediately. */
     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.
     359 ECB             :  */
     360                 : static void
     361 GIC        2650 : EvalOrderByExpressions(IndexScanState *node, ExprContext *econtext)
     362                 : {
     363                 :     int         i;
     364                 :     ListCell   *l;
     365 ECB             :     MemoryContext oldContext;
     366                 : 
     367 CBC        2650 :     oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
     368 ECB             : 
     369 GIC        2650 :     i = 0;
     370 CBC        5300 :     foreach(l, node->indexorderbyorig)
     371                 :     {
     372            2650 :         ExprState  *orderby = (ExprState *) lfirst(l);
     373                 : 
     374            5300 :         node->iss_OrderByValues[i] = ExecEvalExpr(orderby,
     375 ECB             :                                                   econtext,
     376 GIC        2650 :                                                   &node->iss_OrderByNulls[i]);
     377            2650 :         i++;
     378 ECB             :     }
     379                 : 
     380 GIC        2650 :     MemoryContextSwitchTo(oldContext);
     381            2650 : }
     382                 : 
     383                 : /*
     384                 :  * IndexRecheck -- access method routine to recheck a tuple in EvalPlanQual
     385 ECB             :  */
     386                 : static bool
     387 GIC          39 : IndexRecheck(IndexScanState *node, TupleTableSlot *slot)
     388                 : {
     389                 :     ExprContext *econtext;
     390                 : 
     391                 :     /*
     392 ECB             :      * extract necessary information from index scan node
     393                 :      */
     394 GIC          39 :     econtext = node->ss.ps.ps_ExprContext;
     395 ECB             : 
     396                 :     /* Does the tuple meet the indexqual condition? */
     397 GIC          39 :     econtext->ecxt_scantuple = slot;
     398              39 :     return ExecQualAndReset(node->indexqualorig, econtext);
     399                 : }
     400                 : 
     401                 : 
     402                 : /*
     403                 :  * Compare ORDER BY expression values.
     404 ECB             :  */
     405                 : static int
     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;
     411 ECB             :     int         result;
     412                 : 
     413 CBC       14705 :     for (i = 0; i < node->iss_NumOrderByKeys; i++)
     414                 :     {
     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
     420 ECB             :          * implementation otherwise.
     421 EUB             :          */
     422 CBC       14610 :         if (anulls[i] && !bnulls[i])
     423 UBC           0 :             return 1;
     424 CBC       14610 :         else if (!anulls[i] && bnulls[i])
     425 UBC           0 :             return -1;
     426 GIC       14610 :         else if (anulls[i] && bnulls[i])
     427 LBC           0 :             return 0;
     428 ECB             : 
     429 CBC       14610 :         result = ssup->comparator(adist[i], bdist[i], ssup);
     430 GIC       14610 :         if (result != 0)
     431           14515 :             return result;
     432 ECB             :     }
     433                 : 
     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.
     440 ECB             :  */
     441                 : static int
     442 GIC        6795 : reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b,
     443 ECB             :                  void *arg)
     444                 : {
     445 CBC        6795 :     ReorderTuple *rta = (ReorderTuple *) a;
     446 GIC        6795 :     ReorderTuple *rtb = (ReorderTuple *) b;
     447            6795 :     IndexScanState *node = (IndexScanState *) arg;
     448 ECB             : 
     449                 :     /* exchange argument order to invert the sort order */
     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.
     457 ECB             :  */
     458                 : static void
     459 GIC        2588 : reorderqueue_push(IndexScanState *node, TupleTableSlot *slot,
     460 ECB             :                   Datum *orderbyvals, bool *orderbynulls)
     461                 : {
     462 CBC        2588 :     IndexScanDesc scandesc = node->iss_ScanDesc;
     463 GIC        2588 :     EState     *estate = node->ss.ps.state;
     464            2588 :     MemoryContext oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
     465                 :     ReorderTuple *rt;
     466 ECB             :     int         i;
     467                 : 
     468 CBC        2588 :     rt = (ReorderTuple *) palloc(sizeof(ReorderTuple));
     469            2588 :     rt->htup = ExecCopySlotHeapTuple(slot);
     470            2588 :     rt->orderbyvals =
     471            2588 :         (Datum *) palloc(sizeof(Datum) * scandesc->numberOfOrderBys);
     472            2588 :     rt->orderbynulls =
     473 GIC        2588 :         (bool *) palloc(sizeof(bool) * scandesc->numberOfOrderBys);
     474 CBC        5176 :     for (i = 0; i < node->iss_NumOrderByKeys; i++)
     475 ECB             :     {
     476 CBC        2588 :         if (!orderbynulls[i])
     477            2588 :             rt->orderbyvals[i] = datumCopy(orderbyvals[i],
     478 GIC        2588 :                                            node->iss_OrderByTypByVals[i],
     479 GBC        2588 :                                            node->iss_OrderByTypLens[i]);
     480 ECB             :         else
     481 UIC           0 :             rt->orderbyvals[i] = (Datum) 0;
     482 CBC        2588 :         rt->orderbynulls[i] = orderbynulls[i];
     483                 :     }
     484            2588 :     pairingheap_add(node->iss_ReorderQueue, &rt->ph_node);
     485 ECB             : 
     486 GIC        2588 :     MemoryContextSwitchTo(oldContext);
     487            2588 : }
     488                 : 
     489                 : /*
     490                 :  * Helper function to pop the next tuple from the reorder queue.
     491 ECB             :  */
     492                 : static HeapTuple
     493 GIC        2568 : reorderqueue_pop(IndexScanState *node)
     494                 : {
     495                 :     HeapTuple   result;
     496                 :     ReorderTuple *topmost;
     497 ECB             :     int         i;
     498                 : 
     499 CBC        2568 :     topmost = (ReorderTuple *) pairingheap_remove_first(node->iss_ReorderQueue);
     500 ECB             : 
     501 GIC        2568 :     result = topmost->htup;
     502 CBC        5136 :     for (i = 0; i < node->iss_NumOrderByKeys; i++)
     503 EUB             :     {
     504 GIC        2568 :         if (!node->iss_OrderByTypByVals[i] && !topmost->orderbynulls[i])
     505 LBC           0 :             pfree(DatumGetPointer(topmost->orderbyvals[i]));
     506 ECB             :     }
     507 CBC        2568 :     pfree(topmost->orderbyvals);
     508 GIC        2568 :     pfree(topmost->orderbynulls);
     509 CBC        2568 :     pfree(topmost);
     510                 : 
     511 GIC        2568 :     return result;
     512                 : }
     513                 : 
     514                 : 
     515                 : /* ----------------------------------------------------------------
     516                 :  *      ExecIndexScan(node)
     517                 :  * ----------------------------------------------------------------
     518 ECB             :  */
     519                 : static TupleTableSlot *
     520 CBC      836403 : ExecIndexScan(PlanState *pstate)
     521                 : {
     522 GIC      836403 :     IndexScanState *node = castNode(IndexScanState, pstate);
     523                 : 
     524                 :     /*
     525 ECB             :      * If we have runtime keys and they've not already been set up, do it now.
     526                 :      */
     527 GIC      836403 :     if (node->iss_NumRuntimeKeys != 0 && !node->iss_RuntimeKeysReady)
     528 CBC        7504 :         ExecReScan((PlanState *) node);
     529 ECB             : 
     530 GIC      836400 :     if (node->iss_NumOrderByKeys > 0)
     531           41331 :         return ExecScan(&node->ss,
     532                 :                         (ExecScanAccessMtd) IndexNextWithReorder,
     533 ECB             :                         (ExecScanRecheckMtd) IndexRecheck);
     534                 :     else
     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                 :  * ----------------------------------------------------------------
     550 ECB             :  */
     551                 : void
     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
     559 ECB             :      * on each call.
     560                 :      */
     561 CBC      165861 :     if (node->iss_NumRuntimeKeys != 0)
     562                 :     {
     563          161429 :         ExprContext *econtext = node->iss_RuntimeContext;
     564 ECB             : 
     565 GIC      161429 :         ResetExprContext(econtext);
     566          161429 :         ExecIndexEvalRuntimeKeys(econtext,
     567                 :                                  node->iss_RuntimeKeys,
     568 ECB             :                                  node->iss_NumRuntimeKeys);
     569                 :     }
     570 GIC      165858 :     node->iss_RuntimeKeysReady = true;
     571 ECB             : 
     572                 :     /* flush the reorder queue */
     573 GIC      165858 :     if (node->iss_ReorderQueue)
     574                 :     {
     575 ECB             :         HeapTuple   tuple;
     576                 : 
     577 CBC          63 :         while (!pairingheap_is_empty(node->iss_ReorderQueue))
     578 ECB             :         {
     579 GIC          30 :             tuple = reorderqueue_pop(node);
     580              30 :             heap_freetuple(tuple);
     581                 :         }
     582                 :     }
     583 ECB             : 
     584                 :     /* reset index scan */
     585 CBC      165858 :     if (node->iss_ScanDesc)
     586          144121 :         index_rescan(node->iss_ScanDesc,
     587          144121 :                      node->iss_ScanKeys, node->iss_NumScanKeys,
     588 GIC      144121 :                      node->iss_OrderByKeys, node->iss_NumOrderByKeys);
     589 CBC      165858 :     node->iss_ReachedEnd = false;
     590 ECB             : 
     591 GIC      165858 :     ExecScanReScan(&node->ss);
     592          165858 : }
     593                 : 
     594                 : 
     595                 : /*
     596                 :  * ExecIndexEvalRuntimeKeys
     597                 :  *      Evaluate any runtime key values, and update the scankeys.
     598 ECB             :  */
     599                 : void
     600 GIC      204818 : ExecIndexEvalRuntimeKeys(ExprContext *econtext,
     601                 :                          IndexRuntimeKeyInfo *runtimeKeys, int numRuntimeKeys)
     602                 : {
     603                 :     int         j;
     604                 :     MemoryContext oldContext;
     605 ECB             : 
     606                 :     /* We want to keep the key values in per-tuple memory */
     607 CBC      204818 :     oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
     608                 : 
     609          418740 :     for (j = 0; j < numRuntimeKeys; j++)
     610 ECB             :     {
     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
     631 ECB             :          * index support function.
     632                 :          */
     633 GIC      213925 :         scanvalue = ExecEvalExpr(key_expr,
     634 ECB             :                                  econtext,
     635                 :                                  &isNull);
     636 CBC      213922 :         if (isNull)
     637 ECB             :         {
     638 GIC        1277 :             scan_key->sk_argument = scanvalue;
     639            1277 :             scan_key->sk_flags |= SK_ISNULL;
     640                 :         }
     641 ECB             :         else
     642                 :         {
     643 CBC      212645 :             if (runtimeKeys[j].key_toastable)
     644            1650 :                 scanvalue = PointerGetDatum(PG_DETOAST_DATUM(scanvalue));
     645 GIC      212645 :             scan_key->sk_argument = scanvalue;
     646          212645 :             scan_key->sk_flags &= ~SK_ISNULL;
     647                 :         }
     648 ECB             :     }
     649                 : 
     650 GIC      204815 :     MemoryContextSwitchTo(oldContext);
     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.
     660 ECB             :  */
     661                 : bool
     662 GIC          12 : ExecIndexEvalArrayKeys(ExprContext *econtext,
     663 ECB             :                        IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
     664                 : {
     665 GIC          12 :     bool        result = true;
     666                 :     int         j;
     667                 :     MemoryContext oldContext;
     668 ECB             : 
     669                 :     /* We want to keep the arrays in per-tuple memory */
     670 CBC          12 :     oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
     671                 : 
     672              24 :     for (j = 0; j < numArrayKeys; j++)
     673 ECB             :     {
     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
     688 ECB             :          * ExecIndexEvalRuntimeKeys() apply here too.)
     689                 :          */
     690 GIC          12 :         arraydatum = ExecEvalExpr(array_expr,
     691 ECB             :                                   econtext,
     692                 :                                   &isNull);
     693 GBC          12 :         if (isNull)
     694 EUB             :         {
     695 UIC           0 :             result = false;
     696 LBC           0 :             break;              /* no point in evaluating more */
     697                 :         }
     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);
     702 GIC          12 :         deconstruct_array(arrayval,
     703                 :                           ARR_ELEMTYPE(arrayval),
     704 ECB             :                           elmlen, elmbyval, elmalign,
     705                 :                           &elem_values, &elem_nulls, &num_elems);
     706 GBC          12 :         if (num_elems <= 0)
     707 EUB             :         {
     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
     715 ECB             :          * pfree's here.
     716                 :          */
     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;
     720 GBC          12 :         scan_key->sk_argument = elem_values[0];
     721 GIC          12 :         if (elem_nulls[0])
     722 LBC           0 :             scan_key->sk_flags |= SK_ISNULL;
     723 ECB             :         else
     724 GIC          12 :             scan_key->sk_flags &= ~SK_ISNULL;
     725              12 :         arrayKeys[j].next_elem = 1;
     726 ECB             :     }
     727                 : 
     728 CBC          12 :     MemoryContextSwitchTo(oldContext);
     729                 : 
     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.
     739 ECB             :  */
     740                 : bool
     741 CBC        8703 : ExecIndexAdvanceArrayKeys(IndexArrayKeyInfo *arrayKeys, int numArrayKeys)
     742                 : {
     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
     750 ECB             :      * access in the index.
     751                 :      */
     752 CBC        8715 :     for (j = numArrayKeys - 1; j >= 0; j--)
     753 ECB             :     {
     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;
     757 GIC          24 :         Datum      *elem_values = arrayKeys[j].elem_values;
     758 CBC          24 :         bool       *elem_nulls = arrayKeys[j].elem_nulls;
     759                 : 
     760              24 :         if (next_elem >= num_elems)
     761 ECB             :         {
     762 GIC          12 :             next_elem = 0;
     763              12 :             found = false;      /* need to advance next array key */
     764 ECB             :         }
     765                 :         else
     766 CBC          12 :             found = true;
     767 GBC          24 :         scan_key->sk_argument = elem_values[next_elem];
     768 GIC          24 :         if (elem_nulls[next_elem])
     769 LBC           0 :             scan_key->sk_flags |= SK_ISNULL;
     770 ECB             :         else
     771 CBC          24 :             scan_key->sk_flags &= ~SK_ISNULL;
     772              24 :         arrayKeys[j].next_elem = next_elem + 1;
     773 GIC          24 :         if (found)
     774              12 :             break;
     775 ECB             :     }
     776                 : 
     777 GIC        8703 :     return found;
     778                 : }
     779                 : 
     780                 : 
     781                 : /* ----------------------------------------------------------------
     782                 :  *      ExecEndIndexScan
     783                 :  * ----------------------------------------------------------------
     784 ECB             :  */
     785                 : void
     786 GIC       59729 : ExecEndIndexScan(IndexScanState *node)
     787                 : {
     788                 :     Relation    indexRelationDesc;
     789                 :     IndexScanDesc indexScanDesc;
     790                 : 
     791                 :     /*
     792 ECB             :      * extract information from the node
     793                 :      */
     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                 :     /*
     807 ECB             :      * clear out tuple table slots
     808                 :      */
     809 CBC       59729 :     if (node->ss.ps.ps_ResultTupleSlot)
     810 GIC       22522 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     811           59729 :     ExecClearTuple(node->ss.ss_ScanTupleSlot);
     812                 : 
     813                 :     /*
     814 ECB             :      * close the index relation (no-op if we didn't open it)
     815                 :      */
     816 CBC       59729 :     if (indexScanDesc)
     817           49854 :         index_endscan(indexScanDesc);
     818           59729 :     if (indexRelationDesc)
     819 GIC       58546 :         index_close(indexRelationDesc, NoLock);
     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                 :  * ----------------------------------------------------------------
     828 ECB             :  */
     829                 : void
     830 CBC        3025 : ExecIndexMarkPos(IndexScanState *node)
     831 ECB             : {
     832 GIC        3025 :     EState     *estate = node->ss.ps.state;
     833 CBC        3025 :     EPQState   *epqstate = estate->es_epq_active;
     834                 : 
     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]
     844 ECB             :          * already set, and so no state need be saved.
     845                 :          */
     846 CBC           1 :         Index       scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
     847 ECB             : 
     848 GBC           1 :         Assert(scanrelid > 0);
     849 GIC           1 :         if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
     850 UIC           0 :             epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
     851 ECB             :         {
     852 EUB             :             /* Verify the claim above */
     853 CBC           1 :             if (!epqstate->relsubs_done[scanrelid - 1])
     854 UIC           0 :                 elog(ERROR, "unexpected ExecIndexMarkPos call in EPQ recheck");
     855 GIC           1 :             return;
     856                 :         }
     857 ECB             :     }
     858                 : 
     859 GIC        3024 :     index_markpos(node->iss_ScanDesc);
     860                 : }
     861                 : 
     862                 : /* ----------------------------------------------------------------
     863                 :  *      ExecIndexRestrPos
     864                 :  * ----------------------------------------------------------------
     865 ECB             :  */
     866                 : void
     867 CBC       27012 : ExecIndexRestrPos(IndexScanState *node)
     868 ECB             : {
     869 GIC       27012 :     EState     *estate = node->ss.ps.state;
     870 CBC       27012 :     EPQState   *epqstate = estate->es_epq_active;
     871                 : 
     872 GIC       27012 :     if (estate->es_epq_active != NULL)
     873 EUB             :     {
     874                 :         /* See comments in ExecIndexMarkPos */
     875 UBC           0 :         Index       scanrelid = ((Scan *) node->ss.ps.plan)->scanrelid;
     876 EUB             : 
     877 UBC           0 :         Assert(scanrelid > 0);
     878 UIC           0 :         if (epqstate->relsubs_slot[scanrelid - 1] != NULL ||
     879               0 :             epqstate->relsubs_rowmark[scanrelid - 1] != NULL)
     880 EUB             :         {
     881                 :             /* Verify the claim above */
     882 UBC           0 :             if (!epqstate->relsubs_done[scanrelid - 1])
     883 UIC           0 :                 elog(ERROR, "unexpected ExecIndexRestrPos call in EPQ recheck");
     884               0 :             return;
     885                 :         }
     886 ECB             :     }
     887                 : 
     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                 :  * ----------------------------------------------------------------
     901 ECB             :  */
     902                 : IndexScanState *
     903 GIC       60052 : ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
     904                 : {
     905                 :     IndexScanState *indexstate;
     906                 :     Relation    currentRelation;
     907                 :     LOCKMODE    lockmode;
     908                 : 
     909                 :     /*
     910 ECB             :      * create state structure
     911                 :      */
     912 CBC       60052 :     indexstate = makeNode(IndexScanState);
     913           60052 :     indexstate->ss.ps.plan = (Plan *) node;
     914 GIC       60052 :     indexstate->ss.ps.state = estate;
     915           60052 :     indexstate->ss.ps.ExecProcNode = ExecIndexScan;
     916                 : 
     917                 :     /*
     918                 :      * Miscellaneous initialization
     919                 :      *
     920 ECB             :      * create expression context for node
     921                 :      */
     922 GIC       60052 :     ExecAssignExprContext(estate, &indexstate->ss.ps);
     923                 : 
     924                 :     /*
     925 ECB             :      * open the scan relation
     926                 :      */
     927 CBC       60052 :     currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
     928 ECB             : 
     929 GIC       60052 :     indexstate->ss.ss_currentRelation = currentRelation;
     930           60052 :     indexstate->ss.ss_currentScanDesc = NULL;    /* no heap scan here */
     931                 : 
     932                 :     /*
     933 ECB             :      * get the scan type from the relation descriptor.
     934                 :      */
     935 GIC       60052 :     ExecInitScanTupleSlot(estate, &indexstate->ss,
     936                 :                           RelationGetDescr(currentRelation),
     937                 :                           table_slot_callbacks(currentRelation));
     938                 : 
     939                 :     /*
     940 ECB             :      * Initialize result type and projection.
     941                 :      */
     942 GIC       60052 :     ExecInitResultTypeTL(&indexstate->ss.ps);
     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
     953 ECB             :      * in the expression must be found now...)
     954                 :      */
     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);
     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
     965 ECB             :      * references to nonexistent indexes.
     966                 :      */
     967 GIC       60052 :     if (eflags & EXEC_FLAG_EXPLAIN_ONLY)
     968            1183 :         return indexstate;
     969 ECB             : 
     970                 :     /* Open the index relation. */
     971 GIC       58869 :     lockmode = exec_rt_fetch(node->scan.scanrelid, estate)->rellockmode;
     972           58869 :     indexstate->iss_RelationDesc = index_open(node->indexid, lockmode);
     973                 : 
     974                 :     /*
     975 ECB             :      * Initialize index-specific scan state
     976                 :      */
     977 CBC       58869 :     indexstate->iss_RuntimeKeysReady = false;
     978 GIC       58869 :     indexstate->iss_RuntimeKeys = NULL;
     979           58869 :     indexstate->iss_NumRuntimeKeys = 0;
     980                 : 
     981                 :     /*
     982 ECB             :      * build the index scan keys from the index qualification
     983                 :      */
     984 GIC       58869 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     985                 :                            indexstate->iss_RelationDesc,
     986 ECB             :                            node->indexqual,
     987                 :                            false,
     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                 :     /*
     996 ECB             :      * any ORDER BY exprs have to be turned into scankeys in the same way
     997                 :      */
     998 GIC       58869 :     ExecIndexBuildScanKeys((PlanState *) indexstate,
     999                 :                            indexstate->iss_RelationDesc,
    1000 ECB             :                            node->indexorderby,
    1001                 :                            true,
    1002 GIC       58869 :                            &indexstate->iss_OrderByKeys,
    1003                 :                            &indexstate->iss_NumOrderByKeys,
    1004                 :                            &indexstate->iss_RuntimeKeys,
    1005                 :                            &indexstate->iss_NumRuntimeKeys,
    1006                 :                            NULL,    /* no ArrayKeys */
    1007                 :                            NULL);
    1008 ECB             : 
    1009                 :     /* Initialize sort support, if we need to re-check ORDER BY exprs */
    1010 CBC       58869 :     if (indexstate->iss_NumOrderByKeys > 0)
    1011                 :     {
    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
    1019 ECB             :          * expression.
    1020                 :          */
    1021 CBC          23 :         Assert(numOrderByKeys == list_length(node->indexorderbyops));
    1022              23 :         Assert(numOrderByKeys == list_length(node->indexorderbyorig));
    1023              23 :         indexstate->iss_SortSupport = (SortSupportData *)
    1024              23 :             palloc0(numOrderByKeys * sizeof(SortSupportData));
    1025              23 :         indexstate->iss_OrderByTypByVals = (bool *)
    1026              23 :             palloc(numOrderByKeys * sizeof(bool));
    1027              23 :         indexstate->iss_OrderByTypLens = (int16 *)
    1028              23 :             palloc(numOrderByKeys * sizeof(int16));
    1029 GIC          23 :         i = 0;
    1030 CBC          46 :         forboth(lco, node->indexorderbyops, lcx, node->indexorderbyorig)
    1031 ECB             :         {
    1032 CBC          23 :             Oid         orderbyop = lfirst_oid(lco);
    1033              23 :             Node       *orderbyexpr = (Node *) lfirst(lcx);
    1034              23 :             Oid         orderbyType = exprType(orderbyexpr);
    1035 GIC          23 :             Oid         orderbyColl = exprCollation(orderbyexpr);
    1036              23 :             SortSupport orderbysort = &indexstate->iss_SortSupport[i];
    1037 ECB             : 
    1038                 :             /* Initialize sort support */
    1039 GIC          23 :             orderbysort->ssup_cxt = CurrentMemoryContext;
    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;
    1045 ECB             :             /* No abbreviation */
    1046 GIC          23 :             orderbysort->abbreviate = false;
    1047 CBC          23 :             PrepareSortSupportFromOrderingOp(orderbyop, orderbysort);
    1048 ECB             : 
    1049 CBC          23 :             get_typlenbyval(orderbyType,
    1050              23 :                             &indexstate->iss_OrderByTypLens[i],
    1051 GIC          23 :                             &indexstate->iss_OrderByTypByVals[i]);
    1052              23 :             i++;
    1053                 :         }
    1054 ECB             : 
    1055                 :         /* allocate arrays to hold the re-calculated distances */
    1056 CBC          23 :         indexstate->iss_OrderByValues = (Datum *)
    1057              23 :             palloc(numOrderByKeys * sizeof(Datum));
    1058 GIC          23 :         indexstate->iss_OrderByNulls = (bool *)
    1059              23 :             palloc(numOrderByKeys * sizeof(bool));
    1060 ECB             : 
    1061                 :         /* and initialize the reorder queue */
    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...
    1070 ECB             :      * -tgl 7/11/00
    1071                 :      */
    1072 CBC       58869 :     if (indexstate->iss_NumRuntimeKeys != 0)
    1073                 :     {
    1074           26059 :         ExprContext *stdecontext = indexstate->ss.ps.ps_ExprContext;
    1075 ECB             : 
    1076 CBC       26059 :         ExecAssignExprContext(estate, &indexstate->ss.ps);
    1077 GIC       26059 :         indexstate->iss_RuntimeContext = indexstate->ss.ps.ps_ExprContext;
    1078           26059 :         indexstate->ss.ps.ps_ExprContext = stdecontext;
    1079                 :     }
    1080 ECB             :     else
    1081                 :     {
    1082 GIC       32810 :         indexstate->iss_RuntimeContext = NULL;
    1083                 :     }
    1084                 : 
    1085                 :     /*
    1086 ECB             :      * all done.
    1087                 :      */
    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.
    1150 ECB             :  */
    1151                 : void
    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;
    1167 ECB             : 
    1168                 :     /* Allocate array for ScanKey structs: one per qual */
    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
    1177 ECB             :      * call.
    1178                 :      */
    1179 GIC      137858 :     runtime_keys = *runtimeKeys;
    1180          137858 :     n_runtime_keys = max_runtime_keys = *numRuntimeKeys;
    1181                 : 
    1182 ECB             :     /* Allocate array_keys as large as it could possibly need to be */
    1183                 :     array_keys = (IndexArrayKeyInfo *)
    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
    1189 ECB             :      * scan key
    1190                 :      */
    1191 GIC      137858 :     j = 0;
    1192 CBC      221261 :     foreach(qual_cell, quals)
    1193 ECB             :     {
    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 */
    1205 ECB             :         int         indnkeyatts;
    1206                 : 
    1207 GIC       83403 :         indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index);
    1208           83403 :         if (IsA(clause, OpExpr))
    1209 ECB             :         {
    1210                 :             /* indexkey op const or indexkey op expression */
    1211 GIC       82659 :             int         flags = 0;
    1212 ECB             :             Datum       scanvalue;
    1213                 : 
    1214 GIC       82659 :             opno = ((OpExpr *) clause)->opno;
    1215           82659 :             opfuncid = ((OpExpr *) clause)->opfuncid;
    1216                 : 
    1217                 :             /*
    1218 ECB             :              * leftop should be the index key Var, possibly relabeled
    1219                 :              */
    1220 CBC       82659 :             leftop = (Expr *) get_leftop(clause);
    1221 EUB             : 
    1222 GIC       82659 :             if (leftop && IsA(leftop, RelabelType))
    1223 LBC           0 :                 leftop = ((RelabelType *) leftop)->arg;
    1224                 : 
    1225 CBC       82659 :             Assert(leftop != NULL);
    1226 ECB             : 
    1227 GBC       82659 :             if (!(IsA(leftop, Var) &&
    1228 GIC       82659 :                   ((Var *) leftop)->varno == INDEX_VAR))
    1229 LBC           0 :                 elog(ERROR, "indexqual doesn't have key on left side");
    1230 ECB             : 
    1231 GBC       82659 :             varattno = ((Var *) leftop)->varattno;
    1232 GIC       82659 :             if (varattno < 1 || varattno > indnkeyatts)
    1233 UIC           0 :                 elog(ERROR, "bogus index qualification");
    1234                 : 
    1235                 :             /*
    1236                 :              * We have to look up the operator's strategy number.  This
    1237 ECB             :              * provides a cross-check that the operator does match the index.
    1238                 :              */
    1239 CBC       82659 :             opfamily = index->rd_opfamily[varattno - 1];
    1240                 : 
    1241 GIC       82659 :             get_op_opfamily_properties(opno, opfamily, isorderby,
    1242                 :                                        &op_strategy,
    1243                 :                                        &op_lefttype,
    1244 ECB             :                                        &op_righttype);
    1245                 : 
    1246 GIC       82659 :             if (isorderby)
    1247              99 :                 flags |= SK_ORDER_BY;
    1248                 : 
    1249                 :             /*
    1250 ECB             :              * rightop is the constant or variable comparison value
    1251                 :              */
    1252 CBC       82659 :             rightop = (Expr *) get_rightop(clause);
    1253 ECB             : 
    1254 GIC       82659 :             if (rightop && IsA(rightop, RelabelType))
    1255 CBC         393 :                 rightop = ((RelabelType *) rightop)->arg;
    1256                 : 
    1257           82659 :             Assert(rightop != NULL);
    1258                 : 
    1259 GIC       82659 :             if (IsA(rightop, Const))
    1260 ECB             :             {
    1261                 :                 /* OK, simple constant comparison value */
    1262 GBC       51084 :                 scanvalue = ((Const *) rightop)->constvalue;
    1263 GIC       51084 :                 if (((Const *) rightop)->constisnull)
    1264 UIC           0 :                     flags |= SK_ISNULL;
    1265                 :             }
    1266                 :             else
    1267 ECB             :             {
    1268                 :                 /* Need to treat this one as a runtime key */
    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 *)
    1275 GIC       27807 :                             palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
    1276                 :                     }
    1277 ECB             :                     else
    1278                 :                     {
    1279 CBC           3 :                         max_runtime_keys *= 2;
    1280                 :                         runtime_keys = (IndexRuntimeKeyInfo *)
    1281 GIC           3 :                             repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
    1282 ECB             :                     }
    1283                 :                 }
    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);
    1287           31575 :                 runtime_keys[n_runtime_keys].key_toastable =
    1288           31575 :                     TypeIsToastable(op_righttype);
    1289 GIC       31575 :                 n_runtime_keys++;
    1290           31575 :                 scanvalue = (Datum) 0;
    1291                 :             }
    1292                 : 
    1293                 :             /*
    1294 ECB             :              * initialize the scan key's fields appropriately
    1295                 :              */
    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 */
    1303 ECB             :                                    scanvalue);  /* constant */
    1304                 :         }
    1305 GIC         744 :         else if (IsA(clause, RowCompareExpr))
    1306 ECB             :         {
    1307                 :             /* (indexkey, indexkey, ...) op (expression, expression, ...) */
    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;
    1314 ECB             :             ListCell   *collids_cell;
    1315                 : 
    1316 GIC          18 :             Assert(!isorderby);
    1317 ECB             : 
    1318                 :             first_sub_key = (ScanKey)
    1319 GIC          18 :                 palloc(list_length(rc->opnos) * sizeof(ScanKeyData));
    1320              18 :             n_sub_key = 0;
    1321 ECB             : 
    1322                 :             /* Scan RowCompare columns and generate subsidiary ScanKey items */
    1323 GIC          54 :             forfour(largs_cell, rc->largs, rargs_cell, rc->rargs,
    1324 ECB             :                     opnos_cell, rc->opnos, collids_cell, rc->inputcollids)
    1325                 :             {
    1326 GIC          36 :                 ScanKey     this_sub_key = &first_sub_key[n_sub_key];
    1327              36 :                 int         flags = SK_ROW_MEMBER;
    1328                 :                 Datum       scanvalue;
    1329 ECB             :                 Oid         inputcollation;
    1330                 : 
    1331 CBC          36 :                 leftop = (Expr *) lfirst(largs_cell);
    1332              36 :                 rightop = (Expr *) lfirst(rargs_cell);
    1333 GIC          36 :                 opno = lfirst_oid(opnos_cell);
    1334              36 :                 inputcollation = lfirst_oid(collids_cell);
    1335                 : 
    1336                 :                 /*
    1337 ECB             :                  * leftop should be the index key Var, possibly relabeled
    1338 EUB             :                  */
    1339 GIC          36 :                 if (leftop && IsA(leftop, RelabelType))
    1340 LBC           0 :                     leftop = ((RelabelType *) leftop)->arg;
    1341                 : 
    1342 CBC          36 :                 Assert(leftop != NULL);
    1343 ECB             : 
    1344 GBC          36 :                 if (!(IsA(leftop, Var) &&
    1345 GIC          36 :                       ((Var *) leftop)->varno == INDEX_VAR))
    1346 LBC           0 :                     elog(ERROR, "indexqual doesn't have key on left side");
    1347                 : 
    1348 GIC          36 :                 varattno = ((Var *) leftop)->varattno;
    1349                 : 
    1350                 :                 /*
    1351                 :                  * We have to look up the operator's associated btree support
    1352 ECB             :                  * function
    1353                 :                  */
    1354 GBC          36 :                 if (index->rd_rel->relam != BTREE_AM_OID ||
    1355 CBC          36 :                     varattno < 1 || varattno > indnkeyatts)
    1356 UIC           0 :                     elog(ERROR, "bogus RowCompare index qualification");
    1357 CBC          36 :                 opfamily = index->rd_opfamily[varattno - 1];
    1358                 : 
    1359 GIC          36 :                 get_op_opfamily_properties(opno, opfamily, isorderby,
    1360                 :                                            &op_strategy,
    1361                 :                                            &op_lefttype,
    1362 ECB             :                                            &op_righttype);
    1363 EUB             : 
    1364 GIC          36 :                 if (op_strategy != rc->rctype)
    1365 LBC           0 :                     elog(ERROR, "RowCompare index qualification contains wrong operator");
    1366                 : 
    1367 GIC          36 :                 opfuncid = get_opfamily_proc(opfamily,
    1368                 :                                              op_lefttype,
    1369 ECB             :                                              op_righttype,
    1370 EUB             :                                              BTORDER_PROC);
    1371 GIC          36 :                 if (!RegProcedureIsValid(opfuncid))
    1372 UIC           0 :                     elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
    1373                 :                          BTORDER_PROC, op_lefttype, op_righttype, opfamily);
    1374                 : 
    1375                 :                 /*
    1376 ECB             :                  * rightop is the constant or variable comparison value
    1377 EUB             :                  */
    1378 GIC          36 :                 if (rightop && IsA(rightop, RelabelType))
    1379 LBC           0 :                     rightop = ((RelabelType *) rightop)->arg;
    1380                 : 
    1381 CBC          36 :                 Assert(rightop != NULL);
    1382                 : 
    1383 GIC          36 :                 if (IsA(rightop, Const))
    1384 ECB             :                 {
    1385                 :                     /* OK, simple constant comparison value */
    1386 GBC          36 :                     scanvalue = ((Const *) rightop)->constvalue;
    1387 GIC          36 :                     if (((Const *) rightop)->constisnull)
    1388 UIC           0 :                         flags |= SK_ISNULL;
    1389                 :                 }
    1390                 :                 else
    1391 EUB             :                 {
    1392                 :                     /* Need to treat this one as a runtime key */
    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 *)
    1399 UIC           0 :                                 palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
    1400                 :                         }
    1401 EUB             :                         else
    1402                 :                         {
    1403 UBC           0 :                             max_runtime_keys *= 2;
    1404                 :                             runtime_keys = (IndexRuntimeKeyInfo *)
    1405 UIC           0 :                                 repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
    1406 EUB             :                         }
    1407                 :                     }
    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);
    1411               0 :                     runtime_keys[n_runtime_keys].key_toastable =
    1412               0 :                         TypeIsToastable(op_righttype);
    1413 UIC           0 :                     n_runtime_keys++;
    1414               0 :                     scanvalue = (Datum) 0;
    1415                 :                 }
    1416                 : 
    1417                 :                 /*
    1418 ECB             :                  * initialize the subsidiary scan key's fields appropriately
    1419                 :                  */
    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 */
    1426 ECB             :                                        opfuncid,    /* reg proc to use */
    1427                 :                                        scanvalue);  /* constant */
    1428 GIC          36 :                 n_sub_key++;
    1429                 :             }
    1430 ECB             : 
    1431                 :             /* Mark the last subsidiary scankey correctly */
    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
    1436 ECB             :              * isn't going to contain a valid sk_func pointer.
    1437                 :              */
    1438 CBC         180 :             MemSet(this_scan_key, 0, sizeof(ScanKeyData));
    1439              18 :             this_scan_key->sk_flags = SK_ROW_HEADER;
    1440 GIC          18 :             this_scan_key->sk_attno = first_sub_key->sk_attno;
    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                 :         }
    1445 GIC         726 :         else if (IsA(clause, ScalarArrayOpExpr))
    1446 ECB             :         {
    1447                 :             /* indexkey op ANY (array-expression) */
    1448 GIC         375 :             ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
    1449             375 :             int         flags = 0;
    1450 ECB             :             Datum       scanvalue;
    1451                 : 
    1452 CBC         375 :             Assert(!isorderby);
    1453 ECB             : 
    1454 CBC         375 :             Assert(saop->useOr);
    1455 GIC         375 :             opno = saop->opno;
    1456             375 :             opfuncid = saop->opfuncid;
    1457                 : 
    1458                 :             /*
    1459 ECB             :              * leftop should be the index key Var, possibly relabeled
    1460                 :              */
    1461 CBC         375 :             leftop = (Expr *) linitial(saop->args);
    1462 EUB             : 
    1463 GIC         375 :             if (leftop && IsA(leftop, RelabelType))
    1464 LBC           0 :                 leftop = ((RelabelType *) leftop)->arg;
    1465                 : 
    1466 CBC         375 :             Assert(leftop != NULL);
    1467 ECB             : 
    1468 GBC         375 :             if (!(IsA(leftop, Var) &&
    1469 GIC         375 :                   ((Var *) leftop)->varno == INDEX_VAR))
    1470 LBC           0 :                 elog(ERROR, "indexqual doesn't have key on left side");
    1471 ECB             : 
    1472 GBC         375 :             varattno = ((Var *) leftop)->varattno;
    1473 GIC         375 :             if (varattno < 1 || varattno > indnkeyatts)
    1474 UIC           0 :                 elog(ERROR, "bogus index qualification");
    1475                 : 
    1476                 :             /*
    1477                 :              * We have to look up the operator's strategy number.  This
    1478 ECB             :              * provides a cross-check that the operator does match the index.
    1479                 :              */
    1480 CBC         375 :             opfamily = index->rd_opfamily[varattno - 1];
    1481                 : 
    1482 GIC         375 :             get_op_opfamily_properties(opno, opfamily, isorderby,
    1483                 :                                        &op_strategy,
    1484                 :                                        &op_lefttype,
    1485                 :                                        &op_righttype);
    1486                 : 
    1487                 :             /*
    1488 ECB             :              * rightop is the constant or variable array value
    1489                 :              */
    1490 CBC         375 :             rightop = (Expr *) lsecond(saop->args);
    1491 EUB             : 
    1492 GIC         375 :             if (rightop && IsA(rightop, RelabelType))
    1493 LBC           0 :                 rightop = ((RelabelType *) rightop)->arg;
    1494                 : 
    1495 CBC         375 :             Assert(rightop != NULL);
    1496                 : 
    1497 GIC         375 :             if (index->rd_indam->amsearcharray)
    1498 ECB             :             {
    1499                 :                 /* Index AM will handle this like a simple operator */
    1500 GIC         363 :                 flags |= SK_SEARCHARRAY;
    1501             363 :                 if (IsA(rightop, Const))
    1502 ECB             :                 {
    1503                 :                     /* OK, simple constant comparison value */
    1504 GBC         357 :                     scanvalue = ((Const *) rightop)->constvalue;
    1505 GIC         357 :                     if (((Const *) rightop)->constisnull)
    1506 UIC           0 :                         flags |= SK_ISNULL;
    1507                 :                 }
    1508                 :                 else
    1509 ECB             :                 {
    1510                 :                     /* Need to treat this one as a runtime key */
    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 *)
    1517 GIC           6 :                                 palloc(max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
    1518                 :                         }
    1519 EUB             :                         else
    1520                 :                         {
    1521 UBC           0 :                             max_runtime_keys *= 2;
    1522                 :                             runtime_keys = (IndexRuntimeKeyInfo *)
    1523 UIC           0 :                                 repalloc(runtime_keys, max_runtime_keys * sizeof(IndexRuntimeKeyInfo));
    1524 ECB             :                         }
    1525                 :                     }
    1526 CBC           6 :                     runtime_keys[n_runtime_keys].scan_key = this_scan_key;
    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
    1534 ECB             :                      * assume that all array types are toastable.
    1535                 :                      */
    1536 CBC           6 :                     runtime_keys[n_runtime_keys].key_toastable = true;
    1537 GIC           6 :                     n_runtime_keys++;
    1538               6 :                     scanvalue = (Datum) 0;
    1539                 :                 }
    1540                 :             }
    1541                 :             else
    1542 ECB             :             {
    1543                 :                 /* Executor has to expand the array value */
    1544 CBC          12 :                 array_keys[n_array_keys].scan_key = this_scan_key;
    1545 GIC          24 :                 array_keys[n_array_keys].array_expr =
    1546 CBC          12 :                     ExecInitExpr(rightop, planstate);
    1547 ECB             :                 /* the remaining fields were zeroed by palloc0 */
    1548 GIC          12 :                 n_array_keys++;
    1549              12 :                 scanvalue = (Datum) 0;
    1550                 :             }
    1551                 : 
    1552                 :             /*
    1553 ECB             :              * initialize the scan key's fields appropriately
    1554                 :              */
    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 */
    1562 ECB             :                                    scanvalue);  /* constant */
    1563                 :         }
    1564 GIC         351 :         else if (IsA(clause, NullTest))
    1565 ECB             :         {
    1566                 :             /* indexkey IS NULL or indexkey IS NOT NULL */
    1567 GIC         351 :             NullTest   *ntest = (NullTest *) clause;
    1568 ECB             :             int         flags;
    1569                 : 
    1570 GIC         351 :             Assert(!isorderby);
    1571                 : 
    1572                 :             /*
    1573 ECB             :              * argument should be the index key Var, possibly relabeled
    1574                 :              */
    1575 CBC         351 :             leftop = ntest->arg;
    1576 EUB             : 
    1577 GIC         351 :             if (leftop && IsA(leftop, RelabelType))
    1578 LBC           0 :                 leftop = ((RelabelType *) leftop)->arg;
    1579                 : 
    1580 CBC         351 :             Assert(leftop != NULL);
    1581 ECB             : 
    1582 GBC         351 :             if (!(IsA(leftop, Var) &&
    1583 GIC         351 :                   ((Var *) leftop)->varno == INDEX_VAR))
    1584 LBC           0 :                 elog(ERROR, "NullTest indexqual has wrong key");
    1585                 : 
    1586 GIC         351 :             varattno = ((Var *) leftop)->varattno;
    1587                 : 
    1588                 :             /*
    1589 ECB             :              * initialize the scan key's fields appropriately
    1590                 :              */
    1591 CBC         351 :             switch (ntest->nulltesttype)
    1592 ECB             :             {
    1593 CBC          88 :                 case IS_NULL:
    1594              88 :                     flags = SK_ISNULL | SK_SEARCHNULL;
    1595              88 :                     break;
    1596             263 :                 case IS_NOT_NULL:
    1597 GBC         263 :                     flags = SK_ISNULL | SK_SEARCHNOTNULL;
    1598             263 :                     break;
    1599 UIC           0 :                 default:
    1600               0 :                     elog(ERROR, "unrecognized nulltesttype: %d",
    1601                 :                          (int) ntest->nulltesttype);
    1602                 :                     flags = 0;  /* keep compiler quiet */
    1603                 :                     break;
    1604 ECB             :             }
    1605                 : 
    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 */
    1614 EUB             :         }
    1615                 :         else
    1616 UIC           0 :             elog(ERROR, "unsupported indexqual type: %d",
    1617                 :                  (int) nodeTag(clause));
    1618 ECB             :     }
    1619                 : 
    1620 GIC      137858 :     Assert(n_runtime_keys <= max_runtime_keys);
    1621 ECB             : 
    1622                 :     /* Get rid of any unused arrays */
    1623 CBC      137858 :     if (n_array_keys == 0)
    1624 ECB             :     {
    1625 GIC      137846 :         pfree(array_keys);
    1626          137846 :         array_keys = NULL;
    1627                 :     }
    1628                 : 
    1629                 :     /*
    1630 ECB             :      * Return info to our caller.
    1631                 :      */
    1632 CBC      137858 :     *scanKeys = scan_keys;
    1633          137858 :     *numScanKeys = n_scan_keys;
    1634          137858 :     *runtimeKeys = runtime_keys;
    1635 GIC      137858 :     *numRuntimeKeys = n_runtime_keys;
    1636 CBC      137858 :     if (arrayKeys)
    1637 ECB             :     {
    1638 GIC        9070 :         *arrayKeys = array_keys;
    1639 CBC        9070 :         *numArrayKeys = n_array_keys;
    1640 EUB             :     }
    1641 CBC      128788 :     else if (n_array_keys != 0)
    1642 UIC           0 :         elog(ERROR, "ScalarArrayOpExpr index qual found where not allowed");
    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                 :  * ----------------------------------------------------------------
    1656 ECB             :  */
    1657                 : void
    1658 GIC           6 : ExecIndexScanEstimate(IndexScanState *node,
    1659 ECB             :                       ParallelContext *pcxt)
    1660                 : {
    1661 CBC           6 :     EState     *estate = node->ss.ps.state;
    1662                 : 
    1663               6 :     node->iss_PscanLen = index_parallelscan_estimate(node->iss_RelationDesc,
    1664 ECB             :                                                      estate->es_snapshot);
    1665 CBC           6 :     shm_toc_estimate_chunk(&pcxt->estimator, node->iss_PscanLen);
    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                 :  * ----------------------------------------------------------------
    1674 ECB             :  */
    1675                 : void
    1676 GIC           6 : ExecIndexScanInitializeDSM(IndexScanState *node,
    1677 ECB             :                            ParallelContext *pcxt)
    1678                 : {
    1679 GIC           6 :     EState     *estate = node->ss.ps.state;
    1680 ECB             :     ParallelIndexScanDesc piscan;
    1681                 : 
    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,
    1685 ECB             :                                   estate->es_snapshot,
    1686                 :                                   piscan);
    1687 CBC           6 :     shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, piscan);
    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
    1697 ECB             :      * the scankeys to the index AM.
    1698                 :      */
    1699 CBC           6 :     if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
    1700               6 :         index_rescan(node->iss_ScanDesc,
    1701               6 :                      node->iss_ScanKeys, node->iss_NumScanKeys,
    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                 :  * ----------------------------------------------------------------
    1710 ECB             :  */
    1711                 : void
    1712 GIC           6 : ExecIndexScanReInitializeDSM(IndexScanState *node,
    1713 ECB             :                              ParallelContext *pcxt)
    1714                 : {
    1715 GIC           6 :     index_parallelrescan(node->iss_ScanDesc);
    1716               6 : }
    1717                 : 
    1718                 : /* ----------------------------------------------------------------
    1719                 :  *      ExecIndexScanInitializeWorker
    1720                 :  *
    1721                 :  *      Copy relevant information from TOC into planstate.
    1722                 :  * ----------------------------------------------------------------
    1723 ECB             :  */
    1724                 : void
    1725 GIC          48 : ExecIndexScanInitializeWorker(IndexScanState *node,
    1726                 :                               ParallelWorkerContext *pwcxt)
    1727                 : {
    1728 ECB             :     ParallelIndexScanDesc piscan;
    1729                 : 
    1730 CBC          48 :     piscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
    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
    1740 ECB             :      * the scankeys to the index AM.
    1741                 :      */
    1742 CBC          48 :     if (node->iss_NumRuntimeKeys == 0 || node->iss_RuntimeKeysReady)
    1743              48 :         index_rescan(node->iss_ScanDesc,
    1744              48 :                      node->iss_ScanKeys, node->iss_NumScanKeys,
    1745 GIC          48 :                      node->iss_OrderByKeys, node->iss_NumOrderByKeys);
    1746              48 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a