LCOV - differential code coverage report
Current view: top level - src/backend/executor - nodeLimit.c (source / functions) Coverage Total Hit LBC UBC CBC
Current: a2387c32f2f8a1643c7d71b951587e6bcb2d4744 vs 371a302eecdc82274b0ae2967d18fd726a0aa6a1 Lines: 87.4 % 175 153 22 153
Current Date: 2025-10-26 12:31:50 -0700 Functions: 100.0 % 6 6 6
Baseline: lcov-20251027-010456-baseline Branches: 65.3 % 121 79 1 41 79
Baseline Date: 2025-10-26 11:01:32 +1300 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(360..) days: 87.4 % 175 153 22 153
Function coverage date bins:
(360..) days: 100.0 % 6 6 6
Branch coverage date bins:
(360..) days: 65.3 % 121 79 1 41 79

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

Generated by: LCOV version 2.4-beta