24
24
* values plus row-locating info for UPDATE and MERGE cases, or just the
25
25
* row-locating info for DELETE cases.
26
26
*
27
+ * The relation to modify can be an ordinary table, a view having an
28
+ * INSTEAD OF trigger, or a foreign table. Earlier processing already
29
+ * pointed ModifyTable to the underlying relations of any automatically
30
+ * updatable view not using an INSTEAD OF trigger, so code here can
31
+ * assume it won't have one as a modification target. This node does
32
+ * process ri_WithCheckOptions, which may have expressions from those
33
+ * automatically updatable views.
34
+ *
27
35
* MERGE runs a join between the source relation and the target table.
28
36
* If any WHEN NOT MATCHED [BY TARGET] clauses are present, then the join
29
37
* is an outer join that might output tuples without a matching target
@@ -1398,18 +1406,18 @@ ExecDeleteEpilogue(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
1398
1406
* DELETE is like UPDATE, except that we delete the tuple and no
1399
1407
* index modifications are needed.
1400
1408
*
1401
- * When deleting from a table, tupleid identifies the tuple to
1402
- * delete and oldtuple is NULL. When deleting from a view,
1403
- * oldtuple is passed to the INSTEAD OF triggers and identifies
1404
- * what to delete, and tupleid is invalid. When deleting from a
1405
- * foreign table, tupleid is invalid; the FDW has to figure out
1406
- * which row to delete using data from the planSlot. oldtuple is
1407
- * passed to foreign table triggers; it is NULL when the foreign
1408
- * table has no relevant triggers. We use tupleDeleted to indicate
1409
- * whether the tuple is actually deleted, callers can use it to
1410
- * decide whether to continue the operation. When this DELETE is a
1411
- * part of an UPDATE of partition-key, then the slot returned by
1412
- * EvalPlanQual() is passed back using output parameter epqreturnslot.
1409
+ * When deleting from a table, tupleid identifies the tuple to delete and
1410
+ * oldtuple is NULL. When deleting through a view INSTEAD OF trigger ,
1411
+ * oldtuple is passed to the triggers and identifies what to delete, and
1412
+ * tupleid is invalid. When deleting from a foreign table, tupleid is
1413
+ * invalid; the FDW has to figure out which row to delete using data from
1414
+ * the planSlot. oldtuple is passed to foreign table triggers; it is
1415
+ * NULL when the foreign table has no relevant triggers. We use
1416
+ * tupleDeleted to indicate whether the tuple is actually deleted,
1417
+ * callers can use it to decide whether to continue the operation. When
1418
+ * this DELETE is a part of an UPDATE of partition-key, then the slot
1419
+ * returned by EvalPlanQual() is passed back using output parameter
1420
+ * epqreturnslot.
1413
1421
*
1414
1422
* Returns RETURNING result if any, otherwise NULL.
1415
1423
* ----------------------------------------------------------------
@@ -2238,21 +2246,22 @@ ExecCrossPartitionUpdateForeignKey(ModifyTableContext *context,
2238
2246
* is, we don't want to get stuck in an infinite loop
2239
2247
* which corrupts your database..
2240
2248
*
2241
- * When updating a table, tupleid identifies the tuple to
2242
- * update and oldtuple is NULL. When updating a view, oldtuple
2243
- * is passed to the INSTEAD OF triggers and identifies what to
2244
- * update, and tupleid is invalid. When updating a foreign table,
2245
- * tupleid is invalid; the FDW has to figure out which row to
2246
- * update using data from the planSlot. oldtuple is passed to
2247
- * foreign table triggers; it is NULL when the foreign table has
2248
- * no relevant triggers.
2249
+ * When updating a table, tupleid identifies the tuple to update and
2250
+ * oldtuple is NULL. When updating through a view INSTEAD OF trigger,
2251
+ * oldtuple is passed to the triggers and identifies what to update, and
2252
+ * tupleid is invalid. When updating a foreign table, tupleid is
2253
+ * invalid; the FDW has to figure out which row to update using data from
2254
+ * the planSlot. oldtuple is passed to foreign table triggers; it is
2255
+ * NULL when the foreign table has no relevant triggers.
2249
2256
*
2250
2257
* slot contains the new tuple value to be stored.
2251
2258
* planSlot is the output of the ModifyTable's subplan; we use it
2252
2259
* to access values from other input tables (for RETURNING),
2253
2260
* row-ID junk columns, etc.
2254
2261
*
2255
- * Returns RETURNING result if any, otherwise NULL.
2262
+ * Returns RETURNING result if any, otherwise NULL. On exit, if tupleid
2263
+ * had identified the tuple to update, it will identify the tuple
2264
+ * actually updated after EvalPlanQual.
2256
2265
* ----------------------------------------------------------------
2257
2266
*/
2258
2267
static TupleTableSlot *
@@ -2717,10 +2726,10 @@ ExecMerge(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
2717
2726
2718
2727
/*-----
2719
2728
* If we are dealing with a WHEN MATCHED case, tupleid or oldtuple is
2720
- * valid, depending on whether the result relation is a table or a view.
2721
- * We execute the first action for which the additional WHEN MATCHED AND
2722
- * quals pass. If an action without quals is found, that action is
2723
- * executed.
2729
+ * valid, depending on whether the result relation is a table or a view
2730
+ * having an INSTEAD OF trigger. We execute the first action for which
2731
+ * the additional WHEN MATCHED AND quals pass. If an action without quals
2732
+ * is found, that action is executed.
2724
2733
*
2725
2734
* Similarly, in the WHEN NOT MATCHED BY SOURCE case, tupleid or oldtuple
2726
2735
* is valid, and we look at the given WHEN NOT MATCHED BY SOURCE actions
@@ -2811,8 +2820,8 @@ ExecMerge(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
2811
2820
* Check and execute the first qualifying MATCHED or NOT MATCHED BY SOURCE
2812
2821
* action, depending on whether the join quals are satisfied. If the target
2813
2822
* relation is a table, the current target tuple is identified by tupleid.
2814
- * Otherwise, if the target relation is a view, oldtuple is the current target
2815
- * tuple from the view.
2823
+ * Otherwise, if the target relation is a view having an INSTEAD OF trigger,
2824
+ * oldtuple is the current target tuple from the view.
2816
2825
*
2817
2826
* We start from the first WHEN MATCHED or WHEN NOT MATCHED BY SOURCE action
2818
2827
* 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,
2878
2887
*/
2879
2888
Assert (tupleid != NULL || oldtuple != NULL );
2880
2889
if (oldtuple != NULL )
2890
+ {
2891
+ Assert (resultRelInfo -> ri_TrigDesc );
2881
2892
ExecForceStoreHeapTuple (oldtuple , resultRelInfo -> ri_oldTupleSlot ,
2882
2893
false);
2894
+ }
2883
2895
else if (!table_tuple_fetch_row_version (resultRelInfo -> ri_RelationDesc ,
2884
2896
tupleid ,
2885
2897
SnapshotAny ,
@@ -3992,8 +4004,8 @@ ExecModifyTable(PlanState *pstate)
3992
4004
* know enough here to set t_tableOid. Quite separately from
3993
4005
* this, the FDW may fetch its own junk attrs to identify the row.
3994
4006
*
3995
- * Other relevant relkinds, currently limited to views, always
3996
- * have a wholerow attribute.
4007
+ * Other relevant relkinds, currently limited to views having
4008
+ * INSTEAD OF triggers, always have a wholerow attribute.
3997
4009
*/
3998
4010
else if (AttributeNumberIsValid (resultRelInfo -> ri_RowIdAttNo ))
3999
4011
{
0 commit comments