diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 52100e92dd..c71d081809 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.119 2000/07/14 22:17:42 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.120 2000/08/06 04:26:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -827,9 +827,10 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, * Check the constraints of the tuple * ---------------- */ + ExecStoreTuple(tuple, slot, InvalidBuffer, false); if (rel->rd_att->constr) - ExecConstraints("CopyFrom", rel, tuple, estate); + ExecConstraints("CopyFrom", rel, slot, estate); /* ---------------- * OK, store the tuple and create index entries for it @@ -838,10 +839,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, heap_insert(rel, tuple); if (relationInfo->ri_NumIndices > 0) - { - ExecStoreTuple(tuple, slot, InvalidBuffer, false); ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); - } /* AFTER ROW INSERT Triggers */ if (rel->trigdesc && diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 3125bf175e..e66107ce7d 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -27,7 +27,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.122 2000/07/12 02:37:00 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.123 2000/08/06 04:26:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1296,10 +1296,6 @@ ExecAppend(TupleTableSlot *slot, resultRelationInfo = estate->es_result_relation_info; resultRelationDesc = resultRelationInfo->ri_RelationDesc; - /* - * have to add code to preform unique checking here. cim -12/1/89 - */ - /* BEFORE ROW INSERT Triggers */ if (resultRelationDesc->trigdesc && resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) @@ -1320,18 +1316,20 @@ ExecAppend(TupleTableSlot *slot, } /* - * Check the constraints of a tuple + * Check the constraints of the tuple */ if (resultRelationDesc->rd_att->constr) - ExecConstraints("ExecAppend", resultRelationDesc, tuple, estate); + ExecConstraints("ExecAppend", resultRelationDesc, slot, estate); /* * insert the tuple */ - newId = heap_insert(resultRelationDesc, /* relation desc */ - tuple); /* heap tuple */ + newId = heap_insert(resultRelationDesc, tuple); + IncrAppended(); + (estate->es_processed)++; + estate->es_lastoid = newId; /* * process indices @@ -1343,8 +1341,6 @@ ExecAppend(TupleTableSlot *slot, numIndices = resultRelationInfo->ri_NumIndices; if (numIndices > 0) ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); - (estate->es_processed)++; - estate->es_lastoid = newId; /* AFTER ROW INSERT Triggers */ if (resultRelationDesc->trigdesc) @@ -1466,7 +1462,7 @@ ExecReplace(TupleTableSlot *slot, */ if (IsBootstrapProcessingMode()) { - elog(DEBUG, "ExecReplace: replace can't run without transactions"); + elog(NOTICE, "ExecReplace: replace can't run without transactions"); return; } @@ -1481,12 +1477,6 @@ ExecReplace(TupleTableSlot *slot, resultRelationInfo = estate->es_result_relation_info; resultRelationDesc = resultRelationInfo->ri_RelationDesc; - /* - * have to add code to preform unique checking here. in the event of - * unique tuples, this becomes a deletion of the original tuple - * affected by the replace. cim -12/1/89 - */ - /* BEFORE ROW UPDATE Triggers */ if (resultRelationDesc->trigdesc && resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0) @@ -1507,11 +1497,11 @@ ExecReplace(TupleTableSlot *slot, } /* - * Check the constraints of a tuple + * Check the constraints of the tuple */ if (resultRelationDesc->rd_att->constr) - ExecConstraints("ExecReplace", resultRelationDesc, tuple, estate); + ExecConstraints("ExecReplace", resultRelationDesc, slot, estate); /* * replace the heap tuple @@ -1555,9 +1545,9 @@ lreplace:; /* * 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 + * tuples. This is because replaces are actually deletes and inserts + * and index tuple deletion is done automagically by the vacuum + * daemon. All we do is insert new index tuples. -cim 9/27/89 */ /* @@ -1579,109 +1569,55 @@ lreplace:; ExecARUpdateTriggers(estate, tupleid, tuple); } -#ifdef NOT_USED -static HeapTuple -ExecAttrDefault(Relation rel, HeapTuple tuple) -{ - int ndef = rel->rd_att->constr->num_defval; - AttrDefault *attrdef = rel->rd_att->constr->defval; - ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext); - HeapTuple newtuple; - Node *expr; - bool isnull; - bool isdone; - Datum val; - Datum *replValue = NULL; - char *replNull = NULL; - char *repl = NULL; - int i; - - for (i = 0; i < ndef; i++) - { - if (!heap_attisnull(tuple, attrdef[i].adnum)) - continue; - expr = (Node *) stringToNode(attrdef[i].adbin); - - val = ExecEvalExprSwitchContext(expr, econtext, &isnull, &isdone); - - 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; - - } - - if (repl == NULL) - { - /* no changes needed */ - newtuple = tuple; - } - else - { - newtuple = heap_modifytuple(tuple, rel, replValue, replNull, repl); - - pfree(repl); - pfree(replNull); - pfree(replValue); - heap_freetuple(tuple); - } - - FreeMemoryContext(econtext); - - return newtuple; -} - -#endif - static char * -ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) +ExecRelCheck(Relation rel, TupleTableSlot *slot, EState *estate) { int ncheck = rel->rd_att->constr->num_check; ConstrCheck *check = rel->rd_att->constr->check; - TupleTableSlot *slot = makeNode(TupleTableSlot); - RangeTblEntry *rte = makeNode(RangeTblEntry); - ExprContext *econtext = MakeExprContext(slot, - TransactionCommandContext); - List *rtlist; + MemoryContext oldContext; + ExprContext *econtext; List *qual; 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 = RelationGetRelationName(rel); - rte->ref = makeNode(Attr); - rte->ref->relname = rte->relname; - rte->relid = RelationGetRelid(rel); - /* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */ - rtlist = lcons(rte, NIL); - econtext->ecxt_range_table = rtlist; /* phony range table */ + /* + * Make sure econtext, expressions, etc are placed in appropriate context. + */ + oldContext = MemoryContextSwitchTo(TransactionCommandContext); /* - * Save the de-stringized constraint expressions in command-level - * memory context. XXX should build the above stuff there too, - * instead of doing it over for each tuple. - * XXX Is it sufficient to have just one es_result_relation_constraints - * in an inherited insert/update? + * Create or reset the exprcontext for evaluating constraint expressions. */ - if (estate->es_result_relation_constraints == NULL) - { - MemoryContext oldContext; + econtext = estate->es_constraint_exprcontext; + if (econtext == NULL) + estate->es_constraint_exprcontext = econtext = + MakeExprContext(NULL, TransactionCommandContext); + else + ResetExprContext(econtext); - oldContext = MemoryContextSwitchTo(TransactionCommandContext); + /* + * If first time through for current result relation, set up econtext's + * range table to refer to result rel, and build expression nodetrees + * for rel's constraint expressions. All this stuff is kept in + * TransactionCommandContext so it will still be here next time through. + * + * NOTE: if there are multiple result relations (eg, due to inheritance) + * then we leak storage for prior rel's expressions and rangetable. + * This should not be a big problem as long as result rels are processed + * sequentially within a command. + */ + if (econtext->ecxt_range_table == NIL || + getrelid(1, econtext->ecxt_range_table) != RelationGetRelid(rel)) + { + RangeTblEntry *rte = makeNode(RangeTblEntry); + + rte->relname = RelationGetRelationName(rel); + rte->ref = makeNode(Attr); + rte->ref->relname = rte->relname; + rte->relid = RelationGetRelid(rel); + /* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */ + + /* Set up single-entry range table */ + econtext->ecxt_range_table = lcons(rte, NIL); estate->es_result_relation_constraints = (List **) palloc(ncheck * sizeof(List *)); @@ -1691,10 +1627,15 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) qual = (List *) stringToNode(check[i].ccbin); estate->es_result_relation_constraints[i] = qual; } - - MemoryContextSwitchTo(oldContext); } + /* Done with building long-lived items */ + MemoryContextSwitchTo(oldContext); + + /* Arrange for econtext's scan tuple to be the tuple under test */ + econtext->ecxt_scantuple = slot; + + /* And evaluate the constraints */ for (i = 0; i < ncheck; i++) { qual = estate->es_result_relation_constraints[i]; @@ -1708,25 +1649,25 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) return check[i].ccname; } - pfree(slot); - pfree(rte); - pfree(rtlist); - - FreeExprContext(econtext); - + /* NULL result means no error */ return (char *) NULL; } void -ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate) +ExecConstraints(char *caller, Relation rel, + TupleTableSlot *slot, EState *estate) { - Assert(rel->rd_att->constr); + HeapTuple tuple = slot->val; + TupleConstr *constr = rel->rd_att->constr; - if (rel->rd_att->constr->has_not_null) + Assert(constr); + + if (constr->has_not_null) { + int natts = rel->rd_att->natts; int attrChk; - for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++) + for (attrChk = 1; attrChk <= natts; attrChk++) { if (rel->rd_att->attrs[attrChk-1]->attnotnull && heap_attisnull(tuple, attrChk)) @@ -1735,11 +1676,11 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate) } } - if (rel->rd_att->constr->num_check > 0) + if (constr->num_check > 0) { char *failed; - if ((failed = ExecRelCheck(rel, tuple, estate)) != NULL) + if ((failed = ExecRelCheck(rel, slot, estate)) != NULL) elog(ERROR, "%s: rejected due to CHECK constraint %s", caller, failed); } diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index b835b29044..7849e87a78 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: executor.h,v 1.46 2000/07/12 02:37:30 tgl Exp $ + * $Id: executor.h,v 1.47 2000/08/06 04:26:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,8 +56,8 @@ extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate); extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, Node *limoffset, Node *limcount); extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate); -extern void ExecConstraints(char *caller, Relation rel, HeapTuple tuple, - EState *estate); +extern void ExecConstraints(char *caller, Relation rel, + TupleTableSlot *slot, EState *estate); extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 62a887d754..a9ef6e78ae 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: execnodes.h,v 1.44 2000/07/14 22:17:58 tgl Exp $ + * $Id: execnodes.h,v 1.45 2000/08/06 04:26:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -215,7 +215,6 @@ typedef struct EState Snapshot es_snapshot; List *es_range_table; RelationInfo *es_result_relation_info; - List **es_result_relation_constraints; Relation es_into_relation_descriptor; ParamListInfo es_param_list_info; ParamExecData *es_param_exec_vals; /* this is for subselects */ @@ -224,6 +223,9 @@ typedef struct EState uint32 es_processed; /* # of tuples processed */ Oid es_lastoid; /* last oid processed (by INSERT) */ List *es_rowMark; /* not good place, but there is no other */ + /* these two fields are storage space for ExecConstraints(): */ + List **es_result_relation_constraints; + ExprContext *es_constraint_exprcontext; /* Below is to re-evaluate plan qual in READ COMMITTED mode */ struct Plan *es_origPlan; Pointer es_evalPlanQual;