1 /*-------------------------------------------------------------------------
4 * top level executor interface routines
11 * The old ExecutorMain() has been replaced by ExecutorStart(),
12 * ExecutorRun() and ExecutorEnd()
14 * These three procedures are the external interfaces to the executor.
15 * In each case, the query descriptor and the execution state is required
18 * ExecutorStart() must be called at the beginning of any execution of any
19 * query plan and ExecutorEnd() should always be called at the end of
20 * execution of a plan.
22 * ExecutorRun accepts 'feature' and 'count' arguments that specify whether
23 * the plan is to be executed forwards, backwards, and for how many tuples.
25 * Copyright (c) 1994, Regents of the University of California
29 * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.33 1997/11/24 05:08:20 momjian Exp $
31 *-------------------------------------------------------------------------
35 #include "miscadmin.h"
37 #include "executor/executor.h"
38 #include "executor/execdefs.h"
39 #include "executor/execdebug.h"
40 #include "executor/nodeIndexscan.h"
41 #include "utils/builtins.h"
42 #include "utils/palloc.h"
43 #include "utils/acl.h"
44 #include "utils/syscache.h"
45 #include "utils/tqual.h"
46 #include "parser/parsetree.h" /* rt_fetch() */
47 #include "storage/bufmgr.h"
48 #include "storage/lmgr.h"
49 #include "storage/smgr.h"
50 #include "commands/async.h"
51 /* #include "access/localam.h" */
52 #include "optimizer/var.h"
53 #include "access/heapam.h"
54 #include "catalog/heap.h"
55 #include "commands/trigger.h"
59 /* decls for local routines only used within this module */
61 ExecCheckPerms(CmdType operation, int resultRelation, List *rangeTable,
64 InitPlan(CmdType operation, Query *parseTree,
65 Plan *plan, EState *estate);
66 static void EndPlan(Plan *plan, EState *estate);
67 static TupleTableSlot *
68 ExecutePlan(EState *estate, Plan *plan,
69 Query *parseTree, CmdType operation,
70 int numberTuples, ScanDirection direction,
71 void (*printfunc) ());
72 static void ExecRetrieve(TupleTableSlot *slot, void (*printfunc) (),
75 ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
78 ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
81 ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
82 EState *estate, Query *parseTree);
84 /* end of local decls */
87 static int queryLimit = ALL_TUPLES;
90 #define ALL_TUPLES queryLimit
92 int ExecutorLimit(int limit);
95 ExecutorLimit(int limit)
97 return queryLimit = limit;
101 /* ----------------------------------------------------------------
104 * This routine must be called at the beginning of any execution of any
107 * returns (AttrInfo*) which describes the attributes of the tuples to
108 * be returned by the query.
110 * ----------------------------------------------------------------
113 ExecutorStart(QueryDesc *queryDesc, EState *estate)
118 Assert(queryDesc != NULL);
120 result = InitPlan(queryDesc->operation,
121 queryDesc->parsetree,
126 * reset buffer refcount. the current refcounts are saved and will be
127 * restored when ExecutorEnd is called
129 * this makes sure that when ExecutorRun's are called recursively as for
130 * postquel functions, the buffers pinned by one ExecutorRun will not
131 * be unpinned by another ExecutorRun.
133 BufferRefCountReset(estate->es_refcount);
138 /* ----------------------------------------------------------------
141 * This is the main routine of the executor module. It accepts
142 * the query descriptor from the traffic cop and executes the
145 * ExecutorStart must have been called already.
147 * the different features supported are:
148 * EXEC_RUN: retrieve all tuples in the forward direction
149 * EXEC_FOR: retrieve 'count' number of tuples in the forward dir
150 * EXEC_BACK: retrieve 'count' number of tuples in the backward dir
151 * EXEC_RETONE: return one tuple but don't 'retrieve' it
152 * used in postquel function processing
155 * ----------------------------------------------------------------
158 ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
163 TupleTableSlot *result;
165 void (*destination) ();
171 Assert(queryDesc != NULL);
174 * extract information from the query descriptor
175 * and the query feature.
178 operation = queryDesc->operation;
179 parseTree = queryDesc->parsetree;
180 plan = queryDesc->plantree;
181 dest = queryDesc->dest;
182 destination = (void (*) ()) DestToFunction(dest);
183 estate->es_processed = 0;
184 estate->es_lastoid = InvalidOid;
189 * It doesn't work in common case (i.g. if function has a aggregate).
190 * Now we store parameter values before ExecutorStart. - vadim
193 #ifdef INDEXSCAN_PATCH
196 * If the plan is an index scan and some of the scan key are function
197 * arguments rescan the indices after the parameter values have been
198 * stored in the execution state. DZ - 27-8-1996
200 if ((nodeTag(plan) == T_IndexScan) &&
201 (((IndexScan *) plan)->indxstate->iss_RuntimeKeyInfo != NULL))
203 ExprContext *econtext;
205 econtext = ((IndexScan *) plan)->scan.scanstate->cstate.cs_ExprContext;
206 ExecIndexReScan((IndexScan *) plan, econtext, plan);
215 result = ExecutePlan(estate,
220 ForwardScanDirection,
224 result = ExecutePlan(estate,
229 ForwardScanDirection,
234 * retrieve next n "backward" tuples
238 result = ExecutePlan(estate,
243 BackwardScanDirection,
248 * return one tuple but don't "retrieve" it.
249 * (this is used by the rule manager..) -cim 9/14/89
253 result = ExecutePlan(estate,
258 ForwardScanDirection,
263 elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
270 /* ----------------------------------------------------------------
273 * This routine must be called at the end of any execution of any
276 * returns (AttrInfo*) which describes the attributes of the tuples to
277 * be returned by the query.
279 * ----------------------------------------------------------------
282 ExecutorEnd(QueryDesc *queryDesc, EState *estate)
285 Assert(queryDesc != NULL);
287 EndPlan(queryDesc->plantree, estate);
289 /* restore saved refcounts. */
290 BufferRefCountRestore(estate->es_refcount);
293 /* ===============================================================
294 * ===============================================================
295 static routines follow
296 * ===============================================================
297 * ===============================================================
301 ExecCheckPerms(CmdType operation,
313 aclcheck_result = -1;
318 #define CHECK(MODE) pg_aclcheck(rname.data, userName, MODE)
320 userName = GetPgUserName();
322 foreach(lp, rangeTable)
324 RangeTblEntry *rte = lfirst(lp);
327 htp = SearchSysCacheTuple(RELOID,
328 ObjectIdGetDatum(relid),
330 if (!HeapTupleIsValid(htp))
331 elog(WARN, "ExecCheckPerms: bogus RT relid: %d",
334 ((Form_pg_class) GETSTRUCT(htp))->relname.data,
336 if (i == resultRelation)
337 { /* this is the result relation */
338 qvars = pull_varnos(parseTree->qual);
339 tvars = pull_varnos((Node *) parseTree->targetList);
340 if (intMember(resultRelation, qvars) ||
341 intMember(resultRelation, tvars))
343 /* result relation is scanned */
344 ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
352 ok = ((aclcheck_result = CHECK(ACL_AP)) == ACLCHECK_OK) ||
353 ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
356 case CMD_NOTIFY: /* what does this mean?? -- jw,
360 ok = ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
364 elog(WARN, "ExecCheckPerms: bogus operation %d",
371 ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
380 elog(WARN, "%s: %s", rname.data, aclcheck_error_strings[aclcheck_result]);
385 /* ----------------------------------------------------------------
388 * Initializes the query plan: open files, allocate storage
389 * and start up the rule manager
390 * ----------------------------------------------------------------
393 InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
397 Relation intoRelationDesc;
404 * get information from query descriptor
407 rangeTable = parseTree->rtable;
408 resultRelation = parseTree->resultRelation;
411 * initialize the node's execution state
414 estate->es_range_table = rangeTable;
417 * initialize the BaseId counter so node base_id's
418 * are assigned correctly. Someday baseid's will have to
419 * be stored someplace other than estate because they
420 * should be unique per query planned.
423 estate->es_BaseId = 1;
426 * initialize result relation stuff
430 if (resultRelation != 0 && operation != CMD_SELECT)
433 * if we have a result relation, open it and
435 * initialize the result relation info stuff.
438 RelationInfo *resultRelationInfo;
439 Index resultRelationIndex;
440 RangeTblEntry *rtentry;
441 Oid resultRelationOid;
442 Relation resultRelationDesc;
444 resultRelationIndex = resultRelation;
445 rtentry = rt_fetch(resultRelationIndex, rangeTable);
446 resultRelationOid = rtentry->relid;
447 resultRelationDesc = heap_open(resultRelationOid);
449 if (resultRelationDesc->rd_rel->relkind == RELKIND_SEQUENCE)
450 elog(WARN, "You can't change sequence relation %s",
451 resultRelationDesc->rd_rel->relname.data);
454 * Write-lock the result relation right away: if the relation is
455 * used in a subsequent scan, we won't have to elevate the
456 * read-lock set by heap_beginscan to a write-lock (needed by
457 * heap_insert, heap_delete and heap_replace). This will hopefully
458 * prevent some deadlocks. - 01/24/94
460 RelationSetLockForWrite(resultRelationDesc);
462 resultRelationInfo = makeNode(RelationInfo);
463 resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
464 resultRelationInfo->ri_RelationDesc = resultRelationDesc;
465 resultRelationInfo->ri_NumIndices = 0;
466 resultRelationInfo->ri_IndexRelationDescs = NULL;
467 resultRelationInfo->ri_IndexRelationInfo = NULL;
470 * open indices on result relation and save descriptors
471 * in the result relation information..
474 ExecOpenIndices(resultRelationOid, resultRelationInfo);
476 estate->es_result_relation_info = resultRelationInfo;
481 * if no result relation, then set state appropriately
484 estate->es_result_relation_info = NULL;
488 ExecCheckPerms(operation, resultRelation, rangeTable, parseTree);
492 * initialize the executor "tuple" table.
496 int nSlots = ExecCountSlotsNode(plan);
497 TupleTable tupleTable = ExecCreateTupleTable(nSlots + 10); /* why add ten? - jolly */
499 estate->es_tupleTable = tupleTable;
503 * initialize the private state information for
504 * all the nodes in the query tree. This opens
505 * files, allocates storage and leaves us ready
506 * to start processing tuples..
509 ExecInitNode(plan, estate, NULL);
512 * get the tuple descriptor describing the type
513 * of tuples to return.. (this is especially important
514 * if we are creating a relation with "retrieve into")
517 tupType = ExecGetTupType(plan); /* tuple descriptor */
518 targetList = plan->targetlist;
519 len = ExecTargetListLength(targetList); /* number of attributes */
522 * now that we have the target list, initialize the junk filter
523 * if this is a REPLACE or a DELETE query.
524 * We also init the junk filter if this is an append query
525 * (there might be some rule lock info there...)
526 * NOTE: in the future we might want to initialize the junk
527 * filter for all queries.
530 if (operation == CMD_UPDATE || operation == CMD_DELETE ||
531 operation == CMD_INSERT)
534 JunkFilter *j = (JunkFilter *) ExecInitJunkFilter(targetList);
536 estate->es_junkFilter = j;
539 estate->es_junkFilter = NULL;
542 * initialize the "into" relation
545 intoRelationDesc = (Relation) NULL;
547 if (operation == CMD_SELECT)
553 if (!parseTree->isPortal)
557 * a select into table
559 if (parseTree->into != NULL)
562 * create the "into" relation
565 intoName = parseTree->into;
568 * have to copy tupType to get rid of constraints
570 tupdesc = CreateTupleDescCopy(tupType);
572 /* fixup to prevent zero-length columns in create */
573 setVarAttrLenForCreateTable(tupdesc, targetList, rangeTable);
575 intoRelationId = heap_create(intoName, tupdesc);
576 #ifdef NOT_USED /* it's copy ... */
577 resetVarAttrLenForCreateTable(tupdesc);
579 FreeTupleDesc(tupdesc);
582 * XXX rather than having to call setheapoverride(true)
583 * and then back to false, we should change the
584 * arguments to heap_open() instead..
587 setheapoverride(true);
589 intoRelationDesc = heap_open(intoRelationId);
591 setheapoverride(false);
596 estate->es_into_relation_descriptor = intoRelationDesc;
599 * return the type information..
603 attinfo = (AttrInfo *)palloc(sizeof(AttrInfo));
604 attinfo->numAttr = len;
605 attinfo->attrs = tupType->attrs;
611 /* ----------------------------------------------------------------
614 * Cleans up the query plan -- closes files and free up storages
615 * ----------------------------------------------------------------
618 EndPlan(Plan *plan, EState *estate)
620 RelationInfo *resultRelationInfo;
621 Relation intoRelationDesc;
624 * get information from state
627 resultRelationInfo = estate->es_result_relation_info;
628 intoRelationDesc = estate->es_into_relation_descriptor;
631 * shut down the query
634 ExecEndNode(plan, plan);
637 * destroy the executor "tuple" table.
641 TupleTable tupleTable = (TupleTable) estate->es_tupleTable;
643 ExecDestroyTupleTable(tupleTable, true); /* was missing last arg */
644 estate->es_tupleTable = NULL;
648 * close the result relations if necessary
651 if (resultRelationInfo != NULL)
653 Relation resultRelationDesc;
655 resultRelationDesc = resultRelationInfo->ri_RelationDesc;
656 heap_close(resultRelationDesc);
659 * close indices on the result relation
662 ExecCloseIndices(resultRelationInfo);
666 * close the "into" relation if necessary
669 if (intoRelationDesc != NULL)
671 heap_close(intoRelationDesc);
675 /* ----------------------------------------------------------------
678 * processes the query plan to retrieve 'tupleCount' tuples in the
679 * direction specified.
680 * Retrieves all tuples if tupleCount is 0
682 * result is either a slot containing a tuple in the case
683 * of a RETRIEVE or NULL otherwise.
685 * ----------------------------------------------------------------
688 /* the ctid attribute is a 'junk' attribute that is removed before the
691 static TupleTableSlot *
692 ExecutePlan(EState *estate,
697 ScanDirection direction,
698 void (*printfunc) ())
700 JunkFilter *junkfilter;
702 TupleTableSlot *slot;
703 ItemPointer tupleid = NULL;
704 ItemPointerData tuple_ctid;
705 int current_tuple_count;
706 TupleTableSlot *result;
709 * initialize local variables
713 current_tuple_count = 0;
720 estate->es_direction = direction;
723 * Loop until we've processed the proper number
724 * of tuples from the plan..
730 if (operation != CMD_NOTIFY)
733 * Execute the plan and obtain a tuple
736 /* at the top level, the parent of a plan (2nd arg) is itself */
737 slot = ExecProcNode(plan, plan);
740 * if the tuple is null, then we assume
741 * there is nothing more to process so
742 * we just return null...
753 * if we have a junk filter, then project a new
754 * tuple with the junk removed.
756 * Store this new "clean" tuple in the place of the
759 * Also, extract all the junk ifnormation we need.
762 if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL)
766 /* NameData attrName; */
771 * extract the 'ctid' junk attribute.
774 if (operation == CMD_UPDATE || operation == CMD_DELETE)
776 if (!ExecGetJunkAttribute(junkfilter,
781 elog(WARN, "ExecutePlan: NO (junk) `ctid' was found!");
784 elog(WARN, "ExecutePlan: (junk) `ctid' is NULL!");
786 tupleid = (ItemPointer) DatumGetPointer(datum);
787 tuple_ctid = *tupleid; /* make sure we don't free the
789 tupleid = &tuple_ctid;
793 * Finally create a new "clean" tuple with all junk attributes
797 newTuple = ExecRemoveJunk(junkfilter, slot);
799 slot = ExecStoreTuple(newTuple, /* tuple to store */
800 slot, /* destination slot */
801 InvalidBuffer, /* this tuple has no
803 true); /* tuple should be pfreed */
804 } /* if (junkfilter... */
807 * now that we have a tuple, do the appropriate thing
808 * with it.. either return it to the user, add
809 * it to a relation someplace, delete it from a
810 * relation, or modify some of it's attributes.
817 ExecRetrieve(slot, /* slot containing tuple */
818 printfunc, /* print function */
824 ExecAppend(slot, tupleid, estate);
829 ExecDelete(slot, tupleid, estate);
834 ExecReplace(slot, tupleid, estate, parseTree);
839 * Total hack. I'm ignoring any accessor functions for
840 * Relation, RelationTupleForm, NameData. Assuming that
841 * NameData.data has offset 0.
845 RelationInfo *rInfo = estate->es_result_relation_info;
846 Relation rDesc = rInfo->ri_RelationDesc;
848 Async_Notify(rDesc->rd_rel->relname.data);
850 current_tuple_count = 0;
852 elog(DEBUG, "ExecNotify %s", &rDesc->rd_rel->relname);
857 elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
862 * check our tuple count.. if we've returned the
863 * proper number then return, else loop again and
864 * process more tuples..
867 current_tuple_count += 1;
868 if (numberTuples == current_tuple_count)
873 * here, result is either a slot containing a tuple in the case
874 * of a RETRIEVE or NULL otherwise.
880 /* ----------------------------------------------------------------
883 * RETRIEVEs are easy.. we just pass the tuple to the appropriate
884 * print function. The only complexity is when we do a
885 * "retrieve into", in which case we insert the tuple into
886 * the appropriate relation (note: this is a newly created relation
887 * so we don't need to worry about indices or locks.)
888 * ----------------------------------------------------------------
891 ExecRetrieve(TupleTableSlot *slot,
892 void (*printfunc) (),
899 * get the heap tuple out of the tuple table slot
903 attrtype = slot->ttc_tupleDescriptor;
906 * insert the tuple into the "into relation"
909 if (estate->es_into_relation_descriptor != NULL)
911 heap_insert(estate->es_into_relation_descriptor, tuple);
916 * send the tuple to the front end (or the screen)
919 (*printfunc) (tuple, attrtype);
921 (estate->es_processed)++;
924 /* ----------------------------------------------------------------
927 * APPENDs are trickier.. we have to insert the tuple into
928 * the base relation and insert appropriate tuples into the
930 * ----------------------------------------------------------------
934 ExecAppend(TupleTableSlot *slot,
939 RelationInfo *resultRelationInfo;
940 Relation resultRelationDesc;
945 * get the heap tuple out of the tuple table slot
951 * get information on the result relation
954 resultRelationInfo = estate->es_result_relation_info;
955 resultRelationDesc = resultRelationInfo->ri_RelationDesc;
958 * have to add code to preform unique checking here.
963 /* BEFORE ROW INSERT Triggers */
964 if (resultRelationDesc->trigdesc &&
965 resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
969 newtuple = ExecBRInsertTriggers(resultRelationDesc, tuple);
971 if (newtuple == NULL) /* "do nothing" */
974 if (newtuple != tuple) /* modified by Trigger(s) */
976 Assert(slot->ttc_shouldFree);
978 slot->val = tuple = newtuple;
983 * Check the constraints of a tuple
987 if (resultRelationDesc->rd_att->constr)
991 newtuple = ExecConstraints("ExecAppend", resultRelationDesc, tuple);
993 if (newtuple != tuple) /* modified by DEFAULT */
995 Assert(slot->ttc_shouldFree);
997 slot->val = tuple = newtuple;
1005 newId = heap_insert(resultRelationDesc, /* relation desc */
1006 tuple); /* heap tuple */
1012 * Note: heap_insert adds a new tuple to a relation. As a side
1013 * effect, the tupleid of the new tuple is placed in the new
1014 * tuple's t_ctid field.
1017 numIndices = resultRelationInfo->ri_NumIndices;
1020 ExecInsertIndexTuples(slot, &(tuple->t_ctid), estate, false);
1022 (estate->es_processed)++;
1023 estate->es_lastoid = newId;
1025 /* AFTER ROW INSERT Triggers */
1026 if (resultRelationDesc->trigdesc &&
1027 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
1028 ExecARInsertTriggers(resultRelationDesc, tuple);
1031 /* ----------------------------------------------------------------
1034 * DELETE is like append, we delete the tuple and its
1036 * ----------------------------------------------------------------
1039 ExecDelete(TupleTableSlot *slot,
1040 ItemPointer tupleid,
1043 RelationInfo *resultRelationInfo;
1044 Relation resultRelationDesc;
1047 * get the result relation information
1050 resultRelationInfo = estate->es_result_relation_info;
1051 resultRelationDesc = resultRelationInfo->ri_RelationDesc;
1053 /* BEFORE ROW DELETE Triggers */
1054 if (resultRelationDesc->trigdesc &&
1055 resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
1059 dodelete = ExecBRDeleteTriggers(resultRelationDesc, tupleid);
1061 if (!dodelete) /* "do nothing" */
1069 if (heap_delete(resultRelationDesc, /* relation desc */
1070 tupleid)) /* item pointer to tuple */
1074 (estate->es_processed)++;
1077 * Note: Normally one would think that we have to
1078 * delete index tuples associated with the
1081 * ... but in POSTGRES, we have no need to do this
1082 * because the vacuum daemon automatically
1083 * opens an index scan and deletes index tuples
1084 * when it finds deleted heap tuples. -cim 9/27/89
1088 /* AFTER ROW DELETE Triggers */
1089 if (resultRelationDesc->trigdesc &&
1090 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
1091 ExecARDeleteTriggers(resultRelationDesc, tupleid);
1095 /* ----------------------------------------------------------------
1098 * note: we can't run replace queries with transactions
1099 * off because replaces are actually appends and our
1100 * scan will mistakenly loop forever, replacing the tuple
1101 * it just appended.. This should be fixed but until it
1102 * is, we don't want to get stuck in an infinite loop
1103 * which corrupts your database..
1104 * ----------------------------------------------------------------
1107 ExecReplace(TupleTableSlot *slot,
1108 ItemPointer tupleid,
1113 RelationInfo *resultRelationInfo;
1114 Relation resultRelationDesc;
1118 * abort the operation if not running transactions
1121 if (IsBootstrapProcessingMode())
1123 elog(DEBUG, "ExecReplace: replace can't run without transactions");
1128 * get the heap tuple out of the tuple table slot
1134 * get the result relation information
1137 resultRelationInfo = estate->es_result_relation_info;
1138 resultRelationDesc = resultRelationInfo->ri_RelationDesc;
1141 * have to add code to preform unique checking here.
1142 * in the event of unique tuples, this becomes a deletion
1143 * of the original tuple affected by the replace.
1148 /* BEFORE ROW UPDATE Triggers */
1149 if (resultRelationDesc->trigdesc &&
1150 resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
1154 newtuple = ExecBRUpdateTriggers(resultRelationDesc, tupleid, tuple);
1156 if (newtuple == NULL) /* "do nothing" */
1159 if (newtuple != tuple) /* modified by Trigger(s) */
1161 Assert(slot->ttc_shouldFree);
1163 slot->val = tuple = newtuple;
1168 * Check the constraints of a tuple
1172 if (resultRelationDesc->rd_att->constr)
1176 newtuple = ExecConstraints("ExecReplace", resultRelationDesc, tuple);
1178 if (newtuple != tuple) /* modified by DEFAULT */
1180 Assert(slot->ttc_shouldFree);
1182 slot->val = tuple = newtuple;
1187 * replace the heap tuple
1189 * Don't want to continue if our heap_replace didn't actually
1190 * do a replace. This would be the case if heap_replace
1191 * detected a non-functional update. -kw 12/30/93
1194 if (heap_replace(resultRelationDesc, /* relation desc */
1195 tupleid, /* item ptr of tuple to replace */
1197 { /* replacement heap tuple */
1202 (estate->es_processed)++;
1205 * Note: instead of having to update the old index tuples
1206 * associated with the heap tuple, all we do is form
1207 * and insert new index tuples.. This is because
1208 * replaces are actually deletes and inserts and
1209 * index tuple deletion is done automagically by
1210 * the vaccuum deamon.. All we do is insert new
1211 * index tuples. -cim 9/27/89
1218 * heap_replace updates a tuple in the base relation by invalidating
1219 * it and then appending a new tuple to the relation. As a side
1220 * effect, the tupleid of the new tuple is placed in the new
1221 * tuple's t_ctid field. So we now insert index tuples using
1222 * the new tupleid stored there.
1226 numIndices = resultRelationInfo->ri_NumIndices;
1229 ExecInsertIndexTuples(slot, &(tuple->t_ctid), estate, true);
1232 /* AFTER ROW UPDATE Triggers */
1233 if (resultRelationDesc->trigdesc &&
1234 resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
1235 ExecARUpdateTriggers(resultRelationDesc, tupleid, tuple);
1240 ExecAttrDefault(Relation rel, HeapTuple tuple)
1242 int ndef = rel->rd_att->constr->num_defval;
1243 AttrDefault *attrdef = rel->rd_att->constr->defval;
1244 ExprContext *econtext = makeNode(ExprContext);
1250 Datum *replValue = NULL;
1251 char *replNull = NULL;
1255 econtext->ecxt_scantuple = NULL; /* scan tuple slot */
1256 econtext->ecxt_innertuple = NULL; /* inner tuple slot */
1257 econtext->ecxt_outertuple = NULL; /* outer tuple slot */
1258 econtext->ecxt_relation = NULL; /* relation */
1259 econtext->ecxt_relid = 0; /* relid */
1260 econtext->ecxt_param_list_info = NULL; /* param list info */
1261 econtext->ecxt_range_table = NULL; /* range table */
1262 for (i = 0; i < ndef; i++)
1264 if (!heap_attisnull(tuple, attrdef[i].adnum))
1266 expr = (Node *) stringToNode(attrdef[i].adbin);
1268 val = ExecEvalExpr(expr, econtext, &isnull, &isdone);
1277 repl = (char *) palloc(rel->rd_att->natts * sizeof(char));
1278 replNull = (char *) palloc(rel->rd_att->natts * sizeof(char));
1279 replValue = (Datum *) palloc(rel->rd_att->natts * sizeof(Datum));
1280 MemSet(repl, ' ', rel->rd_att->natts * sizeof(char));
1283 repl[attrdef[i].adnum - 1] = 'r';
1284 replNull[attrdef[i].adnum - 1] = ' ';
1285 replValue[attrdef[i].adnum - 1] = val;
1294 newtuple = heap_modifytuple(tuple, InvalidBuffer, rel, replValue, replNull, repl);
1306 ExecRelCheck(Relation rel, HeapTuple tuple)
1308 int ncheck = rel->rd_att->constr->num_check;
1309 ConstrCheck *check = rel->rd_att->constr->check;
1310 ExprContext *econtext = makeNode(ExprContext);
1311 TupleTableSlot *slot = makeNode(TupleTableSlot);
1312 RangeTblEntry *rte = makeNode(RangeTblEntry);
1319 slot->ttc_shouldFree = false;
1320 slot->ttc_descIsNew = true;
1321 slot->ttc_tupleDescriptor = rel->rd_att;
1322 slot->ttc_buffer = InvalidBuffer;
1323 slot->ttc_whichplan = -1;
1324 rte->relname = nameout(&(rel->rd_rel->relname));
1325 rte->refname = rte->relname;
1326 rte->relid = rel->rd_id;
1328 rte->inFromCl = true;
1329 rtlist = lcons(rte, NIL);
1330 econtext->ecxt_scantuple = slot; /* scan tuple slot */
1331 econtext->ecxt_innertuple = NULL; /* inner tuple slot */
1332 econtext->ecxt_outertuple = NULL; /* outer tuple slot */
1333 econtext->ecxt_relation = rel; /* relation */
1334 econtext->ecxt_relid = 0; /* relid */
1335 econtext->ecxt_param_list_info = NULL; /* param list info */
1336 econtext->ecxt_range_table = rtlist; /* range table */
1338 for (i = 0; i < ncheck; i++)
1340 qual = (List *) stringToNode(check[i].ccbin);
1342 res = ExecQual(qual, econtext);
1347 return (check[i].ccname);
1351 pfree(rte->relname);
1356 return ((char *) NULL);
1361 ExecConstraints(char *caller, Relation rel, HeapTuple tuple)
1363 HeapTuple newtuple = tuple;
1365 Assert(rel->rd_att->constr);
1368 if (rel->rd_att->constr->num_defval > 0)
1369 newtuple = tuple = ExecAttrDefault(rel, tuple);
1372 if (rel->rd_att->constr->has_not_null)
1376 for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++)
1378 if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk))
1379 elog(WARN, "%s: Fail to add null value in not null attribute %s",
1380 caller, rel->rd_att->attrs[attrChk - 1]->attname.data);
1384 if (rel->rd_att->constr->num_check > 0)
1388 if ((failed = ExecRelCheck(rel, tuple)) != NULL)
1389 elog(WARN, "%s: rejected due to CHECK constraint %s", caller, failed);