aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeSort.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/nodeSort.c')
-rw-r--r--src/backend/executor/nodeSort.c523
1 files changed, 523 insertions, 0 deletions
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
new file mode 100644
index 00000000000..9a7f4f9456f
--- /dev/null
+++ b/src/backend/executor/nodeSort.c
@@ -0,0 +1,523 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeSort.c--
+ * Routines to handle sorting of relations into temporaries.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.1.1.1 1996/07/09 06:21:27 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "executor/executor.h"
+#include "executor/nodeSort.h"
+#include "utils/palloc.h"
+#include "utils/psort.h"
+#include "catalog/catalog.h"
+#include "storage/bufmgr.h"
+#include "optimizer/internal.h" /* for _TEMP_RELATION_ID_ */
+
+/* ----------------------------------------------------------------
+ * FormSortKeys(node)
+ *
+ * Forms the structure containing information used to sort the relation.
+ *
+ * Returns an array of ScanKeyData.
+ * ----------------------------------------------------------------
+ */
+static ScanKey
+FormSortKeys(Sort *sortnode)
+{
+ ScanKey sortkeys;
+ List *targetList;
+ List *tl;
+ int keycount;
+ Resdom *resdom;
+ AttrNumber resno;
+ Index reskey;
+ Oid reskeyop;
+
+ /* ----------------
+ * get information from the node
+ * ----------------
+ */
+ targetList = sortnode->plan.targetlist;
+ keycount = sortnode->keycount;
+
+ /* ----------------
+ * first allocate space for scan keys
+ * ----------------
+ */
+ if (keycount <= 0)
+ elog(WARN, "FormSortKeys: keycount <= 0");
+ sortkeys = (ScanKey) palloc(keycount * sizeof(ScanKeyData));
+
+ /* ----------------
+ * form each scan key from the resdom info in the target list
+ * ----------------
+ */
+ foreach(tl, targetList) {
+ TargetEntry *target = (TargetEntry *)lfirst(tl);
+ resdom = target->resdom;
+ resno = resdom->resno;
+ reskey = resdom->reskey;
+ reskeyop = resdom->reskeyop;
+
+ if (reskey > 0) {
+ ScanKeyEntryInitialize(&sortkeys[reskey-1],
+ 0,
+ resno,
+ (RegProcedure) DatumGetInt32(reskeyop),
+ (Datum) 0);
+ }
+ }
+
+ return sortkeys;
+}
+
+/* ----------------------------------------------------------------
+ * ExecSort
+ *
+ * old comments
+ * Retrieves tuples fron the outer subtree and insert them into a
+ * temporary relation. The temporary relation is then sorted and
+ * the sorted relation is stored in the relation whose ID is indicated
+ * in the 'tempid' field of this node.
+ * Assumes that heap access method is used.
+ *
+ * Conditions:
+ * -- none.
+ *
+ * Initial States:
+ * -- the outer child is prepared to return the first tuple.
+ * ----------------------------------------------------------------
+ */
+TupleTableSlot *
+ExecSort(Sort *node)
+{
+ EState *estate;
+ SortState *sortstate;
+ Plan *outerNode;
+ ScanDirection dir;
+ int keycount;
+ ScanKey sortkeys;
+ Relation tempRelation;
+ Relation currentRelation;
+ HeapScanDesc currentScanDesc;
+ HeapTuple heapTuple;
+ TupleTableSlot *slot;
+ Buffer buffer;
+ int tupCount = 0;
+
+ /* ----------------
+ * get state info from node
+ * ----------------
+ */
+ SO1_printf("ExecSort: %s\n",
+ "entering routine");
+
+ sortstate = node->sortstate;
+ estate = node->plan.state;
+ dir = estate->es_direction;
+
+ /* ----------------
+ * the first time we call this, we retrieve all tuples
+ * from the subplan into a temporary relation and then
+ * we sort the relation. Subsequent calls return tuples
+ * from the temporary relation.
+ * ----------------
+ */
+
+ if (sortstate->sort_Flag == false) {
+ SO1_printf("ExecSort: %s\n",
+ "sortstate == false -> sorting subplan");
+ /* ----------------
+ * set all relations to be scanned in the forward direction
+ * while creating the temporary relation.
+ * ----------------
+ */
+ estate->es_direction = EXEC_FRWD;
+
+ /* ----------------
+ * if we couldn't create the temp or current relations then
+ * we print a warning and return NULL.
+ * ----------------
+ */
+ tempRelation = sortstate->sort_TempRelation;
+ if (tempRelation == NULL) {
+ elog(DEBUG, "ExecSort: temp relation is NULL! aborting...");
+ return NULL;
+ }
+
+ currentRelation = sortstate->csstate.css_currentRelation;
+ if (currentRelation == NULL) {
+ elog(DEBUG, "ExecSort: current relation is NULL! aborting...");
+ return NULL;
+ }
+
+ /* ----------------
+ * retrieve tuples from the subplan and
+ * insert them in the temporary relation
+ * ----------------
+ */
+ outerNode = outerPlan((Plan *) node);
+ SO1_printf("ExecSort: %s\n",
+ "inserting tuples into tempRelation");
+
+ for (;;) {
+ slot = ExecProcNode(outerNode, (Plan*)node);
+
+ if (TupIsNull(slot))
+ break;
+
+ tupCount++;
+
+ heapTuple = slot->val;
+
+ heap_insert(tempRelation, /* relation desc */
+ heapTuple); /* heap tuple to insert */
+
+ ExecClearTuple(slot);
+ }
+
+ /* ----------------
+ * now sort the tuples in our temporary relation
+ * into a new sorted relation using psort()
+ *
+ * psort() seems to require that the relations
+ * are created and opened in advance.
+ * -cim 1/25/90
+ * ----------------
+ */
+ keycount = node->keycount;
+ sortkeys = (ScanKey)sortstate->sort_Keys;
+ SO1_printf("ExecSort: %s\n",
+ "calling psort");
+
+ /*
+ * If no tuples were fetched from the proc node return NULL now
+ * psort dumps it if 0 tuples are in the relation and I don't want
+ * to try to debug *that* routine!!
+ */
+ if (tupCount == 0)
+ return NULL;
+
+ psort(tempRelation, /* old relation */
+ currentRelation, /* new relation */
+ keycount, /* number keys */
+ sortkeys); /* keys */
+
+ if (currentRelation == NULL) {
+ elog(DEBUG, "ExecSort: sorted relation is NULL! aborting...");
+ return NULL;
+ }
+
+ /* ----------------
+ * restore to user specified direction
+ * ----------------
+ */
+ estate->es_direction = dir;
+
+ /* ----------------
+ * now initialize the scan descriptor to scan the
+ * sorted relation and update the sortstate information
+ * ----------------
+ */
+ currentScanDesc = heap_beginscan(currentRelation, /* relation */
+ ScanDirectionIsBackward(dir),
+ /* bkwd flag */
+ NowTimeQual, /* time qual */
+ 0, /* num scan keys */
+ NULL); /* scan keys */
+
+ sortstate->csstate.css_currentRelation = currentRelation;
+ sortstate->csstate.css_currentScanDesc = currentScanDesc;
+
+ /* ----------------
+ * make sure the tuple descriptor is up to date
+ * ----------------
+ */
+ slot = sortstate->csstate.css_ScanTupleSlot;
+
+ slot->ttc_tupleDescriptor =
+ RelationGetTupleDescriptor(currentRelation);
+
+ /* ----------------
+ * finally set the sorted flag to true
+ * ----------------
+ */
+ sortstate->sort_Flag = true;
+ }
+ else {
+ slot = sortstate->csstate.css_ScanTupleSlot;
+ }
+
+ SO1_printf("ExecSort: %s\n",
+ "retrieveing tuple from sorted relation");
+
+ /* ----------------
+ * at this point we know we have a sorted relation so
+ * we preform a simple scan on it with amgetnext()..
+ * ----------------
+ */
+ currentScanDesc = sortstate->csstate.css_currentScanDesc;
+
+ heapTuple = heap_getnext(currentScanDesc, /* scan desc */
+ ScanDirectionIsBackward(dir),
+ /* bkwd flag */
+ &buffer); /* return: buffer */
+
+ /* Increase the pin count on the buffer page, because the tuple stored in
+ the slot also points to it (as well as the scan descriptor). If we
+ don't, ExecStoreTuple will decrease the pin count on the next iteration.
+ - 01/09/93 */
+
+ if (buffer != InvalidBuffer)
+ IncrBufferRefCount(buffer);
+
+ return ExecStoreTuple(heapTuple, /* tuple to store */
+ slot, /* slot to store in */
+ buffer, /* this tuple's buffer */
+ false); /* don't free stuff from amgetnext */
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitSort
+ *
+ * old comments
+ * Creates the run-time state information for the sort node
+ * produced by the planner and initailizes its outer subtree.
+ * ----------------------------------------------------------------
+ */
+bool
+ExecInitSort(Sort *node, EState *estate, Plan *parent)
+{
+ SortState *sortstate;
+ Plan *outerPlan;
+ ScanKey sortkeys;
+ TupleDesc tupType;
+ Oid tempOid;
+ Oid sortOid;
+ Relation tempDesc;
+ Relation sortedDesc;
+
+ SO1_printf("ExecInitSort: %s\n",
+ "initializing sort node");
+
+ /* ----------------
+ * assign the node's execution state
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ /* ----------------
+ * create state structure
+ * ----------------
+ */
+ sortstate = makeNode(SortState);
+ sortstate->sort_Flag = 0;
+ sortstate->sort_Keys = NULL;
+ sortstate->sort_TempRelation = NULL;
+
+ node->sortstate = sortstate;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks
+ *
+ * Sort nodes don't initialize their ExprContexts because
+ * they never call ExecQual or ExecTargetList.
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &sortstate->csstate.cstate, parent);
+
+#define SORT_NSLOTS 1
+ /* ----------------
+ * tuple table initialization
+ *
+ * sort nodes only return scan tuples from their sorted
+ * relation.
+ * ----------------
+ */
+ ExecInitScanTupleSlot(estate, &sortstate->csstate);
+ ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
+
+ /* ----------------
+ * initializes child nodes
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * initialize sortstate information
+ * ----------------
+ */
+ sortkeys = FormSortKeys(node);
+ sortstate->sort_Keys = sortkeys;
+ sortstate->sort_Flag = false;
+
+ /* ----------------
+ * initialize tuple type. no need to initialize projection
+ * info because this node doesn't do projections.
+ * ----------------
+ */
+ ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
+ sortstate->csstate.cstate.cs_ProjInfo = NULL;
+
+ /* ----------------
+ * get type information needed for ExecCreatR
+ * ----------------
+ */
+ tupType = ExecGetScanType(&sortstate->csstate);
+
+ /* ----------------
+ * ExecCreatR wants its second argument to be an object id of
+ * a relation in the range table or _TEMP_RELATION_ID_
+ * indicating that the relation is not in the range table.
+ *
+ * In the second case ExecCreatR creates a temp relation.
+ * (currently this is the only case we support -cim 10/16/89)
+ * ----------------
+ */
+ tempOid = node->tempid;
+ sortOid = _TEMP_RELATION_ID_;
+
+ /* ----------------
+ * create the temporary relations
+ * ----------------
+ */
+/* len = ExecTargetListLength(node->plan.targetlist); */
+ tempDesc = ExecCreatR(tupType, tempOid);
+ sortedDesc = ExecCreatR(tupType, sortOid);
+
+ /* ----------------
+ * save the relation descriptor in the sortstate
+ * ----------------
+ */
+ sortstate->sort_TempRelation = tempDesc;
+ sortstate->csstate.css_currentRelation = sortedDesc;
+ SO1_printf("ExecInitSort: %s\n",
+ "sort node initialized");
+
+ /* ----------------
+ * return relation oid of temporary sort relation in a list
+ * (someday -- for now we return LispTrue... cim 10/12/89)
+ * ----------------
+ */
+ return TRUE;
+}
+
+int
+ExecCountSlotsSort(Sort *node)
+{
+ return ExecCountSlotsNode(outerPlan((Plan *)node)) +
+ ExecCountSlotsNode(innerPlan((Plan *)node)) +
+ SORT_NSLOTS;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndSort(node)
+ *
+ * old comments
+ * destroys the temporary relation.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndSort(Sort *node)
+{
+ SortState *sortstate;
+ Relation tempRelation;
+ Relation sortedRelation;
+ Plan *outerPlan;
+
+ /* ----------------
+ * get info from the sort state
+ * ----------------
+ */
+ SO1_printf("ExecEndSort: %s\n",
+ "shutting down sort node");
+
+ sortstate = node->sortstate;
+ tempRelation = sortstate->sort_TempRelation;
+ sortedRelation = sortstate->csstate.css_currentRelation;
+
+ heap_destroyr(tempRelation);
+ heap_destroyr(sortedRelation);
+
+
+ /* ----------------
+ * close the sorted relation and shut down the scan.
+ * ----------------
+ */
+ ExecCloseR((Plan *) node);
+
+ /* ----------------
+ * shut down the subplan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecEndNode(outerPlan, (Plan*)node);
+
+ /* ----------------
+ * clean out the tuple table
+ * ----------------
+ */
+ ExecClearTuple(sortstate->csstate.css_ScanTupleSlot);
+
+ SO1_printf("ExecEndSort: %s\n",
+ "sort node shutdown");
+}
+
+/* ----------------------------------------------------------------
+ * ExecSortMarkPos
+ * ----------------------------------------------------------------
+ */
+void
+ExecSortMarkPos(Sort *node)
+{
+ SortState *sortstate;
+ HeapScanDesc sdesc;
+
+ /* ----------------
+ * if we haven't sorted yet, just return
+ * ----------------
+ */
+ sortstate = node->sortstate;
+ if (sortstate->sort_Flag == false)
+ return;
+
+ sdesc = sortstate->csstate.css_currentScanDesc;
+ heap_markpos(sdesc);
+ return;
+}
+
+/* ----------------------------------------------------------------
+ * ExecSortRestrPos
+ * ----------------------------------------------------------------
+ */
+void
+ExecSortRestrPos(Sort *node)
+{
+ SortState *sortstate;
+ HeapScanDesc sdesc;
+
+ /* ----------------
+ * if we haven't sorted yet, just return.
+ * ----------------
+ */
+ sortstate = node->sortstate;
+ if (sortstate->sort_Flag == false)
+ return;
+
+ /* ----------------
+ * restore the scan to the previously marked position
+ * ----------------
+ */
+ sdesc = sortstate->csstate.css_currentScanDesc;
+ heap_restrpos(sdesc);
+}