1 /*-------------------------------------------------------------------------
4 * Routines to check access control permissions.
6 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/aclchk.c
16 *-------------------------------------------------------------------------
20 #include "access/genam.h"
21 #include "access/heapam.h"
22 #include "access/htup_details.h"
23 #include "access/sysattr.h"
24 #include "access/tableam.h"
25 #include "access/xact.h"
26 #include "catalog/binary_upgrade.h"
27 #include "catalog/catalog.h"
28 #include "catalog/dependency.h"
29 #include "catalog/indexing.h"
30 #include "catalog/objectaccess.h"
31 #include "catalog/pg_aggregate.h"
32 #include "catalog/pg_am.h"
33 #include "catalog/pg_authid.h"
34 #include "catalog/pg_cast.h"
35 #include "catalog/pg_collation.h"
36 #include "catalog/pg_conversion.h"
37 #include "catalog/pg_database.h"
38 #include "catalog/pg_default_acl.h"
39 #include "catalog/pg_event_trigger.h"
40 #include "catalog/pg_extension.h"
41 #include "catalog/pg_foreign_data_wrapper.h"
42 #include "catalog/pg_foreign_server.h"
43 #include "catalog/pg_init_privs.h"
44 #include "catalog/pg_language.h"
45 #include "catalog/pg_largeobject.h"
46 #include "catalog/pg_largeobject_metadata.h"
47 #include "catalog/pg_namespace.h"
48 #include "catalog/pg_opclass.h"
49 #include "catalog/pg_operator.h"
50 #include "catalog/pg_opfamily.h"
51 #include "catalog/pg_proc.h"
52 #include "catalog/pg_statistic_ext.h"
53 #include "catalog/pg_subscription.h"
54 #include "catalog/pg_tablespace.h"
55 #include "catalog/pg_transform.h"
56 #include "catalog/pg_ts_config.h"
57 #include "catalog/pg_ts_dict.h"
58 #include "catalog/pg_ts_parser.h"
59 #include "catalog/pg_ts_template.h"
60 #include "catalog/pg_type.h"
61 #include "commands/dbcommands.h"
62 #include "commands/event_trigger.h"
63 #include "commands/extension.h"
64 #include "commands/proclang.h"
65 #include "commands/tablespace.h"
66 #include "foreign/foreign.h"
67 #include "miscadmin.h"
68 #include "nodes/makefuncs.h"
69 #include "parser/parse_func.h"
70 #include "parser/parse_type.h"
71 #include "utils/acl.h"
72 #include "utils/aclchk_internal.h"
73 #include "utils/builtins.h"
74 #include "utils/fmgroids.h"
75 #include "utils/lsyscache.h"
76 #include "utils/rel.h"
77 #include "utils/syscache.h"
80 * Internal format used by ALTER DEFAULT PRIVILEGES.
84 Oid roleid
; /* owning role */
85 Oid nspid
; /* namespace, or InvalidOid if none */
86 /* remaining fields are same as in InternalGrant: */
93 DropBehavior behavior
;
97 * When performing a binary-upgrade, pg_dump will call a function to set
98 * this variable to let us know that we need to populate the pg_init_privs
99 * table for the GRANT/REVOKE commands while this variable is set to true.
101 bool binary_upgrade_record_init_privs
= false;
103 static void ExecGrantStmt_oids(InternalGrant
*istmt
);
104 static void ExecGrant_Relation(InternalGrant
*grantStmt
);
105 static void ExecGrant_Database(InternalGrant
*grantStmt
);
106 static void ExecGrant_Fdw(InternalGrant
*grantStmt
);
107 static void ExecGrant_ForeignServer(InternalGrant
*grantStmt
);
108 static void ExecGrant_Function(InternalGrant
*grantStmt
);
109 static void ExecGrant_Language(InternalGrant
*grantStmt
);
110 static void ExecGrant_Largeobject(InternalGrant
*grantStmt
);
111 static void ExecGrant_Namespace(InternalGrant
*grantStmt
);
112 static void ExecGrant_Tablespace(InternalGrant
*grantStmt
);
113 static void ExecGrant_Type(InternalGrant
*grantStmt
);
115 static void SetDefaultACLsInSchemas(InternalDefaultACL
*iacls
, List
*nspnames
);
116 static void SetDefaultACL(InternalDefaultACL
*iacls
);
118 static List
*objectNamesToOids(ObjectType objtype
, List
*objnames
);
119 static List
*objectsInSchemaToOids(ObjectType objtype
, List
*nspnames
);
120 static List
*getRelationsInNamespace(Oid namespaceId
, char relkind
);
121 static void expand_col_privileges(List
*colnames
, Oid table_oid
,
122 AclMode this_privileges
,
123 AclMode
*col_privileges
,
124 int num_col_privileges
);
125 static void expand_all_col_privileges(Oid table_oid
, Form_pg_class classForm
,
126 AclMode this_privileges
,
127 AclMode
*col_privileges
,
128 int num_col_privileges
);
129 static AclMode
string_to_privilege(const char *privname
);
130 static const char *privilege_to_string(AclMode privilege
);
131 static AclMode
restrict_and_check_grant(bool is_grant
, AclMode avail_goptions
,
132 bool all_privs
, AclMode privileges
,
133 Oid objectId
, Oid grantorId
,
134 ObjectType objtype
, const char *objname
,
135 AttrNumber att_number
, const char *colname
);
136 static AclMode
pg_aclmask(ObjectType objtype
, Oid table_oid
, AttrNumber attnum
,
137 Oid roleid
, AclMode mask
, AclMaskHow how
);
138 static void recordExtensionInitPriv(Oid objoid
, Oid classoid
, int objsubid
,
140 static void recordExtensionInitPrivWorker(Oid objoid
, Oid classoid
, int objsubid
,
145 * If is_grant is true, adds the given privileges for the list of
146 * grantees to the existing old_acl. If is_grant is false, the
147 * privileges for the given grantees are removed from old_acl.
149 * NB: the original old_acl is pfree'd.
152 merge_acl_with_grant(Acl
*old_acl
, bool is_grant
,
153 bool grant_option
, DropBehavior behavior
,
154 List
*grantees
, AclMode privileges
,
155 Oid grantorId
, Oid ownerId
)
161 modechg
= is_grant
? ACL_MODECHG_ADD
: ACL_MODECHG_DEL
;
170 aclitem
.ai_grantee
= lfirst_oid(j
);
173 * Grant options can only be granted to individual roles, not PUBLIC.
174 * The reason is that if a user would re-grant a privilege that he
175 * held through PUBLIC, and later the user is removed, the situation
176 * is impossible to clean up.
178 if (is_grant
&& grant_option
&& aclitem
.ai_grantee
== ACL_ID_PUBLIC
)
180 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
181 errmsg("grant options can only be granted to roles")));
183 aclitem
.ai_grantor
= grantorId
;
186 * The asymmetry in the conditions here comes from the spec. In
187 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means
188 * to grant both the basic privilege and its grant option. But in
189 * REVOKE, plain revoke revokes both the basic privilege and its grant
190 * option, while REVOKE GRANT OPTION revokes only the option.
192 ACLITEM_SET_PRIVS_GOPTIONS(aclitem
,
193 (is_grant
|| !grant_option
) ? privileges
: ACL_NO_RIGHTS
,
194 (!is_grant
|| grant_option
) ? privileges
: ACL_NO_RIGHTS
);
196 newer_acl
= aclupdate(new_acl
, &aclitem
, modechg
, ownerId
, behavior
);
198 /* avoid memory leak when there are many grantees */
207 * Restrict the privileges to what we can actually grant, and emit
208 * the standards-mandated warning and error messages.
211 restrict_and_check_grant(bool is_grant
, AclMode avail_goptions
, bool all_privs
,
212 AclMode privileges
, Oid objectId
, Oid grantorId
,
213 ObjectType objtype
, const char *objname
,
214 AttrNumber att_number
, const char *colname
)
216 AclMode this_privileges
;
222 whole_mask
= ACL_ALL_RIGHTS_COLUMN
;
225 whole_mask
= ACL_ALL_RIGHTS_RELATION
;
227 case OBJECT_SEQUENCE
:
228 whole_mask
= ACL_ALL_RIGHTS_SEQUENCE
;
230 case OBJECT_DATABASE
:
231 whole_mask
= ACL_ALL_RIGHTS_DATABASE
;
233 case OBJECT_FUNCTION
:
234 whole_mask
= ACL_ALL_RIGHTS_FUNCTION
;
236 case OBJECT_LANGUAGE
:
237 whole_mask
= ACL_ALL_RIGHTS_LANGUAGE
;
239 case OBJECT_LARGEOBJECT
:
240 whole_mask
= ACL_ALL_RIGHTS_LARGEOBJECT
;
243 whole_mask
= ACL_ALL_RIGHTS_SCHEMA
;
245 case OBJECT_TABLESPACE
:
246 whole_mask
= ACL_ALL_RIGHTS_TABLESPACE
;
249 whole_mask
= ACL_ALL_RIGHTS_FDW
;
251 case OBJECT_FOREIGN_SERVER
:
252 whole_mask
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
254 case OBJECT_EVENT_TRIGGER
:
255 elog(ERROR
, "grantable rights not supported for event triggers");
256 /* not reached, but keep compiler quiet */
257 return ACL_NO_RIGHTS
;
259 whole_mask
= ACL_ALL_RIGHTS_TYPE
;
262 elog(ERROR
, "unrecognized object type: %d", objtype
);
263 /* not reached, but keep compiler quiet */
264 return ACL_NO_RIGHTS
;
268 * If we found no grant options, consider whether to issue a hard error.
269 * Per spec, having any privilege at all on the object will get you by
272 if (avail_goptions
== ACL_NO_RIGHTS
)
274 if (pg_aclmask(objtype
, objectId
, att_number
, grantorId
,
275 whole_mask
| ACL_GRANT_OPTION_FOR(whole_mask
),
276 ACLMASK_ANY
) == ACL_NO_RIGHTS
)
278 if (objtype
== OBJECT_COLUMN
&& colname
)
279 aclcheck_error_col(ACLCHECK_NO_PRIV
, objtype
, objname
, colname
);
281 aclcheck_error(ACLCHECK_NO_PRIV
, objtype
, objname
);
286 * Restrict the operation to what we can actually grant or revoke, and
287 * issue a warning if appropriate. (For REVOKE this isn't quite what the
288 * spec says to do: the spec seems to want a warning only if no privilege
289 * bits actually change in the ACL. In practice that behavior seems much
290 * too noisy, as well as inconsistent with the GRANT case.)
292 this_privileges
= privileges
& ACL_OPTION_TO_PRIVS(avail_goptions
);
295 if (this_privileges
== 0)
297 if (objtype
== OBJECT_COLUMN
&& colname
)
299 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
300 errmsg("no privileges were granted for column \"%s\" of relation \"%s\"",
304 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
305 errmsg("no privileges were granted for \"%s\"",
308 else if (!all_privs
&& this_privileges
!= privileges
)
310 if (objtype
== OBJECT_COLUMN
&& colname
)
312 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
313 errmsg("not all privileges were granted for column \"%s\" of relation \"%s\"",
317 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED
),
318 errmsg("not all privileges were granted for \"%s\"",
324 if (this_privileges
== 0)
326 if (objtype
== OBJECT_COLUMN
&& colname
)
328 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
329 errmsg("no privileges could be revoked for column \"%s\" of relation \"%s\"",
333 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
334 errmsg("no privileges could be revoked for \"%s\"",
337 else if (!all_privs
&& this_privileges
!= privileges
)
339 if (objtype
== OBJECT_COLUMN
&& colname
)
341 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
342 errmsg("not all privileges could be revoked for column \"%s\" of relation \"%s\"",
346 (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED
),
347 errmsg("not all privileges could be revoked for \"%s\"",
352 return this_privileges
;
356 * Called to execute the utility commands GRANT and REVOKE
359 ExecuteGrantStmt(GrantStmt
*stmt
)
363 const char *errormsg
;
364 AclMode all_privileges
;
367 * Turn the regular GrantStmt into the InternalGrant form.
369 istmt
.is_grant
= stmt
->is_grant
;
370 istmt
.objtype
= stmt
->objtype
;
372 /* Collect the OIDs of the target objects */
373 switch (stmt
->targtype
)
375 case ACL_TARGET_OBJECT
:
376 istmt
.objects
= objectNamesToOids(stmt
->objtype
, stmt
->objects
);
378 case ACL_TARGET_ALL_IN_SCHEMA
:
379 istmt
.objects
= objectsInSchemaToOids(stmt
->objtype
, stmt
->objects
);
381 /* ACL_TARGET_DEFAULTS should not be seen here */
383 elog(ERROR
, "unrecognized GrantStmt.targtype: %d",
384 (int) stmt
->targtype
);
387 /* all_privs to be filled below */
388 /* privileges to be filled below */
389 istmt
.col_privs
= NIL
; /* may get filled below */
390 istmt
.grantees
= NIL
; /* filled below */
391 istmt
.grant_option
= stmt
->grant_option
;
392 istmt
.behavior
= stmt
->behavior
;
395 * Convert the RoleSpec list into an Oid list. Note that at this point we
396 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
397 * there shouldn't be any additional work needed to support this case.
399 foreach(cell
, stmt
->grantees
)
401 RoleSpec
*grantee
= (RoleSpec
*) lfirst(cell
);
404 switch (grantee
->roletype
)
406 case ROLESPEC_PUBLIC
:
407 grantee_uid
= ACL_ID_PUBLIC
;
410 grantee_uid
= get_rolespec_oid(grantee
, false);
413 istmt
.grantees
= lappend_oid(istmt
.grantees
, grantee_uid
);
417 * Convert stmt->privileges, a list of AccessPriv nodes, into an AclMode
418 * bitmask. Note: objtype can't be OBJECT_COLUMN.
420 switch (stmt
->objtype
)
425 * Because this might be a sequence, we test both relation and
426 * sequence bits, and later do a more limited test when we know
429 all_privileges
= ACL_ALL_RIGHTS_RELATION
| ACL_ALL_RIGHTS_SEQUENCE
;
430 errormsg
= gettext_noop("invalid privilege type %s for relation");
432 case OBJECT_SEQUENCE
:
433 all_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
434 errormsg
= gettext_noop("invalid privilege type %s for sequence");
436 case OBJECT_DATABASE
:
437 all_privileges
= ACL_ALL_RIGHTS_DATABASE
;
438 errormsg
= gettext_noop("invalid privilege type %s for database");
441 all_privileges
= ACL_ALL_RIGHTS_TYPE
;
442 errormsg
= gettext_noop("invalid privilege type %s for domain");
444 case OBJECT_FUNCTION
:
445 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
446 errormsg
= gettext_noop("invalid privilege type %s for function");
448 case OBJECT_LANGUAGE
:
449 all_privileges
= ACL_ALL_RIGHTS_LANGUAGE
;
450 errormsg
= gettext_noop("invalid privilege type %s for language");
452 case OBJECT_LARGEOBJECT
:
453 all_privileges
= ACL_ALL_RIGHTS_LARGEOBJECT
;
454 errormsg
= gettext_noop("invalid privilege type %s for large object");
457 all_privileges
= ACL_ALL_RIGHTS_SCHEMA
;
458 errormsg
= gettext_noop("invalid privilege type %s for schema");
460 case OBJECT_PROCEDURE
:
461 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
462 errormsg
= gettext_noop("invalid privilege type %s for procedure");
465 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
466 errormsg
= gettext_noop("invalid privilege type %s for routine");
468 case OBJECT_TABLESPACE
:
469 all_privileges
= ACL_ALL_RIGHTS_TABLESPACE
;
470 errormsg
= gettext_noop("invalid privilege type %s for tablespace");
473 all_privileges
= ACL_ALL_RIGHTS_TYPE
;
474 errormsg
= gettext_noop("invalid privilege type %s for type");
477 all_privileges
= ACL_ALL_RIGHTS_FDW
;
478 errormsg
= gettext_noop("invalid privilege type %s for foreign-data wrapper");
480 case OBJECT_FOREIGN_SERVER
:
481 all_privileges
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
482 errormsg
= gettext_noop("invalid privilege type %s for foreign server");
485 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
486 (int) stmt
->objtype
);
487 /* keep compiler quiet */
488 all_privileges
= ACL_NO_RIGHTS
;
492 if (stmt
->privileges
== NIL
)
494 istmt
.all_privs
= true;
497 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
498 * depending on the object type
500 istmt
.privileges
= ACL_NO_RIGHTS
;
504 istmt
.all_privs
= false;
505 istmt
.privileges
= ACL_NO_RIGHTS
;
507 foreach(cell
, stmt
->privileges
)
509 AccessPriv
*privnode
= (AccessPriv
*) lfirst(cell
);
513 * If it's a column-level specification, we just set it aside in
514 * col_privs for the moment; but insist it's for a relation.
518 if (stmt
->objtype
!= OBJECT_TABLE
)
520 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
521 errmsg("column privileges are only valid for relations")));
522 istmt
.col_privs
= lappend(istmt
.col_privs
, privnode
);
526 if (privnode
->priv_name
== NULL
) /* parser mistake? */
527 elog(ERROR
, "AccessPriv node must specify privilege or columns");
528 priv
= string_to_privilege(privnode
->priv_name
);
530 if (priv
& ~((AclMode
) all_privileges
))
532 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
533 errmsg(errormsg
, privilege_to_string(priv
))));
535 istmt
.privileges
|= priv
;
539 ExecGrantStmt_oids(&istmt
);
545 * Internal entry point for granting and revoking privileges.
548 ExecGrantStmt_oids(InternalGrant
*istmt
)
550 switch (istmt
->objtype
)
553 case OBJECT_SEQUENCE
:
554 ExecGrant_Relation(istmt
);
556 case OBJECT_DATABASE
:
557 ExecGrant_Database(istmt
);
561 ExecGrant_Type(istmt
);
564 ExecGrant_Fdw(istmt
);
566 case OBJECT_FOREIGN_SERVER
:
567 ExecGrant_ForeignServer(istmt
);
569 case OBJECT_FUNCTION
:
570 case OBJECT_PROCEDURE
:
572 ExecGrant_Function(istmt
);
574 case OBJECT_LANGUAGE
:
575 ExecGrant_Language(istmt
);
577 case OBJECT_LARGEOBJECT
:
578 ExecGrant_Largeobject(istmt
);
581 ExecGrant_Namespace(istmt
);
583 case OBJECT_TABLESPACE
:
584 ExecGrant_Tablespace(istmt
);
587 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
588 (int) istmt
->objtype
);
592 * Pass the info to event triggers about the just-executed GRANT. Note
593 * that we prefer to do it after actually executing it, because that gives
594 * the functions a chance to adjust the istmt with privileges actually
597 if (EventTriggerSupportsObjectType(istmt
->objtype
))
598 EventTriggerCollectGrant(istmt
);
604 * Turn a list of object names of a given type into an Oid list.
606 * XXX: This function doesn't take any sort of locks on the objects whose
607 * names it looks up. In the face of concurrent DDL, we might easily latch
608 * onto an old version of an object, causing the GRANT or REVOKE statement
612 objectNamesToOids(ObjectType objtype
, List
*objnames
)
617 Assert(objnames
!= NIL
);
622 case OBJECT_SEQUENCE
:
623 foreach(cell
, objnames
)
625 RangeVar
*relvar
= (RangeVar
*) lfirst(cell
);
628 relOid
= RangeVarGetRelid(relvar
, NoLock
, false);
629 objects
= lappend_oid(objects
, relOid
);
632 case OBJECT_DATABASE
:
633 foreach(cell
, objnames
)
635 char *dbname
= strVal(lfirst(cell
));
638 dbid
= get_database_oid(dbname
, false);
639 objects
= lappend_oid(objects
, dbid
);
644 foreach(cell
, objnames
)
646 List
*typname
= (List
*) lfirst(cell
);
649 oid
= typenameTypeId(NULL
, makeTypeNameFromNameList(typname
));
650 objects
= lappend_oid(objects
, oid
);
653 case OBJECT_FUNCTION
:
654 foreach(cell
, objnames
)
656 ObjectWithArgs
*func
= (ObjectWithArgs
*) lfirst(cell
);
659 funcid
= LookupFuncWithArgs(OBJECT_FUNCTION
, func
, false);
660 objects
= lappend_oid(objects
, funcid
);
663 case OBJECT_LANGUAGE
:
664 foreach(cell
, objnames
)
666 char *langname
= strVal(lfirst(cell
));
669 oid
= get_language_oid(langname
, false);
670 objects
= lappend_oid(objects
, oid
);
673 case OBJECT_LARGEOBJECT
:
674 foreach(cell
, objnames
)
676 Oid lobjOid
= oidparse(lfirst(cell
));
678 if (!LargeObjectExists(lobjOid
))
680 (errcode(ERRCODE_UNDEFINED_OBJECT
),
681 errmsg("large object %u does not exist",
684 objects
= lappend_oid(objects
, lobjOid
);
688 foreach(cell
, objnames
)
690 char *nspname
= strVal(lfirst(cell
));
693 oid
= get_namespace_oid(nspname
, false);
694 objects
= lappend_oid(objects
, oid
);
697 case OBJECT_PROCEDURE
:
698 foreach(cell
, objnames
)
700 ObjectWithArgs
*func
= (ObjectWithArgs
*) lfirst(cell
);
703 procid
= LookupFuncWithArgs(OBJECT_PROCEDURE
, func
, false);
704 objects
= lappend_oid(objects
, procid
);
708 foreach(cell
, objnames
)
710 ObjectWithArgs
*func
= (ObjectWithArgs
*) lfirst(cell
);
713 routid
= LookupFuncWithArgs(OBJECT_ROUTINE
, func
, false);
714 objects
= lappend_oid(objects
, routid
);
717 case OBJECT_TABLESPACE
:
718 foreach(cell
, objnames
)
720 char *spcname
= strVal(lfirst(cell
));
723 spcoid
= get_tablespace_oid(spcname
, false);
724 objects
= lappend_oid(objects
, spcoid
);
728 foreach(cell
, objnames
)
730 char *fdwname
= strVal(lfirst(cell
));
731 Oid fdwid
= get_foreign_data_wrapper_oid(fdwname
, false);
733 objects
= lappend_oid(objects
, fdwid
);
736 case OBJECT_FOREIGN_SERVER
:
737 foreach(cell
, objnames
)
739 char *srvname
= strVal(lfirst(cell
));
740 Oid srvid
= get_foreign_server_oid(srvname
, false);
742 objects
= lappend_oid(objects
, srvid
);
746 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
754 * objectsInSchemaToOids
756 * Find all objects of a given type in specified schemas, and make a list
757 * of their Oids. We check USAGE privilege on the schemas, but there is
758 * no privilege checking on the individual objects here.
761 objectsInSchemaToOids(ObjectType objtype
, List
*nspnames
)
766 foreach(cell
, nspnames
)
768 char *nspname
= strVal(lfirst(cell
));
772 namespaceId
= LookupExplicitNamespace(nspname
, false);
777 objs
= getRelationsInNamespace(namespaceId
, RELKIND_RELATION
);
778 objects
= list_concat(objects
, objs
);
779 objs
= getRelationsInNamespace(namespaceId
, RELKIND_VIEW
);
780 objects
= list_concat(objects
, objs
);
781 objs
= getRelationsInNamespace(namespaceId
, RELKIND_MATVIEW
);
782 objects
= list_concat(objects
, objs
);
783 objs
= getRelationsInNamespace(namespaceId
, RELKIND_FOREIGN_TABLE
);
784 objects
= list_concat(objects
, objs
);
785 objs
= getRelationsInNamespace(namespaceId
, RELKIND_PARTITIONED_TABLE
);
786 objects
= list_concat(objects
, objs
);
788 case OBJECT_SEQUENCE
:
789 objs
= getRelationsInNamespace(namespaceId
, RELKIND_SEQUENCE
);
790 objects
= list_concat(objects
, objs
);
792 case OBJECT_FUNCTION
:
793 case OBJECT_PROCEDURE
:
803 ScanKeyInit(&key
[keycount
++],
804 Anum_pg_proc_pronamespace
,
805 BTEqualStrategyNumber
, F_OIDEQ
,
806 ObjectIdGetDatum(namespaceId
));
808 if (objtype
== OBJECT_FUNCTION
)
809 /* includes aggregates and window functions */
810 ScanKeyInit(&key
[keycount
++],
811 Anum_pg_proc_prokind
,
812 BTEqualStrategyNumber
, F_CHARNE
,
813 CharGetDatum(PROKIND_PROCEDURE
));
814 else if (objtype
== OBJECT_PROCEDURE
)
815 ScanKeyInit(&key
[keycount
++],
816 Anum_pg_proc_prokind
,
817 BTEqualStrategyNumber
, F_CHAREQ
,
818 CharGetDatum(PROKIND_PROCEDURE
));
820 rel
= table_open(ProcedureRelationId
, AccessShareLock
);
821 scan
= table_beginscan_catalog(rel
, keycount
, key
);
823 while ((tuple
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
825 Oid oid
= ((Form_pg_proc
) GETSTRUCT(tuple
))->oid
;
827 objects
= lappend_oid(objects
, oid
);
831 table_close(rel
, AccessShareLock
);
835 /* should not happen */
836 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
845 * getRelationsInNamespace
847 * Return Oid list of relations in given namespace filtered by relation kind
850 getRelationsInNamespace(Oid namespaceId
, char relkind
)
852 List
*relations
= NIL
;
859 Anum_pg_class_relnamespace
,
860 BTEqualStrategyNumber
, F_OIDEQ
,
861 ObjectIdGetDatum(namespaceId
));
863 Anum_pg_class_relkind
,
864 BTEqualStrategyNumber
, F_CHAREQ
,
865 CharGetDatum(relkind
));
867 rel
= table_open(RelationRelationId
, AccessShareLock
);
868 scan
= table_beginscan_catalog(rel
, 2, key
);
870 while ((tuple
= heap_getnext(scan
, ForwardScanDirection
)) != NULL
)
872 Oid oid
= ((Form_pg_class
) GETSTRUCT(tuple
))->oid
;
874 relations
= lappend_oid(relations
, oid
);
878 table_close(rel
, AccessShareLock
);
885 * ALTER DEFAULT PRIVILEGES statement
888 ExecAlterDefaultPrivilegesStmt(ParseState
*pstate
, AlterDefaultPrivilegesStmt
*stmt
)
890 GrantStmt
*action
= stmt
->action
;
891 InternalDefaultACL iacls
;
893 List
*rolespecs
= NIL
;
894 List
*nspnames
= NIL
;
895 DefElem
*drolespecs
= NULL
;
896 DefElem
*dnspnames
= NULL
;
897 AclMode all_privileges
;
898 const char *errormsg
;
900 /* Deconstruct the "options" part of the statement */
901 foreach(cell
, stmt
->options
)
903 DefElem
*defel
= (DefElem
*) lfirst(cell
);
905 if (strcmp(defel
->defname
, "schemas") == 0)
909 (errcode(ERRCODE_SYNTAX_ERROR
),
910 errmsg("conflicting or redundant options"),
911 parser_errposition(pstate
, defel
->location
)));
914 else if (strcmp(defel
->defname
, "roles") == 0)
918 (errcode(ERRCODE_SYNTAX_ERROR
),
919 errmsg("conflicting or redundant options"),
920 parser_errposition(pstate
, defel
->location
)));
924 elog(ERROR
, "option \"%s\" not recognized", defel
->defname
);
928 nspnames
= (List
*) dnspnames
->arg
;
930 rolespecs
= (List
*) drolespecs
->arg
;
932 /* Prepare the InternalDefaultACL representation of the statement */
933 /* roleid to be filled below */
934 /* nspid to be filled in SetDefaultACLsInSchemas */
935 iacls
.is_grant
= action
->is_grant
;
936 iacls
.objtype
= action
->objtype
;
937 /* all_privs to be filled below */
938 /* privileges to be filled below */
939 iacls
.grantees
= NIL
; /* filled below */
940 iacls
.grant_option
= action
->grant_option
;
941 iacls
.behavior
= action
->behavior
;
944 * Convert the RoleSpec list into an Oid list. Note that at this point we
945 * insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
946 * there shouldn't be any additional work needed to support this case.
948 foreach(cell
, action
->grantees
)
950 RoleSpec
*grantee
= (RoleSpec
*) lfirst(cell
);
953 switch (grantee
->roletype
)
955 case ROLESPEC_PUBLIC
:
956 grantee_uid
= ACL_ID_PUBLIC
;
959 grantee_uid
= get_rolespec_oid(grantee
, false);
962 iacls
.grantees
= lappend_oid(iacls
.grantees
, grantee_uid
);
966 * Convert action->privileges, a list of privilege strings, into an
969 switch (action
->objtype
)
972 all_privileges
= ACL_ALL_RIGHTS_RELATION
;
973 errormsg
= gettext_noop("invalid privilege type %s for relation");
975 case OBJECT_SEQUENCE
:
976 all_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
977 errormsg
= gettext_noop("invalid privilege type %s for sequence");
979 case OBJECT_FUNCTION
:
980 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
981 errormsg
= gettext_noop("invalid privilege type %s for function");
983 case OBJECT_PROCEDURE
:
984 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
985 errormsg
= gettext_noop("invalid privilege type %s for procedure");
988 all_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
989 errormsg
= gettext_noop("invalid privilege type %s for routine");
992 all_privileges
= ACL_ALL_RIGHTS_TYPE
;
993 errormsg
= gettext_noop("invalid privilege type %s for type");
996 all_privileges
= ACL_ALL_RIGHTS_SCHEMA
;
997 errormsg
= gettext_noop("invalid privilege type %s for schema");
1000 elog(ERROR
, "unrecognized GrantStmt.objtype: %d",
1001 (int) action
->objtype
);
1002 /* keep compiler quiet */
1003 all_privileges
= ACL_NO_RIGHTS
;
1007 if (action
->privileges
== NIL
)
1009 iacls
.all_privs
= true;
1012 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
1013 * depending on the object type
1015 iacls
.privileges
= ACL_NO_RIGHTS
;
1019 iacls
.all_privs
= false;
1020 iacls
.privileges
= ACL_NO_RIGHTS
;
1022 foreach(cell
, action
->privileges
)
1024 AccessPriv
*privnode
= (AccessPriv
*) lfirst(cell
);
1029 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1030 errmsg("default privileges cannot be set for columns")));
1032 if (privnode
->priv_name
== NULL
) /* parser mistake? */
1033 elog(ERROR
, "AccessPriv node must specify privilege");
1034 priv
= string_to_privilege(privnode
->priv_name
);
1036 if (priv
& ~((AclMode
) all_privileges
))
1038 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1039 errmsg(errormsg
, privilege_to_string(priv
))));
1041 iacls
.privileges
|= priv
;
1045 if (rolespecs
== NIL
)
1047 /* Set permissions for myself */
1048 iacls
.roleid
= GetUserId();
1050 SetDefaultACLsInSchemas(&iacls
, nspnames
);
1054 /* Look up the role OIDs and do permissions checks */
1057 foreach(rolecell
, rolespecs
)
1059 RoleSpec
*rolespec
= lfirst(rolecell
);
1061 iacls
.roleid
= get_rolespec_oid(rolespec
, false);
1064 * We insist that calling user be a member of each target role. If
1065 * he has that, he could become that role anyway via SET ROLE, so
1066 * FOR ROLE is just a syntactic convenience and doesn't give any
1067 * special privileges.
1069 check_is_member_of_role(GetUserId(), iacls
.roleid
);
1071 SetDefaultACLsInSchemas(&iacls
, nspnames
);
1077 * Process ALTER DEFAULT PRIVILEGES for a list of target schemas
1079 * All fields of *iacls except nspid were filled already
1082 SetDefaultACLsInSchemas(InternalDefaultACL
*iacls
, List
*nspnames
)
1084 if (nspnames
== NIL
)
1086 /* Set database-wide permissions if no schema was specified */
1087 iacls
->nspid
= InvalidOid
;
1089 SetDefaultACL(iacls
);
1093 /* Look up the schema OIDs and set permissions for each one */
1096 foreach(nspcell
, nspnames
)
1098 char *nspname
= strVal(lfirst(nspcell
));
1100 iacls
->nspid
= get_namespace_oid(nspname
, false);
1103 * We used to insist that the target role have CREATE privileges
1104 * on the schema, since without that it wouldn't be able to create
1105 * an object for which these default privileges would apply.
1106 * However, this check proved to be more confusing than helpful,
1107 * and it also caused certain database states to not be
1108 * dumpable/restorable, since revoking CREATE doesn't cause
1109 * default privileges for the schema to go away. So now, we just
1110 * allow the ALTER; if the user lacks CREATE he'll find out when
1111 * he tries to create an object.
1114 SetDefaultACL(iacls
);
1121 * Create or update a pg_default_acl entry
1124 SetDefaultACL(InternalDefaultACL
*iacls
)
1126 AclMode this_privileges
= iacls
->privileges
;
1135 Datum values
[Natts_pg_default_acl
];
1136 bool nulls
[Natts_pg_default_acl
];
1137 bool replaces
[Natts_pg_default_acl
];
1143 rel
= table_open(DefaultAclRelationId
, RowExclusiveLock
);
1146 * The default for a global entry is the hard-wired default ACL for the
1147 * particular object type. The default for non-global entries is an empty
1148 * ACL. This must be so because global entries replace the hard-wired
1149 * defaults, while others are added on.
1151 if (!OidIsValid(iacls
->nspid
))
1152 def_acl
= acldefault(iacls
->objtype
, iacls
->roleid
);
1154 def_acl
= make_empty_acl();
1157 * Convert ACL object type to pg_default_acl object type and handle
1160 switch (iacls
->objtype
)
1163 objtype
= DEFACLOBJ_RELATION
;
1164 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1165 this_privileges
= ACL_ALL_RIGHTS_RELATION
;
1168 case OBJECT_SEQUENCE
:
1169 objtype
= DEFACLOBJ_SEQUENCE
;
1170 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1171 this_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
1174 case OBJECT_FUNCTION
:
1175 objtype
= DEFACLOBJ_FUNCTION
;
1176 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1177 this_privileges
= ACL_ALL_RIGHTS_FUNCTION
;
1181 objtype
= DEFACLOBJ_TYPE
;
1182 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1183 this_privileges
= ACL_ALL_RIGHTS_TYPE
;
1187 if (OidIsValid(iacls
->nspid
))
1189 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1190 errmsg("cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS")));
1191 objtype
= DEFACLOBJ_NAMESPACE
;
1192 if (iacls
->all_privs
&& this_privileges
== ACL_NO_RIGHTS
)
1193 this_privileges
= ACL_ALL_RIGHTS_SCHEMA
;
1197 elog(ERROR
, "unrecognized objtype: %d",
1198 (int) iacls
->objtype
);
1199 objtype
= 0; /* keep compiler quiet */
1203 /* Search for existing row for this object type in catalog */
1204 tuple
= SearchSysCache3(DEFACLROLENSPOBJ
,
1205 ObjectIdGetDatum(iacls
->roleid
),
1206 ObjectIdGetDatum(iacls
->nspid
),
1207 CharGetDatum(objtype
));
1209 if (HeapTupleIsValid(tuple
))
1214 aclDatum
= SysCacheGetAttr(DEFACLROLENSPOBJ
, tuple
,
1215 Anum_pg_default_acl_defaclacl
,
1218 old_acl
= DatumGetAclPCopy(aclDatum
);
1220 old_acl
= NULL
; /* this case shouldn't happen, probably */
1229 if (old_acl
!= NULL
)
1232 * We need the members of both old and new ACLs so we can correct the
1233 * shared dependency information. Collect data before
1234 * merge_acl_with_grant throws away old_acl.
1236 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1240 /* If no or null entry, start with the default ACL value */
1241 old_acl
= aclcopy(def_acl
);
1242 /* There are no old member roles according to the catalogs */
1248 * Generate new ACL. Grantor of rights is always the same as the target
1251 new_acl
= merge_acl_with_grant(old_acl
,
1253 iacls
->grant_option
,
1261 * If the result is the same as the default value, we do not need an
1262 * explicit pg_default_acl entry, and should in fact remove the entry if
1263 * it exists. Must sort both arrays to compare properly.
1265 aclitemsort(new_acl
);
1266 aclitemsort(def_acl
);
1267 if (aclequal(new_acl
, def_acl
))
1269 /* delete old entry, if indeed there is one */
1272 ObjectAddress myself
;
1275 * The dependency machinery will take care of removing all
1276 * associated dependency entries. We use DROP_RESTRICT since
1277 * there shouldn't be anything depending on this entry.
1279 myself
.classId
= DefaultAclRelationId
;
1280 myself
.objectId
= ((Form_pg_default_acl
) GETSTRUCT(tuple
))->oid
;
1281 myself
.objectSubId
= 0;
1283 performDeletion(&myself
, DROP_RESTRICT
, 0);
1290 /* Prepare to insert or update pg_default_acl entry */
1291 MemSet(values
, 0, sizeof(values
));
1292 MemSet(nulls
, false, sizeof(nulls
));
1293 MemSet(replaces
, false, sizeof(replaces
));
1297 /* insert new entry */
1298 defAclOid
= GetNewOidWithIndex(rel
, DefaultAclOidIndexId
,
1299 Anum_pg_default_acl_oid
);
1300 values
[Anum_pg_default_acl_oid
- 1] = ObjectIdGetDatum(defAclOid
);
1301 values
[Anum_pg_default_acl_defaclrole
- 1] = ObjectIdGetDatum(iacls
->roleid
);
1302 values
[Anum_pg_default_acl_defaclnamespace
- 1] = ObjectIdGetDatum(iacls
->nspid
);
1303 values
[Anum_pg_default_acl_defaclobjtype
- 1] = CharGetDatum(objtype
);
1304 values
[Anum_pg_default_acl_defaclacl
- 1] = PointerGetDatum(new_acl
);
1306 newtuple
= heap_form_tuple(RelationGetDescr(rel
), values
, nulls
);
1307 CatalogTupleInsert(rel
, newtuple
);
1311 defAclOid
= ((Form_pg_default_acl
) GETSTRUCT(tuple
))->oid
;
1313 /* update existing entry */
1314 values
[Anum_pg_default_acl_defaclacl
- 1] = PointerGetDatum(new_acl
);
1315 replaces
[Anum_pg_default_acl_defaclacl
- 1] = true;
1317 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(rel
),
1318 values
, nulls
, replaces
);
1319 CatalogTupleUpdate(rel
, &newtuple
->t_self
, newtuple
);
1322 /* these dependencies don't change in an update */
1325 /* dependency on role */
1326 recordDependencyOnOwner(DefaultAclRelationId
, defAclOid
,
1329 /* dependency on namespace */
1330 if (OidIsValid(iacls
->nspid
))
1332 ObjectAddress myself
,
1335 myself
.classId
= DefaultAclRelationId
;
1336 myself
.objectId
= defAclOid
;
1337 myself
.objectSubId
= 0;
1339 referenced
.classId
= NamespaceRelationId
;
1340 referenced
.objectId
= iacls
->nspid
;
1341 referenced
.objectSubId
= 0;
1343 recordDependencyOn(&myself
, &referenced
, DEPENDENCY_AUTO
);
1348 * Update the shared dependency ACL info
1350 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1352 updateAclDependencies(DefaultAclRelationId
,
1355 noldmembers
, oldmembers
,
1356 nnewmembers
, newmembers
);
1359 InvokeObjectPostCreateHook(DefaultAclRelationId
, defAclOid
, 0);
1361 InvokeObjectPostAlterHook(DefaultAclRelationId
, defAclOid
, 0);
1364 if (HeapTupleIsValid(tuple
))
1365 ReleaseSysCache(tuple
);
1367 table_close(rel
, RowExclusiveLock
);
1372 * RemoveRoleFromObjectACL
1374 * Used by shdepDropOwned to remove mentions of a role in ACLs
1377 RemoveRoleFromObjectACL(Oid roleid
, Oid classid
, Oid objid
)
1379 if (classid
== DefaultAclRelationId
)
1381 InternalDefaultACL iacls
;
1382 Form_pg_default_acl pg_default_acl_tuple
;
1384 ScanKeyData skey
[1];
1388 /* first fetch info needed by SetDefaultACL */
1389 rel
= table_open(DefaultAclRelationId
, AccessShareLock
);
1391 ScanKeyInit(&skey
[0],
1392 Anum_pg_default_acl_oid
,
1393 BTEqualStrategyNumber
, F_OIDEQ
,
1394 ObjectIdGetDatum(objid
));
1396 scan
= systable_beginscan(rel
, DefaultAclOidIndexId
, true,
1399 tuple
= systable_getnext(scan
);
1401 if (!HeapTupleIsValid(tuple
))
1402 elog(ERROR
, "could not find tuple for default ACL %u", objid
);
1404 pg_default_acl_tuple
= (Form_pg_default_acl
) GETSTRUCT(tuple
);
1406 iacls
.roleid
= pg_default_acl_tuple
->defaclrole
;
1407 iacls
.nspid
= pg_default_acl_tuple
->defaclnamespace
;
1409 switch (pg_default_acl_tuple
->defaclobjtype
)
1411 case DEFACLOBJ_RELATION
:
1412 iacls
.objtype
= OBJECT_TABLE
;
1414 case DEFACLOBJ_SEQUENCE
:
1415 iacls
.objtype
= OBJECT_SEQUENCE
;
1417 case DEFACLOBJ_FUNCTION
:
1418 iacls
.objtype
= OBJECT_FUNCTION
;
1420 case DEFACLOBJ_TYPE
:
1421 iacls
.objtype
= OBJECT_TYPE
;
1423 case DEFACLOBJ_NAMESPACE
:
1424 iacls
.objtype
= OBJECT_SCHEMA
;
1427 /* Shouldn't get here */
1428 elog(ERROR
, "unexpected default ACL type: %d",
1429 (int) pg_default_acl_tuple
->defaclobjtype
);
1433 systable_endscan(scan
);
1434 table_close(rel
, AccessShareLock
);
1436 iacls
.is_grant
= false;
1437 iacls
.all_privs
= true;
1438 iacls
.privileges
= ACL_NO_RIGHTS
;
1439 iacls
.grantees
= list_make1_oid(roleid
);
1440 iacls
.grant_option
= false;
1441 iacls
.behavior
= DROP_CASCADE
;
1444 SetDefaultACL(&iacls
);
1448 InternalGrant istmt
;
1452 case RelationRelationId
:
1453 /* it's OK to use TABLE for a sequence */
1454 istmt
.objtype
= OBJECT_TABLE
;
1456 case DatabaseRelationId
:
1457 istmt
.objtype
= OBJECT_DATABASE
;
1459 case TypeRelationId
:
1460 istmt
.objtype
= OBJECT_TYPE
;
1462 case ProcedureRelationId
:
1463 istmt
.objtype
= OBJECT_ROUTINE
;
1465 case LanguageRelationId
:
1466 istmt
.objtype
= OBJECT_LANGUAGE
;
1468 case LargeObjectRelationId
:
1469 istmt
.objtype
= OBJECT_LARGEOBJECT
;
1471 case NamespaceRelationId
:
1472 istmt
.objtype
= OBJECT_SCHEMA
;
1474 case TableSpaceRelationId
:
1475 istmt
.objtype
= OBJECT_TABLESPACE
;
1477 case ForeignServerRelationId
:
1478 istmt
.objtype
= OBJECT_FOREIGN_SERVER
;
1480 case ForeignDataWrapperRelationId
:
1481 istmt
.objtype
= OBJECT_FDW
;
1484 elog(ERROR
, "unexpected object class %u", classid
);
1487 istmt
.is_grant
= false;
1488 istmt
.objects
= list_make1_oid(objid
);
1489 istmt
.all_privs
= true;
1490 istmt
.privileges
= ACL_NO_RIGHTS
;
1491 istmt
.col_privs
= NIL
;
1492 istmt
.grantees
= list_make1_oid(roleid
);
1493 istmt
.grant_option
= false;
1494 istmt
.behavior
= DROP_CASCADE
;
1496 ExecGrantStmt_oids(&istmt
);
1502 * expand_col_privileges
1504 * OR the specified privilege(s) into per-column array entries for each
1505 * specified attribute. The per-column array is indexed starting at
1506 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1509 expand_col_privileges(List
*colnames
, Oid table_oid
,
1510 AclMode this_privileges
,
1511 AclMode
*col_privileges
,
1512 int num_col_privileges
)
1516 foreach(cell
, colnames
)
1518 char *colname
= strVal(lfirst(cell
));
1521 attnum
= get_attnum(table_oid
, colname
);
1522 if (attnum
== InvalidAttrNumber
)
1524 (errcode(ERRCODE_UNDEFINED_COLUMN
),
1525 errmsg("column \"%s\" of relation \"%s\" does not exist",
1526 colname
, get_rel_name(table_oid
))));
1527 attnum
-= FirstLowInvalidHeapAttributeNumber
;
1528 if (attnum
<= 0 || attnum
>= num_col_privileges
)
1529 elog(ERROR
, "column number out of range"); /* safety check */
1530 col_privileges
[attnum
] |= this_privileges
;
1535 * expand_all_col_privileges
1537 * OR the specified privilege(s) into per-column array entries for each valid
1538 * attribute of a relation. The per-column array is indexed starting at
1539 * FirstLowInvalidHeapAttributeNumber, up to relation's last attribute.
1542 expand_all_col_privileges(Oid table_oid
, Form_pg_class classForm
,
1543 AclMode this_privileges
,
1544 AclMode
*col_privileges
,
1545 int num_col_privileges
)
1547 AttrNumber curr_att
;
1549 Assert(classForm
->relnatts
- FirstLowInvalidHeapAttributeNumber
< num_col_privileges
);
1550 for (curr_att
= FirstLowInvalidHeapAttributeNumber
+ 1;
1551 curr_att
<= classForm
->relnatts
;
1557 if (curr_att
== InvalidAttrNumber
)
1560 /* Views don't have any system columns at all */
1561 if (classForm
->relkind
== RELKIND_VIEW
&& curr_att
< 0)
1564 attTuple
= SearchSysCache2(ATTNUM
,
1565 ObjectIdGetDatum(table_oid
),
1566 Int16GetDatum(curr_att
));
1567 if (!HeapTupleIsValid(attTuple
))
1568 elog(ERROR
, "cache lookup failed for attribute %d of relation %u",
1569 curr_att
, table_oid
);
1571 isdropped
= ((Form_pg_attribute
) GETSTRUCT(attTuple
))->attisdropped
;
1573 ReleaseSysCache(attTuple
);
1575 /* ignore dropped columns */
1579 col_privileges
[curr_att
- FirstLowInvalidHeapAttributeNumber
] |= this_privileges
;
1584 * This processes attributes, but expects to be called from
1585 * ExecGrant_Relation, not directly from ExecuteGrantStmt.
1588 ExecGrant_Attribute(InternalGrant
*istmt
, Oid relOid
, const char *relname
,
1589 AttrNumber attnum
, Oid ownerId
, AclMode col_privileges
,
1590 Relation attRelation
, const Acl
*old_rel_acl
)
1592 HeapTuple attr_tuple
;
1593 Form_pg_attribute pg_attribute_tuple
;
1600 AclMode avail_goptions
;
1603 Datum values
[Natts_pg_attribute
];
1604 bool nulls
[Natts_pg_attribute
];
1605 bool replaces
[Natts_pg_attribute
];
1611 attr_tuple
= SearchSysCache2(ATTNUM
,
1612 ObjectIdGetDatum(relOid
),
1613 Int16GetDatum(attnum
));
1614 if (!HeapTupleIsValid(attr_tuple
))
1615 elog(ERROR
, "cache lookup failed for attribute %d of relation %u",
1617 pg_attribute_tuple
= (Form_pg_attribute
) GETSTRUCT(attr_tuple
);
1620 * Get working copy of existing ACL. If there's no ACL, substitute the
1623 aclDatum
= SysCacheGetAttr(ATTNUM
, attr_tuple
, Anum_pg_attribute_attacl
,
1627 old_acl
= acldefault(OBJECT_COLUMN
, ownerId
);
1628 /* There are no old member roles according to the catalogs */
1634 old_acl
= DatumGetAclPCopy(aclDatum
);
1635 /* Get the roles mentioned in the existing ACL */
1636 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1640 * In select_best_grantor we should consider existing table-level ACL bits
1641 * as well as the per-column ACL. Build a new ACL that is their
1642 * concatenation. (This is a bit cheap and dirty compared to merging them
1643 * properly with no duplications, but it's all we need here.)
1645 merged_acl
= aclconcat(old_rel_acl
, old_acl
);
1647 /* Determine ID to do the grant as, and available grant options */
1648 select_best_grantor(GetUserId(), col_privileges
,
1649 merged_acl
, ownerId
,
1650 &grantorId
, &avail_goptions
);
1655 * Restrict the privileges to what we can actually grant, and emit the
1656 * standards-mandated warning and error messages. Note: we don't track
1657 * whether the user actually used the ALL PRIVILEGES(columns) syntax for
1658 * each column; we just approximate it by whether all the possible
1659 * privileges are specified now. Since the all_privs flag only determines
1660 * whether a warning is issued, this seems close enough.
1663 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1664 (col_privileges
== ACL_ALL_RIGHTS_COLUMN
),
1666 relOid
, grantorId
, OBJECT_COLUMN
,
1668 NameStr(pg_attribute_tuple
->attname
));
1673 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
1674 istmt
->grant_option
,
1675 istmt
->behavior
, istmt
->grantees
,
1676 col_privileges
, grantorId
,
1680 * We need the members of both old and new ACLs so we can correct the
1681 * shared dependency information.
1683 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1685 /* finished building new ACL value, now insert it */
1686 MemSet(values
, 0, sizeof(values
));
1687 MemSet(nulls
, false, sizeof(nulls
));
1688 MemSet(replaces
, false, sizeof(replaces
));
1691 * If the updated ACL is empty, we can set attacl to null, and maybe even
1692 * avoid an update of the pg_attribute row. This is worth testing because
1693 * we'll come through here multiple times for any relation-level REVOKE,
1694 * even if there were never any column GRANTs. Note we are assuming that
1695 * the "default" ACL state for columns is empty.
1697 if (ACL_NUM(new_acl
) > 0)
1699 values
[Anum_pg_attribute_attacl
- 1] = PointerGetDatum(new_acl
);
1704 nulls
[Anum_pg_attribute_attacl
- 1] = true;
1705 need_update
= !isNull
;
1707 replaces
[Anum_pg_attribute_attacl
- 1] = true;
1711 newtuple
= heap_modify_tuple(attr_tuple
, RelationGetDescr(attRelation
),
1712 values
, nulls
, replaces
);
1714 CatalogTupleUpdate(attRelation
, &newtuple
->t_self
, newtuple
);
1716 /* Update initial privileges for extensions */
1717 recordExtensionInitPriv(relOid
, RelationRelationId
, attnum
,
1718 ACL_NUM(new_acl
) > 0 ? new_acl
: NULL
);
1720 /* Update the shared dependency ACL info */
1721 updateAclDependencies(RelationRelationId
, relOid
, attnum
,
1723 noldmembers
, oldmembers
,
1724 nnewmembers
, newmembers
);
1729 ReleaseSysCache(attr_tuple
);
1733 * This processes both sequences and non-sequences.
1736 ExecGrant_Relation(InternalGrant
*istmt
)
1739 Relation attRelation
;
1742 relation
= table_open(RelationRelationId
, RowExclusiveLock
);
1743 attRelation
= table_open(AttributeRelationId
, RowExclusiveLock
);
1745 foreach(cell
, istmt
->objects
)
1747 Oid relOid
= lfirst_oid(cell
);
1749 Form_pg_class pg_class_tuple
;
1751 AclMode this_privileges
;
1752 AclMode
*col_privileges
;
1753 int num_col_privileges
;
1754 bool have_col_privileges
;
1761 ListCell
*cell_colprivs
;
1763 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(relOid
));
1764 if (!HeapTupleIsValid(tuple
))
1765 elog(ERROR
, "cache lookup failed for relation %u", relOid
);
1766 pg_class_tuple
= (Form_pg_class
) GETSTRUCT(tuple
);
1768 /* Not sensible to grant on an index */
1769 if (pg_class_tuple
->relkind
== RELKIND_INDEX
||
1770 pg_class_tuple
->relkind
== RELKIND_PARTITIONED_INDEX
)
1772 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1773 errmsg("\"%s\" is an index",
1774 NameStr(pg_class_tuple
->relname
))));
1776 /* Composite types aren't tables either */
1777 if (pg_class_tuple
->relkind
== RELKIND_COMPOSITE_TYPE
)
1779 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1780 errmsg("\"%s\" is a composite type",
1781 NameStr(pg_class_tuple
->relname
))));
1783 /* Used GRANT SEQUENCE on a non-sequence? */
1784 if (istmt
->objtype
== OBJECT_SEQUENCE
&&
1785 pg_class_tuple
->relkind
!= RELKIND_SEQUENCE
)
1787 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1788 errmsg("\"%s\" is not a sequence",
1789 NameStr(pg_class_tuple
->relname
))));
1791 /* Adjust the default permissions based on object type */
1792 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
1794 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
)
1795 this_privileges
= ACL_ALL_RIGHTS_SEQUENCE
;
1797 this_privileges
= ACL_ALL_RIGHTS_RELATION
;
1800 this_privileges
= istmt
->privileges
;
1803 * The GRANT TABLE syntax can be used for sequences and non-sequences,
1804 * so we have to look at the relkind to determine the supported
1805 * permissions. The OR of table and sequence permissions were already
1808 if (istmt
->objtype
== OBJECT_TABLE
)
1810 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
)
1813 * For backward compatibility, just throw a warning for
1814 * invalid sequence permissions when using the non-sequence
1817 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_SEQUENCE
))
1820 * Mention the object name because the user needs to know
1821 * which operations succeeded. This is required because
1822 * WARNING allows the command to continue.
1825 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1826 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
1827 NameStr(pg_class_tuple
->relname
))));
1828 this_privileges
&= (AclMode
) ACL_ALL_RIGHTS_SEQUENCE
;
1833 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_RELATION
))
1836 * USAGE is the only permission supported by sequences but
1837 * not by non-sequences. Don't mention the object name
1838 * because we didn't in the combined TABLE | SEQUENCE
1842 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
1843 errmsg("invalid privilege type %s for table",
1850 * Set up array in which we'll accumulate any column privilege bits
1851 * that need modification. The array is indexed such that entry [0]
1852 * corresponds to FirstLowInvalidHeapAttributeNumber.
1854 num_col_privileges
= pg_class_tuple
->relnatts
- FirstLowInvalidHeapAttributeNumber
+ 1;
1855 col_privileges
= (AclMode
*) palloc0(num_col_privileges
* sizeof(AclMode
));
1856 have_col_privileges
= false;
1859 * If we are revoking relation privileges that are also column
1860 * privileges, we must implicitly revoke them from each column too,
1861 * per SQL spec. (We don't need to implicitly add column privileges
1862 * during GRANT because the permissions-checking code always checks
1863 * both relation and per-column privileges.)
1865 if (!istmt
->is_grant
&&
1866 (this_privileges
& ACL_ALL_RIGHTS_COLUMN
) != 0)
1868 expand_all_col_privileges(relOid
, pg_class_tuple
,
1869 this_privileges
& ACL_ALL_RIGHTS_COLUMN
,
1871 num_col_privileges
);
1872 have_col_privileges
= true;
1876 * Get owner ID and working copy of existing ACL. If there's no ACL,
1877 * substitute the proper default.
1879 ownerId
= pg_class_tuple
->relowner
;
1880 aclDatum
= SysCacheGetAttr(RELOID
, tuple
, Anum_pg_class_relacl
,
1884 switch (pg_class_tuple
->relkind
)
1886 case RELKIND_SEQUENCE
:
1887 old_acl
= acldefault(OBJECT_SEQUENCE
, ownerId
);
1890 old_acl
= acldefault(OBJECT_TABLE
, ownerId
);
1893 /* There are no old member roles according to the catalogs */
1899 old_acl
= DatumGetAclPCopy(aclDatum
);
1900 /* Get the roles mentioned in the existing ACL */
1901 noldmembers
= aclmembers(old_acl
, &oldmembers
);
1904 /* Need an extra copy of original rel ACL for column handling */
1905 old_rel_acl
= aclcopy(old_acl
);
1908 * Handle relation-level privileges, if any were specified
1910 if (this_privileges
!= ACL_NO_RIGHTS
)
1912 AclMode avail_goptions
;
1916 Datum values
[Natts_pg_class
];
1917 bool nulls
[Natts_pg_class
];
1918 bool replaces
[Natts_pg_class
];
1923 /* Determine ID to do the grant as, and available grant options */
1924 select_best_grantor(GetUserId(), this_privileges
,
1926 &grantorId
, &avail_goptions
);
1928 switch (pg_class_tuple
->relkind
)
1930 case RELKIND_SEQUENCE
:
1931 objtype
= OBJECT_SEQUENCE
;
1934 objtype
= OBJECT_TABLE
;
1939 * Restrict the privileges to what we can actually grant, and emit
1940 * the standards-mandated warning and error messages.
1943 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
1944 istmt
->all_privs
, this_privileges
,
1945 relOid
, grantorId
, objtype
,
1946 NameStr(pg_class_tuple
->relname
),
1952 new_acl
= merge_acl_with_grant(old_acl
,
1954 istmt
->grant_option
,
1962 * We need the members of both old and new ACLs so we can correct
1963 * the shared dependency information.
1965 nnewmembers
= aclmembers(new_acl
, &newmembers
);
1967 /* finished building new ACL value, now insert it */
1968 MemSet(values
, 0, sizeof(values
));
1969 MemSet(nulls
, false, sizeof(nulls
));
1970 MemSet(replaces
, false, sizeof(replaces
));
1972 replaces
[Anum_pg_class_relacl
- 1] = true;
1973 values
[Anum_pg_class_relacl
- 1] = PointerGetDatum(new_acl
);
1975 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
),
1976 values
, nulls
, replaces
);
1978 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
1980 /* Update initial privileges for extensions */
1981 recordExtensionInitPriv(relOid
, RelationRelationId
, 0, new_acl
);
1983 /* Update the shared dependency ACL info */
1984 updateAclDependencies(RelationRelationId
, relOid
, 0,
1986 noldmembers
, oldmembers
,
1987 nnewmembers
, newmembers
);
1993 * Handle column-level privileges, if any were specified or implied.
1994 * We first expand the user-specified column privileges into the
1995 * array, and then iterate over all nonempty array entries.
1997 foreach(cell_colprivs
, istmt
->col_privs
)
1999 AccessPriv
*col_privs
= (AccessPriv
*) lfirst(cell_colprivs
);
2001 if (col_privs
->priv_name
== NULL
)
2002 this_privileges
= ACL_ALL_RIGHTS_COLUMN
;
2004 this_privileges
= string_to_privilege(col_privs
->priv_name
);
2006 if (this_privileges
& ~((AclMode
) ACL_ALL_RIGHTS_COLUMN
))
2008 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
2009 errmsg("invalid privilege type %s for column",
2010 privilege_to_string(this_privileges
))));
2012 if (pg_class_tuple
->relkind
== RELKIND_SEQUENCE
&&
2013 this_privileges
& ~((AclMode
) ACL_SELECT
))
2016 * The only column privilege allowed on sequences is SELECT.
2017 * This is a warning not error because we do it that way for
2018 * relation-level privileges.
2021 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
2022 errmsg("sequence \"%s\" only supports SELECT column privileges",
2023 NameStr(pg_class_tuple
->relname
))));
2025 this_privileges
&= (AclMode
) ACL_SELECT
;
2028 expand_col_privileges(col_privs
->cols
, relOid
,
2031 num_col_privileges
);
2032 have_col_privileges
= true;
2035 if (have_col_privileges
)
2039 for (i
= 0; i
< num_col_privileges
; i
++)
2041 if (col_privileges
[i
] == ACL_NO_RIGHTS
)
2043 ExecGrant_Attribute(istmt
,
2045 NameStr(pg_class_tuple
->relname
),
2046 i
+ FirstLowInvalidHeapAttributeNumber
,
2055 pfree(col_privileges
);
2057 ReleaseSysCache(tuple
);
2059 /* prevent error when processing duplicate objects */
2060 CommandCounterIncrement();
2063 table_close(attRelation
, RowExclusiveLock
);
2064 table_close(relation
, RowExclusiveLock
);
2068 ExecGrant_Database(InternalGrant
*istmt
)
2073 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2074 istmt
->privileges
= ACL_ALL_RIGHTS_DATABASE
;
2076 relation
= table_open(DatabaseRelationId
, RowExclusiveLock
);
2078 foreach(cell
, istmt
->objects
)
2080 Oid datId
= lfirst_oid(cell
);
2081 Form_pg_database pg_database_tuple
;
2084 AclMode avail_goptions
;
2085 AclMode this_privileges
;
2091 Datum values
[Natts_pg_database
];
2092 bool nulls
[Natts_pg_database
];
2093 bool replaces
[Natts_pg_database
];
2100 tuple
= SearchSysCache1(DATABASEOID
, ObjectIdGetDatum(datId
));
2101 if (!HeapTupleIsValid(tuple
))
2102 elog(ERROR
, "cache lookup failed for database %u", datId
);
2104 pg_database_tuple
= (Form_pg_database
) GETSTRUCT(tuple
);
2107 * Get owner ID and working copy of existing ACL. If there's no ACL,
2108 * substitute the proper default.
2110 ownerId
= pg_database_tuple
->datdba
;
2111 aclDatum
= heap_getattr(tuple
, Anum_pg_database_datacl
,
2112 RelationGetDescr(relation
), &isNull
);
2115 old_acl
= acldefault(OBJECT_DATABASE
, ownerId
);
2116 /* There are no old member roles according to the catalogs */
2122 old_acl
= DatumGetAclPCopy(aclDatum
);
2123 /* Get the roles mentioned in the existing ACL */
2124 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2127 /* Determine ID to do the grant as, and available grant options */
2128 select_best_grantor(GetUserId(), istmt
->privileges
,
2130 &grantorId
, &avail_goptions
);
2133 * Restrict the privileges to what we can actually grant, and emit the
2134 * standards-mandated warning and error messages.
2137 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2138 istmt
->all_privs
, istmt
->privileges
,
2139 datId
, grantorId
, OBJECT_DATABASE
,
2140 NameStr(pg_database_tuple
->datname
),
2146 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2147 istmt
->grant_option
, istmt
->behavior
,
2148 istmt
->grantees
, this_privileges
,
2149 grantorId
, ownerId
);
2152 * We need the members of both old and new ACLs so we can correct the
2153 * shared dependency information.
2155 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2157 /* finished building new ACL value, now insert it */
2158 MemSet(values
, 0, sizeof(values
));
2159 MemSet(nulls
, false, sizeof(nulls
));
2160 MemSet(replaces
, false, sizeof(replaces
));
2162 replaces
[Anum_pg_database_datacl
- 1] = true;
2163 values
[Anum_pg_database_datacl
- 1] = PointerGetDatum(new_acl
);
2165 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
2168 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2170 /* Update the shared dependency ACL info */
2171 updateAclDependencies(DatabaseRelationId
, pg_database_tuple
->oid
, 0,
2173 noldmembers
, oldmembers
,
2174 nnewmembers
, newmembers
);
2176 ReleaseSysCache(tuple
);
2180 /* prevent error when processing duplicate objects */
2181 CommandCounterIncrement();
2184 table_close(relation
, RowExclusiveLock
);
2188 ExecGrant_Fdw(InternalGrant
*istmt
)
2193 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2194 istmt
->privileges
= ACL_ALL_RIGHTS_FDW
;
2196 relation
= table_open(ForeignDataWrapperRelationId
, RowExclusiveLock
);
2198 foreach(cell
, istmt
->objects
)
2200 Oid fdwid
= lfirst_oid(cell
);
2201 Form_pg_foreign_data_wrapper pg_fdw_tuple
;
2204 AclMode avail_goptions
;
2205 AclMode this_privileges
;
2212 Datum values
[Natts_pg_foreign_data_wrapper
];
2213 bool nulls
[Natts_pg_foreign_data_wrapper
];
2214 bool replaces
[Natts_pg_foreign_data_wrapper
];
2220 tuple
= SearchSysCache1(FOREIGNDATAWRAPPEROID
,
2221 ObjectIdGetDatum(fdwid
));
2222 if (!HeapTupleIsValid(tuple
))
2223 elog(ERROR
, "cache lookup failed for foreign-data wrapper %u", fdwid
);
2225 pg_fdw_tuple
= (Form_pg_foreign_data_wrapper
) GETSTRUCT(tuple
);
2228 * Get owner ID and working copy of existing ACL. If there's no ACL,
2229 * substitute the proper default.
2231 ownerId
= pg_fdw_tuple
->fdwowner
;
2232 aclDatum
= SysCacheGetAttr(FOREIGNDATAWRAPPEROID
, tuple
,
2233 Anum_pg_foreign_data_wrapper_fdwacl
,
2237 old_acl
= acldefault(OBJECT_FDW
, ownerId
);
2238 /* There are no old member roles according to the catalogs */
2244 old_acl
= DatumGetAclPCopy(aclDatum
);
2245 /* Get the roles mentioned in the existing ACL */
2246 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2249 /* Determine ID to do the grant as, and available grant options */
2250 select_best_grantor(GetUserId(), istmt
->privileges
,
2252 &grantorId
, &avail_goptions
);
2255 * Restrict the privileges to what we can actually grant, and emit the
2256 * standards-mandated warning and error messages.
2259 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2260 istmt
->all_privs
, istmt
->privileges
,
2261 fdwid
, grantorId
, OBJECT_FDW
,
2262 NameStr(pg_fdw_tuple
->fdwname
),
2268 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2269 istmt
->grant_option
, istmt
->behavior
,
2270 istmt
->grantees
, this_privileges
,
2271 grantorId
, ownerId
);
2274 * We need the members of both old and new ACLs so we can correct the
2275 * shared dependency information.
2277 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2279 /* finished building new ACL value, now insert it */
2280 MemSet(values
, 0, sizeof(values
));
2281 MemSet(nulls
, false, sizeof(nulls
));
2282 MemSet(replaces
, false, sizeof(replaces
));
2284 replaces
[Anum_pg_foreign_data_wrapper_fdwacl
- 1] = true;
2285 values
[Anum_pg_foreign_data_wrapper_fdwacl
- 1] = PointerGetDatum(new_acl
);
2287 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
2290 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2292 /* Update initial privileges for extensions */
2293 recordExtensionInitPriv(fdwid
, ForeignDataWrapperRelationId
, 0,
2296 /* Update the shared dependency ACL info */
2297 updateAclDependencies(ForeignDataWrapperRelationId
,
2298 pg_fdw_tuple
->oid
, 0,
2300 noldmembers
, oldmembers
,
2301 nnewmembers
, newmembers
);
2303 ReleaseSysCache(tuple
);
2307 /* prevent error when processing duplicate objects */
2308 CommandCounterIncrement();
2311 table_close(relation
, RowExclusiveLock
);
2315 ExecGrant_ForeignServer(InternalGrant
*istmt
)
2320 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2321 istmt
->privileges
= ACL_ALL_RIGHTS_FOREIGN_SERVER
;
2323 relation
= table_open(ForeignServerRelationId
, RowExclusiveLock
);
2325 foreach(cell
, istmt
->objects
)
2327 Oid srvid
= lfirst_oid(cell
);
2328 Form_pg_foreign_server pg_server_tuple
;
2331 AclMode avail_goptions
;
2332 AclMode this_privileges
;
2339 Datum values
[Natts_pg_foreign_server
];
2340 bool nulls
[Natts_pg_foreign_server
];
2341 bool replaces
[Natts_pg_foreign_server
];
2347 tuple
= SearchSysCache1(FOREIGNSERVEROID
, ObjectIdGetDatum(srvid
));
2348 if (!HeapTupleIsValid(tuple
))
2349 elog(ERROR
, "cache lookup failed for foreign server %u", srvid
);
2351 pg_server_tuple
= (Form_pg_foreign_server
) GETSTRUCT(tuple
);
2354 * Get owner ID and working copy of existing ACL. If there's no ACL,
2355 * substitute the proper default.
2357 ownerId
= pg_server_tuple
->srvowner
;
2358 aclDatum
= SysCacheGetAttr(FOREIGNSERVEROID
, tuple
,
2359 Anum_pg_foreign_server_srvacl
,
2363 old_acl
= acldefault(OBJECT_FOREIGN_SERVER
, ownerId
);
2364 /* There are no old member roles according to the catalogs */
2370 old_acl
= DatumGetAclPCopy(aclDatum
);
2371 /* Get the roles mentioned in the existing ACL */
2372 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2375 /* Determine ID to do the grant as, and available grant options */
2376 select_best_grantor(GetUserId(), istmt
->privileges
,
2378 &grantorId
, &avail_goptions
);
2381 * Restrict the privileges to what we can actually grant, and emit the
2382 * standards-mandated warning and error messages.
2385 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2386 istmt
->all_privs
, istmt
->privileges
,
2387 srvid
, grantorId
, OBJECT_FOREIGN_SERVER
,
2388 NameStr(pg_server_tuple
->srvname
),
2394 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2395 istmt
->grant_option
, istmt
->behavior
,
2396 istmt
->grantees
, this_privileges
,
2397 grantorId
, ownerId
);
2400 * We need the members of both old and new ACLs so we can correct the
2401 * shared dependency information.
2403 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2405 /* finished building new ACL value, now insert it */
2406 MemSet(values
, 0, sizeof(values
));
2407 MemSet(nulls
, false, sizeof(nulls
));
2408 MemSet(replaces
, false, sizeof(replaces
));
2410 replaces
[Anum_pg_foreign_server_srvacl
- 1] = true;
2411 values
[Anum_pg_foreign_server_srvacl
- 1] = PointerGetDatum(new_acl
);
2413 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
2416 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2418 /* Update initial privileges for extensions */
2419 recordExtensionInitPriv(srvid
, ForeignServerRelationId
, 0, new_acl
);
2421 /* Update the shared dependency ACL info */
2422 updateAclDependencies(ForeignServerRelationId
,
2423 pg_server_tuple
->oid
, 0,
2425 noldmembers
, oldmembers
,
2426 nnewmembers
, newmembers
);
2428 ReleaseSysCache(tuple
);
2432 /* prevent error when processing duplicate objects */
2433 CommandCounterIncrement();
2436 table_close(relation
, RowExclusiveLock
);
2440 ExecGrant_Function(InternalGrant
*istmt
)
2445 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2446 istmt
->privileges
= ACL_ALL_RIGHTS_FUNCTION
;
2448 relation
= table_open(ProcedureRelationId
, RowExclusiveLock
);
2450 foreach(cell
, istmt
->objects
)
2452 Oid funcId
= lfirst_oid(cell
);
2453 Form_pg_proc pg_proc_tuple
;
2456 AclMode avail_goptions
;
2457 AclMode this_privileges
;
2464 Datum values
[Natts_pg_proc
];
2465 bool nulls
[Natts_pg_proc
];
2466 bool replaces
[Natts_pg_proc
];
2472 tuple
= SearchSysCache1(PROCOID
, ObjectIdGetDatum(funcId
));
2473 if (!HeapTupleIsValid(tuple
))
2474 elog(ERROR
, "cache lookup failed for function %u", funcId
);
2476 pg_proc_tuple
= (Form_pg_proc
) GETSTRUCT(tuple
);
2479 * Get owner ID and working copy of existing ACL. If there's no ACL,
2480 * substitute the proper default.
2482 ownerId
= pg_proc_tuple
->proowner
;
2483 aclDatum
= SysCacheGetAttr(PROCOID
, tuple
, Anum_pg_proc_proacl
,
2487 old_acl
= acldefault(OBJECT_FUNCTION
, ownerId
);
2488 /* There are no old member roles according to the catalogs */
2494 old_acl
= DatumGetAclPCopy(aclDatum
);
2495 /* Get the roles mentioned in the existing ACL */
2496 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2499 /* Determine ID to do the grant as, and available grant options */
2500 select_best_grantor(GetUserId(), istmt
->privileges
,
2502 &grantorId
, &avail_goptions
);
2505 * Restrict the privileges to what we can actually grant, and emit the
2506 * standards-mandated warning and error messages.
2509 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2510 istmt
->all_privs
, istmt
->privileges
,
2511 funcId
, grantorId
, OBJECT_FUNCTION
,
2512 NameStr(pg_proc_tuple
->proname
),
2518 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2519 istmt
->grant_option
, istmt
->behavior
,
2520 istmt
->grantees
, this_privileges
,
2521 grantorId
, ownerId
);
2524 * We need the members of both old and new ACLs so we can correct the
2525 * shared dependency information.
2527 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2529 /* finished building new ACL value, now insert it */
2530 MemSet(values
, 0, sizeof(values
));
2531 MemSet(nulls
, false, sizeof(nulls
));
2532 MemSet(replaces
, false, sizeof(replaces
));
2534 replaces
[Anum_pg_proc_proacl
- 1] = true;
2535 values
[Anum_pg_proc_proacl
- 1] = PointerGetDatum(new_acl
);
2537 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
2540 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2542 /* Update initial privileges for extensions */
2543 recordExtensionInitPriv(funcId
, ProcedureRelationId
, 0, new_acl
);
2545 /* Update the shared dependency ACL info */
2546 updateAclDependencies(ProcedureRelationId
, funcId
, 0,
2548 noldmembers
, oldmembers
,
2549 nnewmembers
, newmembers
);
2551 ReleaseSysCache(tuple
);
2555 /* prevent error when processing duplicate objects */
2556 CommandCounterIncrement();
2559 table_close(relation
, RowExclusiveLock
);
2563 ExecGrant_Language(InternalGrant
*istmt
)
2568 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2569 istmt
->privileges
= ACL_ALL_RIGHTS_LANGUAGE
;
2571 relation
= table_open(LanguageRelationId
, RowExclusiveLock
);
2573 foreach(cell
, istmt
->objects
)
2575 Oid langId
= lfirst_oid(cell
);
2576 Form_pg_language pg_language_tuple
;
2579 AclMode avail_goptions
;
2580 AclMode this_privileges
;
2587 Datum values
[Natts_pg_language
];
2588 bool nulls
[Natts_pg_language
];
2589 bool replaces
[Natts_pg_language
];
2595 tuple
= SearchSysCache1(LANGOID
, ObjectIdGetDatum(langId
));
2596 if (!HeapTupleIsValid(tuple
))
2597 elog(ERROR
, "cache lookup failed for language %u", langId
);
2599 pg_language_tuple
= (Form_pg_language
) GETSTRUCT(tuple
);
2601 if (!pg_language_tuple
->lanpltrusted
)
2603 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
2604 errmsg("language \"%s\" is not trusted",
2605 NameStr(pg_language_tuple
->lanname
)),
2606 errdetail("GRANT and REVOKE are not allowed on untrusted languages, "
2607 "because only superusers can use untrusted languages.")));
2610 * Get owner ID and working copy of existing ACL. If there's no ACL,
2611 * substitute the proper default.
2613 ownerId
= pg_language_tuple
->lanowner
;
2614 aclDatum
= SysCacheGetAttr(LANGNAME
, tuple
, Anum_pg_language_lanacl
,
2618 old_acl
= acldefault(OBJECT_LANGUAGE
, ownerId
);
2619 /* There are no old member roles according to the catalogs */
2625 old_acl
= DatumGetAclPCopy(aclDatum
);
2626 /* Get the roles mentioned in the existing ACL */
2627 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2630 /* Determine ID to do the grant as, and available grant options */
2631 select_best_grantor(GetUserId(), istmt
->privileges
,
2633 &grantorId
, &avail_goptions
);
2636 * Restrict the privileges to what we can actually grant, and emit the
2637 * standards-mandated warning and error messages.
2640 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2641 istmt
->all_privs
, istmt
->privileges
,
2642 langId
, grantorId
, OBJECT_LANGUAGE
,
2643 NameStr(pg_language_tuple
->lanname
),
2649 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2650 istmt
->grant_option
, istmt
->behavior
,
2651 istmt
->grantees
, this_privileges
,
2652 grantorId
, ownerId
);
2655 * We need the members of both old and new ACLs so we can correct the
2656 * shared dependency information.
2658 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2660 /* finished building new ACL value, now insert it */
2661 MemSet(values
, 0, sizeof(values
));
2662 MemSet(nulls
, false, sizeof(nulls
));
2663 MemSet(replaces
, false, sizeof(replaces
));
2665 replaces
[Anum_pg_language_lanacl
- 1] = true;
2666 values
[Anum_pg_language_lanacl
- 1] = PointerGetDatum(new_acl
);
2668 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
2671 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2673 /* Update initial privileges for extensions */
2674 recordExtensionInitPriv(langId
, LanguageRelationId
, 0, new_acl
);
2676 /* Update the shared dependency ACL info */
2677 updateAclDependencies(LanguageRelationId
, pg_language_tuple
->oid
, 0,
2679 noldmembers
, oldmembers
,
2680 nnewmembers
, newmembers
);
2682 ReleaseSysCache(tuple
);
2686 /* prevent error when processing duplicate objects */
2687 CommandCounterIncrement();
2690 table_close(relation
, RowExclusiveLock
);
2694 ExecGrant_Largeobject(InternalGrant
*istmt
)
2699 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2700 istmt
->privileges
= ACL_ALL_RIGHTS_LARGEOBJECT
;
2702 relation
= table_open(LargeObjectMetadataRelationId
,
2705 foreach(cell
, istmt
->objects
)
2707 Oid loid
= lfirst_oid(cell
);
2708 Form_pg_largeobject_metadata form_lo_meta
;
2709 char loname
[NAMEDATALEN
];
2712 AclMode avail_goptions
;
2713 AclMode this_privileges
;
2719 Datum values
[Natts_pg_largeobject_metadata
];
2720 bool nulls
[Natts_pg_largeobject_metadata
];
2721 bool replaces
[Natts_pg_largeobject_metadata
];
2726 ScanKeyData entry
[1];
2730 /* There's no syscache for pg_largeobject_metadata */
2731 ScanKeyInit(&entry
[0],
2732 Anum_pg_largeobject_metadata_oid
,
2733 BTEqualStrategyNumber
, F_OIDEQ
,
2734 ObjectIdGetDatum(loid
));
2736 scan
= systable_beginscan(relation
,
2737 LargeObjectMetadataOidIndexId
, true,
2740 tuple
= systable_getnext(scan
);
2741 if (!HeapTupleIsValid(tuple
))
2742 elog(ERROR
, "could not find tuple for large object %u", loid
);
2744 form_lo_meta
= (Form_pg_largeobject_metadata
) GETSTRUCT(tuple
);
2747 * Get owner ID and working copy of existing ACL. If there's no ACL,
2748 * substitute the proper default.
2750 ownerId
= form_lo_meta
->lomowner
;
2751 aclDatum
= heap_getattr(tuple
,
2752 Anum_pg_largeobject_metadata_lomacl
,
2753 RelationGetDescr(relation
), &isNull
);
2756 old_acl
= acldefault(OBJECT_LARGEOBJECT
, ownerId
);
2757 /* There are no old member roles according to the catalogs */
2763 old_acl
= DatumGetAclPCopy(aclDatum
);
2764 /* Get the roles mentioned in the existing ACL */
2765 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2768 /* Determine ID to do the grant as, and available grant options */
2769 select_best_grantor(GetUserId(), istmt
->privileges
,
2771 &grantorId
, &avail_goptions
);
2774 * Restrict the privileges to what we can actually grant, and emit the
2775 * standards-mandated warning and error messages.
2777 snprintf(loname
, sizeof(loname
), "large object %u", loid
);
2779 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2780 istmt
->all_privs
, istmt
->privileges
,
2781 loid
, grantorId
, OBJECT_LARGEOBJECT
,
2787 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2788 istmt
->grant_option
, istmt
->behavior
,
2789 istmt
->grantees
, this_privileges
,
2790 grantorId
, ownerId
);
2793 * We need the members of both old and new ACLs so we can correct the
2794 * shared dependency information.
2796 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2798 /* finished building new ACL value, now insert it */
2799 MemSet(values
, 0, sizeof(values
));
2800 MemSet(nulls
, false, sizeof(nulls
));
2801 MemSet(replaces
, false, sizeof(replaces
));
2803 replaces
[Anum_pg_largeobject_metadata_lomacl
- 1] = true;
2804 values
[Anum_pg_largeobject_metadata_lomacl
- 1]
2805 = PointerGetDatum(new_acl
);
2807 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
),
2808 values
, nulls
, replaces
);
2810 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2812 /* Update initial privileges for extensions */
2813 recordExtensionInitPriv(loid
, LargeObjectRelationId
, 0, new_acl
);
2815 /* Update the shared dependency ACL info */
2816 updateAclDependencies(LargeObjectRelationId
,
2817 form_lo_meta
->oid
, 0,
2819 noldmembers
, oldmembers
,
2820 nnewmembers
, newmembers
);
2822 systable_endscan(scan
);
2826 /* prevent error when processing duplicate objects */
2827 CommandCounterIncrement();
2830 table_close(relation
, RowExclusiveLock
);
2834 ExecGrant_Namespace(InternalGrant
*istmt
)
2839 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2840 istmt
->privileges
= ACL_ALL_RIGHTS_SCHEMA
;
2842 relation
= table_open(NamespaceRelationId
, RowExclusiveLock
);
2844 foreach(cell
, istmt
->objects
)
2846 Oid nspid
= lfirst_oid(cell
);
2847 Form_pg_namespace pg_namespace_tuple
;
2850 AclMode avail_goptions
;
2851 AclMode this_privileges
;
2858 Datum values
[Natts_pg_namespace
];
2859 bool nulls
[Natts_pg_namespace
];
2860 bool replaces
[Natts_pg_namespace
];
2866 tuple
= SearchSysCache1(NAMESPACEOID
, ObjectIdGetDatum(nspid
));
2867 if (!HeapTupleIsValid(tuple
))
2868 elog(ERROR
, "cache lookup failed for namespace %u", nspid
);
2870 pg_namespace_tuple
= (Form_pg_namespace
) GETSTRUCT(tuple
);
2873 * Get owner ID and working copy of existing ACL. If there's no ACL,
2874 * substitute the proper default.
2876 ownerId
= pg_namespace_tuple
->nspowner
;
2877 aclDatum
= SysCacheGetAttr(NAMESPACENAME
, tuple
,
2878 Anum_pg_namespace_nspacl
,
2882 old_acl
= acldefault(OBJECT_SCHEMA
, ownerId
);
2883 /* There are no old member roles according to the catalogs */
2889 old_acl
= DatumGetAclPCopy(aclDatum
);
2890 /* Get the roles mentioned in the existing ACL */
2891 noldmembers
= aclmembers(old_acl
, &oldmembers
);
2894 /* Determine ID to do the grant as, and available grant options */
2895 select_best_grantor(GetUserId(), istmt
->privileges
,
2897 &grantorId
, &avail_goptions
);
2900 * Restrict the privileges to what we can actually grant, and emit the
2901 * standards-mandated warning and error messages.
2904 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
2905 istmt
->all_privs
, istmt
->privileges
,
2906 nspid
, grantorId
, OBJECT_SCHEMA
,
2907 NameStr(pg_namespace_tuple
->nspname
),
2913 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
2914 istmt
->grant_option
, istmt
->behavior
,
2915 istmt
->grantees
, this_privileges
,
2916 grantorId
, ownerId
);
2919 * We need the members of both old and new ACLs so we can correct the
2920 * shared dependency information.
2922 nnewmembers
= aclmembers(new_acl
, &newmembers
);
2924 /* finished building new ACL value, now insert it */
2925 MemSet(values
, 0, sizeof(values
));
2926 MemSet(nulls
, false, sizeof(nulls
));
2927 MemSet(replaces
, false, sizeof(replaces
));
2929 replaces
[Anum_pg_namespace_nspacl
- 1] = true;
2930 values
[Anum_pg_namespace_nspacl
- 1] = PointerGetDatum(new_acl
);
2932 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
2935 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
2937 /* Update initial privileges for extensions */
2938 recordExtensionInitPriv(nspid
, NamespaceRelationId
, 0, new_acl
);
2940 /* Update the shared dependency ACL info */
2941 updateAclDependencies(NamespaceRelationId
, pg_namespace_tuple
->oid
, 0,
2943 noldmembers
, oldmembers
,
2944 nnewmembers
, newmembers
);
2946 ReleaseSysCache(tuple
);
2950 /* prevent error when processing duplicate objects */
2951 CommandCounterIncrement();
2954 table_close(relation
, RowExclusiveLock
);
2958 ExecGrant_Tablespace(InternalGrant
*istmt
)
2963 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
2964 istmt
->privileges
= ACL_ALL_RIGHTS_TABLESPACE
;
2966 relation
= table_open(TableSpaceRelationId
, RowExclusiveLock
);
2968 foreach(cell
, istmt
->objects
)
2970 Oid tblId
= lfirst_oid(cell
);
2971 Form_pg_tablespace pg_tablespace_tuple
;
2974 AclMode avail_goptions
;
2975 AclMode this_privileges
;
2981 Datum values
[Natts_pg_tablespace
];
2982 bool nulls
[Natts_pg_tablespace
];
2983 bool replaces
[Natts_pg_tablespace
];
2990 /* Search syscache for pg_tablespace */
2991 tuple
= SearchSysCache1(TABLESPACEOID
, ObjectIdGetDatum(tblId
));
2992 if (!HeapTupleIsValid(tuple
))
2993 elog(ERROR
, "cache lookup failed for tablespace %u", tblId
);
2995 pg_tablespace_tuple
= (Form_pg_tablespace
) GETSTRUCT(tuple
);
2998 * Get owner ID and working copy of existing ACL. If there's no ACL,
2999 * substitute the proper default.
3001 ownerId
= pg_tablespace_tuple
->spcowner
;
3002 aclDatum
= heap_getattr(tuple
, Anum_pg_tablespace_spcacl
,
3003 RelationGetDescr(relation
), &isNull
);
3006 old_acl
= acldefault(OBJECT_TABLESPACE
, ownerId
);
3007 /* There are no old member roles according to the catalogs */
3013 old_acl
= DatumGetAclPCopy(aclDatum
);
3014 /* Get the roles mentioned in the existing ACL */
3015 noldmembers
= aclmembers(old_acl
, &oldmembers
);
3018 /* Determine ID to do the grant as, and available grant options */
3019 select_best_grantor(GetUserId(), istmt
->privileges
,
3021 &grantorId
, &avail_goptions
);
3024 * Restrict the privileges to what we can actually grant, and emit the
3025 * standards-mandated warning and error messages.
3028 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
3029 istmt
->all_privs
, istmt
->privileges
,
3030 tblId
, grantorId
, OBJECT_TABLESPACE
,
3031 NameStr(pg_tablespace_tuple
->spcname
),
3037 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
3038 istmt
->grant_option
, istmt
->behavior
,
3039 istmt
->grantees
, this_privileges
,
3040 grantorId
, ownerId
);
3043 * We need the members of both old and new ACLs so we can correct the
3044 * shared dependency information.
3046 nnewmembers
= aclmembers(new_acl
, &newmembers
);
3048 /* finished building new ACL value, now insert it */
3049 MemSet(values
, 0, sizeof(values
));
3050 MemSet(nulls
, false, sizeof(nulls
));
3051 MemSet(replaces
, false, sizeof(replaces
));
3053 replaces
[Anum_pg_tablespace_spcacl
- 1] = true;
3054 values
[Anum_pg_tablespace_spcacl
- 1] = PointerGetDatum(new_acl
);
3056 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
3059 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
3061 /* Update the shared dependency ACL info */
3062 updateAclDependencies(TableSpaceRelationId
, tblId
, 0,
3064 noldmembers
, oldmembers
,
3065 nnewmembers
, newmembers
);
3067 ReleaseSysCache(tuple
);
3070 /* prevent error when processing duplicate objects */
3071 CommandCounterIncrement();
3074 table_close(relation
, RowExclusiveLock
);
3078 ExecGrant_Type(InternalGrant
*istmt
)
3083 if (istmt
->all_privs
&& istmt
->privileges
== ACL_NO_RIGHTS
)
3084 istmt
->privileges
= ACL_ALL_RIGHTS_TYPE
;
3086 relation
= table_open(TypeRelationId
, RowExclusiveLock
);
3088 foreach(cell
, istmt
->objects
)
3090 Oid typId
= lfirst_oid(cell
);
3091 Form_pg_type pg_type_tuple
;
3094 AclMode avail_goptions
;
3095 AclMode this_privileges
;
3101 Datum values
[Natts_pg_type
];
3102 bool nulls
[Natts_pg_type
];
3103 bool replaces
[Natts_pg_type
];
3110 /* Search syscache for pg_type */
3111 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(typId
));
3112 if (!HeapTupleIsValid(tuple
))
3113 elog(ERROR
, "cache lookup failed for type %u", typId
);
3115 pg_type_tuple
= (Form_pg_type
) GETSTRUCT(tuple
);
3117 if (pg_type_tuple
->typelem
!= 0 && pg_type_tuple
->typlen
== -1)
3119 (errcode(ERRCODE_INVALID_GRANT_OPERATION
),
3120 errmsg("cannot set privileges of array types"),
3121 errhint("Set the privileges of the element type instead.")));
3123 /* Used GRANT DOMAIN on a non-domain? */
3124 if (istmt
->objtype
== OBJECT_DOMAIN
&&
3125 pg_type_tuple
->typtype
!= TYPTYPE_DOMAIN
)
3127 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
3128 errmsg("\"%s\" is not a domain",
3129 NameStr(pg_type_tuple
->typname
))));
3132 * Get owner ID and working copy of existing ACL. If there's no ACL,
3133 * substitute the proper default.
3135 ownerId
= pg_type_tuple
->typowner
;
3136 aclDatum
= heap_getattr(tuple
, Anum_pg_type_typacl
,
3137 RelationGetDescr(relation
), &isNull
);
3140 old_acl
= acldefault(istmt
->objtype
, ownerId
);
3141 /* There are no old member roles according to the catalogs */
3147 old_acl
= DatumGetAclPCopy(aclDatum
);
3148 /* Get the roles mentioned in the existing ACL */
3149 noldmembers
= aclmembers(old_acl
, &oldmembers
);
3152 /* Determine ID to do the grant as, and available grant options */
3153 select_best_grantor(GetUserId(), istmt
->privileges
,
3155 &grantorId
, &avail_goptions
);
3158 * Restrict the privileges to what we can actually grant, and emit the
3159 * standards-mandated warning and error messages.
3162 restrict_and_check_grant(istmt
->is_grant
, avail_goptions
,
3163 istmt
->all_privs
, istmt
->privileges
,
3164 typId
, grantorId
, OBJECT_TYPE
,
3165 NameStr(pg_type_tuple
->typname
),
3171 new_acl
= merge_acl_with_grant(old_acl
, istmt
->is_grant
,
3172 istmt
->grant_option
, istmt
->behavior
,
3173 istmt
->grantees
, this_privileges
,
3174 grantorId
, ownerId
);
3177 * We need the members of both old and new ACLs so we can correct the
3178 * shared dependency information.
3180 nnewmembers
= aclmembers(new_acl
, &newmembers
);
3182 /* finished building new ACL value, now insert it */
3183 MemSet(values
, 0, sizeof(values
));
3184 MemSet(nulls
, false, sizeof(nulls
));
3185 MemSet(replaces
, false, sizeof(replaces
));
3187 replaces
[Anum_pg_type_typacl
- 1] = true;
3188 values
[Anum_pg_type_typacl
- 1] = PointerGetDatum(new_acl
);
3190 newtuple
= heap_modify_tuple(tuple
, RelationGetDescr(relation
), values
,
3193 CatalogTupleUpdate(relation
, &newtuple
->t_self
, newtuple
);
3195 /* Update initial privileges for extensions */
3196 recordExtensionInitPriv(typId
, TypeRelationId
, 0, new_acl
);
3198 /* Update the shared dependency ACL info */
3199 updateAclDependencies(TypeRelationId
, typId
, 0,
3201 noldmembers
, oldmembers
,
3202 nnewmembers
, newmembers
);
3204 ReleaseSysCache(tuple
);
3207 /* prevent error when processing duplicate objects */
3208 CommandCounterIncrement();
3211 table_close(relation
, RowExclusiveLock
);
3216 string_to_privilege(const char *privname
)
3218 if (strcmp(privname
, "insert") == 0)
3220 if (strcmp(privname
, "select") == 0)
3222 if (strcmp(privname
, "update") == 0)
3224 if (strcmp(privname
, "delete") == 0)
3226 if (strcmp(privname
, "truncate") == 0)
3227 return ACL_TRUNCATE
;
3228 if (strcmp(privname
, "references") == 0)
3229 return ACL_REFERENCES
;
3230 if (strcmp(privname
, "trigger") == 0)
3232 if (strcmp(privname
, "execute") == 0)
3234 if (strcmp(privname
, "usage") == 0)
3236 if (strcmp(privname
, "create") == 0)
3238 if (strcmp(privname
, "temporary") == 0)
3239 return ACL_CREATE_TEMP
;
3240 if (strcmp(privname
, "temp") == 0)
3241 return ACL_CREATE_TEMP
;
3242 if (strcmp(privname
, "connect") == 0)
3244 if (strcmp(privname
, "rule") == 0)
3245 return 0; /* ignore old RULE privileges */
3247 (errcode(ERRCODE_SYNTAX_ERROR
),
3248 errmsg("unrecognized privilege type \"%s\"", privname
)));
3249 return 0; /* appease compiler */
3253 privilege_to_string(AclMode privilege
)
3267 case ACL_REFERENCES
:
3268 return "REFERENCES";
3277 case ACL_CREATE_TEMP
:
3282 elog(ERROR
, "unrecognized privilege: %d", (int) privilege
);
3284 return NULL
; /* appease compiler */
3288 * Standardized reporting of aclcheck permissions failures.
3290 * Note: we do not double-quote the %s's below, because many callers
3291 * supply strings that might be already quoted.
3294 aclcheck_error(AclResult aclerr
, ObjectType objtype
,
3295 const char *objectname
)
3300 /* no error, so return to caller */
3302 case ACLCHECK_NO_PRIV
:
3304 const char *msg
= "???";
3308 case OBJECT_AGGREGATE
:
3309 msg
= gettext_noop("permission denied for aggregate %s");
3311 case OBJECT_COLLATION
:
3312 msg
= gettext_noop("permission denied for collation %s");
3315 msg
= gettext_noop("permission denied for column %s");
3317 case OBJECT_CONVERSION
:
3318 msg
= gettext_noop("permission denied for conversion %s");
3320 case OBJECT_DATABASE
:
3321 msg
= gettext_noop("permission denied for database %s");
3324 msg
= gettext_noop("permission denied for domain %s");
3326 case OBJECT_EVENT_TRIGGER
:
3327 msg
= gettext_noop("permission denied for event trigger %s");
3329 case OBJECT_EXTENSION
:
3330 msg
= gettext_noop("permission denied for extension %s");
3333 msg
= gettext_noop("permission denied for foreign-data wrapper %s");
3335 case OBJECT_FOREIGN_SERVER
:
3336 msg
= gettext_noop("permission denied for foreign server %s");
3338 case OBJECT_FOREIGN_TABLE
:
3339 msg
= gettext_noop("permission denied for foreign table %s");
3341 case OBJECT_FUNCTION
:
3342 msg
= gettext_noop("permission denied for function %s");
3345 msg
= gettext_noop("permission denied for index %s");
3347 case OBJECT_LANGUAGE
:
3348 msg
= gettext_noop("permission denied for language %s");
3350 case OBJECT_LARGEOBJECT
:
3351 msg
= gettext_noop("permission denied for large object %s");
3353 case OBJECT_MATVIEW
:
3354 msg
= gettext_noop("permission denied for materialized view %s");
3356 case OBJECT_OPCLASS
:
3357 msg
= gettext_noop("permission denied for operator class %s");
3359 case OBJECT_OPERATOR
:
3360 msg
= gettext_noop("permission denied for operator %s");
3362 case OBJECT_OPFAMILY
:
3363 msg
= gettext_noop("permission denied for operator family %s");
3366 msg
= gettext_noop("permission denied for policy %s");
3368 case OBJECT_PROCEDURE
:
3369 msg
= gettext_noop("permission denied for procedure %s");
3371 case OBJECT_PUBLICATION
:
3372 msg
= gettext_noop("permission denied for publication %s");
3374 case OBJECT_ROUTINE
:
3375 msg
= gettext_noop("permission denied for routine %s");
3378 msg
= gettext_noop("permission denied for schema %s");
3380 case OBJECT_SEQUENCE
:
3381 msg
= gettext_noop("permission denied for sequence %s");
3383 case OBJECT_STATISTIC_EXT
:
3384 msg
= gettext_noop("permission denied for statistics object %s");
3386 case OBJECT_SUBSCRIPTION
:
3387 msg
= gettext_noop("permission denied for subscription %s");
3390 msg
= gettext_noop("permission denied for table %s");
3392 case OBJECT_TABLESPACE
:
3393 msg
= gettext_noop("permission denied for tablespace %s");
3395 case OBJECT_TSCONFIGURATION
:
3396 msg
= gettext_noop("permission denied for text search configuration %s");
3398 case OBJECT_TSDICTIONARY
:
3399 msg
= gettext_noop("permission denied for text search dictionary %s");
3402 msg
= gettext_noop("permission denied for type %s");
3405 msg
= gettext_noop("permission denied for view %s");
3407 /* these currently aren't used */
3408 case OBJECT_ACCESS_METHOD
:
3411 case OBJECT_ATTRIBUTE
:
3413 case OBJECT_DEFAULT
:
3415 case OBJECT_DOMCONSTRAINT
:
3416 case OBJECT_PUBLICATION_REL
:
3419 case OBJECT_TABCONSTRAINT
:
3420 case OBJECT_TRANSFORM
:
3421 case OBJECT_TRIGGER
:
3422 case OBJECT_TSPARSER
:
3423 case OBJECT_TSTEMPLATE
:
3424 case OBJECT_USER_MAPPING
:
3425 elog(ERROR
, "unsupported object type %d", objtype
);
3429 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
3430 errmsg(msg
, objectname
)));
3433 case ACLCHECK_NOT_OWNER
:
3435 const char *msg
= "???";
3439 case OBJECT_AGGREGATE
:
3440 msg
= gettext_noop("must be owner of aggregate %s");
3442 case OBJECT_COLLATION
:
3443 msg
= gettext_noop("must be owner of collation %s");
3445 case OBJECT_CONVERSION
:
3446 msg
= gettext_noop("must be owner of conversion %s");
3448 case OBJECT_DATABASE
:
3449 msg
= gettext_noop("must be owner of database %s");
3452 msg
= gettext_noop("must be owner of domain %s");
3454 case OBJECT_EVENT_TRIGGER
:
3455 msg
= gettext_noop("must be owner of event trigger %s");
3457 case OBJECT_EXTENSION
:
3458 msg
= gettext_noop("must be owner of extension %s");
3461 msg
= gettext_noop("must be owner of foreign-data wrapper %s");
3463 case OBJECT_FOREIGN_SERVER
:
3464 msg
= gettext_noop("must be owner of foreign server %s");
3466 case OBJECT_FOREIGN_TABLE
:
3467 msg
= gettext_noop("must be owner of foreign table %s");
3469 case OBJECT_FUNCTION
:
3470 msg
= gettext_noop("must be owner of function %s");
3473 msg
= gettext_noop("must be owner of index %s");
3475 case OBJECT_LANGUAGE
:
3476 msg
= gettext_noop("must be owner of language %s");
3478 case OBJECT_LARGEOBJECT
:
3479 msg
= gettext_noop("must be owner of large object %s");
3481 case OBJECT_MATVIEW
:
3482 msg
= gettext_noop("must be owner of materialized view %s");
3484 case OBJECT_OPCLASS
:
3485 msg
= gettext_noop("must be owner of operator class %s");
3487 case OBJECT_OPERATOR
:
3488 msg
= gettext_noop("must be owner of operator %s");
3490 case OBJECT_OPFAMILY
:
3491 msg
= gettext_noop("must be owner of operator family %s");
3493 case OBJECT_PROCEDURE
:
3494 msg
= gettext_noop("must be owner of procedure %s");
3496 case OBJECT_PUBLICATION
:
3497 msg
= gettext_noop("must be owner of publication %s");
3499 case OBJECT_ROUTINE
:
3500 msg
= gettext_noop("must be owner of routine %s");
3502 case OBJECT_SEQUENCE
:
3503 msg
= gettext_noop("must be owner of sequence %s");
3505 case OBJECT_SUBSCRIPTION
:
3506 msg
= gettext_noop("must be owner of subscription %s");
3509 msg
= gettext_noop("must be owner of table %s");
3512 msg
= gettext_noop("must be owner of type %s");
3515 msg
= gettext_noop("must be owner of view %s");
3518 msg
= gettext_noop("must be owner of schema %s");
3520 case OBJECT_STATISTIC_EXT
:
3521 msg
= gettext_noop("must be owner of statistics object %s");
3523 case OBJECT_TABLESPACE
:
3524 msg
= gettext_noop("must be owner of tablespace %s");
3526 case OBJECT_TSCONFIGURATION
:
3527 msg
= gettext_noop("must be owner of text search configuration %s");
3529 case OBJECT_TSDICTIONARY
:
3530 msg
= gettext_noop("must be owner of text search dictionary %s");
3534 * Special cases: For these, the error message talks
3535 * about "relation", because that's where the
3536 * ownership is attached. See also
3537 * check_object_ownership().
3542 case OBJECT_TABCONSTRAINT
:
3543 case OBJECT_TRIGGER
:
3544 msg
= gettext_noop("must be owner of relation %s");
3546 /* these currently aren't used */
3547 case OBJECT_ACCESS_METHOD
:
3550 case OBJECT_ATTRIBUTE
:
3552 case OBJECT_DEFAULT
:
3554 case OBJECT_DOMCONSTRAINT
:
3555 case OBJECT_PUBLICATION_REL
:
3557 case OBJECT_TRANSFORM
:
3558 case OBJECT_TSPARSER
:
3559 case OBJECT_TSTEMPLATE
:
3560 case OBJECT_USER_MAPPING
:
3561 elog(ERROR
, "unsupported object type %d", objtype
);
3565 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
3566 errmsg(msg
, objectname
)));
3570 elog(ERROR
, "unrecognized AclResult: %d", (int) aclerr
);
3577 aclcheck_error_col(AclResult aclerr
, ObjectType objtype
,
3578 const char *objectname
, const char *colname
)
3583 /* no error, so return to caller */
3585 case ACLCHECK_NO_PRIV
:
3587 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
3588 errmsg("permission denied for column \"%s\" of relation \"%s\"",
3589 colname
, objectname
)));
3591 case ACLCHECK_NOT_OWNER
:
3592 /* relation msg is OK since columns don't have separate owners */
3593 aclcheck_error(aclerr
, objtype
, objectname
);
3596 elog(ERROR
, "unrecognized AclResult: %d", (int) aclerr
);
3603 * Special common handling for types: use element type instead of array type,
3607 aclcheck_error_type(AclResult aclerr
, Oid typeOid
)
3609 Oid element_type
= get_element_type(typeOid
);
3611 aclcheck_error(aclerr
, OBJECT_TYPE
, format_type_be(element_type
? element_type
: typeOid
));
3616 * Relay for the various pg_*_mask routines depending on object kind
3619 pg_aclmask(ObjectType objtype
, Oid table_oid
, AttrNumber attnum
, Oid roleid
,
3620 AclMode mask
, AclMaskHow how
)
3626 pg_class_aclmask(table_oid
, roleid
, mask
, how
) |
3627 pg_attribute_aclmask(table_oid
, attnum
, roleid
, mask
, how
);
3629 case OBJECT_SEQUENCE
:
3630 return pg_class_aclmask(table_oid
, roleid
, mask
, how
);
3631 case OBJECT_DATABASE
:
3632 return pg_database_aclmask(table_oid
, roleid
, mask
, how
);
3633 case OBJECT_FUNCTION
:
3634 return pg_proc_aclmask(table_oid
, roleid
, mask
, how
);
3635 case OBJECT_LANGUAGE
:
3636 return pg_language_aclmask(table_oid
, roleid
, mask
, how
);
3637 case OBJECT_LARGEOBJECT
:
3638 return pg_largeobject_aclmask_snapshot(table_oid
, roleid
,
3641 return pg_namespace_aclmask(table_oid
, roleid
, mask
, how
);
3642 case OBJECT_STATISTIC_EXT
:
3643 elog(ERROR
, "grantable rights not supported for statistics objects");
3644 /* not reached, but keep compiler quiet */
3645 return ACL_NO_RIGHTS
;
3646 case OBJECT_TABLESPACE
:
3647 return pg_tablespace_aclmask(table_oid
, roleid
, mask
, how
);
3649 return pg_foreign_data_wrapper_aclmask(table_oid
, roleid
, mask
, how
);
3650 case OBJECT_FOREIGN_SERVER
:
3651 return pg_foreign_server_aclmask(table_oid
, roleid
, mask
, how
);
3652 case OBJECT_EVENT_TRIGGER
:
3653 elog(ERROR
, "grantable rights not supported for event triggers");
3654 /* not reached, but keep compiler quiet */
3655 return ACL_NO_RIGHTS
;
3657 return pg_type_aclmask(table_oid
, roleid
, mask
, how
);
3659 elog(ERROR
, "unrecognized objtype: %d",
3661 /* not reached, but keep compiler quiet */
3662 return ACL_NO_RIGHTS
;
3667 /* ****************************************************************
3668 * Exported routines for examining a user's privileges for various objects
3670 * See aclmask() for a description of the common API for these functions.
3672 * Note: we give lookup failure the full ereport treatment because the
3673 * has_xxx_privilege() family of functions allow users to pass any random
3674 * OID to these functions.
3675 * ****************************************************************
3679 * Exported routine for examining a user's privileges for a column
3681 * Note: this considers only privileges granted specifically on the column.
3682 * It is caller's responsibility to take relation-level privileges into account
3683 * as appropriate. (For the same reason, we have no special case for
3684 * superuser-ness here.)
3687 pg_attribute_aclmask(Oid table_oid
, AttrNumber attnum
, Oid roleid
,
3688 AclMode mask
, AclMaskHow how
)
3691 HeapTuple classTuple
;
3693 Form_pg_class classForm
;
3694 Form_pg_attribute attributeForm
;
3701 * First, get the column's ACL from its pg_attribute entry
3703 attTuple
= SearchSysCache2(ATTNUM
,
3704 ObjectIdGetDatum(table_oid
),
3705 Int16GetDatum(attnum
));
3706 if (!HeapTupleIsValid(attTuple
))
3708 (errcode(ERRCODE_UNDEFINED_COLUMN
),
3709 errmsg("attribute %d of relation with OID %u does not exist",
3710 attnum
, table_oid
)));
3711 attributeForm
= (Form_pg_attribute
) GETSTRUCT(attTuple
);
3713 /* Throw error on dropped columns, too */
3714 if (attributeForm
->attisdropped
)
3716 (errcode(ERRCODE_UNDEFINED_COLUMN
),
3717 errmsg("attribute %d of relation with OID %u does not exist",
3718 attnum
, table_oid
)));
3720 aclDatum
= SysCacheGetAttr(ATTNUM
, attTuple
, Anum_pg_attribute_attacl
,
3724 * Here we hard-wire knowledge that the default ACL for a column grants no
3725 * privileges, so that we can fall out quickly in the very common case
3726 * where attacl is null.
3730 ReleaseSysCache(attTuple
);
3735 * Must get the relation's ownerId from pg_class. Since we already found
3736 * a pg_attribute entry, the only likely reason for this to fail is that a
3737 * concurrent DROP of the relation committed since then (which could only
3738 * happen if we don't have lock on the relation). We prefer to report "no
3739 * privileges" rather than failing in such a case, so as to avoid unwanted
3740 * failures in has_column_privilege() tests.
3742 classTuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(table_oid
));
3743 if (!HeapTupleIsValid(classTuple
))
3745 ReleaseSysCache(attTuple
);
3748 classForm
= (Form_pg_class
) GETSTRUCT(classTuple
);
3750 ownerId
= classForm
->relowner
;
3752 ReleaseSysCache(classTuple
);
3754 /* detoast column's ACL if necessary */
3755 acl
= DatumGetAclP(aclDatum
);
3757 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3759 /* if we have a detoasted copy, free it */
3760 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3763 ReleaseSysCache(attTuple
);
3769 * Exported routine for examining a user's privileges for a table
3772 pg_class_aclmask(Oid table_oid
, Oid roleid
,
3773 AclMode mask
, AclMaskHow how
)
3777 Form_pg_class classForm
;
3784 * Must get the relation's tuple from pg_class
3786 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(table_oid
));
3787 if (!HeapTupleIsValid(tuple
))
3789 (errcode(ERRCODE_UNDEFINED_TABLE
),
3790 errmsg("relation with OID %u does not exist",
3792 classForm
= (Form_pg_class
) GETSTRUCT(tuple
);
3795 * Deny anyone permission to update a system catalog unless
3796 * pg_authid.rolsuper is set.
3798 * As of 7.4 we have some updatable system views; those shouldn't be
3799 * protected in this way. Assume the view rules can take care of
3800 * themselves. ACL_USAGE is if we ever have system sequences.
3802 if ((mask
& (ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
| ACL_TRUNCATE
| ACL_USAGE
)) &&
3803 IsSystemClass(table_oid
, classForm
) &&
3804 classForm
->relkind
!= RELKIND_VIEW
&&
3805 !superuser_arg(roleid
))
3806 mask
&= ~(ACL_INSERT
| ACL_UPDATE
| ACL_DELETE
| ACL_TRUNCATE
| ACL_USAGE
);
3809 * Otherwise, superusers bypass all permission-checking.
3811 if (superuser_arg(roleid
))
3813 ReleaseSysCache(tuple
);
3818 * Normal case: get the relation's ACL from pg_class
3820 ownerId
= classForm
->relowner
;
3822 aclDatum
= SysCacheGetAttr(RELOID
, tuple
, Anum_pg_class_relacl
,
3826 /* No ACL, so build default ACL */
3827 switch (classForm
->relkind
)
3829 case RELKIND_SEQUENCE
:
3830 acl
= acldefault(OBJECT_SEQUENCE
, ownerId
);
3833 acl
= acldefault(OBJECT_TABLE
, ownerId
);
3836 aclDatum
= (Datum
) 0;
3840 /* detoast rel's ACL if necessary */
3841 acl
= DatumGetAclP(aclDatum
);
3844 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3846 /* if we have a detoasted copy, free it */
3847 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3850 ReleaseSysCache(tuple
);
3856 * Exported routine for examining a user's privileges for a database
3859 pg_database_aclmask(Oid db_oid
, Oid roleid
,
3860 AclMode mask
, AclMaskHow how
)
3869 /* Superusers bypass all permission checking. */
3870 if (superuser_arg(roleid
))
3874 * Get the database's ACL from pg_database
3876 tuple
= SearchSysCache1(DATABASEOID
, ObjectIdGetDatum(db_oid
));
3877 if (!HeapTupleIsValid(tuple
))
3879 (errcode(ERRCODE_UNDEFINED_DATABASE
),
3880 errmsg("database with OID %u does not exist", db_oid
)));
3882 ownerId
= ((Form_pg_database
) GETSTRUCT(tuple
))->datdba
;
3884 aclDatum
= SysCacheGetAttr(DATABASEOID
, tuple
, Anum_pg_database_datacl
,
3888 /* No ACL, so build default ACL */
3889 acl
= acldefault(OBJECT_DATABASE
, ownerId
);
3890 aclDatum
= (Datum
) 0;
3894 /* detoast ACL if necessary */
3895 acl
= DatumGetAclP(aclDatum
);
3898 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3900 /* if we have a detoasted copy, free it */
3901 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3904 ReleaseSysCache(tuple
);
3910 * Exported routine for examining a user's privileges for a function
3913 pg_proc_aclmask(Oid proc_oid
, Oid roleid
,
3914 AclMode mask
, AclMaskHow how
)
3923 /* Superusers bypass all permission checking. */
3924 if (superuser_arg(roleid
))
3928 * Get the function's ACL from pg_proc
3930 tuple
= SearchSysCache1(PROCOID
, ObjectIdGetDatum(proc_oid
));
3931 if (!HeapTupleIsValid(tuple
))
3933 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
3934 errmsg("function with OID %u does not exist", proc_oid
)));
3936 ownerId
= ((Form_pg_proc
) GETSTRUCT(tuple
))->proowner
;
3938 aclDatum
= SysCacheGetAttr(PROCOID
, tuple
, Anum_pg_proc_proacl
,
3942 /* No ACL, so build default ACL */
3943 acl
= acldefault(OBJECT_FUNCTION
, ownerId
);
3944 aclDatum
= (Datum
) 0;
3948 /* detoast ACL if necessary */
3949 acl
= DatumGetAclP(aclDatum
);
3952 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
3954 /* if we have a detoasted copy, free it */
3955 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
3958 ReleaseSysCache(tuple
);
3964 * Exported routine for examining a user's privileges for a language
3967 pg_language_aclmask(Oid lang_oid
, Oid roleid
,
3968 AclMode mask
, AclMaskHow how
)
3977 /* Superusers bypass all permission checking. */
3978 if (superuser_arg(roleid
))
3982 * Get the language's ACL from pg_language
3984 tuple
= SearchSysCache1(LANGOID
, ObjectIdGetDatum(lang_oid
));
3985 if (!HeapTupleIsValid(tuple
))
3987 (errcode(ERRCODE_UNDEFINED_OBJECT
),
3988 errmsg("language with OID %u does not exist", lang_oid
)));
3990 ownerId
= ((Form_pg_language
) GETSTRUCT(tuple
))->lanowner
;
3992 aclDatum
= SysCacheGetAttr(LANGOID
, tuple
, Anum_pg_language_lanacl
,
3996 /* No ACL, so build default ACL */
3997 acl
= acldefault(OBJECT_LANGUAGE
, ownerId
);
3998 aclDatum
= (Datum
) 0;
4002 /* detoast ACL if necessary */
4003 acl
= DatumGetAclP(aclDatum
);
4006 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
4008 /* if we have a detoasted copy, free it */
4009 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
4012 ReleaseSysCache(tuple
);
4018 * Exported routine for examining a user's privileges for a largeobject
4020 * When a large object is opened for reading, it is opened relative to the
4021 * caller's snapshot, but when it is opened for writing, a current
4022 * MVCC snapshot will be used. See doc/src/sgml/lobj.sgml. This function
4023 * takes a snapshot argument so that the permissions check can be made
4024 * relative to the same snapshot that will be used to read the underlying
4025 * data. The caller will actually pass NULL for an instantaneous MVCC
4026 * snapshot, since all we do with the snapshot argument is pass it through
4027 * to systable_beginscan().
4030 pg_largeobject_aclmask_snapshot(Oid lobj_oid
, Oid roleid
,
4031 AclMode mask
, AclMaskHow how
,
4035 Relation pg_lo_meta
;
4036 ScanKeyData entry
[1];
4044 /* Superusers bypass all permission checking. */
4045 if (superuser_arg(roleid
))
4049 * Get the largeobject's ACL from pg_largeobject_metadata
4051 pg_lo_meta
= table_open(LargeObjectMetadataRelationId
,
4054 ScanKeyInit(&entry
[0],
4055 Anum_pg_largeobject_metadata_oid
,
4056 BTEqualStrategyNumber
, F_OIDEQ
,
4057 ObjectIdGetDatum(lobj_oid
));
4059 scan
= systable_beginscan(pg_lo_meta
,
4060 LargeObjectMetadataOidIndexId
, true,
4061 snapshot
, 1, entry
);
4063 tuple
= systable_getnext(scan
);
4064 if (!HeapTupleIsValid(tuple
))
4066 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4067 errmsg("large object %u does not exist", lobj_oid
)));
4069 ownerId
= ((Form_pg_largeobject_metadata
) GETSTRUCT(tuple
))->lomowner
;
4071 aclDatum
= heap_getattr(tuple
, Anum_pg_largeobject_metadata_lomacl
,
4072 RelationGetDescr(pg_lo_meta
), &isNull
);
4076 /* No ACL, so build default ACL */
4077 acl
= acldefault(OBJECT_LARGEOBJECT
, ownerId
);
4078 aclDatum
= (Datum
) 0;
4082 /* detoast ACL if necessary */
4083 acl
= DatumGetAclP(aclDatum
);
4086 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
4088 /* if we have a detoasted copy, free it */
4089 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
4092 systable_endscan(scan
);
4094 table_close(pg_lo_meta
, AccessShareLock
);
4100 * Exported routine for examining a user's privileges for a namespace
4103 pg_namespace_aclmask(Oid nsp_oid
, Oid roleid
,
4104 AclMode mask
, AclMaskHow how
)
4113 /* Superusers bypass all permission checking. */
4114 if (superuser_arg(roleid
))
4118 * If we have been assigned this namespace as a temp namespace, check to
4119 * make sure we have CREATE TEMP permission on the database, and if so act
4120 * as though we have all standard (but not GRANT OPTION) permissions on
4121 * the namespace. If we don't have CREATE TEMP, act as though we have
4122 * only USAGE (and not CREATE) rights.
4124 * This may seem redundant given the check in InitTempTableNamespace, but
4125 * it really isn't since current user ID may have changed since then. The
4126 * upshot of this behavior is that a SECURITY DEFINER function can create
4127 * temp tables that can then be accessed (if permission is granted) by
4128 * code in the same session that doesn't have permissions to create temp
4131 * XXX Would it be safe to ereport a special error message as
4132 * InitTempTableNamespace does? Returning zero here means we'll get a
4133 * generic "permission denied for schema pg_temp_N" message, which is not
4134 * remarkably user-friendly.
4136 if (isTempNamespace(nsp_oid
))
4138 if (pg_database_aclcheck(MyDatabaseId
, roleid
,
4139 ACL_CREATE_TEMP
) == ACLCHECK_OK
)
4140 return mask
& ACL_ALL_RIGHTS_SCHEMA
;
4142 return mask
& ACL_USAGE
;
4146 * Get the schema's ACL from pg_namespace
4148 tuple
= SearchSysCache1(NAMESPACEOID
, ObjectIdGetDatum(nsp_oid
));
4149 if (!HeapTupleIsValid(tuple
))
4151 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
4152 errmsg("schema with OID %u does not exist", nsp_oid
)));
4154 ownerId
= ((Form_pg_namespace
) GETSTRUCT(tuple
))->nspowner
;
4156 aclDatum
= SysCacheGetAttr(NAMESPACEOID
, tuple
, Anum_pg_namespace_nspacl
,
4160 /* No ACL, so build default ACL */
4161 acl
= acldefault(OBJECT_SCHEMA
, ownerId
);
4162 aclDatum
= (Datum
) 0;
4166 /* detoast ACL if necessary */
4167 acl
= DatumGetAclP(aclDatum
);
4170 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
4172 /* if we have a detoasted copy, free it */
4173 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
4176 ReleaseSysCache(tuple
);
4182 * Exported routine for examining a user's privileges for a tablespace
4185 pg_tablespace_aclmask(Oid spc_oid
, Oid roleid
,
4186 AclMode mask
, AclMaskHow how
)
4195 /* Superusers bypass all permission checking. */
4196 if (superuser_arg(roleid
))
4200 * Get the tablespace's ACL from pg_tablespace
4202 tuple
= SearchSysCache1(TABLESPACEOID
, ObjectIdGetDatum(spc_oid
));
4203 if (!HeapTupleIsValid(tuple
))
4205 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4206 errmsg("tablespace with OID %u does not exist", spc_oid
)));
4208 ownerId
= ((Form_pg_tablespace
) GETSTRUCT(tuple
))->spcowner
;
4210 aclDatum
= SysCacheGetAttr(TABLESPACEOID
, tuple
,
4211 Anum_pg_tablespace_spcacl
,
4216 /* No ACL, so build default ACL */
4217 acl
= acldefault(OBJECT_TABLESPACE
, ownerId
);
4218 aclDatum
= (Datum
) 0;
4222 /* detoast ACL if necessary */
4223 acl
= DatumGetAclP(aclDatum
);
4226 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
4228 /* if we have a detoasted copy, free it */
4229 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
4232 ReleaseSysCache(tuple
);
4238 * Exported routine for examining a user's privileges for a foreign
4242 pg_foreign_data_wrapper_aclmask(Oid fdw_oid
, Oid roleid
,
4243 AclMode mask
, AclMaskHow how
)
4252 Form_pg_foreign_data_wrapper fdwForm
;
4254 /* Bypass permission checks for superusers */
4255 if (superuser_arg(roleid
))
4259 * Must get the FDW's tuple from pg_foreign_data_wrapper
4261 tuple
= SearchSysCache1(FOREIGNDATAWRAPPEROID
, ObjectIdGetDatum(fdw_oid
));
4262 if (!HeapTupleIsValid(tuple
))
4264 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4265 errmsg("foreign-data wrapper with OID %u does not exist",
4267 fdwForm
= (Form_pg_foreign_data_wrapper
) GETSTRUCT(tuple
);
4270 * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
4272 ownerId
= fdwForm
->fdwowner
;
4274 aclDatum
= SysCacheGetAttr(FOREIGNDATAWRAPPEROID
, tuple
,
4275 Anum_pg_foreign_data_wrapper_fdwacl
, &isNull
);
4278 /* No ACL, so build default ACL */
4279 acl
= acldefault(OBJECT_FDW
, ownerId
);
4280 aclDatum
= (Datum
) 0;
4284 /* detoast rel's ACL if necessary */
4285 acl
= DatumGetAclP(aclDatum
);
4288 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
4290 /* if we have a detoasted copy, free it */
4291 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
4294 ReleaseSysCache(tuple
);
4300 * Exported routine for examining a user's privileges for a foreign
4304 pg_foreign_server_aclmask(Oid srv_oid
, Oid roleid
,
4305 AclMode mask
, AclMaskHow how
)
4314 Form_pg_foreign_server srvForm
;
4316 /* Bypass permission checks for superusers */
4317 if (superuser_arg(roleid
))
4321 * Must get the FDW's tuple from pg_foreign_data_wrapper
4323 tuple
= SearchSysCache1(FOREIGNSERVEROID
, ObjectIdGetDatum(srv_oid
));
4324 if (!HeapTupleIsValid(tuple
))
4326 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4327 errmsg("foreign server with OID %u does not exist",
4329 srvForm
= (Form_pg_foreign_server
) GETSTRUCT(tuple
);
4332 * Normal case: get the foreign server's ACL from pg_foreign_server
4334 ownerId
= srvForm
->srvowner
;
4336 aclDatum
= SysCacheGetAttr(FOREIGNSERVEROID
, tuple
,
4337 Anum_pg_foreign_server_srvacl
, &isNull
);
4340 /* No ACL, so build default ACL */
4341 acl
= acldefault(OBJECT_FOREIGN_SERVER
, ownerId
);
4342 aclDatum
= (Datum
) 0;
4346 /* detoast rel's ACL if necessary */
4347 acl
= DatumGetAclP(aclDatum
);
4350 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
4352 /* if we have a detoasted copy, free it */
4353 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
4356 ReleaseSysCache(tuple
);
4362 * Exported routine for examining a user's privileges for a type.
4365 pg_type_aclmask(Oid type_oid
, Oid roleid
, AclMode mask
, AclMaskHow how
)
4374 Form_pg_type typeForm
;
4376 /* Bypass permission checks for superusers */
4377 if (superuser_arg(roleid
))
4381 * Must get the type's tuple from pg_type
4383 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(type_oid
));
4384 if (!HeapTupleIsValid(tuple
))
4386 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4387 errmsg("type with OID %u does not exist",
4389 typeForm
= (Form_pg_type
) GETSTRUCT(tuple
);
4392 * "True" array types don't manage permissions of their own; consult the
4393 * element type instead.
4395 if (OidIsValid(typeForm
->typelem
) && typeForm
->typlen
== -1)
4397 Oid elttype_oid
= typeForm
->typelem
;
4399 ReleaseSysCache(tuple
);
4401 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(elttype_oid
));
4402 /* this case is not a user-facing error, so elog not ereport */
4403 if (!HeapTupleIsValid(tuple
))
4404 elog(ERROR
, "cache lookup failed for type %u", elttype_oid
);
4405 typeForm
= (Form_pg_type
) GETSTRUCT(tuple
);
4409 * Now get the type's owner and ACL from the tuple
4411 ownerId
= typeForm
->typowner
;
4413 aclDatum
= SysCacheGetAttr(TYPEOID
, tuple
,
4414 Anum_pg_type_typacl
, &isNull
);
4417 /* No ACL, so build default ACL */
4418 acl
= acldefault(OBJECT_TYPE
, ownerId
);
4419 aclDatum
= (Datum
) 0;
4423 /* detoast rel's ACL if necessary */
4424 acl
= DatumGetAclP(aclDatum
);
4427 result
= aclmask(acl
, roleid
, ownerId
, mask
, how
);
4429 /* if we have a detoasted copy, free it */
4430 if (acl
&& (Pointer
) acl
!= DatumGetPointer(aclDatum
))
4433 ReleaseSysCache(tuple
);
4439 * Exported routine for checking a user's access privileges to a column
4441 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4442 * 'mode'; otherwise returns a suitable error code (in practice, always
4443 * ACLCHECK_NO_PRIV).
4445 * As with pg_attribute_aclmask, only privileges granted directly on the
4446 * column are considered here.
4449 pg_attribute_aclcheck(Oid table_oid
, AttrNumber attnum
,
4450 Oid roleid
, AclMode mode
)
4452 if (pg_attribute_aclmask(table_oid
, attnum
, roleid
, mode
, ACLMASK_ANY
) != 0)
4455 return ACLCHECK_NO_PRIV
;
4459 * Exported routine for checking a user's access privileges to any/all columns
4461 * If 'how' is ACLMASK_ANY, then returns ACLCHECK_OK if user has any of the
4462 * privileges identified by 'mode' on any non-dropped column in the relation;
4463 * otherwise returns a suitable error code (in practice, always
4464 * ACLCHECK_NO_PRIV).
4466 * If 'how' is ACLMASK_ALL, then returns ACLCHECK_OK if user has any of the
4467 * privileges identified by 'mode' on each non-dropped column in the relation
4468 * (and there must be at least one such column); otherwise returns a suitable
4469 * error code (in practice, always ACLCHECK_NO_PRIV).
4471 * As with pg_attribute_aclmask, only privileges granted directly on the
4472 * column(s) are considered here.
4474 * Note: system columns are not considered here; there are cases where that
4475 * might be appropriate but there are also cases where it wouldn't.
4478 pg_attribute_aclcheck_all(Oid table_oid
, Oid roleid
, AclMode mode
,
4482 HeapTuple classTuple
;
4483 Form_pg_class classForm
;
4485 AttrNumber curr_att
;
4488 * Must fetch pg_class row to check number of attributes. As in
4489 * pg_attribute_aclmask, we prefer to return "no privileges" instead of
4490 * throwing an error if we get any unexpected lookup errors.
4492 classTuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(table_oid
));
4493 if (!HeapTupleIsValid(classTuple
))
4494 return ACLCHECK_NO_PRIV
;
4495 classForm
= (Form_pg_class
) GETSTRUCT(classTuple
);
4497 nattrs
= classForm
->relnatts
;
4499 ReleaseSysCache(classTuple
);
4502 * Initialize result in case there are no non-dropped columns. We want to
4503 * report failure in such cases for either value of 'how'.
4505 result
= ACLCHECK_NO_PRIV
;
4507 for (curr_att
= 1; curr_att
<= nattrs
; curr_att
++)
4512 attTuple
= SearchSysCache2(ATTNUM
,
4513 ObjectIdGetDatum(table_oid
),
4514 Int16GetDatum(curr_att
));
4515 if (!HeapTupleIsValid(attTuple
))
4518 /* ignore dropped columns */
4519 if (((Form_pg_attribute
) GETSTRUCT(attTuple
))->attisdropped
)
4521 ReleaseSysCache(attTuple
);
4526 * Here we hard-wire knowledge that the default ACL for a column
4527 * grants no privileges, so that we can fall out quickly in the very
4528 * common case where attacl is null.
4530 if (heap_attisnull(attTuple
, Anum_pg_attribute_attacl
, NULL
))
4533 attmask
= pg_attribute_aclmask(table_oid
, curr_att
, roleid
,
4536 ReleaseSysCache(attTuple
);
4540 result
= ACLCHECK_OK
;
4541 if (how
== ACLMASK_ANY
)
4542 break; /* succeed on any success */
4546 result
= ACLCHECK_NO_PRIV
;
4547 if (how
== ACLMASK_ALL
)
4548 break; /* fail on any failure */
4556 * Exported routine for checking a user's access privileges to a table
4558 * Returns ACLCHECK_OK if the user has any of the privileges identified by
4559 * 'mode'; otherwise returns a suitable error code (in practice, always
4560 * ACLCHECK_NO_PRIV).
4563 pg_class_aclcheck(Oid table_oid
, Oid roleid
, AclMode mode
)
4565 if (pg_class_aclmask(table_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4568 return ACLCHECK_NO_PRIV
;
4572 * Exported routine for checking a user's access privileges to a database
4575 pg_database_aclcheck(Oid db_oid
, Oid roleid
, AclMode mode
)
4577 if (pg_database_aclmask(db_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4580 return ACLCHECK_NO_PRIV
;
4584 * Exported routine for checking a user's access privileges to a function
4587 pg_proc_aclcheck(Oid proc_oid
, Oid roleid
, AclMode mode
)
4589 if (pg_proc_aclmask(proc_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4592 return ACLCHECK_NO_PRIV
;
4596 * Exported routine for checking a user's access privileges to a language
4599 pg_language_aclcheck(Oid lang_oid
, Oid roleid
, AclMode mode
)
4601 if (pg_language_aclmask(lang_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4604 return ACLCHECK_NO_PRIV
;
4608 * Exported routine for checking a user's access privileges to a largeobject
4611 pg_largeobject_aclcheck_snapshot(Oid lobj_oid
, Oid roleid
, AclMode mode
,
4614 if (pg_largeobject_aclmask_snapshot(lobj_oid
, roleid
, mode
,
4615 ACLMASK_ANY
, snapshot
) != 0)
4618 return ACLCHECK_NO_PRIV
;
4622 * Exported routine for checking a user's access privileges to a namespace
4625 pg_namespace_aclcheck(Oid nsp_oid
, Oid roleid
, AclMode mode
)
4627 if (pg_namespace_aclmask(nsp_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4630 return ACLCHECK_NO_PRIV
;
4634 * Exported routine for checking a user's access privileges to a tablespace
4637 pg_tablespace_aclcheck(Oid spc_oid
, Oid roleid
, AclMode mode
)
4639 if (pg_tablespace_aclmask(spc_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4642 return ACLCHECK_NO_PRIV
;
4646 * Exported routine for checking a user's access privileges to a foreign
4650 pg_foreign_data_wrapper_aclcheck(Oid fdw_oid
, Oid roleid
, AclMode mode
)
4652 if (pg_foreign_data_wrapper_aclmask(fdw_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4655 return ACLCHECK_NO_PRIV
;
4659 * Exported routine for checking a user's access privileges to a foreign
4663 pg_foreign_server_aclcheck(Oid srv_oid
, Oid roleid
, AclMode mode
)
4665 if (pg_foreign_server_aclmask(srv_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4668 return ACLCHECK_NO_PRIV
;
4672 * Exported routine for checking a user's access privileges to a type
4675 pg_type_aclcheck(Oid type_oid
, Oid roleid
, AclMode mode
)
4677 if (pg_type_aclmask(type_oid
, roleid
, mode
, ACLMASK_ANY
) != 0)
4680 return ACLCHECK_NO_PRIV
;
4684 * Ownership check for a relation (specified by OID).
4687 pg_class_ownercheck(Oid class_oid
, Oid roleid
)
4692 /* Superusers bypass all permission checking. */
4693 if (superuser_arg(roleid
))
4696 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(class_oid
));
4697 if (!HeapTupleIsValid(tuple
))
4699 (errcode(ERRCODE_UNDEFINED_TABLE
),
4700 errmsg("relation with OID %u does not exist", class_oid
)));
4702 ownerId
= ((Form_pg_class
) GETSTRUCT(tuple
))->relowner
;
4704 ReleaseSysCache(tuple
);
4706 return has_privs_of_role(roleid
, ownerId
);
4710 * Ownership check for a type (specified by OID).
4713 pg_type_ownercheck(Oid type_oid
, Oid roleid
)
4718 /* Superusers bypass all permission checking. */
4719 if (superuser_arg(roleid
))
4722 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(type_oid
));
4723 if (!HeapTupleIsValid(tuple
))
4725 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4726 errmsg("type with OID %u does not exist", type_oid
)));
4728 ownerId
= ((Form_pg_type
) GETSTRUCT(tuple
))->typowner
;
4730 ReleaseSysCache(tuple
);
4732 return has_privs_of_role(roleid
, ownerId
);
4736 * Ownership check for an operator (specified by OID).
4739 pg_oper_ownercheck(Oid oper_oid
, Oid roleid
)
4744 /* Superusers bypass all permission checking. */
4745 if (superuser_arg(roleid
))
4748 tuple
= SearchSysCache1(OPEROID
, ObjectIdGetDatum(oper_oid
));
4749 if (!HeapTupleIsValid(tuple
))
4751 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
4752 errmsg("operator with OID %u does not exist", oper_oid
)));
4754 ownerId
= ((Form_pg_operator
) GETSTRUCT(tuple
))->oprowner
;
4756 ReleaseSysCache(tuple
);
4758 return has_privs_of_role(roleid
, ownerId
);
4762 * Ownership check for a function (specified by OID).
4765 pg_proc_ownercheck(Oid proc_oid
, Oid roleid
)
4770 /* Superusers bypass all permission checking. */
4771 if (superuser_arg(roleid
))
4774 tuple
= SearchSysCache1(PROCOID
, ObjectIdGetDatum(proc_oid
));
4775 if (!HeapTupleIsValid(tuple
))
4777 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
4778 errmsg("function with OID %u does not exist", proc_oid
)));
4780 ownerId
= ((Form_pg_proc
) GETSTRUCT(tuple
))->proowner
;
4782 ReleaseSysCache(tuple
);
4784 return has_privs_of_role(roleid
, ownerId
);
4788 * Ownership check for a procedural language (specified by OID)
4791 pg_language_ownercheck(Oid lan_oid
, Oid roleid
)
4796 /* Superusers bypass all permission checking. */
4797 if (superuser_arg(roleid
))
4800 tuple
= SearchSysCache1(LANGOID
, ObjectIdGetDatum(lan_oid
));
4801 if (!HeapTupleIsValid(tuple
))
4803 (errcode(ERRCODE_UNDEFINED_FUNCTION
),
4804 errmsg("language with OID %u does not exist", lan_oid
)));
4806 ownerId
= ((Form_pg_language
) GETSTRUCT(tuple
))->lanowner
;
4808 ReleaseSysCache(tuple
);
4810 return has_privs_of_role(roleid
, ownerId
);
4814 * Ownership check for a largeobject (specified by OID)
4816 * This is only used for operations like ALTER LARGE OBJECT that are always
4817 * relative to an up-to-date snapshot.
4820 pg_largeobject_ownercheck(Oid lobj_oid
, Oid roleid
)
4822 Relation pg_lo_meta
;
4823 ScanKeyData entry
[1];
4828 /* Superusers bypass all permission checking. */
4829 if (superuser_arg(roleid
))
4832 /* There's no syscache for pg_largeobject_metadata */
4833 pg_lo_meta
= table_open(LargeObjectMetadataRelationId
,
4836 ScanKeyInit(&entry
[0],
4837 Anum_pg_largeobject_metadata_oid
,
4838 BTEqualStrategyNumber
, F_OIDEQ
,
4839 ObjectIdGetDatum(lobj_oid
));
4841 scan
= systable_beginscan(pg_lo_meta
,
4842 LargeObjectMetadataOidIndexId
, true,
4845 tuple
= systable_getnext(scan
);
4846 if (!HeapTupleIsValid(tuple
))
4848 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4849 errmsg("large object %u does not exist", lobj_oid
)));
4851 ownerId
= ((Form_pg_largeobject_metadata
) GETSTRUCT(tuple
))->lomowner
;
4853 systable_endscan(scan
);
4854 table_close(pg_lo_meta
, AccessShareLock
);
4856 return has_privs_of_role(roleid
, ownerId
);
4860 * Ownership check for a namespace (specified by OID).
4863 pg_namespace_ownercheck(Oid nsp_oid
, Oid roleid
)
4868 /* Superusers bypass all permission checking. */
4869 if (superuser_arg(roleid
))
4872 tuple
= SearchSysCache1(NAMESPACEOID
, ObjectIdGetDatum(nsp_oid
));
4873 if (!HeapTupleIsValid(tuple
))
4875 (errcode(ERRCODE_UNDEFINED_SCHEMA
),
4876 errmsg("schema with OID %u does not exist", nsp_oid
)));
4878 ownerId
= ((Form_pg_namespace
) GETSTRUCT(tuple
))->nspowner
;
4880 ReleaseSysCache(tuple
);
4882 return has_privs_of_role(roleid
, ownerId
);
4886 * Ownership check for a tablespace (specified by OID).
4889 pg_tablespace_ownercheck(Oid spc_oid
, Oid roleid
)
4894 /* Superusers bypass all permission checking. */
4895 if (superuser_arg(roleid
))
4898 /* Search syscache for pg_tablespace */
4899 spctuple
= SearchSysCache1(TABLESPACEOID
, ObjectIdGetDatum(spc_oid
));
4900 if (!HeapTupleIsValid(spctuple
))
4902 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4903 errmsg("tablespace with OID %u does not exist", spc_oid
)));
4905 spcowner
= ((Form_pg_tablespace
) GETSTRUCT(spctuple
))->spcowner
;
4907 ReleaseSysCache(spctuple
);
4909 return has_privs_of_role(roleid
, spcowner
);
4913 * Ownership check for an operator class (specified by OID).
4916 pg_opclass_ownercheck(Oid opc_oid
, Oid roleid
)
4921 /* Superusers bypass all permission checking. */
4922 if (superuser_arg(roleid
))
4925 tuple
= SearchSysCache1(CLAOID
, ObjectIdGetDatum(opc_oid
));
4926 if (!HeapTupleIsValid(tuple
))
4928 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4929 errmsg("operator class with OID %u does not exist",
4932 ownerId
= ((Form_pg_opclass
) GETSTRUCT(tuple
))->opcowner
;
4934 ReleaseSysCache(tuple
);
4936 return has_privs_of_role(roleid
, ownerId
);
4940 * Ownership check for an operator family (specified by OID).
4943 pg_opfamily_ownercheck(Oid opf_oid
, Oid roleid
)
4948 /* Superusers bypass all permission checking. */
4949 if (superuser_arg(roleid
))
4952 tuple
= SearchSysCache1(OPFAMILYOID
, ObjectIdGetDatum(opf_oid
));
4953 if (!HeapTupleIsValid(tuple
))
4955 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4956 errmsg("operator family with OID %u does not exist",
4959 ownerId
= ((Form_pg_opfamily
) GETSTRUCT(tuple
))->opfowner
;
4961 ReleaseSysCache(tuple
);
4963 return has_privs_of_role(roleid
, ownerId
);
4967 * Ownership check for a text search dictionary (specified by OID).
4970 pg_ts_dict_ownercheck(Oid dict_oid
, Oid roleid
)
4975 /* Superusers bypass all permission checking. */
4976 if (superuser_arg(roleid
))
4979 tuple
= SearchSysCache1(TSDICTOID
, ObjectIdGetDatum(dict_oid
));
4980 if (!HeapTupleIsValid(tuple
))
4982 (errcode(ERRCODE_UNDEFINED_OBJECT
),
4983 errmsg("text search dictionary with OID %u does not exist",
4986 ownerId
= ((Form_pg_ts_dict
) GETSTRUCT(tuple
))->dictowner
;
4988 ReleaseSysCache(tuple
);
4990 return has_privs_of_role(roleid
, ownerId
);
4994 * Ownership check for a text search configuration (specified by OID).
4997 pg_ts_config_ownercheck(Oid cfg_oid
, Oid roleid
)
5002 /* Superusers bypass all permission checking. */
5003 if (superuser_arg(roleid
))
5006 tuple
= SearchSysCache1(TSCONFIGOID
, ObjectIdGetDatum(cfg_oid
));
5007 if (!HeapTupleIsValid(tuple
))
5009 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5010 errmsg("text search configuration with OID %u does not exist",
5013 ownerId
= ((Form_pg_ts_config
) GETSTRUCT(tuple
))->cfgowner
;
5015 ReleaseSysCache(tuple
);
5017 return has_privs_of_role(roleid
, ownerId
);
5021 * Ownership check for a foreign-data wrapper (specified by OID).
5024 pg_foreign_data_wrapper_ownercheck(Oid srv_oid
, Oid roleid
)
5029 /* Superusers bypass all permission checking. */
5030 if (superuser_arg(roleid
))
5033 tuple
= SearchSysCache1(FOREIGNDATAWRAPPEROID
, ObjectIdGetDatum(srv_oid
));
5034 if (!HeapTupleIsValid(tuple
))
5036 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5037 errmsg("foreign-data wrapper with OID %u does not exist",
5040 ownerId
= ((Form_pg_foreign_data_wrapper
) GETSTRUCT(tuple
))->fdwowner
;
5042 ReleaseSysCache(tuple
);
5044 return has_privs_of_role(roleid
, ownerId
);
5048 * Ownership check for a foreign server (specified by OID).
5051 pg_foreign_server_ownercheck(Oid srv_oid
, Oid roleid
)
5056 /* Superusers bypass all permission checking. */
5057 if (superuser_arg(roleid
))
5060 tuple
= SearchSysCache1(FOREIGNSERVEROID
, ObjectIdGetDatum(srv_oid
));
5061 if (!HeapTupleIsValid(tuple
))
5063 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5064 errmsg("foreign server with OID %u does not exist",
5067 ownerId
= ((Form_pg_foreign_server
) GETSTRUCT(tuple
))->srvowner
;
5069 ReleaseSysCache(tuple
);
5071 return has_privs_of_role(roleid
, ownerId
);
5075 * Ownership check for an event trigger (specified by OID).
5078 pg_event_trigger_ownercheck(Oid et_oid
, Oid roleid
)
5083 /* Superusers bypass all permission checking. */
5084 if (superuser_arg(roleid
))
5087 tuple
= SearchSysCache1(EVENTTRIGGEROID
, ObjectIdGetDatum(et_oid
));
5088 if (!HeapTupleIsValid(tuple
))
5090 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5091 errmsg("event trigger with OID %u does not exist",
5094 ownerId
= ((Form_pg_event_trigger
) GETSTRUCT(tuple
))->evtowner
;
5096 ReleaseSysCache(tuple
);
5098 return has_privs_of_role(roleid
, ownerId
);
5102 * Ownership check for a database (specified by OID).
5105 pg_database_ownercheck(Oid db_oid
, Oid roleid
)
5110 /* Superusers bypass all permission checking. */
5111 if (superuser_arg(roleid
))
5114 tuple
= SearchSysCache1(DATABASEOID
, ObjectIdGetDatum(db_oid
));
5115 if (!HeapTupleIsValid(tuple
))
5117 (errcode(ERRCODE_UNDEFINED_DATABASE
),
5118 errmsg("database with OID %u does not exist", db_oid
)));
5120 dba
= ((Form_pg_database
) GETSTRUCT(tuple
))->datdba
;
5122 ReleaseSysCache(tuple
);
5124 return has_privs_of_role(roleid
, dba
);
5128 * Ownership check for a collation (specified by OID).
5131 pg_collation_ownercheck(Oid coll_oid
, Oid roleid
)
5136 /* Superusers bypass all permission checking. */
5137 if (superuser_arg(roleid
))
5140 tuple
= SearchSysCache1(COLLOID
, ObjectIdGetDatum(coll_oid
));
5141 if (!HeapTupleIsValid(tuple
))
5143 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5144 errmsg("collation with OID %u does not exist", coll_oid
)));
5146 ownerId
= ((Form_pg_collation
) GETSTRUCT(tuple
))->collowner
;
5148 ReleaseSysCache(tuple
);
5150 return has_privs_of_role(roleid
, ownerId
);
5154 * Ownership check for a conversion (specified by OID).
5157 pg_conversion_ownercheck(Oid conv_oid
, Oid roleid
)
5162 /* Superusers bypass all permission checking. */
5163 if (superuser_arg(roleid
))
5166 tuple
= SearchSysCache1(CONVOID
, ObjectIdGetDatum(conv_oid
));
5167 if (!HeapTupleIsValid(tuple
))
5169 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5170 errmsg("conversion with OID %u does not exist", conv_oid
)));
5172 ownerId
= ((Form_pg_conversion
) GETSTRUCT(tuple
))->conowner
;
5174 ReleaseSysCache(tuple
);
5176 return has_privs_of_role(roleid
, ownerId
);
5180 * Ownership check for an extension (specified by OID).
5183 pg_extension_ownercheck(Oid ext_oid
, Oid roleid
)
5185 Relation pg_extension
;
5186 ScanKeyData entry
[1];
5191 /* Superusers bypass all permission checking. */
5192 if (superuser_arg(roleid
))
5195 /* There's no syscache for pg_extension, so do it the hard way */
5196 pg_extension
= table_open(ExtensionRelationId
, AccessShareLock
);
5198 ScanKeyInit(&entry
[0],
5199 Anum_pg_extension_oid
,
5200 BTEqualStrategyNumber
, F_OIDEQ
,
5201 ObjectIdGetDatum(ext_oid
));
5203 scan
= systable_beginscan(pg_extension
,
5204 ExtensionOidIndexId
, true,
5207 tuple
= systable_getnext(scan
);
5208 if (!HeapTupleIsValid(tuple
))
5210 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5211 errmsg("extension with OID %u does not exist", ext_oid
)));
5213 ownerId
= ((Form_pg_extension
) GETSTRUCT(tuple
))->extowner
;
5215 systable_endscan(scan
);
5216 table_close(pg_extension
, AccessShareLock
);
5218 return has_privs_of_role(roleid
, ownerId
);
5222 * Ownership check for a publication (specified by OID).
5225 pg_publication_ownercheck(Oid pub_oid
, Oid roleid
)
5230 /* Superusers bypass all permission checking. */
5231 if (superuser_arg(roleid
))
5234 tuple
= SearchSysCache1(PUBLICATIONOID
, ObjectIdGetDatum(pub_oid
));
5235 if (!HeapTupleIsValid(tuple
))
5237 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5238 errmsg("publication with OID %u does not exist", pub_oid
)));
5240 ownerId
= ((Form_pg_publication
) GETSTRUCT(tuple
))->pubowner
;
5242 ReleaseSysCache(tuple
);
5244 return has_privs_of_role(roleid
, ownerId
);
5248 * Ownership check for a subscription (specified by OID).
5251 pg_subscription_ownercheck(Oid sub_oid
, Oid roleid
)
5256 /* Superusers bypass all permission checking. */
5257 if (superuser_arg(roleid
))
5260 tuple
= SearchSysCache1(SUBSCRIPTIONOID
, ObjectIdGetDatum(sub_oid
));
5261 if (!HeapTupleIsValid(tuple
))
5263 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5264 errmsg("subscription with OID %u does not exist", sub_oid
)));
5266 ownerId
= ((Form_pg_subscription
) GETSTRUCT(tuple
))->subowner
;
5268 ReleaseSysCache(tuple
);
5270 return has_privs_of_role(roleid
, ownerId
);
5274 * Ownership check for a statistics object (specified by OID).
5277 pg_statistics_object_ownercheck(Oid stat_oid
, Oid roleid
)
5282 /* Superusers bypass all permission checking. */
5283 if (superuser_arg(roleid
))
5286 tuple
= SearchSysCache1(STATEXTOID
, ObjectIdGetDatum(stat_oid
));
5287 if (!HeapTupleIsValid(tuple
))
5289 (errcode(ERRCODE_UNDEFINED_OBJECT
),
5290 errmsg("statistics object with OID %u does not exist",
5293 ownerId
= ((Form_pg_statistic_ext
) GETSTRUCT(tuple
))->stxowner
;
5295 ReleaseSysCache(tuple
);
5297 return has_privs_of_role(roleid
, ownerId
);
5301 * Check whether specified role has CREATEROLE privilege (or is a superuser)
5303 * Note: roles do not have owners per se; instead we use this test in
5304 * places where an ownership-like permissions test is needed for a role.
5305 * Be sure to apply it to the role trying to do the operation, not the
5306 * role being operated on! Also note that this generally should not be
5307 * considered enough privilege if the target role is a superuser.
5308 * (We don't handle that consideration here because we want to give a
5309 * separate error message for such cases, so the caller has to deal with it.)
5312 has_createrole_privilege(Oid roleid
)
5314 bool result
= false;
5317 /* Superusers bypass all permission checking. */
5318 if (superuser_arg(roleid
))
5321 utup
= SearchSysCache1(AUTHOID
, ObjectIdGetDatum(roleid
));
5322 if (HeapTupleIsValid(utup
))
5324 result
= ((Form_pg_authid
) GETSTRUCT(utup
))->rolcreaterole
;
5325 ReleaseSysCache(utup
);
5331 has_bypassrls_privilege(Oid roleid
)
5333 bool result
= false;
5336 /* Superusers bypass all permission checking. */
5337 if (superuser_arg(roleid
))
5340 utup
= SearchSysCache1(AUTHOID
, ObjectIdGetDatum(roleid
));
5341 if (HeapTupleIsValid(utup
))
5343 result
= ((Form_pg_authid
) GETSTRUCT(utup
))->rolbypassrls
;
5344 ReleaseSysCache(utup
);
5350 * Fetch pg_default_acl entry for given role, namespace and object type
5351 * (object type must be given in pg_default_acl's encoding).
5352 * Returns NULL if no such entry.
5355 get_default_acl_internal(Oid roleId
, Oid nsp_oid
, char objtype
)
5360 tuple
= SearchSysCache3(DEFACLROLENSPOBJ
,
5361 ObjectIdGetDatum(roleId
),
5362 ObjectIdGetDatum(nsp_oid
),
5363 CharGetDatum(objtype
));
5365 if (HeapTupleIsValid(tuple
))
5370 aclDatum
= SysCacheGetAttr(DEFACLROLENSPOBJ
, tuple
,
5371 Anum_pg_default_acl_defaclacl
,
5374 result
= DatumGetAclPCopy(aclDatum
);
5375 ReleaseSysCache(tuple
);
5382 * Get default permissions for newly created object within given schema
5384 * Returns NULL if built-in system defaults should be used.
5386 * If the result is not NULL, caller must call recordDependencyOnNewAcl
5387 * once the OID of the new object is known.
5390 get_user_default_acl(ObjectType objtype
, Oid ownerId
, Oid nsp_oid
)
5399 * Use NULL during bootstrap, since pg_default_acl probably isn't there
5402 if (IsBootstrapProcessingMode())
5405 /* Check if object type is supported in pg_default_acl */
5409 defaclobjtype
= DEFACLOBJ_RELATION
;
5412 case OBJECT_SEQUENCE
:
5413 defaclobjtype
= DEFACLOBJ_SEQUENCE
;
5416 case OBJECT_FUNCTION
:
5417 defaclobjtype
= DEFACLOBJ_FUNCTION
;
5421 defaclobjtype
= DEFACLOBJ_TYPE
;
5425 defaclobjtype
= DEFACLOBJ_NAMESPACE
;
5432 /* Look up the relevant pg_default_acl entries */
5433 glob_acl
= get_default_acl_internal(ownerId
, InvalidOid
, defaclobjtype
);
5434 schema_acl
= get_default_acl_internal(ownerId
, nsp_oid
, defaclobjtype
);
5436 /* Quick out if neither entry exists */
5437 if (glob_acl
== NULL
&& schema_acl
== NULL
)
5440 /* We need to know the hard-wired default value, too */
5441 def_acl
= acldefault(objtype
, ownerId
);
5443 /* If there's no global entry, substitute the hard-wired default */
5444 if (glob_acl
== NULL
)
5447 /* Merge in any per-schema privileges */
5448 result
= aclmerge(glob_acl
, schema_acl
, ownerId
);
5451 * For efficiency, we want to return NULL if the result equals default.
5452 * This requires sorting both arrays to get an accurate comparison.
5454 aclitemsort(result
);
5455 aclitemsort(def_acl
);
5456 if (aclequal(result
, def_acl
))
5463 * Record dependencies on roles mentioned in a new object's ACL.
5466 recordDependencyOnNewAcl(Oid classId
, Oid objectId
, int32 objsubId
,
5467 Oid ownerId
, Acl
*acl
)
5472 /* Nothing to do if ACL is defaulted */
5476 /* Extract roles mentioned in ACL */
5477 nmembers
= aclmembers(acl
, &members
);
5479 /* Update the shared dependency ACL info */
5480 updateAclDependencies(classId
, objectId
, objsubId
,
5487 * Record initial privileges for the top-level object passed in.
5489 * For the object passed in, this will record its ACL (if any) and the ACLs of
5490 * any sub-objects (eg: columns) into pg_init_privs.
5492 * Any new kinds of objects which have ACLs associated with them and can be
5493 * added to an extension should be added to the if-else tree below.
5496 recordExtObjInitPriv(Oid objoid
, Oid classoid
)
5499 * pg_class / pg_attribute
5501 * If this is a relation then we need to see if there are any sub-objects
5502 * (eg: columns) for it and, if so, be sure to call
5503 * recordExtensionInitPrivWorker() for each one.
5505 if (classoid
== RelationRelationId
)
5507 Form_pg_class pg_class_tuple
;
5512 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(objoid
));
5513 if (!HeapTupleIsValid(tuple
))
5514 elog(ERROR
, "cache lookup failed for relation %u", objoid
);
5515 pg_class_tuple
= (Form_pg_class
) GETSTRUCT(tuple
);
5518 * Indexes don't have permissions, neither do the pg_class rows for
5519 * composite types. (These cases are unreachable given the
5520 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
5522 if (pg_class_tuple
->relkind
== RELKIND_INDEX
||
5523 pg_class_tuple
->relkind
== RELKIND_PARTITIONED_INDEX
||
5524 pg_class_tuple
->relkind
== RELKIND_COMPOSITE_TYPE
)
5526 ReleaseSysCache(tuple
);
5531 * If this isn't a sequence then it's possibly going to have
5532 * column-level ACLs associated with it.
5534 if (pg_class_tuple
->relkind
!= RELKIND_SEQUENCE
)
5536 AttrNumber curr_att
;
5537 AttrNumber nattrs
= pg_class_tuple
->relnatts
;
5539 for (curr_att
= 1; curr_att
<= nattrs
; curr_att
++)
5544 attTuple
= SearchSysCache2(ATTNUM
,
5545 ObjectIdGetDatum(objoid
),
5546 Int16GetDatum(curr_att
));
5548 if (!HeapTupleIsValid(attTuple
))
5551 /* ignore dropped columns */
5552 if (((Form_pg_attribute
) GETSTRUCT(attTuple
))->attisdropped
)
5554 ReleaseSysCache(attTuple
);
5558 attaclDatum
= SysCacheGetAttr(ATTNUM
, attTuple
,
5559 Anum_pg_attribute_attacl
,
5562 /* no need to do anything for a NULL ACL */
5565 ReleaseSysCache(attTuple
);
5569 recordExtensionInitPrivWorker(objoid
, classoid
, curr_att
,
5570 DatumGetAclP(attaclDatum
));
5572 ReleaseSysCache(attTuple
);
5576 aclDatum
= SysCacheGetAttr(RELOID
, tuple
, Anum_pg_class_relacl
,
5579 /* Add the record, if any, for the top-level object */
5581 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
5582 DatumGetAclP(aclDatum
));
5584 ReleaseSysCache(tuple
);
5586 /* pg_foreign_data_wrapper */
5587 else if (classoid
== ForeignDataWrapperRelationId
)
5593 tuple
= SearchSysCache1(FOREIGNDATAWRAPPEROID
,
5594 ObjectIdGetDatum(objoid
));
5595 if (!HeapTupleIsValid(tuple
))
5596 elog(ERROR
, "cache lookup failed for foreign data wrapper %u",
5599 aclDatum
= SysCacheGetAttr(FOREIGNDATAWRAPPEROID
, tuple
,
5600 Anum_pg_foreign_data_wrapper_fdwacl
,
5603 /* Add the record, if any, for the top-level object */
5605 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
5606 DatumGetAclP(aclDatum
));
5608 ReleaseSysCache(tuple
);
5610 /* pg_foreign_server */
5611 else if (classoid
== ForeignServerRelationId
)
5617 tuple
= SearchSysCache1(FOREIGNSERVEROID
, ObjectIdGetDatum(objoid
));
5618 if (!HeapTupleIsValid(tuple
))
5619 elog(ERROR
, "cache lookup failed for foreign data wrapper %u",
5622 aclDatum
= SysCacheGetAttr(FOREIGNSERVEROID
, tuple
,
5623 Anum_pg_foreign_server_srvacl
,
5626 /* Add the record, if any, for the top-level object */
5628 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
5629 DatumGetAclP(aclDatum
));
5631 ReleaseSysCache(tuple
);
5634 else if (classoid
== LanguageRelationId
)
5640 tuple
= SearchSysCache1(LANGOID
, ObjectIdGetDatum(objoid
));
5641 if (!HeapTupleIsValid(tuple
))
5642 elog(ERROR
, "cache lookup failed for language %u", objoid
);
5644 aclDatum
= SysCacheGetAttr(LANGOID
, tuple
, Anum_pg_language_lanacl
,
5647 /* Add the record, if any, for the top-level object */
5649 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
5650 DatumGetAclP(aclDatum
));
5652 ReleaseSysCache(tuple
);
5654 /* pg_largeobject_metadata */
5655 else if (classoid
== LargeObjectMetadataRelationId
)
5660 ScanKeyData entry
[1];
5665 * Note: this is dead code, given that we don't allow large objects to
5666 * be made extension members. But it seems worth carrying in case
5667 * some future caller of this function has need for it.
5669 relation
= table_open(LargeObjectMetadataRelationId
, RowExclusiveLock
);
5671 /* There's no syscache for pg_largeobject_metadata */
5672 ScanKeyInit(&entry
[0],
5673 Anum_pg_largeobject_metadata_oid
,
5674 BTEqualStrategyNumber
, F_OIDEQ
,
5675 ObjectIdGetDatum(objoid
));
5677 scan
= systable_beginscan(relation
,
5678 LargeObjectMetadataOidIndexId
, true,
5681 tuple
= systable_getnext(scan
);
5682 if (!HeapTupleIsValid(tuple
))
5683 elog(ERROR
, "could not find tuple for large object %u", objoid
);
5685 aclDatum
= heap_getattr(tuple
,
5686 Anum_pg_largeobject_metadata_lomacl
,
5687 RelationGetDescr(relation
), &isNull
);
5689 /* Add the record, if any, for the top-level object */
5691 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
5692 DatumGetAclP(aclDatum
));
5694 systable_endscan(scan
);
5697 else if (classoid
== NamespaceRelationId
)
5703 tuple
= SearchSysCache1(NAMESPACEOID
, ObjectIdGetDatum(objoid
));
5704 if (!HeapTupleIsValid(tuple
))
5705 elog(ERROR
, "cache lookup failed for function %u", objoid
);
5707 aclDatum
= SysCacheGetAttr(NAMESPACEOID
, tuple
,
5708 Anum_pg_namespace_nspacl
, &isNull
);
5710 /* Add the record, if any, for the top-level object */
5712 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
5713 DatumGetAclP(aclDatum
));
5715 ReleaseSysCache(tuple
);
5718 else if (classoid
== ProcedureRelationId
)
5724 tuple
= SearchSysCache1(PROCOID
, ObjectIdGetDatum(objoid
));
5725 if (!HeapTupleIsValid(tuple
))
5726 elog(ERROR
, "cache lookup failed for function %u", objoid
);
5728 aclDatum
= SysCacheGetAttr(PROCOID
, tuple
, Anum_pg_proc_proacl
,
5731 /* Add the record, if any, for the top-level object */
5733 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
5734 DatumGetAclP(aclDatum
));
5736 ReleaseSysCache(tuple
);
5739 else if (classoid
== TypeRelationId
)
5745 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(objoid
));
5746 if (!HeapTupleIsValid(tuple
))
5747 elog(ERROR
, "cache lookup failed for function %u", objoid
);
5749 aclDatum
= SysCacheGetAttr(TYPEOID
, tuple
, Anum_pg_type_typacl
,
5752 /* Add the record, if any, for the top-level object */
5754 recordExtensionInitPrivWorker(objoid
, classoid
, 0,
5755 DatumGetAclP(aclDatum
));
5757 ReleaseSysCache(tuple
);
5759 else if (classoid
== AccessMethodRelationId
||
5760 classoid
== AggregateRelationId
||
5761 classoid
== CastRelationId
||
5762 classoid
== CollationRelationId
||
5763 classoid
== ConversionRelationId
||
5764 classoid
== EventTriggerRelationId
||
5765 classoid
== OperatorRelationId
||
5766 classoid
== OperatorClassRelationId
||
5767 classoid
== OperatorFamilyRelationId
||
5768 classoid
== NamespaceRelationId
||
5769 classoid
== TSConfigRelationId
||
5770 classoid
== TSDictionaryRelationId
||
5771 classoid
== TSParserRelationId
||
5772 classoid
== TSTemplateRelationId
||
5773 classoid
== TransformRelationId
5776 /* no ACL for these object types, so do nothing. */
5780 * complain if we are given a class OID for a class that extensions don't
5781 * support or that we don't recognize.
5785 elog(ERROR
, "unrecognized or unsupported class OID: %u", classoid
);
5790 * For the object passed in, remove its ACL and the ACLs of any object subIds
5791 * from pg_init_privs (via recordExtensionInitPrivWorker()).
5794 removeExtObjInitPriv(Oid objoid
, Oid classoid
)
5797 * If this is a relation then we need to see if there are any sub-objects
5798 * (eg: columns) for it and, if so, be sure to call
5799 * recordExtensionInitPrivWorker() for each one.
5801 if (classoid
== RelationRelationId
)
5803 Form_pg_class pg_class_tuple
;
5806 tuple
= SearchSysCache1(RELOID
, ObjectIdGetDatum(objoid
));
5807 if (!HeapTupleIsValid(tuple
))
5808 elog(ERROR
, "cache lookup failed for relation %u", objoid
);
5809 pg_class_tuple
= (Form_pg_class
) GETSTRUCT(tuple
);
5812 * Indexes don't have permissions, neither do the pg_class rows for
5813 * composite types. (These cases are unreachable given the
5814 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
5816 if (pg_class_tuple
->relkind
== RELKIND_INDEX
||
5817 pg_class_tuple
->relkind
== RELKIND_PARTITIONED_INDEX
||
5818 pg_class_tuple
->relkind
== RELKIND_COMPOSITE_TYPE
)
5820 ReleaseSysCache(tuple
);
5825 * If this isn't a sequence then it's possibly going to have
5826 * column-level ACLs associated with it.
5828 if (pg_class_tuple
->relkind
!= RELKIND_SEQUENCE
)
5830 AttrNumber curr_att
;
5831 AttrNumber nattrs
= pg_class_tuple
->relnatts
;
5833 for (curr_att
= 1; curr_att
<= nattrs
; curr_att
++)
5837 attTuple
= SearchSysCache2(ATTNUM
,
5838 ObjectIdGetDatum(objoid
),
5839 Int16GetDatum(curr_att
));
5841 if (!HeapTupleIsValid(attTuple
))
5844 /* when removing, remove all entries, even dropped columns */
5846 recordExtensionInitPrivWorker(objoid
, classoid
, curr_att
, NULL
);
5848 ReleaseSysCache(attTuple
);
5852 ReleaseSysCache(tuple
);
5855 /* Remove the record, if any, for the top-level object */
5856 recordExtensionInitPrivWorker(objoid
, classoid
, 0, NULL
);
5860 * Record initial ACL for an extension object
5862 * Can be called at any time, we check if 'creating_extension' is set and, if
5863 * not, exit immediately.
5865 * Pass in the object OID, the OID of the class (the OID of the table which
5866 * the object is defined in) and the 'sub' id of the object (objsubid), if
5867 * any. If there is no 'sub' id (they are currently only used for columns of
5868 * tables) then pass in '0'. Finally, pass in the complete ACL to store.
5870 * If an ACL already exists for this object/sub-object then we will replace
5871 * it with what is passed in.
5873 * Passing in NULL for 'new_acl' will result in the entry for the object being
5874 * removed, if one is found.
5877 recordExtensionInitPriv(Oid objoid
, Oid classoid
, int objsubid
, Acl
*new_acl
)
5880 * Generally, we only record the initial privileges when an extension is
5881 * being created, but because we don't actually use CREATE EXTENSION
5882 * during binary upgrades with pg_upgrade, there is a variable to let us
5883 * know that the GRANT and REVOKE statements being issued, while this
5884 * variable is true, are for the initial privileges of the extension
5885 * object and therefore we need to record them.
5887 if (!creating_extension
&& !binary_upgrade_record_init_privs
)
5890 recordExtensionInitPrivWorker(objoid
, classoid
, objsubid
, new_acl
);
5894 * Record initial ACL for an extension object, worker.
5896 * This will perform a wholesale replacement of the entire ACL for the object
5897 * passed in, therefore be sure to pass in the complete new ACL to use.
5899 * Generally speaking, do *not* use this function directly but instead use
5900 * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
5901 * This function does *not* check if 'creating_extension' is set as it is also
5902 * used when an object is added to or removed from an extension via ALTER
5903 * EXTENSION ... ADD/DROP.
5906 recordExtensionInitPrivWorker(Oid objoid
, Oid classoid
, int objsubid
, Acl
*new_acl
)
5914 relation
= table_open(InitPrivsRelationId
, RowExclusiveLock
);
5916 ScanKeyInit(&key
[0],
5917 Anum_pg_init_privs_objoid
,
5918 BTEqualStrategyNumber
, F_OIDEQ
,
5919 ObjectIdGetDatum(objoid
));
5920 ScanKeyInit(&key
[1],
5921 Anum_pg_init_privs_classoid
,
5922 BTEqualStrategyNumber
, F_OIDEQ
,
5923 ObjectIdGetDatum(classoid
));
5924 ScanKeyInit(&key
[2],
5925 Anum_pg_init_privs_objsubid
,
5926 BTEqualStrategyNumber
, F_INT4EQ
,
5927 Int32GetDatum(objsubid
));
5929 scan
= systable_beginscan(relation
, InitPrivsObjIndexId
, true,
5932 /* There should exist only one entry or none. */
5933 oldtuple
= systable_getnext(scan
);
5935 /* If we find an entry, update it with the latest ACL. */
5936 if (HeapTupleIsValid(oldtuple
))
5938 Datum values
[Natts_pg_init_privs
];
5939 bool nulls
[Natts_pg_init_privs
];
5940 bool replace
[Natts_pg_init_privs
];
5942 /* If we have a new ACL to set, then update the row with it. */
5945 MemSet(values
, 0, sizeof(values
));
5946 MemSet(nulls
, false, sizeof(nulls
));
5947 MemSet(replace
, false, sizeof(replace
));
5949 values
[Anum_pg_init_privs_initprivs
- 1] = PointerGetDatum(new_acl
);
5950 replace
[Anum_pg_init_privs_initprivs
- 1] = true;
5952 oldtuple
= heap_modify_tuple(oldtuple
, RelationGetDescr(relation
),
5953 values
, nulls
, replace
);
5955 CatalogTupleUpdate(relation
, &oldtuple
->t_self
, oldtuple
);
5959 /* new_acl is NULL, so delete the entry we found. */
5960 CatalogTupleDelete(relation
, &oldtuple
->t_self
);
5965 Datum values
[Natts_pg_init_privs
];
5966 bool nulls
[Natts_pg_init_privs
];
5969 * Only add a new entry if the new ACL is non-NULL.
5971 * If we are passed in a NULL ACL and no entry exists, we can just
5972 * fall through and do nothing.
5976 /* No entry found, so add it. */
5977 MemSet(nulls
, false, sizeof(nulls
));
5979 values
[Anum_pg_init_privs_objoid
- 1] = ObjectIdGetDatum(objoid
);
5980 values
[Anum_pg_init_privs_classoid
- 1] = ObjectIdGetDatum(classoid
);
5981 values
[Anum_pg_init_privs_objsubid
- 1] = Int32GetDatum(objsubid
);
5983 /* This function only handles initial privileges of extensions */
5984 values
[Anum_pg_init_privs_privtype
- 1] =
5985 CharGetDatum(INITPRIVS_EXTENSION
);
5987 values
[Anum_pg_init_privs_initprivs
- 1] = PointerGetDatum(new_acl
);
5989 tuple
= heap_form_tuple(RelationGetDescr(relation
), values
, nulls
);
5991 CatalogTupleInsert(relation
, tuple
);
5995 systable_endscan(scan
);
5997 /* prevent error when processing objects multiple times */
5998 CommandCounterIncrement();
6000 table_close(relation
, RowExclusiveLock
);