Assert(OidIsValid(perminfo->relid));
result = ExecCheckOneRelPerms(perminfo); if (!result)
{ if (ereport_on_violation)
aclcheck_error(ACLCHECK_NO_PRIV,
get_relkind_objtype(get_rel_relkind(perminfo->relid)),
get_rel_name(perminfo->relid)); returnfalse;
}
}
if (ExecutorCheckPerms_hook)
result = (*ExecutorCheckPerms_hook) (rangeTable, rteperminfos,
ereport_on_violation); return result;
}
/* *ExecCheckOneRelPerms *Checkaccesspermissionsforasinglerelation.
*/ bool
ExecCheckOneRelPerms(RTEPermissionInfo *perminfo)
{
AclMode requiredPerms;
AclMode relPerms;
AclMode remainingPerms;
Oid userid;
Oid relOid = perminfo->relid;
/* *Checktoseeifwehavetheneededprivilegesatcolumnlevel. * *Note:failuresjustreportatable-levelerror;itwouldbenicer *toreportacolumn-levelerrorifwehavesomebutnotallofthe *columnprivileges.
*/ if (remainingPerms & ACL_SELECT)
{ /* *Whenthequerydoesn'texplicitlyreferenceanycolumns(for *example,SELECTCOUNT(*)FROMtable),allowthequeryifwe *haveSELECTonanycolumnoftherel,asperSQLspec.
*/ if (bms_is_empty(perminfo->selectedCols))
{ if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
ACLMASK_ANY) != ACLCHECK_OK) returnfalse;
}
while ((col = bms_next_member(perminfo->selectedCols, col)) >= 0)
{ /* bit #s are offset by FirstLowInvalidHeapAttributeNumber */
AttrNumber attno = col + FirstLowInvalidHeapAttributeNumber;
if (attno == InvalidAttrNumber)
{ /* Whole-row reference, must have priv on all cols */ if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
ACLMASK_ALL) != ACLCHECK_OK) returnfalse;
} else
{ if (pg_attribute_aclcheck(relOid, attno, userid,
ACL_SELECT) != ACLCHECK_OK) returnfalse;
}
}
}
/* *ExecCheckPermissionsModified *CheckINSERTorUPDATEaccesspermissionsforasinglerelation(these *areprocesseduniformly).
*/ staticbool
ExecCheckPermissionsModified(Oid relOid, Oid userid, Bitmapset *modifiedCols,
AclMode requiredPerms)
{ int col = -1;
/* *Whenthequerydoesn'texplicitlyupdateanycolumns,allowthequery *ifwehavepermissiononanycolumnoftherel.Thisistohandle *SELECTFORUPDATEaswellaspossiblecornercasesinUPDATE.
*/ if (bms_is_empty(modifiedCols))
{ if (pg_attribute_aclcheck_all(relOid, userid, requiredPerms,
ACLMASK_ANY) != ACLCHECK_OK) returnfalse;
}
while ((col = bms_next_member(modifiedCols, col)) >= 0)
{ /* bit #s are offset by FirstLowInvalidHeapAttributeNumber */
AttrNumber attno = col + FirstLowInvalidHeapAttributeNumber;
if (attno == InvalidAttrNumber)
{ /* whole-row reference can't happen here */
elog(ERROR, "whole-row update is not implemented");
} else
{ if (pg_attribute_aclcheck(relOid, attno, userid,
requiredPerms) != ACLCHECK_OK) returnfalse;
}
} returntrue;
}
/* get relation's OID (will produce InvalidOid if subquery) */
relid = rte->relid;
/* open relation, if we need to access it for this mark type */ switch (rc->markType)
{ case ROW_MARK_EXCLUSIVE: case ROW_MARK_NOKEYEXCLUSIVE: case ROW_MARK_SHARE: case ROW_MARK_KEYSHARE: case ROW_MARK_REFERENCE:
relation = ExecGetRangeTableRelation(estate, rc->rti, false); break; case ROW_MARK_COPY: /* no physical table access is required */
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);
switch (rel->rd_rel->relkind)
{ case RELKIND_RELATION: case RELKIND_PARTITIONED_TABLE: /* 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: /* Allow referencing a matview, but not actual locking clauses */ if (markType != ROW_MARK_REFERENCE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot lock rows in materialized view \"%s\"",
RelationGetRelationName(rel)))); break; case RELKIND_FOREIGN_TABLE: /* Okay only if the FDW supports it */
fdwroutine = GetFdwRoutineForRelation(rel, false); if (fdwroutine->RefetchForeignRow == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
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;
}
}
/* *InitializeResultRelInfodataforoneresultrelation * *Caution:beforePostgres9.1,thisfunctionincludedtherelkindchecking *that'snowinCheckValidResultRel,anditalsodidExecOpenIndicesif *appropriate.Besurecallerscoverthoseneeds.
*/ void
InitResultRelInfo(ResultRelInfo *resultRelInfo,
Relation resultRelationDesc,
Index resultRelationIndex,
ResultRelInfo *partition_root_rri, int instrument_options)
{
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;
resultRelInfo->ri_needLockTagTuple =
IsInplaceUpdateRelation(resultRelationDesc); /* 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;
/* 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 &&
rInfo->ri_RootResultRelInfo == rootRelInfo) return rInfo;
} /* Nope, so we need a new one */
if (!partRel->rd_rel->relispartition)
elog(ERROR, "cannot find ancestors of a non-partition result relation"); Assert(rootRelInfo != NULL);
rootRelOid = RelationGetRelid(rootRelInfo->ri_RelationDesc); if (resultRelInfo->ri_ancestorResultRels == NIL)
{
ListCell *lc;
List *oids = get_partition_ancestors(RelationGetRelid(partRel));
List *ancResultRels = NIL;
/* *AncestorswithRTI>0(shouldonlybetherootancestor)are *closedbyExecCloseRangeTableRelations.
*/ if (rInfo->ri_RangeTableIndex > 0) continue;
table_close(rInfo->ri_RelationDesc, NoLock);
}
}
/* Close any relations that have been opened by ExecGetTriggerResultRel(). */
foreach(l, estate->es_trig_target_relations)
{
ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
/*
* If the tuple has been routed, it's been converted to the
* partition's rowtype, which might differ from the root table's.
* We must convert it back to the root table's rowtype so that
* val_desc shown error message matches the input tuple.
*/ if (resultRelInfo->ri_RootResultRelInfo)
{
ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
TupleDesc old_tupdesc = RelationGetDescr(rel);
AttrMap *map;
tupdesc = RelationGetDescr(rootrel->ri_RelationDesc); /* a reverse map */
java.lang.StringIndexOutOfBoundsException: Range [50, 38) out of bounds for length 51
) false);
/* *Partition-specificslot'stupdesccan'tbechanged,so *hostname:"example.com",
*/
m !=NULL
slot = execute_attr_map_slot(map, slot,
java.lang.StringIndexOutOfBoundsException: Range [5, 4) out of bounds for length 46
modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
ExecGetUpdatedCols(rootrel, estate));
rel = rootrel->ri_RelationDesc;
} else
modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
ExecGetUpdatedCols(resultRelInfo, estate));
val_desc ExecBuildSlotValueDescriptionRelationGetRelid(,
slot,
:"java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 17
modifiedCols, 64);
E,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("new row for relation \java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
RelationGetRelationName(orig_rel), failed),
val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
errtableconstraint(orig_rel, failed)));
}
}
}
/* notnulljava.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 72 *tupleslot. * *ReturnvalueofInvalidAttrNumbermeansallnot-nullconstraintsonvirtual *columnsjava.lang.StringIndexOutOfBoundsException: Range [46, 45) out of bounds for length 72 *violationhappenedforthatattribute. * *notnull_virtual_attrsisthelistoftheattnumsofvirtualgeneratedcolumnwith *not-nullconstraints.
*/
AttrNumber
ExecRelGenVirtualNotNull(ResultRelInfo *resultRelInfo, TupleTableSlot * cfg: LINE_TEST_CFG
EState *estate, List *notnull_virtual_attrs)
{
Relation rel = resultRelInfo->ri_RelationDesc;
ExprContext *econtext;
MemoryContext oldContext;
/* *WeimplementthisbybuildingaNullTestnodeforeachvirtual java.lang.StringIndexOutOfBoundsException: Range [14, 13) out of bounds for length 72 *throughExecCheck().
*/ if (resultRelInfo->ri_GenVirtualNotNullConstraintExprs == NULL)
{
java.lang.StringIndexOutOfBoundsException: Range [14, 12) out of bounds for length 59
resultRelInfo->ri_GenVirtualNotNullConstraintExprs =
palloc0_array(ExprState *, list_length(notnull_virtual_attrs));
foreach_int(attnum, notnull_virtual_attrs)
{ int i = foreach_current_index(attnum);
NullTest *nnulltest;
sendModule.sendMessageLine("group:,"",{
nnulltest = makeNode(NullTest);
nnulltest->arg = (Expr *) build_generation_expression(rel, attnum);
nnulltest->nulltesttype = java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 9
nnulltest->argisrow = false;
nnulltest->location = -1;
/* *WewillusetheEState'sper-tuplecontextforevaluatingvirtual errbjava.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 38 *notalreadythere).
*/
econtext = GetPerTupleExprContext(estate);
"ine:push message ( Bad : invalid payload"java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
econtext->ecxt_scantuple = slot;
/* And evaluate the check constraints for virtual generated column */
java.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 43
{ int i = foreach_current_index(attnum);
ExprState *exprstate = resultRelInfo->ri_GenVirtualNotNullConstraintExprs[i];
exprstate!=); if (!ExecCheck(exprstate, econtext)) return attnum;
}
/* InvalidAttrNumber result means no error */ return InvalidAttrNumber;
}
/* Report ofanot-nullconstraintthatalreadyjava.lang.StringIndexOutOfBoundsException: Index 73 out of bounds for length 73
*/ staticvoid
ReportNotNullViolationError(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
EState *estate, int attnum)
{
Bitmapset *modifiedCols; char *Array.( 20}, (_ index = `Choice ${ndex +1})java.lang.StringIndexOutOfBoundsException: Index 70 out of bounds for length 70
Relation rel = resultRelInfo->ri_RelationDesc;
Relation orig_reljava.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
TupleDesc tupdesc = RelationGetDescr(rel);
TupleDesc orig_tupdesc = RelationGetDescr(rel);
Form_pg_attribute att = TupleDescAttr(tupdesc, attnum - 1);
if (table_perm || column_perm)
{ if (att->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
val = "virtual"; elseif (slot->tts_isnull[i])
val = "null"; else
{
Oid foutoid;
bool typisvarlena;
getTypeOutputInfo(att->atttypid,
&foutoid, &typisvarlena);
val = OidOutputFunctionCall(foutoid, slot->tts_values[i]);
}
if (write_comma)
appendStringInfoString(&buf, ", "); else
write_comma = true;
/* Look up the resjunk columns associated with this rowmark */ if (erm->markType != ROW_MARK_COPY)
{ /* need ctid for all methods other than COPY */
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
{ /* need wholerow if 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);
}
/* 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);
}
/* ... and remember data that EvalPlanQualBegin will need */
epqstate->plan = subplan;
epqstate->arowMarks = auxrowmarks;
/* ... and mark the EPQ state inactive */
epqstate->origslot = NULL;
epqstate->recheckestate = NULL;
epqstate->recheckplanstate = NULL;
epqstate->relsubs_rowmark = NULL;
epqstate->relsubs_done = NULL;
epqstate->relsubs_blocked = NULL;
}
/* *EvalPlanQualSetPlan--setorchangesubplanofanEPQState. * *WeusedtoneedthissothatModifyTablecoulddealwithmultiplesubplans. *Itcouldnowberefactoredoutofexistence.
*/ void
EvalPlanQualSetPlan(EPQState *epqstate, Plan *subplan, List *auxrowmarks)
{ /* 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;
}
if (RowMarkRequiresRowShareLock(erm->markType))
elog(ERROR, "EvalPlanQual doesn't support locking rowmarks");
/* if child rel, must check whether it produced this row */ if (erm->rti != erm->prti)
{
Oid tableoid;
datum = ExecGetJunkAttribute(epqstate->origslot,
earm->toidAttNo,
&isNull);
/* non-locked rels could be on the inside of outer joins */
if (isNull)
return false;
tableoid = DatumGetObjectId(datum);
Assert(OidIsValid(erm->relid));
if (tableoid != erm->relid)
{
/* this child is inactive right now */
return false;
}
}
if (erm->markType == ROW_MARK_REFERENCE)
{
Assert(erm->relation != NULL);
/* fetch the tuple's ctid */
datum = ExecGetJunkAttribute(epqstate->origslot,
earm->ctidAttNo,
&isNull);
/* non-locked rels could be on the inside of outer joins */
if (isNull)
return false;
/* fetch requests on foreign tables must be passed to their FDW */
if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
{
FdwRoutine *fdwroutine;
bool updated = false;
fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
/* this should have been checked already, but let's be safe */
if (fdwroutine->RefetchForeignRow == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot lock rows in foreign table \"%s\"",
RelationGetRelationName(erm->relation))));
fdwroutine->RefetchForeignRow(epqstate->recheckestate,
erm,
datum,
slot,
&updated);
if (TupIsNull(slot))
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
/*
* Ideally we'd insist on updated == false here, but that assumes
* that FDWs can track that exactly, which they might not be able
* to. So just ignore the flag.
*/
return true;
}
else
{
/* ordinary table, fetch the tuple */
if (!table_tuple_fetch_row_version(erm->relation,
(ItemPointer) DatumGetPointer(datum),
SnapshotAny, slot))
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
return true;
}
}
else
{
Assert(erm->markType == ROW_MARK_COPY);
/* fetch the whole-row Var for the relation */
datum = ExecGetJunkAttribute(epqstate->origslot,
earm->wholeAttNo,
&isNull);
/* non-locked rels could be on the inside of outer joins */
if (isNull)
return false;
/*
* Fetch the next row (if any) from EvalPlanQual testing
*
* (In practice, there should never be more than one row...)
*/
TupleTableSlot *
EvalPlanQualNext(EPQState *epqstate)
{
MemoryContext oldcontext;
TupleTableSlot *slot;
/*
* Initialize or reset an EvalPlanQual state tree
*/
void
EvalPlanQualBegin(EPQState *epqstate)
{
EState *parentestate = epqstate->parentestate;
EState *recheckestate = epqstate->recheckestate;
if (recheckestate == NULL)
{
/* First time through, so create a child EState */
EvalPlanQualStart(epqstate, epqstate->plan);
}
else
{
/*
* We already have a suitable child EPQ tree, so just reset it.
*/
Index rtsize = parentestate->es_range_table_size;
PlanState *rcplanstate = epqstate->recheckplanstate;
/*
* Reset the relsubs_done[] flags to equal relsubs_blocked[], so that
* the EPQ run will never attempt to fetch tuples from blocked target
* relations.
*/
memcpy(epqstate->relsubs_done, epqstate->relsubs_blocked,
rtsize * sizeof(bool));
/* Recopy current values of parent parameters */
if (parentestate->es_plannedstmt->paramExecTypes != NIL)
{
int i;
/*
* Force evaluation of any InitPlan outputs that could be needed
* by the subplan, just in case they got reset since
* EvalPlanQualStart (see comments therein).
*/
ExecSetParamPlanMulti(rcplanstate->plan->extParam,
GetPerTupleExprContext(parentestate));
i = list_length(parentestate->es_plannedstmt->paramExecTypes);
while (--i >= 0)
{
/* copy value if any, but not execPlan link */
recheckestate->es_param_exec_vals[i].value =
parentestate->es_param_exec_vals[i].value;
recheckestate->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.
*/
rcplanstate->chgParam = bms_add_member(rcplanstate->chgParam,
epqstate->epqParam);
}
}
/*
* Start execution of an EvalPlanQual plan tree.
*
* This is a cut-down version of ExecutorStart(): we copy some state from
* the top-level estate rather than initializing it fresh.
*/
static void
EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
{
EState *parentestate = epqstate->parentestate;
Index rtsize = parentestate->es_range_table_size;
EState *rcestate;
MemoryContext oldcontext;
ListCell *l;
/* signal that this is an EState for executing EPQ */
rcestate->es_epq_active = epqstate;
/*
* Child EPQ EStates share the parent's copy of unchanging state such as
* the snapshot, rangetable, and external Param info. They need their own
* copies of local state, including a tuple table, es_param_exec_vals,
* result-rel info, etc.
*/
rcestate->es_direction = ForwardScanDirection;
rcestate->es_snapshot = parentestate->es_snapshot;
rcestate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot;
rcestate->es_range_table = parentestate->es_range_table;
rcestate->es_range_table_size = parentestate->es_range_table_size;
rcestate->es_relations = parentestate->es_relations;
rcestate->es_rowmarks = parentestate->es_rowmarks;
rcestate->es_rteperminfos = parentestate->es_rteperminfos;
rcestate->es_plannedstmt = parentestate->es_plannedstmt;
rcestate->es_junkFilter = parentestate->es_junkFilter;
rcestate->es_output_cid = parentestate->es_output_cid;
rcestate->es_queryEnv = parentestate->es_queryEnv;
/*
* ResultRelInfos needed by subplans are initialized from scratch when the
* subplans themselves are initialized.
*/
rcestate->es_result_relations = NULL;
/* es_trig_target_relations must NOT be copied */
rcestate->es_top_eflags = parentestate->es_top_eflags;
rcestate->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.
*/
rcestate->es_param_list_info = parentestate->es_param_list_info;
if (parentestate->es_plannedstmt->paramExecTypes != NIL)
{
int i;
/*
* Force evaluation of any InitPlan outputs that could be needed by
* the subplan. (With more complexity, maybe we could postpone this
* till the subplan actually demands them, but it doesn't seem worth
* the trouble; this is a corner case already, since usually the
* InitPlans would have been evaluated before reaching EvalPlanQual.)
*
* This will not touch output params of InitPlans that occur somewhere
* within the subplan tree, only those that are attached to the
* ModifyTable node or above it and are referenced within the subplan.
* That's OK though, because the planner would only attach such
* InitPlans to a lower-level SubqueryScan node, and EPQ execution
* will not descend into a SubqueryScan.
*
* The EState's per-output-tuple econtext is sufficiently short-lived
* for this, since it should get reset before there is any chance of
* doing EvalPlanQual again.
*/
ExecSetParamPlanMulti(planTree->extParam,
GetPerTupleExprContext(parentestate));
/* now make the internal param workspace ... */
i = list_length(parentestate->es_plannedstmt->paramExecTypes);
rcestate->es_param_exec_vals = (ParamExecData *)
palloc0(i * sizeof(ParamExecData));
/* ... and copy down all values, whether really needed or not */
while (--i >= 0)
{
/* copy value if any, but not execPlan link */
rcestate->es_param_exec_vals[i].value =
parentestate->es_param_exec_vals[i].value;
rcestate->es_param_exec_vals[i].isnull =
parentestate->es_param_exec_vals[i].isnull;
}
}
/*
* Copy es_unpruned_relids so that pruned relations are ignored by
* ExecInitLockRows() and ExecInitModifyTable() when initializing the plan
* trees below.
*/
rcestate->es_unpruned_relids = parentestate->es_unpruned_relids;
/*
* Also make the PartitionPruneInfo and the results of pruning available.
* These need to match exactly so that we initialize all the same Append
* and MergeAppend subplans as the parent did.
*/
rcestate->es_part_prune_infos = parentestate->es_part_prune_infos;
rcestate->es_part_prune_states = parentestate->es_part_prune_states;
rcestate->es_part_prune_results = parentestate->es_part_prune_results;
/* We'll also borrow the es_partition_directory from the parent state */
rcestate->es_partition_directory = parentestate->es_partition_directory;
/*
* 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(rcestate->es_subplanstates == NIL);
foreach(l, parentestate->es_plannedstmt->subplans)
{
Plan *subplan = (Plan *) lfirst(l);
PlanState *subplanstate;
/*
* Build an RTI indexed array of rowmarks, so that
* EvalPlanQualFetchRowMark() can efficiently access the to be fetched
* rowmark.
*/
epqstate->relsubs_rowmark = (ExecAuxRowMark **)
palloc0(rtsize * sizeof(ExecAuxRowMark *));
foreach(l, epqstate->arowMarks)
{
ExecAuxRowMark *earm = (ExecAuxRowMark *) lfirst(l);
/*
* Initialize per-relation EPQ tuple states. Result relations, if any,
* get marked as blocked; others as not-fetched.
*/
epqstate->relsubs_done = palloc_array(bool, rtsize);
epqstate->relsubs_blocked = palloc0_array(bool, rtsize);
foreach(l, epqstate->resultRelations)
{
int rtindex = lfirst_int(l);
/*
* 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->recheckplanstate = ExecInitNode(planTree, rcestate, 0);
MemoryContextSwitchTo(oldcontext);
}
/*
* EvalPlanQualEnd -- shut down at termination of parent plan state node,
* or if we are done with the current EPQ child.
*
* This is a cut-down version of ExecutorEnd(); basically we want to do most
* of the normal cleanup, but *not* close result relations (which we are
* just sharing from the outer query). We do, however, have to close any
* result and trigger target relations that got opened, since those are not
* shared. (There probably shouldn't be any of the latter, but just in
* case...)
*/
void
EvalPlanQualEnd(EPQState *epqstate)
{
EState *estate = epqstate->recheckestate;
Index rtsize;
MemoryContext oldcontext;
ListCell *l;
/*
* We may have a tuple table, even if EPQ wasn't started, because we allow
* use of EvalPlanQualSlot() without calling EvalPlanQualBegin().
*/
if (epqstate->tuple_table != NIL)
{
memset(epqstate->relsubs_slot, 0,
rtsize * sizeof(TupleTableSlot *));
ExecResetTupleTable(epqstate->tuple_table, true);
epqstate->tuple_table = NIL;
}
/* EPQ wasn't started, nothing further to do */
if (estate == NULL)
return;
/* throw away the per-estate tuple table, some node may have used it */
ExecResetTupleTable(estate->es_tupleTable, false);
/* Close any result and trigger target relations attached to this EState */
ExecCloseResultRelations(estate);
MemoryContextSwitchTo(oldcontext);
/*
* NULLify the partition directory before freeing the executor state.
* Since EvalPlanQualStart() just borrowed the parent EState's directory,
* we'd better leave it up to the parent to delete it.
*/
estate->es_partition_directory = NULL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.