summaryrefslogtreecommitdiff
path: root/src/bin/pg_dump/pg_backup_db.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2020-10-27 14:31:37 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2020-10-27 14:31:37 -0300
commit403a3d91c841beabf3efd7bffddb47a2bce4481f (patch)
treeec9fed8ddebae8efeabe9ba4e59a95989a95a0ca /src/bin/pg_dump/pg_backup_db.c
parentf893e68d761adbee7f888109b1adf76151e3e17a (diff)
pg_dump: Lock all relations, not just plain tables
Now that LOCK TABLE can take any relation type, acquire lock on all relations that are to be dumped. This prevents schema changes or deadlock errors that could cause a dump to fail after expending much effort. The server is tested to have the capability and the feature disabled if it doesn't, so that a patched pg_dump doesn't fail when connecting to an unpatched server. Backpatch to 9.5. Author: Álvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Reported-by: Wells Oliver <wells.oliver@gmail.com> Discussion: https://postgr.es/m/20201021200659.GA32358@alvherre.pgsql
Diffstat (limited to 'src/bin/pg_dump/pg_backup_db.c')
-rw-r--r--src/bin/pg_dump/pg_backup_db.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
index 5ba43441f50..28b2892538a 100644
--- a/src/bin/pg_dump/pg_backup_db.c
+++ b/src/bin/pg_dump/pg_backup_db.c
@@ -531,6 +531,70 @@ EndDBCopyMode(Archive *AHX, const char *tocEntryTag)
}
}
+/*
+ * Does LOCK TABLE work on non-table relations on this server?
+ *
+ * Note: assumes it is called out of any transaction
+ */
+bool
+IsLockTableGeneric(Archive *AHX)
+{
+ ArchiveHandle *AH = (ArchiveHandle *) AHX;
+ PGresult *res;
+ char *sqlstate;
+ bool retval;
+
+ if (AHX->remoteVersion >= 140000)
+ return true;
+ else if (AHX->remoteVersion < 90500)
+ return false;
+
+ StartTransaction(AHX);
+
+ /*
+ * Try a LOCK TABLE on a well-known non-table catalog; WRONG_OBJECT_TYPE
+ * tells us that this server doesn't support locking non-table rels, while
+ * LOCK_NOT_AVAILABLE and INSUFFICIENT_PRIVILEGE tell us that it does.
+ * Report anything else as a fatal problem.
+ */
+#define ERRCODE_INSUFFICIENT_PRIVILEGE "42501"
+#define ERRCODE_WRONG_OBJECT_TYPE "42809"
+#define ERRCODE_LOCK_NOT_AVAILABLE "55P03"
+ res = PQexec(AH->connection,
+ "LOCK TABLE pg_catalog.pg_class_tblspc_relfilenode_index IN ACCESS SHARE MODE NOWAIT");
+ switch (PQresultStatus(res))
+ {
+ case PGRES_COMMAND_OK:
+ retval = true;
+ break;
+ case PGRES_FATAL_ERROR:
+ sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+ if (strcmp(sqlstate, ERRCODE_WRONG_OBJECT_TYPE) == 0)
+ {
+ retval = false;
+ break;
+ }
+ else if (strcmp(sqlstate, ERRCODE_LOCK_NOT_AVAILABLE) == 0 ||
+ strcmp(sqlstate, ERRCODE_INSUFFICIENT_PRIVILEGE) == 0)
+ {
+ retval = true;
+ break;
+ }
+ /* else, falls through */
+ default:
+ warn_or_exit_horribly(AH, "LOCK TABLE failed for \"%s\": %s",
+ "pg_catalog.pg_class_tblspc_relfilenode_index",
+ PQerrorMessage(AH->connection));
+ retval = false; /* not reached */
+ break;
+ }
+ PQclear(res);
+
+ CommitTransaction(AHX);
+
+ return retval;
+}
+
void
StartTransaction(Archive *AHX)
{