aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_dump/pg_backup_archiver.c
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2024-04-22 15:15:36 +0900
committerMichael Paquier <michael@paquier.xyz>2024-04-22 15:15:36 +0900
commitf46bee346c3b6aab0a0f3f39dc734732b79ce1ed (patch)
treea30708c5105cd1ebc75203f46ad5d9a9d34942ff /src/bin/pg_dump/pg_backup_archiver.c
parenteff6a757fde3ba072a03dd06edc2eafeac5e602d (diff)
downloadpostgresql-f46bee346c3b6aab0a0f3f39dc734732b79ce1ed.tar.gz
postgresql-f46bee346c3b6aab0a0f3f39dc734732b79ce1ed.zip
Fix dumps of partitioned tables with table AMs
pg_dump/restore failed to properly set the table access method for partitioned tables, as it relies on SET queries that would change default_table_access_method. However, SET affects only tables and materialized views, not partitioned tables which would always be restored with their pg_class.relam set to 0, losing their table AM set by either a CREATE TABLE .. USING or by a ALTER TABLE .. SET ACCESS METHOD. Appending a USING clause to the definition of CREATE TABLE is not possible as users may specify --no-table-access-method at restore or for a dump, meaning that the table AM portions may have to be skipped. Rather than SET, the solution used by this commit is to generate an extra ALTER TABLE .. SET ACCESS METHOD when restoring a partitioned table, based on the table AM set in its TOC entry. The choice of using a SET query or an ALTER TABLE query for a relation requires the addition of the relkind to the TOC entry to be able to choose between one or the other. Note that using ALTER TABLE SET ACCESS METHOD on a relation with physical storage would require a full rewrite, which would be costly for one. This also creates problems with binary upgrades where the rewrite would not be able to keep the OID of the relation consistent across the upgrade. This commit would normally require a protocol bump, but a45c78e3284b has already done one for this release cycle. Regression tests are adjusted with the new expected output, with some tweaks for the table AMs of the partitions to make the output more readable. Issue introduced by 374c7a229042, that has added support for table AMs in partitioned tables. Author: Michael Paquier Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/Zh4JLSvvtQgBJZkZ@paquier.xyz
Diffstat (limited to 'src/bin/pg_dump/pg_backup_archiver.c')
-rw-r--r--src/bin/pg_dump/pg_backup_archiver.c70
1 files changed, 68 insertions, 2 deletions
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index c7a6c918a65..c6c101c118b 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -30,6 +30,7 @@
#include <io.h>
#endif
+#include "catalog/pg_class_d.h"
#include "common/string.h"
#include "compress_io.h"
#include "dumputils.h"
@@ -62,6 +63,8 @@ static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
static void _selectTableAccessMethod(ArchiveHandle *AH, const char *tableam);
+static void _printTableAccessMethodNoStorage(ArchiveHandle *AH,
+ TocEntry *te);
static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
static void processSearchPathEntry(ArchiveHandle *AH, TocEntry *te);
@@ -1222,6 +1225,7 @@ ArchiveEntry(Archive *AHX, CatalogId catalogId, DumpId dumpId,
newToc->namespace = opts->namespace ? pg_strdup(opts->namespace) : NULL;
newToc->tablespace = opts->tablespace ? pg_strdup(opts->tablespace) : NULL;
newToc->tableam = opts->tableam ? pg_strdup(opts->tableam) : NULL;
+ newToc->relkind = opts->relkind;
newToc->owner = opts->owner ? pg_strdup(opts->owner) : NULL;
newToc->desc = pg_strdup(opts->description);
newToc->defn = opts->createStmt ? pg_strdup(opts->createStmt) : NULL;
@@ -2602,6 +2606,7 @@ WriteToc(ArchiveHandle *AH)
WriteStr(AH, te->namespace);
WriteStr(AH, te->tablespace);
WriteStr(AH, te->tableam);
+ WriteInt(AH, te->relkind);
WriteStr(AH, te->owner);
WriteStr(AH, "false");
@@ -2707,6 +2712,9 @@ ReadToc(ArchiveHandle *AH)
if (AH->version >= K_VERS_1_14)
te->tableam = ReadStr(AH);
+ if (AH->version >= K_VERS_1_16)
+ te->relkind = ReadInt(AH);
+
te->owner = ReadStr(AH);
is_supported = true;
if (AH->version < K_VERS_1_9)
@@ -3568,6 +3576,51 @@ _selectTableAccessMethod(ArchiveHandle *AH, const char *tableam)
}
/*
+ * Set the proper default table access method for a table without storage.
+ * Currently, this is required only for partitioned tables with a table AM.
+ */
+static void
+_printTableAccessMethodNoStorage(ArchiveHandle *AH, TocEntry *te)
+{
+ RestoreOptions *ropt = AH->public.ropt;
+ const char *tableam = te->tableam;
+ PQExpBuffer cmd;
+
+ /* do nothing in --no-table-access-method mode */
+ if (ropt->noTableAm)
+ return;
+
+ if (!tableam)
+ return;
+
+ Assert(te->relkind == RELKIND_PARTITIONED_TABLE);
+
+ cmd = createPQExpBuffer();
+
+ appendPQExpBufferStr(cmd, "ALTER TABLE ");
+ appendPQExpBuffer(cmd, "%s ", fmtQualifiedId(te->namespace, te->tag));
+ appendPQExpBuffer(cmd, "SET ACCESS METHOD %s;",
+ fmtId(tableam));
+
+ if (RestoringToDB(AH))
+ {
+ PGresult *res;
+
+ res = PQexec(AH->connection, cmd->data);
+
+ if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
+ warn_or_exit_horribly(AH,
+ "could not alter table access method: %s",
+ PQerrorMessage(AH->connection));
+ PQclear(res);
+ }
+ else
+ ahprintf(AH, "%s\n\n", cmd->data);
+
+ destroyPQExpBuffer(cmd);
+}
+
+/*
* Extract an object description for a TOC entry, and append it to buf.
*
* This is used for ALTER ... OWNER TO.
@@ -3673,11 +3726,17 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
{
RestoreOptions *ropt = AH->public.ropt;
- /* Select owner, schema, tablespace and default AM as necessary */
+ /*
+ * Select owner, schema, tablespace and default AM as necessary. The
+ * default access method for partitioned tables is handled after
+ * generating the object definition, as it requires an ALTER command
+ * rather than SET.
+ */
_becomeOwner(AH, te);
_selectOutputSchema(AH, te->namespace);
_selectTablespace(AH, te->tablespace);
- _selectTableAccessMethod(AH, te->tableam);
+ if (te->relkind != RELKIND_PARTITIONED_TABLE)
+ _selectTableAccessMethod(AH, te->tableam);
/* Emit header comment for item */
if (!AH->noTocComments)
@@ -3813,6 +3872,13 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
}
/*
+ * Select a partitioned table's default AM, once the table definition has
+ * been generated.
+ */
+ if (te->relkind == RELKIND_PARTITIONED_TABLE)
+ _printTableAccessMethodNoStorage(AH, te);
+
+ /*
* If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
* commands, so we can no longer assume we know the current auth setting.
*/