Header And Logo

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

Functions

execScan.c File Reference

#include "postgres.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "utils/memutils.h"
Include dependency graph for execScan.c:

Go to the source code of this file.

Functions

static bool tlist_matches_tupdesc (PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
static TupleTableSlotExecScanFetch (ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
TupleTableSlotExecScan (ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
void ExecAssignScanProjectionInfo (ScanState *node)
void ExecScanReScan (ScanState *node)

Function Documentation

void ExecAssignScanProjectionInfo ( ScanState node  ) 
TupleTableSlot* ExecScan ( ScanState node,
ExecScanAccessMtd  accessMtd,
ExecScanRecheckMtd  recheckMtd 
)

Definition at line 108 of file execScan.c.

References Assert, CHECK_FOR_INTERRUPTS, ExprContext::ecxt_scantuple, ExecClearTuple(), ExecProject(), ExecQual(), ExecScanFetch(), ExprEndResult, ExprMultipleResult, InstrCountFiltered1, ProjectionInfo::pi_slot, ScanState::ps, PlanState::ps_ExprContext, PlanState::ps_ProjInfo, PlanState::ps_TupFromTlist, PlanState::qual, ResetExprContext, and TupIsNull.

Referenced by ExecBitmapHeapScan(), ExecCteScan(), ExecForeignScan(), ExecFunctionScan(), ExecIndexOnlyScan(), ExecIndexScan(), ExecSeqScan(), ExecSubqueryScan(), ExecTidScan(), ExecValuesScan(), and ExecWorkTableScan().

{
    ExprContext *econtext;
    List       *qual;
    ProjectionInfo *projInfo;
    ExprDoneCond isDone;
    TupleTableSlot *resultSlot;

    /*
     * Fetch data from node
     */
    qual = node->ps.qual;
    projInfo = node->ps.ps_ProjInfo;
    econtext = node->ps.ps_ExprContext;

    /*
     * If we have neither a qual to check nor a projection to do, just skip
     * all the overhead and return the raw scan tuple.
     */
    if (!qual && !projInfo)
    {
        ResetExprContext(econtext);
        return ExecScanFetch(node, accessMtd, recheckMtd);
    }

    /*
     * Check to see if we're still projecting out tuples from a previous scan
     * tuple (because there is a function-returning-set in the projection
     * expressions).  If so, try to project another one.
     */
    if (node->ps.ps_TupFromTlist)
    {
        Assert(projInfo);       /* can't get here if not projecting */
        resultSlot = ExecProject(projInfo, &isDone);
        if (isDone == ExprMultipleResult)
            return resultSlot;
        /* Done with that source tuple... */
        node->ps.ps_TupFromTlist = false;
    }

    /*
     * Reset per-tuple memory context to free any expression evaluation
     * storage allocated in the previous tuple cycle.  Note this can't happen
     * until we're done projecting out tuples from a scan tuple.
     */
    ResetExprContext(econtext);

    /*
     * get a tuple from the access method.  Loop until we obtain a tuple that
     * passes the qualification.
     */
    for (;;)
    {
        TupleTableSlot *slot;

        CHECK_FOR_INTERRUPTS();

        slot = ExecScanFetch(node, accessMtd, recheckMtd);

        /*
         * if the slot returned by the accessMtd contains NULL, then it means
         * there is nothing more to scan so we just return an empty slot,
         * being careful to use the projection result slot so it has correct
         * tupleDesc.
         */
        if (TupIsNull(slot))
        {
            if (projInfo)
                return ExecClearTuple(projInfo->pi_slot);
            else
                return slot;
        }

        /*
         * place the current tuple into the expr context
         */
        econtext->ecxt_scantuple = slot;

        /*
         * check that the current tuple satisfies the qual-clause
         *
         * check for non-nil qual here to avoid a function call to ExecQual()
         * when the qual is nil ... saves only a few cycles, but they add up
         * ...
         */
        if (!qual || ExecQual(qual, econtext, false))
        {
            /*
             * Found a satisfactory scan tuple.
             */
            if (projInfo)
            {
                /*
                 * Form a projection tuple, store it in the result tuple slot
                 * and return it --- unless we find we can project no tuples
                 * from this scan tuple, in which case continue scan.
                 */
                resultSlot = ExecProject(projInfo, &isDone);
                if (isDone != ExprEndResult)
                {
                    node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
                    return resultSlot;
                }
            }
            else
            {
                /*
                 * Here, we aren't projecting, so just return scan tuple.
                 */
                return slot;
            }
        }
        else
            InstrCountFiltered1(node, 1);

        /*
         * Tuple fails qual, so free per-tuple memory and try again.
         */
        ResetExprContext(econtext);
    }
}

static TupleTableSlot* ExecScanFetch ( ScanState node,
ExecScanAccessMtd  accessMtd,
ExecScanRecheckMtd  recheckMtd 
) [inline, static]

Definition at line 37 of file execScan.c.

References Assert, EState::es_epqScanDone, EState::es_epqTuple, EState::es_epqTupleSet, ExecClearTuple(), ExecStoreTuple(), InvalidBuffer, NULL, PlanState::plan, ScanState::ps, ScanState::ss_ScanTupleSlot, and PlanState::state.

Referenced by ExecScan().

{
    EState     *estate = node->ps.state;

    if (estate->es_epqTuple != NULL)
    {
        /*
         * We are inside an EvalPlanQual recheck.  Return the test tuple if
         * one is available, after rechecking any access-method-specific
         * conditions.
         */
        Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;

        Assert(scanrelid > 0);
        if (estate->es_epqTupleSet[scanrelid - 1])
        {
            TupleTableSlot *slot = node->ss_ScanTupleSlot;

            /* Return empty slot if we already returned a tuple */
            if (estate->es_epqScanDone[scanrelid - 1])
                return ExecClearTuple(slot);
            /* Else mark to remember that we shouldn't return more */
            estate->es_epqScanDone[scanrelid - 1] = true;

            /* Return empty slot if we haven't got a test tuple */
            if (estate->es_epqTuple[scanrelid - 1] == NULL)
                return ExecClearTuple(slot);

            /* Store test tuple in the plan node's scan slot */
            ExecStoreTuple(estate->es_epqTuple[scanrelid - 1],
                           slot, InvalidBuffer, false);

            /* Check if it meets the access-method conditions */
            if (!(*recheckMtd) (node, slot))
                ExecClearTuple(slot);   /* would not be returned by scan */

            return slot;
        }
    }

    /*
     * Run the node-type-specific access method function to get the next tuple
     */
    return (*accessMtd) (node);
}

void ExecScanReScan ( ScanState node  ) 

Definition at line 333 of file execScan.c.

References Assert, EState::es_epqScanDone, NULL, PlanState::plan, ScanState::ps, PlanState::ps_TupFromTlist, and PlanState::state.

Referenced by ExecReScanBitmapHeapScan(), ExecReScanCteScan(), ExecReScanForeignScan(), ExecReScanFunctionScan(), ExecReScanIndexOnlyScan(), ExecReScanIndexScan(), ExecReScanSeqScan(), ExecReScanSubqueryScan(), ExecReScanTidScan(), ExecReScanValuesScan(), and ExecReScanWorkTableScan().

{
    EState     *estate = node->ps.state;

    /* Stop projecting any tuples from SRFs in the targetlist */
    node->ps.ps_TupFromTlist = false;

    /* Rescan EvalPlanQual tuple if we're inside an EvalPlanQual recheck */
    if (estate->es_epqScanDone != NULL)
    {
        Index       scanrelid = ((Scan *) node->ps.plan)->scanrelid;

        Assert(scanrelid > 0);

        estate->es_epqScanDone[scanrelid - 1] = false;
    }
}

static bool tlist_matches_tupdesc ( PlanState ps,
List tlist,
Index  varno,
TupleDesc  tupdesc 
) [static]

Definition at line 268 of file execScan.c.

References Assert, tupleDesc::attrs, ExecContextForcesOids(), IsA, lfirst, list_head(), lnext, tupleDesc::natts, NULL, tupleDesc::tdhasoid, Var::varattno, Var::varlevelsup, Var::varno, Var::vartype, and Var::vartypmod.

Referenced by ExecAssignScanProjectionInfo().

{
    int         numattrs = tupdesc->natts;
    int         attrno;
    bool        hasoid;
    ListCell   *tlist_item = list_head(tlist);

    /* Check the tlist attributes */
    for (attrno = 1; attrno <= numattrs; attrno++)
    {
        Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1];
        Var        *var;

        if (tlist_item == NULL)
            return false;       /* tlist too short */
        var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
        if (!var || !IsA(var, Var))
            return false;       /* tlist item not a Var */
        /* if these Asserts fail, planner messed up */
        Assert(var->varno == varno);
        Assert(var->varlevelsup == 0);
        if (var->varattno != attrno)
            return false;       /* out of order */
        if (att_tup->attisdropped)
            return false;       /* table contains dropped columns */

        /*
         * Note: usually the Var's type should match the tupdesc exactly, but
         * in situations involving unions of columns that have different
         * typmods, the Var may have come from above the union and hence have
         * typmod -1.  This is a legitimate situation since the Var still
         * describes the column, just not as exactly as the tupdesc does. We
         * could change the planner to prevent it, but it'd then insert
         * projection steps just to convert from specific typmod to typmod -1,
         * which is pretty silly.
         */
        if (var->vartype != att_tup->atttypid ||
            (var->vartypmod != att_tup->atttypmod &&
             var->vartypmod != -1))
            return false;       /* type mismatch */

        tlist_item = lnext(tlist_item);
    }

    if (tlist_item)
        return false;           /* tlist too long */

    /*
     * If the plan context requires a particular hasoid setting, then that has
     * to match, too.
     */
    if (ExecContextForcesOids(ps, &hasoid) &&
        hasoid != tupdesc->tdhasoid)
        return false;

    return true;
}