📄 execmain.c
字号:
TupleDesc tupType; /* * Do permissions checks. It's sufficient to examine the query's top * rangetable here --- subplan RTEs will be checked during * ExecInitSubPlan(). */ ExecCheckRTPerms(parseTree->rtable); /* * get information from query descriptor */ rangeTable = parseTree->rtable; /* * initialize the node's execution state */ estate->es_range_table = rangeTable; /* * if there is a result relation, initialize result relation stuff */ if (parseTree->resultRelation != 0 && operation != CMD_SELECT) { List *resultRelations = parseTree->resultRelations; int numResultRelations; ResultRelInfo *resultRelInfos; if (resultRelations != NIL) { /* * Multiple result relations (due to inheritance) * parseTree->resultRelations identifies them all */ ResultRelInfo *resultRelInfo; ListCell *l; numResultRelations = list_length(resultRelations); resultRelInfos = (ResultRelInfo *) palloc(numResultRelations * sizeof(ResultRelInfo)); resultRelInfo = resultRelInfos; foreach(l, resultRelations) { initResultRelInfo(resultRelInfo, lfirst_int(l), rangeTable, operation, estate->es_instrument); resultRelInfo++; } } else { /* * Single result relation identified by parseTree->resultRelation */ numResultRelations = 1; resultRelInfos = (ResultRelInfo *) palloc(sizeof(ResultRelInfo)); initResultRelInfo(resultRelInfos, parseTree->resultRelation, rangeTable, operation, estate->es_instrument); } estate->es_result_relations = resultRelInfos; estate->es_num_result_relations = numResultRelations; /* Initialize to first or only result rel */ estate->es_result_relation_info = resultRelInfos; } 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; } /* * Detect whether we're doing SELECT INTO. If so, set the es_into_oids * flag appropriately so that the plan tree will be initialized with the * correct tuple descriptors. */ do_select_into = false; if (operation == CMD_SELECT && parseTree->into != NULL) { do_select_into = true; estate->es_select_into = true; estate->es_into_oids = parseTree->intoHasOids; } /* * Have to lock relations selected FOR UPDATE/FOR SHARE */ estate->es_rowMarks = NIL; estate->es_forUpdate = parseTree->forUpdate; estate->es_rowNoWait = parseTree->rowNoWait; if (parseTree->rowMarks != NIL) { ListCell *l; foreach(l, parseTree->rowMarks) { Index rti = lfirst_int(l); Oid relid = getrelid(rti, rangeTable); Relation relation; execRowMark *erm; relation = heap_open(relid, RowShareLock); erm = (execRowMark *) palloc(sizeof(execRowMark)); erm->relation = relation; erm->rti = rti; snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rti); estate->es_rowMarks = lappend(estate->es_rowMarks, erm); } } /* * initialize the executor "tuple" table. We need slots for all the plan * nodes, plus possibly output slots for the junkfilter(s). At this point * we aren't sure if we need junkfilters, so just add slots for them * unconditionally. Also, if it's not a SELECT, set up a slot for use for * trigger output tuples. */ { int nSlots = ExecCountSlotsNode(plan); if (parseTree->resultRelations != NIL) nSlots += list_length(parseTree->resultRelations); else nSlots += 1; if (operation != CMD_SELECT) nSlots++; estate->es_tupleTable = ExecCreateTupleTable(nSlots); if (operation != CMD_SELECT) estate->es_trig_tuple_slot = ExecAllocTableSlot(estate->es_tupleTable); } /* mark EvalPlanQual not active */ estate->es_topPlan = plan; estate->es_evalPlanQual = NULL; estate->es_evTupleNull = NULL; estate->es_evTuple = NULL; estate->es_useEvalPlan = false; /* * 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); /* * Get the tuple descriptor describing the type of tuples to return. (this * is especially important if we are creating a relation with "SELECT * INTO") */ tupType = ExecGetResultType(planstate); /* * Initialize the junk filter if needed. SELECT and INSERT queries need a * filter if there are any junk attrs in the tlist. INSERT and SELECT * INTO also need a filter if the plan may return raw disk tuples (else * heap_insert will be scribbling on the source relation!). UPDATE and * DELETE always need a filter, since there's always a junk 'ctid' * attribute present --- no need to look first. */ { bool junk_filter_needed = false; ListCell *tlist; switch (operation) { case CMD_SELECT: case CMD_INSERT: foreach(tlist, plan->targetlist) { TargetEntry *tle = (TargetEntry *) lfirst(tlist); if (tle->resjunk) { junk_filter_needed = true; break; } } if (!junk_filter_needed && (operation == CMD_INSERT || do_select_into) && ExecMayReturnRawTuples(planstate)) junk_filter_needed = true; break; case CMD_UPDATE: case CMD_DELETE: junk_filter_needed = true; break; default: break; } if (junk_filter_needed) { /* * If there are multiple result relations, each one needs its own * junk filter. Note this is only possible for UPDATE/DELETE, so * we can't be fooled by some needing a filter and some not. */ if (parseTree->resultRelations != NIL) { PlanState **appendplans; int as_nplans; ResultRelInfo *resultRelInfo; int i; /* Top plan had better be an Append here. */ Assert(IsA(plan, Append)); Assert(((Append *) plan)->isTarget); Assert(IsA(planstate, AppendState)); appendplans = ((AppendState *) planstate)->appendplans; as_nplans = ((AppendState *) planstate)->as_nplans; Assert(as_nplans == estate->es_num_result_relations); resultRelInfo = estate->es_result_relations; for (i = 0; i < as_nplans; i++) { PlanState *subplan = appendplans[i]; JunkFilter *j; j = ExecInitJunkFilter(subplan->plan->targetlist, resultRelInfo->ri_RelationDesc->rd_att->tdhasoid, ExecAllocTableSlot(estate->es_tupleTable)); resultRelInfo->ri_junkFilter = j; resultRelInfo++; } /* * Set active junkfilter too; at this point ExecInitAppend has * already selected an active result relation... */ estate->es_junkFilter = estate->es_result_relation_info->ri_junkFilter; } else { /* Normal case with just one JunkFilter */ JunkFilter *j; j = ExecInitJunkFilter(planstate->plan->targetlist, tupType->tdhasoid, ExecAllocTableSlot(estate->es_tupleTable)); estate->es_junkFilter = j; if (estate->es_result_relation_info) estate->es_result_relation_info->ri_junkFilter = j; /* For SELECT, want to return the cleaned tuple type */ if (operation == CMD_SELECT) tupType = j->jf_cleanTupType; } } else estate->es_junkFilter = NULL; } /* * If doing SELECT INTO, initialize the "into" relation. We must wait * till now so we have the "clean" result tuple type to create the new * table from. * * If EXPLAIN, skip creating the "into" relation. */ intoRelationDesc = NULL; if (do_select_into && !explainOnly) { char *intoName; Oid namespaceId; Oid tablespaceId; AclResult aclresult; Oid intoRelationId; TupleDesc tupdesc; /* * find namespace to create in, check permissions */ intoName = parseTree->into->relname; namespaceId = RangeVarGetCreationNamespace(parseTree->into); aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); tablespaceId = GetDefaultTablespace(); if (OidIsValid(tablespaceId)) { aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_TABLESPACE, get_tablespace_name(tablespaceId)); } /* * have to copy tupType to get rid of constraints */ tupdesc = CreateTupleDescCopy(tupType); intoRelationId = heap_create_with_catalog(intoName, namespaceId, tablespaceId, InvalidOid, GetUserId(), tupdesc, RELKIND_RELATION, false, true, 0, ONCOMMIT_NOOP, allowSystemTableMods); FreeTupleDesc(tupdesc); /* * Advance command counter so that the newly-created relation's * catalog tuples will be visible to heap_open. */ CommandCounterIncrement(); /* * If necessary, create a TOAST table for the into relation. Note that * AlterTableCreateToastTable ends with CommandCounterIncrement(), so * that the TOAST table will be visible for insertion. */ AlterTableCreateToastTable(intoRelationId, true); /* * And open the constructed table for writing. */ intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock); /* use_wal off requires rd_targblock be initially invalid */ Assert(intoRelationDesc->rd_targblock == InvalidBlockNumber); /* * We can skip WAL-logging the insertions, unless PITR is in use. * * Note that for a non-temp INTO table, this is safe only because we * know that the catalog changes above will have been WAL-logged, and * so RecordTransactionCommit will think it needs to WAL-log the * eventual transaction commit. Else the commit might be lost, even * though all the data is safely fsync'd ... */ estate->es_into_relation_use_wal = XLogArchivingActive(); } estate->es_into_relation_descriptor = intoRelationDesc; queryDesc->tupDesc = tupType; queryDesc->planstate = planstate;}/* * Initialize ResultRelInfo data for one result relation */static voidinitResultRelInfo(ResultRelInfo *resultRelInfo, Index resultRelationIndex, List *rangeTable, CmdType operation, bool doInstrument){ Oid resultRelationOid; Relation resultRelationDesc; resultRelationOid = getrelid(resultRelationIndex, rangeTable); resultRelationDesc = heap_open(resultRelationOid, RowExclusiveLock); switch (resultRelationDesc->rd_rel->relkind) { case RELKIND_SEQUENCE: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot change sequence \"%s\"", RelationGetRelationName(resultRelationDesc)))); break; case RELKIND_TOASTVALUE: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot change TOAST relation \"%s\"", RelationGetRelationName(resultRelationDesc)))); break; case RELKIND_VIEW: ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot change view \"%s\"", RelationGetRelationName(resultRelationDesc)))); break; } 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)); if (doInstrument) resultRelInfo->ri_TrigInstrument = InstrAlloc(n); else resultRelInfo->ri_TrigInstrument = NULL; } else { resultRelInfo->ri_TrigFunctions = NULL; resultRelInfo->ri_TrigInstrument = NULL; } resultRelInfo->ri_ConstraintExprs = NULL; resultRelInfo->ri_junkFilter = NULL; /* * If there are indices on the result relation, open them and save * descriptors in the result relation info, so that we can add new index * entries for the tuples we add/update. We need not do this for a * DELETE, however, since deletion doesn't affect indexes. */ if (resultRelationDesc->rd_rel->relhasindex && operation != CMD_DELETE) ExecOpenIndices(resultRelInfo);}/* * ExecContextForcesOids * * This is pretty grotty: when doing INSERT, UPDATE, or SELECT INTO, * we need to ensure that result tuples have space for an OID iff they are * going to be stored into a relation that has OIDs. In other contexts * we are free to choose whether to leave space for OIDs in result tuples * (we generally don't want to, but we do if a physical-tlist optimization * is possible). This routine checks the plan context and returns TRUE if the * choice is forced, FALSE if the choice is not forced. In the TRUE case, * *hasoids is set to the required value. * * One reason this is ugly is that all plan nodes in the plan tree will emit * tuples with space for an OID, though we really only need the topmost node * to do so. However, node types like Sort don't project new tuples but just * return their inputs, and in those cases the requirement propagates down * to the input node. Eventually we might make this code smart enough to * recognize how far down the requirement really goes, but for now we just * make all plan nodes do the same thing if the top level forces the choice.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -