mirror of
https://github.com/postgres/postgres.git
synced 2025-06-05 23:56:58 +03:00
Fix new assertion for MERGE view_name ... DO NOTHING.
Such queries don't expand automatically updatable views, and ModifyTable uses the wholerow attribute unconditionally. The user-visible behavior is fine, so change to more-specific assertions. Commit d5f788b41dc2cbdde6e7694c70dda54d829a5ed5 added the wrong assertion. Back-patch to v17, where commit 5f2e179bd31e5f5803005101eb12a8d7bf8db8f3 introduced MERGE view_name. Reported by Alexander Lakhin. Discussion: https://postgr.es/m/e4b40a88-c134-6926-3196-bc4501cb87a2@gmail.com
This commit is contained in:
parent
f5bb46fb2e
commit
0d3b35c367
@ -24,12 +24,13 @@
|
|||||||
* 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
|
* The relation to modify can be an ordinary table, a foreign table, or a
|
||||||
* INSTEAD OF trigger, or a foreign table. Earlier processing already
|
* view. If it's a view, either it has sufficient INSTEAD OF triggers or
|
||||||
* pointed ModifyTable to the underlying relations of any automatically
|
* this node executes only MERGE ... DO NOTHING. If the original MERGE
|
||||||
* updatable view not using an INSTEAD OF trigger, so code here can
|
* targeted a view not in one of those two categories, earlier processing
|
||||||
* assume it won't have one as a modification target. This node does
|
* already pointed the ModifyTable result relation to an underlying
|
||||||
* process ri_WithCheckOptions, which may have expressions from those
|
* relation of that other view. This node does process
|
||||||
|
* ri_WithCheckOptions, which may have expressions from those other,
|
||||||
* automatically updatable views.
|
* 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.
|
||||||
@ -2726,10 +2727,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.
|
||||||
* having an INSTEAD OF trigger. We execute the first action for which
|
* We execute the first action for which the additional WHEN MATCHED AND
|
||||||
* the additional WHEN MATCHED AND quals pass. If an action without quals
|
* quals pass. If an action without quals is found, that action is
|
||||||
* is found, that action is executed.
|
* 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
|
||||||
@ -2820,8 +2821,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 having an INSTEAD OF trigger,
|
* Otherwise, if the target relation is a view, oldtuple is the current target
|
||||||
* oldtuple is the current target tuple from the view.
|
* 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
|
||||||
@ -2887,11 +2888,8 @@ 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,
|
||||||
@ -2983,6 +2981,9 @@ lmerge_matched:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* called table_tuple_fetch_row_version() above */
|
||||||
|
Assert(oldtuple == NULL);
|
||||||
|
|
||||||
result = ExecUpdateAct(context, resultRelInfo, tupleid,
|
result = ExecUpdateAct(context, resultRelInfo, tupleid,
|
||||||
NULL, newslot, canSetTag,
|
NULL, newslot, canSetTag,
|
||||||
&updateCxt);
|
&updateCxt);
|
||||||
@ -3031,8 +3032,13 @@ lmerge_matched:
|
|||||||
return NULL; /* "do nothing" */
|
return NULL; /* "do nothing" */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
/* called table_tuple_fetch_row_version() above */
|
||||||
|
Assert(oldtuple == NULL);
|
||||||
|
|
||||||
result = ExecDeleteAct(context, resultRelInfo, tupleid,
|
result = ExecDeleteAct(context, resultRelInfo, tupleid,
|
||||||
false);
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
if (result == TM_Ok)
|
if (result == TM_Ok)
|
||||||
{
|
{
|
||||||
@ -4004,8 +4010,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 having
|
* Other relevant relkinds, currently limited to views, always
|
||||||
* INSTEAD OF triggers, always have a wholerow attribute.
|
* have a wholerow attribute.
|
||||||
*/
|
*/
|
||||||
else if (AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
|
else if (AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo))
|
||||||
{
|
{
|
||||||
|
@ -199,6 +199,9 @@ MERGE INTO ro_view13 AS t USING (VALUES (3, 'Row 3')) AS v(a,b) ON t.a = v.a
|
|||||||
ERROR: cannot insert into view "ro_view13"
|
ERROR: cannot insert into view "ro_view13"
|
||||||
DETAIL: Views that do not select from a single table or view are not automatically updatable.
|
DETAIL: Views that do not select from a single table or view are not automatically updatable.
|
||||||
HINT: To enable inserting into the view using MERGE, provide an INSTEAD OF INSERT trigger.
|
HINT: To enable inserting into the view using MERGE, provide an INSTEAD OF INSERT trigger.
|
||||||
|
MERGE INTO ro_view13 AS t USING (VALUES (2, 'Row 2')) AS v(a,b) ON t.a = v.a
|
||||||
|
WHEN MATCHED THEN DO NOTHING
|
||||||
|
WHEN NOT MATCHED THEN DO NOTHING; -- should be OK to do nothing
|
||||||
MERGE INTO ro_view13 AS t USING (VALUES (3, 'Row 3')) AS v(a,b) ON t.a = v.a
|
MERGE INTO ro_view13 AS t USING (VALUES (3, 'Row 3')) AS v(a,b) ON t.a = v.a
|
||||||
WHEN MATCHED THEN DO NOTHING
|
WHEN MATCHED THEN DO NOTHING
|
||||||
WHEN NOT MATCHED THEN DO NOTHING; -- should be OK to do nothing
|
WHEN NOT MATCHED THEN DO NOTHING; -- should be OK to do nothing
|
||||||
@ -375,6 +378,8 @@ DELETE FROM ro_view18;
|
|||||||
ERROR: cannot delete from view "ro_view18"
|
ERROR: cannot delete from view "ro_view18"
|
||||||
DETAIL: Views that do not select from a single table or view are not automatically updatable.
|
DETAIL: Views that do not select from a single table or view are not automatically updatable.
|
||||||
HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.
|
HINT: To enable deleting from the view, provide an INSTEAD OF DELETE trigger or an unconditional ON DELETE DO INSTEAD rule.
|
||||||
|
MERGE INTO ro_view18 AS t USING (VALUES (1, 'Row 1')) AS v(a,b) ON t.a = v.a
|
||||||
|
WHEN MATCHED THEN DO NOTHING; -- should be OK to do nothing
|
||||||
UPDATE ro_view19 SET last_value=1000;
|
UPDATE ro_view19 SET last_value=1000;
|
||||||
ERROR: cannot update view "ro_view19"
|
ERROR: cannot update view "ro_view19"
|
||||||
DETAIL: Views that do not select from a single table or view are not automatically updatable.
|
DETAIL: Views that do not select from a single table or view are not automatically updatable.
|
||||||
|
@ -68,6 +68,9 @@ MERGE INTO ro_view13 AS t USING (VALUES (2, 'Row 2')) AS v(a,b) ON t.a = v.a
|
|||||||
WHEN MATCHED THEN UPDATE SET b = v.b;
|
WHEN MATCHED THEN UPDATE SET b = v.b;
|
||||||
MERGE INTO ro_view13 AS t USING (VALUES (3, 'Row 3')) AS v(a,b) ON t.a = v.a
|
MERGE INTO ro_view13 AS t USING (VALUES (3, 'Row 3')) AS v(a,b) ON t.a = v.a
|
||||||
WHEN NOT MATCHED THEN INSERT VALUES (v.a, v.b);
|
WHEN NOT MATCHED THEN INSERT VALUES (v.a, v.b);
|
||||||
|
MERGE INTO ro_view13 AS t USING (VALUES (2, 'Row 2')) AS v(a,b) ON t.a = v.a
|
||||||
|
WHEN MATCHED THEN DO NOTHING
|
||||||
|
WHEN NOT MATCHED THEN DO NOTHING; -- should be OK to do nothing
|
||||||
MERGE INTO ro_view13 AS t USING (VALUES (3, 'Row 3')) AS v(a,b) ON t.a = v.a
|
MERGE INTO ro_view13 AS t USING (VALUES (3, 'Row 3')) AS v(a,b) ON t.a = v.a
|
||||||
WHEN MATCHED THEN DO NOTHING
|
WHEN MATCHED THEN DO NOTHING
|
||||||
WHEN NOT MATCHED THEN DO NOTHING; -- should be OK to do nothing
|
WHEN NOT MATCHED THEN DO NOTHING; -- should be OK to do nothing
|
||||||
@ -121,6 +124,8 @@ DELETE FROM rw_view16 WHERE a=-3; -- should be OK
|
|||||||
-- Read-only views
|
-- Read-only views
|
||||||
INSERT INTO ro_view17 VALUES (3, 'ROW 3');
|
INSERT INTO ro_view17 VALUES (3, 'ROW 3');
|
||||||
DELETE FROM ro_view18;
|
DELETE FROM ro_view18;
|
||||||
|
MERGE INTO ro_view18 AS t USING (VALUES (1, 'Row 1')) AS v(a,b) ON t.a = v.a
|
||||||
|
WHEN MATCHED THEN DO NOTHING; -- should be OK to do nothing
|
||||||
UPDATE ro_view19 SET last_value=1000;
|
UPDATE ro_view19 SET last_value=1000;
|
||||||
UPDATE ro_view20 SET b=upper(b);
|
UPDATE ro_view20 SET b=upper(b);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user