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 : }