pg_dump: fix mis-dumping of non-global default privileges.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 22 Oct 2021 19:22:25 +0000 (15:22 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 22 Oct 2021 19:22:25 +0000 (15:22 -0400)
Non-global default privilege entries should be dumped as-is,
not made relative to the default ACL for their object type.
This would typically only matter if one had revoked some
on-by-default privileges in a global entry, and then wanted
to grant them again in a non-global entry.

Per report from Boris Korzun.  This is an old bug, so back-patch
to all supported branches.

Neil Chen, test case by Masahiko Sawada

Discussion: https://postgr.es/m/111621616618184@mail.yandex.ru
Discussion: https://postgr.es/m/CAA3qoJnr2+1dVJObNtfec=qW4Z0nz=A9+r5bZKoTSy5RDjskMw@mail.gmail.com

src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/t/002_pg_dump.pl

index ed8ed2f266e18d002742724e3e6cc51dbbcef799..52f1a3acb31804907b94b5f674a8464cb3e73ec5 100644 (file)
@@ -9562,10 +9562,27 @@ getDefaultACLs(Archive *fout, int *numDefaultACLs)
        PQExpBuffer initacl_subquery = createPQExpBuffer();
        PQExpBuffer initracl_subquery = createPQExpBuffer();
 
+       /*
+        * Global entries (with defaclnamespace=0) replace the hard-wired
+        * default ACL for their object type.  We should dump them as deltas
+        * from the default ACL, since that will be used as a starting point
+        * for interpreting the ALTER DEFAULT PRIVILEGES commands.  On the
+        * other hand, non-global entries can only add privileges not revoke
+        * them.  We must dump those as-is (i.e., as deltas from an empty
+        * ACL).  We implement that by passing NULL as the object type for
+        * acldefault(), which works because acldefault() is STRICT.
+        *
+        * We can use defaclobjtype as the object type for acldefault(),
+        * except for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be
+        * converted to 's'.
+        */
        buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
                        initracl_subquery, "defaclacl", "defaclrole",
                        "pip.initprivs",
-                       "CASE WHEN defaclobjtype = 'S' THEN 's' ELSE defaclobjtype END::\"char\"",
+                       "CASE WHEN defaclnamespace = 0 THEN"
+                       "     CASE WHEN defaclobjtype = 'S' THEN 's'::\"char\""
+                       "     ELSE defaclobjtype END "
+                       "ELSE NULL END",
                        dopt->binary_upgrade);
 
        appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
index c61d95e81746732096a9c1c6c64478acefd0b524..7e00f4ddbb1b5e000d96665f771148242046cb9a 100644 (file)
@@ -443,6 +443,25 @@ my %tests = (
        },
    },
 
+   'ALTER DEFAULT PRIVILEGES FOR ROLE regress_dump_test_role GRANT EXECUTE ON FUNCTIONS'
+     => {
+       create_order => 15,
+       create_sql   => 'ALTER DEFAULT PRIVILEGES
+                      FOR ROLE regress_dump_test_role IN SCHEMA dump_test
+                      GRANT EXECUTE ON FUNCTIONS TO regress_dump_test_role;',
+       regexp => qr/^
+           \QALTER DEFAULT PRIVILEGES \E
+           \QFOR ROLE regress_dump_test_role IN SCHEMA dump_test \E
+           \QGRANT ALL ON FUNCTIONS  TO regress_dump_test_role;\E
+           /xm,
+       like =>
+         { %full_runs, %dump_test_schema_runs, section_post_data => 1, },
+       unlike => {
+           exclude_dump_test_schema => 1,
+           no_privs                 => 1,
+       },
+     },
+
    'ALTER DEFAULT PRIVILEGES FOR ROLE regress_dump_test_role REVOKE' => {
        create_order => 55,
        create_sql   => 'ALTER DEFAULT PRIVILEGES