📄 execmain.c
字号:
/* Reset the per-output-tuple exprcontext */ ResetPerTupleExprContext(estate); /* * Execute the plan and obtain a tuple */lnext: ; if (estate->es_useEvalPlan) { slot = EvalPlanQualNext(estate); if (TupIsNull(slot)) slot = ExecProcNode(planstate); } else slot = ExecProcNode(planstate); /* * if the tuple is null, then we assume there is nothing more to * process so we just return null... */ if (TupIsNull(slot)) { result = NULL; 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.) * * Also, extract all the junk information we need. */ if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL) { Datum datum; HeapTuple newTuple; bool isNull; /* * extract the 'ctid' junk attribute. */ if (operation == CMD_UPDATE || operation == CMD_DELETE) { if (!ExecGetJunkAttribute(junkfilter, slot, "ctid", &datum, &isNull)) elog(ERROR, "could not find junk ctid column"); /* shouldn't ever get a null result... */ if (isNull) elog(ERROR, "ctid is NULL"); tupleid = (ItemPointer) DatumGetPointer(datum); tuple_ctid = *tupleid; /* make sure we don't free the * ctid!! */ tupleid = &tuple_ctid; } else if (estate->es_rowMark != NIL) { List *l; lmark: ; foreach(l, estate->es_rowMark) { execRowMark *erm = lfirst(l); Buffer buffer; HeapTupleData tuple; TupleTableSlot *newSlot; int test; if (!ExecGetJunkAttribute(junkfilter, slot, erm->resname, &datum, &isNull)) elog(ERROR, "could not find junk \"%s\" column", erm->resname); /* shouldn't ever get a null result... */ if (isNull) elog(ERROR, "\"%s\" is NULL", erm->resname); tuple.t_self = *((ItemPointer) DatumGetPointer(datum)); test = heap_mark4update(erm->relation, &tuple, &buffer, estate->es_snapshot->curcid); ReleaseBuffer(buffer); switch (test) { case HeapTupleSelfUpdated: /* treat it as deleted; do not process */ goto lnext; case HeapTupleMayBeUpdated: break; case HeapTupleUpdated: if (XactIsoLevel == XACT_SERIALIZABLE) ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), errmsg("could not serialize access due to concurrent update"))); if (!(ItemPointerEquals(&(tuple.t_self), (ItemPointer) DatumGetPointer(datum)))) { newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self)); if (!(TupIsNull(newSlot))) { slot = newSlot; estate->es_useEvalPlan = true; goto lmark; } } /* * if tuple was deleted or PlanQual failed for * updated tuple - we must not return this * tuple! */ goto lnext; default: elog(ERROR, "unrecognized heap_mark4update status: %u", test); return (NULL); } } } /* * Finally create a new "clean" tuple with all junk attributes * removed */ newTuple = ExecRemoveJunk(junkfilter, slot); slot = ExecStoreTuple(newTuple, /* tuple to store */ junkfilter->jf_resultSlot, /* dest slot */ InvalidBuffer, /* this tuple has no * buffer */ true); /* tuple should be pfreed */ } /* * now that we have a tuple, do the appropriate thing with it.. * either return it to the user, add it to a relation someplace, * delete it from a relation, or modify some of its attributes. */ switch (operation) { case CMD_SELECT: ExecSelect(slot, /* slot containing tuple */ dest, /* destination's tuple-receiver obj */ estate); result = slot; break; case CMD_INSERT: ExecInsert(slot, tupleid, estate); result = NULL; break; case CMD_DELETE: ExecDelete(slot, tupleid, estate); result = NULL; break; case CMD_UPDATE: ExecUpdate(slot, tupleid, estate); result = NULL; break; default: elog(ERROR, "unrecognized operation code: %d", (int) operation); result = NULL; break; } /* * 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; } /* * Process AFTER EACH STATEMENT triggers */ switch (operation) { case CMD_UPDATE: ExecASUpdateTriggers(estate, estate->es_result_relation_info); break; case CMD_DELETE: ExecASDeleteTriggers(estate, estate->es_result_relation_info); break; case CMD_INSERT: ExecASInsertTriggers(estate, estate->es_result_relation_info); break; default: /* do nothing */ break; } /* * here, result is either a slot containing a tuple in the case of a * SELECT or NULL otherwise. */ return result;}/* ---------------------------------------------------------------- * ExecSelect * * SELECTs are easy.. we just pass the tuple to the appropriate * print function. The only complexity is when we do a * "SELECT INTO", in which case we insert the tuple into * the appropriate relation (note: this is a newly created relation * so we don't need to worry about indices or locks.) * ---------------------------------------------------------------- */static voidExecSelect(TupleTableSlot *slot, DestReceiver *dest, EState *estate){ HeapTuple tuple; TupleDesc attrtype; /* * get the heap tuple out of the tuple table slot */ tuple = slot->val; attrtype = slot->ttc_tupleDescriptor; /* * insert the tuple into the "into relation" * * XXX this probably ought to be replaced by a separate destination */ if (estate->es_into_relation_descriptor != NULL) { heap_insert(estate->es_into_relation_descriptor, tuple, estate->es_snapshot->curcid); IncrAppended(); } /* * send the tuple to the destination */ (*dest->receiveTuple) (tuple, attrtype, dest); IncrRetrieved(); (estate->es_processed)++;}/* ---------------------------------------------------------------- * ExecInsert * * INSERTs are trickier.. we have to insert the tuple into * the base relation and insert appropriate tuples into the * index relations. * ---------------------------------------------------------------- */static voidExecInsert(TupleTableSlot *slot, ItemPointer tupleid, EState *estate){ HeapTuple tuple; ResultRelInfo *resultRelInfo; Relation resultRelationDesc; int numIndices; Oid newId; /* * get the heap tuple out of the tuple table slot */ tuple = slot->val; /* * get information on the (current) result relation */ resultRelInfo = estate->es_result_relation_info; resultRelationDesc = resultRelInfo->ri_RelationDesc; /* BEFORE ROW INSERT Triggers */ if (resultRelInfo->ri_TrigDesc && resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) { HeapTuple newtuple; newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple); if (newtuple == NULL) /* "do nothing" */ return; if (newtuple != tuple) /* modified by Trigger(s) */ { /* * Insert modified tuple into tuple table slot, replacing the * original. We assume that it was allocated in per-tuple * memory context, and therefore will go away by itself. The * tuple table slot should not try to clear it. */ ExecStoreTuple(newtuple, slot, InvalidBuffer, false); tuple = newtuple; } } /* * Check the constraints of the tuple */ if (resultRelationDesc->rd_att->constr) ExecConstraints(resultRelInfo, slot, estate); /* * insert the tuple */ newId = heap_insert(resultRelationDesc, tuple, estate->es_snapshot->curcid); IncrAppended(); (estate->es_processed)++; estate->es_lastoid = newId; setLastTid(&(tuple->t_self)); /* * process indices * * Note: heap_insert adds a new tuple to a relation. As a side effect, * the tupleid of the new tuple is placed in the new tuple's t_ctid * field. */ numIndices = resultRelInfo->ri_NumIndices; if (numIndices > 0) ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); /* AFTER ROW INSERT Triggers */ ExecARInsertTriggers(estate, resultRelInfo, tuple);}/* ---------------------------------------------------------------- * ExecDelete * * DELETE is like UPDATE, we delete the tuple and its * index tuples. * ---------------------------------------------------------------- */static voidExecDelete(TupleTableSlot *slot, ItemPointer tupleid, EState *estate){ ResultRelInfo *resultRelInfo; Relation resultRelationDesc; ItemPointerData ctid; int result; /* * get information on the (current) result relation */ resultRelInfo = estate->es_result_relation_info; resultRelationDesc = resultRelInfo->ri_RelationDesc; /* BEFORE ROW DELETE Triggers */ if (resultRelInfo->ri_TrigDesc && resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_DELETE] > 0) { bool dodelete; dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid, estate->es_snapshot->curcid); if (!dodelete) /* "do nothing" */ return; } /* * delete the tuple */ldelete:; result = heap_delete(resultRelationDesc, tupleid, &ctid, estate->es_snapshot->curcid, estate->es_crosscheck_snapshot, true /* wait for commit */); switch (result) { case HeapTupleSelfUpdated: /* already deleted by self; nothing to do */ return; case HeapTupleMayBeUpdated: break; case HeapTupleUpdated: if (XactIsoLevel == XACT_SERIALIZABLE) ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), errmsg("could not serialize access due to concurrent update"))); else if (!(ItemPointerEquals(tupleid, &ctid))) { TupleTableSlot *epqslot = EvalPlanQual(estate, resultRelInfo->ri_RangeTableIndex, &ctid); if (!TupIsNull(epqslot)) { *tupleid = ctid; goto ldelete; } } /* tuple already deleted; nothing to do */ return; default: elog(ERROR, "unrecognized heap_delete status: %u", result); return; } IncrDeleted(); (estate->es_processed)++; /* * Note: Normally one would think that we have to delete index tuples * associated with the heap tuple now.. * * ... but in POSTGRES, we have no need to do this because the vacuum * daemon automatically opens an index scan and deletes index tuples * when it finds deleted heap tuples. -cim 9/27/89 */ /* AFTER ROW DELETE Triggers */ ExecARDeleteTriggers(estate, resultRelInfo, tupleid);}/* ---------------------------------------------------------------- * ExecUpdate * * note: we can't run UPDATE queries with transactions * off because UPDATEs are actually INSERTs and our * scan will mistakenly loop forever, updating the tuple * it just inserted.. This should be fixed but until it * is, we don't want to get stuck in an infinite loop * which corrupts your database.. * ---------------------------------------------------------------- */static voidExecUpdate(TupleTableSlot *slot, ItemPointer tupleid, EState *estate){ HeapTuple tuple; ResultRelInfo *resultRelInfo; Relation resultRelationDesc; ItemPointerData ctid; int result; int numIndices; /* * abort the operation if not running transactions */ if (IsBootstrapProcessingMode()) elog(ERROR, "cannot UPDATE during bootstrap"); /* * get the heap tuple out of the tuple table slot */ tuple = slot->val; /* * get information on the (current) result relation */ resultRelInfo = estate->es_result_relation_info; resultRelationDesc = resultRelInfo->ri_RelationDesc; /* BEFORE ROW UPDATE Triggers */ if (resultRelInfo->ri_TrigDesc && resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0) { HeapTuple newtuple; newtuple = ExecBRUpdateTriggers(estate, resultRelInfo, tupleid, tuple, estate->es_snapshot->curcid); if (newtuple == NULL) /* "do nothing" */ return; if (newtuple != tuple) /* modified by Trigger(s) */ { /* * Insert modified tuple into tuple table slot, replacing the * original. We assume that it was allocated in per-tuple * memory context, and therefore will go away by itself. The * tuple table slot should not try to clear it. */ ExecStoreTuple(newtuple, slot, InvalidBuffer, false); tuple = newtuple; } } /* * Check the constraints of the tuple * * If we generate a new candidate tuple after EvalPlanQual testing, we * must loop back here and recheck constraints. (We don't need to * redo triggers, however. If there are any BEFORE triggers then * trigger.c will have done mark4update to lock the correct tuple, so * there's no need to do them again.) */lreplace:; if (resultRelationDesc->rd_att->constr) ExecConstraints(resultRelInfo, slot, estate); /* * replace the heap tuple */ result = heap_update(resultRelationDesc, tupleid, tuple, &ctid, estate->es_snapshot->curcid, estate->es_crosscheck_snapshot, true /* wait for commit */); switch (result) { case HeapTupleSelfUpdated: /* already deleted by self; nothing to do */ return; case HeapTupleMayBeUpdated: break; case HeapTupleUpdated: if (XactIsoLevel == XACT_SERIALIZABLE) ereport(ERROR, (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), errmsg("could not serialize access due to concurrent update"))); else if (!(ItemPointerEquals(tupleid, &ctid)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -