mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-11 19:20:40 +08:00
Fix for backward cursors with ORDER BY.
This commit is contained in:
parent
9acf938c10
commit
78351f422b
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.25 1997/09/26 20:05:47 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.26 1997/10/15 06:36:08 vadim Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Sorts the first relation into the second relation.
|
* Sorts the first relation into the second relation.
|
||||||
@ -80,7 +80,12 @@ static int _psort_cmp (HeapTuple *ltup, HeapTuple *rtup);
|
|||||||
|
|
||||||
#define TEMPDIR "./"
|
#define TEMPDIR "./"
|
||||||
|
|
||||||
static long shortzero = 0; /* used to delimit runs */
|
/*
|
||||||
|
* tlenzero used to delimit runs; both vars below must have
|
||||||
|
* the same size as HeapTuple->t_len
|
||||||
|
*/
|
||||||
|
static unsigned int tlenzero = 0;
|
||||||
|
static unsigned int tlendummy;
|
||||||
|
|
||||||
static TupleDesc PsortTupDesc;
|
static TupleDesc PsortTupDesc;
|
||||||
static ScanKey PsortKeys; /* used by _psort_cmp */
|
static ScanKey PsortKeys; /* used by _psort_cmp */
|
||||||
@ -150,6 +155,7 @@ psort_begin(Sort * node, int nkeys, ScanKey key)
|
|||||||
PS(node)->tupcount = 0;
|
PS(node)->tupcount = 0;
|
||||||
|
|
||||||
PS(node)->using_tape_files = false;
|
PS(node)->using_tape_files = false;
|
||||||
|
PS(node)->all_fetched = false;
|
||||||
PS(node)->psort_grab_file = NULL;
|
PS(node)->psort_grab_file = NULL;
|
||||||
PS(node)->memtuples = NULL;
|
PS(node)->memtuples = NULL;
|
||||||
|
|
||||||
@ -219,21 +225,24 @@ inittapes(Sort * node)
|
|||||||
* GETTUP - reads the tuple
|
* GETTUP - reads the tuple
|
||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
* LEN field must be a short; FP is a stream
|
* LEN field must be as HeapTuple->t_len; FP is a stream
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define PUTTUP(NODE, TUP, FP) do {\
|
#define PUTTUP(NODE, TUP, FP) do {\
|
||||||
((Psortstate *)NODE->psortstate)->BytesWritten += (TUP)->t_len; \
|
((Psortstate *)NODE->psortstate)->BytesWritten += (TUP)->t_len; \
|
||||||
fwrite((char *)TUP, (TUP)->t_len, 1, FP);} while (0)
|
fwrite((char *)TUP, (TUP)->t_len, 1, FP); \
|
||||||
#define ENDRUN(FP) fwrite((char *)&shortzero, sizeof (shortzero), 1, FP)
|
fwrite((char *)&((TUP)->t_len), sizeof (tlendummy), 1, FP); \
|
||||||
#define GETLEN(LEN, FP) fread((char *)&(LEN), sizeof (shortzero), 1, FP)
|
} while (0)
|
||||||
|
#define ENDRUN(FP) fwrite((char *)&tlenzero, sizeof (tlenzero), 1, FP)
|
||||||
|
#define GETLEN(LEN, FP) fread((char *)&(LEN), sizeof (tlenzero), 1, FP)
|
||||||
#define ALLOCTUP(LEN) ((HeapTuple)palloc((unsigned)LEN))
|
#define ALLOCTUP(LEN) ((HeapTuple)palloc((unsigned)LEN))
|
||||||
#define GETTUP(NODE, TUP, LEN, FP) do {\
|
#define GETTUP(NODE, TUP, LEN, FP) do {\
|
||||||
IncrProcessed(); \
|
IncrProcessed(); \
|
||||||
((Psortstate *)NODE->psortstate)->BytesRead += (LEN) - sizeof (shortzero); \
|
((Psortstate *)NODE->psortstate)->BytesRead += (LEN) - sizeof (tlenzero); \
|
||||||
fread((char *)(TUP) + sizeof (shortzero), (LEN) - sizeof (shortzero), 1, FP);} \
|
fread((char *)(TUP) + sizeof (tlenzero), (LEN) - sizeof (tlenzero), 1, FP); \
|
||||||
while (0)
|
fread((char *)&tlendummy, sizeof (tlendummy), 1, FP); \
|
||||||
|
} while (0)
|
||||||
#define SETTUPLEN(TUP, LEN) (TUP)->t_len = LEN
|
#define SETTUPLEN(TUP, LEN) (TUP)->t_len = LEN
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -633,7 +642,7 @@ merge(Sort * node, struct tape * dest)
|
|||||||
int times; /* runs left to merge */
|
int times; /* runs left to merge */
|
||||||
int outdummy; /* complete dummy runs */
|
int outdummy; /* complete dummy runs */
|
||||||
short fromtape;
|
short fromtape;
|
||||||
long tuplen;
|
unsigned int tuplen;
|
||||||
|
|
||||||
Assert(node != (Sort *) NULL);
|
Assert(node != (Sort *) NULL);
|
||||||
Assert(PS(node) != (Psortstate *) NULL);
|
Assert(PS(node) != (Psortstate *) NULL);
|
||||||
@ -768,15 +777,19 @@ HeapTuple
|
|||||||
psort_grabtuple(Sort * node, bool * should_free)
|
psort_grabtuple(Sort * node, bool * should_free)
|
||||||
{
|
{
|
||||||
register HeapTuple tup;
|
register HeapTuple tup;
|
||||||
long tuplen;
|
|
||||||
|
|
||||||
Assert(node != (Sort *) NULL);
|
Assert(node != (Sort *) NULL);
|
||||||
Assert(PS(node) != (Psortstate *) NULL);
|
Assert(PS(node) != (Psortstate *) NULL);
|
||||||
|
|
||||||
if (PS(node)->using_tape_files == true)
|
if (PS(node)->using_tape_files == true)
|
||||||
{
|
{
|
||||||
if (!feof(PS(node)->psort_grab_file))
|
unsigned int tuplen;
|
||||||
|
|
||||||
|
*should_free = true;
|
||||||
|
if (ScanDirectionIsForward (node->plan.state->es_direction))
|
||||||
{
|
{
|
||||||
|
if (PS(node)->all_fetched)
|
||||||
|
return NULL;
|
||||||
if (GETLEN(tuplen, PS(node)->psort_grab_file) && tuplen != 0)
|
if (GETLEN(tuplen, PS(node)->psort_grab_file) && tuplen != 0)
|
||||||
{
|
{
|
||||||
tup = (HeapTuple) palloc((unsigned) tuplen);
|
tup = (HeapTuple) palloc((unsigned) tuplen);
|
||||||
@ -784,26 +797,100 @@ psort_grabtuple(Sort * node, bool * should_free)
|
|||||||
GETTUP(node, tup, tuplen, PS(node)->psort_grab_file);
|
GETTUP(node, tup, tuplen, PS(node)->psort_grab_file);
|
||||||
|
|
||||||
/* Update current merged sort file position */
|
/* Update current merged sort file position */
|
||||||
PS(node)->psort_current += tuplen;
|
PS(node)->psort_current += tuplen + sizeof (tlendummy);
|
||||||
*should_free = true;
|
|
||||||
return tup;
|
return tup;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
PS(node)->all_fetched = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
/* Backward */
|
||||||
|
if (PS(node)->psort_current <= sizeof (tlendummy))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
/*
|
||||||
|
* if all tuples are fetched already then we return last tuple,
|
||||||
|
* else - tuple before last returned.
|
||||||
|
*/
|
||||||
|
if (PS(node)->all_fetched)
|
||||||
|
{
|
||||||
|
/* psort_current is pointing to the zero tuplen at the end of file */
|
||||||
|
fseek(PS(node)->psort_grab_file,
|
||||||
|
PS(node)->psort_current - sizeof (tlendummy), SEEK_SET);
|
||||||
|
GETLEN(tuplen, PS(node)->psort_grab_file);
|
||||||
|
if (PS(node)->psort_current < tuplen)
|
||||||
|
elog (FATAL, "psort_grabtuple: too big last tuple len in backward scan");
|
||||||
|
PS(node)->all_fetched = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (PS(node)->psort_current < PS(node)->tupcount)
|
/* move to position of end tlen of prev tuple */
|
||||||
|
PS(node)->psort_current -= sizeof (tlendummy);
|
||||||
|
fseek(PS(node)->psort_grab_file, PS(node)->psort_current, SEEK_SET);
|
||||||
|
GETLEN(tuplen, PS(node)->psort_grab_file); /* get tlen of prev tuple */
|
||||||
|
if (tuplen == 0)
|
||||||
|
elog (FATAL, "psort_grabtuple: tuplen is 0 in backward scan");
|
||||||
|
if (PS(node)->psort_current <= tuplen + sizeof (tlendummy))
|
||||||
|
{ /* prev tuple should be first one */
|
||||||
|
if (PS(node)->psort_current != tuplen)
|
||||||
|
elog (FATAL, "psort_grabtuple: first tuple expected in backward scan");
|
||||||
|
PS(node)->psort_current = 0;
|
||||||
|
fseek(PS(node)->psort_grab_file, PS(node)->psort_current, SEEK_SET);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Get position of prev tuple. This tuple becomes current tuple
|
||||||
|
* now and we have to return previous one.
|
||||||
|
*/
|
||||||
|
PS(node)->psort_current -= tuplen;
|
||||||
|
/* move to position of end tlen of prev tuple */
|
||||||
|
fseek(PS(node)->psort_grab_file,
|
||||||
|
PS(node)->psort_current - sizeof (tlendummy), SEEK_SET);
|
||||||
|
GETLEN(tuplen, PS(node)->psort_grab_file);
|
||||||
|
if (PS(node)->psort_current < tuplen + sizeof (tlendummy))
|
||||||
|
elog (FATAL, "psort_grabtuple: too big tuple len in backward scan");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* move to prev (or last) tuple start position + sizeof(t_len)
|
||||||
|
*/
|
||||||
|
fseek(PS(node)->psort_grab_file,
|
||||||
|
PS(node)->psort_current - tuplen, SEEK_SET);
|
||||||
|
tup = (HeapTuple) palloc((unsigned) tuplen);
|
||||||
|
SETTUPLEN(tup, tuplen);
|
||||||
|
GETTUP(node, tup, tuplen, PS(node)->psort_grab_file);
|
||||||
|
return tup; /* file position is equal to psort_current */
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
*should_free = false;
|
*should_free = false;
|
||||||
|
if (ScanDirectionIsForward (node->plan.state->es_direction))
|
||||||
|
{
|
||||||
|
if (PS(node)->psort_current < PS(node)->tupcount)
|
||||||
return (PS(node)->memtuples[PS(node)->psort_current++]);
|
return (PS(node)->memtuples[PS(node)->psort_current++]);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
PS(node)->all_fetched = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/* Backward */
|
||||||
|
if (PS(node)->psort_current <= 0)
|
||||||
|
return NULL;
|
||||||
|
/*
|
||||||
|
* if all tuples are fetched already then we return last tuple,
|
||||||
|
* else - tuple before last returned.
|
||||||
|
*/
|
||||||
|
if (PS(node)->all_fetched)
|
||||||
|
PS(node)->all_fetched = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PS(node)->psort_current--; /* last returned tuple */
|
||||||
|
if (PS(node)->psort_current <= 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return (PS(node)->memtuples[PS(node)->psort_current - 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: psort.h,v 1.13 1997/09/18 14:42:35 vadim Exp $
|
* $Id: psort.h,v 1.14 1997/10/15 06:36:36 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -62,6 +62,7 @@ typedef struct Psortstate
|
|||||||
long psort_current; /* could be file offset, or array index */
|
long psort_current; /* could be file offset, or array index */
|
||||||
long psort_saved; /* could be file offset, or array index */
|
long psort_saved; /* could be file offset, or array index */
|
||||||
bool using_tape_files;
|
bool using_tape_files;
|
||||||
|
bool all_fetched; /* this is for cursors */
|
||||||
|
|
||||||
HeapTuple *memtuples;
|
HeapTuple *memtuples;
|
||||||
} Psortstate;
|
} Psortstate;
|
||||||
|
Loading…
Reference in New Issue
Block a user