LCOV - code coverage report
Current view: top level - src/backend/executor - nodeSort.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 98.3 % 174 171
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 10 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 83.8 % 74 62

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * nodeSort.c
       4                 :             :  *        Routines to handle sorting of relations.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/executor/nodeSort.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : 
      16                 :             : #include "postgres.h"
      17                 :             : 
      18                 :             : #include "access/parallel.h"
      19                 :             : #include "executor/execdebug.h"
      20                 :             : #include "executor/nodeSort.h"
      21                 :             : #include "miscadmin.h"
      22                 :             : #include "utils/tuplesort.h"
      23                 :             : 
      24                 :             : 
      25                 :             : /* ----------------------------------------------------------------
      26                 :             :  *              ExecSort
      27                 :             :  *
      28                 :             :  *              Sorts tuples from the outer subtree of the node using tuplesort,
      29                 :             :  *              which saves the results in a temporary file or memory. After the
      30                 :             :  *              initial call, returns a tuple from the file with each call.
      31                 :             :  *
      32                 :             :  *              There are two distinct ways that this sort can be performed:
      33                 :             :  *
      34                 :             :  *              1) When the result is a single column we perform a Datum sort.
      35                 :             :  *
      36                 :             :  *              2) When the result contains multiple columns we perform a tuple sort.
      37                 :             :  *
      38                 :             :  *              We could do this by always performing a tuple sort, however sorting
      39                 :             :  *              Datums only can be significantly faster than sorting tuples,
      40                 :             :  *              especially when the Datums are of a pass-by-value type.
      41                 :             :  *
      42                 :             :  *              Conditions:
      43                 :             :  *                -- none.
      44                 :             :  *
      45                 :             :  *              Initial States:
      46                 :             :  *                -- the outer child is prepared to return the first tuple.
      47                 :             :  * ----------------------------------------------------------------
      48                 :             :  */
      49                 :             : static TupleTableSlot *
      50                 :      926835 : ExecSort(PlanState *pstate)
      51                 :             : {
      52                 :      926835 :         SortState  *node = castNode(SortState, pstate);
      53                 :      926835 :         EState     *estate;
      54                 :      926835 :         ScanDirection dir;
      55                 :      926835 :         Tuplesortstate *tuplesortstate;
      56                 :      926835 :         TupleTableSlot *slot;
      57                 :             : 
      58         [ +  + ]:      926835 :         CHECK_FOR_INTERRUPTS();
      59                 :             : 
      60                 :             :         /*
      61                 :             :          * get state info from node
      62                 :             :          */
      63                 :             :         SO1_printf("ExecSort: %s\n",
      64                 :             :                            "entering routine");
      65                 :             : 
      66                 :      926835 :         estate = node->ss.ps.state;
      67                 :      926835 :         dir = estate->es_direction;
      68                 :      926835 :         tuplesortstate = (Tuplesortstate *) node->tuplesortstate;
      69                 :             : 
      70                 :             :         /*
      71                 :             :          * If first time through, read all tuples from outer plan and pass them to
      72                 :             :          * tuplesort.c. Subsequent calls just fetch tuples from tuplesort.
      73                 :             :          */
      74                 :             : 
      75         [ +  + ]:      926835 :         if (!node->sort_Done)
      76                 :             :         {
      77                 :        8611 :                 Sort       *plannode = (Sort *) node->ss.ps.plan;
      78                 :        8611 :                 PlanState  *outerNode;
      79                 :        8611 :                 TupleDesc       tupDesc;
      80                 :        8611 :                 int                     tuplesortopts = TUPLESORT_NONE;
      81                 :             : 
      82                 :             :                 SO1_printf("ExecSort: %s\n",
      83                 :             :                                    "sorting subplan");
      84                 :             : 
      85                 :             :                 /*
      86                 :             :                  * Want to scan subplan in the forward direction while creating the
      87                 :             :                  * sorted data.
      88                 :             :                  */
      89                 :        8611 :                 estate->es_direction = ForwardScanDirection;
      90                 :             : 
      91                 :             :                 /*
      92                 :             :                  * Initialize tuplesort module.
      93                 :             :                  */
      94                 :             :                 SO1_printf("ExecSort: %s\n",
      95                 :             :                                    "calling tuplesort_begin");
      96                 :             : 
      97                 :        8611 :                 outerNode = outerPlanState(node);
      98                 :        8611 :                 tupDesc = ExecGetResultType(outerNode);
      99                 :             : 
     100         [ +  + ]:        8611 :                 if (node->randomAccess)
     101                 :         382 :                         tuplesortopts |= TUPLESORT_RANDOMACCESS;
     102         [ +  + ]:        8611 :                 if (node->bounded)
     103                 :         120 :                         tuplesortopts |= TUPLESORT_ALLOWBOUNDED;
     104                 :             : 
     105         [ +  + ]:        8611 :                 if (node->datumSort)
     106                 :        1122 :                         tuplesortstate = tuplesort_begin_datum(TupleDescAttr(tupDesc, 0)->atttypid,
     107                 :         561 :                                                                                                    plannode->sortOperators[0],
     108                 :         561 :                                                                                                    plannode->collations[0],
     109                 :         561 :                                                                                                    plannode->nullsFirst[0],
     110                 :         561 :                                                                                                    work_mem,
     111                 :             :                                                                                                    NULL,
     112                 :         561 :                                                                                                    tuplesortopts);
     113                 :             :                 else
     114                 :       16100 :                         tuplesortstate = tuplesort_begin_heap(tupDesc,
     115                 :        8050 :                                                                                                   plannode->numCols,
     116                 :        8050 :                                                                                                   plannode->sortColIdx,
     117                 :        8050 :                                                                                                   plannode->sortOperators,
     118                 :        8050 :                                                                                                   plannode->collations,
     119                 :        8050 :                                                                                                   plannode->nullsFirst,
     120                 :        8050 :                                                                                                   work_mem,
     121                 :             :                                                                                                   NULL,
     122                 :        8050 :                                                                                                   tuplesortopts);
     123         [ +  + ]:        8611 :                 if (node->bounded)
     124                 :         120 :                         tuplesort_set_bound(tuplesortstate, node->bound);
     125                 :        8611 :                 node->tuplesortstate = tuplesortstate;
     126                 :             : 
     127                 :             :                 /*
     128                 :             :                  * Scan the subplan and feed all the tuples to tuplesort using the
     129                 :             :                  * appropriate method based on the type of sort we're doing.
     130                 :             :                  */
     131         [ +  + ]:        8611 :                 if (node->datumSort)
     132                 :             :                 {
     133                 :      236778 :                         for (;;)
     134                 :             :                         {
     135                 :      236778 :                                 slot = ExecProcNode(outerNode);
     136                 :             : 
     137   [ +  +  +  + ]:      236778 :                                 if (TupIsNull(slot))
     138                 :         563 :                                         break;
     139                 :      236215 :                                 slot_getsomeattrs(slot, 1);
     140                 :      472430 :                                 tuplesort_putdatum(tuplesortstate,
     141                 :      236215 :                                                                    slot->tts_values[0],
     142                 :      236215 :                                                                    slot->tts_isnull[0]);
     143                 :             :                         }
     144                 :         563 :                 }
     145                 :             :                 else
     146                 :             :                 {
     147                 :      892772 :                         for (;;)
     148                 :             :                         {
     149                 :      892772 :                                 slot = ExecProcNode(outerNode);
     150                 :             : 
     151   [ +  +  +  + ]:      892772 :                                 if (TupIsNull(slot))
     152                 :        8048 :                                         break;
     153                 :      884724 :                                 tuplesort_puttupleslot(tuplesortstate, slot);
     154                 :             :                         }
     155                 :             :                 }
     156                 :             : 
     157                 :             :                 /*
     158                 :             :                  * Complete the sort.
     159                 :             :                  */
     160                 :        8611 :                 tuplesort_performsort(tuplesortstate);
     161                 :             : 
     162                 :             :                 /*
     163                 :             :                  * restore to user specified direction
     164                 :             :                  */
     165                 :        8611 :                 estate->es_direction = dir;
     166                 :             : 
     167                 :             :                 /*
     168                 :             :                  * finally set the sorted flag to true
     169                 :             :                  */
     170                 :        8611 :                 node->sort_Done = true;
     171                 :        8611 :                 node->bounded_Done = node->bounded;
     172                 :        8611 :                 node->bound_Done = node->bound;
     173   [ +  +  +  + ]:        8611 :                 if (node->shared_info && node->am_worker)
     174                 :             :                 {
     175                 :          16 :                         TuplesortInstrumentation *si;
     176                 :             : 
     177         [ +  - ]:          16 :                         Assert(IsParallelWorker());
     178         [ +  - ]:          16 :                         Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
     179                 :          16 :                         si = &node->shared_info->sinstrument[ParallelWorkerNumber];
     180                 :          16 :                         tuplesort_get_stats(tuplesortstate, si);
     181                 :          16 :                 }
     182                 :             :                 SO1_printf("ExecSort: %s\n", "sorting done");
     183                 :        8611 :         }
     184                 :             : 
     185                 :             :         SO1_printf("ExecSort: %s\n",
     186                 :             :                            "retrieving tuple from tuplesort");
     187                 :             : 
     188                 :      926835 :         slot = node->ss.ps.ps_ResultTupleSlot;
     189                 :             : 
     190                 :             :         /*
     191                 :             :          * Fetch the next sorted item from the appropriate tuplesort function. For
     192                 :             :          * datum sorts we must manage the slot ourselves and leave it clear when
     193                 :             :          * tuplesort_getdatum returns false to indicate there are no more datums.
     194                 :             :          * For tuple sorts, tuplesort_gettupleslot manages the slot for us and
     195                 :             :          * empties the slot when it runs out of tuples.
     196                 :             :          */
     197         [ +  + ]:      926835 :         if (node->datumSort)
     198                 :             :         {
     199                 :      187044 :                 ExecClearTuple(slot);
     200   [ +  +  +  + ]:      374088 :                 if (tuplesort_getdatum(tuplesortstate, ScanDirectionIsForward(dir),
     201                 :      187044 :                                                            false, &(slot->tts_values[0]),
     202                 :      187044 :                                                            &(slot->tts_isnull[0]), NULL))
     203                 :      186507 :                         ExecStoreVirtualTuple(slot);
     204                 :      187044 :         }
     205                 :             :         else
     206                 :     1479582 :                 (void) tuplesort_gettupleslot(tuplesortstate,
     207                 :      739791 :                                                                           ScanDirectionIsForward(dir),
     208                 :      739791 :                                                                           false, slot, NULL);
     209                 :             : 
     210                 :     1853670 :         return slot;
     211                 :      926835 : }
     212                 :             : 
     213                 :             : /* ----------------------------------------------------------------
     214                 :             :  *              ExecInitSort
     215                 :             :  *
     216                 :             :  *              Creates the run-time state information for the sort node
     217                 :             :  *              produced by the planner and initializes its outer subtree.
     218                 :             :  * ----------------------------------------------------------------
     219                 :             :  */
     220                 :             : SortState *
     221                 :        9455 : ExecInitSort(Sort *node, EState *estate, int eflags)
     222                 :             : {
     223                 :        9455 :         SortState  *sortstate;
     224                 :        9455 :         TupleDesc       outerTupDesc;
     225                 :             : 
     226                 :             :         SO1_printf("ExecInitSort: %s\n",
     227                 :             :                            "initializing sort node");
     228                 :             : 
     229                 :             :         /*
     230                 :             :          * create state structure
     231                 :             :          */
     232                 :        9455 :         sortstate = makeNode(SortState);
     233                 :        9455 :         sortstate->ss.ps.plan = (Plan *) node;
     234                 :        9455 :         sortstate->ss.ps.state = estate;
     235                 :        9455 :         sortstate->ss.ps.ExecProcNode = ExecSort;
     236                 :             : 
     237                 :             :         /*
     238                 :             :          * We must have random access to the sort output to do backward scan or
     239                 :             :          * mark/restore.  We also prefer to materialize the sort output if we
     240                 :             :          * might be called on to rewind and replay it many times.
     241                 :             :          */
     242                 :       18910 :         sortstate->randomAccess = (eflags & (EXEC_FLAG_REWIND |
     243                 :             :                                                                                  EXEC_FLAG_BACKWARD |
     244                 :        9455 :                                                                                  EXEC_FLAG_MARK)) != 0;
     245                 :             : 
     246                 :        9455 :         sortstate->bounded = false;
     247                 :        9455 :         sortstate->sort_Done = false;
     248                 :        9455 :         sortstate->tuplesortstate = NULL;
     249                 :             : 
     250                 :             :         /*
     251                 :             :          * Miscellaneous initialization
     252                 :             :          *
     253                 :             :          * Sort nodes don't initialize their ExprContexts because they never call
     254                 :             :          * ExecQual or ExecProject.
     255                 :             :          */
     256                 :             : 
     257                 :             :         /*
     258                 :             :          * initialize child nodes
     259                 :             :          *
     260                 :             :          * We shield the child node from the need to support REWIND, BACKWARD, or
     261                 :             :          * MARK/RESTORE.
     262                 :             :          */
     263                 :        9455 :         eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);
     264                 :             : 
     265                 :        9455 :         outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate, eflags);
     266                 :             : 
     267                 :             :         /*
     268                 :             :          * Initialize scan slot and type.
     269                 :             :          */
     270                 :        9455 :         ExecCreateScanSlotFromOuterPlan(estate, &sortstate->ss, &TTSOpsVirtual);
     271                 :             : 
     272                 :             :         /*
     273                 :             :          * Initialize return slot and type. No need to initialize projection info
     274                 :             :          * because this node doesn't do projections.
     275                 :             :          */
     276                 :        9455 :         ExecInitResultTupleSlotTL(&sortstate->ss.ps, &TTSOpsMinimalTuple);
     277                 :        9455 :         sortstate->ss.ps.ps_ProjInfo = NULL;
     278                 :             : 
     279                 :        9455 :         outerTupDesc = ExecGetResultType(outerPlanState(sortstate));
     280                 :             : 
     281                 :             :         /*
     282                 :             :          * We perform a Datum sort when we're sorting just a single column,
     283                 :             :          * otherwise we perform a tuple sort.
     284                 :             :          */
     285         [ +  + ]:        9455 :         if (outerTupDesc->natts == 1)
     286                 :        1179 :                 sortstate->datumSort = true;
     287                 :             :         else
     288                 :        8276 :                 sortstate->datumSort = false;
     289                 :             : 
     290                 :             :         SO1_printf("ExecInitSort: %s\n",
     291                 :             :                            "sort node initialized");
     292                 :             : 
     293                 :       18910 :         return sortstate;
     294                 :        9455 : }
     295                 :             : 
     296                 :             : /* ----------------------------------------------------------------
     297                 :             :  *              ExecEndSort(node)
     298                 :             :  * ----------------------------------------------------------------
     299                 :             :  */
     300                 :             : void
     301                 :        9429 : ExecEndSort(SortState *node)
     302                 :             : {
     303                 :             :         SO1_printf("ExecEndSort: %s\n",
     304                 :             :                            "shutting down sort node");
     305                 :             : 
     306                 :             :         /*
     307                 :             :          * Release tuplesort resources
     308                 :             :          */
     309         [ +  + ]:        9429 :         if (node->tuplesortstate != NULL)
     310                 :        8222 :                 tuplesort_end((Tuplesortstate *) node->tuplesortstate);
     311                 :        9429 :         node->tuplesortstate = NULL;
     312                 :             : 
     313                 :             :         /*
     314                 :             :          * shut down the subplan
     315                 :             :          */
     316                 :        9429 :         ExecEndNode(outerPlanState(node));
     317                 :             : 
     318                 :             :         SO1_printf("ExecEndSort: %s\n",
     319                 :             :                            "sort node shutdown");
     320                 :        9429 : }
     321                 :             : 
     322                 :             : /* ----------------------------------------------------------------
     323                 :             :  *              ExecSortMarkPos
     324                 :             :  *
     325                 :             :  *              Calls tuplesort to save the current position in the sorted file.
     326                 :             :  * ----------------------------------------------------------------
     327                 :             :  */
     328                 :             : void
     329                 :       93465 : ExecSortMarkPos(SortState *node)
     330                 :             : {
     331                 :             :         /*
     332                 :             :          * if we haven't sorted yet, just return
     333                 :             :          */
     334         [ -  + ]:       93465 :         if (!node->sort_Done)
     335                 :           0 :                 return;
     336                 :             : 
     337                 :       93465 :         tuplesort_markpos((Tuplesortstate *) node->tuplesortstate);
     338                 :       93465 : }
     339                 :             : 
     340                 :             : /* ----------------------------------------------------------------
     341                 :             :  *              ExecSortRestrPos
     342                 :             :  *
     343                 :             :  *              Calls tuplesort to restore the last saved sort file position.
     344                 :             :  * ----------------------------------------------------------------
     345                 :             :  */
     346                 :             : void
     347                 :        4886 : ExecSortRestrPos(SortState *node)
     348                 :             : {
     349                 :             :         /*
     350                 :             :          * if we haven't sorted yet, just return.
     351                 :             :          */
     352         [ -  + ]:        4886 :         if (!node->sort_Done)
     353                 :           0 :                 return;
     354                 :             : 
     355                 :             :         /*
     356                 :             :          * restore the scan to the previously marked position
     357                 :             :          */
     358                 :        4886 :         tuplesort_restorepos((Tuplesortstate *) node->tuplesortstate);
     359                 :        4886 : }
     360                 :             : 
     361                 :             : void
     362                 :         423 : ExecReScanSort(SortState *node)
     363                 :             : {
     364                 :         423 :         PlanState  *outerPlan = outerPlanState(node);
     365                 :             : 
     366                 :             :         /*
     367                 :             :          * If we haven't sorted yet, just return. If outerplan's chgParam is not
     368                 :             :          * NULL then it will be re-scanned by ExecProcNode, else no reason to
     369                 :             :          * re-scan it at all.
     370                 :             :          */
     371         [ +  + ]:         423 :         if (!node->sort_Done)
     372                 :          55 :                 return;
     373                 :             : 
     374                 :             :         /* must drop pointer to sort result tuple */
     375                 :         368 :         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
     376                 :             : 
     377                 :             :         /*
     378                 :             :          * If subnode is to be rescanned then we forget previous sort results; we
     379                 :             :          * have to re-read the subplan and re-sort.  Also must re-sort if the
     380                 :             :          * bounded-sort parameters changed or we didn't select randomAccess.
     381                 :             :          *
     382                 :             :          * Otherwise we can just rewind and rescan the sorted output.
     383                 :             :          */
     384         [ +  + ]:         368 :         if (outerPlan->chgParam != NULL ||
     385         [ +  - ]:          62 :                 node->bounded != node->bounded_Done ||
     386   [ +  +  +  + ]:          62 :                 node->bound != node->bound_Done ||
     387                 :          53 :                 !node->randomAccess)
     388                 :             :         {
     389                 :         367 :                 node->sort_Done = false;
     390                 :         367 :                 tuplesort_end((Tuplesortstate *) node->tuplesortstate);
     391                 :         367 :                 node->tuplesortstate = NULL;
     392                 :             : 
     393                 :             :                 /*
     394                 :             :                  * if chgParam of subnode is not null then plan will be re-scanned by
     395                 :             :                  * first ExecProcNode.
     396                 :             :                  */
     397         [ +  + ]:         367 :                 if (outerPlan->chgParam == NULL)
     398                 :          61 :                         ExecReScan(outerPlan);
     399                 :         367 :         }
     400                 :             :         else
     401                 :           1 :                 tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);
     402         [ -  + ]:         423 : }
     403                 :             : 
     404                 :             : /* ----------------------------------------------------------------
     405                 :             :  *                                              Parallel Query Support
     406                 :             :  * ----------------------------------------------------------------
     407                 :             :  */
     408                 :             : 
     409                 :             : /* ----------------------------------------------------------------
     410                 :             :  *              ExecSortEstimate
     411                 :             :  *
     412                 :             :  *              Estimate space required to propagate sort statistics.
     413                 :             :  * ----------------------------------------------------------------
     414                 :             :  */
     415                 :             : void
     416                 :          26 : ExecSortEstimate(SortState *node, ParallelContext *pcxt)
     417                 :             : {
     418                 :          26 :         Size            size;
     419                 :             : 
     420                 :             :         /* don't need this if not instrumenting or no workers */
     421   [ +  +  -  + ]:          26 :         if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     422                 :          24 :                 return;
     423                 :             : 
     424                 :           2 :         size = mul_size(pcxt->nworkers, sizeof(TuplesortInstrumentation));
     425                 :           2 :         size = add_size(size, offsetof(SharedSortInfo, sinstrument));
     426                 :           2 :         shm_toc_estimate_chunk(&pcxt->estimator, size);
     427                 :           2 :         shm_toc_estimate_keys(&pcxt->estimator, 1);
     428         [ -  + ]:          26 : }
     429                 :             : 
     430                 :             : /* ----------------------------------------------------------------
     431                 :             :  *              ExecSortInitializeDSM
     432                 :             :  *
     433                 :             :  *              Initialize DSM space for sort statistics.
     434                 :             :  * ----------------------------------------------------------------
     435                 :             :  */
     436                 :             : void
     437                 :          26 : ExecSortInitializeDSM(SortState *node, ParallelContext *pcxt)
     438                 :             : {
     439                 :          26 :         Size            size;
     440                 :             : 
     441                 :             :         /* don't need this if not instrumenting or no workers */
     442   [ +  +  -  + ]:          26 :         if (!node->ss.ps.instrument || pcxt->nworkers == 0)
     443                 :          24 :                 return;
     444                 :             : 
     445                 :           2 :         size = offsetof(SharedSortInfo, sinstrument)
     446                 :           2 :                 + pcxt->nworkers * sizeof(TuplesortInstrumentation);
     447                 :           2 :         node->shared_info = shm_toc_allocate(pcxt->toc, size);
     448                 :             :         /* ensure any unfilled slots will contain zeroes */
     449                 :           2 :         memset(node->shared_info, 0, size);
     450                 :           2 :         node->shared_info->num_workers = pcxt->nworkers;
     451                 :           4 :         shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id,
     452                 :           2 :                                    node->shared_info);
     453         [ -  + ]:          26 : }
     454                 :             : 
     455                 :             : /* ----------------------------------------------------------------
     456                 :             :  *              ExecSortInitializeWorker
     457                 :             :  *
     458                 :             :  *              Attach worker to DSM space for sort statistics.
     459                 :             :  * ----------------------------------------------------------------
     460                 :             :  */
     461                 :             : void
     462                 :          77 : ExecSortInitializeWorker(SortState *node, ParallelWorkerContext *pwcxt)
     463                 :             : {
     464                 :          77 :         node->shared_info =
     465                 :          77 :                 shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, true);
     466                 :          77 :         node->am_worker = true;
     467                 :          77 : }
     468                 :             : 
     469                 :             : /* ----------------------------------------------------------------
     470                 :             :  *              ExecSortRetrieveInstrumentation
     471                 :             :  *
     472                 :             :  *              Transfer sort statistics from DSM to private memory.
     473                 :             :  * ----------------------------------------------------------------
     474                 :             :  */
     475                 :             : void
     476                 :           2 : ExecSortRetrieveInstrumentation(SortState *node)
     477                 :             : {
     478                 :           2 :         Size            size;
     479                 :           2 :         SharedSortInfo *si;
     480                 :             : 
     481         [ +  - ]:           2 :         if (node->shared_info == NULL)
     482                 :           0 :                 return;
     483                 :             : 
     484                 :           2 :         size = offsetof(SharedSortInfo, sinstrument)
     485                 :           2 :                 + node->shared_info->num_workers * sizeof(TuplesortInstrumentation);
     486                 :           2 :         si = palloc(size);
     487                 :           2 :         memcpy(si, node->shared_info, size);
     488                 :           2 :         node->shared_info = si;
     489         [ -  + ]:           2 : }
        

Generated by: LCOV version 2.3.2-1