LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeLimit.c (source / functions) Coverage Total Hit UBC GIC GNC CBC ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 87.5 % 176 154 22 1 3 150 4
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 6 6 1 5
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 87.5 % 176 154 22 1 3 150 2
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 6 6 1 5

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * nodeLimit.c
                                  4                 :  *    Routines to handle limiting of query results where appropriate
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  *
                                 10                 :  * IDENTIFICATION
                                 11                 :  *    src/backend/executor/nodeLimit.c
                                 12                 :  *
                                 13                 :  *-------------------------------------------------------------------------
                                 14                 :  */
                                 15                 : /*
                                 16                 :  * INTERFACE ROUTINES
                                 17                 :  *      ExecLimit       - extract a limited range of tuples
                                 18                 :  *      ExecInitLimit   - initialize node and subnodes..
                                 19                 :  *      ExecEndLimit    - shutdown node and subnodes
                                 20                 :  */
                                 21                 : 
                                 22                 : #include "postgres.h"
                                 23                 : 
                                 24                 : #include "executor/executor.h"
                                 25                 : #include "executor/nodeLimit.h"
                                 26                 : #include "miscadmin.h"
                                 27                 : #include "nodes/nodeFuncs.h"
                                 28                 : 
                                 29                 : static void recompute_limits(LimitState *node);
                                 30                 : static int64 compute_tuples_needed(LimitState *node);
                                 31                 : 
                                 32                 : 
                                 33                 : /* ----------------------------------------------------------------
                                 34                 :  *      ExecLimit
                                 35                 :  *
                                 36                 :  *      This is a very simple node which just performs LIMIT/OFFSET
                                 37                 :  *      filtering on the stream of tuples returned by a subplan.
                                 38                 :  * ----------------------------------------------------------------
                                 39                 :  */
                                 40                 : static TupleTableSlot *         /* return: a tuple or NULL */
 2092 andres                     41 CBC       17972 : ExecLimit(PlanState *pstate)
                                 42                 : {
                                 43           17972 :     LimitState *node = castNode(LimitState, pstate);
 1097 alvherre                   44           17972 :     ExprContext *econtext = node->ps.ps_ExprContext;
                                 45                 :     ScanDirection direction;
                                 46                 :     TupleTableSlot *slot;
                                 47                 :     PlanState  *outerPlan;
                                 48                 : 
 2084 andres                     49           17972 :     CHECK_FOR_INTERRUPTS();
                                 50                 : 
                                 51                 :     /*
                                 52                 :      * get information from the node
                                 53                 :      */
 7430 tgl                        54           17972 :     direction = node->ps.state->es_direction;
                                 55           17972 :     outerPlan = outerPlanState(node);
                                 56                 : 
                                 57                 :     /*
                                 58                 :      * The main logic is a simple state machine.
                                 59                 :      */
                                 60           17972 :     switch (node->lstate)
                                 61                 :     {
 7443                            62            1960 :         case LIMIT_INITIAL:
                                 63                 : 
                                 64                 :             /*
                                 65                 :              * First call for this node, so compute limit/offset. (We can't do
                                 66                 :              * this any earlier, because parameters from upper nodes will not
                                 67                 :              * be set during ExecInitLimit.)  This also sets position = 0 and
                                 68                 :              * changes the state to LIMIT_RESCAN.
                                 69                 :              */
 5806                            70            1960 :             recompute_limits(node);
                                 71                 : 
                                 72                 :             /* FALL THRU */
                                 73                 : 
                                 74            2410 :         case LIMIT_RESCAN:
                                 75                 : 
                                 76                 :             /*
                                 77                 :              * If backwards scan, just return NULL without changing state.
                                 78                 :              */
                                 79            2410 :             if (!ScanDirectionIsForward(direction))
 5806 tgl                        80 UBC           0 :                 return NULL;
                                 81                 : 
                                 82                 :             /*
                                 83                 :              * Check for empty window; if so, treat like empty subplan.
                                 84                 :              */
 7430 tgl                        85 CBC        2410 :             if (node->count <= 0 && !node->noCount)
                                 86                 :             {
                                 87              69 :                 node->lstate = LIMIT_EMPTY;
 8200                            88              69 :                 return NULL;
                                 89                 :             }
                                 90                 : 
                                 91                 :             /*
                                 92                 :              * Fetch rows from subplan until we reach position > offset.
                                 93                 :              */
                                 94                 :             for (;;)
                                 95                 :             {
 7430                            96          254720 :                 slot = ExecProcNode(outerPlan);
 7443                            97          254713 :                 if (TupIsNull(slot))
                                 98                 :                 {
                                 99                 :                     /*
                                100                 :                      * The subplan returns too few tuples for us to produce
                                101                 :                      * any output at all.
                                102                 :                      */
 7430                           103             125 :                     node->lstate = LIMIT_EMPTY;
 7443                           104             125 :                     return NULL;
                                105                 :                 }
                                106                 : 
                                107                 :                 /*
                                108                 :                  * Tuple at limit is needed for comparison in subsequent
                                109                 :                  * execution to detect ties.
                                110                 :                  */
 1097 alvherre                  111          254588 :                 if (node->limitOption == LIMIT_OPTION_WITH_TIES &&
                                112              13 :                     node->position - node->offset == node->count - 1)
                                113                 :                 {
                                114               6 :                     ExecCopySlot(node->last_slot, slot);
                                115                 :                 }
 7430 tgl                       116          254588 :                 node->subSlot = slot;
                                117          254588 :                 if (++node->position > node->offset)
 7443                           118            2209 :                     break;
                                119                 :             }
                                120                 : 
                                121                 :             /*
                                122                 :              * Okay, we have the first tuple of the window.
                                123                 :              */
 7430                           124            2209 :             node->lstate = LIMIT_INWINDOW;
 7443                           125            2209 :             break;
                                126                 : 
 7443 tgl                       127 UBC           0 :         case LIMIT_EMPTY:
                                128                 : 
                                129                 :             /*
                                130                 :              * The subplan is known to return no tuples (or not more than
                                131                 :              * OFFSET tuples, in general).  So we return no tuples.
                                132                 :              */
                                133               0 :             return NULL;
                                134                 : 
 7443 tgl                       135 CBC       15446 :         case LIMIT_INWINDOW:
 8200                           136           15446 :             if (ScanDirectionIsForward(direction))
                                137                 :             {
                                138                 :                 /*
                                139                 :                  * Forwards scan, so check for stepping off end of window.  At
                                140                 :                  * the end of the window, the behavior depends on whether WITH
                                141                 :                  * TIES was specified: if so, we need to change the state
                                142                 :                  * machine to WINDOWEND_TIES, and fall through to the code for
                                143                 :                  * that case.  If not (nothing was specified, or ONLY was)
                                144                 :                  * return NULL without advancing the subplan or the position
                                145                 :                  * variable, but change the state machine to record having
                                146                 :                  * done so.
                                147                 :                  *
                                148                 :                  * Once at the end, ideally, we would shut down parallel
                                149                 :                  * resources; but that would destroy the parallel context
                                150                 :                  * which might be required for rescans.  To do that, we'll
                                151                 :                  * need to find a way to pass down more information about
                                152                 :                  * whether rescans are possible.
                                153                 :                  */
 7430                           154           15401 :                 if (!node->noCount &&
 4268 heikki.linnakangas        155           15149 :                     node->position - node->offset >= node->count)
                                156                 :                 {
 1097 alvherre                  157            1882 :                     if (node->limitOption == LIMIT_OPTION_COUNT)
                                158                 :                     {
                                159            1863 :                         node->lstate = LIMIT_WINDOWEND;
                                160            1863 :                         return NULL;
                                161                 :                     }
                                162                 :                     else
                                163                 :                     {
                                164              19 :                         node->lstate = LIMIT_WINDOWEND_TIES;
                                165                 :                         /* we'll fall through to the next case */
                                166                 :                     }
                                167                 :                 }
                                168                 :                 else
                                169                 :                 {
                                170                 :                     /*
                                171                 :                      * Get next tuple from subplan, if any.
                                172                 :                      */
                                173           13519 :                     slot = ExecProcNode(outerPlan);
                                174           13516 :                     if (TupIsNull(slot))
                                175                 :                     {
                                176              82 :                         node->lstate = LIMIT_SUBPLANEOF;
                                177              82 :                         return NULL;
                                178                 :                     }
                                179                 : 
                                180                 :                     /*
                                181                 :                      * If WITH TIES is active, and this is the last in-window
                                182                 :                      * tuple, save it to be used in subsequent WINDOWEND_TIES
                                183                 :                      * processing.
                                184                 :                      */
                                185           13434 :                     if (node->limitOption == LIMIT_OPTION_WITH_TIES &&
                                186              13 :                         node->position - node->offset == node->count - 1)
                                187                 :                     {
                                188              13 :                         ExecCopySlot(node->last_slot, slot);
                                189                 :                     }
                                190           13434 :                     node->subSlot = slot;
                                191           13434 :                     node->position++;
                                192           13434 :                     break;
                                193                 :                 }
                                194                 :             }
                                195                 :             else
                                196                 :             {
                                197                 :                 /*
                                198                 :                  * Backwards scan, so check for stepping off start of window.
                                199                 :                  * As above, only change state-machine status if so.
                                200                 :                  */
                                201              45 :                 if (node->position <= node->offset + 1)
                                202                 :                 {
                                203              15 :                     node->lstate = LIMIT_WINDOWSTART;
 7443 tgl                       204              15 :                     return NULL;
                                205                 :                 }
                                206                 : 
                                207                 :                 /*
                                208                 :                  * Get previous tuple from subplan; there should be one!
                                209                 :                  */
 1097 alvherre                  210              30 :                 slot = ExecProcNode(outerPlan);
                                211              30 :                 if (TupIsNull(slot))
 1097 alvherre                  212 UBC           0 :                     elog(ERROR, "LIMIT subplan failed to run backwards");
 1097 alvherre                  213 CBC          30 :                 node->subSlot = slot;
                                214              30 :                 node->position--;
                                215              30 :                 break;
                                216                 :             }
                                217                 : 
 1093 tgl                       218              19 :             Assert(node->lstate == LIMIT_WINDOWEND_TIES);
                                219                 :             /* FALL THRU */
                                220                 : 
                                221                 :         case LIMIT_WINDOWEND_TIES:
 1097 alvherre                  222             105 :             if (ScanDirectionIsForward(direction))
                                223                 :             {
                                224                 :                 /*
                                225                 :                  * Advance the subplan until we find the first row with
                                226                 :                  * different ORDER BY pathkeys.
                                227                 :                  */
 7430 tgl                       228             105 :                 slot = ExecProcNode(outerPlan);
 7443                           229             105 :                 if (TupIsNull(slot))
                                230                 :                 {
 7430                           231               1 :                     node->lstate = LIMIT_SUBPLANEOF;
 7443                           232               1 :                     return NULL;
                                233                 :                 }
                                234                 : 
                                235                 :                 /*
                                236                 :                  * Test if the new tuple and the last tuple match. If so we
                                237                 :                  * return the tuple.
                                238                 :                  */
 1097 alvherre                  239             104 :                 econtext->ecxt_innertuple = slot;
                                240             104 :                 econtext->ecxt_outertuple = node->last_slot;
                                241             104 :                 if (ExecQualAndReset(node->eqfunction, econtext))
                                242                 :                 {
                                243              86 :                     node->subSlot = slot;
                                244              86 :                     node->position++;
                                245                 :                 }
                                246                 :                 else
                                247                 :                 {
                                248              18 :                     node->lstate = LIMIT_WINDOWEND;
                                249              18 :                     return NULL;
                                250                 :                 }
                                251                 :             }
                                252                 :             else
                                253                 :             {
                                254                 :                 /*
                                255                 :                  * Backwards scan, so check for stepping off start of window.
                                256                 :                  * Change only state-machine status if so.
                                257                 :                  */
 7430 tgl                       258 UBC           0 :                 if (node->position <= node->offset + 1)
                                259                 :                 {
                                260               0 :                     node->lstate = LIMIT_WINDOWSTART;
 7443                           261               0 :                     return NULL;
                                262                 :                 }
                                263                 : 
                                264                 :                 /*
                                265                 :                  * Get previous tuple from subplan; there should be one! And
                                266                 :                  * change state-machine status.
                                267                 :                  */
 7430                           268               0 :                 slot = ExecProcNode(outerPlan);
 7443                           269               0 :                 if (TupIsNull(slot))
 7202                           270               0 :                     elog(ERROR, "LIMIT subplan failed to run backwards");
 7430                           271               0 :                 node->subSlot = slot;
                                272               0 :                 node->position--;
 1097 alvherre                  273               0 :                 node->lstate = LIMIT_INWINDOW;
                                274                 :             }
 7443 tgl                       275 CBC          86 :             break;
                                276                 : 
                                277               6 :         case LIMIT_SUBPLANEOF:
                                278               6 :             if (ScanDirectionIsForward(direction))
 7443 tgl                       279 UBC           0 :                 return NULL;
                                280                 : 
                                281                 :             /*
                                282                 :              * Backing up from subplan EOF, so re-fetch previous tuple; there
                                283                 :              * should be one!  Note previous tuple must be in window.
                                284                 :              */
 7430 tgl                       285 CBC           6 :             slot = ExecProcNode(outerPlan);
 7443                           286               6 :             if (TupIsNull(slot))
 7202 tgl                       287 UBC           0 :                 elog(ERROR, "LIMIT subplan failed to run backwards");
 7430 tgl                       288 CBC           6 :             node->subSlot = slot;
                                289               6 :             node->lstate = LIMIT_INWINDOW;
                                290                 :             /* position does not change 'cause we didn't advance it before */
 7443                           291               6 :             break;
                                292                 : 
                                293              12 :         case LIMIT_WINDOWEND:
                                294              12 :             if (ScanDirectionIsForward(direction))
 7443 tgl                       295 UBC           0 :                 return NULL;
                                296                 : 
                                297                 :             /*
                                298                 :              * We already past one position to detect ties so re-fetch
                                299                 :              * previous tuple; there should be one!  Note previous tuple must
                                300                 :              * be in window.
                                301                 :              */
 1097 alvherre                  302 CBC          12 :             if (node->limitOption == LIMIT_OPTION_WITH_TIES)
                                303                 :             {
                                304               9 :                 slot = ExecProcNode(outerPlan);
                                305               9 :                 if (TupIsNull(slot))
 1097 alvherre                  306 UBC           0 :                     elog(ERROR, "LIMIT subplan failed to run backwards");
 1097 alvherre                  307 CBC           9 :                 node->subSlot = slot;
                                308               9 :                 node->lstate = LIMIT_INWINDOW;
                                309                 :             }
                                310                 :             else
                                311                 :             {
                                312                 :                 /*
                                313                 :                  * Backing up from window end: simply re-return the last tuple
                                314                 :                  * fetched from the subplan.
                                315                 :                  */
                                316               3 :                 slot = node->subSlot;
                                317               3 :                 node->lstate = LIMIT_INWINDOW;
                                318                 :                 /* position does not change 'cause we didn't advance it before */
                                319                 :             }
 7443 tgl                       320              12 :             break;
                                321                 : 
                                322              12 :         case LIMIT_WINDOWSTART:
                                323              12 :             if (!ScanDirectionIsForward(direction))
 7443 tgl                       324 UBC           0 :                 return NULL;
                                325                 : 
                                326                 :             /*
                                327                 :              * Advancing after having backed off window start: simply
                                328                 :              * re-return the last tuple fetched from the subplan.
                                329                 :              */
 7430 tgl                       330 CBC          12 :             slot = node->subSlot;
                                331              12 :             node->lstate = LIMIT_INWINDOW;
                                332                 :             /* position does not change 'cause we didn't change it before */
 7443                           333              12 :             break;
                                334                 : 
 7443 tgl                       335 UBC           0 :         default:
 7202                           336               0 :             elog(ERROR, "impossible LIMIT state: %d",
                                337                 :                  (int) node->lstate);
                                338                 :             slot = NULL;        /* keep compiler quiet */
                                339                 :             break;
                                340                 :     }
                                341                 : 
                                342                 :     /* Return the current tuple */
 7443 tgl                       343 CBC       15789 :     Assert(!TupIsNull(slot));
                                344                 : 
 6598                           345           15789 :     return slot;
                                346                 : }
                                347                 : 
                                348                 : /*
                                349                 :  * Evaluate the limit/offset expressions --- done at startup or rescan.
                                350                 :  *
                                351                 :  * This is also a handy place to reset the current-position state info.
                                352                 :  */
                                353                 : static void
 7430                           354            2410 : recompute_limits(LimitState *node)
                                355                 : {
                                356            2410 :     ExprContext *econtext = node->ps.ps_ExprContext;
                                357                 :     Datum       val;
                                358                 :     bool        isNull;
                                359                 : 
 8200                           360            2410 :     if (node->limitOffset)
                                361                 :     {
 5971                           362             150 :         val = ExecEvalExprSwitchContext(node->limitOffset,
                                363                 :                                         econtext,
                                364                 :                                         &isNull);
                                365                 :         /* Interpret NULL offset as no offset */
 8200                           366             150 :         if (isNull)
 7430                           367               3 :             node->offset = 0;
                                368                 :         else
                                369                 :         {
 5971                           370             147 :             node->offset = DatumGetInt64(val);
                                371             147 :             if (node->offset < 0)
 5508 tgl                       372 UBC           0 :                 ereport(ERROR,
                                373                 :                         (errcode(ERRCODE_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE),
                                374                 :                          errmsg("OFFSET must not be negative")));
                                375                 :         }
                                376                 :     }
                                377                 :     else
                                378                 :     {
                                379                 :         /* No OFFSET supplied */
 7430 tgl                       380 CBC        2260 :         node->offset = 0;
                                381                 :     }
                                382                 : 
 8200                           383            2410 :     if (node->limitCount)
                                384                 :     {
 5971                           385            2386 :         val = ExecEvalExprSwitchContext(node->limitCount,
                                386                 :                                         econtext,
                                387                 :                                         &isNull);
                                388                 :         /* Interpret NULL count as no count (LIMIT ALL) */
 8200                           389            2386 :         if (isNull)
                                390                 :         {
 7430                           391               3 :             node->count = 0;
 5971                           392               3 :             node->noCount = true;
                                393                 :         }
                                394                 :         else
                                395                 :         {
                                396            2383 :             node->count = DatumGetInt64(val);
                                397            2383 :             if (node->count < 0)
 5508 tgl                       398 UBC           0 :                 ereport(ERROR,
                                399                 :                         (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
                                400                 :                          errmsg("LIMIT must not be negative")));
 5971 tgl                       401 CBC        2383 :             node->noCount = false;
                                402                 :         }
                                403                 :     }
                                404                 :     else
                                405                 :     {
                                406                 :         /* No COUNT supplied */
 7430                           407              24 :         node->count = 0;
                                408              24 :         node->noCount = true;
                                409                 :     }
                                410                 : 
                                411                 :     /* Reset position to start-of-scan */
                                412            2410 :     node->position = 0;
                                413            2410 :     node->subSlot = NULL;
                                414                 : 
                                415                 :     /* Set state-machine state */
 5806                           416            2410 :     node->lstate = LIMIT_RESCAN;
                                417                 : 
                                418                 :     /*
                                419                 :      * Notify child node about limit.  Note: think not to "optimize" by
                                420                 :      * skipping ExecSetTupleBound if compute_tuples_needed returns < 0.  We
                                421                 :      * must update the child node anyway, in case this is a rescan and the
                                422                 :      * previous time we got a different result.
                                423                 :      */
 2049 rhaas                     424            2410 :     ExecSetTupleBound(compute_tuples_needed(node), outerPlanState(node));
 4525 tgl                       425            2410 : }
                                426                 : 
                                427                 : /*
                                428                 :  * Compute the maximum number of tuples needed to satisfy this Limit node.
                                429                 :  * Return a negative value if there is not a determinable limit.
                                430                 :  */
                                431                 : static int64
 2049 rhaas                     432            2410 : compute_tuples_needed(LimitState *node)
                                433                 : {
 1097 alvherre                  434            2410 :     if ((node->noCount) || (node->limitOption == LIMIT_OPTION_WITH_TIES))
 2049 rhaas                     435              40 :         return -1;
                                436                 :     /* Note: if this overflows, we'll return a negative value, which is OK */
                                437            2370 :     return node->count + node->offset;
                                438                 : }
                                439                 : 
                                440                 : /* ----------------------------------------------------------------
                                441                 :  *      ExecInitLimit
                                442                 :  *
                                443                 :  *      This initializes the limit node state structures and
                                444                 :  *      the node's subplan.
                                445                 :  * ----------------------------------------------------------------
                                446                 :  */
                                447                 : LimitState *
 6249 tgl                       448            2572 : ExecInitLimit(Limit *node, EState *estate, int eflags)
                                449                 : {
                                450                 :     LimitState *limitstate;
                                451                 :     Plan       *outerPlan;
                                452                 : 
                                453                 :     /* check for unsupported flags */
                                454            2572 :     Assert(!(eflags & EXEC_FLAG_MARK));
                                455                 : 
                                456                 :     /*
                                457                 :      * create state structure
                                458                 :      */
 8200                           459            2572 :     limitstate = makeNode(LimitState);
 7430                           460            2572 :     limitstate->ps.plan = (Plan *) node;
                                461            2572 :     limitstate->ps.state = estate;
 2092 andres                    462            2572 :     limitstate->ps.ExecProcNode = ExecLimit;
                                463                 : 
 7443 tgl                       464            2572 :     limitstate->lstate = LIMIT_INITIAL;
                                465                 : 
                                466                 :     /*
                                467                 :      * Miscellaneous initialization
                                468                 :      *
                                469                 :      * Limit nodes never call ExecQual or ExecProject, but they need an
                                470                 :      * exprcontext anyway to evaluate the limit/offset parameters in.
                                471                 :      */
 7430                           472            2572 :     ExecAssignExprContext(estate, &limitstate->ps);
                                473                 : 
                                474                 :     /*
                                475                 :      * initialize outer plan
                                476                 :      */
 1878 andres                    477            2572 :     outerPlan = outerPlan(node);
                                478            2572 :     outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags);
                                479                 : 
                                480                 :     /*
                                481                 :      * initialize child expressions
                                482                 :      */
 7422 tgl                       483            2572 :     limitstate->limitOffset = ExecInitExpr((Expr *) node->limitOffset,
                                484                 :                                            (PlanState *) limitstate);
                                485            2572 :     limitstate->limitCount = ExecInitExpr((Expr *) node->limitCount,
                                486                 :                                           (PlanState *) limitstate);
 1097 alvherre                  487            2572 :     limitstate->limitOption = node->limitOption;
                                488                 : 
                                489                 :     /*
                                490                 :      * Initialize result type.
                                491                 :      */
 1612 andres                    492            2572 :     ExecInitResultTypeTL(&limitstate->ps);
                                493                 : 
 1606                           494            2572 :     limitstate->ps.resultopsset = true;
                                495            2572 :     limitstate->ps.resultops = ExecGetResultSlotOps(outerPlanState(limitstate),
                                496                 :                                                     &limitstate->ps.resultopsfixed);
                                497                 : 
                                498                 :     /*
                                499                 :      * limit nodes do no projections, so initialize projection info for this
                                500                 :      * node appropriately
                                501                 :      */
 7430 tgl                       502            2572 :     limitstate->ps.ps_ProjInfo = NULL;
                                503                 : 
                                504                 :     /*
                                505                 :      * Initialize the equality evaluation, to detect ties.
                                506                 :      */
 1097 alvherre                  507            2572 :     if (node->limitOption == LIMIT_OPTION_WITH_TIES)
                                508                 :     {
                                509                 :         TupleDesc   desc;
                                510                 :         const TupleTableSlotOps *ops;
                                511                 : 
                                512              13 :         desc = ExecGetResultType(outerPlanState(limitstate));
                                513              13 :         ops = ExecGetResultSlotOps(outerPlanState(limitstate), NULL);
                                514                 : 
                                515              13 :         limitstate->last_slot = ExecInitExtraTupleSlot(estate, desc, ops);
                                516              13 :         limitstate->eqfunction = execTuplesMatchPrepare(desc,
                                517                 :                                                         node->uniqNumCols,
                                518              13 :                                                         node->uniqColIdx,
                                519              13 :                                                         node->uniqOperators,
                                520              13 :                                                         node->uniqCollations,
                                521                 :                                                         &limitstate->ps);
                                522                 :     }
                                523                 : 
 7430 tgl                       524            2572 :     return limitstate;
                                525                 : }
                                526                 : 
                                527                 : /* ----------------------------------------------------------------
                                528                 :  *      ExecEndLimit
                                529                 :  *
                                530                 :  *      This shuts down the subplan and frees resources allocated
                                531                 :  *      to this node.
                                532                 :  * ----------------------------------------------------------------
                                533                 :  */
                                534                 : void
                                535            2541 : ExecEndLimit(LimitState *node)
                                536                 : {
                                537            2541 :     ExecFreeExprContext(&node->ps);
 7420                           538            2541 :     ExecEndNode(outerPlanState(node));
 8200                           539            2541 : }
                                540                 : 
                                541                 : 
                                542                 : void
 4654                           543             450 : ExecReScanLimit(LimitState *node)
                                544                 : {
  276 tgl                       545 GNC         450 :     PlanState  *outerPlan = outerPlanState(node);
                                546                 : 
 5806 tgl                       547 ECB             :     /*
                                548                 :      * Recompute limit/offset in case parameters changed, and reset the state
                                549                 :      * machine.  We must do this before rescanning our child node, in case
                                550                 :      * it's a Sort that we are passing the parameters down to.
                                551                 :      */
 5806 tgl                       552 GIC         450 :     recompute_limits(node);
                                553                 : 
 8200 tgl                       554 ECB             :     /*
                                555                 :      * if chgParam of subnode is not null then plan will be re-scanned by
                                556                 :      * first ExecProcNode.
                                557                 :      */
  276 tgl                       558 GNC         450 :     if (outerPlan->chgParam == NULL)
                                559              60 :         ExecReScan(outerPlan);
 8200 tgl                       560 CBC         450 : }
        

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