postgresql/src/backend/executor/nodeSort.c

365 lines
8.5 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* nodeSort.c
* Routines to handle sorting of relations.
*
2002-06-20 22:29:54 +02:00
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.43 2003/05/05 17:57:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
1999-07-16 07:00:38 +02:00
#include "postgres.h"
1996-11-08 07:02:30 +01:00
#include "executor/execdebug.h"
#include "executor/nodeSort.h"
#include "utils/tuplesort.h"
/* ----------------------------------------------------------------
* ExtractSortKeys
*
* Extract the sorting key information from the plan node.
*
* Returns two palloc'd arrays, one of sort operator OIDs and
* one of attribute numbers.
* ----------------------------------------------------------------
*/
static void
ExtractSortKeys(Sort *sortnode,
Oid **sortOperators,
AttrNumber **attNums)
{
List *targetList;
int keycount;
Oid *sortOps;
AttrNumber *attNos;
List *tl;
/*
* get information from the node
*/
targetList = sortnode->plan.targetlist;
keycount = sortnode->keycount;
/*
* first allocate space for results
*/
if (keycount <= 0)
elog(ERROR, "ExtractSortKeys: keycount <= 0");
sortOps = (Oid *) palloc0(keycount * sizeof(Oid));
*sortOperators = sortOps;
attNos = (AttrNumber *) palloc0(keycount * sizeof(AttrNumber));
*attNums = attNos;
/*
* extract info from the resdom nodes in the target list
*/
foreach(tl, targetList)
{
TargetEntry *target = (TargetEntry *) lfirst(tl);
Resdom *resdom = target->resdom;
Index reskey = resdom->reskey;
if (reskey > 0) /* ignore TLEs that are not sort keys */
{
Assert(reskey <= keycount);
sortOps[reskey - 1] = resdom->reskeyop;
attNos[reskey - 1] = resdom->resno;
}
}
}
/* ----------------------------------------------------------------
* ExecSort
*
* Sorts tuples from the outer subtree of the node using tuplesort,
* which saves the results in a temporary file or memory. After the
* initial call, returns a tuple from the file with each call.
*
* Conditions:
* -- none.
*
* Initial States:
* -- the outer child is prepared to return the first tuple.
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecSort(SortState *node)
{
EState *estate;
ScanDirection dir;
Tuplesortstate *tuplesortstate;
HeapTuple heapTuple;
TupleTableSlot *slot;
bool should_free;
/*
* get state info from node
*/
SO1_printf("ExecSort: %s\n",
"entering routine");
estate = node->ss.ps.state;
dir = estate->es_direction;
tuplesortstate = (Tuplesortstate *) node->tuplesortstate;
/*
* If first time through, read all tuples from outer plan and pass
* them to tuplesort.c. Subsequent calls just fetch tuples from
* tuplesort.
*/
if (!node->sort_Done)
{
Sort *plannode = (Sort *) node->ss.ps.plan;
PlanState *outerNode;
TupleDesc tupDesc;
Oid *sortOperators;
AttrNumber *attNums;
SO1_printf("ExecSort: %s\n",
"sorting subplan");
/*
* Want to scan subplan in the forward direction while creating
* the sorted data.
*/
estate->es_direction = ForwardScanDirection;
/*
* Initialize tuplesort module.
*/
SO1_printf("ExecSort: %s\n",
"calling tuplesort_begin");
outerNode = outerPlanState(node);
tupDesc = ExecGetResultType(outerNode);
ExtractSortKeys(plannode, &sortOperators, &attNums);
tuplesortstate = tuplesort_begin_heap(tupDesc, plannode->keycount,
sortOperators, attNums,
true /* randomAccess */ );
node->tuplesortstate = (void *) tuplesortstate;
pfree(sortOperators);
pfree(attNums);
/*
* Scan the subplan and feed all the tuples to tuplesort.
*/
for (;;)
{
slot = ExecProcNode(outerNode);
if (TupIsNull(slot))
break;
tuplesort_puttuple(tuplesortstate, (void *) slot->val);
}
/*
* Complete the sort.
*/
tuplesort_performsort(tuplesortstate);
/*
* restore to user specified direction
*/
estate->es_direction = dir;
/*
* finally set the sorted flag to true
*/
node->sort_Done = true;
SO1_printf("ExecSort: %s\n", "sorting done");
}
SO1_printf("ExecSort: %s\n",
"retrieving tuple from tuplesort");
/*
* Get the first or next tuple from tuplesort. Returns NULL if no more
* tuples.
*/
heapTuple = tuplesort_getheaptuple(tuplesortstate,
ScanDirectionIsForward(dir),
&should_free);
slot = node->ss.ps.ps_ResultTupleSlot;
1998-09-01 05:29:17 +02:00
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
}
/* ----------------------------------------------------------------
* ExecInitSort
*
* Creates the run-time state information for the sort node
* produced by the planner and initailizes its outer subtree.
* ----------------------------------------------------------------
*/
SortState *
ExecInitSort(Sort *node, EState *estate)
{
SortState *sortstate;
SO1_printf("ExecInitSort: %s\n",
"initializing sort node");
/*
* create state structure
*/
sortstate = makeNode(SortState);
sortstate->ss.ps.plan = (Plan *) node;
sortstate->ss.ps.state = estate;
sortstate->sort_Done = false;
sortstate->tuplesortstate = NULL;
/*
* Miscellaneous initialization
*
* Sort nodes don't initialize their ExprContexts because they never call
* ExecQual or ExecProject.
*/
#define SORT_NSLOTS 2
/*
* tuple table initialization
*
* sort nodes only return scan tuples from their sorted relation.
*/
ExecInitResultTupleSlot(estate, &sortstate->ss.ps);
ExecInitScanTupleSlot(estate, &sortstate->ss);
/*
* initializes child nodes
*/
outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate);
/*
* initialize tuple type. no need to initialize projection info
* because this node doesn't do projections.
*/
ExecAssignResultTypeFromOuterPlan(&sortstate->ss.ps);
ExecAssignScanTypeFromOuterPlan(&sortstate->ss);
sortstate->ss.ps.ps_ProjInfo = NULL;
SO1_printf("ExecInitSort: %s\n",
"sort node initialized");
return sortstate;
}
int
ExecCountSlotsSort(Sort *node)
{
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
ExecCountSlotsNode(innerPlan((Plan *) node)) +
SORT_NSLOTS;
}
/* ----------------------------------------------------------------
* ExecEndSort(node)
* ----------------------------------------------------------------
*/
void
ExecEndSort(SortState *node)
{
SO1_printf("ExecEndSort: %s\n",
"shutting down sort node");
/*
* clean out the tuple table
*/
ExecClearTuple(node->ss.ss_ScanTupleSlot);
/*
* Release tuplesort resources
*/
if (node->tuplesortstate != NULL)
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL;
/*
* shut down the subplan
*/
ExecEndNode(outerPlanState(node));
SO1_printf("ExecEndSort: %s\n",
"sort node shutdown");
}
/* ----------------------------------------------------------------
* ExecSortMarkPos
*
* Calls tuplesort to save the current position in the sorted file.
* ----------------------------------------------------------------
*/
void
ExecSortMarkPos(SortState *node)
{
/*
* if we haven't sorted yet, just return
*/
if (!node->sort_Done)
return;
tuplesort_markpos((Tuplesortstate *) node->tuplesortstate);
}
/* ----------------------------------------------------------------
* ExecSortRestrPos
*
* Calls tuplesort to restore the last saved sort file position.
* ----------------------------------------------------------------
*/
void
ExecSortRestrPos(SortState *node)
{
/*
* if we haven't sorted yet, just return.
*/
if (!node->sort_Done)
return;
/*
* restore the scan to the previously marked position
*/
tuplesort_restorepos((Tuplesortstate *) node->tuplesortstate);
}
1998-02-23 07:28:16 +01:00
void
ExecReScanSort(SortState *node, ExprContext *exprCtxt)
1998-02-23 07:28:16 +01:00
{
/*
* If we haven't sorted yet, just return. If outerplan' chgParam is
* not NULL then it will be re-scanned by ExecProcNode, else - no
* reason to re-scan it at all.
1998-02-23 07:28:16 +01:00
*/
if (!node->sort_Done)
1998-02-23 07:28:16 +01:00
return;
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
1998-02-23 07:28:16 +01:00
/*
* If subnode is to be rescanned then we forget previous sort results;
* we have to re-read the subplan and re-sort.
*
* Otherwise we can just rewind and rescan the sorted output.
1998-02-23 07:28:16 +01:00
*/
if (((PlanState *) node)->lefttree->chgParam != NULL)
{
node->sort_Done = false;
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL;
}
else
tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);
1998-02-23 07:28:16 +01:00
}