1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-26 12:21:12 +03:00

Handle heap rewrites better in logical replication

A FOR ALL TABLES publication naturally considers all base tables to be a
candidate for replication.  This includes transient heaps that are
created during a table rewrite during DDL.  This causes failures on the
subscriber side because it will not have a table like pg_temp_16386 to
receive data (and if it did, it would be the wrong table).

The prevent this problem, we filter out any tables that match this
naming pattern and match an actual table from FOR ALL TABLES
publications.  This is only a heuristic, meaning that user tables that
match that naming could accidentally be omitted.  A more robust solution
might require an explicit marking of such tables in pg_class somehow.

Reported-by: yxq <yxq@o2.pl>
Bug: #14785
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Petr Jelinek <petr.jelinek@2ndquadrant.com>
This commit is contained in:
Peter Eisentraut
2017-09-26 10:03:56 -04:00
parent 22c5e73562
commit ab28feae2b
2 changed files with 99 additions and 0 deletions

View File

@ -21,6 +21,7 @@
#include "utils/inval.h"
#include "utils/int8.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/varlena.h"
@ -509,6 +510,31 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
{
Publication *pub = lfirst(lc);
/*
* Skip tables that look like they are from a heap rewrite (see
* make_new_heap()). We need to skip them because the subscriber
* won't have a table by that name to receive the data. That
* means we won't ship the new data in, say, an added column with
* a DEFAULT, but if the user applies the same DDL manually on the
* subscriber, then this will work out for them.
*
* We only need to consider the alltables case, because such a
* transient heap won't be an explicit member of a publication.
*/
if (pub->alltables)
{
char *relname = get_rel_name(relid);
unsigned int u;
int n;
if (sscanf(relname, "pg_temp_%u%n", &u, &n) == 1 &&
relname[n] == '\0')
{
if (get_rel_relkind(u) == RELKIND_RELATION)
break;
}
}
if (pub->alltables || list_member_oid(pubids, pub->oid))
{
entry->pubactions.pubinsert |= pub->pubactions.pubinsert;