@@ -249,6 +249,67 @@ logicalrep_report_missing_attrs(LogicalRepRelation *remoterel,
249
249
}
250
250
}
251
251
252
+ /*
253
+ * Check if replica identity matches and mark the updatable flag.
254
+ *
255
+ * We allow for stricter replica identity (fewer columns) on subscriber as
256
+ * that will not stop us from finding unique tuple. IE, if publisher has
257
+ * identity (id,timestamp) and subscriber just (id) this will not be a
258
+ * problem, but in the opposite scenario it will.
259
+ *
260
+ * We just mark the relation entry as not updatable here if the local
261
+ * replica identity is found to be insufficient for applying
262
+ * updates/deletes (inserts don't care!) and leave it to
263
+ * check_relation_updatable() to throw the actual error if needed.
264
+ */
265
+ static void
266
+ logicalrep_rel_mark_updatable (LogicalRepRelMapEntry * entry )
267
+ {
268
+ Bitmapset * idkey ;
269
+ LogicalRepRelation * remoterel = & entry -> remoterel ;
270
+ int i ;
271
+
272
+ entry -> updatable = true;
273
+
274
+ idkey = RelationGetIndexAttrBitmap (entry -> localrel ,
275
+ INDEX_ATTR_BITMAP_IDENTITY_KEY );
276
+ /* fallback to PK if no replica identity */
277
+ if (idkey == NULL )
278
+ {
279
+ idkey = RelationGetIndexAttrBitmap (entry -> localrel ,
280
+ INDEX_ATTR_BITMAP_PRIMARY_KEY );
281
+
282
+ /*
283
+ * If no replica identity index and no PK, the published table must
284
+ * have replica identity FULL.
285
+ */
286
+ if (idkey == NULL && remoterel -> replident != REPLICA_IDENTITY_FULL )
287
+ entry -> updatable = false;
288
+ }
289
+
290
+ i = -1 ;
291
+ while ((i = bms_next_member (idkey , i )) >= 0 )
292
+ {
293
+ int attnum = i + FirstLowInvalidHeapAttributeNumber ;
294
+
295
+ if (!AttrNumberIsForUserDefinedAttr (attnum ))
296
+ ereport (ERROR ,
297
+ (errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
298
+ errmsg ("logical replication target relation \"%s.%s\" uses "
299
+ "system columns in REPLICA IDENTITY index" ,
300
+ remoterel -> nspname , remoterel -> relname )));
301
+
302
+ attnum = AttrNumberGetAttrOffset (attnum );
303
+
304
+ if (entry -> attrmap -> attnums [attnum ] < 0 ||
305
+ !bms_is_member (entry -> attrmap -> attnums [attnum ], remoterel -> attkeys ))
306
+ {
307
+ entry -> updatable = false;
308
+ break ;
309
+ }
310
+ }
311
+ }
312
+
252
313
/*
253
314
* Open the local relation associated with the remote one.
254
315
*
@@ -307,7 +368,6 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
307
368
if (!entry -> localrelvalid )
308
369
{
309
370
Oid relid ;
310
- Bitmapset * idkey ;
311
371
TupleDesc desc ;
312
372
MemoryContext oldctx ;
313
373
int i ;
@@ -366,54 +426,10 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
366
426
bms_free (missingatts );
367
427
368
428
/*
369
- * Check that replica identity matches. We allow for stricter replica
370
- * identity (fewer columns) on subscriber as that will not stop us
371
- * from finding unique tuple. IE, if publisher has identity
372
- * (id,timestamp) and subscriber just (id) this will not be a problem,
373
- * but in the opposite scenario it will.
374
- *
375
- * Don't throw any error here just mark the relation entry as not
376
- * updatable, as replica identity is only for updates and deletes but
377
- * inserts can be replicated even without it.
429
+ * Set if the table's replica identity is enough to apply
430
+ * update/delete.
378
431
*/
379
- entry -> updatable = true;
380
- idkey = RelationGetIndexAttrBitmap (entry -> localrel ,
381
- INDEX_ATTR_BITMAP_IDENTITY_KEY );
382
- /* fallback to PK if no replica identity */
383
- if (idkey == NULL )
384
- {
385
- idkey = RelationGetIndexAttrBitmap (entry -> localrel ,
386
- INDEX_ATTR_BITMAP_PRIMARY_KEY );
387
-
388
- /*
389
- * If no replica identity index and no PK, the published table
390
- * must have replica identity FULL.
391
- */
392
- if (idkey == NULL && remoterel -> replident != REPLICA_IDENTITY_FULL )
393
- entry -> updatable = false;
394
- }
395
-
396
- i = -1 ;
397
- while ((i = bms_next_member (idkey , i )) >= 0 )
398
- {
399
- int attnum = i + FirstLowInvalidHeapAttributeNumber ;
400
-
401
- if (!AttrNumberIsForUserDefinedAttr (attnum ))
402
- ereport (ERROR ,
403
- (errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
404
- errmsg ("logical replication target relation \"%s.%s\" uses "
405
- "system columns in REPLICA IDENTITY index" ,
406
- remoterel -> nspname , remoterel -> relname )));
407
-
408
- attnum = AttrNumberGetAttrOffset (attnum );
409
-
410
- if (entry -> attrmap -> attnums [attnum ] < 0 ||
411
- !bms_is_member (entry -> attrmap -> attnums [attnum ], remoterel -> attkeys ))
412
- {
413
- entry -> updatable = false;
414
- break ;
415
- }
416
- }
432
+ logicalrep_rel_mark_updatable (entry );
417
433
418
434
entry -> localrelvalid = true;
419
435
}
@@ -651,7 +667,8 @@ logicalrep_partition_open(LogicalRepRelMapEntry *root,
651
667
attrmap -> maplen * sizeof (AttrNumber ));
652
668
}
653
669
654
- entry -> updatable = root -> updatable ;
670
+ /* Set if the table's replica identity is enough to apply update/delete. */
671
+ logicalrep_rel_mark_updatable (entry );
655
672
656
673
entry -> localrelvalid = true;
657
674
0 commit comments