3030 * in a format that allows either forward or backward scan. Otherwise, only
3131 * forward scan is allowed. A request for backward scan must be made before
3232 * putting any tuples into the tuplestore. Rewind is normally allowed but
33- * can be turned off via tuplestore_set_eflags; turning off both backward
34- * scan and rewind for all read pointers enables truncation of the tuplestore
35- * at the oldest read point for minimal memory usage.
33+ * can be turned off via tuplestore_set_eflags; turning off rewind for all
34+ * read pointers enables truncation of the tuplestore at the oldest read point
35+ * for minimal memory usage. (The caller must explicitly call tuplestore_trim
36+ * at appropriate times for truncation to actually happen.)
3637 *
3738 * Note: in TSS_WRITEFILE state, the temp file's seek position is the
3839 * current write position, and the write-position variables in the tuplestore
4647 * Portions Copyright (c) 1994, Regents of the University of California
4748 *
4849 * IDENTIFICATION
49- * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.43 2008/10/28 15:51:03 tgl Exp $
50+ * $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.44 2008/12/27 17:39:00 tgl Exp $
5051 *
5152 *-------------------------------------------------------------------------
5253 */
@@ -101,6 +102,7 @@ struct Tuplestorestate
101102int eflags ;/* capability flags (OR of pointers' flags) */
102103bool backward ;/* store extra length words in file? */
103104bool interXact ;/* keep open through transactions? */
105+ bool truncated ;/* tuplestore_trim has removed tuples? */
104106long availMem ;/* remaining memory available, in bytes */
105107BufFile * myfile ;/* underlying file, or NULL if none */
106108
@@ -220,7 +222,6 @@ static Tuplestorestate *tuplestore_begin_common(int eflags,
220222int maxKBytes );
221223static void tuplestore_puttuple_common (Tuplestorestate * state ,void * tuple );
222224static void dumptuples (Tuplestorestate * state );
223- static void tuplestore_trim (Tuplestorestate * state );
224225static unsignedint getlen (Tuplestorestate * state ,bool eofOK );
225226static void * copytup_heap (Tuplestorestate * state ,void * tup );
226227static void writetup_heap (Tuplestorestate * state ,void * tup );
@@ -242,6 +243,7 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes)
242243state -> status = TSS_INMEM ;
243244state -> eflags = eflags ;
244245state -> interXact = interXact ;
246+ state -> truncated = false;
245247state -> availMem = maxKBytes * 1024L ;
246248state -> myfile = NULL ;
247249
@@ -319,6 +321,10 @@ tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
319321 *EXEC_FLAG_BACKWARDneed backward fetch
320322 * If tuplestore_set_eflags is not called, REWIND is allowed, and BACKWARD
321323 * is set per "randomAccess" in the tuplestore_begin_xxx call.
324+ *
325+ * NOTE: setting BACKWARD without REWIND means the pointer can read backwards,
326+ * but not further than the truncation point (the furthest-back read pointer
327+ * position at the time of the last tuplestore_trim call).
322328 */
323329void
324330tuplestore_set_eflags (Tuplestorestate * state ,int eflags )
@@ -397,6 +403,7 @@ tuplestore_clear(Tuplestorestate *state)
397403}
398404}
399405state -> status = TSS_INMEM ;
406+ state -> truncated = false;
400407state -> memtupcount = 0 ;
401408readptr = state -> readptrs ;
402409for (i = 0 ;i < state -> readptrcount ;readptr ++ ,i ++ )
@@ -723,12 +730,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
723730return NULL ;
724731if (readptr -> current < state -> memtupcount )
725732{
726- /*
727- * We have another tuple, so return it. Note: in
728- * principle we could try tuplestore_trim() here after
729- * advancing current, but this would cost cycles with
730- * little chance of success, so we don't bother.
731- */
733+ /* We have another tuple, so return it */
732734return state -> memtuples [readptr -> current ++ ];
733735}
734736readptr -> eof_reached = true;
@@ -738,7 +740,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
738740{
739741/*
740742 * if all tuples are fetched already then we return last
741- * tuple, else- tuple before last returned.
743+ * tuple, else tuple before last returned.
742744 */
743745if (readptr -> eof_reached )
744746{
@@ -748,11 +750,17 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
748750else
749751{
750752if (readptr -> current <=0 )
753+ {
754+ Assert (!state -> truncated );
751755return NULL ;
756+ }
752757readptr -> current -- ;/* last returned tuple */
753758}
754759if (readptr -> current <=0 )
760+ {
761+ Assert (!state -> truncated );
755762return NULL ;
763+ }
756764return state -> memtuples [readptr -> current - 1 ];
757765}
758766break ;
@@ -795,7 +803,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
795803 * Backward.
796804 *
797805 * if all tuples are fetched already then we return last tuple,
798- * else- tuple before last returned.
806+ * else tuple before last returned.
799807 *
800808 * Back up to fetch previously-returned tuple's ending length
801809 * word. If seek fails, assume we are at start of file.
@@ -805,6 +813,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
805813{
806814/* even a failed backwards fetch gets you out of eof state */
807815readptr -> eof_reached = false;
816+ Assert (!state -> truncated );
808817return NULL ;
809818}
810819tuplen = getlen (state , false);
@@ -833,6 +842,7 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
833842- (long ) (tuplen + sizeof (unsignedint )),
834843SEEK_CUR )!= 0 )
835844elog (ERROR ,"bogus tuple length in backward scan" );
845+ Assert (!state -> truncated );
836846return NULL ;
837847}
838848tuplen = getlen (state , false);
@@ -887,7 +897,8 @@ tuplestore_gettupleslot(Tuplestorestate *state, bool forward,
887897 * tuplestore_advance - exported function to adjust position without fetching
888898 *
889899 * We could optimize this case to avoid palloc/pfree overhead, but for the
890- * moment it doesn't seem worthwhile.
900+ * moment it doesn't seem worthwhile. (XXX this probably needs to be
901+ * reconsidered given the needs of window functions.)
891902 */
892903bool
893904tuplestore_advance (Tuplestorestate * state ,bool forward )
@@ -948,6 +959,7 @@ tuplestore_rescan(Tuplestorestate *state)
948959TSReadPointer * readptr = & state -> readptrs [state -> activeptr ];
949960
950961Assert (readptr -> eflags & EXEC_FLAG_REWIND );
962+ Assert (!state -> truncated );
951963
952964switch (state -> status )
953965{
@@ -1006,10 +1018,8 @@ tuplestore_copy_read_pointer(Tuplestorestate *state,
10061018switch (state -> status )
10071019{
10081020case TSS_INMEM :
1009- /* We might be able to truncate the tuplestore */
1010- tuplestore_trim (state );
1011- break ;
10121021case TSS_WRITEFILE :
1022+ /* no work */
10131023break ;
10141024case TSS_READFILE :
10151025/*
@@ -1053,19 +1063,27 @@ tuplestore_copy_read_pointer(Tuplestorestate *state,
10531063
10541064/*
10551065 * tuplestore_trim- remove all no-longer-needed tuples
1066+ *
1067+ * Calling this function authorizes the tuplestore to delete all tuples
1068+ * before the oldest read pointer, if no read pointer is marked as requiring
1069+ * REWIND capability.
1070+ *
1071+ * Note: this is obviously safe if no pointer has BACKWARD capability either.
1072+ * If a pointer is marked as BACKWARD but not REWIND capable, it means that
1073+ * the pointer can be moved backward but not before the oldest other read
1074+ * pointer.
10561075 */
1057- static void
1076+ void
10581077tuplestore_trim (Tuplestorestate * state )
10591078{
10601079int oldest ;
10611080int nremove ;
10621081int i ;
10631082
10641083/*
1065- * We can truncate the tuplestore if neither backward scan nor
1066- * rewind capability are required by any read pointer.
1084+ * Truncation is disallowed if any read pointer requires rewind capability.
10671085 */
1068- if (state -> eflags & ( EXEC_FLAG_BACKWARD | EXEC_FLAG_REWIND ) )
1086+ if (state -> eflags & EXEC_FLAG_REWIND )
10691087return ;
10701088
10711089/*
@@ -1125,6 +1143,9 @@ tuplestore_trim(Tuplestorestate *state)
11251143if (!state -> readptrs [i ].eof_reached )
11261144state -> readptrs [i ].current -= nremove ;
11271145}
1146+
1147+ /* mark tuplestore as truncated (used for Assert crosschecks only) */
1148+ state -> truncated = true;
11281149}
11291150
11301151