Header And Logo

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

Functions | Variables

execMain.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/namespace.h"
#include "commands/trigger.h"
#include "executor/execdebug.h"
#include "foreign/fdwapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "utils/tqual.h"
Include dependency graph for execMain.c:

Go to the source code of this file.

Functions

static void InitPlan (QueryDesc *queryDesc, int eflags)
static void CheckValidRowMarkRel (Relation rel, RowMarkType markType)
static void ExecPostprocessPlan (EState *estate)
static void ExecEndPlan (PlanState *planstate, EState *estate)
static void ExecutePlan (EState *estate, PlanState *planstate, CmdType operation, bool sendTuples, long numberTuples, ScanDirection direction, DestReceiver *dest)
static bool ExecCheckRTEPerms (RangeTblEntry *rte)
static void ExecCheckXactReadOnly (PlannedStmt *plannedstmt)
static char * ExecBuildSlotValueDescription (TupleTableSlot *slot, int maxfieldlen)
static void EvalPlanQualStart (EPQState *epqstate, EState *parentestate, Plan *planTree)
void ExecutorStart (QueryDesc *queryDesc, int eflags)
void standard_ExecutorStart (QueryDesc *queryDesc, int eflags)
void ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, long count)
void standard_ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, long count)
void ExecutorFinish (QueryDesc *queryDesc)
void standard_ExecutorFinish (QueryDesc *queryDesc)
void ExecutorEnd (QueryDesc *queryDesc)
void standard_ExecutorEnd (QueryDesc *queryDesc)
void ExecutorRewind (QueryDesc *queryDesc)
bool ExecCheckRTPerms (List *rangeTable, bool ereport_on_violation)
void CheckValidResultRel (Relation resultRel, CmdType operation)
void InitResultRelInfo (ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, int instrument_options)
ResultRelInfoExecGetTriggerResultRel (EState *estate, Oid relid)
bool ExecContextForcesOids (PlanState *planstate, bool *hasoids)
static const char * ExecRelCheck (ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
void ExecConstraints (ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
ExecRowMarkExecFindRowMark (EState *estate, Index rti)
ExecAuxRowMarkExecBuildAuxRowMark (ExecRowMark *erm, List *targetlist)
TupleTableSlotEvalPlanQual (EState *estate, EPQState *epqstate, Relation relation, Index rti, int lockmode, ItemPointer tid, TransactionId priorXmax)
HeapTuple EvalPlanQualFetch (EState *estate, Relation relation, int lockmode, ItemPointer tid, TransactionId priorXmax)
void EvalPlanQualInit (EPQState *epqstate, EState *estate, Plan *subplan, List *auxrowmarks, int epqParam)
void EvalPlanQualSetPlan (EPQState *epqstate, Plan *subplan, List *auxrowmarks)
void EvalPlanQualSetTuple (EPQState *epqstate, Index rti, HeapTuple tuple)
HeapTuple EvalPlanQualGetTuple (EPQState *epqstate, Index rti)
void EvalPlanQualFetchRowMarks (EPQState *epqstate)
TupleTableSlotEvalPlanQualNext (EPQState *epqstate)
void EvalPlanQualBegin (EPQState *epqstate, EState *parentestate)
void EvalPlanQualEnd (EPQState *epqstate)

Variables

ExecutorStart_hook_type ExecutorStart_hook = NULL
ExecutorRun_hook_type ExecutorRun_hook = NULL
ExecutorFinish_hook_type ExecutorFinish_hook = NULL
ExecutorEnd_hook_type ExecutorEnd_hook = NULL
ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook = NULL

Function Documentation

void CheckValidResultRel ( Relation  resultRel,
CmdType  operation 
)

Definition at line 939 of file execMain.c.

References CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ereport, errcode(), errhint(), errmsg(), ERROR, FdwRoutine::ExecForeignDelete, FdwRoutine::ExecForeignInsert, FdwRoutine::ExecForeignUpdate, GetFdwRoutineForRelation(), NULL, RelationData::rd_rel, RelationGetRelationName, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_TOASTVALUE, RELKIND_VIEW, TriggerDesc::trig_delete_instead_row, TriggerDesc::trig_insert_instead_row, TriggerDesc::trig_update_instead_row, and RelationData::trigdesc.

Referenced by ExecInitModifyTable().

{
    TriggerDesc *trigDesc = resultRel->trigdesc;
    FdwRoutine *fdwroutine;

    switch (resultRel->rd_rel->relkind)
    {
        case RELKIND_RELATION:
            /* OK */
            break;
        case RELKIND_SEQUENCE:
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot change sequence \"%s\"",
                            RelationGetRelationName(resultRel))));
            break;
        case RELKIND_TOASTVALUE:
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot change TOAST relation \"%s\"",
                            RelationGetRelationName(resultRel))));
            break;
        case RELKIND_VIEW:
            /*
             * Okay only if there's a suitable INSTEAD OF trigger.  Messages
             * here should match rewriteHandler.c's rewriteTargetView, except
             * that we omit errdetail because we haven't got the information
             * handy (and given that we really shouldn't get here anyway,
             * it's not worth great exertion to get).
             */
            switch (operation)
            {
                case CMD_INSERT:
                    if (!trigDesc || !trigDesc->trig_insert_instead_row)
                        ereport(ERROR,
                          (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                           errmsg("cannot insert into view \"%s\"",
                                  RelationGetRelationName(resultRel)),
                           errhint("To make the view insertable, provide an unconditional ON INSERT DO INSTEAD rule or an INSTEAD OF INSERT trigger.")));
                    break;
                case CMD_UPDATE:
                    if (!trigDesc || !trigDesc->trig_update_instead_row)
                        ereport(ERROR,
                          (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                           errmsg("cannot update view \"%s\"",
                                  RelationGetRelationName(resultRel)),
                           errhint("To make the view updatable, provide an unconditional ON UPDATE DO INSTEAD rule or an INSTEAD OF UPDATE trigger.")));
                    break;
                case CMD_DELETE:
                    if (!trigDesc || !trigDesc->trig_delete_instead_row)
                        ereport(ERROR,
                          (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                           errmsg("cannot delete from view \"%s\"",
                                  RelationGetRelationName(resultRel)),
                           errhint("To make the view updatable, provide an unconditional ON DELETE DO INSTEAD rule or an INSTEAD OF DELETE trigger.")));
                    break;
                default:
                    elog(ERROR, "unrecognized CmdType: %d", (int) operation);
                    break;
            }
            break;
        case RELKIND_MATVIEW:
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot change materialized view \"%s\"",
                            RelationGetRelationName(resultRel))));
            break;
        case RELKIND_FOREIGN_TABLE:
            /* Okay only if the FDW supports it */
            fdwroutine = GetFdwRoutineForRelation(resultRel, false);
            switch (operation)
            {
                case CMD_INSERT:
                    if (fdwroutine->ExecForeignInsert == NULL)
                        ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("cannot insert into foreign table \"%s\"",
                                        RelationGetRelationName(resultRel))));
                    break;
                case CMD_UPDATE:
                    if (fdwroutine->ExecForeignUpdate == NULL)
                        ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("cannot update foreign table \"%s\"",
                                        RelationGetRelationName(resultRel))));
                    break;
                case CMD_DELETE:
                    if (fdwroutine->ExecForeignDelete == NULL)
                        ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("cannot delete from foreign table \"%s\"",
                                        RelationGetRelationName(resultRel))));
                    break;
                default:
                    elog(ERROR, "unrecognized CmdType: %d", (int) operation);
                    break;
            }
            break;
        default:
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot change relation \"%s\"",
                            RelationGetRelationName(resultRel))));
            break;
    }
}

static void CheckValidRowMarkRel ( Relation  rel,
RowMarkType  markType 
) [static]

Definition at line 1053 of file execMain.c.

References ereport, errcode(), errmsg(), ERROR, RelationData::rd_rel, RelationGetRelationName, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_TOASTVALUE, and RELKIND_VIEW.

Referenced by InitPlan().

{
    switch (rel->rd_rel->relkind)
    {
        case RELKIND_RELATION:
            /* OK */
            break;
        case RELKIND_SEQUENCE:
            /* Must disallow this because we don't vacuum sequences */
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot lock rows in sequence \"%s\"",
                            RelationGetRelationName(rel))));
            break;
        case RELKIND_TOASTVALUE:
            /* We could allow this, but there seems no good reason to */
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot lock rows in TOAST relation \"%s\"",
                            RelationGetRelationName(rel))));
            break;
        case RELKIND_VIEW:
            /* Should not get here; planner should have expanded the view */
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot lock rows in view \"%s\"",
                            RelationGetRelationName(rel))));
            break;
        case RELKIND_MATVIEW:
            /* Should not get here */
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot lock rows in materialized view \"%s\"",
                            RelationGetRelationName(rel))));
            break;
        case RELKIND_FOREIGN_TABLE:
            /* Should not get here */
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot lock rows in foreign table \"%s\"",
                            RelationGetRelationName(rel))));
            break;
        default:
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot lock rows in relation \"%s\"",
                            RelationGetRelationName(rel))));
            break;
    }
}

TupleTableSlot* EvalPlanQual ( EState estate,
EPQState epqstate,
Relation  relation,
Index  rti,
int  lockmode,
ItemPointer  tid,
TransactionId  priorXmax 
)

Definition at line 1765 of file execMain.c.

References Assert, EvalPlanQualBegin(), EvalPlanQualFetch(), EvalPlanQualFetchRowMarks(), EvalPlanQualNext(), EvalPlanQualSetTuple(), ExecMaterializeSlot(), NULL, HeapTupleData::t_self, and TupIsNull.

Referenced by ExecDelete(), ExecUpdate(), and GetTupleForTrigger().

{
    TupleTableSlot *slot;
    HeapTuple   copyTuple;

    Assert(rti > 0);

    /*
     * Get and lock the updated version of the row; if fail, return NULL.
     */
    copyTuple = EvalPlanQualFetch(estate, relation, lockmode,
                                  tid, priorXmax);

    if (copyTuple == NULL)
        return NULL;

    /*
     * For UPDATE/DELETE we have to return tid of actual row we're executing
     * PQ for.
     */
    *tid = copyTuple->t_self;

    /*
     * Need to run a recheck subquery.  Initialize or reinitialize EPQ state.
     */
    EvalPlanQualBegin(epqstate, estate);

    /*
     * Free old test tuple, if any, and store new tuple where relation's scan
     * node will see it
     */
    EvalPlanQualSetTuple(epqstate, rti, copyTuple);

    /*
     * Fetch any non-locked source rows
     */
    EvalPlanQualFetchRowMarks(epqstate);

    /*
     * Run the EPQ query.  We assume it will return at most one tuple.
     */
    slot = EvalPlanQualNext(epqstate);

    /*
     * If we got a tuple, force the slot to materialize the tuple so that it
     * is not dependent on any local state in the EPQ query (in particular,
     * it's highly likely that the slot contains references to any pass-by-ref
     * datums that may be present in copyTuple).  As with the next step, this
     * is to guard against early re-use of the EPQ query.
     */
    if (!TupIsNull(slot))
        (void) ExecMaterializeSlot(slot);

    /*
     * Clear out the test tuple.  This is needed in case the EPQ query is
     * re-used to test a tuple for a different relation.  (Not clear that can
     * really happen, but let's be safe.)
     */
    EvalPlanQualSetTuple(epqstate, rti, NULL);

    return slot;
}

void EvalPlanQualBegin ( EPQState epqstate,
EState parentestate 
)

Definition at line 2230 of file execMain.c.

References bms_add_member(), PlanState::chgParam, EPQState::epqParam, EState::es_epqScanDone, EState::es_param_exec_vals, EState::es_plannedstmt, EState::es_range_table, EPQState::estate, EvalPlanQualStart(), i, ParamExecData::isnull, list_length(), MemSet, PlannedStmt::nParamExec, NULL, EPQState::plan, EPQState::planstate, and ParamExecData::value.

Referenced by EvalPlanQual(), and ExecLockRows().

{
    EState     *estate = epqstate->estate;

    if (estate == NULL)
    {
        /* First time through, so create a child EState */
        EvalPlanQualStart(epqstate, parentestate, epqstate->plan);
    }
    else
    {
        /*
         * We already have a suitable child EPQ tree, so just reset it.
         */
        int         rtsize = list_length(parentestate->es_range_table);
        PlanState  *planstate = epqstate->planstate;

        MemSet(estate->es_epqScanDone, 0, rtsize * sizeof(bool));

        /* Recopy current values of parent parameters */
        if (parentestate->es_plannedstmt->nParamExec > 0)
        {
            int         i = parentestate->es_plannedstmt->nParamExec;

            while (--i >= 0)
            {
                /* copy value if any, but not execPlan link */
                estate->es_param_exec_vals[i].value =
                    parentestate->es_param_exec_vals[i].value;
                estate->es_param_exec_vals[i].isnull =
                    parentestate->es_param_exec_vals[i].isnull;
            }
        }

        /*
         * Mark child plan tree as needing rescan at all scan nodes.  The
         * first ExecProcNode will take care of actually doing the rescan.
         */
        planstate->chgParam = bms_add_member(planstate->chgParam,
                                             epqstate->epqParam);
    }
}

void EvalPlanQualEnd ( EPQState epqstate  ) 

Definition at line 2402 of file execMain.c.

References EState::es_query_cxt, EState::es_subplanstates, EState::es_trig_target_relations, EState::es_tupleTable, EPQState::estate, ExecCloseIndices(), ExecEndNode(), ExecResetTupleTable(), FreeExecutorState(), heap_close, lfirst, MemoryContextSwitchTo(), NoLock, NULL, EPQState::origslot, EPQState::planstate, and ResultRelInfo::ri_RelationDesc.

Referenced by EvalPlanQualSetPlan(), ExecEndLockRows(), and ExecEndModifyTable().

{
    EState     *estate = epqstate->estate;
    MemoryContext oldcontext;
    ListCell   *l;

    if (estate == NULL)
        return;                 /* idle, so nothing to do */

    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    ExecEndNode(epqstate->planstate);

    foreach(l, estate->es_subplanstates)
    {
        PlanState  *subplanstate = (PlanState *) lfirst(l);

        ExecEndNode(subplanstate);
    }

    /* throw away the per-estate tuple table */
    ExecResetTupleTable(estate->es_tupleTable, false);

    /* close any trigger target relations attached to this EState */
    foreach(l, estate->es_trig_target_relations)
    {
        ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);

        /* Close indices and then the relation itself */
        ExecCloseIndices(resultRelInfo);
        heap_close(resultRelInfo->ri_RelationDesc, NoLock);
    }

    MemoryContextSwitchTo(oldcontext);

    FreeExecutorState(estate);

    /* Mark EPQState idle */
    epqstate->estate = NULL;
    epqstate->planstate = NULL;
    epqstate->origslot = NULL;
}

HeapTuple EvalPlanQualFetch ( EState estate,
Relation  relation,
int  lockmode,
ItemPointer  tid,
TransactionId  priorXmax 
)

Definition at line 1848 of file execMain.c.

References HeapUpdateFailureData::ctid, elog, ereport, errcode(), errmsg(), ERROR, EState::es_output_cid, heap_copytuple(), heap_fetch(), heap_lock_tuple(), HeapTupleHeaderGetCmin(), HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleMayBeUpdated, HeapTupleSelfUpdated, HeapTupleUpdated, InitDirtySnapshot, IsolationUsesXactSnapshot, ItemPointerEquals(), NULL, ReleaseBuffer(), HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleData::t_self, TransactionIdEquals, TransactionIdIsCurrentTransactionId(), TransactionIdIsValid, XactLockTableWait(), HeapUpdateFailureData::xmax, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by EvalPlanQual(), and ExecLockRows().

{
    HeapTuple   copyTuple = NULL;
    HeapTupleData tuple;
    SnapshotData SnapshotDirty;

    /*
     * fetch target tuple
     *
     * Loop here to deal with updated or busy tuples
     */
    InitDirtySnapshot(SnapshotDirty);
    tuple.t_self = *tid;
    for (;;)
    {
        Buffer      buffer;

        if (heap_fetch(relation, &SnapshotDirty, &tuple, &buffer, true, NULL))
        {
            HTSU_Result test;
            HeapUpdateFailureData hufd;

            /*
             * If xmin isn't what we're expecting, the slot must have been
             * recycled and reused for an unrelated tuple.  This implies that
             * the latest version of the row was deleted, so we need do
             * nothing.  (Should be safe to examine xmin without getting
             * buffer's content lock, since xmin never changes in an existing
             * tuple.)
             */
            if (!TransactionIdEquals(HeapTupleHeaderGetXmin(tuple.t_data),
                                     priorXmax))
            {
                ReleaseBuffer(buffer);
                return NULL;
            }

            /* otherwise xmin should not be dirty... */
            if (TransactionIdIsValid(SnapshotDirty.xmin))
                elog(ERROR, "t_xmin is uncommitted in tuple to be updated");

            /*
             * If tuple is being updated by other transaction then we have to
             * wait for its commit/abort.
             */
            if (TransactionIdIsValid(SnapshotDirty.xmax))
            {
                ReleaseBuffer(buffer);
                XactLockTableWait(SnapshotDirty.xmax);
                continue;       /* loop back to repeat heap_fetch */
            }

            /*
             * If tuple was inserted by our own transaction, we have to check
             * cmin against es_output_cid: cmin >= current CID means our
             * command cannot see the tuple, so we should ignore it.
             * Otherwise heap_lock_tuple() will throw an error, and so would
             * any later attempt to update or delete the tuple.  (We need not
             * check cmax because HeapTupleSatisfiesDirty will consider a
             * tuple deleted by our transaction dead, regardless of cmax.)
             * Wee just checked that priorXmax == xmin, so we can test that
             * variable instead of doing HeapTupleHeaderGetXmin again.
             */
            if (TransactionIdIsCurrentTransactionId(priorXmax) &&
                HeapTupleHeaderGetCmin(tuple.t_data) >= estate->es_output_cid)
            {
                ReleaseBuffer(buffer);
                return NULL;
            }

            /*
             * This is a live tuple, so now try to lock it.
             */
            test = heap_lock_tuple(relation, &tuple,
                                   estate->es_output_cid,
                                   lockmode, false /* wait */,
                                   false, &buffer, &hufd);
            /* We now have two pins on the buffer, get rid of one */
            ReleaseBuffer(buffer);

            switch (test)
            {
                case HeapTupleSelfUpdated:
                    /*
                     * The target tuple was already updated or deleted by the
                     * current command, or by a later command in the current
                     * transaction.  We *must* ignore the tuple in the former
                     * case, so as to avoid the "Halloween problem" of
                     * repeated update attempts.  In the latter case it might
                     * be sensible to fetch the updated tuple instead, but
                     * doing so would require changing heap_lock_tuple as well
                     * as heap_update and heap_delete to not complain about
                     * updating "invisible" tuples, which seems pretty scary.
                     * So for now, treat the tuple as deleted and do not
                     * process.
                     */
                    ReleaseBuffer(buffer);
                    return NULL;

                case HeapTupleMayBeUpdated:
                    /* successfully locked */
                    break;

                case HeapTupleUpdated:
                    ReleaseBuffer(buffer);
                    if (IsolationUsesXactSnapshot())
                        ereport(ERROR,
                                (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
                                 errmsg("could not serialize access due to concurrent update")));
                    if (!ItemPointerEquals(&hufd.ctid, &tuple.t_self))
                    {
                        /* it was updated, so look at the updated version */
                        tuple.t_self = hufd.ctid;
                        /* updated row should have xmin matching this xmax */
                        priorXmax = hufd.xmax;
                        continue;
                    }
                    /* tuple was deleted, so give up */
                    return NULL;

                default:
                    ReleaseBuffer(buffer);
                    elog(ERROR, "unrecognized heap_lock_tuple status: %u",
                         test);
                    return NULL;    /* keep compiler quiet */
            }

            /*
             * We got tuple - now copy it for use by recheck query.
             */
            copyTuple = heap_copytuple(&tuple);
            ReleaseBuffer(buffer);
            break;
        }

        /*
         * If the referenced slot was actually empty, the latest version of
         * the row must have been deleted, so we need do nothing.
         */
        if (tuple.t_data == NULL)
        {
            ReleaseBuffer(buffer);
            return NULL;
        }

        /*
         * As above, if xmin isn't what we're expecting, do nothing.
         */
        if (!TransactionIdEquals(HeapTupleHeaderGetXmin(tuple.t_data),
                                 priorXmax))
        {
            ReleaseBuffer(buffer);
            return NULL;
        }

        /*
         * If we get here, the tuple was found but failed SnapshotDirty.
         * Assuming the xmin is either a committed xact or our own xact (as it
         * certainly should be if we're trying to modify the tuple), this must
         * mean that the row was updated or deleted by either a committed xact
         * or our own xact.  If it was deleted, we can ignore it; if it was
         * updated then chain up to the next version and repeat the whole
         * process.
         *
         * As above, it should be safe to examine xmax and t_ctid without the
         * buffer content lock, because they can't be changing.
         */
        if (ItemPointerEquals(&tuple.t_self, &tuple.t_data->t_ctid))
        {
            /* deleted, so forget about it */
            ReleaseBuffer(buffer);
            return NULL;
        }

        /* updated, so look at the updated row */
        tuple.t_self = tuple.t_data->t_ctid;
        /* updated row should have xmin matching this xmax */
        priorXmax = HeapTupleHeaderGetUpdateXid(tuple.t_data);
        ReleaseBuffer(buffer);
        /* loop back to fetch next in chain */
    }

    /*
     * Return the copied tuple
     */
    return copyTuple;
}

void EvalPlanQualFetchRowMarks ( EPQState epqstate  ) 

Definition at line 2115 of file execMain.c.

References EPQState::arowMarks, Assert, ExecAuxRowMark::ctidAttNo, DatumGetHeapTupleHeader, DatumGetObjectId, DatumGetPointer, elog, ERROR, EvalPlanQualSetTuple(), ExecGetJunkAttribute(), heap_copytuple(), heap_fetch(), HeapTupleHeaderGetDatumLength, ItemPointerSetInvalid, lfirst, ExecRowMark::markType, NULL, EPQState::origslot, ExecRowMark::prti, ExecRowMark::relation, RelationGetRelid, ReleaseBuffer(), ROW_MARK_COPY, ROW_MARK_REFERENCE, ExecAuxRowMark::rowmark, RowMarkRequiresRowShareLock, ExecRowMark::rti, SnapshotAny, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, ExecAuxRowMark::toidAttNo, and ExecAuxRowMark::wholeAttNo.

Referenced by EvalPlanQual(), and ExecLockRows().

{
    ListCell   *l;

    Assert(epqstate->origslot != NULL);

    foreach(l, epqstate->arowMarks)
    {
        ExecAuxRowMark *aerm = (ExecAuxRowMark *) lfirst(l);
        ExecRowMark *erm = aerm->rowmark;
        Datum       datum;
        bool        isNull;
        HeapTupleData tuple;

        if (RowMarkRequiresRowShareLock(erm->markType))
            elog(ERROR, "EvalPlanQual doesn't support locking rowmarks");

        /* clear any leftover test tuple for this rel */
        EvalPlanQualSetTuple(epqstate, erm->rti, NULL);

        if (erm->relation)
        {
            Buffer      buffer;

            Assert(erm->markType == ROW_MARK_REFERENCE);

            /* if child rel, must check whether it produced this row */
            if (erm->rti != erm->prti)
            {
                Oid         tableoid;

                datum = ExecGetJunkAttribute(epqstate->origslot,
                                             aerm->toidAttNo,
                                             &isNull);
                /* non-locked rels could be on the inside of outer joins */
                if (isNull)
                    continue;
                tableoid = DatumGetObjectId(datum);

                if (tableoid != RelationGetRelid(erm->relation))
                {
                    /* this child is inactive right now */
                    continue;
                }
            }

            /* fetch the tuple's ctid */
            datum = ExecGetJunkAttribute(epqstate->origslot,
                                         aerm->ctidAttNo,
                                         &isNull);
            /* non-locked rels could be on the inside of outer joins */
            if (isNull)
                continue;
            tuple.t_self = *((ItemPointer) DatumGetPointer(datum));

            /* okay, fetch the tuple */
            if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
                            false, NULL))
                elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");

            /* successful, copy and store tuple */
            EvalPlanQualSetTuple(epqstate, erm->rti,
                                 heap_copytuple(&tuple));
            ReleaseBuffer(buffer);
        }
        else
        {
            HeapTupleHeader td;

            Assert(erm->markType == ROW_MARK_COPY);

            /* fetch the whole-row Var for the relation */
            datum = ExecGetJunkAttribute(epqstate->origslot,
                                         aerm->wholeAttNo,
                                         &isNull);
            /* non-locked rels could be on the inside of outer joins */
            if (isNull)
                continue;
            td = DatumGetHeapTupleHeader(datum);

            /* build a temporary HeapTuple control structure */
            tuple.t_len = HeapTupleHeaderGetDatumLength(td);
            ItemPointerSetInvalid(&(tuple.t_self));
            tuple.t_tableOid = InvalidOid;
            tuple.t_data = td;

            /* copy and store tuple */
            EvalPlanQualSetTuple(epqstate, erm->rti,
                                 heap_copytuple(&tuple));
        }
    }
}

HeapTuple EvalPlanQualGetTuple ( EPQState epqstate,
Index  rti 
)

Definition at line 2100 of file execMain.c.

References Assert, EState::es_epqTuple, and EPQState::estate.

Referenced by ExecLockRows().

{
    EState     *estate = epqstate->estate;

    Assert(rti > 0);

    return estate->es_epqTuple[rti - 1];
}

void EvalPlanQualInit ( EPQState epqstate,
EState estate,
Plan subplan,
List auxrowmarks,
int  epqParam 
)

Definition at line 2045 of file execMain.c.

References EPQState::arowMarks, EPQState::epqParam, EPQState::estate, EPQState::origslot, EPQState::plan, and EPQState::planstate.

Referenced by ExecInitLockRows(), and ExecInitModifyTable().

{
    /* Mark the EPQ state inactive */
    epqstate->estate = NULL;
    epqstate->planstate = NULL;
    epqstate->origslot = NULL;
    /* ... and remember data that EvalPlanQualBegin will need */
    epqstate->plan = subplan;
    epqstate->arowMarks = auxrowmarks;
    epqstate->epqParam = epqParam;
}

TupleTableSlot* EvalPlanQualNext ( EPQState epqstate  ) 

Definition at line 2214 of file execMain.c.

References EState::es_query_cxt, EPQState::estate, ExecProcNode(), MemoryContextSwitchTo(), and EPQState::planstate.

Referenced by EvalPlanQual(), and ExecLockRows().

{
    MemoryContext oldcontext;
    TupleTableSlot *slot;

    oldcontext = MemoryContextSwitchTo(epqstate->estate->es_query_cxt);
    slot = ExecProcNode(epqstate->planstate);
    MemoryContextSwitchTo(oldcontext);

    return slot;
}

void EvalPlanQualSetPlan ( EPQState epqstate,
Plan subplan,
List auxrowmarks 
)

Definition at line 2064 of file execMain.c.

References EPQState::arowMarks, EvalPlanQualEnd(), and EPQState::plan.

Referenced by ExecInitModifyTable(), and ExecModifyTable().

{
    /* If we have a live EPQ query, shut it down */
    EvalPlanQualEnd(epqstate);
    /* And set/change the plan pointer */
    epqstate->plan = subplan;
    /* The rowmarks depend on the plan, too */
    epqstate->arowMarks = auxrowmarks;
}

void EvalPlanQualSetTuple ( EPQState epqstate,
Index  rti,
HeapTuple  tuple 
)

Definition at line 2080 of file execMain.c.

References Assert, EState::es_epqTuple, EState::es_epqTupleSet, EPQState::estate, heap_freetuple(), and NULL.

Referenced by EvalPlanQual(), EvalPlanQualFetchRowMarks(), and ExecLockRows().

{
    EState     *estate = epqstate->estate;

    Assert(rti > 0);

    /*
     * free old test tuple, if any, and store new tuple where relation's scan
     * node will see it
     */
    if (estate->es_epqTuple[rti - 1] != NULL)
        heap_freetuple(estate->es_epqTuple[rti - 1]);
    estate->es_epqTuple[rti - 1] = tuple;
    estate->es_epqTupleSet[rti - 1] = true;
}

static void EvalPlanQualStart ( EPQState epqstate,
EState parentestate,
Plan planTree 
) [static]

Definition at line 2280 of file execMain.c.

References Assert, CreateExecutorState(), EState::es_crosscheck_snapshot, EState::es_direction, EState::es_epqScanDone, EState::es_epqTuple, EState::es_epqTupleSet, EState::es_instrument, EState::es_junkFilter, EState::es_num_result_relations, EState::es_output_cid, EState::es_param_exec_vals, EState::es_param_list_info, EState::es_plannedstmt, EState::es_query_cxt, EState::es_range_table, EState::es_result_relation_info, EState::es_result_relations, EState::es_rowMarks, EState::es_snapshot, EState::es_subplanstates, EState::es_top_eflags, EState::es_tupleTable, EPQState::estate, ExecInitNode(), i, ParamExecData::isnull, lappend(), lfirst, list_length(), MemoryContextSwitchTo(), NIL, PlannedStmt::nParamExec, NULL, palloc0(), EPQState::planstate, PlannedStmt::subplans, and ParamExecData::value.

Referenced by EvalPlanQualBegin().

{
    EState     *estate;
    int         rtsize;
    MemoryContext oldcontext;
    ListCell   *l;

    rtsize = list_length(parentestate->es_range_table);

    epqstate->estate = estate = CreateExecutorState();

    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    /*
     * Child EPQ EStates share the parent's copy of unchanging state such as
     * the snapshot, rangetable, result-rel info, and external Param info.
     * They need their own copies of local state, including a tuple table,
     * es_param_exec_vals, etc.
     */
    estate->es_direction = ForwardScanDirection;
    estate->es_snapshot = parentestate->es_snapshot;
    estate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot;
    estate->es_range_table = parentestate->es_range_table;
    estate->es_plannedstmt = parentestate->es_plannedstmt;
    estate->es_junkFilter = parentestate->es_junkFilter;
    estate->es_output_cid = parentestate->es_output_cid;
    estate->es_result_relations = parentestate->es_result_relations;
    estate->es_num_result_relations = parentestate->es_num_result_relations;
    estate->es_result_relation_info = parentestate->es_result_relation_info;
    /* es_trig_target_relations must NOT be copied */
    estate->es_rowMarks = parentestate->es_rowMarks;
    estate->es_top_eflags = parentestate->es_top_eflags;
    estate->es_instrument = parentestate->es_instrument;
    /* es_auxmodifytables must NOT be copied */

    /*
     * The external param list is simply shared from parent.  The internal
     * param workspace has to be local state, but we copy the initial values
     * from the parent, so as to have access to any param values that were
     * already set from other parts of the parent's plan tree.
     */
    estate->es_param_list_info = parentestate->es_param_list_info;
    if (parentestate->es_plannedstmt->nParamExec > 0)
    {
        int         i = parentestate->es_plannedstmt->nParamExec;

        estate->es_param_exec_vals = (ParamExecData *)
            palloc0(i * sizeof(ParamExecData));
        while (--i >= 0)
        {
            /* copy value if any, but not execPlan link */
            estate->es_param_exec_vals[i].value =
                parentestate->es_param_exec_vals[i].value;
            estate->es_param_exec_vals[i].isnull =
                parentestate->es_param_exec_vals[i].isnull;
        }
    }

    /*
     * Each EState must have its own es_epqScanDone state, but if we have
     * nested EPQ checks they should share es_epqTuple arrays.  This allows
     * sub-rechecks to inherit the values being examined by an outer recheck.
     */
    estate->es_epqScanDone = (bool *) palloc0(rtsize * sizeof(bool));
    if (parentestate->es_epqTuple != NULL)
    {
        estate->es_epqTuple = parentestate->es_epqTuple;
        estate->es_epqTupleSet = parentestate->es_epqTupleSet;
    }
    else
    {
        estate->es_epqTuple = (HeapTuple *)
            palloc0(rtsize * sizeof(HeapTuple));
        estate->es_epqTupleSet = (bool *)
            palloc0(rtsize * sizeof(bool));
    }

    /*
     * Each estate also has its own tuple table.
     */
    estate->es_tupleTable = NIL;

    /*
     * Initialize private state information for each SubPlan.  We must do this
     * before running ExecInitNode on the main query tree, since
     * ExecInitSubPlan expects to be able to find these entries. Some of the
     * SubPlans might not be used in the part of the plan tree we intend to
     * run, but since it's not easy to tell which, we just initialize them
     * all.
     */
    Assert(estate->es_subplanstates == NIL);
    foreach(l, parentestate->es_plannedstmt->subplans)
    {
        Plan       *subplan = (Plan *) lfirst(l);
        PlanState  *subplanstate;

        subplanstate = ExecInitNode(subplan, estate, 0);
        estate->es_subplanstates = lappend(estate->es_subplanstates,
                                           subplanstate);
    }

    /*
     * Initialize the private state information for all the nodes in the part
     * of the plan tree we need to run.  This opens files, allocates storage
     * and leaves us ready to start processing tuples.
     */
    epqstate->planstate = ExecInitNode(planTree, estate, 0);

    MemoryContextSwitchTo(oldcontext);
}

ExecAuxRowMark* ExecBuildAuxRowMark ( ExecRowMark erm,
List targetlist 
)

Definition at line 1691 of file execMain.c.

References Assert, AttributeNumberIsValid, ExecAuxRowMark::ctidAttNo, elog, ERROR, ExecFindJunkAttributeInTlist(), ExecRowMark::markType, palloc0(), ExecRowMark::prti, ExecRowMark::relation, ROW_MARK_COPY, ExecAuxRowMark::rowmark, ExecRowMark::rowmarkId, ExecRowMark::rti, snprintf(), ExecAuxRowMark::toidAttNo, and ExecAuxRowMark::wholeAttNo.

Referenced by ExecInitLockRows(), and ExecInitModifyTable().

{
    ExecAuxRowMark *aerm = (ExecAuxRowMark *) palloc0(sizeof(ExecAuxRowMark));
    char        resname[32];

    aerm->rowmark = erm;

    /* Look up the resjunk columns associated with this rowmark */
    if (erm->relation)
    {
        Assert(erm->markType != ROW_MARK_COPY);

        /* if child rel, need tableoid */
        if (erm->rti != erm->prti)
        {
            snprintf(resname, sizeof(resname), "tableoid%u", erm->rowmarkId);
            aerm->toidAttNo = ExecFindJunkAttributeInTlist(targetlist,
                                                           resname);
            if (!AttributeNumberIsValid(aerm->toidAttNo))
                elog(ERROR, "could not find junk %s column", resname);
        }

        /* always need ctid for real relations */
        snprintf(resname, sizeof(resname), "ctid%u", erm->rowmarkId);
        aerm->ctidAttNo = ExecFindJunkAttributeInTlist(targetlist,
                                                       resname);
        if (!AttributeNumberIsValid(aerm->ctidAttNo))
            elog(ERROR, "could not find junk %s column", resname);
    }
    else
    {
        Assert(erm->markType == ROW_MARK_COPY);

        snprintf(resname, sizeof(resname), "wholerow%u", erm->rowmarkId);
        aerm->wholeAttNo = ExecFindJunkAttributeInTlist(targetlist,
                                                        resname);
        if (!AttributeNumberIsValid(aerm->wholeAttNo))
            elog(ERROR, "could not find junk %s column", resname);
    }

    return aerm;
}

static char * ExecBuildSlotValueDescription ( TupleTableSlot slot,
int  maxfieldlen 
) [static]

Definition at line 1613 of file execMain.c.

References appendBinaryStringInfo(), appendStringInfoChar(), appendStringInfoString(), tupleDesc::attrs, buf, StringInfoData::data, getTypeOutputInfo(), i, initStringInfo(), tupleDesc::natts, OidOutputFunctionCall(), pg_mbcliplen(), slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, TupleTableSlot::tts_values, and val.

Referenced by ExecConstraints().

{
    StringInfoData buf;
    TupleDesc   tupdesc = slot->tts_tupleDescriptor;
    int         i;

    /* Make sure the tuple is fully deconstructed */
    slot_getallattrs(slot);

    initStringInfo(&buf);

    appendStringInfoChar(&buf, '(');

    for (i = 0; i < tupdesc->natts; i++)
    {
        char       *val;
        int         vallen;

        if (slot->tts_isnull[i])
            val = "null";
        else
        {
            Oid         foutoid;
            bool        typisvarlena;

            getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
                              &foutoid, &typisvarlena);
            val = OidOutputFunctionCall(foutoid, slot->tts_values[i]);
        }

        if (i > 0)
            appendStringInfoString(&buf, ", ");

        /* truncate if needed */
        vallen = strlen(val);
        if (vallen <= maxfieldlen)
            appendStringInfoString(&buf, val);
        else
        {
            vallen = pg_mbcliplen(val, vallen, maxfieldlen);
            appendBinaryStringInfo(&buf, val, vallen);
            appendStringInfoString(&buf, "...");
        }
    }

    appendStringInfoChar(&buf, ')');

    return buf.data;
}

static bool ExecCheckRTEPerms ( RangeTblEntry rte  )  [static]

Definition at line 535 of file execMain.c.

References ACL_INSERT, ACL_SELECT, ACL_UPDATE, ACLCHECK_OK, ACLMASK_ALL, ACLMASK_ANY, bms_copy(), bms_first_member(), bms_free(), bms_is_empty(), RangeTblEntry::checkAsUser, elog, ERROR, GetUserId(), InvalidAttrNumber, RangeTblEntry::modifiedCols, pg_attribute_aclcheck(), pg_attribute_aclcheck_all(), pg_class_aclmask(), RangeTblEntry::relid, RangeTblEntry::requiredPerms, RTE_RELATION, RangeTblEntry::rtekind, and RangeTblEntry::selectedCols.

Referenced by ExecCheckRTPerms().

{
    AclMode     requiredPerms;
    AclMode     relPerms;
    AclMode     remainingPerms;
    Oid         relOid;
    Oid         userid;
    Bitmapset  *tmpset;
    int         col;

    /*
     * Only plain-relation RTEs need to be checked here.  Function RTEs are
     * checked by init_fcache when the function is prepared for execution.
     * Join, subquery, and special RTEs need no checks.
     */
    if (rte->rtekind != RTE_RELATION)
        return true;

    /*
     * No work if requiredPerms is empty.
     */
    requiredPerms = rte->requiredPerms;
    if (requiredPerms == 0)
        return true;

    relOid = rte->relid;

    /*
     * userid to check as: current user unless we have a setuid indication.
     *
     * Note: GetUserId() is presently fast enough that there's no harm in
     * calling it separately for each RTE.  If that stops being true, we could
     * call it once in ExecCheckRTPerms and pass the userid down from there.
     * But for now, no need for the extra clutter.
     */
    userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();

    /*
     * We must have *all* the requiredPerms bits, but some of the bits can be
     * satisfied from column-level rather than relation-level permissions.
     * First, remove any bits that are satisfied by relation permissions.
     */
    relPerms = pg_class_aclmask(relOid, userid, requiredPerms, ACLMASK_ALL);
    remainingPerms = requiredPerms & ~relPerms;
    if (remainingPerms != 0)
    {
        /*
         * If we lack any permissions that exist only as relation permissions,
         * we can fail straight away.
         */
        if (remainingPerms & ~(ACL_SELECT | ACL_INSERT | ACL_UPDATE))
            return false;

        /*
         * Check to see if we have the needed privileges at column level.
         *
         * Note: failures just report a table-level error; it would be nicer
         * to report a column-level error if we have some but not all of the
         * column privileges.
         */
        if (remainingPerms & ACL_SELECT)
        {
            /*
             * When the query doesn't explicitly reference any columns (for
             * example, SELECT COUNT(*) FROM table), allow the query if we
             * have SELECT on any column of the rel, as per SQL spec.
             */
            if (bms_is_empty(rte->selectedCols))
            {
                if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
                                              ACLMASK_ANY) != ACLCHECK_OK)
                    return false;
            }

            tmpset = bms_copy(rte->selectedCols);
            while ((col = bms_first_member(tmpset)) >= 0)
            {
                /* remove the column number offset */
                col += FirstLowInvalidHeapAttributeNumber;
                if (col == InvalidAttrNumber)
                {
                    /* Whole-row reference, must have priv on all cols */
                    if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
                                                  ACLMASK_ALL) != ACLCHECK_OK)
                        return false;
                }
                else
                {
                    if (pg_attribute_aclcheck(relOid, col, userid,
                                              ACL_SELECT) != ACLCHECK_OK)
                        return false;
                }
            }
            bms_free(tmpset);
        }

        /*
         * Basically the same for the mod columns, with either INSERT or
         * UPDATE privilege as specified by remainingPerms.
         */
        remainingPerms &= ~ACL_SELECT;
        if (remainingPerms != 0)
        {
            /*
             * When the query doesn't explicitly change any columns, allow the
             * query if we have permission on any column of the rel.  This is
             * to handle SELECT FOR UPDATE as well as possible corner cases in
             * INSERT and UPDATE.
             */
            if (bms_is_empty(rte->modifiedCols))
            {
                if (pg_attribute_aclcheck_all(relOid, userid, remainingPerms,
                                              ACLMASK_ANY) != ACLCHECK_OK)
                    return false;
            }

            tmpset = bms_copy(rte->modifiedCols);
            while ((col = bms_first_member(tmpset)) >= 0)
            {
                /* remove the column number offset */
                col += FirstLowInvalidHeapAttributeNumber;
                if (col == InvalidAttrNumber)
                {
                    /* whole-row reference can't happen here */
                    elog(ERROR, "whole-row update is not implemented");
                }
                else
                {
                    if (pg_attribute_aclcheck(relOid, col, userid,
                                              remainingPerms) != ACLCHECK_OK)
                        return false;
                }
            }
            bms_free(tmpset);
        }
    }
    return true;
}

bool ExecCheckRTPerms ( List rangeTable,
bool  ereport_on_violation 
)

Definition at line 504 of file execMain.c.

References ACL_KIND_CLASS, aclcheck_error(), ACLCHECK_NO_PRIV, Assert, ExecCheckRTEPerms(), ExecutorCheckPerms_hook, get_rel_name(), lfirst, RangeTblEntry::relid, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by DoCopy(), InitPlan(), intorel_startup(), and RI_Initial_Check().

{
    ListCell   *l;
    bool        result = true;

    foreach(l, rangeTable)
    {
        RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);

        result = ExecCheckRTEPerms(rte);
        if (!result)
        {
            Assert(rte->rtekind == RTE_RELATION);
            if (ereport_on_violation)
                aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
                               get_rel_name(rte->relid));
            return false;
        }
    }

    if (ExecutorCheckPerms_hook)
        result = (*ExecutorCheckPerms_hook) (rangeTable,
                                             ereport_on_violation);
    return result;
}

static void ExecCheckXactReadOnly ( PlannedStmt plannedstmt  )  [static]

Definition at line 682 of file execMain.c.

References ACL_SELECT, CreateCommandTag(), get_rel_namespace(), isTempNamespace(), lfirst, PreventCommandIfReadOnly(), RangeTblEntry::relid, RangeTblEntry::requiredPerms, PlannedStmt::rtable, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by standard_ExecutorStart().

{
    ListCell   *l;

    /* Fail if write permissions are requested on any non-temp table */
    foreach(l, plannedstmt->rtable)
    {
        RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);

        if (rte->rtekind != RTE_RELATION)
            continue;

        if ((rte->requiredPerms & (~ACL_SELECT)) == 0)
            continue;

        if (isTempNamespace(get_rel_namespace(rte->relid)))
            continue;

        PreventCommandIfReadOnly(CreateCommandTag((Node *) plannedstmt));
    }
}

void ExecConstraints ( ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate 
)

Definition at line 1562 of file execMain.c.

References Assert, tupleDesc::attrs, tupleDesc::constr, ereport, errcode(), errdetail(), errmsg(), ERROR, errtablecol(), errtableconstraint(), ExecBuildSlotValueDescription(), ExecRelCheck(), tupleConstr::has_not_null, NameStr, tupleDesc::natts, NULL, tupleConstr::num_check, RelationData::rd_att, RelationGetRelationName, ResultRelInfo::ri_RelationDesc, and slot_attisnull().

Referenced by CopyFrom(), ExecInsert(), and ExecUpdate().

{
    Relation    rel = resultRelInfo->ri_RelationDesc;
    TupleConstr *constr = rel->rd_att->constr;

    Assert(constr);

    if (constr->has_not_null)
    {
        int         natts = rel->rd_att->natts;
        int         attrChk;

        for (attrChk = 1; attrChk <= natts; attrChk++)
        {
            if (rel->rd_att->attrs[attrChk - 1]->attnotnull &&
                slot_attisnull(slot, attrChk))
                ereport(ERROR,
                        (errcode(ERRCODE_NOT_NULL_VIOLATION),
                         errmsg("null value in column \"%s\" violates not-null constraint",
                          NameStr(rel->rd_att->attrs[attrChk - 1]->attname)),
                         errdetail("Failing row contains %s.",
                                   ExecBuildSlotValueDescription(slot, 64)),
                         errtablecol(rel, attrChk)));
        }
    }

    if (constr->num_check > 0)
    {
        const char *failed;

        if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_CHECK_VIOLATION),
                     errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
                            RelationGetRelationName(rel), failed),
                     errdetail("Failing row contains %s.",
                               ExecBuildSlotValueDescription(slot, 64)),
                     errtableconstraint(rel, failed)));
    }
}

bool ExecContextForcesOids ( PlanState planstate,
bool hasoids 
)

Definition at line 1259 of file execMain.c.

References EState::es_result_relation_info, EState::es_top_eflags, EXEC_FLAG_WITH_OIDS, EXEC_FLAG_WITHOUT_OIDS, NULL, RelationData::rd_rel, ResultRelInfo::ri_RelationDesc, and PlanState::state.

Referenced by ExecAssignResultTypeFromTL(), and tlist_matches_tupdesc().

{
    ResultRelInfo *ri = planstate->state->es_result_relation_info;

    if (ri != NULL)
    {
        Relation    rel = ri->ri_RelationDesc;

        if (rel != NULL)
        {
            *hasoids = rel->rd_rel->relhasoids;
            return true;
        }
    }

    if (planstate->state->es_top_eflags & EXEC_FLAG_WITH_OIDS)
    {
        *hasoids = true;
        return true;
    }
    if (planstate->state->es_top_eflags & EXEC_FLAG_WITHOUT_OIDS)
    {
        *hasoids = false;
        return true;
    }

    return false;
}

static void ExecEndPlan ( PlanState planstate,
EState estate 
) [static]

Definition at line 1341 of file execMain.c.

References EState::es_num_result_relations, EState::es_result_relations, EState::es_rowMarks, EState::es_subplanstates, EState::es_trig_target_relations, EState::es_tupleTable, ExecCloseIndices(), ExecEndNode(), ExecResetTupleTable(), heap_close, i, lfirst, NoLock, ExecRowMark::relation, and ResultRelInfo::ri_RelationDesc.

Referenced by standard_ExecutorEnd().

{
    ResultRelInfo *resultRelInfo;
    int         i;
    ListCell   *l;

    /*
     * shut down the node-type-specific query processing
     */
    ExecEndNode(planstate);

    /*
     * for subplans too
     */
    foreach(l, estate->es_subplanstates)
    {
        PlanState  *subplanstate = (PlanState *) lfirst(l);

        ExecEndNode(subplanstate);
    }

    /*
     * destroy the executor's tuple table.  Actually we only care about
     * releasing buffer pins and tupdesc refcounts; there's no need to pfree
     * the TupleTableSlots, since the containing memory context is about to go
     * away anyway.
     */
    ExecResetTupleTable(estate->es_tupleTable, false);

    /*
     * close the result relation(s) if any, but hold locks until xact commit.
     */
    resultRelInfo = estate->es_result_relations;
    for (i = estate->es_num_result_relations; i > 0; i--)
    {
        /* Close indices and then the relation itself */
        ExecCloseIndices(resultRelInfo);
        heap_close(resultRelInfo->ri_RelationDesc, NoLock);
        resultRelInfo++;
    }

    /*
     * likewise close any trigger target relations
     */
    foreach(l, estate->es_trig_target_relations)
    {
        resultRelInfo = (ResultRelInfo *) lfirst(l);
        /* Close indices and then the relation itself */
        ExecCloseIndices(resultRelInfo);
        heap_close(resultRelInfo->ri_RelationDesc, NoLock);
    }

    /*
     * close any relations selected FOR [KEY] UPDATE/SHARE, again keeping locks
     */
    foreach(l, estate->es_rowMarks)
    {
        ExecRowMark *erm = (ExecRowMark *) lfirst(l);

        if (erm->relation)
            heap_close(erm->relation, NoLock);
    }
}

ExecRowMark* ExecFindRowMark ( EState estate,
Index  rti 
)

Definition at line 1668 of file execMain.c.

References elog, ERROR, EState::es_rowMarks, lfirst, and ExecRowMark::rti.

Referenced by ExecInitLockRows(), and ExecInitModifyTable().

{
    ListCell   *lc;

    foreach(lc, estate->es_rowMarks)
    {
        ExecRowMark *erm = (ExecRowMark *) lfirst(lc);

        if (erm->rti == rti)
            return erm;
    }
    elog(ERROR, "failed to find ExecRowMark for rangetable index %u", rti);
    return NULL;                /* keep compiler quiet */
}

ResultRelInfo* ExecGetTriggerResultRel ( EState estate,
Oid  relid 
)

Definition at line 1170 of file execMain.c.

References EState::es_instrument, EState::es_num_result_relations, EState::es_query_cxt, EState::es_result_relations, EState::es_trig_target_relations, heap_open(), InitResultRelInfo(), lappend(), lfirst, makeNode, MemoryContextSwitchTo(), NoLock, RelationGetRelid, and ResultRelInfo::ri_RelationDesc.

Referenced by afterTriggerInvokeEvents().

{
    ResultRelInfo *rInfo;
    int         nr;
    ListCell   *l;
    Relation    rel;
    MemoryContext oldcontext;

    /* First, search through the query result relations */
    rInfo = estate->es_result_relations;
    nr = estate->es_num_result_relations;
    while (nr > 0)
    {
        if (RelationGetRelid(rInfo->ri_RelationDesc) == relid)
            return rInfo;
        rInfo++;
        nr--;
    }
    /* Nope, but maybe we already made an extra ResultRelInfo for it */
    foreach(l, estate->es_trig_target_relations)
    {
        rInfo = (ResultRelInfo *) lfirst(l);
        if (RelationGetRelid(rInfo->ri_RelationDesc) == relid)
            return rInfo;
    }
    /* Nope, so we need a new one */

    /*
     * Open the target relation's relcache entry.  We assume that an
     * appropriate lock is still held by the backend from whenever the trigger
     * event got queued, so we need take no new lock here.  Also, we need not
     * recheck the relkind, so no need for CheckValidResultRel.
     */
    rel = heap_open(relid, NoLock);

    /*
     * Make the new entry in the right context.
     */
    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
    rInfo = makeNode(ResultRelInfo);
    InitResultRelInfo(rInfo,
                      rel,
                      0,        /* dummy rangetable index */
                      estate->es_instrument);
    estate->es_trig_target_relations =
        lappend(estate->es_trig_target_relations, rInfo);
    MemoryContextSwitchTo(oldcontext);

    /*
     * Currently, we don't need any index information in ResultRelInfos used
     * only for triggers, so no need to call ExecOpenIndices.
     */

    return rInfo;
}

static void ExecPostprocessPlan ( EState estate  )  [static]

Definition at line 1295 of file execMain.c.

References EState::es_auxmodifytables, EState::es_direction, ExecProcNode(), lfirst, ResetPerTupleExprContext, and TupIsNull.

Referenced by standard_ExecutorFinish().

{
    ListCell   *lc;

    /*
     * Make sure nodes run forward.
     */
    estate->es_direction = ForwardScanDirection;

    /*
     * Run any secondary ModifyTable nodes to completion, in case the main
     * query did not fetch all rows from them.  (We do this to ensure that
     * such nodes have predictable results.)
     */
    foreach(lc, estate->es_auxmodifytables)
    {
        PlanState  *ps = (PlanState *) lfirst(lc);

        for (;;)
        {
            TupleTableSlot *slot;

            /* Reset the per-output-tuple exprcontext each time */
            ResetPerTupleExprContext(estate);

            slot = ExecProcNode(ps);

            if (TupIsNull(slot))
                break;
        }
    }
}

static const char* ExecRelCheck ( ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate 
) [static]

Definition at line 1503 of file execMain.c.

References constrCheck::ccname, tupleConstr::check, tupleDesc::constr, ExprContext::ecxt_scantuple, EState::es_query_cxt, ExecPrepareExpr(), ExecQual(), GetPerTupleExprContext, i, make_ands_implicit(), MemoryContextSwitchTo(), NULL, tupleConstr::num_check, palloc(), RelationData::rd_att, ResultRelInfo::ri_ConstraintExprs, ResultRelInfo::ri_RelationDesc, and stringToNode().

Referenced by ExecConstraints().

{
    Relation    rel = resultRelInfo->ri_RelationDesc;
    int         ncheck = rel->rd_att->constr->num_check;
    ConstrCheck *check = rel->rd_att->constr->check;
    ExprContext *econtext;
    MemoryContext oldContext;
    List       *qual;
    int         i;

    /*
     * If first time through for this result relation, build expression
     * nodetrees for rel's constraint expressions.  Keep them in the per-query
     * memory context so they'll survive throughout the query.
     */
    if (resultRelInfo->ri_ConstraintExprs == NULL)
    {
        oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
        resultRelInfo->ri_ConstraintExprs =
            (List **) palloc(ncheck * sizeof(List *));
        for (i = 0; i < ncheck; i++)
        {
            /* ExecQual wants implicit-AND form */
            qual = make_ands_implicit(stringToNode(check[i].ccbin));
            resultRelInfo->ri_ConstraintExprs[i] = (List *)
                ExecPrepareExpr((Expr *) qual, estate);
        }
        MemoryContextSwitchTo(oldContext);
    }

    /*
     * We will use the EState's per-tuple context for evaluating constraint
     * expressions (creating it if it's not already there).
     */
    econtext = GetPerTupleExprContext(estate);

    /* Arrange for econtext's scan tuple to be the tuple under test */
    econtext->ecxt_scantuple = slot;

    /* And evaluate the constraints */
    for (i = 0; i < ncheck; i++)
    {
        qual = resultRelInfo->ri_ConstraintExprs[i];

        /*
         * NOTE: SQL specifies that a NULL result from a constraint
         * expression is not to be treated as a failure.  Therefore, tell
         * ExecQual to return TRUE for NULL.
         */
        if (!ExecQual(qual, econtext, true))
            return check[i].ccname;
    }

    /* NULL result means no error */
    return NULL;
}

static void ExecutePlan ( EState estate,
PlanState planstate,
CmdType  operation,
bool  sendTuples,
long  numberTuples,
ScanDirection  direction,
DestReceiver dest 
) [static]

Definition at line 1418 of file execMain.c.

References CMD_SELECT, EState::es_direction, EState::es_junkFilter, EState::es_processed, ExecFilterJunk(), ExecProcNode(), NULL, _DestReceiver::receiveSlot, ResetPerTupleExprContext, and TupIsNull.

Referenced by standard_ExecutorRun().

{
    TupleTableSlot *slot;
    long        current_tuple_count;

    /*
     * initialize local variables
     */
    current_tuple_count = 0;

    /*
     * Set the direction.
     */
    estate->es_direction = direction;

    /*
     * Loop until we've processed the proper number of tuples from the plan.
     */
    for (;;)
    {
        /* Reset the per-output-tuple exprcontext */
        ResetPerTupleExprContext(estate);

        /*
         * Execute the plan and obtain a tuple
         */
        slot = ExecProcNode(planstate);

        /*
         * if the tuple is null, then we assume there is nothing more to
         * process so we just end the loop...
         */
        if (TupIsNull(slot))
            break;

        /*
         * If we have a junk filter, then project a new tuple with the junk
         * removed.
         *
         * Store this new "clean" tuple in the junkfilter's resultSlot.
         * (Formerly, we stored it back over the "dirty" tuple, which is WRONG
         * because that tuple slot has the wrong descriptor.)
         */
        if (estate->es_junkFilter != NULL)
            slot = ExecFilterJunk(estate->es_junkFilter, slot);

        /*
         * If we are supposed to send the tuple somewhere, do so. (In
         * practice, this is probably always the case at this point.)
         */
        if (sendTuples)
            (*dest->receiveSlot) (slot, dest);

        /*
         * Count tuples processed, if this is a SELECT.  (For other operation
         * types, the ModifyTable plan node must count the appropriate
         * events.)
         */
        if (operation == CMD_SELECT)
            (estate->es_processed)++;

        /*
         * check our tuple count.. if we've processed the proper number then
         * quit, else loop again and process more tuples.  Zero numberTuples
         * means no limit.
         */
        current_tuple_count++;
        if (numberTuples && numberTuples == current_tuple_count)
            break;
    }
}

void ExecutorEnd ( QueryDesc queryDesc  ) 
void ExecutorFinish ( QueryDesc queryDesc  ) 
void ExecutorRewind ( QueryDesc queryDesc  ) 

Definition at line 467 of file execMain.c.

References Assert, CMD_SELECT, EState::es_query_cxt, QueryDesc::estate, ExecReScan(), MemoryContextSwitchTo(), NULL, QueryDesc::operation, and QueryDesc::planstate.

Referenced by DoPortalRewind(), and PersistHoldablePortal().

{
    EState     *estate;
    MemoryContext oldcontext;

    /* sanity checks */
    Assert(queryDesc != NULL);

    estate = queryDesc->estate;

    Assert(estate != NULL);

    /* It's probably not sensible to rescan updating queries */
    Assert(queryDesc->operation == CMD_SELECT);

    /*
     * Switch into per-query memory context
     */
    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    /*
     * rescan plan
     */
    ExecReScan(queryDesc->planstate);

    MemoryContextSwitchTo(oldcontext);
}

void ExecutorRun ( QueryDesc queryDesc,
ScanDirection  direction,
long  count 
)

Definition at line 248 of file execMain.c.

References ExecutorRun_hook, and standard_ExecutorRun().

Referenced by _SPI_pquery(), CopyTo(), ExecCreateTableAs(), execute_sql_string(), ExplainOnePlan(), PersistHoldablePortal(), PortalRunSelect(), postquel_getnext(), ProcessQuery(), and refresh_matview_datafill().

{
    if (ExecutorRun_hook)
        (*ExecutorRun_hook) (queryDesc, direction, count);
    else
        standard_ExecutorRun(queryDesc, direction, count);
}

void ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)

Definition at line 115 of file execMain.c.

References ExecutorStart_hook, and standard_ExecutorStart().

Referenced by _SPI_pquery(), BeginCopy(), ExecCreateTableAs(), execute_sql_string(), ExplainOnePlan(), PortalStart(), postquel_start(), ProcessQuery(), and refresh_matview_datafill().

{
    if (ExecutorStart_hook)
        (*ExecutorStart_hook) (queryDesc, eflags);
    else
        standard_ExecutorStart(queryDesc, eflags);
}

static void InitPlan ( QueryDesc queryDesc,
int  eflags 
) [static]

Definition at line 713 of file execMain.c.

References AccessShareLock, Assert, bms_is_member(), CheckValidRowMarkRel(), CMD_SELECT, ExecRowMark::curCtid, elog, ERROR, EState::es_epqScanDone, EState::es_epqTuple, EState::es_epqTupleSet, EState::es_instrument, EState::es_junkFilter, EState::es_num_result_relations, EState::es_plannedstmt, EState::es_range_table, EState::es_result_relation_info, EState::es_result_relations, EState::es_rowMarks, EState::es_subplanstates, EState::es_trig_newtup_slot, EState::es_trig_oldtup_slot, EState::es_trig_tuple_slot, EState::es_tupleTable, QueryDesc::estate, EXEC_FLAG_REWIND, ExecCheckRTPerms(), ExecGetResultType(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitNode(), getrelid, heap_open(), i, InitResultRelInfo(), PlanRowMark::isParent, ItemPointerSetInvalid, JunkFilter::jf_cleanTupType, lappend(), lfirst, lfirst_int, list_length(), ExecRowMark::markType, PlanRowMark::markType, NIL, PlanRowMark::noWait, ExecRowMark::noWait, QueryDesc::operation, palloc(), PlanState::plan, QueryDesc::plannedstmt, QueryDesc::planstate, PlannedStmt::planTree, PlanRowMark::prti, ExecRowMark::prti, ExecRowMark::relation, TargetEntry::resjunk, PlannedStmt::resultRelations, PlannedStmt::rewindPlanIDs, ROW_MARK_COPY, ROW_MARK_EXCLUSIVE, ROW_MARK_KEYSHARE, ROW_MARK_NOKEYEXCLUSIVE, ROW_MARK_REFERENCE, ROW_MARK_SHARE, RowExclusiveLock, PlanRowMark::rowmarkId, ExecRowMark::rowmarkId, PlannedStmt::rowMarks, RowShareLock, PlannedStmt::rtable, ExecRowMark::rti, PlanRowMark::rti, PlannedStmt::subplans, Plan::targetlist, tupleDesc::tdhasoid, and QueryDesc::tupDesc.

Referenced by standard_ExecutorStart().

{
    CmdType     operation = queryDesc->operation;
    PlannedStmt *plannedstmt = queryDesc->plannedstmt;
    Plan       *plan = plannedstmt->planTree;
    List       *rangeTable = plannedstmt->rtable;
    EState     *estate = queryDesc->estate;
    PlanState  *planstate;
    TupleDesc   tupType;
    ListCell   *l;
    int         i;

    /*
     * Do permissions checks
     */
    ExecCheckRTPerms(rangeTable, true);

    /*
     * initialize the node's execution state
     */
    estate->es_range_table = rangeTable;
    estate->es_plannedstmt = plannedstmt;

    /*
     * initialize result relation stuff, and open/lock the result rels.
     *
     * We must do this before initializing the plan tree, else we might try to
     * do a lock upgrade if a result rel is also a source rel.
     */
    if (plannedstmt->resultRelations)
    {
        List       *resultRelations = plannedstmt->resultRelations;
        int         numResultRelations = list_length(resultRelations);
        ResultRelInfo *resultRelInfos;
        ResultRelInfo *resultRelInfo;

        resultRelInfos = (ResultRelInfo *)
            palloc(numResultRelations * sizeof(ResultRelInfo));
        resultRelInfo = resultRelInfos;
        foreach(l, resultRelations)
        {
            Index       resultRelationIndex = lfirst_int(l);
            Oid         resultRelationOid;
            Relation    resultRelation;

            resultRelationOid = getrelid(resultRelationIndex, rangeTable);
            resultRelation = heap_open(resultRelationOid, RowExclusiveLock);
            InitResultRelInfo(resultRelInfo,
                              resultRelation,
                              resultRelationIndex,
                              estate->es_instrument);
            resultRelInfo++;
        }
        estate->es_result_relations = resultRelInfos;
        estate->es_num_result_relations = numResultRelations;
        /* es_result_relation_info is NULL except when within ModifyTable */
        estate->es_result_relation_info = NULL;
    }
    else
    {
        /*
         * if no result relation, then set state appropriately
         */
        estate->es_result_relations = NULL;
        estate->es_num_result_relations = 0;
        estate->es_result_relation_info = NULL;
    }

    /*
     * Similarly, we have to lock relations selected FOR [KEY] UPDATE/SHARE
     * before we initialize the plan tree, else we'd be risking lock upgrades.
     * While we are at it, build the ExecRowMark list.
     */
    estate->es_rowMarks = NIL;
    foreach(l, plannedstmt->rowMarks)
    {
        PlanRowMark *rc = (PlanRowMark *) lfirst(l);
        Oid         relid;
        Relation    relation;
        ExecRowMark *erm;

        /* ignore "parent" rowmarks; they are irrelevant at runtime */
        if (rc->isParent)
            continue;

        switch (rc->markType)
        {
            case ROW_MARK_EXCLUSIVE:
            case ROW_MARK_NOKEYEXCLUSIVE:
            case ROW_MARK_SHARE:
            case ROW_MARK_KEYSHARE:
                relid = getrelid(rc->rti, rangeTable);
                relation = heap_open(relid, RowShareLock);
                break;
            case ROW_MARK_REFERENCE:
                relid = getrelid(rc->rti, rangeTable);
                relation = heap_open(relid, AccessShareLock);
                break;
            case ROW_MARK_COPY:
                /* there's no real table here ... */
                relation = NULL;
                break;
            default:
                elog(ERROR, "unrecognized markType: %d", rc->markType);
                relation = NULL;    /* keep compiler quiet */
                break;
        }

        /* Check that relation is a legal target for marking */
        if (relation)
            CheckValidRowMarkRel(relation, rc->markType);

        erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
        erm->relation = relation;
        erm->rti = rc->rti;
        erm->prti = rc->prti;
        erm->rowmarkId = rc->rowmarkId;
        erm->markType = rc->markType;
        erm->noWait = rc->noWait;
        ItemPointerSetInvalid(&(erm->curCtid));
        estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
    }

    /*
     * Initialize the executor's tuple table to empty.
     */
    estate->es_tupleTable = NIL;
    estate->es_trig_tuple_slot = NULL;
    estate->es_trig_oldtup_slot = NULL;
    estate->es_trig_newtup_slot = NULL;

    /* mark EvalPlanQual not active */
    estate->es_epqTuple = NULL;
    estate->es_epqTupleSet = NULL;
    estate->es_epqScanDone = NULL;

    /*
     * Initialize private state information for each SubPlan.  We must do this
     * before running ExecInitNode on the main query tree, since
     * ExecInitSubPlan expects to be able to find these entries.
     */
    Assert(estate->es_subplanstates == NIL);
    i = 1;                      /* subplan indices count from 1 */
    foreach(l, plannedstmt->subplans)
    {
        Plan       *subplan = (Plan *) lfirst(l);
        PlanState  *subplanstate;
        int         sp_eflags;

        /*
         * A subplan will never need to do BACKWARD scan nor MARK/RESTORE. If
         * it is a parameterless subplan (not initplan), we suggest that it be
         * prepared to handle REWIND efficiently; otherwise there is no need.
         */
        sp_eflags = eflags & EXEC_FLAG_EXPLAIN_ONLY;
        if (bms_is_member(i, plannedstmt->rewindPlanIDs))
            sp_eflags |= EXEC_FLAG_REWIND;

        subplanstate = ExecInitNode(subplan, estate, sp_eflags);

        estate->es_subplanstates = lappend(estate->es_subplanstates,
                                           subplanstate);

        i++;
    }

    /*
     * Initialize the private state information for all the nodes in the query
     * tree.  This opens files, allocates storage and leaves us ready to start
     * processing tuples.
     */
    planstate = ExecInitNode(plan, estate, eflags);

    /*
     * Get the tuple descriptor describing the type of tuples to return.
     */
    tupType = ExecGetResultType(planstate);

    /*
     * Initialize the junk filter if needed.  SELECT queries need a filter if
     * there are any junk attrs in the top-level tlist.
     */
    if (operation == CMD_SELECT)
    {
        bool        junk_filter_needed = false;
        ListCell   *tlist;

        foreach(tlist, plan->targetlist)
        {
            TargetEntry *tle = (TargetEntry *) lfirst(tlist);

            if (tle->resjunk)
            {
                junk_filter_needed = true;
                break;
            }
        }

        if (junk_filter_needed)
        {
            JunkFilter *j;

            j = ExecInitJunkFilter(planstate->plan->targetlist,
                                   tupType->tdhasoid,
                                   ExecInitExtraTupleSlot(estate));
            estate->es_junkFilter = j;

            /* Want to return the cleaned tuple type */
            tupType = j->jf_cleanTupType;
        }
    }

    queryDesc->tupDesc = tupType;
    queryDesc->planstate = planstate;
}

void InitResultRelInfo ( ResultRelInfo resultRelInfo,
Relation  resultRelationDesc,
Index  resultRelationIndex,
int  instrument_options 
)

Definition at line 1112 of file execMain.c.

References CopyTriggerDesc(), GetFdwRoutineForRelation(), InstrAlloc(), MemSet, TriggerDesc::numtriggers, palloc0(), RelationData::rd_rel, RELKIND_FOREIGN_TABLE, ResultRelInfo::ri_ConstraintExprs, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_FdwState, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_IndexRelationInfo, ResultRelInfo::ri_junkFilter, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, ResultRelInfo::ri_TrigWhenExprs, RelationData::trigdesc, and ResultRelInfo::type.

Referenced by CopyFrom(), ExecGetTriggerResultRel(), ExecuteTruncate(), and InitPlan().

{
    MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
    resultRelInfo->type = T_ResultRelInfo;
    resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
    resultRelInfo->ri_RelationDesc = resultRelationDesc;
    resultRelInfo->ri_NumIndices = 0;
    resultRelInfo->ri_IndexRelationDescs = NULL;
    resultRelInfo->ri_IndexRelationInfo = NULL;
    /* make a copy so as not to depend on relcache info not changing... */
    resultRelInfo->ri_TrigDesc = CopyTriggerDesc(resultRelationDesc->trigdesc);
    if (resultRelInfo->ri_TrigDesc)
    {
        int         n = resultRelInfo->ri_TrigDesc->numtriggers;

        resultRelInfo->ri_TrigFunctions = (FmgrInfo *)
            palloc0(n * sizeof(FmgrInfo));
        resultRelInfo->ri_TrigWhenExprs = (List **)
            palloc0(n * sizeof(List *));
        if (instrument_options)
            resultRelInfo->ri_TrigInstrument = InstrAlloc(n, instrument_options);
    }
    else
    {
        resultRelInfo->ri_TrigFunctions = NULL;
        resultRelInfo->ri_TrigWhenExprs = NULL;
        resultRelInfo->ri_TrigInstrument = NULL;
    }
    if (resultRelationDesc->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
        resultRelInfo->ri_FdwRoutine = GetFdwRoutineForRelation(resultRelationDesc, true);
    else
        resultRelInfo->ri_FdwRoutine = NULL;
    resultRelInfo->ri_FdwState = NULL;
    resultRelInfo->ri_ConstraintExprs = NULL;
    resultRelInfo->ri_junkFilter = NULL;
    resultRelInfo->ri_projectReturning = NULL;
}

void standard_ExecutorEnd ( QueryDesc queryDesc  ) 

Definition at line 410 of file execMain.c.

References Assert, EState::es_crosscheck_snapshot, EState::es_finished, EState::es_query_cxt, EState::es_snapshot, EState::es_top_eflags, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, ExecEndPlan(), FreeExecutorState(), MemoryContextSwitchTo(), NULL, QueryDesc::planstate, QueryDesc::totaltime, QueryDesc::tupDesc, and UnregisterSnapshot().

Referenced by ExecutorEnd(), explain_ExecutorEnd(), and pgss_ExecutorEnd().

{
    EState     *estate;
    MemoryContext oldcontext;

    /* sanity checks */
    Assert(queryDesc != NULL);

    estate = queryDesc->estate;

    Assert(estate != NULL);

    /*
     * Check that ExecutorFinish was called, unless in EXPLAIN-only mode. This
     * Assert is needed because ExecutorFinish is new as of 9.1, and callers
     * might forget to call it.
     */
    Assert(estate->es_finished ||
           (estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY));

    /*
     * Switch into per-query memory context to run ExecEndPlan
     */
    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    ExecEndPlan(queryDesc->planstate, estate);

    /* do away with our snapshots */
    UnregisterSnapshot(estate->es_snapshot);
    UnregisterSnapshot(estate->es_crosscheck_snapshot);

    /*
     * Must switch out of context before destroying it
     */
    MemoryContextSwitchTo(oldcontext);

    /*
     * Release EState and per-query memory context.  This should release
     * everything the executor has allocated.
     */
    FreeExecutorState(estate);

    /* Reset queryDesc fields that no longer point to anything */
    queryDesc->tupDesc = NULL;
    queryDesc->estate = NULL;
    queryDesc->planstate = NULL;
    queryDesc->totaltime = NULL;
}

void standard_ExecutorFinish ( QueryDesc queryDesc  ) 

Definition at line 350 of file execMain.c.

References AfterTriggerEndQuery(), Assert, EState::es_finished, EState::es_query_cxt, EState::es_top_eflags, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_SKIP_TRIGGERS, ExecPostprocessPlan(), InstrStartNode(), InstrStopNode(), MemoryContextSwitchTo(), NULL, and QueryDesc::totaltime.

Referenced by ExecutorFinish(), explain_ExecutorFinish(), and pgss_ExecutorFinish().

{
    EState     *estate;
    MemoryContext oldcontext;

    /* sanity checks */
    Assert(queryDesc != NULL);

    estate = queryDesc->estate;

    Assert(estate != NULL);
    Assert(!(estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY));

    /* This should be run once and only once per Executor instance */
    Assert(!estate->es_finished);

    /* Switch into per-query memory context */
    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    /* Allow instrumentation of Executor overall runtime */
    if (queryDesc->totaltime)
        InstrStartNode(queryDesc->totaltime);

    /* Run ModifyTable nodes to completion */
    ExecPostprocessPlan(estate);

    /* Execute queued AFTER triggers, unless told not to */
    if (!(estate->es_top_eflags & EXEC_FLAG_SKIP_TRIGGERS))
        AfterTriggerEndQuery(estate);

    if (queryDesc->totaltime)
        InstrStopNode(queryDesc->totaltime, 0);

    MemoryContextSwitchTo(oldcontext);

    estate->es_finished = true;
}

void standard_ExecutorRun ( QueryDesc queryDesc,
ScanDirection  direction,
long  count 
)

Definition at line 258 of file execMain.c.

References Assert, CMD_SELECT, QueryDesc::dest, EState::es_lastoid, EState::es_processed, EState::es_query_cxt, EState::es_top_eflags, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, ExecutePlan(), PlannedStmt::hasReturning, InstrStartNode(), InstrStopNode(), MemoryContextSwitchTo(), NULL, QueryDesc::operation, QueryDesc::plannedstmt, QueryDesc::planstate, _DestReceiver::rShutdown, _DestReceiver::rStartup, ScanDirectionIsNoMovement, QueryDesc::totaltime, and QueryDesc::tupDesc.

Referenced by ExecutorRun(), explain_ExecutorRun(), and pgss_ExecutorRun().

{
    EState     *estate;
    CmdType     operation;
    DestReceiver *dest;
    bool        sendTuples;
    MemoryContext oldcontext;

    /* sanity checks */
    Assert(queryDesc != NULL);

    estate = queryDesc->estate;

    Assert(estate != NULL);
    Assert(!(estate->es_top_eflags & EXEC_FLAG_EXPLAIN_ONLY));

    /*
     * Switch into per-query memory context
     */
    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    /* Allow instrumentation of Executor overall runtime */
    if (queryDesc->totaltime)
        InstrStartNode(queryDesc->totaltime);

    /*
     * extract information from the query descriptor and the query feature.
     */
    operation = queryDesc->operation;
    dest = queryDesc->dest;

    /*
     * startup tuple receiver, if we will be emitting tuples
     */
    estate->es_processed = 0;
    estate->es_lastoid = InvalidOid;

    sendTuples = (operation == CMD_SELECT ||
                  queryDesc->plannedstmt->hasReturning);

    if (sendTuples)
        (*dest->rStartup) (dest, operation, queryDesc->tupDesc);

    /*
     * run plan
     */
    if (!ScanDirectionIsNoMovement(direction))
        ExecutePlan(estate,
                    queryDesc->planstate,
                    operation,
                    sendTuples,
                    count,
                    direction,
                    dest);

    /*
     * shutdown tuple receiver, if we started it
     */
    if (sendTuples)
        (*dest->rShutdown) (dest);

    if (queryDesc->totaltime)
        InstrStopNode(queryDesc->totaltime, estate->es_processed);

    MemoryContextSwitchTo(oldcontext);
}

void standard_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)

Definition at line 124 of file execMain.c.

References AfterTriggerBeginQuery(), Assert, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, CreateExecutorState(), QueryDesc::crosscheck_snapshot, elog, ERROR, EState::es_crosscheck_snapshot, EState::es_instrument, EState::es_output_cid, EState::es_param_exec_vals, EState::es_param_list_info, EState::es_query_cxt, EState::es_snapshot, EState::es_top_eflags, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_SKIP_TRIGGERS, ExecCheckXactReadOnly(), GetCurrentCommandId(), PlannedStmt::hasModifyingCTE, InitPlan(), QueryDesc::instrument_options, MemoryContextSwitchTo(), NIL, PlannedStmt::nParamExec, NULL, QueryDesc::operation, palloc0(), QueryDesc::params, QueryDesc::plannedstmt, RegisterSnapshot(), PlannedStmt::rowMarks, QueryDesc::snapshot, and XactReadOnly.

Referenced by ExecutorStart(), explain_ExecutorStart(), and pgss_ExecutorStart().

{
    EState     *estate;
    MemoryContext oldcontext;

    /* sanity checks: queryDesc must not be started already */
    Assert(queryDesc != NULL);
    Assert(queryDesc->estate == NULL);

    /*
     * If the transaction is read-only, we need to check if any writes are
     * planned to non-temporary tables.  EXPLAIN is considered read-only.
     */
    if (XactReadOnly && !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
        ExecCheckXactReadOnly(queryDesc->plannedstmt);

    /*
     * Build EState, switch into per-query memory context for startup.
     */
    estate = CreateExecutorState();
    queryDesc->estate = estate;

    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    /*
     * Fill in external parameters, if any, from queryDesc; and allocate
     * workspace for internal parameters
     */
    estate->es_param_list_info = queryDesc->params;

    if (queryDesc->plannedstmt->nParamExec > 0)
        estate->es_param_exec_vals = (ParamExecData *)
            palloc0(queryDesc->plannedstmt->nParamExec * sizeof(ParamExecData));

    /*
     * If non-read-only query, set the command ID to mark output tuples with
     */
    switch (queryDesc->operation)
    {
        case CMD_SELECT:

            /*
             * SELECT FOR [KEY] UPDATE/SHARE and modifying CTEs need to mark
             * tuples
             */
            if (queryDesc->plannedstmt->rowMarks != NIL ||
                queryDesc->plannedstmt->hasModifyingCTE)
                estate->es_output_cid = GetCurrentCommandId(true);

            /*
             * A SELECT without modifying CTEs can't possibly queue triggers,
             * so force skip-triggers mode. This is just a marginal efficiency
             * hack, since AfterTriggerBeginQuery/AfterTriggerEndQuery aren't
             * all that expensive, but we might as well do it.
             */
            if (!queryDesc->plannedstmt->hasModifyingCTE)
                eflags |= EXEC_FLAG_SKIP_TRIGGERS;
            break;

        case CMD_INSERT:
        case CMD_DELETE:
        case CMD_UPDATE:
            estate->es_output_cid = GetCurrentCommandId(true);
            break;

        default:
            elog(ERROR, "unrecognized operation code: %d",
                 (int) queryDesc->operation);
            break;
    }

    /*
     * Copy other important information into the EState
     */
    estate->es_snapshot = RegisterSnapshot(queryDesc->snapshot);
    estate->es_crosscheck_snapshot = RegisterSnapshot(queryDesc->crosscheck_snapshot);
    estate->es_top_eflags = eflags;
    estate->es_instrument = queryDesc->instrument_options;

    /*
     * Initialize the plan state tree
     */
    InitPlan(queryDesc, eflags);

    /*
     * Set up an AFTER-trigger statement context, unless told not to, or
     * unless it's EXPLAIN-only mode (when ExecutorFinish won't be called).
     */
    if (!(eflags & (EXEC_FLAG_SKIP_TRIGGERS | EXEC_FLAG_EXPLAIN_ONLY)))
        AfterTriggerBeginQuery();

    MemoryContextSwitchTo(oldcontext);
}


Variable Documentation

Definition at line 69 of file execMain.c.

Referenced by _PG_init(), and ExecCheckRTPerms().

Definition at line 66 of file execMain.c.

Referenced by _PG_fini(), _PG_init(), and ExecutorEnd().

Definition at line 65 of file execMain.c.

Referenced by _PG_fini(), _PG_init(), and ExecutorFinish().

Definition at line 64 of file execMain.c.

Referenced by _PG_fini(), _PG_init(), and ExecutorRun().

Definition at line 63 of file execMain.c.

Referenced by _PG_fini(), _PG_init(), and ExecutorStart().