mirror of
https://github.com/postgres/postgres.git
synced 2025-10-09 00:05:07 -04:00
Fix replica identity check for MERGE.
When executing a MERGE, check that the target relation supports all actions mentioned in the MERGE command. Specifically, check that it has a REPLICA IDENTITY if it publishes updates or deletes and the MERGE command contains update or delete actions. Failing to do this can silently break replication. Author: Zhijie Hou <houzj.fnst@fujitsu.com> Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com> Tested-by: Chao Li <li.evan.chao@gmail.com> Discussion: https://postgr.es/m/OS3PR01MB57180C87E43A679A730482DF94B62@OS3PR01MB5718.jpnprd01.prod.outlook.com Backpatch-through: 15
This commit is contained in:
parent
5386bfb9c1
commit
fc6600fc1c
@ -1061,6 +1061,15 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation,
|
|||||||
{
|
{
|
||||||
case RELKIND_RELATION:
|
case RELKIND_RELATION:
|
||||||
case RELKIND_PARTITIONED_TABLE:
|
case RELKIND_PARTITIONED_TABLE:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For MERGE, check that the target relation supports each action.
|
||||||
|
* For other operations, just check the operation itself.
|
||||||
|
*/
|
||||||
|
if (operation == CMD_MERGE)
|
||||||
|
foreach_node(MergeAction, action, mergeActions)
|
||||||
|
CheckCmdReplicaIdentity(resultRel, action->commandType);
|
||||||
|
else
|
||||||
CheckCmdReplicaIdentity(resultRel, operation);
|
CheckCmdReplicaIdentity(resultRel, operation);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1947,6 +1947,34 @@ INSERT INTO testpub_insert_onconfl_parted VALUES (1, 1) ON CONFLICT DO NOTHING;
|
|||||||
DROP PUBLICATION pub1;
|
DROP PUBLICATION pub1;
|
||||||
DROP TABLE testpub_insert_onconfl_no_ri;
|
DROP TABLE testpub_insert_onconfl_no_ri;
|
||||||
DROP TABLE testpub_insert_onconfl_parted;
|
DROP TABLE testpub_insert_onconfl_parted;
|
||||||
|
-- Test that the MERGE command correctly checks REPLICA IDENTITY when the
|
||||||
|
-- target table is published.
|
||||||
|
CREATE TABLE testpub_merge_no_ri (a int, b int);
|
||||||
|
CREATE TABLE testpub_merge_pk (a int primary key, b int);
|
||||||
|
SET client_min_messages = 'ERROR';
|
||||||
|
CREATE PUBLICATION pub1 FOR ALL TABLES;
|
||||||
|
RESET client_min_messages;
|
||||||
|
-- fail - missing REPLICA IDENTITY
|
||||||
|
MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1
|
||||||
|
WHEN MATCHED THEN UPDATE SET b = s.b;
|
||||||
|
ERROR: cannot update table "testpub_merge_no_ri" because it does not have a replica identity and publishes updates
|
||||||
|
HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
|
||||||
|
-- fail - missing REPLICA IDENTITY
|
||||||
|
MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1
|
||||||
|
WHEN MATCHED THEN DELETE;
|
||||||
|
ERROR: cannot delete from table "testpub_merge_no_ri" because it does not have a replica identity and publishes deletes
|
||||||
|
HINT: To enable deleting from the table, set REPLICA IDENTITY using ALTER TABLE.
|
||||||
|
-- ok - insert and do nothing are not restricted
|
||||||
|
MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1
|
||||||
|
WHEN MATCHED THEN DO NOTHING
|
||||||
|
WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, 0);
|
||||||
|
-- ok - REPLICA IDENTITY is DEFAULT and table has a PK
|
||||||
|
MERGE INTO testpub_merge_pk USING testpub_merge_no_ri s ON s.a >= 1
|
||||||
|
WHEN MATCHED AND s.a > 0 THEN UPDATE SET b = s.b
|
||||||
|
WHEN MATCHED THEN DELETE;
|
||||||
|
DROP PUBLICATION pub1;
|
||||||
|
DROP TABLE testpub_merge_no_ri;
|
||||||
|
DROP TABLE testpub_merge_pk;
|
||||||
RESET SESSION AUTHORIZATION;
|
RESET SESSION AUTHORIZATION;
|
||||||
DROP ROLE regress_publication_user, regress_publication_user2;
|
DROP ROLE regress_publication_user, regress_publication_user2;
|
||||||
DROP ROLE regress_publication_user_dummy;
|
DROP ROLE regress_publication_user_dummy;
|
||||||
|
@ -1250,6 +1250,37 @@ DROP PUBLICATION pub1;
|
|||||||
DROP TABLE testpub_insert_onconfl_no_ri;
|
DROP TABLE testpub_insert_onconfl_no_ri;
|
||||||
DROP TABLE testpub_insert_onconfl_parted;
|
DROP TABLE testpub_insert_onconfl_parted;
|
||||||
|
|
||||||
|
-- Test that the MERGE command correctly checks REPLICA IDENTITY when the
|
||||||
|
-- target table is published.
|
||||||
|
CREATE TABLE testpub_merge_no_ri (a int, b int);
|
||||||
|
CREATE TABLE testpub_merge_pk (a int primary key, b int);
|
||||||
|
|
||||||
|
SET client_min_messages = 'ERROR';
|
||||||
|
CREATE PUBLICATION pub1 FOR ALL TABLES;
|
||||||
|
RESET client_min_messages;
|
||||||
|
|
||||||
|
-- fail - missing REPLICA IDENTITY
|
||||||
|
MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1
|
||||||
|
WHEN MATCHED THEN UPDATE SET b = s.b;
|
||||||
|
|
||||||
|
-- fail - missing REPLICA IDENTITY
|
||||||
|
MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1
|
||||||
|
WHEN MATCHED THEN DELETE;
|
||||||
|
|
||||||
|
-- ok - insert and do nothing are not restricted
|
||||||
|
MERGE INTO testpub_merge_no_ri USING testpub_merge_pk s ON s.a >= 1
|
||||||
|
WHEN MATCHED THEN DO NOTHING
|
||||||
|
WHEN NOT MATCHED THEN INSERT (a, b) VALUES (0, 0);
|
||||||
|
|
||||||
|
-- ok - REPLICA IDENTITY is DEFAULT and table has a PK
|
||||||
|
MERGE INTO testpub_merge_pk USING testpub_merge_no_ri s ON s.a >= 1
|
||||||
|
WHEN MATCHED AND s.a > 0 THEN UPDATE SET b = s.b
|
||||||
|
WHEN MATCHED THEN DELETE;
|
||||||
|
|
||||||
|
DROP PUBLICATION pub1;
|
||||||
|
DROP TABLE testpub_merge_no_ri;
|
||||||
|
DROP TABLE testpub_merge_pk;
|
||||||
|
|
||||||
RESET SESSION AUTHORIZATION;
|
RESET SESSION AUTHORIZATION;
|
||||||
DROP ROLE regress_publication_user, regress_publication_user2;
|
DROP ROLE regress_publication_user, regress_publication_user2;
|
||||||
DROP ROLE regress_publication_user_dummy;
|
DROP ROLE regress_publication_user_dummy;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user