Header And Logo

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

Functions

nodeMaterial.c File Reference

#include "postgres.h"
#include "executor/executor.h"
#include "executor/nodeMaterial.h"
#include "miscadmin.h"
Include dependency graph for nodeMaterial.c:

Go to the source code of this file.

Functions

TupleTableSlotExecMaterial (MaterialState *node)
MaterialStateExecInitMaterial (Material *node, EState *estate, int eflags)
void ExecEndMaterial (MaterialState *node)
void ExecMaterialMarkPos (MaterialState *node)
void ExecMaterialRestrPos (MaterialState *node)
void ExecReScanMaterial (MaterialState *node)

Function Documentation

void ExecEndMaterial ( MaterialState node  ) 

Definition at line 240 of file nodeMaterial.c.

References ExecClearTuple(), ExecEndNode(), NULL, outerPlanState, MaterialState::ss, ScanState::ss_ScanTupleSlot, tuplestore_end(), and MaterialState::tuplestorestate.

Referenced by ExecEndNode().

{
    /*
     * clean out the tuple table
     */
    ExecClearTuple(node->ss.ss_ScanTupleSlot);

    /*
     * Release tuplestore resources
     */
    if (node->tuplestorestate != NULL)
        tuplestore_end(node->tuplestorestate);
    node->tuplestorestate = NULL;

    /*
     * shut down the subplan
     */
    ExecEndNode(outerPlanState(node));
}

MaterialState* ExecInitMaterial ( Material node,
EState estate,
int  eflags 
)

Definition at line 163 of file nodeMaterial.c.

References MaterialState::eflags, MaterialState::eof_underlying, EXEC_FLAG_BACKWARD, EXEC_FLAG_REWIND, ExecAssignResultTypeFromTL(), ExecAssignScanTypeFromOuterPlan(), ExecInitNode(), ExecInitResultTupleSlot(), ExecInitScanTupleSlot(), makeNode, outerPlan, outerPlanState, PlanState::plan, ScanState::ps, PlanState::ps_ProjInfo, MaterialState::ss, PlanState::state, and MaterialState::tuplestorestate.

Referenced by ExecInitNode().

{
    MaterialState *matstate;
    Plan       *outerPlan;

    /*
     * create state structure
     */
    matstate = makeNode(MaterialState);
    matstate->ss.ps.plan = (Plan *) node;
    matstate->ss.ps.state = estate;

    /*
     * We must have a tuplestore buffering the subplan output to do backward
     * scan or mark/restore.  We also prefer to materialize the subplan output
     * if we might be called on to rewind and replay it many times. However,
     * if none of these cases apply, we can skip storing the data.
     */
    matstate->eflags = (eflags & (EXEC_FLAG_REWIND |
                                  EXEC_FLAG_BACKWARD |
                                  EXEC_FLAG_MARK));

    /*
     * Tuplestore's interpretation of the flag bits is subtly different from
     * the general executor meaning: it doesn't think BACKWARD necessarily
     * means "backwards all the way to start".  If told to support BACKWARD we
     * must include REWIND in the tuplestore eflags, else tuplestore_trim
     * might throw away too much.
     */
    if (eflags & EXEC_FLAG_BACKWARD)
        matstate->eflags |= EXEC_FLAG_REWIND;

    matstate->eof_underlying = false;
    matstate->tuplestorestate = NULL;

    /*
     * Miscellaneous initialization
     *
     * Materialization nodes don't need ExprContexts because they never call
     * ExecQual or ExecProject.
     */

    /*
     * tuple table initialization
     *
     * material nodes only return tuples from their materialized relation.
     */
    ExecInitResultTupleSlot(estate, &matstate->ss.ps);
    ExecInitScanTupleSlot(estate, &matstate->ss);

    /*
     * initialize child nodes
     *
     * We shield the child node from the need to support REWIND, BACKWARD, or
     * MARK/RESTORE.
     */
    eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK);

    outerPlan = outerPlan(node);
    outerPlanState(matstate) = ExecInitNode(outerPlan, estate, eflags);

    /*
     * initialize tuple type.  no need to initialize projection info because
     * this node doesn't do projections.
     */
    ExecAssignResultTypeFromTL(&matstate->ss.ps);
    ExecAssignScanTypeFromOuterPlan(&matstate->ss);
    matstate->ss.ps.ps_ProjInfo = NULL;

    return matstate;
}

TupleTableSlot* ExecMaterial ( MaterialState node  ) 

Definition at line 39 of file nodeMaterial.c.

References Assert, MaterialState::eflags, MaterialState::eof_underlying, EState::es_direction, EXEC_FLAG_MARK, ExecClearTuple(), ExecProcNode(), NULL, outerPlanState, ScanState::ps, PlanState::ps_ResultTupleSlot, ScanDirectionIsForward, MaterialState::ss, PlanState::state, TupIsNull, tuplestore_advance(), tuplestore_alloc_read_pointer(), tuplestore_ateof(), tuplestore_begin_heap(), tuplestore_gettupleslot(), tuplestore_puttupleslot(), tuplestore_set_eflags(), MaterialState::tuplestorestate, and work_mem.

Referenced by ExecProcNode().

{
    EState     *estate;
    ScanDirection dir;
    bool        forward;
    Tuplestorestate *tuplestorestate;
    bool        eof_tuplestore;
    TupleTableSlot *slot;

    /*
     * get state info from node
     */
    estate = node->ss.ps.state;
    dir = estate->es_direction;
    forward = ScanDirectionIsForward(dir);
    tuplestorestate = node->tuplestorestate;

    /*
     * If first time through, and we need a tuplestore, initialize it.
     */
    if (tuplestorestate == NULL && node->eflags != 0)
    {
        tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
        tuplestore_set_eflags(tuplestorestate, node->eflags);
        if (node->eflags & EXEC_FLAG_MARK)
        {
            /*
             * Allocate a second read pointer to serve as the mark. We know it
             * must have index 1, so needn't store that.
             */
            int ptrno   PG_USED_FOR_ASSERTS_ONLY;

            ptrno = tuplestore_alloc_read_pointer(tuplestorestate,
                                                  node->eflags);
            Assert(ptrno == 1);
        }
        node->tuplestorestate = tuplestorestate;
    }

    /*
     * If we are not at the end of the tuplestore, or are going backwards, try
     * to fetch a tuple from tuplestore.
     */
    eof_tuplestore = (tuplestorestate == NULL) ||
        tuplestore_ateof(tuplestorestate);

    if (!forward && eof_tuplestore)
    {
        if (!node->eof_underlying)
        {
            /*
             * When reversing direction at tuplestore EOF, the first
             * gettupleslot call will fetch the last-added tuple; but we want
             * to return the one before that, if possible. So do an extra
             * fetch.
             */
            if (!tuplestore_advance(tuplestorestate, forward))
                return NULL;    /* the tuplestore must be empty */
        }
        eof_tuplestore = false;
    }

    /*
     * If we can fetch another tuple from the tuplestore, return it.
     */
    slot = node->ss.ps.ps_ResultTupleSlot;
    if (!eof_tuplestore)
    {
        if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot))
            return slot;
        if (forward)
            eof_tuplestore = true;
    }

    /*
     * If necessary, try to fetch another row from the subplan.
     *
     * Note: the eof_underlying state variable exists to short-circuit further
     * subplan calls.  It's not optional, unfortunately, because some plan
     * node types are not robust about being called again when they've already
     * returned NULL.
     */
    if (eof_tuplestore && !node->eof_underlying)
    {
        PlanState  *outerNode;
        TupleTableSlot *outerslot;

        /*
         * We can only get here with forward==true, so no need to worry about
         * which direction the subplan will go.
         */
        outerNode = outerPlanState(node);
        outerslot = ExecProcNode(outerNode);
        if (TupIsNull(outerslot))
        {
            node->eof_underlying = true;
            return NULL;
        }

        /*
         * Append a copy of the returned tuple to tuplestore.  NOTE: because
         * the tuplestore is certainly in EOF state, its read position will
         * move forward over the added tuple.  This is what we want.
         */
        if (tuplestorestate)
            tuplestore_puttupleslot(tuplestorestate, outerslot);

        /*
         * We can just return the subplan's returned tuple, without copying.
         */
        return outerslot;
    }

    /*
     * Nothing left ...
     */
    return ExecClearTuple(slot);
}

void ExecMaterialMarkPos ( MaterialState node  ) 

Definition at line 267 of file nodeMaterial.c.

References Assert, MaterialState::eflags, EXEC_FLAG_MARK, tuplestore_copy_read_pointer(), tuplestore_trim(), and MaterialState::tuplestorestate.

Referenced by ExecMarkPos().

{
    Assert(node->eflags & EXEC_FLAG_MARK);

    /*
     * if we haven't materialized yet, just return.
     */
    if (!node->tuplestorestate)
        return;

    /*
     * copy the active read pointer to the mark.
     */
    tuplestore_copy_read_pointer(node->tuplestorestate, 0, 1);

    /*
     * since we may have advanced the mark, try to truncate the tuplestore.
     */
    tuplestore_trim(node->tuplestorestate);
}

void ExecMaterialRestrPos ( MaterialState node  ) 

Definition at line 295 of file nodeMaterial.c.

References Assert, MaterialState::eflags, EXEC_FLAG_MARK, tuplestore_copy_read_pointer(), and MaterialState::tuplestorestate.

Referenced by ExecRestrPos().

{
    Assert(node->eflags & EXEC_FLAG_MARK);

    /*
     * if we haven't materialized yet, just return.
     */
    if (!node->tuplestorestate)
        return;

    /*
     * copy the mark to the active read pointer.
     */
    tuplestore_copy_read_pointer(node->tuplestorestate, 1, 0);
}

void ExecReScanMaterial ( MaterialState node  ) 

Definition at line 318 of file nodeMaterial.c.

References PlanState::chgParam, MaterialState::eflags, MaterialState::eof_underlying, EXEC_FLAG_REWIND, ExecClearTuple(), ExecReScan(), PlanState::lefttree, NULL, ScanState::ps, PlanState::ps_ResultTupleSlot, MaterialState::ss, tuplestore_end(), tuplestore_rescan(), and MaterialState::tuplestorestate.

Referenced by ExecReScan().

{
    ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);

    if (node->eflags != 0)
    {
        /*
         * If we haven't materialized yet, just return. If outerplan's
         * chgParam is not NULL then it will be re-scanned by ExecProcNode,
         * else no reason to re-scan it at all.
         */
        if (!node->tuplestorestate)
            return;

        /*
         * If subnode is to be rescanned then we forget previous stored
         * results; we have to re-read the subplan and re-store.  Also, if we
         * told tuplestore it needn't support rescan, we lose and must
         * re-read.  (This last should not happen in common cases; else our
         * caller lied by not passing EXEC_FLAG_REWIND to us.)
         *
         * Otherwise we can just rewind and rescan the stored output. The
         * state of the subnode does not change.
         */
        if (node->ss.ps.lefttree->chgParam != NULL ||
            (node->eflags & EXEC_FLAG_REWIND) == 0)
        {
            tuplestore_end(node->tuplestorestate);
            node->tuplestorestate = NULL;
            if (node->ss.ps.lefttree->chgParam == NULL)
                ExecReScan(node->ss.ps.lefttree);
            node->eof_underlying = false;
        }
        else
            tuplestore_rescan(node->tuplestorestate);
    }
    else
    {
        /* In this case we are just passing on the subquery's output */

        /*
         * if chgParam of subnode is not null then plan will be re-scanned by
         * first ExecProcNode.
         */
        if (node->ss.ps.lefttree->chgParam == NULL)
            ExecReScan(node->ss.ps.lefttree);
        node->eof_underlying = false;
    }
}