LCOV - code coverage report
Current view: top level - src/backend/executor - nodeUnique.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 36 42 85.7 %
Date: 2023-06-06 10:12:12 Functions: 3 4 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * nodeUnique.c
       4             :  *    Routines to handle unique'ing of queries where appropriate
       5             :  *
       6             :  * Unique is a very simple node type that just filters out duplicate
       7             :  * tuples from a stream of sorted tuples from its subplan.  It's essentially
       8             :  * a dumbed-down form of Group: the duplicate-removal functionality is
       9             :  * identical.  However, Unique doesn't do projection nor qual checking,
      10             :  * so it's marginally more efficient for cases where neither is needed.
      11             :  * (It's debatable whether the savings justifies carrying two plan node
      12             :  * types, though.)
      13             :  *
      14             :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
      15             :  * Portions Copyright (c) 1994, Regents of the University of California
      16             :  *
      17             :  *
      18             :  * IDENTIFICATION
      19             :  *    src/backend/executor/nodeUnique.c
      20             :  *
      21             :  *-------------------------------------------------------------------------
      22             :  */
      23             : /*
      24             :  * INTERFACE ROUTINES
      25             :  *      ExecUnique      - generate a unique'd temporary relation
      26             :  *      ExecInitUnique  - initialize node and subnodes
      27             :  *      ExecEndUnique   - shutdown node and subnodes
      28             :  *
      29             :  * NOTES
      30             :  *      Assumes tuples returned from subplan arrive in
      31             :  *      sorted order.
      32             :  */
      33             : 
      34             : #include "postgres.h"
      35             : 
      36             : #include "executor/executor.h"
      37             : #include "executor/nodeUnique.h"
      38             : #include "miscadmin.h"
      39             : #include "utils/memutils.h"
      40             : 
      41             : 
      42             : /* ----------------------------------------------------------------
      43             :  *      ExecUnique
      44             :  * ----------------------------------------------------------------
      45             :  */
      46             : static TupleTableSlot *         /* return: a tuple or NULL */
      47       83110 : ExecUnique(PlanState *pstate)
      48             : {
      49       83110 :     UniqueState *node = castNode(UniqueState, pstate);
      50       83110 :     ExprContext *econtext = node->ps.ps_ExprContext;
      51             :     TupleTableSlot *resultTupleSlot;
      52             :     TupleTableSlot *slot;
      53             :     PlanState  *outerPlan;
      54             : 
      55       83110 :     CHECK_FOR_INTERRUPTS();
      56             : 
      57             :     /*
      58             :      * get information from the node
      59             :      */
      60       83110 :     outerPlan = outerPlanState(node);
      61       83110 :     resultTupleSlot = node->ps.ps_ResultTupleSlot;
      62             : 
      63             :     /*
      64             :      * now loop, returning only non-duplicate tuples. We assume that the
      65             :      * tuples arrive in sorted order so we can detect duplicates easily. The
      66             :      * first tuple of each group is returned.
      67             :      */
      68             :     for (;;)
      69             :     {
      70             :         /*
      71             :          * fetch a tuple from the outer subplan
      72             :          */
      73      399910 :         slot = ExecProcNode(outerPlan);
      74      399910 :         if (TupIsNull(slot))
      75             :         {
      76             :             /* end of subplan, so we're done */
      77        1406 :             ExecClearTuple(resultTupleSlot);
      78        1406 :             return NULL;
      79             :         }
      80             : 
      81             :         /*
      82             :          * Always return the first tuple from the subplan.
      83             :          */
      84      398504 :         if (TupIsNull(resultTupleSlot))
      85             :             break;
      86             : 
      87             :         /*
      88             :          * Else test if the new tuple and the previously returned tuple match.
      89             :          * If so then we loop back and fetch another new tuple from the
      90             :          * subplan.
      91             :          */
      92      397176 :         econtext->ecxt_innertuple = slot;
      93      397176 :         econtext->ecxt_outertuple = resultTupleSlot;
      94      397176 :         if (!ExecQualAndReset(node->eqfunction, econtext))
      95       80376 :             break;
      96             :     }
      97             : 
      98             :     /*
      99             :      * We have a new tuple different from the previous saved tuple (if any).
     100             :      * Save it and return it.  We must copy it because the source subplan
     101             :      * won't guarantee that this source tuple is still accessible after
     102             :      * fetching the next source tuple.
     103             :      */
     104       81704 :     return ExecCopySlot(resultTupleSlot, slot);
     105             : }
     106             : 
     107             : /* ----------------------------------------------------------------
     108             :  *      ExecInitUnique
     109             :  *
     110             :  *      This initializes the unique node state structures and
     111             :  *      the node's subplan.
     112             :  * ----------------------------------------------------------------
     113             :  */
     114             : UniqueState *
     115        1636 : ExecInitUnique(Unique *node, EState *estate, int eflags)
     116             : {
     117             :     UniqueState *uniquestate;
     118             : 
     119             :     /* check for unsupported flags */
     120             :     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
     121             : 
     122             :     /*
     123             :      * create state structure
     124             :      */
     125        1636 :     uniquestate = makeNode(UniqueState);
     126        1636 :     uniquestate->ps.plan = (Plan *) node;
     127        1636 :     uniquestate->ps.state = estate;
     128        1636 :     uniquestate->ps.ExecProcNode = ExecUnique;
     129             : 
     130             :     /*
     131             :      * create expression context
     132             :      */
     133        1636 :     ExecAssignExprContext(estate, &uniquestate->ps);
     134             : 
     135             :     /*
     136             :      * then initialize outer plan
     137             :      */
     138        1636 :     outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags);
     139             : 
     140             :     /*
     141             :      * Initialize result slot and type. Unique nodes do no projections, so
     142             :      * initialize projection info for this node appropriately.
     143             :      */
     144        1636 :     ExecInitResultTupleSlotTL(&uniquestate->ps, &TTSOpsMinimalTuple);
     145        1636 :     uniquestate->ps.ps_ProjInfo = NULL;
     146             : 
     147             :     /*
     148             :      * Precompute fmgr lookup data for inner loop
     149             :      */
     150        1636 :     uniquestate->eqfunction =
     151        1636 :         execTuplesMatchPrepare(ExecGetResultType(outerPlanState(uniquestate)),
     152             :                                node->numCols,
     153        1636 :                                node->uniqColIdx,
     154        1636 :                                node->uniqOperators,
     155        1636 :                                node->uniqCollations,
     156             :                                &uniquestate->ps);
     157             : 
     158        1636 :     return uniquestate;
     159             : }
     160             : 
     161             : /* ----------------------------------------------------------------
     162             :  *      ExecEndUnique
     163             :  *
     164             :  *      This shuts down the subplan and frees resources allocated
     165             :  *      to this node.
     166             :  * ----------------------------------------------------------------
     167             :  */
     168             : void
     169        1636 : ExecEndUnique(UniqueState *node)
     170             : {
     171             :     /* clean up tuple table */
     172        1636 :     ExecClearTuple(node->ps.ps_ResultTupleSlot);
     173             : 
     174        1636 :     ExecFreeExprContext(&node->ps);
     175             : 
     176        1636 :     ExecEndNode(outerPlanState(node));
     177        1636 : }
     178             : 
     179             : 
     180             : void
     181           0 : ExecReScanUnique(UniqueState *node)
     182             : {
     183           0 :     PlanState  *outerPlan = outerPlanState(node);
     184             : 
     185             :     /* must clear result tuple so first input tuple is returned */
     186           0 :     ExecClearTuple(node->ps.ps_ResultTupleSlot);
     187             : 
     188             :     /*
     189             :      * if chgParam of subnode is not null then plan will be re-scanned by
     190             :      * first ExecProcNode.
     191             :      */
     192           0 :     if (outerPlan->chgParam == NULL)
     193           0 :         ExecReScan(outerPlan);
     194           0 : }

Generated by: LCOV version 1.14