@ -24,6 +24,14 @@
* values plus row - locating info for UPDATE and MERGE cases , or just the
* values plus row - locating info for UPDATE and MERGE cases , or just the
* row - locating info for DELETE cases .
* row - locating info for DELETE cases .
*
*
* The relation to modify can be an ordinary table , a view having an
* INSTEAD OF trigger , or a foreign table . Earlier processing already
* pointed ModifyTable to the underlying relations of any automatically
* updatable view not using an INSTEAD OF trigger , so code here can
* assume it won ' t have one as a modification target . This node does
* process ri_WithCheckOptions , which may have expressions from those
* automatically updatable views .
*
* MERGE runs a join between the source relation and the target table .
* MERGE runs a join between the source relation and the target table .
* If any WHEN NOT MATCHED [ BY TARGET ] clauses are present , then the join
* If any WHEN NOT MATCHED [ BY TARGET ] clauses are present , then the join
* is an outer join that might output tuples without a matching target
* is an outer join that might output tuples without a matching target
@ -1398,18 +1406,18 @@ ExecDeleteEpilogue(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
* DELETE is like UPDATE , except that we delete the tuple and no
* DELETE is like UPDATE , except that we delete the tuple and no
* index modifications are needed .
* index modifications are needed .
*
*
* When deleting from a table , tupleid identifies the tuple to
* When deleting from a table , tupleid identifies the tuple to delete and
* delete and oldtuple is NULL . When deleting from a view ,
* oldtuple is NULL . When deleting through a view INSTEAD OF trigger ,
* oldtuple is passed to the INSTEAD OF triggers and identifies
* oldtuple is passed to the triggers and identifies what to delete , and
* what to delete , and tupleid is invalid . When deleting from a
* tupleid is invalid . When deleting from a foreign table , tupleid is
* foreign table , tupleid is invalid ; the FDW has to figure out
* invalid ; the FDW has to figure out which row to delete using data from
* which row to delete using data from the planSlot . oldtuple is
* the planSlot . oldtuple is passed to foreign table triggers ; it is
* passed to foreign table triggers ; it is NULL when the foreign
* NULL when the foreign table has no relevant triggers . We use
* table has no relevant triggers . We use tupleDeleted to indicate
* tupleDeleted to indicate whether the tuple is actually deleted ,
* whether the tuple is actually deleted , callers can use it to
* callers can use it to decide whether to continue the operation . When
* decide whether to continue the operation . When this DELETE is a
* this DELETE is a part of an UPDATE of partition - key , then the slot
* part of an UPDATE of partition - key , then the slot returned by
* returned by EvalPlanQual ( ) is passed back using output parameter
* EvalPlanQual ( ) is passed back using output parameter epqreturnslot .
* epqreturnslot .
*
*
* Returns RETURNING result if any , otherwise NULL .
* Returns RETURNING result if any , otherwise NULL .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -2238,21 +2246,22 @@ ExecCrossPartitionUpdateForeignKey(ModifyTableContext *context,
* is , we don ' t want to get stuck in an infinite loop
* is , we don ' t want to get stuck in an infinite loop
* which corrupts your database . .
* which corrupts your database . .
*
*
* When updating a table , tupleid identifies the tuple to
* When updating a table , tupleid identifies the tuple to update and
* update and oldtuple is NULL . When updating a view , oldtuple
* oldtuple is NULL . When updating through a view INSTEAD OF trigger ,
* is passed to the INSTEAD OF triggers and identifies what to
* oldtuple is passed to the triggers and identifies what to update , and
* update , and tupleid is invalid . When updating a foreign table ,
* tupleid is invalid . When updating a foreign table , tupleid is
* tupleid is invalid ; the FDW has to figure out which row to
* invalid ; the FDW has to figure out which row to update using data from
* update using data from the planSlot . oldtuple is passed to
* the planSlot . oldtuple is passed to foreign table triggers ; it is
* foreign table triggers ; it is NULL when the foreign table has
* NULL when the foreign table has no relevant triggers .
* no relevant triggers .
*
*
* slot contains the new tuple value to be stored .
* slot contains the new tuple value to be stored .
* planSlot is the output of the ModifyTable ' s subplan ; we use it
* planSlot is the output of the ModifyTable ' s subplan ; we use it
* to access values from other input tables ( for RETURNING ) ,
* to access values from other input tables ( for RETURNING ) ,
* row - ID junk columns , etc .
* row - ID junk columns , etc .
*
*
* Returns RETURNING result if any , otherwise NULL .
* Returns RETURNING result if any , otherwise NULL . On exit , if tupleid
* had identified the tuple to update , it will identify the tuple
* actually updated after EvalPlanQual .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
*/
static TupleTableSlot *
static TupleTableSlot *
@ -2717,10 +2726,10 @@ ExecMerge(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
/*-----
/*-----
* If we are dealing with a WHEN MATCHED case , tupleid or oldtuple is
* If we are dealing with a WHEN MATCHED case , tupleid or oldtuple is
* valid , depending on whether the result relation is a table or a view .
* valid , depending on whether the result relation is a table or a view
* We execute the first action for which the additional WHEN MATCHED AND
* having an INSTEAD OF trigger . We execute the first action for which
* quals pass . If an action without quals is found , that action i s
* the additional WHEN MATCHED AND quals pass . If an action without quals
* executed .
* is found , that action is executed .
*
*
* Similarly , in the WHEN NOT MATCHED BY SOURCE case , tupleid or oldtuple
* Similarly , in the WHEN NOT MATCHED BY SOURCE case , tupleid or oldtuple
* is valid , and we look at the given WHEN NOT MATCHED BY SOURCE actions
* is valid , and we look at the given WHEN NOT MATCHED BY SOURCE actions
@ -2811,8 +2820,8 @@ ExecMerge(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
* Check and execute the first qualifying MATCHED or NOT MATCHED BY SOURCE
* Check and execute the first qualifying MATCHED or NOT MATCHED BY SOURCE
* action , depending on whether the join quals are satisfied . If the target
* action , depending on whether the join quals are satisfied . If the target
* relation is a table , the current target tuple is identified by tupleid .
* relation is a table , the current target tuple is identified by tupleid .
* Otherwise , if the target relation is a view , oldtuple is the current target
* Otherwise , if the target relation is a view having an INSTEAD OF trigger ,
* tuple from the view .
* oldtuple is the current target tuple from the view .
*
*
* We start from the first WHEN MATCHED or WHEN NOT MATCHED BY SOURCE action
* We start from the first WHEN MATCHED or WHEN NOT MATCHED BY SOURCE action
* and check if the WHEN quals pass , if any . If the WHEN quals for the first
* and check if the WHEN quals pass , if any . If the WHEN quals for the first
@ -2878,8 +2887,11 @@ ExecMergeMatched(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
*/
*/
Assert ( tupleid ! = NULL | | oldtuple ! = NULL ) ;
Assert ( tupleid ! = NULL | | oldtuple ! = NULL ) ;
if ( oldtuple ! = NULL )
if ( oldtuple ! = NULL )
{
Assert ( resultRelInfo - > ri_TrigDesc ) ;
ExecForceStoreHeapTuple ( oldtuple , resultRelInfo - > ri_oldTupleSlot ,
ExecForceStoreHeapTuple ( oldtuple , resultRelInfo - > ri_oldTupleSlot ,
false ) ;
false ) ;
}
else if ( ! table_tuple_fetch_row_version ( resultRelInfo - > ri_RelationDesc ,
else if ( ! table_tuple_fetch_row_version ( resultRelInfo - > ri_RelationDesc ,
tupleid ,
tupleid ,
SnapshotAny ,
SnapshotAny ,
@ -3992,8 +4004,8 @@ ExecModifyTable(PlanState *pstate)
* know enough here to set t_tableOid . Quite separately from
* know enough here to set t_tableOid . Quite separately from
* this , the FDW may fetch its own junk attrs to identify the row .
* this , the FDW may fetch its own junk attrs to identify the row .
*
*
* Other relevant relkinds , currently limited to views , always
* Other relevant relkinds , currently limited to views having
* have a wholerow attribute .
* INSTEAD OF triggers , always have a wholerow attribute .
*/
*/
else if ( AttributeNumberIsValid ( resultRelInfo - > ri_RowIdAttNo ) )
else if ( AttributeNumberIsValid ( resultRelInfo - > ri_RowIdAttNo ) )
{
{