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 17:13:01 Functions: 100.0 % 22 22 21 1 21
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 1 1 1
Legend: Lines: hit not hit (240..) days: 89.6 % 557 499 17 26 15 18 288 193 25 287
Function coverage date bins:
(240..) days: 51.2 % 43 22 21 1 21

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

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