]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix pg_dump ACL minimization for PROPERTY GRAPH.
authorNoah Misch <noah@leadboat.com>
Tue, 7 Jul 2026 16:51:04 +0000 (09:51 -0700)
committerNoah Misch <noah@leadboat.com>
Tue, 7 Jul 2026 16:51:04 +0000 (09:51 -0700)
Adding a GRANT caused pg_dump to emit a useless REVOKE + GRANT of owner
privileges, as seen in a dump of the regression database:

  REVOKE ALL ON PROPERTY GRAPH graph_rls_schema.cabinet FROM nm;
  GRANT ALL ON PROPERTY GRAPH graph_rls_schema.cabinet TO nm;
  GRANT ALL ON PROPERTY GRAPH graph_rls_schema.cabinet TO PUBLIC;

For normal dumps, this has no functional consequences.  For --no-owner
restores, the extra statements may fail or locate unrelated users of the
destination cluster.

The problem was pg_dump assuming NULL relacl implies acldefault('r'),
the default for TABLE.  Fix by teaching acldefault() to retrieve the
PROPERTY GRAPH default ACL.  So pg_dump can still dump from 19beta1, use
acldefault('g') for v20+ only.  For v19, use a hard-coded snapshot of
the v19 default.

information_schema.pg_property_graph_privileges also misused
acldefault('r'), but its "c.prtype IN ('SELECT')" predicate compensated
for it.  Switch to the new acldefault('g') for clarity.  Bump catversion
since a new view won't work with old binaries.  Back-patch to v19, which
introduced PROPERTY GRAPH.

Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Robert Haas <robertmhaas@gmail.com>
Discussion: https://postgr.es/m/20260630023308.c7.noahmisch@microsoft.com
Backpatch-through: 19

src/backend/catalog/information_schema.sql
src/backend/utils/adt/acl.c
src/bin/pg_dump/pg_dump.c
src/include/catalog/catversion.h

index 4f0e2492937743df45955676cd3022688c95bc3b..624d538a5c063aae6d5e9582cb119b7179175fbf 100644 (file)
@@ -3328,7 +3328,7 @@ CREATE VIEW pg_property_graph_privileges AS
                   THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
 
     FROM (
-            SELECT oid, relname, relnamespace, relkind, relowner, (aclexplode(coalesce(relacl, acldefault('r', relowner)))).* FROM pg_class
+            SELECT oid, relname, relnamespace, relkind, relowner, (aclexplode(coalesce(relacl, acldefault('g', relowner)))).* FROM pg_class
          ) AS c (oid, relname, relnamespace, relkind, relowner, grantor, grantee, prtype, grantable),
          pg_namespace nc,
          pg_authid u_grantor,
index 01caa12eca7055f08d9ba764d36284ff8adbe4f4..e2547d719eddd1f12120e8cfe818faef074bdc0e 100644 (file)
@@ -956,6 +956,9 @@ acldefault_sql(PG_FUNCTION_ARGS)
                case 'c':
                        objtype = OBJECT_COLUMN;
                        break;
+               case 'g':
+                       objtype = OBJECT_PROPGRAPH;
+                       break;
                case 'r':
                        objtype = OBJECT_TABLE;
                        break;
index f67daf8591159a7c6110bc9dddc6e4d7bf052a41..4d660d14b4ce10676c8ca30e69832bc2d61df1d8 100644 (file)
@@ -7231,8 +7231,17 @@ getTables(Archive *fout, int *numTables)
                                                 "c.relhastriggers, c.relpersistence, "
                                                 "c.reloftype, "
                                                 "c.relacl, "
-                                                "acldefault(CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
-                                                " THEN 's'::\"char\" ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
+                                                "acldefault(CASE"
+                                                " WHEN c.relkind = " CppAsString2(RELKIND_PROPGRAPH));
+       /* 19beta1 didn't support acldefault('g'), so we'll fix that below */
+       appendPQExpBufferStr(query,
+                                                fout->remoteVersion >= 200000 ?
+                                                " THEN 'g'::\"char\"" :
+                                                " THEN NULL");
+       appendPQExpBufferStr(query,
+                                                " WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
+                                                " THEN 's'::\"char\""
+                                                " ELSE 'r'::\"char\" END, c.relowner) AS acldefault, "
                                                 "CASE WHEN c.relkind = " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN "
                                                 "(SELECT ftserver FROM pg_catalog.pg_foreign_table WHERE ftrelid = c.oid) "
                                                 "ELSE 0 END AS foreignserver, "
@@ -7418,7 +7427,7 @@ getTables(Archive *fout, int *numTables)
                tblinfo[i].dobj.namespace =
                        findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)));
                tblinfo[i].dacl.acl = pg_strdup(PQgetvalue(res, i, i_relacl));
-               tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+               /* acldefault computed below */
                tblinfo[i].dacl.privtype = 0;
                tblinfo[i].dacl.initprivs = NULL;
                tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
@@ -7470,6 +7479,28 @@ getTables(Archive *fout, int *numTables)
                tblinfo[i].is_identity_sequence = (strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
                tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
 
+               if (tblinfo[i].relkind == RELKIND_PROPGRAPH &&
+                       !(fout->remoteVersion >= 200000))
+               {
+                       PQExpBuffer aclarray = createPQExpBuffer();
+                       PQExpBuffer aclitem = createPQExpBuffer();
+
+                       /* Standard ACL as of v19 is {owner=r/owner} */
+                       appendPQExpBufferChar(aclarray, '{');
+                       quoteAclUserName(aclitem, tblinfo[i].rolname);
+                       appendPQExpBufferStr(aclitem, "=r/");
+                       quoteAclUserName(aclitem, tblinfo[i].rolname);
+                       appendPGArray(aclarray, aclitem->data);
+                       appendPQExpBufferChar(aclarray, '}');
+
+                       tblinfo[i].dacl.acldefault = pstrdup(aclarray->data);
+
+                       destroyPQExpBuffer(aclarray);
+                       destroyPQExpBuffer(aclitem);
+               }
+               else
+                       tblinfo[i].dacl.acldefault = pg_strdup(PQgetvalue(res, i, i_acldefault));
+
                /* other fields were zeroed above */
 
                /*
index 73ed6a0fa4b98115237c9064de949006be9c837e..be36ca979037f832145731d1a97100470c1f82ff 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     202607022
+#define CATALOG_VERSION_NO     202607072
 
 #endif