home *** CD-ROM | disk | FTP | other *** search
- /* ----------------------------------------------------------------
- * FILE
- * unique.c
- *
- * DESCRIPTION
- * Routines to handle unique'ing of queries where appropriate
- *
- * INTERFACE ROUTINES
- * 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.
- *
- * IDENTIFICATION
- * $Header: /private/postgres/src/executor/RCS/n_unique.c,v 1.6 1992/08/21 08:02:07 mer Exp $
- * ----------------------------------------------------------------
- */
-
- #include "executor/executor.h"
- #include "planner/clauses.h"
-
- RcsId("$Header: /private/postgres/src/executor/RCS/n_unique.c,v 1.6 1992/08/21 08:02:07 mer Exp $");
-
-
- /* ----------------------------------------------------------------
- * 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
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecUnique
- ****/
- bool /* true if tuples are identical, false otherwise */
- ExecIdenticalTuples(t1, t2)
- List t1;
- List t2;
- {
- HeapTuple h1;
- HeapTuple h2;
- char *d1;
- char *d2;
- int len;
-
- h1 = (HeapTuple) ExecFetchTuple((Pointer) t1);
- h2 = (HeapTuple) ExecFetchTuple((Pointer) t2);
-
- /* ----------------
- * 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 (bcmp(d1, d2, len) != 0)
- return false;
-
- return true;
- }
-
- /* ----------------------------------------------------------------
- * ExecUnique
- *
- * 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.
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecProcNode
- ****/
- TupleTableSlot /* return: a tuple or NULL */
- ExecUnique(node)
- Unique node;
- {
- UniqueState uniquestate;
- TupleTableSlot resultTupleSlot;
- TupleTableSlot slot;
- Plan outerPlan;
- bool shouldFree;
-
- /* ----------------
- * get information from the node
- * ----------------
- */
- uniquestate = get_uniquestate(node);
- outerPlan = get_outerPlan((Plan) node);
- resultTupleSlot = get_cs_ResultTupleSlot((CommonState) uniquestate);
-
- /* ----------------
- * now loop, returning only non-duplicate tuples.
- * We assume that the tuples arrive in sorted order
- * so we can detect duplicates easily.
- * ----------------
- */
- for (;;) {
- /* ----------------
- * fetch a tuple from the outer subplan
- * ----------------
- */
- slot = ExecProcNode(outerPlan);
- if (TupIsNull((Pointer) 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((Pointer) 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 (! ExecIdenticalTuples((List) slot, (List) 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((Pointer)heap_copysimple(ExecFetchTuple((Pointer) slot)),
- (Pointer) resultTupleSlot,
- ExecSlotBuffer((Pointer) slot),
- true);
-
- return
- slot;
- }
-
- /* ----------------------------------------------------------------
- * ExecInitUnique
- *
- * This initializes the unique node state structures and
- * the node's subplan.
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecInitNode
- ****/
- List /* return: initialization status */
- ExecInitUnique(node, estate, parent)
- Unique node;
- EState estate;
- Plan parent;
- {
- UniqueState uniquestate;
- Plan outerPlan;
-
- /* ----------------
- * assign execution state to node
- * ----------------
- */
- set_state((Plan) node, (EStatePtr)estate);
-
- /* ----------------
- * create new UniqueState for node
- * ----------------
- */
- uniquestate = MakeUniqueState(0);
- set_uniquestate(node, uniquestate);
-
- /* ----------------
- * 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, (BaseNode) uniquestate, parent);
- ExecAssignDebugHooks((Plan) node, (BaseNode) uniquestate);
-
- #define UNIQUE_NSLOTS 1
- /* ------------
- * Tuple table initialization
- * ------------
- */
- ExecInitResultTupleSlot(estate, (CommonState) uniquestate);
-
- /* ----------------
- * then initialize outer plan
- * ----------------
- */
- outerPlan = get_outerPlan((Plan) node);
- ExecInitNode(outerPlan, estate, (Plan) node);
-
- /* ----------------
- * unique nodes do no projections, so initialize
- * projection info for this node appropriately
- * ----------------
- */
- ExecAssignResultTypeFromOuterPlan((Plan) node, (CommonState) uniquestate);
- set_cs_ProjInfo((CommonState) uniquestate, NULL);
-
- /* ----------------
- * all done.
- * ----------------
- */
- return
- LispTrue;
- }
-
- int
- ExecCountSlotsUnique(node)
- Plan node;
- {
- return ExecCountSlotsNode(get_outerPlan(node)) +
- ExecCountSlotsNode(get_innerPlan(node)) +
- UNIQUE_NSLOTS;
- }
-
- /* ----------------------------------------------------------------
- * ExecEndUnique
- *
- * This shuts down the subplan and frees resources allocated
- * to this node.
- * ----------------------------------------------------------------
- */
- /**** xxref:
- * ExecEndNode
- ****/
- void
- ExecEndUnique(node)
- Unique node;
- {
- UniqueState uniquestate;
-
- uniquestate = get_uniquestate(node);
- ExecEndNode((Plan) get_outerPlan((Plan) node));
- ExecClearTuple((Pointer)
- get_cs_ResultTupleSlot((CommonState) uniquestate));
- }
-