📄 execmain.c
字号:
slot = ExecStoreTuple(tuple, slot, InvalidBuffer, true); goto lreplace; } } return; default: elog(ERROR, "Unknown status %u from heap_replace", result); return; } IncrReplaced(); (estate->es_processed)++; /* * Note: instead of having to update the old index tuples associated * with the heap tuple, all we do is form and insert new index * tuples.. This is because replaces are actually deletes and inserts * and index tuple deletion is done automagically by the vaccuum * deamon.. All we do is insert new index tuples. -cim 9/27/89 */ /* * process indices * * heap_replace updates a tuple in the base relation by invalidating it * and then appending a new tuple to the relation. As a side effect, * the tupleid of the new tuple is placed in the new tuple's t_ctid * field. So we now insert index tuples using the new tupleid stored * there. */ numIndices = resultRelationInfo->ri_NumIndices; if (numIndices > 0) ExecInsertIndexTuples(slot, &(tuple->t_self), estate, true); /* AFTER ROW UPDATE Triggers */ if (resultRelationDesc->trigdesc && resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0) ExecARUpdateTriggers(estate, tupleid, tuple);}#ifdef NOT_USEDstatic HeapTupleExecAttrDefault(Relation rel, HeapTuple tuple){ int ndef = rel->rd_att->constr->num_defval; AttrDefault *attrdef = rel->rd_att->constr->defval; ExprContext *econtext = makeNode(ExprContext); HeapTuple newtuple; Node *expr; bool isnull; bool isdone; Datum val; Datum *replValue = NULL; char *replNull = NULL; char *repl = NULL; int i; econtext->ecxt_scantuple = NULL; /* scan tuple slot */ econtext->ecxt_innertuple = NULL; /* inner tuple slot */ econtext->ecxt_outertuple = NULL; /* outer tuple slot */ econtext->ecxt_relation = NULL; /* relation */ econtext->ecxt_relid = 0; /* relid */ econtext->ecxt_param_list_info = NULL; /* param list info */ econtext->ecxt_param_exec_vals = NULL; /* exec param values */ econtext->ecxt_range_table = NULL; /* range table */ for (i = 0; i < ndef; i++) { if (!heap_attisnull(tuple, attrdef[i].adnum)) continue; expr = (Node *) stringToNode(attrdef[i].adbin); val = ExecEvalExpr(expr, econtext, &isnull, &isdone); pfree(expr); if (isnull) continue; if (repl == NULL) { repl = (char *) palloc(rel->rd_att->natts * sizeof(char)); replNull = (char *) palloc(rel->rd_att->natts * sizeof(char)); replValue = (Datum *) palloc(rel->rd_att->natts * sizeof(Datum)); MemSet(repl, ' ', rel->rd_att->natts * sizeof(char)); } repl[attrdef[i].adnum - 1] = 'r'; replNull[attrdef[i].adnum - 1] = ' '; replValue[attrdef[i].adnum - 1] = val; } pfree(econtext); if (repl == NULL) return tuple; newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl); pfree(repl); pfree(tuple); pfree(replNull); pfree(replValue); return newtuple;}#endifstatic char *ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate){ int ncheck = rel->rd_att->constr->num_check; ConstrCheck *check = rel->rd_att->constr->check; ExprContext *econtext = makeNode(ExprContext); TupleTableSlot *slot = makeNode(TupleTableSlot); RangeTblEntry *rte = makeNode(RangeTblEntry); List *rtlist; List *qual; bool res; int i; slot->val = tuple; slot->ttc_shouldFree = false; slot->ttc_descIsNew = true; slot->ttc_tupleDescriptor = rel->rd_att; slot->ttc_buffer = InvalidBuffer; slot->ttc_whichplan = -1; rte->relname = nameout(&(rel->rd_rel->relname)); rte->refname = rte->relname; rte->relid = RelationGetRelid(rel); rte->inh = false; rte->inFromCl = true; rtlist = lcons(rte, NIL); econtext->ecxt_scantuple = slot; /* scan tuple slot */ econtext->ecxt_innertuple = NULL; /* inner tuple slot */ econtext->ecxt_outertuple = NULL; /* outer tuple slot */ econtext->ecxt_relation = rel; /* relation */ econtext->ecxt_relid = 0; /* relid */ econtext->ecxt_param_list_info = NULL; /* param list info */ econtext->ecxt_param_exec_vals = NULL; /* exec param values */ econtext->ecxt_range_table = rtlist; /* range table */ if (estate->es_result_relation_constraints == NULL) { estate->es_result_relation_constraints = (List **) palloc(ncheck * sizeof(List *)); for (i = 0; i < ncheck; i++) { qual = (List *) stringToNode(check[i].ccbin); estate->es_result_relation_constraints[i] = qual; } } for (i = 0; i < ncheck; i++) { qual = estate->es_result_relation_constraints[i]; res = ExecQual(qual, econtext); if (!res) return check[i].ccname; } pfree(slot); pfree(rte->relname); pfree(rte); pfree(rtlist); pfree(econtext); return (char *) NULL;}voidExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate){ Assert(rel->rd_att->constr); if (rel->rd_att->constr->has_not_null) { int attrChk; for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++) { if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk)) elog(ERROR, "%s: Fail to add null value in not null attribute %s", caller, rel->rd_att->attrs[attrChk - 1]->attname.data); } } if (rel->rd_att->constr->num_check > 0) { char *failed; if ((failed = ExecRelCheck(rel, tuple, estate)) != NULL) elog(ERROR, "%s: rejected due to CHECK constraint %s", caller, failed); } return;}TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid){ evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual; evalPlanQual *oldepq; EState *epqstate = NULL; Relation relation; Buffer buffer; HeapTupleData tuple; bool endNode = true; Assert(rti != 0); if (epq != NULL && epq->rti == 0) { Assert(!(estate->es_useEvalPlan) && epq->estate.es_evalPlanQual == NULL); epq->rti = rti; endNode = false; } /* * If this is request for another RTE - Ra, - then we have to check * wasn't PlanQual requested for Ra already and if so then Ra' row was * updated again and we have to re-start old execution for Ra and * forget all what we done after Ra was suspended. Cool? -:)) */ if (epq != NULL && epq->rti != rti && epq->estate.es_evTuple[rti - 1] != NULL) { do { /* pop previous PlanQual from the stack */ epqstate = &(epq->estate); oldepq = (evalPlanQual *) epqstate->es_evalPlanQual; Assert(oldepq->rti != 0); /* stop execution */ ExecEndNode(epq->plan, epq->plan); epqstate->es_tupleTable->next = 0; pfree(epqstate->es_evTuple[epq->rti - 1]); epqstate->es_evTuple[epq->rti - 1] = NULL; /* push current PQ to freePQ stack */ oldepq->free = epq; epq = oldepq; } while (epq->rti != rti); estate->es_evalPlanQual = (Pointer) epq; } /* * If we are requested for another RTE then we have to suspend * execution of current PlanQual and start execution for new one. */ if (epq == NULL || epq->rti != rti) { /* try to reuse plan used previously */ evalPlanQual *newepq = (epq != NULL) ? epq->free : NULL; if (newepq == NULL) /* first call or freePQ stack is empty */ { newepq = (evalPlanQual *) palloc(sizeof(evalPlanQual)); /* Init EState */ epqstate = &(newepq->estate); memset(epqstate, 0, sizeof(EState)); epqstate->type = T_EState; epqstate->es_direction = ForwardScanDirection; epqstate->es_snapshot = estate->es_snapshot; epqstate->es_range_table = estate->es_range_table; epqstate->es_param_list_info = estate->es_param_list_info; if (estate->es_origPlan->nParamExec > 0) epqstate->es_param_exec_vals = (ParamExecData *) palloc(estate->es_origPlan->nParamExec * sizeof(ParamExecData)); epqstate->es_tupleTable = ExecCreateTupleTable(estate->es_tupleTable->size); epqstate->es_refcount = estate->es_refcount; /* ... rest */ newepq->plan = copyObject(estate->es_origPlan); newepq->free = NULL; epqstate->es_evTupleNull = (bool *) palloc(length(estate->es_range_table) * sizeof(bool)); if (epq == NULL) /* first call */ { epqstate->es_evTuple = (HeapTuple *) palloc(length(estate->es_range_table) * sizeof(HeapTuple)); memset(epqstate->es_evTuple, 0, length(estate->es_range_table) * sizeof(HeapTuple)); } else epqstate->es_evTuple = epq->estate.es_evTuple; } else epqstate = &(newepq->estate); /* push current PQ to the stack */ epqstate->es_evalPlanQual = (Pointer) epq; epq = newepq; estate->es_evalPlanQual = (Pointer) epq; epq->rti = rti; endNode = false; } epqstate = &(epq->estate); /* * Ok - we're requested for the same RTE (-:)). I'm not sure about * ability to use ExecReScan instead of ExecInitNode, so... */ if (endNode) { ExecEndNode(epq->plan, epq->plan); epqstate->es_tupleTable->next = 0; } /* free old RTE' tuple */ if (epqstate->es_evTuple[epq->rti - 1] != NULL) { pfree(epqstate->es_evTuple[epq->rti - 1]); epqstate->es_evTuple[epq->rti - 1] = NULL; } /* ** fetch tid tuple ** */ if (estate->es_result_relation_info != NULL && estate->es_result_relation_info->ri_RangeTableIndex == rti) relation = estate->es_result_relation_info->ri_RelationDesc; else { List *l; foreach(l, estate->es_rowMark) { if (((execRowMark *) lfirst(l))->rti == rti) break; } relation = ((execRowMark *) lfirst(l))->relation; } tuple.t_self = *tid; for (;;) { heap_fetch(relation, SnapshotDirty, &tuple, &buffer); if (tuple.t_data != NULL) { TransactionId xwait = SnapshotDirty->xmax; if (TransactionIdIsValid(SnapshotDirty->xmin)) { elog(NOTICE, "EvalPlanQual: t_xmin is uncommitted ?!"); Assert(!TransactionIdIsValid(SnapshotDirty->xmin)); elog(ERROR, "Aborting this transaction"); } /* * If tuple is being updated by other transaction then we have * to wait for its commit/abort. */ if (TransactionIdIsValid(xwait)) { ReleaseBuffer(buffer); XactLockTableWait(xwait); continue; } /* * Nice! We got tuple - now copy it. */ if (epqstate->es_evTuple[epq->rti - 1] != NULL) pfree(epqstate->es_evTuple[epq->rti - 1]); epqstate->es_evTuple[epq->rti - 1] = heap_copytuple(&tuple); ReleaseBuffer(buffer); break; } /* * Ops! Invalid tuple. Have to check is it updated or deleted. * Note that it's possible to get invalid SnapshotDirty->tid if * tuple updated by this transaction. Have we to check this ? */ if (ItemPointerIsValid(&(SnapshotDirty->tid)) && !(ItemPointerEquals(&(tuple.t_self), &(SnapshotDirty->tid)))) { tuple.t_self = SnapshotDirty->tid; /* updated ... */ continue; } /* * Deleted or updated by this transaction. Do not (re-)start * execution of this PQ. Continue previous PQ. */ oldepq = (evalPlanQual *) epqstate->es_evalPlanQual; if (oldepq != NULL) { Assert(oldepq->rti != 0); /* push current PQ to freePQ stack */ oldepq->free = epq; epq = oldepq; epqstate = &(epq->estate); estate->es_evalPlanQual = (Pointer) epq; } else { epq->rti = 0; /* this is the first (oldest) */ estate->es_useEvalPlan = false; /* PQ - mark as free and */ return (NULL); /* continue Query execution */ } } if (estate->es_origPlan->nParamExec > 0) memset(epqstate->es_param_exec_vals, 0, estate->es_origPlan->nParamExec * sizeof(ParamExecData)); memset(epqstate->es_evTupleNull, false, length(estate->es_range_table) * sizeof(bool)); Assert(epqstate->es_tupleTable->next == 0); ExecInitNode(epq->plan, epqstate, NULL); /* * For UPDATE/DELETE we have to return tid of actual row we're * executing PQ for. */ *tid = tuple.t_self; return (EvalPlanQualNext(estate));}static TupleTableSlot *EvalPlanQualNext(EState *estate){ evalPlanQual *epq = (evalPlanQual *) estate->es_evalPlanQual; EState *epqstate = &(epq->estate); evalPlanQual *oldepq; TupleTableSlot *slot; Assert(epq->rti != 0);lpqnext:; slot = ExecProcNode(epq->plan, epq->plan); /* * No more tuples for this PQ. Continue previous one. */ if (TupIsNull(slot)) { ExecEndNode(epq->plan, epq->plan); epqstate->es_tupleTable->next = 0; pfree(epqstate->es_evTuple[epq->rti - 1]); epqstate->es_evTuple[epq->rti - 1] = NULL; /* pop old PQ from the stack */ oldepq = (evalPlanQual *) epqstate->es_evalPlanQual; if (oldepq == (evalPlanQual *) NULL) { epq->rti = 0; /* this is the first (oldest) */ estate->es_useEvalPlan = false; /* PQ - mark as free and */ return (NULL); /* continue Query execution */ } Assert(oldepq->rti != 0); /* push current PQ to freePQ stack */ oldepq->free = epq; epq = oldepq; epqstate = &(epq->estate); estate->es_evalPlanQual = (Pointer) epq; goto lpqnext; } return (slot);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -