diff options
Diffstat (limited to 'src/backend/utils/sort/lselect.c')
-rw-r--r-- | src/backend/utils/sort/lselect.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/src/backend/utils/sort/lselect.c b/src/backend/utils/sort/lselect.c new file mode 100644 index 00000000000..1f92e48d838 --- /dev/null +++ b/src/backend/utils/sort/lselect.c @@ -0,0 +1,365 @@ +/*------------------------------------------------------------------------- + * + * lselect.c-- + * leftist tree selection algorithm (linked priority queue--Knuth, Vol.3, + * pp.150-52) + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.1.1.1 1996/07/09 06:22:10 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include <string.h> +#include <stdio.h> + +#include "c.h" + +#include "storage/buf.h" +#include "access/skey.h" +#include "access/heapam.h" +#include "access/htup.h" +#include "utils/rel.h" + +#include "utils/psort.h" +#include "utils/lselect.h" + +extern Relation SortRdesc; /* later static */ + +/* + * PUTTUP - writes the next tuple + * ENDRUN - mark end of run + * GETLEN - reads the length of the next tuple + * ALLOCTUP - returns space for the new tuple + * SETTUPLEN - stores the length into the tuple + * GETTUP - reads the tuple + * + * Note: + * LEN field must be a short; FP is a stream + */ + +#define PUTTUP(TUP, FP) fwrite((char *)TUP, (TUP)->t_len, 1, FP) +#define ENDRUN(FP) fwrite((char *)&shortzero, sizeof (shortzero), 1, FP) +#define GETLEN(LEN, FP) fread(&(LEN), sizeof (shortzero), 1, FP) +#define ALLOCTUP(LEN) ((HeapTuple)malloc((unsigned)LEN)) +#define GETTUP(TUP, LEN, FP)\ + fread((char *)(TUP) + sizeof (shortzero), 1, (LEN) - sizeof (shortzero), FP) +#define SETTUPLEN(TUP, LEN) (TUP)->t_len = LEN + +/* + * USEMEM - record use of memory + * FREEMEM - record freeing of memory + * FULLMEM - 1 iff a tuple will fit + */ + +#define USEMEM(AMT) SortMemory -= (AMT) +#define FREEMEM(AMT) SortMemory += (AMT) +#define LACKMEM() (SortMemory <= BLCKSZ) /* not accurate */ + +/* + * lmerge - merges two leftist trees into one + * + * Note: + * Enforcing the rule that pt->lt_dist >= qt->lt_dist may + * simplifify much of the code. Removing recursion will not + * speed up code significantly. + */ +struct leftist * +lmerge(struct leftist *pt, struct leftist *qt) +{ + register struct leftist *root, *majorLeftist, *minorLeftist; + int dist; + + if (tuplecmp(pt->lt_tuple, qt->lt_tuple)) { + root = pt; + majorLeftist = qt; + } else { + root = qt; + majorLeftist = pt; + } + if (root->lt_left == NULL) + root->lt_left = majorLeftist; + else { + if ((minorLeftist = root->lt_right) != NULL) + majorLeftist = lmerge(majorLeftist, minorLeftist); + if ((dist = root->lt_left->lt_dist) < majorLeftist->lt_dist) { + root->lt_dist = 1 + dist; + root->lt_right = root->lt_left; + root->lt_left = majorLeftist; + } else { + root->lt_dist = 1 + majorLeftist->lt_dist; + root->lt_right = majorLeftist; + } + } + return(root); +} + +static struct leftist * +linsert(struct leftist *root, struct leftist *new1) +{ + register struct leftist *left, *right; + + if (! tuplecmp(root->lt_tuple, new1->lt_tuple)) { + new1->lt_left = root; + return(new1); + } + left = root->lt_left; + right = root->lt_right; + if (right == NULL) { + if (left == NULL) + root->lt_left = new1; + else { + root->lt_right = new1; + root->lt_dist = 2; + } + return(root); + } + right = linsert(right, new1); + if (right->lt_dist < left->lt_dist) { + root->lt_dist = 1 + left->lt_dist; + root->lt_left = right; + root->lt_right = left; + } else { + root->lt_dist = 1 + right->lt_dist; + root->lt_right = right; + } + return(root); +} + +/* + * gettuple - returns tuple at top of tree (Tuples) + * + * Returns: + * tuple at top of tree, NULL if failed ALLOC() + * *devnum is set to the devnum of tuple returned + * *treep is set to the new tree + * + * Note: + * *treep must not be NULL + * NULL is currently never returned BUG + */ +HeapTuple +gettuple(struct leftist **treep, + short *devnum) /* device from which tuple came */ +{ + register struct leftist *tp; + HeapTuple tup; + + tp = *treep; + tup = tp->lt_tuple; + *devnum = tp->lt_devnum; + if (tp->lt_dist == 1) /* lt_left == NULL */ + *treep = tp->lt_left; + else + *treep = lmerge(tp->lt_left, tp->lt_right); + + FREEMEM(sizeof (struct leftist)); + FREE(tp); + return(tup); +} + +/* + * puttuple - inserts new tuple into tree + * + * Returns: + * NULL iff failed ALLOC() + * + * Note: + * Currently never returns NULL BUG + */ +int +puttuple(struct leftist **treep, HeapTuple newtuple, int devnum) +{ + register struct leftist *new1; + register struct leftist *tp; + + new1 = (struct leftist *) malloc((unsigned) sizeof (struct leftist)); + USEMEM(sizeof (struct leftist)); + new1->lt_dist = 1; + new1->lt_devnum = devnum; + new1->lt_tuple = newtuple; + new1->lt_left = NULL; + new1->lt_right = NULL; + if ((tp = *treep) == NULL) + *treep = new1; + else + *treep = linsert(tp, new1); + return(1); +} + + +/* + * dumptuples - stores all the tuples in tree into file + */ +void +dumptuples(FILE *file) +{ + register struct leftist *tp; + register struct leftist *newp; + HeapTuple tup; + + tp = Tuples; + while (tp != NULL) { + tup = tp->lt_tuple; + if (tp->lt_dist == 1) /* lt_right == NULL */ + newp = tp->lt_left; + else + newp = lmerge(tp->lt_left, tp->lt_right); + FREEMEM(sizeof (struct leftist)); + FREE(tp); + PUTTUP(tup, file); + FREEMEM(tup->t_len); + FREE(tup); + tp = newp; + } + Tuples = NULL; +} + +/* + * tuplecmp - Compares two tuples with respect CmpList + * + * Returns: + * 1 if left < right ;0 otherwise + * Assumtions: + */ +int +tuplecmp(HeapTuple ltup, HeapTuple rtup) +{ + register char *lattr, *rattr; + int nkey = 0; + extern int Nkeys; + extern ScanKey Key; + int result = 0; + bool isnull; + + if (ltup == (HeapTuple)NULL) + return(0); + if (rtup == (HeapTuple)NULL) + return(1); + while (nkey < Nkeys && !result) { + lattr = heap_getattr(ltup, InvalidBuffer, + Key[nkey].sk_attno, + RelationGetTupleDescriptor(SortRdesc), + &isnull); + if (isnull) + return(0); + rattr = heap_getattr(rtup, InvalidBuffer, + Key[nkey].sk_attno, + RelationGetTupleDescriptor(SortRdesc), + &isnull); + if (isnull) + return(1); + if (Key[nkey].sk_flags & SK_COMMUTE) { + if (!(result = (long) (*Key[nkey].sk_func) (rattr, lattr))) + result = -(long) (*Key[nkey].sk_func) (lattr, rattr); + } else if (!(result = (long) (*Key[nkey].sk_func) (lattr, rattr))) + result = -(long) (*Key[nkey].sk_func) (rattr, lattr); + nkey++; + } + return (result == 1); +} + +#ifdef EBUG +void +checktree(struct leftist *tree) +{ + int lnodes; + int rnodes; + + if (tree == NULL) { + puts("Null tree."); + return; + } + lnodes = checktreer(tree->lt_left, 1); + rnodes = checktreer(tree->lt_right, 1); + if (lnodes < 0) { + lnodes = -lnodes; + puts("0:\tBad left side."); + } + if (rnodes < 0) { + rnodes = -rnodes; + puts("0:\tBad right side."); + } + if (lnodes == 0) { + if (rnodes != 0) + puts("0:\tLeft and right reversed."); + if (tree->lt_dist != 1) + puts("0:\tDistance incorrect."); + } else if (rnodes == 0) { + if (tree->lt_dist != 1) + puts("0:\tDistance incorrect."); + } else if (tree->lt_left->lt_dist < tree->lt_right->lt_dist) { + puts("0:\tLeft and right reversed."); + if (tree->lt_dist != 1 + tree->lt_left->lt_dist) + puts("0:\tDistance incorrect."); + } else if (tree->lt_dist != 1+ tree->lt_right->lt_dist) + puts("0:\tDistance incorrect."); + if (lnodes > 0) + if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple)) + printf("%d:\tLeft child < parent.\n"); + if (rnodes > 0) + if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple)) + printf("%d:\tRight child < parent.\n"); + printf("Tree has %d nodes\n", 1 + lnodes + rnodes); +} + +int +checktreer(struct leftist *tree, int level) +{ + int lnodes, rnodes; + int error = 0; + + if (tree == NULL) + return(0); + lnodes = checktreer(tree->lt_left, level + 1); + rnodes = checktreer(tree->lt_right, level + 1); + if (lnodes < 0) { + error = 1; + lnodes = -lnodes; + printf("%d:\tBad left side.\n", level); + } + if (rnodes < 0) { + error = 1; + rnodes = -rnodes; + printf("%d:\tBad right side.\n", level); + } + if (lnodes == 0) { + if (rnodes != 0) { + error = 1; + printf("%d:\tLeft and right reversed.\n", level); + } + if (tree->lt_dist != 1) { + error = 1; + printf("%d:\tDistance incorrect.\n", level); + } + } else if (rnodes == 0) { + if (tree->lt_dist != 1) { + error = 1; + printf("%d:\tDistance incorrect.\n", level); + } + } else if (tree->lt_left->lt_dist < tree->lt_right->lt_dist) { + error = 1; + printf("%d:\tLeft and right reversed.\n", level); + if (tree->lt_dist != 1 + tree->lt_left->lt_dist) + printf("%d:\tDistance incorrect.\n", level); + } else if (tree->lt_dist != 1+ tree->lt_right->lt_dist) { + error = 1; + printf("%d:\tDistance incorrect.\n", level); + } + if (lnodes > 0) + if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple)) { + error = 1; + printf("%d:\tLeft child < parent.\n"); + } + if (rnodes > 0) + if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple)) { + error = 1; + printf("%d:\tRight child < parent.\n"); + } + if (error) + return(-1 + -lnodes + -rnodes); + return(1 + lnodes + rnodes); +} +#endif |