Skip to content

Commit 78351f4

Browse files
committed
Fix for backward cursors with ORDER BY.
1 parent 9acf938 commit 78351f4

File tree

2 files changed

+113
-25
lines changed

2 files changed

+113
-25
lines changed

src/backend/utils/sort/psort.c

Lines changed: 111 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.25 1997/09/26 20:05:47 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.26 1997/10/15 06:36:08 vadim Exp $
1111
*
1212
* NOTES
1313
* Sorts the first relation into the second relation.
@@ -80,7 +80,12 @@ static int _psort_cmp (HeapTuple *ltup, HeapTuple *rtup);
8080

8181
#define TEMPDIR "./"
8282

83-
static long shortzero = 0; /* used to delimit runs */
83+
/*
84+
* tlenzero used to delimit runs; both vars below must have
85+
* the same size as HeapTuple->t_len
86+
*/
87+
static unsigned int tlenzero = 0;
88+
static unsigned int tlendummy;
8489

8590
static TupleDesc PsortTupDesc;
8691
static ScanKey PsortKeys; /* used by _psort_cmp */
@@ -150,6 +155,7 @@ psort_begin(Sort * node, int nkeys, ScanKey key)
150155
PS(node)->tupcount = 0;
151156

152157
PS(node)->using_tape_files = false;
158+
PS(node)->all_fetched = false;
153159
PS(node)->psort_grab_file = NULL;
154160
PS(node)->memtuples = NULL;
155161

@@ -219,21 +225,24 @@ inittapes(Sort * node)
219225
* GETTUP - reads the tuple
220226
*
221227
* Note:
222-
* LEN field must be a short; FP is a stream
228+
* LEN field must be as HeapTuple->t_len; FP is a stream
223229
*/
224230

225231

226232
#define PUTTUP(NODE, TUP, FP) do {\
227233
((Psortstate *)NODE->psortstate)->BytesWritten += (TUP)->t_len; \
228-
fwrite((char *)TUP, (TUP)->t_len, 1, FP);} while (0)
229-
#define ENDRUN(FP) fwrite((char *)&shortzero, sizeof (shortzero), 1, FP)
230-
#define GETLEN(LEN, FP) fread((char *)&(LEN), sizeof (shortzero), 1, FP)
234+
fwrite((char *)TUP, (TUP)->t_len, 1, FP); \
235+
fwrite((char *)&((TUP)->t_len), sizeof (tlendummy), 1, FP); \
236+
} while (0)
237+
#define ENDRUN(FP) fwrite((char *)&tlenzero, sizeof (tlenzero), 1, FP)
238+
#define GETLEN(LEN, FP) fread((char *)&(LEN), sizeof (tlenzero), 1, FP)
231239
#define ALLOCTUP(LEN) ((HeapTuple)palloc((unsigned)LEN))
232240
#define GETTUP(NODE, TUP, LEN, FP) do {\
233241
IncrProcessed(); \
234-
((Psortstate *)NODE->psortstate)->BytesRead += (LEN) - sizeof (shortzero); \
235-
fread((char *)(TUP) + sizeof (shortzero), (LEN) - sizeof (shortzero), 1, FP);} \
236-
while (0)
242+
((Psortstate *)NODE->psortstate)->BytesRead += (LEN) - sizeof (tlenzero); \
243+
fread((char *)(TUP) + sizeof (tlenzero), (LEN) - sizeof (tlenzero), 1, FP); \
244+
fread((char *)&tlendummy, sizeof (tlendummy), 1, FP); \
245+
} while (0)
237246
#define SETTUPLEN(TUP, LEN) (TUP)->t_len = LEN
238247

239248
/*
@@ -629,11 +638,11 @@ merge(Sort * node, struct tape * dest)
629638
register struct tape *lasttp; /* (TAPE[P]) */
630639
register struct tape *tp;
631640
struct leftist *tuples;
632-
FILE *destfile;
633-
int times; /* runs left to merge */
634-
int outdummy; /* complete dummy runs */
635-
short fromtape;
636-
long tuplen;
641+
FILE *destfile;
642+
int times; /* runs left to merge */
643+
int outdummy; /* complete dummy runs */
644+
short fromtape;
645+
unsigned int tuplen;
637646

638647
Assert(node != (Sort *) NULL);
639648
Assert(PS(node) != (Psortstate *) NULL);
@@ -767,42 +776,120 @@ dumptuples(FILE * file, Sort * node)
767776
HeapTuple
768777
psort_grabtuple(Sort * node, bool * should_free)
769778
{
770-
register HeapTuple tup;
771-
long tuplen;
779+
register HeapTuple tup;
772780

773781
Assert(node != (Sort *) NULL);
774782
Assert(PS(node) != (Psortstate *) NULL);
775783

776784
if (PS(node)->using_tape_files == true)
777785
{
778-
if (!feof(PS(node)->psort_grab_file))
786+
unsigned int tuplen;
787+
788+
*should_free = true;
789+
if (ScanDirectionIsForward (node->plan.state->es_direction))
779790
{
791+
if (PS(node)->all_fetched)
792+
return NULL;
780793
if (GETLEN(tuplen, PS(node)->psort_grab_file) && tuplen != 0)
781794
{
782795
tup = (HeapTuple) palloc((unsigned) tuplen);
783796
SETTUPLEN(tup, tuplen);
784797
GETTUP(node, tup, tuplen, PS(node)->psort_grab_file);
785798

786799
/* Update current merged sort file position */
787-
PS(node)->psort_current += tuplen;
788-
*should_free = true;
800+
PS(node)->psort_current += tuplen + sizeof (tlendummy);
789801
return tup;
790802
}
791803
else
804+
{
805+
PS(node)->all_fetched = true;
792806
return NULL;
807+
}
793808
}
794-
else
809+
/* Backward */
810+
if (PS(node)->psort_current <= sizeof (tlendummy))
795811
return NULL;
812+
/*
813+
* if all tuples are fetched already then we return last tuple,
814+
* else - tuple before last returned.
815+
*/
816+
if (PS(node)->all_fetched)
817+
{
818+
/* psort_current is pointing to the zero tuplen at the end of file */
819+
fseek(PS(node)->psort_grab_file,
820+
PS(node)->psort_current - sizeof (tlendummy), SEEK_SET);
821+
GETLEN(tuplen, PS(node)->psort_grab_file);
822+
if (PS(node)->psort_current < tuplen)
823+
elog (FATAL, "psort_grabtuple: too big last tuple len in backward scan");
824+
PS(node)->all_fetched = false;
825+
}
826+
else
827+
{
828+
/* move to position of end tlen of prev tuple */
829+
PS(node)->psort_current -= sizeof (tlendummy);
830+
fseek(PS(node)->psort_grab_file, PS(node)->psort_current, SEEK_SET);
831+
GETLEN(tuplen, PS(node)->psort_grab_file); /* get tlen of prev tuple */
832+
if (tuplen == 0)
833+
elog (FATAL, "psort_grabtuple: tuplen is 0 in backward scan");
834+
if (PS(node)->psort_current <= tuplen + sizeof (tlendummy))
835+
{ /* prev tuple should be first one */
836+
if (PS(node)->psort_current != tuplen)
837+
elog (FATAL, "psort_grabtuple: first tuple expected in backward scan");
838+
PS(node)->psort_current = 0;
839+
fseek(PS(node)->psort_grab_file, PS(node)->psort_current, SEEK_SET);
840+
return NULL;
841+
}
842+
/*
843+
* Get position of prev tuple. This tuple becomes current tuple
844+
* now and we have to return previous one.
845+
*/
846+
PS(node)->psort_current -= tuplen;
847+
/* move to position of end tlen of prev tuple */
848+
fseek(PS(node)->psort_grab_file,
849+
PS(node)->psort_current - sizeof (tlendummy), SEEK_SET);
850+
GETLEN(tuplen, PS(node)->psort_grab_file);
851+
if (PS(node)->psort_current < tuplen + sizeof (tlendummy))
852+
elog (FATAL, "psort_grabtuple: too big tuple len in backward scan");
853+
}
854+
/*
855+
* move to prev (or last) tuple start position + sizeof(t_len)
856+
*/
857+
fseek(PS(node)->psort_grab_file,
858+
PS(node)->psort_current - tuplen, SEEK_SET);
859+
tup = (HeapTuple) palloc((unsigned) tuplen);
860+
SETTUPLEN(tup, tuplen);
861+
GETTUP(node, tup, tuplen, PS(node)->psort_grab_file);
862+
return tup; /* file position is equal to psort_current */
796863
}
797864
else
798865
{
799-
if (PS(node)->psort_current < PS(node)->tupcount)
866+
*should_free = false;
867+
if (ScanDirectionIsForward (node->plan.state->es_direction))
800868
{
801-
*should_free = false;
802-
return (PS(node)->memtuples[PS(node)->psort_current++]);
869+
if (PS(node)->psort_current < PS(node)->tupcount)
870+
return (PS(node)->memtuples[PS(node)->psort_current++]);
871+
else
872+
{
873+
PS(node)->all_fetched = true;
874+
return NULL;
875+
}
803876
}
804-
else
877+
/* Backward */
878+
if (PS(node)->psort_current <= 0)
805879
return NULL;
880+
/*
881+
* if all tuples are fetched already then we return last tuple,
882+
* else - tuple before last returned.
883+
*/
884+
if (PS(node)->all_fetched)
885+
PS(node)->all_fetched = false;
886+
else
887+
{
888+
PS(node)->psort_current--; /* last returned tuple */
889+
if (PS(node)->psort_current <= 0)
890+
return NULL;
891+
}
892+
return (PS(node)->memtuples[PS(node)->psort_current - 1]);
806893
}
807894
}
808895

src/include/utils/psort.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: psort.h,v 1.13 1997/09/18 14:42:35 vadim Exp $
9+
* $Id: psort.h,v 1.14 1997/10/15 06:36:36 vadim Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -62,6 +62,7 @@ typedef struct Psortstate
6262
long psort_current; /* could be file offset, or array index */
6363
long psort_saved; /* could be file offset, or array index */
6464
bool using_tape_files;
65+
bool all_fetched; /* this is for cursors */
6566

6667
HeapTuple *memtuples;
6768
} Psortstate;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy