postgres.git / summary / log / commit / refs

commit    6df3be415cdb7c6ae350eadbae2f8ea7a0fcf4be
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Fri Feb 21 18:37:12 2025 +0000

    Fix pg_dumpall to cope with dangling OIDs in pg_auth_members.
    
    There is a race condition between "GRANT role" and "DROP ROLE",
    which allows GRANT to install pg_auth_members entries that refer to
    dropped roles.  (Commit 6566133c5 prevented that for the grantor
    field, but not for the granted or grantee roles.)  We'll soon fix
    that, at least in HEAD, but pg_dumpall needs to cope with the
    situation in case of pre-existing inconsistency.  As pg_dumpall
    stands, it will emit invalid commands like 'GRANT foo TO ""',
    which causes pg_upgrade to fail.  Fix it to emit warnings and skip
    those GRANTs, instead.
    
    There was some discussion of removing the problem by changing
    dumpRoleMembership's query to use JOIN not LEFT JOIN, but that
    would result in silently ignoring such entries.  It seems better
    to produce a warning.
    
    Pre-v16 branches already coped with dangling grantor OIDs by simply
    omitting the GRANTED BY clause.  I left that behavior as-is, although
    it's somewhat inconsistent with the behavior of later branches.
    
    Reported-by: Virender Singla <virender.cse@gmail.com>
    Discussion: https://postgr.es/m/CAM6Zo8woa62ZFHtMKox6a4jb8qQ=w87R2L0K8347iE-juQL2EA@mail.gmail.com
    Backpatch-through: 13


src/bin/pg_dump/pg_dumpall.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 623cc6c1a90..eec820de49e 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -931,10 +931,12 @@ dumpRoleMembership(PGconn *conn) PGresult *res; int i; - printfPQExpBuffer(buf, "SELECT ur.rolname AS roleid, " + printfPQExpBuffer(buf, "SELECT ur.rolname AS role, " "um.rolname AS member, " "a.admin_option, " - "ug.rolname AS grantor " + "ug.rolname AS grantor, " + "a.roleid AS roleid, " + "a.member AS memberid " "FROM pg_auth_members a " "LEFT JOIN %s ur on ur.oid = a.roleid " "LEFT JOIN %s um on um.oid = a.member " @@ -948,13 +950,33 @@ dumpRoleMembership(PGconn *conn) for (i = 0; i < PQntuples(res); i++) { - char *roleid = PQgetvalue(res, i, 0); + char *role = PQgetvalue(res, i, 0); char *member = PQgetvalue(res, i, 1); - char *option = PQgetvalue(res, i, 2); + char *admin_option = PQgetvalue(res, i, 2); - fprintf(OPF, "GRANT %s", fmtId(roleid)); + /* + * Due to race conditions, the role and/or member could have been + * dropped. If we find such cases, print a warning and skip the + * entry. + */ + if (PQgetisnull(res, i, 0)) + { + /* translator: %s represents a numeric role OID */ + pg_log_warning("found orphaned pg_auth_members entry for role %s", + PQgetvalue(res, i, 4)); + continue; + } + if (PQgetisnull(res, i, 1)) + { + /* translator: %s represents a numeric role OID */ + pg_log_warning("found orphaned pg_auth_members entry for role %s", + PQgetvalue(res, i, 5)); + continue; + } + + fprintf(OPF, "GRANT %s", fmtId(role)); fprintf(OPF, " TO %s", fmtId(member)); - if (*option == 't') + if (*admin_option == 't') fprintf(OPF, " WITH ADMIN OPTION"); /* [parent: a5618e40217d]