From 86517f376339a65fcf432caa21dbc68d8c2a93a4 Mon Sep 17 00:00:00 2001 From: Jacob Champion Date: Thu, 16 Mar 2023 11:46:08 -0700 Subject: [PATCH] pg_dump: skip lock for extension tables without policies If a user without SELECT permissions on an internal extension table tries to dump the extension, the dump will fail while trying to lock the table with ACCESS SHARE, even though the user doesn't want or need to dump the table in question. (The lock is taken to allow later pg_get_expr() calls on pg_policy to remain consistent in the face of concurrent schema changes.) It'd be ideal not to require SELECT permissions on a table to be able to dump its policies, but I don't have a great idea for how to implement that without races. As a workaround, skip the policy queries entirely if we determine that no policies exist for a table at the time of getTables(). --- src/bin/pg_dump/pg_dump.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 2e068c6620..49f01247c1 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -6317,6 +6317,7 @@ getTables(Archive *fout, int *numTables) int i_relacl; int i_acldefault; int i_ispartition; + int i_has_policies; /* * Find all the tables and table-like objects. @@ -6358,6 +6359,13 @@ getTables(Archive *fout, int *numTables) "d.refobjsubid AS owning_col, " "tsp.spcname AS reltablespace, "); + if (fout->remoteVersion >= 90500) + appendPQExpBufferStr(query, + "EXISTS (SELECT 1 FROM pg_policy WHERE polrelid = c.oid) AS has_policies, "); + else + appendPQExpBufferStr(query, + "false AS has_policies, "); + if (fout->remoteVersion >= 120000) appendPQExpBufferStr(query, "false AS relhasoids, "); @@ -6531,6 +6539,7 @@ getTables(Archive *fout, int *numTables) i_relacl = PQfnumber(res, "relacl"); i_acldefault = PQfnumber(res, "acldefault"); i_ispartition = PQfnumber(res, "ispartition"); + i_has_policies = PQfnumber(res, "has_policies"); if (dopt->lockWaitTimeout) { @@ -6621,6 +6630,17 @@ getTables(Archive *fout, int *numTables) else selectDumpableTable(&tblinfo[i], fout); + /* + * If the table has no policies, we don't need to worry about those. + * + * For tables internal to an extension, this may mean we don't need to + * take an ACCESS SHARE lock, which in turn allows less privileged users + * to successfully perform a dump if they don't have SELECT access to + * those tables (which they weren't trying to dump in the first place). + */ + if (strcmp(PQgetvalue(res, i, i_has_policies), "f") == 0) + tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_POLICY; + /* * Now, consider the table "interesting" if we need to dump its * definition or its data. Later on, we'll skip a lot of data -- 2.25.1