Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d31bbfb

Browse files
committed
Proper object locking for GRANT/REVOKE
Refactor objectNamesToOids() to use get_object_address() internally if possible. Not only does this save a lot of code, it also allows us to use the object locking provided by get_object_address() for GRANT/REVOKE. There was previously a code comment that complained about the lack of locking in objectNamesToOids(), which is now fixed. The check in ExecGrant_Type_check() is obsolete because get_object_address_type() already does the same check. Reviewed-by: Bertrand Drouvot <[email protected]> Discussion: https://www.postgresql.org/message-id/flat/[email protected]
1 parent cfd7f36 commit d31bbfb

File tree

2 files changed

+39
-120
lines changed

2 files changed

+39
-120
lines changed

src/backend/catalog/aclchk.c

+38-119
Original file line numberDiff line numberDiff line change
@@ -659,147 +659,77 @@ ExecGrantStmt_oids(InternalGrant *istmt)
659659
* objectNamesToOids
660660
*
661661
* Turn a list of object names of a given type into an Oid list.
662-
*
663-
* XXX: This function doesn't take any sort of locks on the objects whose
664-
* names it looks up. In the face of concurrent DDL, we might easily latch
665-
* onto an old version of an object, causing the GRANT or REVOKE statement
666-
* to fail.
667662
*/
668663
static List *
669664
objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
670665
{
671666
List *objects = NIL;
672667
ListCell *cell;
668+
const LOCKMODE lockmode = AccessShareLock;
673669

674670
Assert(objnames != NIL);
675671

676672
switch (objtype)
677673
{
678-
case OBJECT_TABLE:
679-
case OBJECT_SEQUENCE:
680-
foreach(cell, objnames)
681-
{
682-
RangeVar *relvar = (RangeVar *) lfirst(cell);
683-
Oid relOid;
684-
685-
relOid = RangeVarGetRelid(relvar, NoLock, false);
686-
objects = lappend_oid(objects, relOid);
687-
}
688-
break;
689-
case OBJECT_DATABASE:
690-
foreach(cell, objnames)
691-
{
692-
char *dbname = strVal(lfirst(cell));
693-
Oid dbid;
694-
695-
dbid = get_database_oid(dbname, false);
696-
objects = lappend_oid(objects, dbid);
697-
}
698-
break;
699-
case OBJECT_DOMAIN:
700-
case OBJECT_TYPE:
701-
foreach(cell, objnames)
702-
{
703-
List *typname = (List *) lfirst(cell);
704-
Oid oid;
705-
706-
oid = typenameTypeId(NULL, makeTypeNameFromNameList(typname));
707-
objects = lappend_oid(objects, oid);
708-
}
709-
break;
710-
case OBJECT_FUNCTION:
711-
foreach(cell, objnames)
712-
{
713-
ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
714-
Oid funcid;
674+
default:
715675

716-
funcid = LookupFuncWithArgs(OBJECT_FUNCTION, func, false);
717-
objects = lappend_oid(objects, funcid);
718-
}
719-
break;
720-
case OBJECT_LANGUAGE:
676+
/*
677+
* For most object types, we use get_object_address() directly.
678+
*/
721679
foreach(cell, objnames)
722680
{
723-
char *langname = strVal(lfirst(cell));
724-
Oid oid;
681+
ObjectAddress address;
725682

726-
oid = get_language_oid(langname, false);
727-
objects = lappend_oid(objects, oid);
683+
address = get_object_address(objtype, lfirst(cell), NULL, lockmode, false);
684+
objects = lappend_oid(objects, address.objectId);
728685
}
729686
break;
730-
case OBJECT_LARGEOBJECT:
731-
foreach(cell, objnames)
732-
{
733-
Oid lobjOid = oidparse(lfirst(cell));
734687

735-
if (!LargeObjectExists(lobjOid))
736-
ereport(ERROR,
737-
(errcode(ERRCODE_UNDEFINED_OBJECT),
738-
errmsg("large object %u does not exist",
739-
lobjOid)));
740-
741-
objects = lappend_oid(objects, lobjOid);
742-
}
743-
break;
744-
case OBJECT_SCHEMA:
745-
foreach(cell, objnames)
746-
{
747-
char *nspname = strVal(lfirst(cell));
748-
Oid oid;
688+
case OBJECT_TABLE:
689+
case OBJECT_SEQUENCE:
749690

750-
oid = get_namespace_oid(nspname, false);
751-
objects = lappend_oid(objects, oid);
752-
}
753-
break;
754-
case OBJECT_PROCEDURE:
691+
/*
692+
* Here, we don't use get_object_address(). It requires that the
693+
* specified object type match the actual type of the object, but
694+
* in GRANT/REVOKE, all table-like things are addressed as TABLE.
695+
*/
755696
foreach(cell, objnames)
756697
{
757-
ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
758-
Oid procid;
698+
RangeVar *relvar = (RangeVar *) lfirst(cell);
699+
Oid relOid;
759700

760-
procid = LookupFuncWithArgs(OBJECT_PROCEDURE, func, false);
761-
objects = lappend_oid(objects, procid);
701+
relOid = RangeVarGetRelid(relvar, lockmode, false);
702+
objects = lappend_oid(objects, relOid);
762703
}
763704
break;
764-
case OBJECT_ROUTINE:
765-
foreach(cell, objnames)
766-
{
767-
ObjectWithArgs *func = (ObjectWithArgs *) lfirst(cell);
768-
Oid routid;
769705

770-
routid = LookupFuncWithArgs(OBJECT_ROUTINE, func, false);
771-
objects = lappend_oid(objects, routid);
772-
}
773-
break;
774-
case OBJECT_TABLESPACE:
775-
foreach(cell, objnames)
776-
{
777-
char *spcname = strVal(lfirst(cell));
778-
Oid spcoid;
706+
case OBJECT_DOMAIN:
707+
case OBJECT_TYPE:
779708

780-
spcoid = get_tablespace_oid(spcname, false);
781-
objects = lappend_oid(objects, spcoid);
782-
}
783-
break;
784-
case OBJECT_FDW:
709+
/*
710+
* The parse representation of types and domains in privilege
711+
* targets is different from that expected by get_object_address()
712+
* (for parse conflict reasons), so we have to do a bit of
713+
* conversion here.
714+
*/
785715
foreach(cell, objnames)
786716
{
787-
char *fdwname = strVal(lfirst(cell));
788-
Oid fdwid = get_foreign_data_wrapper_oid(fdwname, false);
717+
List *typname = (List *) lfirst(cell);
718+
TypeName *tn = makeTypeNameFromNameList(typname);
719+
ObjectAddress address;
720+
Relation relation;
789721

790-
objects = lappend_oid(objects, fdwid);
722+
address = get_object_address(objtype, (Node *) tn, &relation, lockmode, false);
723+
Assert(relation == NULL);
724+
objects = lappend_oid(objects, address.objectId);
791725
}
792726
break;
793-
case OBJECT_FOREIGN_SERVER:
794-
foreach(cell, objnames)
795-
{
796-
char *srvname = strVal(lfirst(cell));
797-
Oid srvid = get_foreign_server_oid(srvname, false);
798727

799-
objects = lappend_oid(objects, srvid);
800-
}
801-
break;
802728
case OBJECT_PARAMETER_ACL:
729+
730+
/*
731+
* Parameters are handled completely differently.
732+
*/
803733
foreach(cell, objnames)
804734
{
805735
/*
@@ -830,9 +760,6 @@ objectNamesToOids(ObjectType objtype, List *objnames, bool is_grant)
830760
objects = lappend_oid(objects, parameterId);
831761
}
832762
break;
833-
default:
834-
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
835-
(int) objtype);
836763
}
837764

838765
return objects;
@@ -2458,14 +2385,6 @@ ExecGrant_Type_check(InternalGrant *istmt, HeapTuple tuple)
24582385
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
24592386
errmsg("cannot set privileges of multirange types"),
24602387
errhint("Set the privileges of the range type instead.")));
2461-
2462-
/* Used GRANT DOMAIN on a non-domain? */
2463-
if (istmt->objtype == OBJECT_DOMAIN &&
2464-
pg_type_tuple->typtype != TYPTYPE_DOMAIN)
2465-
ereport(ERROR,
2466-
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
2467-
errmsg("\"%s\" is not a domain",
2468-
NameStr(pg_type_tuple->typname))));
24692388
}
24702389

24712390
static void

src/test/isolation/expected/intra-grant-inplace.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,6 @@ relhasindex
248248
-----------
249249
(0 rows)
250250

251-
s4: WARNING: got: cache lookup failed for relation REDACTED
251+
s4: WARNING: got: relation "intra_grant_inplace" does not exist
252252
step revoke4: <... completed>
253253
step r3: ROLLBACK;

0 commit comments

Comments
 (0)