aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_dump/pg_backup_archiver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pg_dump/pg_backup_archiver.c')
-rw-r--r--src/bin/pg_dump/pg_backup_archiver.c73
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;
/*