Header And Logo

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

Functions

execUtils.c File Reference

#include "postgres.h"
#include "access/relscan.h"
#include "access/transam.h"
#include "catalog/index.h"
#include "executor/execdebug.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "storage/lmgr.h"
#include "utils/memutils.h"
#include "utils/tqual.h"
Include dependency graph for execUtils.c:

Go to the source code of this file.

Functions

static bool get_last_attnums (Node *node, ProjectionInfo *projInfo)
static bool index_recheck_constraint (Relation index, Oid *constr_procs, Datum *existing_values, bool *existing_isnull, Datum *new_values)
static void ShutdownExprContext (ExprContext *econtext, bool isCommit)
EStateCreateExecutorState (void)
void FreeExecutorState (EState *estate)
ExprContextCreateExprContext (EState *estate)
ExprContextCreateStandaloneExprContext (void)
void FreeExprContext (ExprContext *econtext, bool isCommit)
void ReScanExprContext (ExprContext *econtext)
ExprContextMakePerTupleExprContext (EState *estate)
void ExecAssignExprContext (EState *estate, PlanState *planstate)
void ExecAssignResultType (PlanState *planstate, TupleDesc tupDesc)
void ExecAssignResultTypeFromTL (PlanState *planstate)
TupleDesc ExecGetResultType (PlanState *planstate)
ProjectionInfoExecBuildProjectionInfo (List *targetList, ExprContext *econtext, TupleTableSlot *slot, TupleDesc inputDesc)
void ExecAssignProjectionInfo (PlanState *planstate, TupleDesc inputDesc)
void ExecFreeExprContext (PlanState *planstate)
TupleDesc ExecGetScanType (ScanState *scanstate)
void ExecAssignScanType (ScanState *scanstate, TupleDesc tupDesc)
void ExecAssignScanTypeFromOuterPlan (ScanState *scanstate)
bool ExecRelationIsTargetRelation (EState *estate, Index scanrelid)
Relation ExecOpenScanRelation (EState *estate, Index scanrelid, int eflags)
void ExecCloseScanRelation (Relation scanrel)
void ExecOpenIndices (ResultRelInfo *resultRelInfo)
void ExecCloseIndices (ResultRelInfo *resultRelInfo)
ListExecInsertIndexTuples (TupleTableSlot *slot, ItemPointer tupleid, EState *estate)
bool check_exclusion_constraint (Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, EState *estate, bool newIndex, bool errorOK)
void UpdateChangedParamSet (PlanState *node, Bitmapset *newchg)
void RegisterExprContextCallback (ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)
void UnregisterExprContextCallback (ExprContext *econtext, ExprContextCallbackFunction function, Datum arg)

Function Documentation

bool check_exclusion_constraint ( Relation  heap,
Relation  index,
IndexInfo indexInfo,
ItemPointer  tupleid,
Datum values,
bool isnull,
EState estate,
bool  newIndex,
bool  errorOK 
)

Definition at line 1174 of file execUtils.c.

References BuildIndexValueDescription(), ExprContext::ecxt_scantuple, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, errtableconstraint(), ExecDropSingleTupleTableSlot(), ExecStoreTuple(), FormIndexDatum(), ForwardScanDirection, GetPerTupleExprContext, i, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, index_beginscan(), index_endscan(), index_getnext(), index_recheck_constraint(), index_rescan(), InitDirtySnapshot, InvalidBuffer, InvalidOid, ItemPointerEquals(), MakeSingleTupleTableSlot(), NULL, RelationData::rd_indcollation, RelationData::rd_index, RelationGetDescr, RelationGetRelationName, ScanKeyEntryInitialize(), HeapTupleData::t_self, TransactionIdIsValid, XactLockTableWait(), SnapshotData::xmax, SnapshotData::xmin, and IndexScanDescData::xs_recheck.

Referenced by ExecInsertIndexTuples(), and IndexCheckExclusion().

{
    Oid        *constr_procs = indexInfo->ii_ExclusionProcs;
    uint16     *constr_strats = indexInfo->ii_ExclusionStrats;
    Oid        *index_collations = index->rd_indcollation;
    int         index_natts = index->rd_index->indnatts;
    IndexScanDesc index_scan;
    HeapTuple   tup;
    ScanKeyData scankeys[INDEX_MAX_KEYS];
    SnapshotData DirtySnapshot;
    int         i;
    bool        conflict;
    bool        found_self;
    ExprContext *econtext;
    TupleTableSlot *existing_slot;
    TupleTableSlot *save_scantuple;

    /*
     * If any of the input values are NULL, the constraint check is assumed to
     * pass (i.e., we assume the operators are strict).
     */
    for (i = 0; i < index_natts; i++)
    {
        if (isnull[i])
            return true;
    }

    /*
     * Search the tuples that are in the index for any violations, including
     * tuples that aren't visible yet.
     */
    InitDirtySnapshot(DirtySnapshot);

    for (i = 0; i < index_natts; i++)
    {
        ScanKeyEntryInitialize(&scankeys[i],
                               0,
                               i + 1,
                               constr_strats[i],
                               InvalidOid,
                               index_collations[i],
                               constr_procs[i],
                               values[i]);
    }

    /*
     * Need a TupleTableSlot to put existing tuples in.
     *
     * To use FormIndexDatum, we have to make the econtext's scantuple point
     * to this slot.  Be sure to save and restore caller's value for
     * scantuple.
     */
    existing_slot = MakeSingleTupleTableSlot(RelationGetDescr(heap));

    econtext = GetPerTupleExprContext(estate);
    save_scantuple = econtext->ecxt_scantuple;
    econtext->ecxt_scantuple = existing_slot;

    /*
     * May have to restart scan from this point if a potential conflict is
     * found.
     */
retry:
    conflict = false;
    found_self = false;
    index_scan = index_beginscan(heap, index, &DirtySnapshot, index_natts, 0);
    index_rescan(index_scan, scankeys, index_natts, NULL, 0);

    while ((tup = index_getnext(index_scan,
                                ForwardScanDirection)) != NULL)
    {
        TransactionId xwait;
        Datum       existing_values[INDEX_MAX_KEYS];
        bool        existing_isnull[INDEX_MAX_KEYS];
        char       *error_new;
        char       *error_existing;

        /*
         * Ignore the entry for the tuple we're trying to check.
         */
        if (ItemPointerEquals(tupleid, &tup->t_self))
        {
            if (found_self)     /* should not happen */
                elog(ERROR, "found self tuple multiple times in index \"%s\"",
                     RelationGetRelationName(index));
            found_self = true;
            continue;
        }

        /*
         * Extract the index column values and isnull flags from the existing
         * tuple.
         */
        ExecStoreTuple(tup, existing_slot, InvalidBuffer, false);
        FormIndexDatum(indexInfo, existing_slot, estate,
                       existing_values, existing_isnull);

        /* If lossy indexscan, must recheck the condition */
        if (index_scan->xs_recheck)
        {
            if (!index_recheck_constraint(index,
                                          constr_procs,
                                          existing_values,
                                          existing_isnull,
                                          values))
                continue;       /* tuple doesn't actually match, so no
                                 * conflict */
        }

        /*
         * At this point we have either a conflict or a potential conflict. If
         * we're not supposed to raise error, just return the fact of the
         * potential conflict without waiting to see if it's real.
         */
        if (errorOK)
        {
            conflict = true;
            break;
        }

        /*
         * If an in-progress transaction is affecting the visibility of this
         * tuple, we need to wait for it to complete and then recheck.  For
         * simplicity we do rechecking by just restarting the whole scan ---
         * this case probably doesn't happen often enough to be worth trying
         * harder, and anyway we don't want to hold any index internal locks
         * while waiting.
         */
        xwait = TransactionIdIsValid(DirtySnapshot.xmin) ?
            DirtySnapshot.xmin : DirtySnapshot.xmax;

        if (TransactionIdIsValid(xwait))
        {
            index_endscan(index_scan);
            XactLockTableWait(xwait);
            goto retry;
        }

        /*
         * We have a definite conflict.  Report it.
         */
        error_new = BuildIndexValueDescription(index, values, isnull);
        error_existing = BuildIndexValueDescription(index, existing_values,
                                                    existing_isnull);
        if (newIndex)
            ereport(ERROR,
                    (errcode(ERRCODE_EXCLUSION_VIOLATION),
                     errmsg("could not create exclusion constraint \"%s\"",
                            RelationGetRelationName(index)),
                     errdetail("Key %s conflicts with key %s.",
                               error_new, error_existing),
                     errtableconstraint(heap,
                                        RelationGetRelationName(index))));
        else
            ereport(ERROR,
                    (errcode(ERRCODE_EXCLUSION_VIOLATION),
                     errmsg("conflicting key value violates exclusion constraint \"%s\"",
                            RelationGetRelationName(index)),
                     errdetail("Key %s conflicts with existing key %s.",
                               error_new, error_existing),
                     errtableconstraint(heap,
                                        RelationGetRelationName(index))));
    }

    index_endscan(index_scan);

    /*
     * Ordinarily, at this point the search should have found the originally
     * inserted tuple, unless we exited the loop early because of conflict.
     * However, it is possible to define exclusion constraints for which that
     * wouldn't be true --- for instance, if the operator is <>. So we no
     * longer complain if found_self is still false.
     */

    econtext->ecxt_scantuple = save_scantuple;

    ExecDropSingleTupleTableSlot(existing_slot);

    return !conflict;
}

EState* CreateExecutorState ( void   ) 

Definition at line 81 of file execUtils.c.

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), CurrentMemoryContext, EState::es_auxmodifytables, EState::es_crosscheck_snapshot, EState::es_direction, EState::es_epqScanDone, EState::es_epqTuple, EState::es_epqTupleSet, EState::es_exprcontexts, EState::es_finished, EState::es_instrument, EState::es_junkFilter, EState::es_lastoid, EState::es_num_result_relations, EState::es_output_cid, EState::es_param_exec_vals, EState::es_param_list_info, EState::es_per_tuple_exprcontext, EState::es_plannedstmt, EState::es_processed, 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_trig_newtup_slot, EState::es_trig_oldtup_slot, EState::es_trig_target_relations, EState::es_trig_tuple_slot, EState::es_tupleTable, makeNode, and MemoryContextSwitchTo().

Referenced by afterTriggerInvokeEvents(), ATRewriteTable(), btree_predicate_proof(), compute_index_stats(), CopyFrom(), EvalPlanQualStart(), evaluate_expr(), ExecuteQuery(), ExecuteTruncate(), ExplainExecuteQuery(), get_actual_variable_range(), IndexBuildHeapScan(), IndexCheckExclusion(), plpgsql_create_econtext(), standard_ExecutorStart(), tuplesort_begin_cluster(), validate_index_heapscan(), validateCheckConstraint(), and validateDomainConstraint().

{
    EState     *estate;
    MemoryContext qcontext;
    MemoryContext oldcontext;

    /*
     * Create the per-query context for this Executor run.
     */
    qcontext = AllocSetContextCreate(CurrentMemoryContext,
                                     "ExecutorState",
                                     ALLOCSET_DEFAULT_MINSIZE,
                                     ALLOCSET_DEFAULT_INITSIZE,
                                     ALLOCSET_DEFAULT_MAXSIZE);

    /*
     * Make the EState node within the per-query context.  This way, we don't
     * need a separate pfree() operation for it at shutdown.
     */
    oldcontext = MemoryContextSwitchTo(qcontext);

    estate = makeNode(EState);

    /*
     * Initialize all fields of the Executor State structure
     */
    estate->es_direction = ForwardScanDirection;
    estate->es_snapshot = SnapshotNow;
    estate->es_crosscheck_snapshot = InvalidSnapshot;   /* no crosscheck */
    estate->es_range_table = NIL;
    estate->es_plannedstmt = NULL;

    estate->es_junkFilter = NULL;

    estate->es_output_cid = (CommandId) 0;

    estate->es_result_relations = NULL;
    estate->es_num_result_relations = 0;
    estate->es_result_relation_info = NULL;

    estate->es_trig_target_relations = NIL;
    estate->es_trig_tuple_slot = NULL;
    estate->es_trig_oldtup_slot = NULL;
    estate->es_trig_newtup_slot = NULL;

    estate->es_param_list_info = NULL;
    estate->es_param_exec_vals = NULL;

    estate->es_query_cxt = qcontext;

    estate->es_tupleTable = NIL;

    estate->es_rowMarks = NIL;

    estate->es_processed = 0;
    estate->es_lastoid = InvalidOid;

    estate->es_top_eflags = 0;
    estate->es_instrument = 0;
    estate->es_finished = false;

    estate->es_exprcontexts = NIL;

    estate->es_subplanstates = NIL;

    estate->es_auxmodifytables = NIL;

    estate->es_per_tuple_exprcontext = NULL;

    estate->es_epqTuple = NULL;
    estate->es_epqTupleSet = NULL;
    estate->es_epqScanDone = NULL;

    /*
     * Return the executor state structure
     */
    MemoryContextSwitchTo(oldcontext);

    return estate;
}

ExprContext* CreateExprContext ( EState estate  ) 

Definition at line 218 of file execUtils.c.

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ExprContext::caseValue_datum, ExprContext::caseValue_isNull, ExprContext::domainValue_datum, ExprContext::domainValue_isNull, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExprContext::ecxt_callbacks, ExprContext::ecxt_estate, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, ExprContext::ecxt_param_exec_vals, ExprContext::ecxt_param_list_info, ExprContext::ecxt_per_query_memory, ExprContext::ecxt_per_tuple_memory, ExprContext::ecxt_scantuple, EState::es_exprcontexts, EState::es_param_exec_vals, EState::es_param_list_info, EState::es_query_cxt, lcons(), makeNode, and MemoryContextSwitchTo().

Referenced by ExecAssignExprContext(), ExecInitMergeJoin(), ExecInitModifyTable(), ExecInitSubPlan(), MakePerTupleExprContext(), and plpgsql_create_econtext().

{
    ExprContext *econtext;
    MemoryContext oldcontext;

    /* Create the ExprContext node within the per-query memory context */
    oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

    econtext = makeNode(ExprContext);

    /* Initialize fields of ExprContext */
    econtext->ecxt_scantuple = NULL;
    econtext->ecxt_innertuple = NULL;
    econtext->ecxt_outertuple = NULL;

    econtext->ecxt_per_query_memory = estate->es_query_cxt;

    /*
     * Create working memory for expression evaluation in this context.
     */
    econtext->ecxt_per_tuple_memory =
        AllocSetContextCreate(estate->es_query_cxt,
                              "ExprContext",
                              ALLOCSET_DEFAULT_MINSIZE,
                              ALLOCSET_DEFAULT_INITSIZE,
                              ALLOCSET_DEFAULT_MAXSIZE);

    econtext->ecxt_param_exec_vals = estate->es_param_exec_vals;
    econtext->ecxt_param_list_info = estate->es_param_list_info;

    econtext->ecxt_aggvalues = NULL;
    econtext->ecxt_aggnulls = NULL;

    econtext->caseValue_datum = (Datum) 0;
    econtext->caseValue_isNull = true;

    econtext->domainValue_datum = (Datum) 0;
    econtext->domainValue_isNull = true;

    econtext->ecxt_estate = estate;

    econtext->ecxt_callbacks = NULL;

    /*
     * Link the ExprContext into the EState to ensure it is shut down when the
     * EState is freed.  Because we use lcons(), shutdowns will occur in
     * reverse order of creation, which may not be essential but can't hurt.
     */
    estate->es_exprcontexts = lcons(econtext, estate->es_exprcontexts);

    MemoryContextSwitchTo(oldcontext);

    return econtext;
}

ExprContext* CreateStandaloneExprContext ( void   ) 

Definition at line 292 of file execUtils.c.

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ExprContext::caseValue_datum, ExprContext::caseValue_isNull, CurrentMemoryContext, ExprContext::domainValue_datum, ExprContext::domainValue_isNull, ExprContext::ecxt_aggnulls, ExprContext::ecxt_aggvalues, ExprContext::ecxt_callbacks, ExprContext::ecxt_estate, ExprContext::ecxt_innertuple, ExprContext::ecxt_outertuple, ExprContext::ecxt_param_exec_vals, ExprContext::ecxt_param_list_info, ExprContext::ecxt_per_query_memory, ExprContext::ecxt_per_tuple_memory, ExprContext::ecxt_scantuple, and makeNode.

Referenced by domain_check_input().

{
    ExprContext *econtext;

    /* Create the ExprContext node within the caller's memory context */
    econtext = makeNode(ExprContext);

    /* Initialize fields of ExprContext */
    econtext->ecxt_scantuple = NULL;
    econtext->ecxt_innertuple = NULL;
    econtext->ecxt_outertuple = NULL;

    econtext->ecxt_per_query_memory = CurrentMemoryContext;

    /*
     * Create working memory for expression evaluation in this context.
     */
    econtext->ecxt_per_tuple_memory =
        AllocSetContextCreate(CurrentMemoryContext,
                              "ExprContext",
                              ALLOCSET_DEFAULT_MINSIZE,
                              ALLOCSET_DEFAULT_INITSIZE,
                              ALLOCSET_DEFAULT_MAXSIZE);

    econtext->ecxt_param_exec_vals = NULL;
    econtext->ecxt_param_list_info = NULL;

    econtext->ecxt_aggvalues = NULL;
    econtext->ecxt_aggnulls = NULL;

    econtext->caseValue_datum = (Datum) 0;
    econtext->caseValue_isNull = true;

    econtext->domainValue_datum = (Datum) 0;
    econtext->domainValue_isNull = true;

    econtext->ecxt_estate = NULL;

    econtext->ecxt_callbacks = NULL;

    return econtext;
}

void ExecAssignExprContext ( EState estate,
PlanState planstate 
)
void ExecAssignProjectionInfo ( PlanState planstate,
TupleDesc  inputDesc 
)
void ExecAssignResultType ( PlanState planstate,
TupleDesc  tupDesc 
)

Definition at line 432 of file execUtils.c.

References ExecSetSlotDescriptor(), and PlanState::ps_ResultTupleSlot.

Referenced by ExecAssignResultTypeFromTL(), and ExecInitModifyTable().

{
    TupleTableSlot *slot = planstate->ps_ResultTupleSlot;

    ExecSetSlotDescriptor(slot, tupDesc);
}

void ExecAssignResultTypeFromTL ( PlanState planstate  ) 

Definition at line 444 of file execUtils.c.

References ExecAssignResultType(), ExecContextForcesOids(), ExecTypeFromTL(), PlanState::plan, and Plan::targetlist.

Referenced by ExecInitAgg(), ExecInitAppend(), ExecInitBitmapHeapScan(), ExecInitCteScan(), ExecInitForeignScan(), ExecInitFunctionScan(), ExecInitGroup(), ExecInitHash(), ExecInitHashJoin(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), ExecInitLimit(), ExecInitLockRows(), ExecInitMaterial(), ExecInitMergeAppend(), ExecInitMergeJoin(), ExecInitNestLoop(), ExecInitRecursiveUnion(), ExecInitResult(), ExecInitSeqScan(), ExecInitSetOp(), ExecInitSort(), ExecInitSubqueryScan(), ExecInitTidScan(), ExecInitUnique(), ExecInitValuesScan(), ExecInitWindowAgg(), and ExecInitWorkTableScan().

{
    bool        hasoid;
    TupleDesc   tupDesc;

    if (ExecContextForcesOids(planstate, &hasoid))
    {
        /* context forces OID choice; hasoid is now set correctly */
    }
    else
    {
        /* given free choice, don't leave space for OIDs in result tuples */
        hasoid = false;
    }

    /*
     * ExecTypeFromTL needs the parse-time representation of the tlist, not a
     * list of ExprStates.  This is good because some plan nodes don't bother
     * to set up planstate->targetlist ...
     */
    tupDesc = ExecTypeFromTL(planstate->plan->targetlist, hasoid);
    ExecAssignResultType(planstate, tupDesc);
}

void ExecAssignScanType ( ScanState scanstate,
TupleDesc  tupDesc 
)
void ExecAssignScanTypeFromOuterPlan ( ScanState scanstate  ) 

Definition at line 750 of file execUtils.c.

References ExecAssignScanType(), ExecGetResultType(), and outerPlanState.

Referenced by ExecInitAgg(), ExecInitGroup(), ExecInitMaterial(), ExecInitSort(), and ExecInitWindowAgg().

{
    PlanState  *outerPlan;
    TupleDesc   tupDesc;

    outerPlan = outerPlanState(scanstate);
    tupDesc = ExecGetResultType(outerPlan);

    ExecAssignScanType(scanstate, tupDesc);
}

ProjectionInfo* ExecBuildProjectionInfo ( List targetList,
ExprContext econtext,
TupleTableSlot slot,
TupleDesc  inputDesc 
)

Definition at line 496 of file execUtils.c.

References GenericExprState::arg, tupleDesc::attrs, ExecTargetListLength(), ExprState::expr, get_last_attnums(), INNER_VAR, IsA, lappend(), lfirst, makeNode, tupleDesc::natts, NIL, NULL, offsetof, OUTER_VAR, palloc(), ProjectionInfo::pi_directMap, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_itemIsDone, ProjectionInfo::pi_lastInnerVar, ProjectionInfo::pi_lastOuterVar, ProjectionInfo::pi_lastScanVar, ProjectionInfo::pi_numSimpleVars, ProjectionInfo::pi_slot, ProjectionInfo::pi_targetlist, ProjectionInfo::pi_varNumbers, ProjectionInfo::pi_varOutputCols, ProjectionInfo::pi_varSlotOffsets, TargetEntry::resno, Var::varattno, Var::varno, Var::vartype, and GenericExprState::xprstate.

Referenced by ExecAssignProjectionInfo(), ExecInitAgg(), ExecInitModifyTable(), and ExecInitSubPlan().

{
    ProjectionInfo *projInfo = makeNode(ProjectionInfo);
    int         len = ExecTargetListLength(targetList);
    int        *workspace;
    int        *varSlotOffsets;
    int        *varNumbers;
    int        *varOutputCols;
    List       *exprlist;
    int         numSimpleVars;
    bool        directMap;
    ListCell   *tl;

    projInfo->pi_exprContext = econtext;
    projInfo->pi_slot = slot;
    /* since these are all int arrays, we need do just one palloc */
    workspace = (int *) palloc(len * 3 * sizeof(int));
    projInfo->pi_varSlotOffsets = varSlotOffsets = workspace;
    projInfo->pi_varNumbers = varNumbers = workspace + len;
    projInfo->pi_varOutputCols = varOutputCols = workspace + len * 2;
    projInfo->pi_lastInnerVar = 0;
    projInfo->pi_lastOuterVar = 0;
    projInfo->pi_lastScanVar = 0;

    /*
     * We separate the target list elements into simple Var references and
     * expressions which require the full ExecTargetList machinery.  To be a
     * simple Var, a Var has to be a user attribute and not mismatch the
     * inputDesc.  (Note: if there is a type mismatch then ExecEvalScalarVar
     * will probably throw an error at runtime, but we leave that to it.)
     */
    exprlist = NIL;
    numSimpleVars = 0;
    directMap = true;
    foreach(tl, targetList)
    {
        GenericExprState *gstate = (GenericExprState *) lfirst(tl);
        Var        *variable = (Var *) gstate->arg->expr;
        bool        isSimpleVar = false;

        if (variable != NULL &&
            IsA(variable, Var) &&
            variable->varattno > 0)
        {
            if (!inputDesc)
                isSimpleVar = true;     /* can't check type, assume OK */
            else if (variable->varattno <= inputDesc->natts)
            {
                Form_pg_attribute attr;

                attr = inputDesc->attrs[variable->varattno - 1];
                if (!attr->attisdropped && variable->vartype == attr->atttypid)
                    isSimpleVar = true;
            }
        }

        if (isSimpleVar)
        {
            TargetEntry *tle = (TargetEntry *) gstate->xprstate.expr;
            AttrNumber  attnum = variable->varattno;

            varNumbers[numSimpleVars] = attnum;
            varOutputCols[numSimpleVars] = tle->resno;
            if (tle->resno != numSimpleVars + 1)
                directMap = false;

            switch (variable->varno)
            {
                case INNER_VAR:
                    varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
                                                             ecxt_innertuple);
                    if (projInfo->pi_lastInnerVar < attnum)
                        projInfo->pi_lastInnerVar = attnum;
                    break;

                case OUTER_VAR:
                    varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
                                                             ecxt_outertuple);
                    if (projInfo->pi_lastOuterVar < attnum)
                        projInfo->pi_lastOuterVar = attnum;
                    break;

                    /* INDEX_VAR is handled by default case */

                default:
                    varSlotOffsets[numSimpleVars] = offsetof(ExprContext,
                                                             ecxt_scantuple);
                    if (projInfo->pi_lastScanVar < attnum)
                        projInfo->pi_lastScanVar = attnum;
                    break;
            }
            numSimpleVars++;
        }
        else
        {
            /* Not a simple variable, add it to generic targetlist */
            exprlist = lappend(exprlist, gstate);
            /* Examine expr to include contained Vars in lastXXXVar counts */
            get_last_attnums((Node *) variable, projInfo);
        }
    }
    projInfo->pi_targetlist = exprlist;
    projInfo->pi_numSimpleVars = numSimpleVars;
    projInfo->pi_directMap = directMap;

    if (exprlist == NIL)
        projInfo->pi_itemIsDone = NULL; /* not needed */
    else
        projInfo->pi_itemIsDone = (ExprDoneCond *)
            palloc(len * sizeof(ExprDoneCond));

    return projInfo;
}

void ExecCloseIndices ( ResultRelInfo resultRelInfo  ) 

Definition at line 956 of file execUtils.c.

References i, index_close(), NULL, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_NumIndices, and RowExclusiveLock.

Referenced by afterTriggerInvokeEvents(), CatalogCloseIndexes(), CopyFrom(), EvalPlanQualEnd(), and ExecEndPlan().

{
    int         i;
    int         numIndices;
    RelationPtr indexDescs;

    numIndices = resultRelInfo->ri_NumIndices;
    indexDescs = resultRelInfo->ri_IndexRelationDescs;

    for (i = 0; i < numIndices; i++)
    {
        if (indexDescs[i] == NULL)
            continue;           /* shouldn't happen? */

        /* Drop lock acquired by ExecOpenIndices */
        index_close(indexDescs[i], RowExclusiveLock);
    }

    /*
     * XXX should free indexInfo array here too?  Currently we assume that
     * such stuff will be cleaned up automatically in FreeExecutorState.
     */
}

void ExecCloseScanRelation ( Relation  scanrel  ) 
void ExecFreeExprContext ( PlanState planstate  ) 
TupleDesc ExecGetResultType ( PlanState planstate  ) 
TupleDesc ExecGetScanType ( ScanState scanstate  ) 

Definition at line 726 of file execUtils.c.

References ScanState::ss_ScanTupleSlot, and TupleTableSlot::tts_tupleDescriptor.

{
    TupleTableSlot *slot = scanstate->ss_ScanTupleSlot;

    return slot->tts_tupleDescriptor;
}

List* ExecInsertIndexTuples ( TupleTableSlot slot,
ItemPointer  tupleid,
EState estate 
)

Definition at line 1001 of file execUtils.c.

References check_exclusion_constraint(), ExprContext::ecxt_scantuple, EState::es_result_relation_info, ExecPrepareExpr(), ExecQual(), FormIndexDatum(), GetPerTupleExprContext, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_ReadyForInserts, index_insert(), lappend_oid(), NIL, NULL, RelationData::rd_index, RelationGetRelid, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_IndexRelationInfo, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_RelationDesc, UNIQUE_CHECK_PARTIAL, and values.

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

{
    List       *result = NIL;
    ResultRelInfo *resultRelInfo;
    int         i;
    int         numIndices;
    RelationPtr relationDescs;
    Relation    heapRelation;
    IndexInfo **indexInfoArray;
    ExprContext *econtext;
    Datum       values[INDEX_MAX_KEYS];
    bool        isnull[INDEX_MAX_KEYS];

    /*
     * Get information from the result relation info structure.
     */
    resultRelInfo = estate->es_result_relation_info;
    numIndices = resultRelInfo->ri_NumIndices;
    relationDescs = resultRelInfo->ri_IndexRelationDescs;
    indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
    heapRelation = resultRelInfo->ri_RelationDesc;

    /*
     * We will use the EState's per-tuple context for evaluating predicates
     * and index 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;

    /*
     * for each index, form and insert the index tuple
     */
    for (i = 0; i < numIndices; i++)
    {
        Relation    indexRelation = relationDescs[i];
        IndexInfo  *indexInfo;
        IndexUniqueCheck checkUnique;
        bool        satisfiesConstraint;

        if (indexRelation == NULL)
            continue;

        indexInfo = indexInfoArray[i];

        /* If the index is marked as read-only, ignore it */
        if (!indexInfo->ii_ReadyForInserts)
            continue;

        /* Check for partial index */
        if (indexInfo->ii_Predicate != NIL)
        {
            List       *predicate;

            /*
             * If predicate state not set up yet, create it (in the estate's
             * per-query context)
             */
            predicate = indexInfo->ii_PredicateState;
            if (predicate == NIL)
            {
                predicate = (List *)
                    ExecPrepareExpr((Expr *) indexInfo->ii_Predicate,
                                    estate);
                indexInfo->ii_PredicateState = predicate;
            }

            /* Skip this index-update if the predicate isn't satisfied */
            if (!ExecQual(predicate, econtext, false))
                continue;
        }

        /*
         * FormIndexDatum fills in its values and isnull parameters with the
         * appropriate values for the column(s) of the index.
         */
        FormIndexDatum(indexInfo,
                       slot,
                       estate,
                       values,
                       isnull);

        /*
         * The index AM does the actual insertion, plus uniqueness checking.
         *
         * For an immediate-mode unique index, we just tell the index AM to
         * throw error if not unique.
         *
         * For a deferrable unique index, we tell the index AM to just detect
         * possible non-uniqueness, and we add the index OID to the result
         * list if further checking is needed.
         */
        if (!indexRelation->rd_index->indisunique)
            checkUnique = UNIQUE_CHECK_NO;
        else if (indexRelation->rd_index->indimmediate)
            checkUnique = UNIQUE_CHECK_YES;
        else
            checkUnique = UNIQUE_CHECK_PARTIAL;

        satisfiesConstraint =
            index_insert(indexRelation, /* index relation */
                         values,    /* array of index Datums */
                         isnull,    /* null flags */
                         tupleid,       /* tid of heap tuple */
                         heapRelation,  /* heap relation */
                         checkUnique);  /* type of uniqueness check to do */

        /*
         * If the index has an associated exclusion constraint, check that.
         * This is simpler than the process for uniqueness checks since we
         * always insert first and then check.  If the constraint is deferred,
         * we check now anyway, but don't throw error on violation; instead
         * we'll queue a recheck event.
         *
         * An index for an exclusion constraint can't also be UNIQUE (not an
         * essential property, we just don't allow it in the grammar), so no
         * need to preserve the prior state of satisfiesConstraint.
         */
        if (indexInfo->ii_ExclusionOps != NULL)
        {
            bool        errorOK = !indexRelation->rd_index->indimmediate;

            satisfiesConstraint =
                check_exclusion_constraint(heapRelation,
                                           indexRelation, indexInfo,
                                           tupleid, values, isnull,
                                           estate, false, errorOK);
        }

        if ((checkUnique == UNIQUE_CHECK_PARTIAL ||
             indexInfo->ii_ExclusionOps != NULL) &&
            !satisfiesConstraint)
        {
            /*
             * The tuple potentially violates the uniqueness or exclusion
             * constraint, so make a note of the index so that we can re-check
             * it later.
             */
            result = lappend_oid(result, RelationGetRelid(indexRelation));
        }
    }

    return result;
}

void ExecOpenIndices ( ResultRelInfo resultRelInfo  ) 

Definition at line 888 of file execUtils.c.

References BuildIndexInfo(), i, index_open(), lfirst_oid, list_free(), list_length(), palloc(), RelationGetForm, RelationGetIndexList(), ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_IndexRelationInfo, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_RelationDesc, and RowExclusiveLock.

Referenced by CatalogOpenIndexes(), CopyFrom(), and ExecInitModifyTable().

{
    Relation    resultRelation = resultRelInfo->ri_RelationDesc;
    List       *indexoidlist;
    ListCell   *l;
    int         len,
                i;
    RelationPtr relationDescs;
    IndexInfo **indexInfoArray;

    resultRelInfo->ri_NumIndices = 0;

    /* fast path if no indexes */
    if (!RelationGetForm(resultRelation)->relhasindex)
        return;

    /*
     * Get cached list of index OIDs
     */
    indexoidlist = RelationGetIndexList(resultRelation);
    len = list_length(indexoidlist);
    if (len == 0)
        return;

    /*
     * allocate space for result arrays
     */
    relationDescs = (RelationPtr) palloc(len * sizeof(Relation));
    indexInfoArray = (IndexInfo **) palloc(len * sizeof(IndexInfo *));

    resultRelInfo->ri_NumIndices = len;
    resultRelInfo->ri_IndexRelationDescs = relationDescs;
    resultRelInfo->ri_IndexRelationInfo = indexInfoArray;

    /*
     * For each index, open the index relation and save pg_index info. We
     * acquire RowExclusiveLock, signifying we will update the index.
     *
     * Note: we do this even if the index is not IndexIsReady; it's not worth
     * the trouble to optimize for the case where it isn't.
     */
    i = 0;
    foreach(l, indexoidlist)
    {
        Oid         indexOid = lfirst_oid(l);
        Relation    indexDesc;
        IndexInfo  *ii;

        indexDesc = index_open(indexOid, RowExclusiveLock);

        /* extract index key information from the index's pg_index info */
        ii = BuildIndexInfo(indexDesc);

        relationDescs[i] = indexDesc;
        indexInfoArray[i] = ii;
        i++;
    }

    list_free(indexoidlist);
}

Relation ExecOpenScanRelation ( EState estate,
Index  scanrelid,
int  eflags 
)

Definition at line 801 of file execUtils.c.

References ereport, errcode(), errhint(), errmsg(), ERROR, EState::es_range_table, EState::es_rowMarks, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_WITH_NO_DATA, ExecRelationIsTargetRelation(), getrelid, heap_open(), lfirst, RelationGetRelationName, RelationIsScannable, and ExecRowMark::rti.

Referenced by ExecInitBitmapHeapScan(), ExecInitForeignScan(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), ExecInitTidScan(), and InitScanRelation().

{
    Relation    rel;
    Oid         reloid;
    LOCKMODE    lockmode;

    /*
     * Determine the lock type we need.  First, scan to see if target relation
     * is a result relation.  If not, check if it's a FOR UPDATE/FOR SHARE
     * relation.  In either of those cases, we got the lock already.
     */
    lockmode = AccessShareLock;
    if (ExecRelationIsTargetRelation(estate, scanrelid))
        lockmode = NoLock;
    else
    {
        ListCell   *l;

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

            if (erm->rti == scanrelid)
            {
                lockmode = NoLock;
                break;
            }
        }
    }

    /* Open the relation and acquire lock as needed */
    reloid = getrelid(scanrelid, estate->es_range_table);
    rel = heap_open(reloid, lockmode);

    /*
     * Complain if we're attempting a scan of an unscannable relation, except
     * when the query won't actually be run.  This is a slightly klugy place
     * to do this, perhaps, but there is no better place.
     */
    if ((eflags & (EXEC_FLAG_EXPLAIN_ONLY | EXEC_FLAG_WITH_NO_DATA)) == 0 &&
        !RelationIsScannable(rel))
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("materialized view \"%s\" has not been populated",
                        RelationGetRelationName(rel)),
                 errhint("Use the REFRESH MATERIALIZED VIEW command.")));

    return rel;
}

bool ExecRelationIsTargetRelation ( EState estate,
Index  scanrelid 
)

Definition at line 775 of file execUtils.c.

References EState::es_num_result_relations, EState::es_result_relations, and i.

Referenced by ExecInitBitmapIndexScan(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), and ExecOpenScanRelation().

{
    ResultRelInfo *resultRelInfos;
    int         i;

    resultRelInfos = estate->es_result_relations;
    for (i = 0; i < estate->es_num_result_relations; i++)
    {
        if (resultRelInfos[i].ri_RangeTableIndex == scanrelid)
            return true;
    }
    return false;
}

void FreeExecutorState ( EState estate  ) 

Definition at line 178 of file execUtils.c.

References EState::es_exprcontexts, EState::es_query_cxt, FreeExprContext(), linitial, and MemoryContextDelete().

Referenced by afterTriggerInvokeEvents(), ATRewriteTable(), btree_predicate_proof(), compute_index_stats(), CopyFrom(), EvalPlanQualEnd(), evaluate_expr(), ExecuteQuery(), ExecuteTruncate(), ExplainExecuteQuery(), get_actual_variable_range(), IndexBuildHeapScan(), IndexCheckExclusion(), plpgsql_xact_cb(), standard_ExecutorEnd(), tuplesort_end(), validate_index_heapscan(), validateCheckConstraint(), and validateDomainConstraint().

{
    /*
     * Shut down and free any remaining ExprContexts.  We do this explicitly
     * to ensure that any remaining shutdown callbacks get called (since they
     * might need to release resources that aren't simply memory within the
     * per-query memory context).
     */
    while (estate->es_exprcontexts)
    {
        /*
         * XXX: seems there ought to be a faster way to implement this than
         * repeated list_delete(), no?
         */
        FreeExprContext((ExprContext *) linitial(estate->es_exprcontexts),
                        true);
        /* FreeExprContext removed the list link for us */
    }

    /*
     * Free the per-query memory context, thereby releasing all working
     * memory, including the EState node itself.
     */
    MemoryContextDelete(estate->es_query_cxt);
}

void FreeExprContext ( ExprContext econtext,
bool  isCommit 
)

Definition at line 353 of file execUtils.c.

References ExprContext::ecxt_estate, ExprContext::ecxt_per_tuple_memory, EState::es_exprcontexts, list_delete_ptr(), MemoryContextDelete(), pfree(), and ShutdownExprContext().

Referenced by ExecEndBitmapIndexScan(), ExecEndIndexOnlyScan(), ExecEndIndexScan(), FreeExecutorState(), plpgsql_destroy_econtext(), and plpgsql_subxact_cb().

{
    EState     *estate;

    /* Call any registered callbacks */
    ShutdownExprContext(econtext, isCommit);
    /* And clean up the memory used */
    MemoryContextDelete(econtext->ecxt_per_tuple_memory);
    /* Unlink self from owning EState, if any */
    estate = econtext->ecxt_estate;
    if (estate)
        estate->es_exprcontexts = list_delete_ptr(estate->es_exprcontexts,
                                                  econtext);
    /* And delete the ExprContext node */
    pfree(econtext);
}

static bool get_last_attnums ( Node node,
ProjectionInfo projInfo 
) [static]

Definition at line 620 of file execUtils.c.

References expression_tree_walker(), INNER_VAR, IsA, NULL, OUTER_VAR, ProjectionInfo::pi_lastInnerVar, ProjectionInfo::pi_lastOuterVar, ProjectionInfo::pi_lastScanVar, Var::varattno, and Var::varno.

Referenced by ExecBuildProjectionInfo().

{
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
        Var        *variable = (Var *) node;
        AttrNumber  attnum = variable->varattno;

        switch (variable->varno)
        {
            case INNER_VAR:
                if (projInfo->pi_lastInnerVar < attnum)
                    projInfo->pi_lastInnerVar = attnum;
                break;

            case OUTER_VAR:
                if (projInfo->pi_lastOuterVar < attnum)
                    projInfo->pi_lastOuterVar = attnum;
                break;

                /* INDEX_VAR is handled by default case */

            default:
                if (projInfo->pi_lastScanVar < attnum)
                    projInfo->pi_lastScanVar = attnum;
                break;
        }
        return false;
    }

    /*
     * Don't examine the arguments of Aggrefs or WindowFuncs, because those do
     * not represent expressions to be evaluated within the overall
     * targetlist's econtext.
     */
    if (IsA(node, Aggref))
        return false;
    if (IsA(node, WindowFunc))
        return false;
    return expression_tree_walker(node, get_last_attnums,
                                  (void *) projInfo);
}

static bool index_recheck_constraint ( Relation  index,
Oid constr_procs,
Datum existing_values,
bool existing_isnull,
Datum new_values 
) [static]

Definition at line 1362 of file execUtils.c.

References DatumGetBool, i, OidFunctionCall2Coll(), RelationData::rd_indcollation, and RelationData::rd_index.

Referenced by check_exclusion_constraint().

{
    int         index_natts = index->rd_index->indnatts;
    int         i;

    for (i = 0; i < index_natts; i++)
    {
        /* Assume the exclusion operators are strict */
        if (existing_isnull[i])
            return false;

        if (!DatumGetBool(OidFunctionCall2Coll(constr_procs[i],
                                               index->rd_indcollation[i],
                                               existing_values[i],
                                               new_values[i])))
            return false;
    }

    return true;
}

ExprContext* MakePerTupleExprContext ( EState estate  ) 

Definition at line 395 of file execUtils.c.

References CreateExprContext(), EState::es_per_tuple_exprcontext, and NULL.

void RegisterExprContextCallback ( ExprContext econtext,
ExprContextCallbackFunction  function,
Datum  arg 
)

Definition at line 1421 of file execUtils.c.

References ExprContext_CB::arg, ExprContext::ecxt_callbacks, ExprContext::ecxt_per_query_memory, ExprContext_CB::function, MemoryContextAlloc(), and ExprContext_CB::next.

Referenced by ExecMakeFunctionResult(), ExecPrepareTuplestoreResult(), fmgr_sql(), get_cached_rowtype(), and init_MultiFuncCall().

{
    ExprContext_CB *ecxt_callback;

    /* Save the info in appropriate memory context */
    ecxt_callback = (ExprContext_CB *)
        MemoryContextAlloc(econtext->ecxt_per_query_memory,
                           sizeof(ExprContext_CB));

    ecxt_callback->function = function;
    ecxt_callback->arg = arg;

    /* link to front of list for appropriate execution order */
    ecxt_callback->next = econtext->ecxt_callbacks;
    econtext->ecxt_callbacks = ecxt_callback;
}

void ReScanExprContext ( ExprContext econtext  ) 

Definition at line 380 of file execUtils.c.

References ExprContext::ecxt_per_tuple_memory, MemoryContextReset(), and ShutdownExprContext().

Referenced by domain_check_input(), ExecReScan(), and ValuesNext().

{
    /* Call any registered callbacks */
    ShutdownExprContext(econtext, true);
    /* And clean up the memory used */
    MemoryContextReset(econtext->ecxt_per_tuple_memory);
}

static void ShutdownExprContext ( ExprContext econtext,
bool  isCommit 
) [static]

Definition at line 1478 of file execUtils.c.

References ExprContext_CB::arg, ExprContext::ecxt_callbacks, ExprContext::ecxt_per_tuple_memory, ExprContext_CB::function, MemoryContextSwitchTo(), ExprContext_CB::next, NULL, and pfree().

Referenced by FreeExprContext(), and ReScanExprContext().

{
    ExprContext_CB *ecxt_callback;
    MemoryContext oldcontext;

    /* Fast path in normal case where there's nothing to do. */
    if (econtext->ecxt_callbacks == NULL)
        return;

    /*
     * Call the callbacks in econtext's per-tuple context.  This ensures that
     * any memory they might leak will get cleaned up.
     */
    oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);

    /*
     * Call each callback function in reverse registration order.
     */
    while ((ecxt_callback = econtext->ecxt_callbacks) != NULL)
    {
        econtext->ecxt_callbacks = ecxt_callback->next;
        if (isCommit)
            (*ecxt_callback->function) (ecxt_callback->arg);
        pfree(ecxt_callback);
    }

    MemoryContextSwitchTo(oldcontext);
}

void UnregisterExprContextCallback ( ExprContext econtext,
ExprContextCallbackFunction  function,
Datum  arg 
)

Definition at line 1447 of file execUtils.c.

References ExprContext_CB::arg, ExprContext::ecxt_callbacks, ExprContext_CB::function, ExprContext_CB::next, NULL, and pfree().

Referenced by end_MultiFuncCall(), and fmgr_sql().

{
    ExprContext_CB **prev_callback;
    ExprContext_CB *ecxt_callback;

    prev_callback = &econtext->ecxt_callbacks;

    while ((ecxt_callback = *prev_callback) != NULL)
    {
        if (ecxt_callback->function == function && ecxt_callback->arg == arg)
        {
            *prev_callback = ecxt_callback->next;
            pfree(ecxt_callback);
        }
        else
            prev_callback = &ecxt_callback->next;
    }
}

void UpdateChangedParamSet ( PlanState node,
Bitmapset newchg 
)

Definition at line 1390 of file execUtils.c.

References Plan::allParam, bms_free(), bms_intersect(), bms_is_empty(), bms_join(), PlanState::chgParam, and PlanState::plan.

Referenced by ExecReScan(), ExecReScanAppend(), ExecReScanBitmapAnd(), ExecReScanBitmapOr(), ExecReScanMergeAppend(), and ExecReScanSubqueryScan().

{
    Bitmapset  *parmset;

    /*
     * The plan node only depends on params listed in its allParam set. Don't
     * include anything else into its chgParam set.
     */
    parmset = bms_intersect(node->plan->allParam, newchg);

    /*
     * Keep node->chgParam == NULL if there's not actually any members; this
     * allows the simplest possible tests in executor node files.
     */
    if (!bms_is_empty(parmset))
        node->chgParam = bms_join(node->chgParam, parmset);
    else
        bms_free(parmset);
}