aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeUnique.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeUnique.c')
-rw-r--r--src/backend/executor/nodeUnique.c532
1 files changed, 277 insertions, 255 deletions
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 65c3bea76e0..75e40ccad96 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -1,25 +1,25 @@
/*-------------------------------------------------------------------------
*
* nodeUnique.c--
- * Routines to handle unique'ing of queries where appropriate
+ * Routines to handle unique'ing of queries where appropriate
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.7 1997/08/26 23:31:44 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.8 1997/09/07 04:41:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecUnique - generate a unique'd temporary relation
- * ExecInitUnique - initialize node and subnodes..
- * ExecEndUnique - shutdown node and subnodes
+ * ExecUnique - generate a unique'd temporary relation
+ * ExecInitUnique - initialize node and subnodes..
+ * ExecEndUnique - shutdown node and subnodes
*
* NOTES
- * Assumes tuples returned from subplan arrive in
- * sorted order.
+ * Assumes tuples returned from subplan arrive in
+ * sorted order.
*
*/
#include <string.h>
@@ -31,296 +31,318 @@
#include "executor/nodeUnique.h"
#include "optimizer/clauses.h"
#include "access/heapam.h"
-#include "access/printtup.h" /* for typtoout() */
-#include "utils/builtins.h" /* for namecpy()*/
+#include "access/printtup.h" /* for typtoout() */
+#include "utils/builtins.h" /* for namecpy() */
/* ----------------------------------------------------------------
- * ExecIdenticalTuples
+ * ExecIdenticalTuples
*
- * This is a hack function used by ExecUnique to see if
- * two tuples are identical. This should be provided
- * by the heap tuple code but isn't. The real problem
- * is that we assume we can byte compare tuples to determine
- * if they are "equal". In fact, if we have user defined
- * types there may be problems because it's possible that
- * an ADT may have multiple representations with the
- * same ADT value. -cim
+ * This is a hack function used by ExecUnique to see if
+ * two tuples are identical. This should be provided
+ * by the heap tuple code but isn't. The real problem
+ * is that we assume we can byte compare tuples to determine
+ * if they are "equal". In fact, if we have user defined
+ * types there may be problems because it's possible that
+ * an ADT may have multiple representations with the
+ * same ADT value. -cim
* ----------------------------------------------------------------
*/
-static bool /* true if tuples are identical, false otherwise */
-ExecIdenticalTuples(TupleTableSlot *t1, TupleTableSlot *t2)
+static bool /* true if tuples are identical, false
+ * otherwise */
+ExecIdenticalTuples(TupleTableSlot * t1, TupleTableSlot * t2)
{
- HeapTuple h1;
- HeapTuple h2;
- char *d1;
- char *d2;
- int len;
-
- h1 = t1->val;
- h2 = t2->val;
-
- /* ----------------
- * if tuples aren't the same length then they are
- * obviously different (one may have null attributes).
- * ----------------
- */
- if (h1->t_len != h2->t_len)
- return false;
-
- /* ----------------
- * if the tuples have different header offsets then
- * they are different. This will prevent us from returning
- * true when comparing tuples of one attribute where one of
- * two we're looking at is null (t_len - t_hoff == 0).
- * THE t_len FIELDS CAN BE THE SAME IN THIS CASE!!
- * ----------------
- */
- if (h1->t_hoff != h2->t_hoff)
- return false;
-
- /* ----------------
- * ok, now get the pointers to the data and the
- * size of the attribute portion of the tuple.
- * ----------------
- */
- d1 = (char *) GETSTRUCT(h1);
- d2 = (char *) GETSTRUCT(h2);
- len = (int) h1->t_len - (int) h1->t_hoff;
-
- /* ----------------
- * byte compare the data areas and return the result.
- * ----------------
- */
- if (memcmp(d1, d2, len) != 0)
- return false;
-
- return true;
+ HeapTuple h1;
+ HeapTuple h2;
+ char *d1;
+ char *d2;
+ int len;
+
+ h1 = t1->val;
+ h2 = t2->val;
+
+ /* ----------------
+ * if tuples aren't the same length then they are
+ * obviously different (one may have null attributes).
+ * ----------------
+ */
+ if (h1->t_len != h2->t_len)
+ return false;
+
+ /* ----------------
+ * if the tuples have different header offsets then
+ * they are different. This will prevent us from returning
+ * true when comparing tuples of one attribute where one of
+ * two we're looking at is null (t_len - t_hoff == 0).
+ * THE t_len FIELDS CAN BE THE SAME IN THIS CASE!!
+ * ----------------
+ */
+ if (h1->t_hoff != h2->t_hoff)
+ return false;
+
+ /* ----------------
+ * ok, now get the pointers to the data and the
+ * size of the attribute portion of the tuple.
+ * ----------------
+ */
+ d1 = (char *) GETSTRUCT(h1);
+ d2 = (char *) GETSTRUCT(h2);
+ len = (int) h1->t_len - (int) h1->t_hoff;
+
+ /* ----------------
+ * byte compare the data areas and return the result.
+ * ----------------
+ */
+ if (memcmp(d1, d2, len) != 0)
+ return false;
+
+ return true;
}
/* ----------------------------------------------------------------
- * ExecUnique
+ * ExecUnique
*
- * This is a very simple node which filters out duplicate
- * tuples from a stream of sorted tuples from a subplan.
+ * This is a very simple node which filters out duplicate
+ * tuples from a stream of sorted tuples from a subplan.
*
- * XXX see comments below regarding freeing tuples.
+ * XXX see comments below regarding freeing tuples.
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecUnique(Unique *node)
+TupleTableSlot * /* return: a tuple or NULL */
+ExecUnique(Unique * node)
{
- UniqueState *uniquestate;
- TupleTableSlot *resultTupleSlot;
- TupleTableSlot *slot;
- Plan *outerPlan;
- char *uniqueAttr;
- AttrNumber uniqueAttrNum;
- TupleDesc tupDesc;
- Oid typoutput;
-
- /* ----------------
- * get information from the node
- * ----------------
- */
- uniquestate = node->uniquestate;
- outerPlan = outerPlan((Plan *) node);
- resultTupleSlot = uniquestate->cs_ResultTupleSlot;
- uniqueAttr = node->uniqueAttr;
- uniqueAttrNum = node->uniqueAttrNum;
-
- if (uniqueAttr) {
- tupDesc = ExecGetResultType(uniquestate);
- typoutput = typtoout((Oid)tupDesc->attrs[uniqueAttrNum-1]->atttypid);
- }
- else { /* keep compiler quiet */
- tupDesc = NULL;
- typoutput = 0;
- }
-
- /* ----------------
- * now loop, returning only non-duplicate tuples.
- * We assume that the tuples arrive in sorted order
- * so we can detect duplicates easily.
- * ----------------
- */
- for (;;) {
+ UniqueState *uniquestate;
+ TupleTableSlot *resultTupleSlot;
+ TupleTableSlot *slot;
+ Plan *outerPlan;
+ char *uniqueAttr;
+ AttrNumber uniqueAttrNum;
+ TupleDesc tupDesc;
+ Oid typoutput;
+
/* ----------------
- * fetch a tuple from the outer subplan
+ * get information from the node
* ----------------
*/
- slot = ExecProcNode(outerPlan, (Plan*)node);
- if (TupIsNull(slot))
- return NULL;
-
+ uniquestate = node->uniquestate;
+ outerPlan = outerPlan((Plan *) node);
+ resultTupleSlot = uniquestate->cs_ResultTupleSlot;
+ uniqueAttr = node->uniqueAttr;
+ uniqueAttrNum = node->uniqueAttrNum;
+
+ if (uniqueAttr)
+ {
+ tupDesc = ExecGetResultType(uniquestate);
+ typoutput = typtoout((Oid) tupDesc->attrs[uniqueAttrNum - 1]->atttypid);
+ }
+ else
+ { /* keep compiler quiet */
+ tupDesc = NULL;
+ typoutput = 0;
+ }
+
/* ----------------
- * we use the result tuple slot to hold our saved tuples.
- * if we haven't a saved tuple to compare our new tuple with,
- * then we exit the loop. This new tuple as the saved tuple
- * the next time we get here.
+ * now loop, returning only non-duplicate tuples.
+ * We assume that the tuples arrive in sorted order
+ * so we can detect duplicates easily.
* ----------------
*/
- if (TupIsNull(resultTupleSlot))
- break;
-
+ for (;;)
+ {
+ /* ----------------
+ * fetch a tuple from the outer subplan
+ * ----------------
+ */
+ slot = ExecProcNode(outerPlan, (Plan *) node);
+ if (TupIsNull(slot))
+ return NULL;
+
+ /* ----------------
+ * we use the result tuple slot to hold our saved tuples.
+ * if we haven't a saved tuple to compare our new tuple with,
+ * then we exit the loop. This new tuple as the saved tuple
+ * the next time we get here.
+ * ----------------
+ */
+ if (TupIsNull(resultTupleSlot))
+ break;
+
+ /* ----------------
+ * now test if the new tuple and the previous
+ * tuple match. If so then we loop back and fetch
+ * another new tuple from the subplan.
+ * ----------------
+ */
+
+ if (uniqueAttr)
+ {
+
+ /*
+ * to check equality, we check to see if the typoutput of the
+ * attributes are equal
+ */
+ bool isNull1,
+ isNull2;
+ char *attr1,
+ *attr2;
+ char *val1,
+ *val2;
+
+ attr1 = heap_getattr(slot->val, InvalidBuffer,
+ uniqueAttrNum, tupDesc, &isNull1);
+ attr2 = heap_getattr(resultTupleSlot->val, InvalidBuffer,
+ uniqueAttrNum, tupDesc, &isNull2);
+
+ if (isNull1 == isNull2)
+ {
+ if (isNull1) /* both are null, they are equal */
+ continue;
+ val1 = fmgr(typoutput, attr1, gettypelem(tupDesc->attrs[uniqueAttrNum - 1]->atttypid));
+ val2 = fmgr(typoutput, attr2, gettypelem(tupDesc->attrs[uniqueAttrNum - 1]->atttypid));
+
+ /*
+ * now, val1 and val2 are ascii representations so we can
+ * use strcmp for comparison
+ */
+ if (strcmp(val1, val2) == 0) /* they are equal */
+ continue;
+ else
+ break;
+ }
+ else
+/* one is null and the other isn't, they aren't equal */
+ break;
+
+ }
+ else
+ {
+ if (!ExecIdenticalTuples(slot, resultTupleSlot))
+ break;
+ }
+
+ }
+
/* ----------------
- * now test if the new tuple and the previous
- * tuple match. If so then we loop back and fetch
- * another new tuple from the subplan.
+ * we have a new tuple different from the previous saved tuple
+ * so we save it in the saved tuple slot. We copy the tuple
+ * so we don't increment the buffer ref count.
* ----------------
*/
+ ExecStoreTuple(heap_copytuple(slot->val),
+ resultTupleSlot,
+ InvalidBuffer,
+ true);
- if (uniqueAttr) {
- /* to check equality, we check to see if the typoutput
- of the attributes are equal */
- bool isNull1,isNull2;
- char *attr1, *attr2;
- char *val1, *val2;
-
- attr1 = heap_getattr(slot->val, InvalidBuffer,
- uniqueAttrNum, tupDesc,&isNull1);
- attr2 = heap_getattr(resultTupleSlot->val, InvalidBuffer,
- uniqueAttrNum, tupDesc,&isNull2);
-
- if (isNull1 == isNull2) {
- if (isNull1) /* both are null, they are equal */
- continue;
- val1 = fmgr(typoutput, attr1, gettypelem(tupDesc->attrs[uniqueAttrNum-1]->atttypid));
- val2 = fmgr(typoutput, attr2, gettypelem(tupDesc->attrs[uniqueAttrNum-1]->atttypid));
- /* now, val1 and val2 are ascii representations so we can
- use strcmp for comparison */
- if (strcmp(val1,val2) == 0) /* they are equal */
- continue;
- else
- break;
- }
- else /* one is null and the other isn't, they aren't equal */
- break;
-
- }
- else {
- if (! ExecIdenticalTuples(slot, resultTupleSlot))
- break;
- }
-
- }
-
- /* ----------------
- * we have a new tuple different from the previous saved tuple
- * so we save it in the saved tuple slot. We copy the tuple
- * so we don't increment the buffer ref count.
- * ----------------
- */
- ExecStoreTuple(heap_copytuple(slot->val),
- resultTupleSlot,
- InvalidBuffer,
- true);
-
- return resultTupleSlot;
+ return resultTupleSlot;
}
/* ----------------------------------------------------------------
- * ExecInitUnique
+ * ExecInitUnique
*
- * This initializes the unique node state structures and
- * the node's subplan.
+ * This initializes the unique node state structures and
+ * the node's subplan.
* ----------------------------------------------------------------
*/
-bool /* return: initialization status */
-ExecInitUnique(Unique *node, EState *estate, Plan *parent)
+bool /* return: initialization status */
+ExecInitUnique(Unique * node, EState * estate, Plan * parent)
{
- UniqueState *uniquestate;
- Plan *outerPlan;
- char *uniqueAttr;
-
- /* ----------------
- * assign execution state to node
- * ----------------
- */
- node->plan.state = estate;
-
- /* ----------------
- * create new UniqueState for node
- * ----------------
- */
- uniquestate = makeNode(UniqueState);
- node->uniquestate = uniquestate;
- uniqueAttr = node->uniqueAttr;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- *
- * Unique nodes have no ExprContext initialization because
- * they never call ExecQual or ExecTargetList.
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, uniquestate, parent);
-
+ UniqueState *uniquestate;
+ Plan *outerPlan;
+ char *uniqueAttr;
+
+ /* ----------------
+ * assign execution state to node
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ /* ----------------
+ * create new UniqueState for node
+ * ----------------
+ */
+ uniquestate = makeNode(UniqueState);
+ node->uniquestate = uniquestate;
+ uniqueAttr = node->uniqueAttr;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ *
+ * Unique nodes have no ExprContext initialization because
+ * they never call ExecQual or ExecTargetList.
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, uniquestate, parent);
+
#define UNIQUE_NSLOTS 1
- /* ------------
- * Tuple table initialization
- * ------------
- */
- ExecInitResultTupleSlot(estate, uniquestate);
-
- /* ----------------
- * then initialize outer plan
- * ----------------
- */
- outerPlan = outerPlan((Plan *) node);
- ExecInitNode(outerPlan, estate, (Plan *) node);
-
- /* ----------------
- * unique nodes do no projections, so initialize
- * projection info for this node appropriately
- * ----------------
- */
- ExecAssignResultTypeFromOuterPlan((Plan *)node,uniquestate);
- uniquestate->cs_ProjInfo = NULL;
-
- if (uniqueAttr) {
- TupleDesc tupDesc;
- int i = 0;
-
- tupDesc = ExecGetResultType(uniquestate);
- /* the parser should have ensured that uniqueAttr is a legal attribute name*/
- while ( strcmp((tupDesc->attrs[i]->attname).data, uniqueAttr) != 0)
- i++;
- node->uniqueAttrNum = i+1; /* attribute numbers start from 1 */
- }
- else
- node->uniqueAttrNum = InvalidAttrNumber;
-
- /* ----------------
- * all done.
- * ----------------
- */
- return TRUE;
+ /* ------------
+ * Tuple table initialization
+ * ------------
+ */
+ ExecInitResultTupleSlot(estate, uniquestate);
+
+ /* ----------------
+ * then initialize outer plan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * unique nodes do no projections, so initialize
+ * projection info for this node appropriately
+ * ----------------
+ */
+ ExecAssignResultTypeFromOuterPlan((Plan *) node, uniquestate);
+ uniquestate->cs_ProjInfo = NULL;
+
+ if (uniqueAttr)
+ {
+ TupleDesc tupDesc;
+ int i = 0;
+
+ tupDesc = ExecGetResultType(uniquestate);
+
+ /*
+ * the parser should have ensured that uniqueAttr is a legal
+ * attribute name
+ */
+ while (strcmp((tupDesc->attrs[i]->attname).data, uniqueAttr) != 0)
+ i++;
+ node->uniqueAttrNum = i + 1; /* attribute numbers start from 1 */
+ }
+ else
+ node->uniqueAttrNum = InvalidAttrNumber;
+
+ /* ----------------
+ * all done.
+ * ----------------
+ */
+ return TRUE;
}
int
-ExecCountSlotsUnique(Unique *node)
+ExecCountSlotsUnique(Unique * node)
{
- return ExecCountSlotsNode(outerPlan(node)) +
+ return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
- UNIQUE_NSLOTS;
+ UNIQUE_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecEndUnique
+ * ExecEndUnique
*
- * This shuts down the subplan and frees resources allocated
- * to this node.
+ * This shuts down the subplan and frees resources allocated
+ * to this node.
* ----------------------------------------------------------------
*/
void
-ExecEndUnique(Unique *node)
+ExecEndUnique(Unique * node)
{
- UniqueState *uniquestate;
-
- uniquestate = node->uniquestate;
- ExecEndNode(outerPlan((Plan *) node), (Plan*)node);
- ExecClearTuple(uniquestate->cs_ResultTupleSlot);
-}
+ UniqueState *uniquestate;
+
+ uniquestate = node->uniquestate;
+ ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
+ ExecClearTuple(uniquestate->cs_ResultTupleSlot);
+}