
each tuple, as per my proposal of several days ago. Also, clean up sort memory management by keeping all working data in a separate memory context, and refine the handling of low-memory conditions.
315 lines
7.4 KiB
C
315 lines
7.4 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* nodeSort.c
|
|
* Routines to handle sorting of relations.
|
|
*
|
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.53 2006/02/26 22:58:12 tgl Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "executor/execdebug.h"
|
|
#include "executor/nodeSort.h"
|
|
#include "miscadmin.h"
|
|
#include "utils/tuplesort.h"
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
* 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;
|
|
|
|
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);
|
|
|
|
tuplesortstate = tuplesort_begin_heap(tupDesc,
|
|
plannode->numCols,
|
|
plannode->sortOperators,
|
|
plannode->sortColIdx,
|
|
work_mem,
|
|
true /* randomAccess */ );
|
|
node->tuplesortstate = (void *) tuplesortstate;
|
|
|
|
/*
|
|
* Scan the subplan and feed all the tuples to tuplesort.
|
|
*/
|
|
|
|
for (;;)
|
|
{
|
|
slot = ExecProcNode(outerNode);
|
|
|
|
if (TupIsNull(slot))
|
|
break;
|
|
|
|
tuplesort_puttuple(tuplesortstate,
|
|
(void *) ExecFetchSlotTuple(slot));
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
if (heapTuple)
|
|
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
|
|
else
|
|
return ExecClearTuple(slot);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------
|
|
* 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.
|
|
*/
|
|
ExecAssignResultTypeFromTL(&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);
|
|
/* must drop pointer to sort result tuple */
|
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
void
|
|
ExecReScanSort(SortState *node, ExprContext *exprCtxt)
|
|
{
|
|
/*
|
|
* 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.
|
|
*/
|
|
if (!node->sort_Done)
|
|
return;
|
|
|
|
/* must drop pointer to sort result tuple */
|
|
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
if (((PlanState *) node)->lefttree->chgParam != NULL)
|
|
{
|
|
node->sort_Done = false;
|
|
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
|
|
node->tuplesortstate = NULL;
|
|
}
|
|
else
|
|
tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);
|
|
}
|