Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4548c76

Browse files
author
Amit Kapila
committed
Invalidate all partitions for a partitioned table in publication.
Updates/Deletes on a partition were allowed even without replica identityafter the parent table was added to a publication. This would later leadto an error on subscribers. The reason was that we were not invalidatingthe partition's relcache and the publication information for partitionswas not getting rebuilt. Similarly, we were not invalidating thepartitions' relcache after dropping a partitioned table from a publicationwhich will prohibit Updates/Deletes on its partition without replicaidentity even without any publication.Reported-by: Haiying TangAuthor: Hou Zhijie and Vignesh CReviewed-by: Vignesh C and Amit KapilaBackpatch-through: 13Discussion:https://postgr.es/m/OS0PR01MB6113D77F583C922F1CEAA1C3FBD29@OS0PR01MB6113.jpnprd01.prod.outlook.com
1 parent5e77625 commit4548c76

File tree

6 files changed

+116
-55
lines changed

6 files changed

+116
-55
lines changed

‎src/backend/catalog/pg_publication.c

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include"catalog/pg_publication.h"
3232
#include"catalog/pg_publication_rel.h"
3333
#include"catalog/pg_type.h"
34+
#include"commands/publicationcmds.h"
3435
#include"funcapi.h"
3536
#include"miscadmin.h"
3637
#include"utils/array.h"
@@ -136,6 +137,42 @@ pg_relation_is_publishable(PG_FUNCTION_ARGS)
136137
PG_RETURN_BOOL(result);
137138
}
138139

140+
/*
141+
* Gets the relations based on the publication partition option for a specified
142+
* relation.
143+
*/
144+
List*
145+
GetPubPartitionOptionRelations(List*result,PublicationPartOptpub_partopt,
146+
Oidrelid)
147+
{
148+
if (get_rel_relkind(relid)==RELKIND_PARTITIONED_TABLE&&
149+
pub_partopt!=PUBLICATION_PART_ROOT)
150+
{
151+
List*all_parts=find_all_inheritors(relid,NoLock,
152+
NULL);
153+
154+
if (pub_partopt==PUBLICATION_PART_ALL)
155+
result=list_concat(result,all_parts);
156+
elseif (pub_partopt==PUBLICATION_PART_LEAF)
157+
{
158+
ListCell*lc;
159+
160+
foreach(lc,all_parts)
161+
{
162+
OidpartOid=lfirst_oid(lc);
163+
164+
if (get_rel_relkind(partOid)!=RELKIND_PARTITIONED_TABLE)
165+
result=lappend_oid(result,partOid);
166+
}
167+
}
168+
else
169+
Assert(false);
170+
}
171+
else
172+
result=lappend_oid(result,relid);
173+
174+
returnresult;
175+
}
139176

140177
/*
141178
* Insert new publication / relation mapping.
@@ -153,6 +190,7 @@ publication_add_relation(Oid pubid, PublicationRelInfo *targetrel,
153190
Publication*pub=GetPublication(pubid);
154191
ObjectAddressmyself,
155192
referenced;
193+
List*relids=NIL;
156194

157195
rel=table_open(PublicationRelRelationId,RowExclusiveLock);
158196

@@ -208,8 +246,18 @@ publication_add_relation(Oid pubid, PublicationRelInfo *targetrel,
208246
/* Close the table. */
209247
table_close(rel,RowExclusiveLock);
210248

211-
/* Invalidate relcache so that publication info is rebuilt. */
212-
CacheInvalidateRelcache(targetrel->relation);
249+
/*
250+
* Invalidate relcache so that publication info is rebuilt.
251+
*
252+
* For the partitioned tables, we must invalidate all partitions contained
253+
* in the respective partition hierarchies, not just the one explicitly
254+
* mentioned in the publication. This is required because we implicitly
255+
* publish the child tables when the parent table is published.
256+
*/
257+
relids=GetPubPartitionOptionRelations(relids,PUBLICATION_PART_ALL,
258+
relid);
259+
260+
InvalidatePublicationRels(relids);
213261

214262
returnmyself;
215263
}
@@ -241,7 +289,7 @@ GetRelationPublications(Oid relid)
241289
/*
242290
* Gets list of relation oids for a publication.
243291
*
244-
* This should only be usedfor normal publications, the FOR ALL TABLES
292+
* This should only be usedFOR TABLE publications, the FOR ALL TABLES
245293
* should use GetAllTablesPublicationRelations().
246294
*/
247295
List*
@@ -270,32 +318,8 @@ GetPublicationRelations(Oid pubid, PublicationPartOpt pub_partopt)
270318
Form_pg_publication_relpubrel;
271319

272320
pubrel= (Form_pg_publication_rel)GETSTRUCT(tup);
273-
274-
if (get_rel_relkind(pubrel->prrelid)==RELKIND_PARTITIONED_TABLE&&
275-
pub_partopt!=PUBLICATION_PART_ROOT)
276-
{
277-
List*all_parts=find_all_inheritors(pubrel->prrelid,NoLock,
278-
NULL);
279-
280-
if (pub_partopt==PUBLICATION_PART_ALL)
281-
result=list_concat(result,all_parts);
282-
elseif (pub_partopt==PUBLICATION_PART_LEAF)
283-
{
284-
ListCell*lc;
285-
286-
foreach(lc,all_parts)
287-
{
288-
OidpartOid=lfirst_oid(lc);
289-
290-
if (get_rel_relkind(partOid)!=RELKIND_PARTITIONED_TABLE)
291-
result=lappend_oid(result,partOid);
292-
}
293-
}
294-
else
295-
Assert(false);
296-
}
297-
else
298-
result=lappend_oid(result,pubrel->prrelid);
321+
result=GetPubPartitionOptionRelations(result,pub_partopt,
322+
pubrel->prrelid);
299323
}
300324

301325
systable_endscan(scan);

‎src/backend/commands/publicationcmds.c

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@
4545
#include"utils/syscache.h"
4646
#include"utils/varlena.h"
4747

48-
/* Same as MAXNUMMESSAGES in sinvaladt.c */
49-
#defineMAX_RELCACHE_INVAL_MSGS 4096
50-
5148
staticList*OpenTableList(List*tables);
5249
staticvoidCloseTableList(List*rels);
5350
staticvoidPublicationAddTables(Oidpubid,List*rels,boolif_not_exists,
@@ -329,23 +326,7 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt,
329326
List*relids=GetPublicationRelations(pubform->oid,
330327
PUBLICATION_PART_ALL);
331328

332-
/*
333-
* We don't want to send too many individual messages, at some point
334-
* it's cheaper to just reset whole relcache.
335-
*/
336-
if (list_length(relids)<MAX_RELCACHE_INVAL_MSGS)
337-
{
338-
ListCell*lc;
339-
340-
foreach(lc,relids)
341-
{
342-
Oidrelid=lfirst_oid(lc);
343-
344-
CacheInvalidateRelcacheByRelid(relid);
345-
}
346-
}
347-
else
348-
CacheInvalidateRelcacheAll();
329+
InvalidatePublicationRels(relids);
349330
}
350331

351332
ObjectAddressSet(obj,PublicationRelationId,pubform->oid);
@@ -355,6 +336,27 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt,
355336
InvokeObjectPostAlterHook(PublicationRelationId,pubform->oid,0);
356337
}
357338

339+
/*
340+
* Invalidate the relations.
341+
*/
342+
void
343+
InvalidatePublicationRels(List*relids)
344+
{
345+
/*
346+
* We don't want to send too many individual messages, at some point it's
347+
* cheaper to just reset whole relcache.
348+
*/
349+
if (list_length(relids)<MAX_RELCACHE_INVAL_MSGS)
350+
{
351+
ListCell*lc;
352+
353+
foreach(lc,relids)
354+
CacheInvalidateRelcacheByRelid(lfirst_oid(lc));
355+
}
356+
else
357+
CacheInvalidateRelcacheAll();
358+
}
359+
358360
/*
359361
* Add or remove table to/from publication.
360362
*/
@@ -488,6 +490,7 @@ RemovePublicationRelById(Oid proid)
488490
Relationrel;
489491
HeapTupletup;
490492
Form_pg_publication_relpubrel;
493+
List*relids=NIL;
491494

492495
rel=table_open(PublicationRelRelationId,RowExclusiveLock);
493496

@@ -499,8 +502,18 @@ RemovePublicationRelById(Oid proid)
499502

500503
pubrel= (Form_pg_publication_rel)GETSTRUCT(tup);
501504

502-
/* Invalidate relcache so that publication info is rebuilt. */
503-
CacheInvalidateRelcacheByRelid(pubrel->prrelid);
505+
/*
506+
* Invalidate relcache so that publication info is rebuilt.
507+
*
508+
* For the partitioned tables, we must invalidate all partitions contained
509+
* in the respective partition hierarchies, not just the one explicitly
510+
* mentioned in the publication. This is required because we implicitly
511+
* publish the child tables when the parent table is published.
512+
*/
513+
relids=GetPubPartitionOptionRelations(relids,PUBLICATION_PART_ALL,
514+
pubrel->prrelid);
515+
516+
InvalidatePublicationRels(relids);
504517

505518
CatalogTupleDelete(rel,&tup->t_self);
506519

‎src/include/catalog/pg_publication.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ typedef enum PublicationPartOpt
111111
externList*GetPublicationRelations(Oidpubid,PublicationPartOptpub_partopt);
112112
externList*GetAllTablesPublications(void);
113113
externList*GetAllTablesPublicationRelations(boolpubviaroot);
114+
externList*GetPubPartitionOptionRelations(List*result,
115+
PublicationPartOptpub_partopt,
116+
Oidrelid);
114117

115118
externboolis_publishable_relation(Relationrel);
116119
externObjectAddresspublication_add_relation(Oidpubid,PublicationRelInfo*targetrel,

‎src/include/commands/publicationcmds.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717

1818
#include"catalog/objectaddress.h"
1919
#include"parser/parse_node.h"
20+
#include"utils/inval.h"
21+
22+
/* Same as MAXNUMMESSAGES in sinvaladt.c */
23+
#defineMAX_RELCACHE_INVAL_MSGS 4096
2024

2125
externObjectAddressCreatePublication(ParseState*pstate,CreatePublicationStmt*stmt);
2226
externvoidAlterPublication(ParseState*pstate,AlterPublicationStmt*stmt);
@@ -25,5 +29,6 @@ extern void RemovePublicationRelById(Oid proid);
2529

2630
externObjectAddressAlterPublicationOwner(constchar*name,OidnewOwnerId);
2731
externvoidAlterPublicationOwner_oid(Oidpubid,OidnewOwnerId);
32+
externvoidInvalidatePublicationRels(List*relids);
2833

2934
#endif/* PUBLICATIONCMDS_H */

‎src/test/regress/expected/publication.out

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,12 @@ CREATE PUBLICATION testpub_forparted;
126126
CREATE PUBLICATION testpub_forparted1;
127127
RESET client_min_messages;
128128
CREATE TABLE testpub_parted1 (LIKE testpub_parted);
129+
CREATE TABLE testpub_parted2 (LIKE testpub_parted);
129130
ALTER PUBLICATION testpub_forparted1 SET (publish='insert');
131+
ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted1 FOR VALUES IN (1);
132+
ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted2 FOR VALUES IN (2);
130133
-- works despite missing REPLICA IDENTITY, because updates are not replicated
131134
UPDATE testpub_parted1 SET a = 1;
132-
ALTER TABLE testpub_parted ATTACH PARTITION testpub_parted1 FOR VALUES IN (1);
133135
-- only parent is listed as being in publication, not the partition
134136
ALTER PUBLICATION testpub_forparted ADD TABLE testpub_parted;
135137
\dRp+ testpub_forparted
@@ -156,7 +158,14 @@ ALTER PUBLICATION testpub_forparted SET (publish_via_partition_root = true);
156158
Tables:
157159
"public.testpub_parted"
158160

159-
DROP TABLE testpub_parted1;
161+
-- still fail, because parent's publication replicates updates
162+
UPDATE testpub_parted2 SET a = 2;
163+
ERROR: cannot update table "testpub_parted2" because it does not have a replica identity and publishes updates
164+
HINT: To enable updating the table, set REPLICA IDENTITY using ALTER TABLE.
165+
ALTER PUBLICATION testpub_forparted DROP TABLE testpub_parted;
166+
-- works again, because update is no longer replicated
167+
UPDATE testpub_parted2 SET a = 2;
168+
DROP TABLE testpub_parted1, testpub_parted2;
160169
DROP PUBLICATION testpub_forparted, testpub_forparted1;
161170
-- Test cache invalidation FOR ALL TABLES publication
162171
SET client_min_messages = 'ERROR';

‎src/test/regress/sql/publication.sql

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,12 @@ CREATE PUBLICATION testpub_forparted;
7676
CREATE PUBLICATION testpub_forparted1;
7777
RESET client_min_messages;
7878
CREATETABLEtestpub_parted1 (LIKE testpub_parted);
79+
CREATETABLEtestpub_parted2 (LIKE testpub_parted);
7980
ALTER PUBLICATION testpub_forparted1SET (publish='insert');
81+
ALTERTABLE testpub_parted ATTACH PARTITION testpub_parted1 FORVALUESIN (1);
82+
ALTERTABLE testpub_parted ATTACH PARTITION testpub_parted2 FORVALUESIN (2);
8083
-- works despite missing REPLICA IDENTITY, because updates are not replicated
8184
UPDATE testpub_parted1SET a=1;
82-
ALTERTABLE testpub_parted ATTACH PARTITION testpub_parted1 FORVALUESIN (1);
8385
-- only parent is listed as being in publication, not the partition
8486
ALTER PUBLICATION testpub_forparted ADD TABLE testpub_parted;
8587
\dRp+ testpub_forparted
@@ -90,7 +92,12 @@ ALTER TABLE testpub_parted DETACH PARTITION testpub_parted1;
9092
UPDATE testpub_parted1SET a=1;
9193
ALTER PUBLICATION testpub_forpartedSET (publish_via_partition_root= true);
9294
\dRp+ testpub_forparted
93-
DROPTABLE testpub_parted1;
95+
-- still fail, because parent's publication replicates updates
96+
UPDATE testpub_parted2SET a=2;
97+
ALTER PUBLICATION testpub_forpartedDROPTABLEtestpub_parted;
98+
-- works again, because update is no longer replicated
99+
UPDATE testpub_parted2SET a=2;
100+
DROPTABLE testpub_parted1, testpub_parted2;
94101
DROP PUBLICATION testpub_forparted, testpub_forparted1;
95102

96103
-- Test cache invalidation FOR ALL TABLES publication

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp