@@ -220,41 +220,63 @@ logicalrep_rel_att_by_name(LogicalRepRelation *remoterel, const char *attname)
220220}
221221
222222/*
223- * Report error with names of the missing local relation column(s), if any.
223+ * Returns a comma-separated string of attribute names based on the provided
224+ * relation and bitmap indicating which attributes to include.
224225 */
225- static void
226- logicalrep_report_missing_attrs (LogicalRepRelation * remoterel ,
227- Bitmapset * missingatts )
226+ static char *
227+ logicalrep_get_attrs_str (LogicalRepRelation * remoterel , Bitmapset * atts )
228228{
229- if (!bms_is_empty (missingatts ))
229+ StringInfoData attsbuf ;
230+ int attcnt = 0 ;
231+ int i = -1 ;
232+
233+ Assert (!bms_is_empty (atts ));
234+
235+ initStringInfo (& attsbuf );
236+
237+ while ((i = bms_next_member (atts , i )) >= 0 )
230238 {
231- StringInfoData missingattsbuf ;
232- int missingattcnt = 0 ;
233- int i ;
239+ attcnt ++ ;
240+ if ( attcnt > 1 )
241+ appendStringInfo ( & attsbuf , _ ( ", " )) ;
234242
235- initStringInfo (& missingattsbuf );
243+ appendStringInfo (& attsbuf , _ ("\"%s\"" ), remoterel -> attnames [i ]);
244+ }
236245
237- i = -1 ;
238- while ((i = bms_next_member (missingatts , i )) >= 0 )
239- {
240- missingattcnt ++ ;
241- if (missingattcnt == 1 )
242- appendStringInfo (& missingattsbuf , _ ("\"%s\"" ),
243- remoterel -> attnames [i ]);
244- else
245- appendStringInfo (& missingattsbuf , _ (", \"%s\"" ),
246- remoterel -> attnames [i ]);
247- }
246+ return attsbuf .data ;
247+ }
248248
249+ /*
250+ * If attempting to replicate missing or generated columns, report an error.
251+ * Prioritize 'missing' errors if both occur though the prioritization is
252+ * arbitrary.
253+ */
254+ static void
255+ logicalrep_report_missing_or_gen_attrs (LogicalRepRelation * remoterel ,
256+ Bitmapset * missingatts ,
257+ Bitmapset * generatedatts )
258+ {
259+ if (!bms_is_empty (missingatts ))
249260 ereport (ERROR ,
250- (errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
251- errmsg_plural ("logical replication target relation \"%s.%s\" is missing replicated column: %s" ,
252- "logical replication target relation \"%s.%s\" is missing replicated columns: %s" ,
253- missingattcnt ,
254- remoterel -> nspname ,
255- remoterel -> relname ,
256- missingattsbuf .data )));
257- }
261+ errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
262+ errmsg_plural ("logical replication target relation \"%s.%s\" is missing replicated column: %s" ,
263+ "logical replication target relation \"%s.%s\" is missing replicated columns: %s" ,
264+ bms_num_members (missingatts ),
265+ remoterel -> nspname ,
266+ remoterel -> relname ,
267+ logicalrep_get_attrs_str (remoterel ,
268+ missingatts )));
269+
270+ if (!bms_is_empty (generatedatts ))
271+ ereport (ERROR ,
272+ errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
273+ errmsg_plural ("logical replication target relation \"%s.%s\" has incompatible generated column: %s" ,
274+ "logical replication target relation \"%s.%s\" has incompatible generated columns: %s" ,
275+ bms_num_members (generatedatts ),
276+ remoterel -> nspname ,
277+ remoterel -> relname ,
278+ logicalrep_get_attrs_str (remoterel ,
279+ generatedatts )));
258280}
259281
260282/*
@@ -380,6 +402,7 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
380402 MemoryContext oldctx ;
381403 int i ;
382404 Bitmapset * missingatts ;
405+ Bitmapset * generatedattrs = NULL ;
383406
384407 /* Release the no-longer-useful attrmap, if any. */
385408 if (entry -> attrmap )
@@ -421,7 +444,7 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
421444 int attnum ;
422445 Form_pg_attribute attr = TupleDescAttr (desc , i );
423446
424- if (attr -> attisdropped || attr -> attgenerated )
447+ if (attr -> attisdropped )
425448 {
426449 entry -> attrmap -> attnums [i ] = -1 ;
427450 continue ;
@@ -432,12 +455,20 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
432455
433456 entry -> attrmap -> attnums [i ] = attnum ;
434457 if (attnum >= 0 )
458+ {
459+ /* Remember which subscriber columns are generated. */
460+ if (attr -> attgenerated )
461+ generatedattrs = bms_add_member (generatedattrs , attnum );
462+
435463 missingatts = bms_del_member (missingatts , attnum );
464+ }
436465 }
437466
438- logicalrep_report_missing_attrs (remoterel , missingatts );
467+ logicalrep_report_missing_or_gen_attrs (remoterel , missingatts ,
468+ generatedattrs );
439469
440470 /* be tidy */
471+ bms_free (generatedattrs );
441472 bms_free (missingatts );
442473
443474 /*
0 commit comments