mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
1. Use qsort for first run
2. Limit number of tuples in leftist trees: - put one tuple from current tree to disk if limit reached; - end run creation if limit reached by nextrun. 3. Avoid mergeruns() if first run is single one!
This commit is contained in:
parent
303f6514bd
commit
712ea2507e
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.8 1997/09/12 04:08:46 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.9 1997/09/18 05:37:30 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -26,15 +26,6 @@
|
|||||||
#include "utils/psort.h"
|
#include "utils/psort.h"
|
||||||
#include "utils/lselect.h"
|
#include "utils/lselect.h"
|
||||||
|
|
||||||
#define PUTTUP(TUP, FP) fwrite((char *)TUP, (TUP)->t_len, 1, FP)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* USEMEM - record use of memory
|
|
||||||
* FREEMEM - record freeing of memory
|
|
||||||
*/
|
|
||||||
#define USEMEM(context,AMT) context->sortMem -= (AMT)
|
|
||||||
#define FREEMEM(context,AMT) context->sortMem += (AMT)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* lmerge - merges two leftist trees into one
|
* lmerge - merges two leftist trees into one
|
||||||
*
|
*
|
||||||
@ -149,8 +140,7 @@ gettuple(struct leftist ** treep,
|
|||||||
else
|
else
|
||||||
*treep = lmerge(tp->lt_left, tp->lt_right, context);
|
*treep = lmerge(tp->lt_left, tp->lt_right, context);
|
||||||
|
|
||||||
FREEMEM(context, sizeof(struct leftist));
|
pfree (tp);
|
||||||
FREE(tp);
|
|
||||||
return (tup);
|
return (tup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +163,6 @@ puttuple(struct leftist ** treep,
|
|||||||
register struct leftist *tp;
|
register struct leftist *tp;
|
||||||
|
|
||||||
new1 = (struct leftist *) palloc((unsigned) sizeof(struct leftist));
|
new1 = (struct leftist *) palloc((unsigned) sizeof(struct leftist));
|
||||||
USEMEM(context, sizeof(struct leftist));
|
|
||||||
new1->lt_dist = 1;
|
new1->lt_dist = 1;
|
||||||
new1->lt_devnum = devnum;
|
new1->lt_devnum = devnum;
|
||||||
new1->lt_tuple = newtuple;
|
new1->lt_tuple = newtuple;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.22 1997/09/15 14:28:42 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.23 1997/09/18 05:37:31 vadim Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Sorts the first relation into the second relation.
|
* Sorts the first relation into the second relation.
|
||||||
@ -64,15 +64,17 @@
|
|||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
|
|
||||||
static bool createrun(Sort *node, FILE *file, bool *empty);
|
static bool createfirstrun(Sort * node);
|
||||||
static void destroytape(FILE *file);
|
static bool createrun(Sort * node, FILE * file);
|
||||||
static void dumptuples(FILE *file, Sort *node);
|
static void destroytape(FILE * file);
|
||||||
|
static void dumptuples(FILE * file, Sort * node);
|
||||||
static FILE *gettape(void);
|
static FILE *gettape(void);
|
||||||
static void initialrun(Sort *node, bool *empty);
|
static void initialrun(Sort * node);
|
||||||
static void inittapes(Sort *node);
|
static void inittapes(Sort * node);
|
||||||
static void merge(Sort *node, struct tape * dest);
|
static void merge(Sort * node, struct tape * dest);
|
||||||
static FILE *mergeruns(Sort *node);
|
static FILE *mergeruns(Sort * node);
|
||||||
static HeapTuple tuplecopy(HeapTuple tup);
|
static HeapTuple tuplecopy(HeapTuple tup);
|
||||||
|
static int _psort_cmp (HeapTuple *ltup, HeapTuple *rtup);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -80,6 +82,10 @@ static HeapTuple tuplecopy(HeapTuple tup);
|
|||||||
|
|
||||||
static long shortzero = 0; /* used to delimit runs */
|
static long shortzero = 0; /* used to delimit runs */
|
||||||
|
|
||||||
|
static TupleDesc PsortTupDesc;
|
||||||
|
static ScanKey PsortKeys; /* used by _psort_cmp */
|
||||||
|
static int PsortNkeys;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* old psort global variables
|
* old psort global variables
|
||||||
*
|
*
|
||||||
@ -123,9 +129,8 @@ static long shortzero = 0; /* used to delimit runs */
|
|||||||
* Allocates and initializes sort node's psort state.
|
* Allocates and initializes sort node's psort state.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
psort_begin(Sort *node, int nkeys, ScanKey key)
|
psort_begin(Sort * node, int nkeys, ScanKey key)
|
||||||
{
|
{
|
||||||
bool empty; /* to answer: is child node empty? */
|
|
||||||
|
|
||||||
node->psortstate = (struct Psortstate *) palloc(sizeof(struct Psortstate));
|
node->psortstate = (struct Psortstate *) palloc(sizeof(struct Psortstate));
|
||||||
|
|
||||||
@ -142,17 +147,20 @@ psort_begin(Sort *node, int nkeys, ScanKey key)
|
|||||||
PS(node)->treeContext.sortMem = SortMem * 1024;
|
PS(node)->treeContext.sortMem = SortMem * 1024;
|
||||||
|
|
||||||
PS(node)->Tuples = NULL;
|
PS(node)->Tuples = NULL;
|
||||||
|
PS(node)->lasttuple = NULL;
|
||||||
|
PS(node)->lt_tupcount = 0;
|
||||||
PS(node)->tupcount = 0;
|
PS(node)->tupcount = 0;
|
||||||
|
|
||||||
PS(node)->using_tape_files = false;
|
PS(node)->using_tape_files = false;
|
||||||
|
PS(node)->psort_grab_file = NULL;
|
||||||
PS(node)->memtuples = NULL;
|
PS(node)->memtuples = NULL;
|
||||||
|
|
||||||
initialrun(node, &empty);
|
initialrun(node);
|
||||||
|
|
||||||
if (empty)
|
if (PS(node)->tupcount == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (PS(node)->using_tape_files)
|
if (PS(node)->using_tape_files && PS(node)->psort_grab_file == NULL)
|
||||||
PS(node)->psort_grab_file = mergeruns(node);
|
PS(node)->psort_grab_file = mergeruns(node);
|
||||||
|
|
||||||
PS(node)->psort_current = 0;
|
PS(node)->psort_current = 0;
|
||||||
@ -168,7 +176,7 @@ psort_begin(Sort *node, int nkeys, ScanKey key)
|
|||||||
* number of allocated tapes
|
* number of allocated tapes
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
inittapes(Sort *node)
|
inittapes(Sort * node)
|
||||||
{
|
{
|
||||||
register int i;
|
register int i;
|
||||||
register struct tape *tp;
|
register struct tape *tp;
|
||||||
@ -266,7 +274,7 @@ inittapes(Sort *node)
|
|||||||
* Also, perhaps allocate tapes when needed. Split into 2 funcs.
|
* Also, perhaps allocate tapes when needed. Split into 2 funcs.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
initialrun(Sort *node, bool *empty)
|
initialrun(Sort * node)
|
||||||
{
|
{
|
||||||
/* register struct tuple *tup; */
|
/* register struct tuple *tup; */
|
||||||
register struct tape *tp;
|
register struct tape *tp;
|
||||||
@ -278,20 +286,27 @@ initialrun(Sort *node, bool *empty)
|
|||||||
|
|
||||||
tp = PS(node)->Tape;
|
tp = PS(node)->Tape;
|
||||||
|
|
||||||
if ((bool) createrun(node, NULL, empty) != false)
|
if (createfirstrun(node))
|
||||||
{
|
{
|
||||||
if (!PS(node)->using_tape_files)
|
Assert (PS(node)->using_tape_files);
|
||||||
inittapes(node);
|
|
||||||
extrapasses = 0;
|
extrapasses = 0;
|
||||||
}
|
}
|
||||||
else
|
else /* all tuples fetched */
|
||||||
{
|
{
|
||||||
/* if empty or rows fit in memory, we never access tape stuff */
|
if ( !PS(node)->using_tape_files ) /* empty or sorted in memory */
|
||||||
if (*empty || !PS(node)->using_tape_files)
|
|
||||||
return;
|
return;
|
||||||
if (!PS(node)->using_tape_files)
|
/*
|
||||||
inittapes(node);
|
* if PS(node)->Tuples == NULL then we have single (sorted) run
|
||||||
extrapasses = 1 + (PS(node)->Tuples != NULL); /* (T != N) ? 2 : 1 */
|
* which can be used as result grab file! So, we may avoid
|
||||||
|
* mergeruns - it will just copy this run to new file.
|
||||||
|
*/
|
||||||
|
if ( PS(node)->Tuples == NULL )
|
||||||
|
{
|
||||||
|
PS(node)->psort_grab_file = PS(node)->Tape->tp_file;
|
||||||
|
rewind (PS(node)->psort_grab_file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extrapasses = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -328,7 +343,7 @@ initialrun(Sort *node, bool *empty)
|
|||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ((bool) createrun(node, tp->tp_file, empty) == false)
|
if ((bool) createrun(node, tp->tp_file) == false)
|
||||||
extrapasses = 1 + (PS(node)->Tuples != NULL);
|
extrapasses = 1 + (PS(node)->Tuples != NULL);
|
||||||
/* D2 */
|
/* D2 */
|
||||||
}
|
}
|
||||||
@ -336,6 +351,138 @@ initialrun(Sort *node, bool *empty)
|
|||||||
rewind(tp->tp_file); /* D. */
|
rewind(tp->tp_file); /* D. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* createfirstrun - tries to sort tuples in memory using qsort
|
||||||
|
* until LACKMEM; if not enough memory then switches
|
||||||
|
* to tape method
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* FALSE iff process through end of relation
|
||||||
|
* Tuples contains the tuples for the following run upon exit
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
createfirstrun(Sort *node)
|
||||||
|
{
|
||||||
|
HeapTuple tup;
|
||||||
|
bool foundeor = false;
|
||||||
|
HeapTuple *memtuples;
|
||||||
|
int t_last = -1;
|
||||||
|
int t_free = 1000;
|
||||||
|
TupleTableSlot *cr_slot;
|
||||||
|
|
||||||
|
Assert(node != (Sort *) NULL);
|
||||||
|
Assert(PS(node) != (Psortstate *) NULL);
|
||||||
|
Assert(!PS(node)->using_tape_files);
|
||||||
|
Assert(PS(node)->memtuples == NULL);
|
||||||
|
Assert(PS(node)->tupcount == 0);
|
||||||
|
if (LACKMEM(node))
|
||||||
|
elog (FATAL, "psort: LACKMEM in createfirstrun");
|
||||||
|
|
||||||
|
memtuples = palloc(t_free * sizeof(HeapTuple));
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if ( LACKMEM (node) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* About to call ExecProcNode, it can mess up the state if it
|
||||||
|
* eventually calls another Sort node. So must stow it away here
|
||||||
|
* for the meantime. -Rex
|
||||||
|
* 2.2.1995
|
||||||
|
*/
|
||||||
|
|
||||||
|
cr_slot = ExecProcNode(outerPlan((Plan *) node), (Plan *) node);
|
||||||
|
|
||||||
|
if (TupIsNull(cr_slot))
|
||||||
|
{
|
||||||
|
foundeor = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tup = tuplecopy(cr_slot->val);
|
||||||
|
ExecClearTuple(cr_slot);
|
||||||
|
|
||||||
|
IncrProcessed();
|
||||||
|
USEMEM(node, tup->t_len);
|
||||||
|
TRACEMEM(createfirstrun);
|
||||||
|
if ( t_free <= 0 )
|
||||||
|
{
|
||||||
|
t_free = 1000;
|
||||||
|
memtuples = repalloc (memtuples,
|
||||||
|
(t_last + t_free + 1) * sizeof (HeapTuple));
|
||||||
|
}
|
||||||
|
t_last++;
|
||||||
|
t_free--;
|
||||||
|
memtuples[t_last] = tup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( t_last < 0 ) /* empty */
|
||||||
|
{
|
||||||
|
Assert (foundeor);
|
||||||
|
pfree (memtuples);
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
t_last++;
|
||||||
|
PS(node)->tupcount = t_last;
|
||||||
|
PsortTupDesc = PS(node)->treeContext.tupDesc;
|
||||||
|
PsortKeys = PS(node)->treeContext.scanKeys;
|
||||||
|
PsortNkeys = PS(node)->treeContext.nKeys;
|
||||||
|
qsort (memtuples, t_last, sizeof (HeapTuple),
|
||||||
|
(int (*)(const void *,const void *))_psort_cmp);
|
||||||
|
|
||||||
|
if ( LACKMEM (node) ) /* in-memory sort is impossible */
|
||||||
|
{
|
||||||
|
register int t;
|
||||||
|
register int f;
|
||||||
|
FILE *file;
|
||||||
|
|
||||||
|
Assert (!foundeor);
|
||||||
|
inittapes(node);
|
||||||
|
file = PS(node)->Tape->tp_file;
|
||||||
|
|
||||||
|
/* put extra tuples into tape file */
|
||||||
|
if ( t_last > SortTuplesInTree )
|
||||||
|
{
|
||||||
|
register HeapTuple lasttuple;
|
||||||
|
|
||||||
|
t = t_last - SortTuplesInTree;
|
||||||
|
for (f = 0, lasttuple = NULL; f < t; f++)
|
||||||
|
{
|
||||||
|
if ( lasttuple )
|
||||||
|
{
|
||||||
|
FREEMEM(node, lasttuple->t_len);
|
||||||
|
FREE(lasttuple);
|
||||||
|
TRACEMEM(createfirstrun);
|
||||||
|
}
|
||||||
|
lasttuple = memtuples[f];
|
||||||
|
PUTTUP(node, lasttuple, file);
|
||||||
|
TRACEOUT(createfirstrun, lasttuple);
|
||||||
|
}
|
||||||
|
PS(node)->lasttuple = lasttuple;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PS(node)->lasttuple = NULL;
|
||||||
|
f = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* put rest of tuples into leftist tree for createrun */
|
||||||
|
for (t = t_last - 1 ; t >= f; t--)
|
||||||
|
puttuple(&PS(node)->Tuples, memtuples[t], 0, &PS(node)->treeContext);
|
||||||
|
PS(node)->lt_tupcount = t_last - f;
|
||||||
|
pfree (memtuples);
|
||||||
|
foundeor = !createrun (node, file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert (foundeor);
|
||||||
|
PS(node)->memtuples = memtuples;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!foundeor);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* createrun - places the next run on file, grabbing the tuples by
|
* createrun - places the next run on file, grabbing the tuples by
|
||||||
* executing the subplan passed in
|
* executing the subplan passed in
|
||||||
@ -348,13 +495,15 @@ initialrun(Sort *node, bool *empty)
|
|||||||
* Tuples contains the tuples for the following run upon exit
|
* Tuples contains the tuples for the following run upon exit
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
createrun(Sort *node, FILE *file, bool *empty)
|
createrun(Sort * node, FILE * file)
|
||||||
{
|
{
|
||||||
register HeapTuple lasttuple;
|
register HeapTuple lasttuple;
|
||||||
register HeapTuple tup;
|
register HeapTuple tup;
|
||||||
struct leftist *nextrun;
|
struct leftist *nextrun;
|
||||||
bool foundeor;
|
bool foundeor;
|
||||||
short junk;
|
short junk;
|
||||||
|
int curr_tupcount = (PS(node)->Tuples != NULL) ? PS(node)->lt_tupcount : 0;
|
||||||
|
int next_tupcount = 0;
|
||||||
|
|
||||||
int cr_tuples = 0; /* Count tuples grabbed from plannode */
|
int cr_tuples = 0; /* Count tuples grabbed from plannode */
|
||||||
TupleTableSlot *cr_slot;
|
TupleTableSlot *cr_slot;
|
||||||
@ -362,33 +511,36 @@ createrun(Sort *node, FILE *file, bool *empty)
|
|||||||
Assert(node != (Sort *) NULL);
|
Assert(node != (Sort *) NULL);
|
||||||
Assert(PS(node) != (Psortstate *) NULL);
|
Assert(PS(node) != (Psortstate *) NULL);
|
||||||
|
|
||||||
lasttuple = NULL;
|
lasttuple = PS(node)->lasttuple; /* !NULL if called from createfirstrun */
|
||||||
nextrun = NULL;
|
nextrun = NULL;
|
||||||
foundeor = false;
|
foundeor = false;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
while (LACKMEM(node) && PS(node)->Tuples != NULL)
|
if ((LACKMEM(node) && PS(node)->Tuples != NULL) || curr_tupcount > SortTuplesInTree)
|
||||||
{
|
{
|
||||||
if (lasttuple != NULL)
|
do
|
||||||
{
|
{
|
||||||
FREEMEM(node, lasttuple->t_len);
|
if (lasttuple != NULL)
|
||||||
FREE(lasttuple);
|
{
|
||||||
TRACEMEM(createrun);
|
FREEMEM(node, lasttuple->t_len);
|
||||||
}
|
FREE(lasttuple);
|
||||||
lasttuple = tup = gettuple(&PS(node)->Tuples, &junk,
|
TRACEMEM(createrun);
|
||||||
&PS(node)->treeContext);
|
}
|
||||||
if (!PS(node)->using_tape_files)
|
lasttuple = tup = gettuple(&PS(node)->Tuples, &junk,
|
||||||
{
|
&PS(node)->treeContext);
|
||||||
inittapes(node);
|
Assert (PS(node)->using_tape_files);
|
||||||
if (!file)
|
PUTTUP(node, tup, file);
|
||||||
file = PS(node)->Tape->tp_file; /* was NULL */
|
TRACEOUT(createrun, tup);
|
||||||
}
|
curr_tupcount--;
|
||||||
PUTTUP(node, tup, file);
|
} while (LACKMEM(node) && PS(node)->Tuples != NULL);
|
||||||
TRACEOUT(createrun, tup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LACKMEM(node))
|
if (LACKMEM(node))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if ( next_tupcount >= SortTuplesInTree )
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* About to call ExecProcNode, it can mess up the state if it
|
* About to call ExecProcNode, it can mess up the state if it
|
||||||
* eventually calls another Sort node. So must stow it away here
|
* eventually calls another Sort node. So must stow it away here
|
||||||
@ -416,9 +568,15 @@ createrun(Sort *node, FILE *file, bool *empty)
|
|||||||
TRACEMEM(createrun);
|
TRACEMEM(createrun);
|
||||||
if (lasttuple != NULL && tuplecmp(tup, lasttuple,
|
if (lasttuple != NULL && tuplecmp(tup, lasttuple,
|
||||||
&PS(node)->treeContext))
|
&PS(node)->treeContext))
|
||||||
|
{
|
||||||
puttuple(&nextrun, tup, 0, &PS(node)->treeContext);
|
puttuple(&nextrun, tup, 0, &PS(node)->treeContext);
|
||||||
|
next_tupcount++;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
puttuple(&PS(node)->Tuples, tup, 0, &PS(node)->treeContext);
|
puttuple(&PS(node)->Tuples, tup, 0, &PS(node)->treeContext);
|
||||||
|
curr_tupcount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (lasttuple != NULL)
|
if (lasttuple != NULL)
|
||||||
{
|
{
|
||||||
@ -427,15 +585,13 @@ createrun(Sort *node, FILE *file, bool *empty)
|
|||||||
TRACEMEM(createrun);
|
TRACEMEM(createrun);
|
||||||
}
|
}
|
||||||
dumptuples(file, node);
|
dumptuples(file, node);
|
||||||
if (PS(node)->using_tape_files)
|
ENDRUN(file);
|
||||||
ENDRUN(file);
|
|
||||||
/* delimit the end of the run */
|
/* delimit the end of the run */
|
||||||
PS(node)->Tuples = nextrun;
|
PS(node)->Tuples = nextrun;
|
||||||
|
PS(node)->lt_tupcount = next_tupcount;
|
||||||
|
PS(node)->lasttuple = NULL;
|
||||||
|
|
||||||
/* if we did not see any tuples, mark empty */
|
return ((bool) ! foundeor); /* XXX - works iff bool is {0,1} */
|
||||||
*empty = (cr_tuples > 0) ? false : true;
|
|
||||||
|
|
||||||
return ((bool) !foundeor); /* XXX - works iff bool is {0,1} */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -466,7 +622,7 @@ tuplecopy(HeapTuple tup)
|
|||||||
* file of tuples in order
|
* file of tuples in order
|
||||||
*/
|
*/
|
||||||
static FILE *
|
static FILE *
|
||||||
mergeruns(Sort *node)
|
mergeruns(Sort * node)
|
||||||
{
|
{
|
||||||
register struct tape *tp;
|
register struct tape *tp;
|
||||||
|
|
||||||
@ -493,7 +649,7 @@ mergeruns(Sort *node)
|
|||||||
* (polyphase merge Alg.D(D5)--Knuth, Vol.3, p271)
|
* (polyphase merge Alg.D(D5)--Knuth, Vol.3, p271)
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
merge(Sort *node, struct tape * dest)
|
merge(Sort * node, struct tape * dest)
|
||||||
{
|
{
|
||||||
register HeapTuple tup;
|
register HeapTuple tup;
|
||||||
register struct tape *lasttp; /* (TAPE[P]) */
|
register struct tape *lasttp; /* (TAPE[P]) */
|
||||||
@ -600,20 +756,15 @@ merge(Sort *node, struct tape * dest)
|
|||||||
* dumptuples - stores all the tuples in tree into file
|
* dumptuples - stores all the tuples in tree into file
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
dumptuples(FILE *file, Sort *node)
|
dumptuples(FILE * file, Sort * node)
|
||||||
{
|
{
|
||||||
register struct leftist *tp;
|
register struct leftist *tp;
|
||||||
register struct leftist *newp;
|
register struct leftist *newp;
|
||||||
struct leftist **treep = &PS(node)->Tuples;
|
struct leftist **treep = &PS(node)->Tuples;
|
||||||
LeftistContext context = &PS(node)->treeContext;
|
LeftistContext context = &PS(node)->treeContext;
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
int memtupindex = 0;
|
|
||||||
|
|
||||||
if (!PS(node)->using_tape_files && PS(node)->tupcount)
|
Assert (PS(node)->using_tape_files);
|
||||||
{
|
|
||||||
Assert(PS(node)->memtuples == NULL);
|
|
||||||
PS(node)->memtuples = palloc(PS(node)->tupcount * sizeof(HeapTuple));
|
|
||||||
}
|
|
||||||
|
|
||||||
tp = *treep;
|
tp = *treep;
|
||||||
while (tp != NULL)
|
while (tp != NULL)
|
||||||
@ -625,14 +776,9 @@ dumptuples(FILE *file, Sort *node)
|
|||||||
newp = lmerge(tp->lt_left, tp->lt_right, context);
|
newp = lmerge(tp->lt_left, tp->lt_right, context);
|
||||||
FREEMEM(node, sizeof(struct leftist));
|
FREEMEM(node, sizeof(struct leftist));
|
||||||
FREE(tp);
|
FREE(tp);
|
||||||
if (PS(node)->using_tape_files)
|
PUTTUP(node, tup, file);
|
||||||
{
|
FREEMEM(node, tup->t_len);
|
||||||
PUTTUP(node, tup, file);
|
FREE(tup);
|
||||||
FREEMEM(node, tup->t_len);
|
|
||||||
FREE(tup);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
PS(node)->memtuples[memtupindex++] = tup;
|
|
||||||
|
|
||||||
tp = newp;
|
tp = newp;
|
||||||
}
|
}
|
||||||
@ -646,7 +792,7 @@ dumptuples(FILE *file, Sort *node)
|
|||||||
* a NULL indicating the last tuple has been processed.
|
* a NULL indicating the last tuple has been processed.
|
||||||
*/
|
*/
|
||||||
HeapTuple
|
HeapTuple
|
||||||
psort_grabtuple(Sort *node, bool *should_free)
|
psort_grabtuple(Sort * node, bool * should_free)
|
||||||
{
|
{
|
||||||
register HeapTuple tup;
|
register HeapTuple tup;
|
||||||
long tuplen;
|
long tuplen;
|
||||||
@ -691,7 +837,7 @@ psort_grabtuple(Sort *node, bool *should_free)
|
|||||||
* psort_markpos - saves current position in the merged sort file
|
* psort_markpos - saves current position in the merged sort file
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
psort_markpos(Sort *node)
|
psort_markpos(Sort * node)
|
||||||
{
|
{
|
||||||
Assert(node != (Sort *) NULL);
|
Assert(node != (Sort *) NULL);
|
||||||
Assert(PS(node) != (Psortstate *) NULL);
|
Assert(PS(node) != (Psortstate *) NULL);
|
||||||
@ -704,7 +850,7 @@ psort_markpos(Sort *node)
|
|||||||
* last saved position
|
* last saved position
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
psort_restorepos(Sort *node)
|
psort_restorepos(Sort * node)
|
||||||
{
|
{
|
||||||
Assert(node != (Sort *) NULL);
|
Assert(node != (Sort *) NULL);
|
||||||
Assert(PS(node) != (Psortstate *) NULL);
|
Assert(PS(node) != (Psortstate *) NULL);
|
||||||
@ -719,13 +865,14 @@ psort_restorepos(Sort *node)
|
|||||||
* called unless psort_grabtuple has returned a NULL.
|
* called unless psort_grabtuple has returned a NULL.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
psort_end(Sort *node)
|
psort_end(Sort * node)
|
||||||
{
|
{
|
||||||
register struct tape *tp;
|
register struct tape *tp;
|
||||||
|
|
||||||
if (!node->cleaned)
|
if (!node->cleaned)
|
||||||
{
|
{
|
||||||
Assert(node != (Sort *) NULL);
|
Assert(node != (Sort *) NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I'm changing this because if we are sorting a relation with no
|
* I'm changing this because if we are sorting a relation with no
|
||||||
* tuples, psortstate is NULL.
|
* tuples, psortstate is NULL.
|
||||||
@ -818,7 +965,7 @@ gettape()
|
|||||||
*/
|
*/
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
static void
|
static void
|
||||||
resettape(FILE *file)
|
resettape(FILE * file)
|
||||||
{
|
{
|
||||||
register struct tapelst *tp;
|
register struct tapelst *tp;
|
||||||
register int fd;
|
register int fd;
|
||||||
@ -850,7 +997,7 @@ resettape(FILE *file)
|
|||||||
* Exits instead of returning status, if given invalid tape.
|
* Exits instead of returning status, if given invalid tape.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
destroytape(FILE *file)
|
destroytape(FILE * file)
|
||||||
{
|
{
|
||||||
register struct tapelst *tp,
|
register struct tapelst *tp,
|
||||||
*tq;
|
*tq;
|
||||||
@ -885,3 +1032,42 @@ destroytape(FILE *file)
|
|||||||
tp = tp->tl_next;
|
tp = tp->tl_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_psort_cmp (HeapTuple *ltup, HeapTuple *rtup)
|
||||||
|
{
|
||||||
|
register Datum lattr, rattr;
|
||||||
|
int nkey = 0;
|
||||||
|
int result = 0;
|
||||||
|
bool isnull1, isnull2;
|
||||||
|
|
||||||
|
while ( nkey < PsortNkeys && !result )
|
||||||
|
{
|
||||||
|
lattr = heap_getattr(*ltup, InvalidBuffer,
|
||||||
|
PsortKeys[nkey].sk_attno,
|
||||||
|
PsortTupDesc,
|
||||||
|
&isnull1);
|
||||||
|
rattr = heap_getattr(*rtup, InvalidBuffer,
|
||||||
|
PsortKeys[nkey].sk_attno,
|
||||||
|
PsortTupDesc,
|
||||||
|
&isnull2);
|
||||||
|
if ( isnull1 )
|
||||||
|
{
|
||||||
|
if ( isnull2 )
|
||||||
|
return (0);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
else if ( isnull2 )
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
if (PsortKeys[nkey].sk_flags & SK_COMMUTE)
|
||||||
|
{
|
||||||
|
if (!(result = -(long) (*PsortKeys[nkey].sk_func) (rattr, lattr)))
|
||||||
|
result = (long) (*PsortKeys[nkey].sk_func) (lattr, rattr);
|
||||||
|
}
|
||||||
|
else if (!(result = -(long) (*PsortKeys[nkey].sk_func) (lattr, rattr)))
|
||||||
|
result = (long) (*PsortKeys[nkey].sk_func) (rattr, lattr);
|
||||||
|
nkey++;
|
||||||
|
}
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user