00001 /*------------------------------------------------------------------------- 00002 * 00003 * nodeUnique.c 00004 * Routines to handle unique'ing of queries where appropriate 00005 * 00006 * Unique is a very simple node type that just filters out duplicate 00007 * tuples from a stream of sorted tuples from its subplan. It's essentially 00008 * a dumbed-down form of Group: the duplicate-removal functionality is 00009 * identical. However, Unique doesn't do projection nor qual checking, 00010 * so it's marginally more efficient for cases where neither is needed. 00011 * (It's debatable whether the savings justifies carrying two plan node 00012 * types, though.) 00013 * 00014 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group 00015 * Portions Copyright (c) 1994, Regents of the University of California 00016 * 00017 * 00018 * IDENTIFICATION 00019 * src/backend/executor/nodeUnique.c 00020 * 00021 *------------------------------------------------------------------------- 00022 */ 00023 /* 00024 * INTERFACE ROUTINES 00025 * ExecUnique - generate a unique'd temporary relation 00026 * ExecInitUnique - initialize node and subnodes 00027 * ExecEndUnique - shutdown node and subnodes 00028 * 00029 * NOTES 00030 * Assumes tuples returned from subplan arrive in 00031 * sorted order. 00032 */ 00033 00034 #include "postgres.h" 00035 00036 #include "executor/executor.h" 00037 #include "executor/nodeUnique.h" 00038 #include "utils/memutils.h" 00039 00040 00041 /* ---------------------------------------------------------------- 00042 * ExecUnique 00043 * ---------------------------------------------------------------- 00044 */ 00045 TupleTableSlot * /* return: a tuple or NULL */ 00046 ExecUnique(UniqueState *node) 00047 { 00048 Unique *plannode = (Unique *) node->ps.plan; 00049 TupleTableSlot *resultTupleSlot; 00050 TupleTableSlot *slot; 00051 PlanState *outerPlan; 00052 00053 /* 00054 * get information from the node 00055 */ 00056 outerPlan = outerPlanState(node); 00057 resultTupleSlot = node->ps.ps_ResultTupleSlot; 00058 00059 /* 00060 * now loop, returning only non-duplicate tuples. We assume that the 00061 * tuples arrive in sorted order so we can detect duplicates easily. The 00062 * first tuple of each group is returned. 00063 */ 00064 for (;;) 00065 { 00066 /* 00067 * fetch a tuple from the outer subplan 00068 */ 00069 slot = ExecProcNode(outerPlan); 00070 if (TupIsNull(slot)) 00071 { 00072 /* end of subplan, so we're done */ 00073 ExecClearTuple(resultTupleSlot); 00074 return NULL; 00075 } 00076 00077 /* 00078 * Always return the first tuple from the subplan. 00079 */ 00080 if (TupIsNull(resultTupleSlot)) 00081 break; 00082 00083 /* 00084 * Else test if the new tuple and the previously returned tuple match. 00085 * If so then we loop back and fetch another new tuple from the 00086 * subplan. 00087 */ 00088 if (!execTuplesMatch(slot, resultTupleSlot, 00089 plannode->numCols, plannode->uniqColIdx, 00090 node->eqfunctions, 00091 node->tempContext)) 00092 break; 00093 } 00094 00095 /* 00096 * We have a new tuple different from the previous saved tuple (if any). 00097 * Save it and return it. We must copy it because the source subplan 00098 * won't guarantee that this source tuple is still accessible after 00099 * fetching the next source tuple. 00100 */ 00101 return ExecCopySlot(resultTupleSlot, slot); 00102 } 00103 00104 /* ---------------------------------------------------------------- 00105 * ExecInitUnique 00106 * 00107 * This initializes the unique node state structures and 00108 * the node's subplan. 00109 * ---------------------------------------------------------------- 00110 */ 00111 UniqueState * 00112 ExecInitUnique(Unique *node, EState *estate, int eflags) 00113 { 00114 UniqueState *uniquestate; 00115 00116 /* check for unsupported flags */ 00117 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); 00118 00119 /* 00120 * create state structure 00121 */ 00122 uniquestate = makeNode(UniqueState); 00123 uniquestate->ps.plan = (Plan *) node; 00124 uniquestate->ps.state = estate; 00125 00126 /* 00127 * Miscellaneous initialization 00128 * 00129 * Unique nodes have no ExprContext initialization because they never call 00130 * ExecQual or ExecProject. But they do need a per-tuple memory context 00131 * anyway for calling execTuplesMatch. 00132 */ 00133 uniquestate->tempContext = 00134 AllocSetContextCreate(CurrentMemoryContext, 00135 "Unique", 00136 ALLOCSET_DEFAULT_MINSIZE, 00137 ALLOCSET_DEFAULT_INITSIZE, 00138 ALLOCSET_DEFAULT_MAXSIZE); 00139 00140 /* 00141 * Tuple table initialization 00142 */ 00143 ExecInitResultTupleSlot(estate, &uniquestate->ps); 00144 00145 /* 00146 * then initialize outer plan 00147 */ 00148 outerPlanState(uniquestate) = ExecInitNode(outerPlan(node), estate, eflags); 00149 00150 /* 00151 * unique nodes do no projections, so initialize projection info for this 00152 * node appropriately 00153 */ 00154 ExecAssignResultTypeFromTL(&uniquestate->ps); 00155 uniquestate->ps.ps_ProjInfo = NULL; 00156 00157 /* 00158 * Precompute fmgr lookup data for inner loop 00159 */ 00160 uniquestate->eqfunctions = 00161 execTuplesMatchPrepare(node->numCols, 00162 node->uniqOperators); 00163 00164 return uniquestate; 00165 } 00166 00167 /* ---------------------------------------------------------------- 00168 * ExecEndUnique 00169 * 00170 * This shuts down the subplan and frees resources allocated 00171 * to this node. 00172 * ---------------------------------------------------------------- 00173 */ 00174 void 00175 ExecEndUnique(UniqueState *node) 00176 { 00177 /* clean up tuple table */ 00178 ExecClearTuple(node->ps.ps_ResultTupleSlot); 00179 00180 MemoryContextDelete(node->tempContext); 00181 00182 ExecEndNode(outerPlanState(node)); 00183 } 00184 00185 00186 void 00187 ExecReScanUnique(UniqueState *node) 00188 { 00189 /* must clear result tuple so first input tuple is returned */ 00190 ExecClearTuple(node->ps.ps_ResultTupleSlot); 00191 00192 /* 00193 * if chgParam of subnode is not null then plan will be re-scanned by 00194 * first ExecProcNode. 00195 */ 00196 if (node->ps.lefttree->chgParam == NULL) 00197 ExecReScan(node->ps.lefttree); 00198 }