Re: Odd pg dump error: cache lookup failure

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Attachments.
>From 7d94ac6e86670e11fdde20cdf8cebb008bbf8901 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@xxxxxxxxxxxxxx>
Date: Tue, 7 Jul 2020 18:45:39 -0400
Subject: [PATCH v3 1/2] accept any relkind in LOCK TABLE

---
 doc/src/sgml/ref/lock.sgml      | 15 +++++++++------
 src/backend/commands/lockcmds.c | 18 ++++--------------
 2 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml
index 4cdfae2279..37881f25ac 100644
--- a/doc/src/sgml/ref/lock.sgml
+++ b/doc/src/sgml/ref/lock.sgml
@@ -16,7 +16,7 @@ PostgreSQL documentation
 
  <refnamediv>
   <refname>LOCK</refname>
-  <refpurpose>lock a table</refpurpose>
+  <refpurpose>lock a named relation (table, etc)</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
@@ -34,7 +34,9 @@ LOCK [ TABLE ] [ ONLY ] <replaceable class="parameter">name</replaceable> [ * ]
   <title>Description</title>
 
   <para>
-   <command>LOCK TABLE</command> obtains a table-level lock, waiting
+   <command>LOCK TABLE</command> obtains a table-level lock on a
+   relation (table, partitioned table, foreign table, view,
+   materialized view, index, composite type, sequence), waiting
    if necessary for any conflicting locks to be released.  If
    <literal>NOWAIT</literal> is specified, <command>LOCK
    TABLE</command> does not wait to acquire the desired lock: if it
@@ -115,17 +117,18 @@ LOCK [ TABLE ] [ ONLY ] <replaceable class="parameter">name</replaceable> [ * ]
     <term><replaceable class="parameter">name</replaceable></term>
     <listitem>
      <para>
-      The name (optionally schema-qualified) of an existing table to
-      lock. If <literal>ONLY</literal> is specified before the table name, only that
+      The name (optionally schema-qualified) of an existing relation to
+      lock. If <literal>ONLY</literal> is specified before a table name, only that
       table is locked. If <literal>ONLY</literal> is not specified, the table and all
       its descendant tables (if any) are locked.  Optionally, <literal>*</literal>
       can be specified after the table name to explicitly indicate that
-      descendant tables are included.
+      descendant tables are included.  When locking a view, all relations appearing
+      in the view definition are locked, regardless of <literal>ONLY</literal>.
      </para>
 
      <para>
       The command <literal>LOCK TABLE a, b;</literal> is equivalent to
-      <literal>LOCK TABLE a; LOCK TABLE b;</literal>. The tables are locked
+      <literal>LOCK TABLE a; LOCK TABLE b;</literal>. The relations are locked
       one-by-one in the order specified in the <command>LOCK
       TABLE</command> command.
      </para>
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index d8cafc42bb..215c1a2bd5 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -83,14 +83,6 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 		return;					/* woops, concurrently dropped; no permissions
 								 * check */
 
-	/* Currently, we only allow plain tables or views to be locked */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
-		relkind != RELKIND_VIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view",
-						rv->relname)));
-
 	/*
 	 * Make note if a temporary relation has been accessed in this
 	 * transaction.
@@ -187,11 +179,14 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
 		{
 			RangeTblEntry *rte = lfirst(rtable);
 			AclResult	aclresult;
-
 			Oid			relid = rte->relid;
 			char		relkind = rte->relkind;
 			char	   *relname = get_rel_name(relid);
 
+			/* ignore all non-relation RTEs */
+			if (rte->rtekind != RTE_RELATION)
+				continue;
+
 			/*
 			 * The OLD and NEW placeholder entries in the view's rtable are
 			 * skipped.
@@ -201,11 +196,6 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
 				 strcmp(rte->eref->aliasname, "new") == 0))
 				continue;
 
-			/* Currently, we only allow plain tables or views to be locked. */
-			if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
-				relkind != RELKIND_VIEW)
-				continue;
-
 			/* Check infinite recursion in the view definition. */
 			if (list_member_oid(context->ancestor_views, relid))
 				ereport(ERROR,
-- 
2.20.1

>From 7cd08ce21b4396165b3e878bb1d4009b1285a46b Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@xxxxxxxxxxxxxx>
Date: Tue, 7 Jul 2020 19:14:21 -0400
Subject: [PATCH v3 2/2] pg_dump: lock all rels, not just RELKIND_RELATION

---
 src/bin/pg_dump/pg_backup.h    |  2 ++
 src/bin/pg_dump/pg_backup_db.c | 64 ++++++++++++++++++++++++++++++++++
 src/bin/pg_dump/pg_backup_db.h |  2 ++
 src/bin/pg_dump/pg_dump.c      | 17 +++++----
 4 files changed, 78 insertions(+), 7 deletions(-)

diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
index a6a8e6f2fd..6c79319164 100644
--- a/src/bin/pg_dump/pg_backup.h
+++ b/src/bin/pg_dump/pg_backup.h
@@ -198,6 +198,8 @@ typedef struct Archive
 	int			minRemoteVersion;	/* allowable range */
 	int			maxRemoteVersion;
 
+	bool		hasGenericLockTable;	/* can LOCK TABLE do non-table rels */
+
 	int			numWorkers;		/* number of parallel processes */
 	char	   *sync_snapshot_id;	/* sync snapshot id for parallel operation */
 
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
index 5ba43441f5..28b2892538 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)
 {
diff --git a/src/bin/pg_dump/pg_backup_db.h b/src/bin/pg_dump/pg_backup_db.h
index 8888dd34b9..355beec1f7 100644
--- a/src/bin/pg_dump/pg_backup_db.h
+++ b/src/bin/pg_dump/pg_backup_db.h
@@ -20,6 +20,8 @@ extern PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, const char *query);
 
 extern void EndDBCopyMode(Archive *AHX, const char *tocEntryTag);
 
+extern bool IsLockTableGeneric(Archive *AHX);
+
 extern void StartTransaction(Archive *AHX);
 extern void CommitTransaction(Archive *AHX);
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index ff45e3fb8c..03f9d4d9e8 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -1176,6 +1176,9 @@ setup_connection(Archive *AH, const char *dumpencoding,
 			ExecuteSqlStatement(AH, "SET row_security = off");
 	}
 
+	/* Detect whether LOCK TABLE can handle non-table relations */
+	AH->hasGenericLockTable = IsLockTableGeneric(AH);
+
 	/*
 	 * Start transaction-snapshot mode transaction to dump consistent data.
 	 */
@@ -6843,16 +6846,16 @@ getTables(Archive *fout, int *numTables)
 		 * assume our lock on the child is enough to prevent schema
 		 * alterations to parent tables.
 		 *
-		 * NOTE: it'd be kinda nice to lock other relations too, not only
-		 * plain or partitioned tables, but the backend doesn't presently
-		 * allow that.
-		 *
-		 * We only need to lock the table for certain components; see
+		 * We only need to lock the relation for certain components; see
 		 * pg_dump.h
+		 *
+		 * On server versions that support it, we lock all relations not just
+		 * plain tables.
 		 */
 		if (tblinfo[i].dobj.dump &&
-			(tblinfo[i].relkind == RELKIND_RELATION ||
-			 tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
+			(fout->hasGenericLockTable ||
+			 tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE ||
+			 tblinfo[i].relkind == RELKIND_RELATION) &&
 			(tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
 		{
 			resetPQExpBuffer(query);
-- 
2.20.1


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux