Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Enumerations | Functions

tuplestore.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "commands/tablespace.h"
#include "executor/executor.h"
#include "storage/buffile.h"
#include "utils/memutils.h"
#include "utils/resowner.h"
Include dependency graph for tuplestore.c:

Go to the source code of this file.

Data Structures

struct  TSReadPointer
struct  Tuplestorestate

Defines

#define COPYTUP(state, tup)   ((*(state)->copytup) (state, tup))
#define WRITETUP(state, tup)   ((*(state)->writetup) (state, tup))
#define READTUP(state, len)   ((*(state)->readtup) (state, len))
#define LACKMEM(state)   ((state)->availMem < 0)
#define USEMEM(state, amt)   ((state)->availMem -= (amt))
#define FREEMEM(state, amt)   ((state)->availMem += (amt))

Enumerations

enum  TupStoreStatus { TSS_INMEM, TSS_WRITEFILE, TSS_READFILE }

Functions

static Tuplestorestatetuplestore_begin_common (int eflags, bool interXact, int maxKBytes)
static void tuplestore_puttuple_common (Tuplestorestate *state, void *tuple)
static void dumptuples (Tuplestorestate *state)
static unsigned int getlen (Tuplestorestate *state, bool eofOK)
static void * copytup_heap (Tuplestorestate *state, void *tup)
static void writetup_heap (Tuplestorestate *state, void *tup)
static void * readtup_heap (Tuplestorestate *state, unsigned int len)
Tuplestorestatetuplestore_begin_heap (bool randomAccess, bool interXact, int maxKBytes)
void tuplestore_set_eflags (Tuplestorestate *state, int eflags)
int tuplestore_alloc_read_pointer (Tuplestorestate *state, int eflags)
void tuplestore_clear (Tuplestorestate *state)
void tuplestore_end (Tuplestorestate *state)
void tuplestore_select_read_pointer (Tuplestorestate *state, int ptr)
bool tuplestore_ateof (Tuplestorestate *state)
static bool grow_memtuples (Tuplestorestate *state)
void tuplestore_puttupleslot (Tuplestorestate *state, TupleTableSlot *slot)
void tuplestore_puttuple (Tuplestorestate *state, HeapTuple tuple)
void tuplestore_putvalues (Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
static void * tuplestore_gettuple (Tuplestorestate *state, bool forward, bool *should_free)
bool tuplestore_gettupleslot (Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
bool tuplestore_advance (Tuplestorestate *state, bool forward)
void tuplestore_rescan (Tuplestorestate *state)
void tuplestore_copy_read_pointer (Tuplestorestate *state, int srcptr, int destptr)
void tuplestore_trim (Tuplestorestate *state)
bool tuplestore_in_memory (Tuplestorestate *state)

Define Documentation

#define COPYTUP (   state,
  tup 
)    ((*(state)->copytup) (state, tup))

Definition at line 179 of file tuplestore.c.

Referenced by tuplestore_puttuple().

#define FREEMEM (   state,
  amt 
)    ((state)->availMem += (amt))

Definition at line 184 of file tuplestore.c.

Referenced by grow_memtuples(), tuplestore_clear(), tuplestore_trim(), and writetup_heap().

#define LACKMEM (   state  )     ((state)->availMem < 0)

Definition at line 182 of file tuplestore.c.

Referenced by grow_memtuples(), and tuplestore_puttuple_common().

#define READTUP (   state,
  len 
)    ((*(state)->readtup) (state, len))

Definition at line 181 of file tuplestore.c.

Referenced by tuplestore_gettuple().

#define USEMEM (   state,
  amt 
)    ((state)->availMem -= (amt))
#define WRITETUP (   state,
  tup 
)    ((*(state)->writetup) (state, tup))

Definition at line 180 of file tuplestore.c.

Referenced by dumptuples(), and tuplestore_puttuple_common().


Enumeration Type Documentation

Enumerator:
TSS_INMEM 
TSS_WRITEFILE 
TSS_READFILE 

Definition at line 69 of file tuplestore.c.

{
    TSS_INMEM,                  /* Tuples still fit in memory */
    TSS_WRITEFILE,              /* Writing to temp file */
    TSS_READFILE                /* Reading from temp file */
} TupStoreStatus;


Function Documentation

static void * copytup_heap ( Tuplestorestate state,
void *  tup 
) [static]

Definition at line 1371 of file tuplestore.c.

References GetMemoryChunkSpace(), minimal_tuple_from_heap_tuple(), and USEMEM.

{
    MinimalTuple tuple;

    tuple = minimal_tuple_from_heap_tuple((HeapTuple) tup);
    USEMEM(state, GetMemoryChunkSpace(tuple));
    return (void *) tuple;
}

static void dumptuples ( Tuplestorestate state  )  [static]

Definition at line 1090 of file tuplestore.c.

References BufFileTell(), TSReadPointer::current, TSReadPointer::eof_reached, TSReadPointer::file, i, Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrcount, Tuplestorestate::readptrs, and WRITETUP.

Referenced by tuplestore_puttuple_common().

{
    int         i;

    for (i = state->memtupdeleted;; i++)
    {
        TSReadPointer *readptr = state->readptrs;
        int         j;

        for (j = 0; j < state->readptrcount; readptr++, j++)
        {
            if (i == readptr->current && !readptr->eof_reached)
                BufFileTell(state->myfile,
                            &readptr->file, &readptr->offset);
        }
        if (i >= state->memtupcount)
            break;
        WRITETUP(state, state->memtuples[i]);
    }
    state->memtupdeleted = 0;
    state->memtupcount = 0;
}

static unsigned int getlen ( Tuplestorestate state,
bool  eofOK 
) [static]

Definition at line 1344 of file tuplestore.c.

References BufFileRead(), elog, ERROR, and Tuplestorestate::myfile.

Referenced by tuplestore_gettuple().

{
    unsigned int len;
    size_t      nbytes;

    nbytes = BufFileRead(state->myfile, (void *) &len, sizeof(len));
    if (nbytes == sizeof(len))
        return len;
    if (nbytes != 0)
        elog(ERROR, "unexpected end of tape");
    if (!eofOK)
        elog(ERROR, "unexpected end of data");
    return 0;
}

static bool grow_memtuples ( Tuplestorestate state  )  [static]

Definition at line 548 of file tuplestore.c.

References Tuplestorestate::allowedMem, Tuplestorestate::availMem, elog, ERROR, FREEMEM, GetMemoryChunkSpace(), Tuplestorestate::growmemtuples, LACKMEM, MaxAllocSize, Tuplestorestate::memtuples, Tuplestorestate::memtupsize, repalloc(), and USEMEM.

Referenced by tuplestore_puttuple_common().

{
    int         newmemtupsize;
    int         memtupsize = state->memtupsize;
    long        memNowUsed = state->allowedMem - state->availMem;

    /* Forget it if we've already maxed out memtuples, per comment above */
    if (!state->growmemtuples)
        return false;

    /* Select new value of memtupsize */
    if (memNowUsed <= state->availMem)
    {
        /*
         * It is surely safe to double memtupsize if we've used no more than
         * half of allowedMem.
         *
         * Note: it might seem that we need to worry about memtupsize * 2
         * overflowing an int, but the MaxAllocSize clamp applied below
         * ensures the existing memtupsize can't be large enough for that.
         */
        newmemtupsize = memtupsize * 2;
    }
    else
    {
        /*
         * This will be the last increment of memtupsize.  Abandon doubling
         * strategy and instead increase as much as we safely can.
         *
         * To stay within allowedMem, we can't increase memtupsize by more
         * than availMem / sizeof(void *) elements. In practice, we want
         * to increase it by considerably less, because we need to leave some
         * space for the tuples to which the new array slots will refer.  We
         * assume the new tuples will be about the same size as the tuples
         * we've already seen, and thus we can extrapolate from the space
         * consumption so far to estimate an appropriate new size for the
         * memtuples array.  The optimal value might be higher or lower than
         * this estimate, but it's hard to know that in advance.
         *
         * This calculation is safe against enlarging the array so much that
         * LACKMEM becomes true, because the memory currently used includes
         * the present array; thus, there would be enough allowedMem for the
         * new array elements even if no other memory were currently used.
         *
         * We do the arithmetic in float8, because otherwise the product of
         * memtupsize and allowedMem could overflow.  (A little algebra shows
         * that grow_ratio must be less than 2 here, so we are not risking
         * integer overflow this way.)  Any inaccuracy in the result should be
         * insignificant; but even if we computed a completely insane result,
         * the checks below will prevent anything really bad from happening.
         */
        double      grow_ratio;

        grow_ratio = (double) state->allowedMem / (double) memNowUsed;
        newmemtupsize = (int) (memtupsize * grow_ratio);

        /* We won't make any further enlargement attempts */
        state->growmemtuples = false;
    }

    /* Must enlarge array by at least one element, else report failure */
    if (newmemtupsize <= memtupsize)
        goto noalloc;

    /*
     * On a 64-bit machine, allowedMem could be more than MaxAllocSize.  Clamp
     * to ensure our request won't be rejected by palloc.
     */
    if ((Size) newmemtupsize >= MaxAllocSize / sizeof(void *))
    {
        newmemtupsize = (int) (MaxAllocSize / sizeof(void *));
        state->growmemtuples = false;   /* can't grow any more */
    }

    /*
     * We need to be sure that we do not cause LACKMEM to become true, else
     * the space management algorithm will go nuts.  The code above should
     * never generate a dangerous request, but to be safe, check explicitly
     * that the array growth fits within availMem.  (We could still cause
     * LACKMEM if the memory chunk overhead associated with the memtuples
     * array were to increase.  That shouldn't happen with any sane value of
     * allowedMem, because at any array size large enough to risk LACKMEM,
     * palloc would be treating both old and new arrays as separate chunks.
     * But we'll check LACKMEM explicitly below just in case.)
     */
    if (state->availMem < (long) ((newmemtupsize - memtupsize) * sizeof(void *)))
        goto noalloc;

    /* OK, do it */
    FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
    state->memtupsize = newmemtupsize;
    state->memtuples = (void **)
        repalloc(state->memtuples,
                 state->memtupsize * sizeof(void *));
    USEMEM(state, GetMemoryChunkSpace(state->memtuples));
    if (LACKMEM(state))
        elog(ERROR, "unexpected out-of-memory situation during sort");
    return true;

noalloc:
    /* If for any reason we didn't realloc, shut off future attempts */
    state->growmemtuples = false;
    return false;
}

static void * readtup_heap ( Tuplestorestate state,
unsigned int  len 
) [static]

Definition at line 1408 of file tuplestore.c.

References Tuplestorestate::backward, BufFileRead(), elog, ERROR, GetMemoryChunkSpace(), Tuplestorestate::myfile, palloc(), MinimalTupleData::t_len, and USEMEM.

{
    unsigned int tupbodylen = len - sizeof(int);
    unsigned int tuplen = tupbodylen + MINIMAL_TUPLE_DATA_OFFSET;
    MinimalTuple tuple = (MinimalTuple) palloc(tuplen);
    char       *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;

    USEMEM(state, GetMemoryChunkSpace(tuple));
    /* read in the tuple proper */
    tuple->t_len = tuplen;
    if (BufFileRead(state->myfile, (void *) tupbody,
                    tupbodylen) != (size_t) tupbodylen)
        elog(ERROR, "unexpected end of data");
    if (state->backward)        /* need trailing length word? */
        if (BufFileRead(state->myfile, (void *) &tuplen,
                        sizeof(tuplen)) != sizeof(tuplen))
            elog(ERROR, "unexpected end of data");
    return (void *) tuple;
}

bool tuplestore_advance ( Tuplestorestate state,
bool  forward 
)

Definition at line 1063 of file tuplestore.c.

References pfree(), and tuplestore_gettuple().

Referenced by CteScanNext(), ExecMaterial(), PersistHoldablePortal(), window_gettupleslot(), and WinSetMarkPosition().

{
    void       *tuple;
    bool        should_free;

    tuple = tuplestore_gettuple(state, forward, &should_free);

    if (tuple)
    {
        if (should_free)
            pfree(tuple);
        return true;
    }
    else
    {
        return false;
    }
}

int tuplestore_alloc_read_pointer ( Tuplestorestate state,
int  eflags 
)

Definition at line 371 of file tuplestore.c.

References TSReadPointer::eflags, Tuplestorestate::eflags, elog, ERROR, Tuplestorestate::memtupcount, Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::readptrsize, repalloc(), Tuplestorestate::status, and TSS_INMEM.

Referenced by begin_partition(), ExecInitCteScan(), and ExecMaterial().

{
    /* Check for possible increase of requirements */
    if (state->status != TSS_INMEM || state->memtupcount != 0)
    {
        if ((state->eflags | eflags) != state->eflags)
            elog(ERROR, "too late to require new tuplestore eflags");
    }

    /* Make room for another read pointer if needed */
    if (state->readptrcount >= state->readptrsize)
    {
        int         newcnt = state->readptrsize * 2;

        state->readptrs = (TSReadPointer *)
            repalloc(state->readptrs, newcnt * sizeof(TSReadPointer));
        state->readptrsize = newcnt;
    }

    /* And set it up */
    state->readptrs[state->readptrcount] = state->readptrs[0];
    state->readptrs[state->readptrcount].eflags = eflags;

    state->eflags |= eflags;

    return state->readptrcount++;
}

bool tuplestore_ateof ( Tuplestorestate state  ) 

Definition at line 528 of file tuplestore.c.

References Tuplestorestate::activeptr, TSReadPointer::eof_reached, and Tuplestorestate::readptrs.

Referenced by CteScanNext(), and ExecMaterial().

{
    return state->readptrs[state->activeptr].eof_reached;
}

static Tuplestorestate * tuplestore_begin_common ( int  eflags,
bool  interXact,
int  maxKBytes 
) [static]

Definition at line 249 of file tuplestore.c.

References Tuplestorestate::activeptr, Tuplestorestate::allowedMem, Tuplestorestate::availMem, Tuplestorestate::context, TSReadPointer::current, CurrentMemoryContext, CurrentResourceOwner, TSReadPointer::eflags, Tuplestorestate::eflags, TSReadPointer::eof_reached, GetMemoryChunkSpace(), Tuplestorestate::growmemtuples, Tuplestorestate::interXact, Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::memtupsize, Tuplestorestate::myfile, palloc(), palloc0(), Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::readptrsize, Tuplestorestate::resowner, Tuplestorestate::status, Tuplestorestate::truncated, and USEMEM.

Referenced by tuplestore_begin_heap().

{
    Tuplestorestate *state;

    state = (Tuplestorestate *) palloc0(sizeof(Tuplestorestate));

    state->status = TSS_INMEM;
    state->eflags = eflags;
    state->interXact = interXact;
    state->truncated = false;
    state->allowedMem = maxKBytes * 1024L;
    state->availMem = state->allowedMem;
    state->myfile = NULL;
    state->context = CurrentMemoryContext;
    state->resowner = CurrentResourceOwner;

    state->memtupdeleted = 0;
    state->memtupcount = 0;
    state->memtupsize = 1024;   /* initial guess */
    state->growmemtuples = true;
    state->memtuples = (void **) palloc(state->memtupsize * sizeof(void *));

    USEMEM(state, GetMemoryChunkSpace(state->memtuples));

    state->activeptr = 0;
    state->readptrcount = 1;
    state->readptrsize = 8;     /* arbitrary */
    state->readptrs = (TSReadPointer *)
        palloc(state->readptrsize * sizeof(TSReadPointer));

    state->readptrs[0].eflags = eflags;
    state->readptrs[0].eof_reached = false;
    state->readptrs[0].current = 0;

    return state;
}

Tuplestorestate* tuplestore_begin_heap ( bool  randomAccess,
bool  interXact,
int  maxKBytes 
)
void tuplestore_clear ( Tuplestorestate state  ) 

Definition at line 406 of file tuplestore.c.

References BufFileClose(), TSReadPointer::current, TSReadPointer::eof_reached, FREEMEM, GetMemoryChunkSpace(), i, Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::myfile, pfree(), Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::status, and Tuplestorestate::truncated.

Referenced by ExecReScanCteScan(), ExecReScanRecursiveUnion(), and fmgr_sql().

{
    int         i;
    TSReadPointer *readptr;

    if (state->myfile)
        BufFileClose(state->myfile);
    state->myfile = NULL;
    if (state->memtuples)
    {
        for (i = state->memtupdeleted; i < state->memtupcount; i++)
        {
            FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i]));
            pfree(state->memtuples[i]);
        }
    }
    state->status = TSS_INMEM;
    state->truncated = false;
    state->memtupdeleted = 0;
    state->memtupcount = 0;
    readptr = state->readptrs;
    for (i = 0; i < state->readptrcount; readptr++, i++)
    {
        readptr->eof_reached = false;
        readptr->current = 0;
    }
}

void tuplestore_copy_read_pointer ( Tuplestorestate state,
int  srcptr,
int  destptr 
)

Definition at line 1150 of file tuplestore.c.

References Tuplestorestate::activeptr, Assert, BufFileSeek(), BufFileTell(), Tuplestorestate::eflags, TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ERROR, TSReadPointer::file, i, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::status, TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, Tuplestorestate::writepos_file, and Tuplestorestate::writepos_offset.

Referenced by ExecMaterialMarkPos(), and ExecMaterialRestrPos().

{
    TSReadPointer *sptr = &state->readptrs[srcptr];
    TSReadPointer *dptr = &state->readptrs[destptr];

    Assert(srcptr >= 0 && srcptr < state->readptrcount);
    Assert(destptr >= 0 && destptr < state->readptrcount);

    /* Assigning to self is a no-op */
    if (srcptr == destptr)
        return;

    if (dptr->eflags != sptr->eflags)
    {
        /* Possible change of overall eflags, so copy and then recompute */
        int         eflags;
        int         i;

        *dptr = *sptr;
        eflags = state->readptrs[0].eflags;
        for (i = 1; i < state->readptrcount; i++)
            eflags |= state->readptrs[i].eflags;
        state->eflags = eflags;
    }
    else
        *dptr = *sptr;

    switch (state->status)
    {
        case TSS_INMEM:
        case TSS_WRITEFILE:
            /* no work */
            break;
        case TSS_READFILE:

            /*
             * This case is a bit tricky since the active read pointer's
             * position corresponds to the seek point, not what is in its
             * variables.  Assigning to the active requires a seek, and
             * assigning from the active requires a tell, except when
             * eof_reached.
             */
            if (destptr == state->activeptr)
            {
                if (dptr->eof_reached)
                {
                    if (BufFileSeek(state->myfile,
                                    state->writepos_file,
                                    state->writepos_offset,
                                    SEEK_SET) != 0)
                        elog(ERROR, "tuplestore seek failed");
                }
                else
                {
                    if (BufFileSeek(state->myfile,
                                    dptr->file, dptr->offset,
                                    SEEK_SET) != 0)
                        elog(ERROR, "tuplestore seek failed");
                }
            }
            else if (srcptr == state->activeptr)
            {
                if (!dptr->eof_reached)
                    BufFileTell(state->myfile,
                                &dptr->file,
                                &dptr->offset);
            }
            break;
        default:
            elog(ERROR, "invalid tuplestore state");
            break;
    }
}

void tuplestore_end ( Tuplestorestate state  ) 
static void* tuplestore_gettuple ( Tuplestorestate state,
bool  forward,
bool should_free 
) [static]

Definition at line 861 of file tuplestore.c.

References Tuplestorestate::activeptr, Assert, BufFileSeek(), BufFileTell(), TSReadPointer::current, TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ERROR, EXEC_FLAG_BACKWARD, TSReadPointer::file, getlen(), Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrs, READTUP, Tuplestorestate::status, Tuplestorestate::truncated, TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, Tuplestorestate::writepos_file, and Tuplestorestate::writepos_offset.

Referenced by tuplestore_advance(), and tuplestore_gettupleslot().

{
    TSReadPointer *readptr = &state->readptrs[state->activeptr];
    unsigned int tuplen;
    void       *tup;

    Assert(forward || (readptr->eflags & EXEC_FLAG_BACKWARD));

    switch (state->status)
    {
        case TSS_INMEM:
            *should_free = false;
            if (forward)
            {
                if (readptr->eof_reached)
                    return NULL;
                if (readptr->current < state->memtupcount)
                {
                    /* We have another tuple, so return it */
                    return state->memtuples[readptr->current++];
                }
                readptr->eof_reached = true;
                return NULL;
            }
            else
            {
                /*
                 * if all tuples are fetched already then we return last
                 * tuple, else tuple before last returned.
                 */
                if (readptr->eof_reached)
                {
                    readptr->current = state->memtupcount;
                    readptr->eof_reached = false;
                }
                else
                {
                    if (readptr->current <= state->memtupdeleted)
                    {
                        Assert(!state->truncated);
                        return NULL;
                    }
                    readptr->current--; /* last returned tuple */
                }
                if (readptr->current <= state->memtupdeleted)
                {
                    Assert(!state->truncated);
                    return NULL;
                }
                return state->memtuples[readptr->current - 1];
            }
            break;

        case TSS_WRITEFILE:
            /* Skip state change if we'll just return NULL */
            if (readptr->eof_reached && forward)
                return NULL;

            /*
             * Switch from writing to reading.
             */
            BufFileTell(state->myfile,
                        &state->writepos_file, &state->writepos_offset);
            if (!readptr->eof_reached)
                if (BufFileSeek(state->myfile,
                                readptr->file, readptr->offset,
                                SEEK_SET) != 0)
                    elog(ERROR, "tuplestore seek failed");
            state->status = TSS_READFILE;
            /* FALL THRU into READFILE case */

        case TSS_READFILE:
            *should_free = true;
            if (forward)
            {
                if ((tuplen = getlen(state, true)) != 0)
                {
                    tup = READTUP(state, tuplen);
                    return tup;
                }
                else
                {
                    readptr->eof_reached = true;
                    return NULL;
                }
            }

            /*
             * Backward.
             *
             * if all tuples are fetched already then we return last tuple,
             * else tuple before last returned.
             *
             * Back up to fetch previously-returned tuple's ending length
             * word. If seek fails, assume we are at start of file.
             */
            if (BufFileSeek(state->myfile, 0, -(long) sizeof(unsigned int),
                            SEEK_CUR) != 0)
            {
                /* even a failed backwards fetch gets you out of eof state */
                readptr->eof_reached = false;
                Assert(!state->truncated);
                return NULL;
            }
            tuplen = getlen(state, false);

            if (readptr->eof_reached)
            {
                readptr->eof_reached = false;
                /* We will return the tuple returned before returning NULL */
            }
            else
            {
                /*
                 * Back up to get ending length word of tuple before it.
                 */
                if (BufFileSeek(state->myfile, 0,
                                -(long) (tuplen + 2 * sizeof(unsigned int)),
                                SEEK_CUR) != 0)
                {
                    /*
                     * If that fails, presumably the prev tuple is the first
                     * in the file.  Back up so that it becomes next to read
                     * in forward direction (not obviously right, but that is
                     * what in-memory case does).
                     */
                    if (BufFileSeek(state->myfile, 0,
                                    -(long) (tuplen + sizeof(unsigned int)),
                                    SEEK_CUR) != 0)
                        elog(ERROR, "bogus tuple length in backward scan");
                    Assert(!state->truncated);
                    return NULL;
                }
                tuplen = getlen(state, false);
            }

            /*
             * Now we have the length of the prior tuple, back up and read it.
             * Note: READTUP expects we are positioned after the initial
             * length word of the tuple, so back up to that point.
             */
            if (BufFileSeek(state->myfile, 0,
                            -(long) tuplen,
                            SEEK_CUR) != 0)
                elog(ERROR, "bogus tuple length in backward scan");
            tup = READTUP(state, tuplen);
            return tup;

        default:
            elog(ERROR, "invalid tuplestore state");
            return NULL;        /* keep compiler quiet */
    }
}

bool tuplestore_gettupleslot ( Tuplestorestate state,
bool  forward,
bool  copy,
TupleTableSlot slot 
)

Definition at line 1030 of file tuplestore.c.

References ExecClearTuple(), ExecStoreMinimalTuple(), heap_copy_minimal_tuple(), and tuplestore_gettuple().

Referenced by CteScanNext(), ExecMakeFunctionResult(), ExecMaterial(), ExecWindowAgg(), fmgr_sql(), FunctionNext(), RunFromStore(), window_gettupleslot(), and WorkTableScanNext().

{
    MinimalTuple tuple;
    bool        should_free;

    tuple = (MinimalTuple) tuplestore_gettuple(state, forward, &should_free);

    if (tuple)
    {
        if (copy && !should_free)
        {
            tuple = heap_copy_minimal_tuple(tuple);
            should_free = true;
        }
        ExecStoreMinimalTuple(tuple, slot, should_free);
        return true;
    }
    else
    {
        ExecClearTuple(slot);
        return false;
    }
}

bool tuplestore_in_memory ( Tuplestorestate state  ) 

Definition at line 1333 of file tuplestore.c.

References Tuplestorestate::status, and TSS_INMEM.

Referenced by spool_tuples().

{
    return (state->status == TSS_INMEM);
}

void tuplestore_puttuple ( Tuplestorestate state,
HeapTuple  tuple 
)
static void tuplestore_puttuple_common ( Tuplestorestate state,
void *  tuple 
) [static]

Definition at line 727 of file tuplestore.c.

References Tuplestorestate::activeptr, Assert, Tuplestorestate::backward, BufFileCreateTemp(), BufFileSeek(), BufFileTell(), TSReadPointer::current, CurrentResourceOwner, dumptuples(), Tuplestorestate::eflags, elog, TSReadPointer::eof_reached, ERROR, TSReadPointer::file, grow_memtuples(), i, Tuplestorestate::interXact, LACKMEM, Tuplestorestate::memtupcount, Tuplestorestate::memtuples, Tuplestorestate::memtupsize, Tuplestorestate::myfile, TSReadPointer::offset, PrepareTempTablespaces(), Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::resowner, Tuplestorestate::status, TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, Tuplestorestate::writepos_file, Tuplestorestate::writepos_offset, and WRITETUP.

Referenced by tuplestore_puttuple(), tuplestore_puttupleslot(), and tuplestore_putvalues().

{
    TSReadPointer *readptr;
    int         i;
    ResourceOwner oldowner;

    switch (state->status)
    {
        case TSS_INMEM:

            /*
             * Update read pointers as needed; see API spec above.
             */
            readptr = state->readptrs;
            for (i = 0; i < state->readptrcount; readptr++, i++)
            {
                if (readptr->eof_reached && i != state->activeptr)
                {
                    readptr->eof_reached = false;
                    readptr->current = state->memtupcount;
                }
            }

            /*
             * Grow the array as needed.  Note that we try to grow the array
             * when there is still one free slot remaining --- if we fail,
             * there'll still be room to store the incoming tuple, and then
             * we'll switch to tape-based operation.
             */
            if (state->memtupcount >= state->memtupsize - 1)
            {
                (void) grow_memtuples(state);
                Assert(state->memtupcount < state->memtupsize);
            }

            /* Stash the tuple in the in-memory array */
            state->memtuples[state->memtupcount++] = tuple;

            /*
             * Done if we still fit in available memory and have array slots.
             */
            if (state->memtupcount < state->memtupsize && !LACKMEM(state))
                return;

            /*
             * Nope; time to switch to tape-based operation.  Make sure that
             * the temp file(s) are created in suitable temp tablespaces.
             */
            PrepareTempTablespaces();

            /* associate the file with the store's resource owner */
            oldowner = CurrentResourceOwner;
            CurrentResourceOwner = state->resowner;

            state->myfile = BufFileCreateTemp(state->interXact);

            CurrentResourceOwner = oldowner;

            /*
             * Freeze the decision about whether trailing length words will be
             * used.  We can't change this choice once data is on tape, even
             * though callers might drop the requirement.
             */
            state->backward = (state->eflags & EXEC_FLAG_BACKWARD) != 0;
            state->status = TSS_WRITEFILE;
            dumptuples(state);
            break;
        case TSS_WRITEFILE:

            /*
             * Update read pointers as needed; see API spec above. Note:
             * BufFileTell is quite cheap, so not worth trying to avoid
             * multiple calls.
             */
            readptr = state->readptrs;
            for (i = 0; i < state->readptrcount; readptr++, i++)
            {
                if (readptr->eof_reached && i != state->activeptr)
                {
                    readptr->eof_reached = false;
                    BufFileTell(state->myfile,
                                &readptr->file,
                                &readptr->offset);
                }
            }

            WRITETUP(state, tuple);
            break;
        case TSS_READFILE:

            /*
             * Switch from reading to writing.
             */
            if (!state->readptrs[state->activeptr].eof_reached)
                BufFileTell(state->myfile,
                            &state->readptrs[state->activeptr].file,
                            &state->readptrs[state->activeptr].offset);
            if (BufFileSeek(state->myfile,
                            state->writepos_file, state->writepos_offset,
                            SEEK_SET) != 0)
                elog(ERROR, "tuplestore seek to EOF failed");
            state->status = TSS_WRITEFILE;

            /*
             * Update read pointers as needed; see API spec above.
             */
            readptr = state->readptrs;
            for (i = 0; i < state->readptrcount; readptr++, i++)
            {
                if (readptr->eof_reached && i != state->activeptr)
                {
                    readptr->eof_reached = false;
                    readptr->file = state->writepos_file;
                    readptr->offset = state->writepos_offset;
                }
            }

            WRITETUP(state, tuple);
            break;
        default:
            elog(ERROR, "invalid tuplestore state");
            break;
    }
}

void tuplestore_puttupleslot ( Tuplestorestate state,
TupleTableSlot slot 
)
void tuplestore_putvalues ( Tuplestorestate state,
TupleDesc  tdesc,
Datum values,
bool isnull 
)
void tuplestore_rescan ( Tuplestorestate state  ) 

Definition at line 1117 of file tuplestore.c.

References Tuplestorestate::activeptr, Assert, BufFileSeek(), TSReadPointer::current, TSReadPointer::eflags, elog, TSReadPointer::eof_reached, ERROR, EXEC_FLAG_REWIND, TSReadPointer::file, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrs, Tuplestorestate::status, Tuplestorestate::truncated, TSS_INMEM, TSS_READFILE, and TSS_WRITEFILE.

Referenced by DoPortalRewind(), ExecReScanCteScan(), ExecReScanFunctionScan(), ExecReScanMaterial(), ExecReScanWorkTableScan(), and PersistHoldablePortal().

{
    TSReadPointer *readptr = &state->readptrs[state->activeptr];

    Assert(readptr->eflags & EXEC_FLAG_REWIND);
    Assert(!state->truncated);

    switch (state->status)
    {
        case TSS_INMEM:
            readptr->eof_reached = false;
            readptr->current = 0;
            break;
        case TSS_WRITEFILE:
            readptr->eof_reached = false;
            readptr->file = 0;
            readptr->offset = 0L;
            break;
        case TSS_READFILE:
            readptr->eof_reached = false;
            if (BufFileSeek(state->myfile, 0, 0L, SEEK_SET) != 0)
                elog(ERROR, "tuplestore seek to start failed");
            break;
        default:
            elog(ERROR, "invalid tuplestore state");
            break;
    }
}

void tuplestore_select_read_pointer ( Tuplestorestate state,
int  ptr 
)

Definition at line 460 of file tuplestore.c.

References Tuplestorestate::activeptr, Assert, BufFileSeek(), BufFileTell(), elog, TSReadPointer::eof_reached, ERROR, TSReadPointer::file, Tuplestorestate::myfile, TSReadPointer::offset, Tuplestorestate::readptrs, Tuplestorestate::status, TSS_INMEM, TSS_READFILE, TSS_WRITEFILE, Tuplestorestate::writepos_file, and Tuplestorestate::writepos_offset.

Referenced by CteScanNext(), ExecReScanCteScan(), ExecWindowAgg(), window_gettupleslot(), and WinSetMarkPosition().

{
    TSReadPointer *readptr;
    TSReadPointer *oldptr;

    Assert(ptr >= 0 && ptr < state->readptrcount);

    /* No work if already active */
    if (ptr == state->activeptr)
        return;

    readptr = &state->readptrs[ptr];
    oldptr = &state->readptrs[state->activeptr];

    switch (state->status)
    {
        case TSS_INMEM:
        case TSS_WRITEFILE:
            /* no work */
            break;
        case TSS_READFILE:

            /*
             * First, save the current read position in the pointer about to
             * become inactive.
             */
            if (!oldptr->eof_reached)
                BufFileTell(state->myfile,
                            &oldptr->file,
                            &oldptr->offset);

            /*
             * We have to make the temp file's seek position equal to the
             * logical position of the new read pointer.  In eof_reached
             * state, that's the EOF, which we have available from the saved
             * write position.
             */
            if (readptr->eof_reached)
            {
                if (BufFileSeek(state->myfile,
                                state->writepos_file,
                                state->writepos_offset,
                                SEEK_SET) != 0)
                    elog(ERROR, "tuplestore seek failed");
            }
            else
            {
                if (BufFileSeek(state->myfile,
                                readptr->file,
                                readptr->offset,
                                SEEK_SET) != 0)
                    elog(ERROR, "tuplestore seek failed");
            }
            break;
        default:
            elog(ERROR, "invalid tuplestore state");
            break;
    }

    state->activeptr = ptr;
}

void tuplestore_set_eflags ( Tuplestorestate state,
int  eflags 
)

Definition at line 347 of file tuplestore.c.

References Tuplestorestate::eflags, TSReadPointer::eflags, elog, ERROR, i, Tuplestorestate::memtupcount, Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::status, and TSS_INMEM.

Referenced by begin_partition(), ExecInitCteScan(), and ExecMaterial().

{
    int         i;

    if (state->status != TSS_INMEM || state->memtupcount != 0)
        elog(ERROR, "too late to call tuplestore_set_eflags");

    state->readptrs[0].eflags = eflags;
    for (i = 1; i < state->readptrcount; i++)
        eflags |= state->readptrs[i].eflags;
    state->eflags = eflags;
}

void tuplestore_trim ( Tuplestorestate state  ) 

Definition at line 1238 of file tuplestore.c.

References Assert, TSReadPointer::current, Tuplestorestate::eflags, TSReadPointer::eof_reached, EXEC_FLAG_REWIND, FREEMEM, GetMemoryChunkSpace(), i, memmove, Tuplestorestate::memtupcount, Tuplestorestate::memtupdeleted, Tuplestorestate::memtuples, Min, pfree(), Tuplestorestate::readptrcount, Tuplestorestate::readptrs, Tuplestorestate::status, Tuplestorestate::truncated, and TSS_INMEM.

Referenced by ExecMaterialMarkPos(), and ExecWindowAgg().

{
    int         oldest;
    int         nremove;
    int         i;

    /*
     * Truncation is disallowed if any read pointer requires rewind
     * capability.
     */
    if (state->eflags & EXEC_FLAG_REWIND)
        return;

    /*
     * We don't bother trimming temp files since it usually would mean more
     * work than just letting them sit in kernel buffers until they age out.
     */
    if (state->status != TSS_INMEM)
        return;

    /* Find the oldest read pointer */
    oldest = state->memtupcount;
    for (i = 0; i < state->readptrcount; i++)
    {
        if (!state->readptrs[i].eof_reached)
            oldest = Min(oldest, state->readptrs[i].current);
    }

    /*
     * Note: you might think we could remove all the tuples before the oldest
     * "current", since that one is the next to be returned.  However, since
     * tuplestore_gettuple returns a direct pointer to our internal copy of
     * the tuple, it's likely that the caller has still got the tuple just
     * before "current" referenced in a slot. So we keep one extra tuple
     * before the oldest "current".  (Strictly speaking, we could require such
     * callers to use the "copy" flag to tuplestore_gettupleslot, but for
     * efficiency we allow this one case to not use "copy".)
     */
    nremove = oldest - 1;
    if (nremove <= 0)
        return;                 /* nothing to do */

    Assert(nremove >= state->memtupdeleted);
    Assert(nremove <= state->memtupcount);

    /* Release no-longer-needed tuples */
    for (i = state->memtupdeleted; i < nremove; i++)
    {
        FREEMEM(state, GetMemoryChunkSpace(state->memtuples[i]));
        pfree(state->memtuples[i]);
        state->memtuples[i] = NULL;
    }
    state->memtupdeleted = nremove;

    /* mark tuplestore as truncated (used for Assert crosschecks only) */
    state->truncated = true;

    /*
     * If nremove is less than 1/8th memtupcount, just stop here, leaving the
     * "deleted" slots as NULL.  This prevents us from expending O(N^2) time
     * repeatedly memmove-ing a large pointer array.  The worst case space
     * wastage is pretty small, since it's just pointers and not whole tuples.
     */
    if (nremove < state->memtupcount / 8)
        return;

    /*
     * Slide the array down and readjust pointers.
     *
     * In mergejoin's current usage, it's demonstrable that there will always
     * be exactly one non-removed tuple; so optimize that case.
     */
    if (nremove + 1 == state->memtupcount)
        state->memtuples[0] = state->memtuples[nremove];
    else
        memmove(state->memtuples, state->memtuples + nremove,
                (state->memtupcount - nremove) * sizeof(void *));

    state->memtupdeleted = 0;
    state->memtupcount -= nremove;
    for (i = 0; i < state->readptrcount; i++)
    {
        if (!state->readptrs[i].eof_reached)
            state->readptrs[i].current -= nremove;
    }
}

static void writetup_heap ( Tuplestorestate state,
void *  tup 
) [static]

Definition at line 1381 of file tuplestore.c.

References Tuplestorestate::backward, BufFileWrite(), elog, ERROR, FREEMEM, GetMemoryChunkSpace(), heap_free_minimal_tuple(), MINIMAL_TUPLE_DATA_OFFSET, Tuplestorestate::myfile, and MinimalTupleData::t_len.

{
    MinimalTuple tuple = (MinimalTuple) tup;

    /* the part of the MinimalTuple we'll write: */
    char       *tupbody = (char *) tuple + MINIMAL_TUPLE_DATA_OFFSET;
    unsigned int tupbodylen = tuple->t_len - MINIMAL_TUPLE_DATA_OFFSET;

    /* total on-disk footprint: */
    unsigned int tuplen = tupbodylen + sizeof(int);

    if (BufFileWrite(state->myfile, (void *) &tuplen,
                     sizeof(tuplen)) != sizeof(tuplen))
        elog(ERROR, "write failed");
    if (BufFileWrite(state->myfile, (void *) tupbody,
                     tupbodylen) != (size_t) tupbodylen)
        elog(ERROR, "write failed");
    if (state->backward)        /* need trailing length word? */
        if (BufFileWrite(state->myfile, (void *) &tuplen,
                         sizeof(tuplen)) != sizeof(tuplen))
            elog(ERROR, "write failed");

    FREEMEM(state, GetMemoryChunkSpace(tuple));
    heap_free_minimal_tuple(tuple);
}