diff options
Diffstat (limited to 'src/bin/pg_dump/pg_backup_archiver.c')
-rw-r--r-- | src/bin/pg_dump/pg_backup_archiver.c | 73 |
1 files changed, 64 insertions, 9 deletions
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 63df3e56e74..485ad49cf49 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -90,6 +90,7 @@ static RestorePass _tocEntryRestorePass(TocEntry *te); static bool _tocEntryIsACL(TocEntry *te); static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te); static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te); +static bool is_load_via_partition_root(TocEntry *te); static void buildTocEntryArrays(ArchiveHandle *AH); static void _moveBefore(ArchiveHandle *AH, TocEntry *pos, TocEntry *te); static int _discoverArchiveFormat(ArchiveHandle *AH); @@ -878,6 +879,8 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel) } else { + bool use_truncate; + _disableTriggersIfNecessary(AH, te); /* Select owner and schema as necessary */ @@ -889,13 +892,24 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel) /* * In parallel restore, if we created the table earlier in - * the run then we wrap the COPY in a transaction and - * precede it with a TRUNCATE. If archiving is not on - * this prevents WAL-logging the COPY. This obtains a - * speedup similar to that from using single_txn mode in - * non-parallel restores. + * this run (so that we know it is empty) and we are not + * restoring a load-via-partition-root data item then we + * wrap the COPY in a transaction and precede it with a + * TRUNCATE. If wal_level is set to minimal this prevents + * WAL-logging the COPY. This obtains a speedup similar + * to that from using single_txn mode in non-parallel + * restores. + * + * We mustn't do this for load-via-partition-root cases + * because some data might get moved across partition + * boundaries, risking deadlock and/or loss of previously + * loaded data. (We assume that all partitions of a + * partitioned table will be treated the same way.) */ - if (is_parallel && te->created) + use_truncate = is_parallel && te->created && + !is_load_via_partition_root(te); + + if (use_truncate) { /* * Parallel restore is always talking directly to a @@ -936,7 +950,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel) AH->outputKind = OUTPUT_SQLCMDS; /* close out the transaction started above */ - if (is_parallel && te->created) + if (use_truncate) CommitTransaction(&AH->public); _enableTriggersIfNecessary(AH, te); @@ -1029,6 +1043,43 @@ _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te) } /* + * Detect whether a TABLE DATA TOC item is performing "load via partition + * root", that is the target table is an ancestor partition rather than the + * table the TOC item is nominally for. + * + * In newer archive files this can be detected by checking for a special + * comment placed in te->defn. In older files we have to fall back to seeing + * if the COPY statement targets the named table or some other one. This + * will not work for data dumped as INSERT commands, so we could give a false + * negative in that case; fortunately, that's a rarely-used option. + */ +static bool +is_load_via_partition_root(TocEntry *te) +{ + if (te->defn && + strncmp(te->defn, "-- load via partition root ", 27) == 0) + return true; + if (te->copyStmt && *te->copyStmt) + { + PQExpBuffer copyStmt = createPQExpBuffer(); + bool result; + + /* + * Build the initial part of the COPY as it would appear if the + * nominal target table is the actual target. If we see anything + * else, it must be a load-via-partition-root case. + */ + appendPQExpBuffer(copyStmt, "COPY %s ", + fmtQualifiedId(te->namespace, te->tag)); + result = strncmp(te->copyStmt, copyStmt->data, copyStmt->len) != 0; + destroyPQExpBuffer(copyStmt); + return result; + } + /* Assume it's not load-via-partition-root */ + return false; +} + +/* * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter. */ @@ -2965,8 +3016,12 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH) res = res & ~REQ_DATA; } - /* If there's no definition command, there's no schema component */ - if (!te->defn || !te->defn[0]) + /* + * If there's no definition command, there's no schema component. Treat + * "load via partition root" comments as not schema. + */ + if (!te->defn || !te->defn[0] || + strncmp(te->defn, "-- load via partition root ", 27) == 0) res = res & ~REQ_SCHEMA; /* |