LCOV - code coverage report
Current view: top level - src/backend/executor - nodeSubplan.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 95.5 % 577 551
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 13 13
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 66.9 % 359 240

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * nodeSubplan.c
       4                 :             :  *        routines to support sub-selects appearing in expressions
       5                 :             :  *
       6                 :             :  * This module is concerned with executing SubPlan expression nodes, which
       7                 :             :  * should not be confused with sub-SELECTs appearing in FROM.  SubPlans are
       8                 :             :  * divided into "initplans", which are those that need only one evaluation per
       9                 :             :  * query (among other restrictions, this requires that they don't use any
      10                 :             :  * direct correlation variables from the parent plan level), and "regular"
      11                 :             :  * subplans, which are re-evaluated every time their result is required.
      12                 :             :  *
      13                 :             :  *
      14                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      15                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      16                 :             :  *
      17                 :             :  * IDENTIFICATION
      18                 :             :  *        src/backend/executor/nodeSubplan.c
      19                 :             :  *
      20                 :             :  *-------------------------------------------------------------------------
      21                 :             :  */
      22                 :             : /*
      23                 :             :  *       INTERFACE ROUTINES
      24                 :             :  *              ExecSubPlan  - process a subselect
      25                 :             :  *              ExecInitSubPlan - initialize a subselect
      26                 :             :  */
      27                 :             : #include "postgres.h"
      28                 :             : 
      29                 :             : #include "access/htup_details.h"
      30                 :             : #include "executor/executor.h"
      31                 :             : #include "executor/nodeSubplan.h"
      32                 :             : #include "miscadmin.h"
      33                 :             : #include "nodes/makefuncs.h"
      34                 :             : #include "nodes/nodeFuncs.h"
      35                 :             : #include "utils/array.h"
      36                 :             : #include "utils/lsyscache.h"
      37                 :             : #include "utils/memutils.h"
      38                 :             : 
      39                 :             : static Datum ExecHashSubPlan(SubPlanState *node,
      40                 :             :                                                          ExprContext *econtext,
      41                 :             :                                                          bool *isNull);
      42                 :             : static Datum ExecScanSubPlan(SubPlanState *node,
      43                 :             :                                                          ExprContext *econtext,
      44                 :             :                                                          bool *isNull);
      45                 :             : static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext);
      46                 :             : static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
      47                 :             :                                                          FmgrInfo *eqfunctions);
      48                 :             : static bool slotAllNulls(TupleTableSlot *slot);
      49                 :             : static bool slotNoNulls(TupleTableSlot *slot);
      50                 :             : 
      51                 :             : 
      52                 :             : /* ----------------------------------------------------------------
      53                 :             :  *              ExecSubPlan
      54                 :             :  *
      55                 :             :  * This is the main entry point for execution of a regular SubPlan.
      56                 :             :  * ----------------------------------------------------------------
      57                 :             :  */
      58                 :             : Datum
      59                 :       97550 : ExecSubPlan(SubPlanState *node,
      60                 :             :                         ExprContext *econtext,
      61                 :             :                         bool *isNull)
      62                 :             : {
      63                 :       97550 :         SubPlan    *subplan = node->subplan;
      64                 :       97550 :         EState     *estate = node->planstate->state;
      65                 :       97550 :         ScanDirection dir = estate->es_direction;
      66                 :       97550 :         Datum           retval;
      67                 :             : 
      68         [ +  - ]:       97550 :         CHECK_FOR_INTERRUPTS();
      69                 :             : 
      70                 :             :         /* Set non-null as default */
      71                 :       97550 :         *isNull = false;
      72                 :             : 
      73                 :             :         /* Sanity checks */
      74         [ +  - ]:       97550 :         if (subplan->subLinkType == CTE_SUBLINK)
      75   [ #  #  #  # ]:           0 :                 elog(ERROR, "CTE subplans should not be executed via ExecSubPlan");
      76   [ +  +  +  - ]:       97550 :         if (subplan->setParam != NIL && subplan->subLinkType != MULTIEXPR_SUBLINK)
      77   [ #  #  #  # ]:           0 :                 elog(ERROR, "cannot set parent params from subquery");
      78                 :             : 
      79                 :             :         /* Force forward-scan mode for evaluation */
      80                 :       97550 :         estate->es_direction = ForwardScanDirection;
      81                 :             : 
      82                 :             :         /* Select appropriate evaluation strategy */
      83         [ +  + ]:       97550 :         if (subplan->useHashTable)
      84                 :       71513 :                 retval = ExecHashSubPlan(node, econtext, isNull);
      85                 :             :         else
      86                 :       26037 :                 retval = ExecScanSubPlan(node, econtext, isNull);
      87                 :             : 
      88                 :             :         /* restore scan direction */
      89                 :       97550 :         estate->es_direction = dir;
      90                 :             : 
      91                 :      195100 :         return retval;
      92                 :       97550 : }
      93                 :             : 
      94                 :             : /*
      95                 :             :  * ExecHashSubPlan: store subselect result in an in-memory hash table
      96                 :             :  */
      97                 :             : static Datum
      98                 :       71512 : ExecHashSubPlan(SubPlanState *node,
      99                 :             :                                 ExprContext *econtext,
     100                 :             :                                 bool *isNull)
     101                 :             : {
     102                 :       71512 :         bool            result = false;
     103                 :       71512 :         SubPlan    *subplan = node->subplan;
     104                 :       71512 :         PlanState  *planstate = node->planstate;
     105                 :       71512 :         TupleTableSlot *slot;
     106                 :             : 
     107                 :             :         /* Shouldn't have any direct correlation Vars */
     108         [ +  - ]:       71512 :         if (subplan->parParam != NIL || subplan->args != NIL)
     109   [ #  #  #  # ]:           0 :                 elog(ERROR, "hashed subplan with direct correlation not supported");
     110                 :             : 
     111                 :             :         /*
     112                 :             :          * If first time through or we need to rescan the subplan, build the hash
     113                 :             :          * table.
     114                 :             :          */
     115   [ +  +  +  + ]:       71512 :         if (node->hashtable == NULL || planstate->chgParam != NULL)
     116                 :         174 :                 buildSubPlanHash(node, econtext);
     117                 :             : 
     118                 :             :         /*
     119                 :             :          * The result for an empty subplan is always FALSE; no need to evaluate
     120                 :             :          * lefthand side.
     121                 :             :          */
     122                 :       71512 :         *isNull = false;
     123   [ +  +  +  + ]:       71512 :         if (!node->havehashrows && !node->havenullrows)
     124                 :          35 :                 return BoolGetDatum(false);
     125                 :             : 
     126                 :             :         /*
     127                 :             :          * Evaluate lefthand expressions and form a projection tuple. First we
     128                 :             :          * have to set the econtext to use (hack alert!).
     129                 :             :          */
     130                 :       71477 :         node->projLeft->pi_exprContext = econtext;
     131                 :       71477 :         slot = ExecProject(node->projLeft);
     132                 :             : 
     133                 :             :         /*
     134                 :             :          * If the LHS is all non-null, probe for an exact match in the main hash
     135                 :             :          * table.  If we find one, the result is TRUE. Otherwise, scan the
     136                 :             :          * partly-null table to see if there are any rows that aren't provably
     137                 :             :          * unequal to the LHS; if so, the result is UNKNOWN.  (We skip that part
     138                 :             :          * if we don't care about UNKNOWN.) Otherwise, the result is FALSE.
     139                 :             :          *
     140                 :             :          * Note: the reason we can avoid a full scan of the main hash table is
     141                 :             :          * that the combining operators are assumed never to yield NULL when both
     142                 :             :          * inputs are non-null.  If they were to do so, we might need to produce
     143                 :             :          * UNKNOWN instead of FALSE because of an UNKNOWN result in comparing the
     144                 :             :          * LHS to some main-table entry --- which is a comparison we will not even
     145                 :             :          * make, unless there's a chance match of hash keys.
     146                 :             :          */
     147         [ +  + ]:       71477 :         if (slotNoNulls(slot))
     148                 :             :         {
     149   [ +  +  +  + ]:       71471 :                 if (node->havehashrows &&
     150                 :      142934 :                         FindTupleHashEntry(node->hashtable,
     151                 :       71467 :                                                            slot,
     152                 :       71467 :                                                            node->cur_eq_comp,
     153                 :      142934 :                                                            node->lhs_hash_expr) != NULL)
     154                 :       10496 :                         result = true;
     155   [ +  +  +  + ]:       60975 :                 else if (node->havenullrows &&
     156                 :           6 :                                  findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
     157                 :           3 :                         *isNull = true;
     158                 :       71471 :         }
     159                 :             : 
     160                 :             :         /*
     161                 :             :          * When the LHS is partly or wholly NULL, we can never return TRUE. If we
     162                 :             :          * don't care about UNKNOWN, just return FALSE.  Otherwise, if the LHS is
     163                 :             :          * wholly NULL, immediately return UNKNOWN.  (Since the combining
     164                 :             :          * operators are strict, the result could only be FALSE if the sub-select
     165                 :             :          * were empty, but we already handled that case.) Otherwise, we must scan
     166                 :             :          * both the main and partly-null tables to see if there are any rows that
     167                 :             :          * aren't provably unequal to the LHS; if so, the result is UNKNOWN.
     168                 :             :          * Otherwise, the result is FALSE.
     169                 :             :          */
     170         [ +  - ]:           6 :         else if (node->hashnulls == NULL)
     171                 :             :                  /* just return FALSE */ ;
     172         [ -  + ]:           6 :         else if (slotAllNulls(slot))
     173                 :           0 :                 *isNull = true;
     174                 :             :         /* Scan partly-null table first, since more likely to get a match */
     175   [ +  -  +  + ]:           6 :         else if (node->havenullrows &&
     176                 :           6 :                          findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
     177                 :           3 :                 *isNull = true;
     178   [ +  +  +  - ]:           3 :         else if (node->havehashrows &&
     179                 :           1 :                          findPartialMatch(node->hashtable, slot, node->cur_eq_funcs))
     180                 :           0 :                 *isNull = true;
     181                 :             : 
     182                 :             :         /*
     183                 :             :          * Note: because we are typically called in a per-tuple context, we have
     184                 :             :          * to explicitly clear the projected tuple before returning. Otherwise,
     185                 :             :          * we'll have a double-free situation: the per-tuple context will probably
     186                 :             :          * be reset before we're called again, and then the tuple slot will think
     187                 :             :          * it still needs to free the tuple.
     188                 :             :          */
     189                 :       71477 :         ExecClearTuple(slot);
     190                 :             : 
     191                 :             :         /* Also must reset the innerecontext after each hashtable lookup. */
     192                 :       71477 :         ResetExprContext(node->innerecontext);
     193                 :             : 
     194                 :       71477 :         return BoolGetDatum(result);
     195                 :       71512 : }
     196                 :             : 
     197                 :             : /*
     198                 :             :  * ExecScanSubPlan: default case where we have to rescan subplan each time
     199                 :             :  */
     200                 :             : static Datum
     201                 :       26037 : ExecScanSubPlan(SubPlanState *node,
     202                 :             :                                 ExprContext *econtext,
     203                 :             :                                 bool *isNull)
     204                 :             : {
     205                 :       26037 :         SubPlan    *subplan = node->subplan;
     206                 :       26037 :         PlanState  *planstate = node->planstate;
     207                 :       26037 :         SubLinkType subLinkType = subplan->subLinkType;
     208                 :       26037 :         MemoryContext oldcontext;
     209                 :       26037 :         TupleTableSlot *slot;
     210                 :       26037 :         Datum           result;
     211                 :       26037 :         bool            found = false;  /* true if got at least one subplan tuple */
     212                 :       26037 :         ListCell   *l;
     213                 :       26037 :         ArrayBuildStateAny *astate = NULL;
     214                 :             : 
     215                 :             :         /* Initialize ArrayBuildStateAny in caller's context, if needed */
     216         [ +  + ]:       26037 :         if (subLinkType == ARRAY_SUBLINK)
     217                 :        1610 :                 astate = initArrayResultAny(subplan->firstColType,
     218                 :         805 :                                                                         CurrentMemoryContext, true);
     219                 :             : 
     220                 :             :         /*
     221                 :             :          * We are probably in a short-lived expression-evaluation context. Switch
     222                 :             :          * to the per-query context for manipulating the child plan's chgParam,
     223                 :             :          * calling ExecProcNode on it, etc.
     224                 :             :          */
     225                 :       26037 :         oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
     226                 :             : 
     227                 :             :         /*
     228                 :             :          * We rely on the caller to evaluate plan correlation values, if
     229                 :             :          * necessary. However we still need to record the fact that the values
     230                 :             :          * (might have) changed, otherwise the ExecReScan() below won't know that
     231                 :             :          * nodes need to be rescanned.
     232                 :             :          */
     233   [ +  +  +  +  :       56640 :         foreach(l, subplan->parParam)
                   +  + ]
     234                 :             :         {
     235                 :       30603 :                 int                     paramid = lfirst_int(l);
     236                 :             : 
     237                 :       30603 :                 planstate->chgParam = bms_add_member(planstate->chgParam, paramid);
     238                 :       30603 :         }
     239                 :             : 
     240                 :             :         /* with that done, we can reset the subplan */
     241                 :       26037 :         ExecReScan(planstate);
     242                 :             : 
     243                 :             :         /*
     244                 :             :          * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
     245                 :             :          * is boolean as are the results of the combining operators. We combine
     246                 :             :          * results across tuples (if the subplan produces more than one) using OR
     247                 :             :          * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
     248                 :             :          * (ROWCOMPARE_SUBLINK doesn't allow multiple tuples from the subplan.)
     249                 :             :          * NULL results from the combining operators are handled according to the
     250                 :             :          * usual SQL semantics for OR and AND.  The result for no input tuples is
     251                 :             :          * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
     252                 :             :          * ROWCOMPARE_SUBLINK.
     253                 :             :          *
     254                 :             :          * For EXPR_SUBLINK we require the subplan to produce no more than one
     255                 :             :          * tuple, else an error is raised.  If zero tuples are produced, we return
     256                 :             :          * NULL.  Assuming we get a tuple, we just use its first column (there can
     257                 :             :          * be only one non-junk column in this case).
     258                 :             :          *
     259                 :             :          * For MULTIEXPR_SUBLINK, we push the per-column subplan outputs out to
     260                 :             :          * the setParams and then return a dummy false value.  There must not be
     261                 :             :          * multiple tuples returned from the subplan; if zero tuples are produced,
     262                 :             :          * set the setParams to NULL.
     263                 :             :          *
     264                 :             :          * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
     265                 :             :          * and form an array of the first column's values.  Note in particular
     266                 :             :          * that we produce a zero-element array if no tuples are produced (this is
     267                 :             :          * a change from pre-8.3 behavior of returning NULL).
     268                 :             :          */
     269                 :       26037 :         result = BoolGetDatum(subLinkType == ALL_SUBLINK);
     270                 :       26037 :         *isNull = false;
     271                 :             : 
     272         [ +  + ]:       81774 :         for (slot = ExecProcNode(planstate);
     273         [ +  + ]:       40887 :                  !TupIsNull(slot);
     274                 :       14850 :                  slot = ExecProcNode(planstate))
     275                 :             :         {
     276                 :       14953 :                 TupleDesc       tdesc = slot->tts_tupleDescriptor;
     277                 :       14953 :                 Datum           rowresult;
     278                 :       14953 :                 bool            rownull;
     279                 :       14953 :                 int                     col;
     280                 :       14953 :                 ListCell   *plst;
     281                 :             : 
     282         [ +  + ]:       14953 :                 if (subLinkType == EXISTS_SUBLINK)
     283                 :             :                 {
     284                 :          80 :                         found = true;
     285                 :          80 :                         result = BoolGetDatum(true);
     286                 :          80 :                         break;
     287                 :             :                 }
     288                 :             : 
     289         [ +  + ]:       14873 :                 if (subLinkType == EXPR_SUBLINK)
     290                 :             :                 {
     291                 :             :                         /* cannot allow multiple input tuples for EXPR sublink */
     292         [ +  - ]:       12316 :                         if (found)
     293   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     294                 :             :                                                 (errcode(ERRCODE_CARDINALITY_VIOLATION),
     295                 :             :                                                  errmsg("more than one row returned by a subquery used as an expression")));
     296                 :       12316 :                         found = true;
     297                 :             : 
     298                 :             :                         /*
     299                 :             :                          * We need to copy the subplan's tuple in case the result is of
     300                 :             :                          * pass-by-ref type --- our return value will point into this
     301                 :             :                          * copied tuple!  Can't use the subplan's instance of the tuple
     302                 :             :                          * since it won't still be valid after next ExecProcNode() call.
     303                 :             :                          * node->curTuple keeps track of the copied tuple for eventual
     304                 :             :                          * freeing.
     305                 :             :                          */
     306         [ +  + ]:       12316 :                         if (node->curTuple)
     307                 :       12048 :                                 heap_freetuple(node->curTuple);
     308                 :       12316 :                         node->curTuple = ExecCopySlotHeapTuple(slot);
     309                 :             : 
     310                 :       12316 :                         result = heap_getattr(node->curTuple, 1, tdesc, isNull);
     311                 :             :                         /* keep scanning subplan to make sure there's only one tuple */
     312                 :       12316 :                         continue;
     313                 :             :                 }
     314                 :             : 
     315         [ +  + ]:        2557 :                 if (subLinkType == MULTIEXPR_SUBLINK)
     316                 :             :                 {
     317                 :             :                         /* cannot allow multiple input tuples for MULTIEXPR sublink */
     318         [ +  - ]:          38 :                         if (found)
     319   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     320                 :             :                                                 (errcode(ERRCODE_CARDINALITY_VIOLATION),
     321                 :             :                                                  errmsg("more than one row returned by a subquery used as an expression")));
     322                 :          38 :                         found = true;
     323                 :             : 
     324                 :             :                         /*
     325                 :             :                          * We need to copy the subplan's tuple in case any result is of
     326                 :             :                          * pass-by-ref type --- our output values will point into this
     327                 :             :                          * copied tuple!  Can't use the subplan's instance of the tuple
     328                 :             :                          * since it won't still be valid after next ExecProcNode() call.
     329                 :             :                          * node->curTuple keeps track of the copied tuple for eventual
     330                 :             :                          * freeing.
     331                 :             :                          */
     332         [ +  + ]:          38 :                         if (node->curTuple)
     333                 :          24 :                                 heap_freetuple(node->curTuple);
     334                 :          38 :                         node->curTuple = ExecCopySlotHeapTuple(slot);
     335                 :             : 
     336                 :             :                         /*
     337                 :             :                          * Now set all the setParam params from the columns of the tuple
     338                 :             :                          */
     339                 :          38 :                         col = 1;
     340   [ +  -  +  +  :         114 :                         foreach(plst, subplan->setParam)
                   +  + ]
     341                 :             :                         {
     342                 :          76 :                                 int                     paramid = lfirst_int(plst);
     343                 :          76 :                                 ParamExecData *prmdata;
     344                 :             : 
     345                 :          76 :                                 prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
     346         [ +  - ]:          76 :                                 Assert(prmdata->execPlan == NULL);
     347                 :         152 :                                 prmdata->value = heap_getattr(node->curTuple, col, tdesc,
     348                 :          76 :                                                                                           &(prmdata->isnull));
     349                 :          76 :                                 col++;
     350                 :          76 :                         }
     351                 :             : 
     352                 :             :                         /* keep scanning subplan to make sure there's only one tuple */
     353                 :          38 :                         continue;
     354                 :             :                 }
     355                 :             : 
     356         [ +  + ]:        2519 :                 if (subLinkType == ARRAY_SUBLINK)
     357                 :             :                 {
     358                 :         671 :                         Datum           dvalue;
     359                 :         671 :                         bool            disnull;
     360                 :             : 
     361                 :         671 :                         found = true;
     362                 :             :                         /* stash away current value */
     363         [ -  + ]:         671 :                         Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
     364                 :         671 :                         dvalue = slot_getattr(slot, 1, &disnull);
     365                 :        1342 :                         astate = accumArrayResultAny(astate, dvalue, disnull,
     366                 :         671 :                                                                                  subplan->firstColType, oldcontext);
     367                 :             :                         /* keep scanning subplan to collect all values */
     368                 :             :                         continue;
     369                 :         671 :                 }
     370                 :             : 
     371                 :             :                 /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
     372   [ +  +  -  + ]:        1848 :                 if (subLinkType == ROWCOMPARE_SUBLINK && found)
     373   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     374                 :             :                                         (errcode(ERRCODE_CARDINALITY_VIOLATION),
     375                 :             :                                          errmsg("more than one row returned by a subquery used as an expression")));
     376                 :             : 
     377                 :        1848 :                 found = true;
     378                 :             : 
     379                 :             :                 /*
     380                 :             :                  * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params
     381                 :             :                  * representing the columns of the sub-select, and then evaluate the
     382                 :             :                  * combining expression.
     383                 :             :                  */
     384                 :        1848 :                 col = 1;
     385   [ +  -  +  +  :        5488 :                 foreach(plst, subplan->paramIds)
                   +  + ]
     386                 :             :                 {
     387                 :        3640 :                         int                     paramid = lfirst_int(plst);
     388                 :        3640 :                         ParamExecData *prmdata;
     389                 :             : 
     390                 :        3640 :                         prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
     391         [ +  - ]:        3640 :                         Assert(prmdata->execPlan == NULL);
     392                 :        3640 :                         prmdata->value = slot_getattr(slot, col, &(prmdata->isnull));
     393                 :        3640 :                         col++;
     394                 :        3640 :                 }
     395                 :             : 
     396                 :        1848 :                 rowresult = ExecEvalExprSwitchContext(node->testexpr, econtext,
     397                 :             :                                                                                           &rownull);
     398                 :             : 
     399         [ +  + ]:        1848 :                 if (subLinkType == ANY_SUBLINK)
     400                 :             :                 {
     401                 :             :                         /* combine across rows per OR semantics */
     402         [ -  + ]:        1825 :                         if (rownull)
     403                 :           0 :                                 *isNull = true;
     404         [ +  + ]:        1825 :                         else if (DatumGetBool(rowresult))
     405                 :             :                         {
     406                 :          19 :                                 result = BoolGetDatum(true);
     407                 :          19 :                                 *isNull = false;
     408                 :          19 :                                 break;                  /* needn't look at any more rows */
     409                 :             :                         }
     410                 :        1806 :                 }
     411         [ +  + ]:          23 :                 else if (subLinkType == ALL_SUBLINK)
     412                 :             :                 {
     413                 :             :                         /* combine across rows per AND semantics */
     414         [ -  + ]:          15 :                         if (rownull)
     415                 :           0 :                                 *isNull = true;
     416         [ +  + ]:          15 :                         else if (!DatumGetBool(rowresult))
     417                 :             :                         {
     418                 :           4 :                                 result = BoolGetDatum(false);
     419                 :           4 :                                 *isNull = false;
     420                 :           4 :                                 break;                  /* needn't look at any more rows */
     421                 :             :                         }
     422                 :          11 :                 }
     423                 :             :                 else
     424                 :             :                 {
     425                 :             :                         /* must be ROWCOMPARE_SUBLINK */
     426                 :           8 :                         result = rowresult;
     427                 :           8 :                         *isNull = rownull;
     428                 :             :                 }
     429   [ -  +  +  + ]:       14953 :         }
     430                 :             : 
     431                 :       26037 :         MemoryContextSwitchTo(oldcontext);
     432                 :             : 
     433         [ +  + ]:       26037 :         if (subLinkType == ARRAY_SUBLINK)
     434                 :             :         {
     435                 :             :                 /* We return the result in the caller's context */
     436                 :         805 :                 result = makeArrayResultAny(astate, oldcontext, true);
     437                 :         805 :         }
     438         [ +  + ]:       25232 :         else if (!found)
     439                 :             :         {
     440                 :             :                 /*
     441                 :             :                  * deal with empty subplan result.  result/isNull were previously
     442                 :             :                  * initialized correctly for all sublink types except EXPR and
     443                 :             :                  * ROWCOMPARE; for those, return NULL.
     444                 :             :                  */
     445   [ +  +  -  + ]:       11863 :                 if (subLinkType == EXPR_SUBLINK ||
     446                 :         182 :                         subLinkType == ROWCOMPARE_SUBLINK)
     447                 :             :                 {
     448                 :       11681 :                         result = (Datum) 0;
     449                 :       11681 :                         *isNull = true;
     450                 :       11681 :                 }
     451         [ +  + ]:         182 :                 else if (subLinkType == MULTIEXPR_SUBLINK)
     452                 :             :                 {
     453                 :             :                         /* We don't care about function result, but set the setParams */
     454   [ +  -  +  +  :           3 :                         foreach(l, subplan->setParam)
                   +  + ]
     455                 :             :                         {
     456                 :           2 :                                 int                     paramid = lfirst_int(l);
     457                 :           2 :                                 ParamExecData *prmdata;
     458                 :             : 
     459                 :           2 :                                 prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
     460         [ +  - ]:           2 :                                 Assert(prmdata->execPlan == NULL);
     461                 :           2 :                                 prmdata->value = (Datum) 0;
     462                 :           2 :                                 prmdata->isnull = true;
     463                 :           2 :                         }
     464                 :           1 :                 }
     465                 :       11863 :         }
     466                 :             : 
     467                 :       52074 :         return result;
     468                 :       26037 : }
     469                 :             : 
     470                 :             : /*
     471                 :             :  * buildSubPlanHash: load hash table by scanning subplan output.
     472                 :             :  */
     473                 :             : static void
     474                 :         174 : buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
     475                 :             : {
     476                 :         174 :         SubPlan    *subplan = node->subplan;
     477                 :         174 :         PlanState  *planstate = node->planstate;
     478                 :         174 :         int                     ncols = node->numCols;
     479                 :         174 :         ExprContext *innerecontext = node->innerecontext;
     480                 :         174 :         MemoryContext oldcontext;
     481                 :         174 :         double          nentries;
     482                 :         174 :         TupleTableSlot *slot;
     483                 :             : 
     484         [ +  - ]:         174 :         Assert(subplan->subLinkType == ANY_SUBLINK);
     485                 :             : 
     486                 :             :         /*
     487                 :             :          * If we already had any hash tables, reset 'em; otherwise create empty
     488                 :             :          * hash table(s).
     489                 :             :          *
     490                 :             :          * If we need to distinguish accurately between FALSE and UNKNOWN (i.e.,
     491                 :             :          * NULL) results of the IN operation, then we have to store subplan output
     492                 :             :          * rows that are partly or wholly NULL.  We store such rows in a separate
     493                 :             :          * hash table that we expect will be much smaller than the main table. (We
     494                 :             :          * can use hashing to eliminate partly-null rows that are not distinct. We
     495                 :             :          * keep them separate to minimize the cost of the inevitable full-table
     496                 :             :          * searches; see findPartialMatch.)
     497                 :             :          *
     498                 :             :          * If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
     499                 :             :          * need to store subplan output rows that contain NULL.
     500                 :             :          *
     501                 :             :          * Because the input slot for each hash table is always the slot resulting
     502                 :             :          * from an ExecProject(), we can use TTSOpsVirtual for the input ops. This
     503                 :             :          * saves a needless fetch inner op step for the hashing ExprState created
     504                 :             :          * in BuildTupleHashTable().
     505                 :             :          */
     506                 :         174 :         node->havehashrows = false;
     507                 :         174 :         node->havenullrows = false;
     508                 :             : 
     509                 :         174 :         nentries = planstate->plan->plan_rows;
     510                 :             : 
     511         [ +  + ]:         174 :         if (node->hashtable)
     512                 :          99 :                 ResetTupleHashTable(node->hashtable);
     513                 :             :         else
     514                 :         150 :                 node->hashtable = BuildTupleHashTable(node->parent,
     515                 :          75 :                                                                                           node->descRight,
     516                 :             :                                                                                           &TTSOpsVirtual,
     517                 :          75 :                                                                                           ncols,
     518                 :          75 :                                                                                           node->keyColIdx,
     519                 :          75 :                                                                                           node->tab_eq_funcoids,
     520                 :          75 :                                                                                           node->tab_hash_funcs,
     521                 :          75 :                                                                                           node->tab_collations,
     522                 :          75 :                                                                                           nentries,
     523                 :             :                                                                                           0,    /* no additional data */
     524                 :          75 :                                                                                           node->planstate->state->es_query_cxt,
     525                 :          75 :                                                                                           node->tuplesContext,
     526                 :          75 :                                                                                           innerecontext->ecxt_per_tuple_memory,
     527                 :             :                                                                                           false);
     528                 :             : 
     529         [ +  + ]:         174 :         if (!subplan->unknownEqFalse)
     530                 :             :         {
     531         [ +  + ]:         131 :                 if (ncols == 1)
     532                 :         120 :                         nentries = 1;           /* there can only be one entry */
     533                 :             :                 else
     534                 :             :                 {
     535                 :          11 :                         nentries /= 16;
     536         [ +  - ]:          11 :                         if (nentries < 1)
     537                 :           0 :                                 nentries = 1;
     538                 :             :                 }
     539                 :             : 
     540         [ +  + ]:         131 :                 if (node->hashnulls)
     541                 :          99 :                         ResetTupleHashTable(node->hashnulls);
     542                 :             :                 else
     543                 :          64 :                         node->hashnulls = BuildTupleHashTable(node->parent,
     544                 :          32 :                                                                                                   node->descRight,
     545                 :             :                                                                                                   &TTSOpsVirtual,
     546                 :          32 :                                                                                                   ncols,
     547                 :          32 :                                                                                                   node->keyColIdx,
     548                 :          32 :                                                                                                   node->tab_eq_funcoids,
     549                 :          32 :                                                                                                   node->tab_hash_funcs,
     550                 :          32 :                                                                                                   node->tab_collations,
     551                 :          32 :                                                                                                   nentries,
     552                 :             :                                                                                                   0,    /* no additional data */
     553                 :          32 :                                                                                                   node->planstate->state->es_query_cxt,
     554                 :          32 :                                                                                                   node->tuplesContext,
     555                 :          32 :                                                                                                   innerecontext->ecxt_per_tuple_memory,
     556                 :             :                                                                                                   false);
     557                 :         131 :         }
     558                 :             :         else
     559                 :          43 :                 node->hashnulls = NULL;
     560                 :             : 
     561                 :             :         /*
     562                 :             :          * We are probably in a short-lived expression-evaluation context. Switch
     563                 :             :          * to the per-query context for manipulating the child plan.
     564                 :             :          */
     565                 :         174 :         oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
     566                 :             : 
     567                 :             :         /*
     568                 :             :          * Reset subplan to start.
     569                 :             :          */
     570                 :         174 :         ExecReScan(planstate);
     571                 :             : 
     572                 :             :         /*
     573                 :             :          * Scan the subplan and load the hash table(s).  Note that when there are
     574                 :             :          * duplicate rows coming out of the sub-select, only one copy is stored.
     575                 :             :          */
     576         [ +  + ]:      115106 :         for (slot = ExecProcNode(planstate);
     577         [ +  + ]:       57553 :                  !TupIsNull(slot);
     578                 :       57379 :                  slot = ExecProcNode(planstate))
     579                 :             :         {
     580                 :       57379 :                 int                     col = 1;
     581                 :       57379 :                 ListCell   *plst;
     582                 :       57379 :                 bool            isnew;
     583                 :             : 
     584                 :             :                 /*
     585                 :             :                  * Load up the Params representing the raw sub-select outputs, then
     586                 :             :                  * form the projection tuple to store in the hashtable.
     587                 :             :                  */
     588   [ +  -  +  +  :      150734 :                 foreach(plst, subplan->paramIds)
                   +  + ]
     589                 :             :                 {
     590                 :       93355 :                         int                     paramid = lfirst_int(plst);
     591                 :       93355 :                         ParamExecData *prmdata;
     592                 :             : 
     593                 :       93355 :                         prmdata = &(innerecontext->ecxt_param_exec_vals[paramid]);
     594         [ +  - ]:       93355 :                         Assert(prmdata->execPlan == NULL);
     595                 :      186710 :                         prmdata->value = slot_getattr(slot, col,
     596                 :       93355 :                                                                                   &(prmdata->isnull));
     597                 :       93355 :                         col++;
     598                 :       93355 :                 }
     599                 :       57379 :                 slot = ExecProject(node->projRight);
     600                 :             : 
     601                 :             :                 /*
     602                 :             :                  * If result contains any nulls, store separately or not at all.
     603                 :             :                  */
     604         [ +  + ]:       57379 :                 if (slotNoNulls(slot))
     605                 :             :                 {
     606                 :       57375 :                         (void) LookupTupleHashEntry(node->hashtable, slot, &isnew, NULL);
     607                 :       57375 :                         node->havehashrows = true;
     608                 :       57375 :                 }
     609         [ -  + ]:           4 :                 else if (node->hashnulls)
     610                 :             :                 {
     611                 :           4 :                         (void) LookupTupleHashEntry(node->hashnulls, slot, &isnew, NULL);
     612                 :           4 :                         node->havenullrows = true;
     613                 :           4 :                 }
     614                 :             : 
     615                 :             :                 /*
     616                 :             :                  * Reset innerecontext after each inner tuple to free any memory used
     617                 :             :                  * during ExecProject and hashtable lookup.
     618                 :             :                  */
     619                 :       57379 :                 ResetExprContext(innerecontext);
     620                 :       57379 :         }
     621                 :             : 
     622                 :             :         /*
     623                 :             :          * Since the projected tuples are in the sub-query's context and not the
     624                 :             :          * main context, we'd better clear the tuple slot before there's any
     625                 :             :          * chance of a reset of the sub-query's context.  Else we will have the
     626                 :             :          * potential for a double free attempt.  (XXX possibly no longer needed,
     627                 :             :          * but can't hurt.)
     628                 :             :          */
     629                 :         174 :         ExecClearTuple(node->projRight->pi_state.resultslot);
     630                 :             : 
     631                 :         174 :         MemoryContextSwitchTo(oldcontext);
     632                 :         174 : }
     633                 :             : 
     634                 :             : /* Planner support routine to estimate space needed for hash table(s) */
     635                 :             : Size
     636                 :         466 : EstimateSubplanHashTableSpace(double nentries,
     637                 :             :                                                           Size tupleWidth,
     638                 :             :                                                           bool unknownEqFalse)
     639                 :             : {
     640                 :         466 :         Size            tab1space,
     641                 :             :                                 tab2space;
     642                 :             : 
     643                 :             :         /* Estimate size of main hashtable */
     644                 :         932 :         tab1space = EstimateTupleHashTableSpace(nentries,
     645                 :         466 :                                                                                         tupleWidth,
     646                 :             :                                                                                         0 /* no additional data */ );
     647                 :             : 
     648                 :             :         /* Give up if that's already too big */
     649         [ +  + ]:         466 :         if (tab1space >= SIZE_MAX)
     650                 :           1 :                 return tab1space;
     651                 :             : 
     652                 :             :         /* Done if we don't need a hashnulls table */
     653         [ +  + ]:         465 :         if (unknownEqFalse)
     654                 :         410 :                 return tab1space;
     655                 :             : 
     656                 :             :         /*
     657                 :             :          * Adjust the rowcount estimate in the same way that buildSubPlanHash
     658                 :             :          * will, except that we don't bother with the special case for a single
     659                 :             :          * hash column.  (We skip that detail because it'd be notationally painful
     660                 :             :          * for our caller to provide the column count, and this table has
     661                 :             :          * relatively little impact on the total estimate anyway.)
     662                 :             :          */
     663                 :          55 :         nentries /= 16;
     664         [ +  + ]:          55 :         if (nentries < 1)
     665                 :          19 :                 nentries = 1;
     666                 :             : 
     667                 :             :         /*
     668                 :             :          * It might be sane to also reduce the tupleWidth, but on the other hand
     669                 :             :          * we are not accounting for the space taken by the tuples' null bitmaps.
     670                 :             :          * Leave it alone for now.
     671                 :             :          */
     672                 :         110 :         tab2space = EstimateTupleHashTableSpace(nentries,
     673                 :          55 :                                                                                         tupleWidth,
     674                 :             :                                                                                         0 /* no additional data */ );
     675                 :             : 
     676                 :             :         /* Guard against overflow */
     677         [ -  + ]:          55 :         if (tab2space >= SIZE_MAX - tab1space)
     678                 :           0 :                 return SIZE_MAX;
     679                 :             : 
     680                 :          55 :         return tab1space + tab2space;
     681                 :         466 : }
     682                 :             : 
     683                 :             : /*
     684                 :             :  * execTuplesUnequal
     685                 :             :  *              Return true if two tuples are definitely unequal in the indicated
     686                 :             :  *              fields.
     687                 :             :  *
     688                 :             :  * Nulls are neither equal nor unequal to anything else.  A true result
     689                 :             :  * is obtained only if there are non-null fields that compare not-equal.
     690                 :             :  *
     691                 :             :  * slot1, slot2: the tuples to compare (must have same columns!)
     692                 :             :  * numCols: the number of attributes to be examined
     693                 :             :  * matchColIdx: array of attribute column numbers
     694                 :             :  * eqFunctions: array of fmgr lookup info for the equality functions to use
     695                 :             :  * evalContext: short-term memory context for executing the functions
     696                 :             :  */
     697                 :             : static bool
     698                 :          13 : execTuplesUnequal(TupleTableSlot *slot1,
     699                 :             :                                   TupleTableSlot *slot2,
     700                 :             :                                   int numCols,
     701                 :             :                                   AttrNumber *matchColIdx,
     702                 :             :                                   FmgrInfo *eqfunctions,
     703                 :             :                                   const Oid *collations,
     704                 :             :                                   MemoryContext evalContext)
     705                 :             : {
     706                 :          13 :         MemoryContext oldContext;
     707                 :          13 :         bool            result;
     708                 :          13 :         int                     i;
     709                 :             : 
     710                 :             :         /* Reset and switch into the temp context. */
     711                 :          13 :         MemoryContextReset(evalContext);
     712                 :          13 :         oldContext = MemoryContextSwitchTo(evalContext);
     713                 :             : 
     714                 :             :         /*
     715                 :             :          * We cannot report a match without checking all the fields, but we can
     716                 :             :          * report a non-match as soon as we find unequal fields.  So, start
     717                 :             :          * comparing at the last field (least significant sort key). That's the
     718                 :             :          * most likely to be different if we are dealing with sorted input.
     719                 :             :          */
     720                 :          13 :         result = false;
     721                 :             : 
     722         [ +  + ]:          39 :         for (i = numCols; --i >= 0;)
     723                 :             :         {
     724                 :          26 :                 AttrNumber      att = matchColIdx[i];
     725                 :          26 :                 Datum           attr1,
     726                 :             :                                         attr2;
     727                 :          26 :                 bool            isNull1,
     728                 :             :                                         isNull2;
     729                 :             : 
     730                 :          26 :                 attr1 = slot_getattr(slot1, att, &isNull1);
     731                 :             : 
     732         [ +  + ]:          26 :                 if (isNull1)
     733                 :           7 :                         continue;                       /* can't prove anything here */
     734                 :             : 
     735                 :          19 :                 attr2 = slot_getattr(slot2, att, &isNull2);
     736                 :             : 
     737         [ +  + ]:          19 :                 if (isNull2)
     738                 :           6 :                         continue;                       /* can't prove anything here */
     739                 :             : 
     740                 :             :                 /* Apply the type-specific equality function */
     741   [ +  +  +  + ]:          26 :                 if (!DatumGetBool(FunctionCall2Coll(&eqfunctions[i],
     742                 :          13 :                                                                                         collations[i],
     743                 :          13 :                                                                                         attr1, attr2)))
     744                 :             :                 {
     745                 :           7 :                         result = true;          /* they are unequal */
     746                 :           7 :                         break;
     747                 :             :                 }
     748      [ -  +  + ]:          26 :         }
     749                 :             : 
     750                 :          13 :         MemoryContextSwitchTo(oldContext);
     751                 :             : 
     752                 :          26 :         return result;
     753                 :          13 : }
     754                 :             : 
     755                 :             : /*
     756                 :             :  * findPartialMatch: does the hashtable contain an entry that is not
     757                 :             :  * provably distinct from the tuple?
     758                 :             :  *
     759                 :             :  * We have to scan the whole hashtable; we can't usefully use hashkeys
     760                 :             :  * to guide probing, since we might get partial matches on tuples with
     761                 :             :  * hashkeys quite unrelated to what we'd get from the given tuple.
     762                 :             :  *
     763                 :             :  * Caller must provide the equality functions to use, since in cross-type
     764                 :             :  * cases these are different from the hashtable's internal functions.
     765                 :             :  */
     766                 :             : static bool
     767                 :          13 : findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
     768                 :             :                                  FmgrInfo *eqfunctions)
     769                 :             : {
     770                 :          13 :         int                     numCols = hashtable->numCols;
     771                 :          13 :         AttrNumber *keyColIdx = hashtable->keyColIdx;
     772                 :          13 :         TupleHashIterator hashiter;
     773                 :          13 :         TupleHashEntry entry;
     774                 :             : 
     775                 :          13 :         InitTupleHashIterator(hashtable, &hashiter);
     776         [ +  + ]:          20 :         while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
     777                 :             :         {
     778         [ +  - ]:          13 :                 CHECK_FOR_INTERRUPTS();
     779                 :             : 
     780                 :          13 :                 ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashtable->tableslot, false);
     781   [ +  +  +  + ]:          26 :                 if (!execTuplesUnequal(slot, hashtable->tableslot,
     782                 :          13 :                                                            numCols, keyColIdx,
     783                 :          13 :                                                            eqfunctions,
     784                 :          13 :                                                            hashtable->tab_collations,
     785                 :          13 :                                                            hashtable->tempcxt))
     786                 :             :                 {
     787                 :             :                         TermTupleHashIterator(&hashiter);
     788                 :           6 :                         return true;
     789                 :             :                 }
     790                 :             :         }
     791                 :             :         /* No TermTupleHashIterator call needed here */
     792                 :           7 :         return false;
     793                 :          13 : }
     794                 :             : 
     795                 :             : /*
     796                 :             :  * slotAllNulls: is the slot completely NULL?
     797                 :             :  *
     798                 :             :  * This does not test for dropped columns, which is OK because we only
     799                 :             :  * use it on projected tuples.
     800                 :             :  */
     801                 :             : static bool
     802                 :           6 : slotAllNulls(TupleTableSlot *slot)
     803                 :             : {
     804                 :           6 :         int                     ncols = slot->tts_tupleDescriptor->natts;
     805                 :           6 :         int                     i;
     806                 :             : 
     807         [ +  - ]:           6 :         for (i = 1; i <= ncols; i++)
     808                 :             :         {
     809         [ +  - ]:           6 :                 if (!slot_attisnull(slot, i))
     810                 :           6 :                         return false;
     811                 :           0 :         }
     812                 :           0 :         return true;
     813                 :           6 : }
     814                 :             : 
     815                 :             : /*
     816                 :             :  * slotNoNulls: is the slot entirely not NULL?
     817                 :             :  *
     818                 :             :  * This does not test for dropped columns, which is OK because we only
     819                 :             :  * use it on projected tuples.
     820                 :             :  */
     821                 :             : static bool
     822                 :      128856 : slotNoNulls(TupleTableSlot *slot)
     823                 :             : {
     824                 :      128856 :         int                     ncols = slot->tts_tupleDescriptor->natts;
     825                 :      128856 :         int                     i;
     826                 :             : 
     827         [ +  + ]:      303709 :         for (i = 1; i <= ncols; i++)
     828                 :             :         {
     829         [ +  + ]:      174863 :                 if (slot_attisnull(slot, i))
     830                 :          10 :                         return false;
     831                 :      174853 :         }
     832                 :      128846 :         return true;
     833                 :      128856 : }
     834                 :             : 
     835                 :             : /* ----------------------------------------------------------------
     836                 :             :  *              ExecInitSubPlan
     837                 :             :  *
     838                 :             :  * Create a SubPlanState for a SubPlan; this is the SubPlan-specific part
     839                 :             :  * of ExecInitExpr().  We split it out so that it can be used for InitPlans
     840                 :             :  * as well as regular SubPlans.  Note that we don't link the SubPlan into
     841                 :             :  * the parent's subPlan list, because that shouldn't happen for InitPlans.
     842                 :             :  * Instead, ExecInitExpr() does that one part.
     843                 :             :  *
     844                 :             :  * We also rely on ExecInitExpr(), more precisely ExecInitSubPlanExpr(), to
     845                 :             :  * evaluate input parameters, as that allows them to be evaluated as part of
     846                 :             :  * the expression referencing the SubPlan.
     847                 :             :  * ----------------------------------------------------------------
     848                 :             :  */
     849                 :             : SubPlanState *
     850                 :        4475 : ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
     851                 :             : {
     852                 :        4475 :         SubPlanState *sstate = makeNode(SubPlanState);
     853                 :        4475 :         EState     *estate = parent->state;
     854                 :             : 
     855                 :        4475 :         sstate->subplan = subplan;
     856                 :             : 
     857                 :             :         /* Link the SubPlanState to already-initialized subplan */
     858                 :        8950 :         sstate->planstate = (PlanState *) list_nth(estate->es_subplanstates,
     859                 :        4475 :                                                                                            subplan->plan_id - 1);
     860                 :             : 
     861                 :             :         /*
     862                 :             :          * This check can fail if the planner mistakenly puts a parallel-unsafe
     863                 :             :          * subplan into a parallelized subquery; see ExecSerializePlan.
     864                 :             :          */
     865         [ +  - ]:        4475 :         if (sstate->planstate == NULL)
     866   [ #  #  #  # ]:           0 :                 elog(ERROR, "subplan \"%s\" was not initialized",
     867                 :             :                          subplan->plan_name);
     868                 :             : 
     869                 :             :         /* Link to parent's state, too */
     870                 :        4475 :         sstate->parent = parent;
     871                 :             : 
     872                 :             :         /* Initialize subexpressions */
     873                 :        4475 :         sstate->testexpr = ExecInitExpr((Expr *) subplan->testexpr, parent);
     874                 :             : 
     875                 :             :         /*
     876                 :             :          * initialize my state
     877                 :             :          */
     878                 :        4475 :         sstate->curTuple = NULL;
     879                 :        4475 :         sstate->curArray = PointerGetDatum(NULL);
     880                 :        4475 :         sstate->projLeft = NULL;
     881                 :        4475 :         sstate->projRight = NULL;
     882                 :        4475 :         sstate->hashtable = NULL;
     883                 :        4475 :         sstate->hashnulls = NULL;
     884                 :        4475 :         sstate->tuplesContext = NULL;
     885                 :        4475 :         sstate->innerecontext = NULL;
     886                 :        4475 :         sstate->keyColIdx = NULL;
     887                 :        4475 :         sstate->tab_eq_funcoids = NULL;
     888                 :        4475 :         sstate->tab_hash_funcs = NULL;
     889                 :        4475 :         sstate->tab_collations = NULL;
     890                 :        4475 :         sstate->cur_eq_funcs = NULL;
     891                 :             : 
     892                 :             :         /*
     893                 :             :          * If this is an initplan, it has output parameters that the parent plan
     894                 :             :          * will use, so mark those parameters as needing evaluation.  We don't
     895                 :             :          * actually run the subplan until we first need one of its outputs.
     896                 :             :          *
     897                 :             :          * A CTE subplan's output parameter is never to be evaluated in the normal
     898                 :             :          * way, so skip this in that case.
     899                 :             :          *
     900                 :             :          * Note that we don't set parent->chgParam here: the parent plan hasn't
     901                 :             :          * been run yet, so no need to force it to re-run.
     902                 :             :          */
     903   [ +  +  +  +  :        4475 :         if (subplan->setParam != NIL && subplan->parParam == NIL &&
                   +  + ]
     904                 :        1153 :                 subplan->subLinkType != CTE_SUBLINK)
     905                 :             :         {
     906                 :         966 :                 ListCell   *lst;
     907                 :             : 
     908   [ +  -  +  +  :        1940 :                 foreach(lst, subplan->setParam)
                   +  + ]
     909                 :             :                 {
     910                 :         974 :                         int                     paramid = lfirst_int(lst);
     911                 :         974 :                         ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
     912                 :             : 
     913                 :         974 :                         prm->execPlan = sstate;
     914                 :         974 :                 }
     915                 :         966 :         }
     916                 :             : 
     917                 :             :         /*
     918                 :             :          * If we are going to hash the subquery output, initialize relevant stuff.
     919                 :             :          * (We don't create the hashtable until needed, though.)
     920                 :             :          */
     921         [ +  + ]:        4475 :         if (subplan->useHashTable)
     922                 :             :         {
     923                 :         103 :                 int                     ncols,
     924                 :             :                                         i;
     925                 :         103 :                 TupleDesc       tupDescLeft;
     926                 :         103 :                 TupleDesc       tupDescRight;
     927                 :         103 :                 Oid                *cross_eq_funcoids;
     928                 :         103 :                 TupleTableSlot *slot;
     929                 :         103 :                 FmgrInfo   *lhs_hash_funcs;
     930                 :         103 :                 List       *oplist,
     931                 :             :                                    *lefttlist,
     932                 :             :                                    *righttlist;
     933                 :         103 :                 ListCell   *l;
     934                 :             : 
     935                 :             :                 /* We need a memory context to hold the hash table(s)' tuples */
     936                 :         103 :                 sstate->tuplesContext =
     937                 :         103 :                         BumpContextCreate(CurrentMemoryContext,
     938                 :             :                                                           "SubPlan hashed tuples",
     939                 :             :                                                           ALLOCSET_DEFAULT_SIZES);
     940                 :             :                 /* and a short-lived exprcontext for function evaluation */
     941                 :         103 :                 sstate->innerecontext = CreateExprContext(estate);
     942                 :             : 
     943                 :             :                 /*
     944                 :             :                  * We use ExecProject to evaluate the lefthand and righthand
     945                 :             :                  * expression lists and form tuples.  (You might think that we could
     946                 :             :                  * use the sub-select's output tuples directly, but that is not the
     947                 :             :                  * case if we had to insert any run-time coercions of the sub-select's
     948                 :             :                  * output datatypes; anyway this avoids storing any resjunk columns
     949                 :             :                  * that might be in the sub-select's output.)  Run through the
     950                 :             :                  * combining expressions to build tlists for the lefthand and
     951                 :             :                  * righthand sides.
     952                 :             :                  *
     953                 :             :                  * We also extract the combining operators themselves to initialize
     954                 :             :                  * the equality and hashing functions for the hash tables.
     955                 :             :                  */
     956         [ +  + ]:         103 :                 if (IsA(subplan->testexpr, OpExpr))
     957                 :             :                 {
     958                 :             :                         /* single combining operator */
     959                 :          88 :                         oplist = list_make1(subplan->testexpr);
     960                 :          88 :                 }
     961         [ +  - ]:          15 :                 else if (is_andclause(subplan->testexpr))
     962                 :             :                 {
     963                 :             :                         /* multiple combining operators */
     964                 :          15 :                         oplist = castNode(BoolExpr, subplan->testexpr)->args;
     965                 :          15 :                 }
     966                 :             :                 else
     967                 :             :                 {
     968                 :             :                         /* shouldn't see anything else in a hashable subplan */
     969   [ #  #  #  # ]:           0 :                         elog(ERROR, "unrecognized testexpr type: %d",
     970                 :             :                                  (int) nodeTag(subplan->testexpr));
     971                 :           0 :                         oplist = NIL;           /* keep compiler quiet */
     972                 :             :                 }
     973                 :         103 :                 ncols = list_length(oplist);
     974                 :             : 
     975                 :         103 :                 lefttlist = righttlist = NIL;
     976                 :         103 :                 sstate->numCols = ncols;
     977                 :         103 :                 sstate->keyColIdx = (AttrNumber *) palloc(ncols * sizeof(AttrNumber));
     978                 :         103 :                 sstate->tab_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
     979                 :         103 :                 sstate->tab_collations = (Oid *) palloc(ncols * sizeof(Oid));
     980                 :         103 :                 sstate->tab_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
     981                 :         103 :                 lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
     982                 :         103 :                 sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
     983                 :             :                 /* we'll need the cross-type equality fns below, but not in sstate */
     984                 :         103 :                 cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
     985                 :             : 
     986                 :         103 :                 i = 1;
     987   [ +  -  +  +  :         221 :                 foreach(l, oplist)
                   +  + ]
     988                 :             :                 {
     989                 :         118 :                         OpExpr     *opexpr = lfirst_node(OpExpr, l);
     990                 :         118 :                         Expr       *expr;
     991                 :         118 :                         TargetEntry *tle;
     992                 :         118 :                         Oid                     rhs_eq_oper;
     993                 :         118 :                         Oid                     left_hashfn;
     994                 :         118 :                         Oid                     right_hashfn;
     995                 :             : 
     996         [ +  - ]:         118 :                         Assert(list_length(opexpr->args) == 2);
     997                 :             : 
     998                 :             :                         /* Process lefthand argument */
     999                 :         118 :                         expr = (Expr *) linitial(opexpr->args);
    1000                 :         236 :                         tle = makeTargetEntry(expr,
    1001                 :         118 :                                                                   i,
    1002                 :             :                                                                   NULL,
    1003                 :             :                                                                   false);
    1004                 :         118 :                         lefttlist = lappend(lefttlist, tle);
    1005                 :             : 
    1006                 :             :                         /* Process righthand argument */
    1007                 :         118 :                         expr = (Expr *) lsecond(opexpr->args);
    1008                 :         236 :                         tle = makeTargetEntry(expr,
    1009                 :         118 :                                                                   i,
    1010                 :             :                                                                   NULL,
    1011                 :             :                                                                   false);
    1012                 :         118 :                         righttlist = lappend(righttlist, tle);
    1013                 :             : 
    1014                 :             :                         /* Lookup the equality function (potentially cross-type) */
    1015                 :         118 :                         cross_eq_funcoids[i - 1] = opexpr->opfuncid;
    1016                 :         118 :                         fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
    1017                 :         118 :                         fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
    1018                 :             : 
    1019                 :             :                         /* Look up the equality function for the RHS type */
    1020         [ +  - ]:         118 :                         if (!get_compatible_hash_operators(opexpr->opno,
    1021                 :             :                                                                                            NULL, &rhs_eq_oper))
    1022   [ #  #  #  # ]:           0 :                                 elog(ERROR, "could not find compatible hash operator for operator %u",
    1023                 :             :                                          opexpr->opno);
    1024                 :         118 :                         sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
    1025                 :             : 
    1026                 :             :                         /* Lookup the associated hash functions */
    1027         [ +  - ]:         118 :                         if (!get_op_hash_functions(opexpr->opno,
    1028                 :             :                                                                            &left_hashfn, &right_hashfn))
    1029   [ #  #  #  # ]:           0 :                                 elog(ERROR, "could not find hash function for hash operator %u",
    1030                 :             :                                          opexpr->opno);
    1031                 :         118 :                         fmgr_info(left_hashfn, &lhs_hash_funcs[i - 1]);
    1032                 :         118 :                         fmgr_info(right_hashfn, &sstate->tab_hash_funcs[i - 1]);
    1033                 :             : 
    1034                 :             :                         /* Set collation */
    1035                 :         118 :                         sstate->tab_collations[i - 1] = opexpr->inputcollid;
    1036                 :             : 
    1037                 :             :                         /* keyColIdx is just column numbers 1..n */
    1038                 :         118 :                         sstate->keyColIdx[i - 1] = i;
    1039                 :             : 
    1040                 :         118 :                         i++;
    1041                 :         118 :                 }
    1042                 :             : 
    1043                 :             :                 /*
    1044                 :             :                  * Construct tupdescs, slots and projection nodes for left and right
    1045                 :             :                  * sides.  The lefthand expressions will be evaluated in the parent
    1046                 :             :                  * plan node's exprcontext, which we don't have access to here.
    1047                 :             :                  * Fortunately we can just pass NULL for now and fill it in later
    1048                 :             :                  * (hack alert!).  The righthand expressions will be evaluated in our
    1049                 :             :                  * own innerecontext.
    1050                 :             :                  */
    1051                 :         103 :                 tupDescLeft = ExecTypeFromTL(lefttlist);
    1052                 :         103 :                 slot = ExecInitExtraTupleSlot(estate, tupDescLeft, &TTSOpsVirtual);
    1053                 :         206 :                 sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
    1054                 :             :                                                                                                    NULL,
    1055                 :         103 :                                                                                                    slot,
    1056                 :         103 :                                                                                                    parent,
    1057                 :             :                                                                                                    NULL);
    1058                 :             : 
    1059                 :         103 :                 sstate->descRight = tupDescRight = ExecTypeFromTL(righttlist);
    1060                 :         103 :                 slot = ExecInitExtraTupleSlot(estate, tupDescRight, &TTSOpsVirtual);
    1061                 :         206 :                 sstate->projRight = ExecBuildProjectionInfo(righttlist,
    1062                 :         103 :                                                                                                         sstate->innerecontext,
    1063                 :         103 :                                                                                                         slot,
    1064                 :         103 :                                                                                                         sstate->planstate,
    1065                 :             :                                                                                                         NULL);
    1066                 :             : 
    1067                 :             :                 /* Build the ExprState for generating hash values */
    1068                 :         206 :                 sstate->lhs_hash_expr = ExecBuildHash32FromAttrs(tupDescLeft,
    1069                 :             :                                                                                                                  &TTSOpsVirtual,
    1070                 :         103 :                                                                                                                  lhs_hash_funcs,
    1071                 :         103 :                                                                                                                  sstate->tab_collations,
    1072                 :         103 :                                                                                                                  sstate->numCols,
    1073                 :         103 :                                                                                                                  sstate->keyColIdx,
    1074                 :         103 :                                                                                                                  parent,
    1075                 :             :                                                                                                                  0);
    1076                 :             : 
    1077                 :             :                 /*
    1078                 :             :                  * Create comparator for lookups of rows in the table (potentially
    1079                 :             :                  * cross-type comparisons).
    1080                 :             :                  */
    1081                 :         206 :                 sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
    1082                 :             :                                                                                                          &TTSOpsVirtual, &TTSOpsMinimalTuple,
    1083                 :         103 :                                                                                                          ncols,
    1084                 :         103 :                                                                                                          sstate->keyColIdx,
    1085                 :         103 :                                                                                                          cross_eq_funcoids,
    1086                 :         103 :                                                                                                          sstate->tab_collations,
    1087                 :         103 :                                                                                                          parent);
    1088                 :         103 :         }
    1089                 :             : 
    1090                 :        8950 :         return sstate;
    1091                 :        4475 : }
    1092                 :             : 
    1093                 :             : /* ----------------------------------------------------------------
    1094                 :             :  *              ExecSetParamPlan
    1095                 :             :  *
    1096                 :             :  *              Executes a subplan and sets its output parameters.
    1097                 :             :  *
    1098                 :             :  * This is called from ExecEvalParamExec() when the value of a PARAM_EXEC
    1099                 :             :  * parameter is requested and the param's execPlan field is set (indicating
    1100                 :             :  * that the param has not yet been evaluated).  This allows lazy evaluation
    1101                 :             :  * of initplans: we don't run the subplan until/unless we need its output.
    1102                 :             :  * Note that this routine MUST clear the execPlan fields of the plan's
    1103                 :             :  * output parameters after evaluating them!
    1104                 :             :  *
    1105                 :             :  * The results of this function are stored in the EState associated with the
    1106                 :             :  * ExprContext (particularly, its ecxt_param_exec_vals); any pass-by-ref
    1107                 :             :  * result Datums are allocated in the EState's per-query memory.  The passed
    1108                 :             :  * econtext can be any ExprContext belonging to that EState; which one is
    1109                 :             :  * important only to the extent that the ExprContext's per-tuple memory
    1110                 :             :  * context is used to evaluate any parameters passed down to the subplan.
    1111                 :             :  * (Thus in principle, the shorter-lived the ExprContext the better, since
    1112                 :             :  * that data isn't needed after we return.  In practice, because initplan
    1113                 :             :  * parameters are never more complex than Vars, Aggrefs, etc, evaluating them
    1114                 :             :  * currently never leaks any memory anyway.)
    1115                 :             :  * ----------------------------------------------------------------
    1116                 :             :  */
    1117                 :             : void
    1118                 :         894 : ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
    1119                 :             : {
    1120                 :         894 :         SubPlan    *subplan = node->subplan;
    1121                 :         894 :         PlanState  *planstate = node->planstate;
    1122                 :         894 :         SubLinkType subLinkType = subplan->subLinkType;
    1123                 :         894 :         EState     *estate = planstate->state;
    1124                 :         894 :         ScanDirection dir = estate->es_direction;
    1125                 :         894 :         MemoryContext oldcontext;
    1126                 :         894 :         TupleTableSlot *slot;
    1127                 :         894 :         ListCell   *l;
    1128                 :         894 :         bool            found = false;
    1129                 :         894 :         ArrayBuildStateAny *astate = NULL;
    1130                 :             : 
    1131         [ +  - ]:         894 :         if (subLinkType == ANY_SUBLINK ||
    1132                 :         894 :                 subLinkType == ALL_SUBLINK)
    1133   [ #  #  #  # ]:           0 :                 elog(ERROR, "ANY/ALL subselect unsupported as initplan");
    1134         [ +  - ]:         894 :         if (subLinkType == CTE_SUBLINK)
    1135   [ #  #  #  # ]:           0 :                 elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
    1136         [ +  - ]:         894 :         if (subplan->parParam || subplan->args)
    1137   [ #  #  #  # ]:           0 :                 elog(ERROR, "correlated subplans should not be executed via ExecSetParamPlan");
    1138                 :             : 
    1139                 :             :         /*
    1140                 :             :          * Enforce forward scan direction regardless of caller. It's hard but not
    1141                 :             :          * impossible to get here in backward scan, so make it work anyway.
    1142                 :             :          */
    1143                 :         894 :         estate->es_direction = ForwardScanDirection;
    1144                 :             : 
    1145                 :             :         /* Initialize ArrayBuildStateAny in caller's context, if needed */
    1146         [ +  + ]:         894 :         if (subLinkType == ARRAY_SUBLINK)
    1147                 :          30 :                 astate = initArrayResultAny(subplan->firstColType,
    1148                 :          15 :                                                                         CurrentMemoryContext, true);
    1149                 :             : 
    1150                 :             :         /*
    1151                 :             :          * Must switch to per-query memory context.
    1152                 :             :          */
    1153                 :         894 :         oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
    1154                 :             : 
    1155                 :             :         /*
    1156                 :             :          * Run the plan.  (If it needs to be rescanned, the first ExecProcNode
    1157                 :             :          * call will take care of that.)
    1158                 :             :          */
    1159         [ +  + ]:        5994 :         for (slot = ExecProcNode(planstate);
    1160         [ +  + ]:        2997 :                  !TupIsNull(slot);
    1161                 :        2103 :                  slot = ExecProcNode(planstate))
    1162                 :             :         {
    1163                 :        2114 :                 TupleDesc       tdesc = slot->tts_tupleDescriptor;
    1164                 :        2114 :                 int                     i = 1;
    1165                 :             : 
    1166         [ +  + ]:        2114 :                 if (subLinkType == EXISTS_SUBLINK)
    1167                 :             :                 {
    1168                 :             :                         /* There can be only one setParam... */
    1169                 :           9 :                         int                     paramid = linitial_int(subplan->setParam);
    1170                 :           9 :                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
    1171                 :             : 
    1172                 :           9 :                         prm->execPlan = NULL;
    1173                 :           9 :                         prm->value = BoolGetDatum(true);
    1174                 :           9 :                         prm->isnull = false;
    1175                 :           9 :                         found = true;
    1176                 :             :                         break;
    1177                 :           9 :                 }
    1178                 :             : 
    1179         [ +  + ]:        2105 :                 if (subLinkType == ARRAY_SUBLINK)
    1180                 :             :                 {
    1181                 :        1350 :                         Datum           dvalue;
    1182                 :        1350 :                         bool            disnull;
    1183                 :             : 
    1184                 :        1350 :                         found = true;
    1185                 :             :                         /* stash away current value */
    1186         [ -  + ]:        1350 :                         Assert(subplan->firstColType == TupleDescAttr(tdesc, 0)->atttypid);
    1187                 :        1350 :                         dvalue = slot_getattr(slot, 1, &disnull);
    1188                 :        2700 :                         astate = accumArrayResultAny(astate, dvalue, disnull,
    1189                 :        1350 :                                                                                  subplan->firstColType, oldcontext);
    1190                 :             :                         /* keep scanning subplan to collect all values */
    1191                 :             :                         continue;
    1192                 :        1350 :                 }
    1193                 :             : 
    1194         [ +  + ]:         756 :                 if (found &&
    1195         [ +  + ]:           3 :                         (subLinkType == EXPR_SUBLINK ||
    1196                 :           1 :                          subLinkType == MULTIEXPR_SUBLINK ||
    1197                 :           1 :                          subLinkType == ROWCOMPARE_SUBLINK))
    1198   [ +  -  +  - ]:           2 :                         ereport(ERROR,
    1199                 :             :                                         (errcode(ERRCODE_CARDINALITY_VIOLATION),
    1200                 :             :                                          errmsg("more than one row returned by a subquery used as an expression")));
    1201                 :             : 
    1202                 :         753 :                 found = true;
    1203                 :             : 
    1204                 :             :                 /*
    1205                 :             :                  * We need to copy the subplan's tuple into our own context, in case
    1206                 :             :                  * any of the params are pass-by-ref type --- the pointers stored in
    1207                 :             :                  * the param structs will point at this copied tuple! node->curTuple
    1208                 :             :                  * keeps track of the copied tuple for eventual freeing.
    1209                 :             :                  */
    1210         [ +  + ]:         753 :                 if (node->curTuple)
    1211                 :          86 :                         heap_freetuple(node->curTuple);
    1212                 :         753 :                 node->curTuple = ExecCopySlotHeapTuple(slot);
    1213                 :             : 
    1214                 :             :                 /*
    1215                 :             :                  * Now set all the setParam params from the columns of the tuple
    1216                 :             :                  */
    1217   [ +  -  +  +  :        1512 :                 foreach(l, subplan->setParam)
                   +  + ]
    1218                 :             :                 {
    1219                 :         759 :                         int                     paramid = lfirst_int(l);
    1220                 :         759 :                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
    1221                 :             : 
    1222                 :         759 :                         prm->execPlan = NULL;
    1223                 :        1518 :                         prm->value = heap_getattr(node->curTuple, i, tdesc,
    1224                 :         759 :                                                                           &(prm->isnull));
    1225                 :         759 :                         i++;
    1226                 :         759 :                 }
    1227   [ -  +  +  + ]:        2112 :         }
    1228                 :             : 
    1229         [ +  + ]:         892 :         if (subLinkType == ARRAY_SUBLINK)
    1230                 :             :         {
    1231                 :             :                 /* There can be only one setParam... */
    1232                 :          15 :                 int                     paramid = linitial_int(subplan->setParam);
    1233                 :          15 :                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
    1234                 :             : 
    1235                 :             :                 /*
    1236                 :             :                  * We build the result array in query context so it won't disappear;
    1237                 :             :                  * to avoid leaking memory across repeated calls, we have to remember
    1238                 :             :                  * the latest value, much as for curTuple above.
    1239                 :             :                  */
    1240         [ +  - ]:          15 :                 if (node->curArray != PointerGetDatum(NULL))
    1241                 :           0 :                         pfree(DatumGetPointer(node->curArray));
    1242                 :          30 :                 node->curArray = makeArrayResultAny(astate,
    1243                 :          15 :                                                                                         econtext->ecxt_per_query_memory,
    1244                 :             :                                                                                         true);
    1245                 :          15 :                 prm->execPlan = NULL;
    1246                 :          15 :                 prm->value = node->curArray;
    1247                 :          15 :                 prm->isnull = false;
    1248                 :          15 :         }
    1249         [ +  + ]:         877 :         else if (!found)
    1250                 :             :         {
    1251         [ +  + ]:         117 :                 if (subLinkType == EXISTS_SUBLINK)
    1252                 :             :                 {
    1253                 :             :                         /* There can be only one setParam... */
    1254                 :         108 :                         int                     paramid = linitial_int(subplan->setParam);
    1255                 :         108 :                         ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
    1256                 :             : 
    1257                 :         108 :                         prm->execPlan = NULL;
    1258                 :         108 :                         prm->value = BoolGetDatum(false);
    1259                 :         108 :                         prm->isnull = false;
    1260                 :         108 :                 }
    1261                 :             :                 else
    1262                 :             :                 {
    1263                 :             :                         /* For other sublink types, set all the output params to NULL */
    1264   [ +  -  +  +  :          19 :                         foreach(l, subplan->setParam)
                   +  + ]
    1265                 :             :                         {
    1266                 :          10 :                                 int                     paramid = lfirst_int(l);
    1267                 :          10 :                                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
    1268                 :             : 
    1269                 :          10 :                                 prm->execPlan = NULL;
    1270                 :          10 :                                 prm->value = (Datum) 0;
    1271                 :          10 :                                 prm->isnull = true;
    1272                 :          10 :                         }
    1273                 :             :                 }
    1274                 :         117 :         }
    1275                 :             : 
    1276                 :         892 :         MemoryContextSwitchTo(oldcontext);
    1277                 :             : 
    1278                 :             :         /* restore scan direction */
    1279                 :         892 :         estate->es_direction = dir;
    1280                 :         892 : }
    1281                 :             : 
    1282                 :             : /*
    1283                 :             :  * ExecSetParamPlanMulti
    1284                 :             :  *
    1285                 :             :  * Apply ExecSetParamPlan to evaluate any not-yet-evaluated initplan output
    1286                 :             :  * parameters whose ParamIDs are listed in "params".  Any listed params that
    1287                 :             :  * are not initplan outputs are ignored.
    1288                 :             :  *
    1289                 :             :  * As with ExecSetParamPlan, any ExprContext belonging to the current EState
    1290                 :             :  * can be used, but in principle a shorter-lived ExprContext is better than a
    1291                 :             :  * longer-lived one.
    1292                 :             :  */
    1293                 :             : void
    1294                 :         164 : ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
    1295                 :             : {
    1296                 :         164 :         int                     paramid;
    1297                 :             : 
    1298                 :         164 :         paramid = -1;
    1299         [ +  + ]:         169 :         while ((paramid = bms_next_member(params, paramid)) >= 0)
    1300                 :             :         {
    1301                 :           5 :                 ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
    1302                 :             : 
    1303         [ -  + ]:           5 :                 if (prm->execPlan != NULL)
    1304                 :             :                 {
    1305                 :             :                         /* Parameter not evaluated yet, so go do it */
    1306                 :           5 :                         ExecSetParamPlan(prm->execPlan, econtext);
    1307                 :             :                         /* ExecSetParamPlan should have processed this param... */
    1308         [ +  - ]:           5 :                         Assert(prm->execPlan == NULL);
    1309                 :           5 :                 }
    1310                 :           5 :         }
    1311                 :         164 : }
    1312                 :             : 
    1313                 :             : /*
    1314                 :             :  * Mark an initplan as needing recalculation
    1315                 :             :  */
    1316                 :             : void
    1317                 :         149 : ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
    1318                 :             : {
    1319                 :         149 :         PlanState  *planstate = node->planstate;
    1320                 :         149 :         SubPlan    *subplan = node->subplan;
    1321                 :         149 :         EState     *estate = parent->state;
    1322                 :         149 :         ListCell   *l;
    1323                 :             : 
    1324                 :             :         /* sanity checks */
    1325         [ +  - ]:         149 :         if (subplan->parParam != NIL)
    1326   [ #  #  #  # ]:           0 :                 elog(ERROR, "direct correlated subquery unsupported as initplan");
    1327         [ +  - ]:         149 :         if (subplan->setParam == NIL)
    1328   [ #  #  #  # ]:           0 :                 elog(ERROR, "setParam list of initplan is empty");
    1329         [ +  - ]:         149 :         if (bms_is_empty(planstate->plan->extParam))
    1330   [ #  #  #  # ]:           0 :                 elog(ERROR, "extParam set of initplan is empty");
    1331                 :             : 
    1332                 :             :         /*
    1333                 :             :          * Don't actually re-scan: it'll happen inside ExecSetParamPlan if needed.
    1334                 :             :          */
    1335                 :             : 
    1336                 :             :         /*
    1337                 :             :          * Mark this subplan's output parameters as needing recalculation.
    1338                 :             :          *
    1339                 :             :          * CTE subplans are never executed via parameter recalculation; instead
    1340                 :             :          * they get run when called by nodeCtescan.c.  So don't mark the output
    1341                 :             :          * parameter of a CTE subplan as dirty, but do set the chgParam bit for it
    1342                 :             :          * so that dependent plan nodes will get told to rescan.
    1343                 :             :          */
    1344   [ +  -  +  +  :         298 :         foreach(l, subplan->setParam)
                   +  + ]
    1345                 :             :         {
    1346                 :         149 :                 int                     paramid = lfirst_int(l);
    1347                 :         149 :                 ParamExecData *prm = &(estate->es_param_exec_vals[paramid]);
    1348                 :             : 
    1349         [ +  + ]:         149 :                 if (subplan->subLinkType != CTE_SUBLINK)
    1350                 :         133 :                         prm->execPlan = node;
    1351                 :             : 
    1352                 :         149 :                 parent->chgParam = bms_add_member(parent->chgParam, paramid);
    1353                 :         149 :         }
    1354                 :         149 : }
        

Generated by: LCOV version 2.3.2-1