18
18
#include "access/relation.h"
19
19
#include "access/sysattr.h"
20
20
#include "access/table.h"
21
+ #include "access/xact.h"
21
22
#include "catalog/catalog.h"
22
23
#include "catalog/dependency.h"
23
24
#include "catalog/indexing.h"
@@ -425,10 +426,9 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
425
426
Oid relid ;
426
427
Relation rel ;
427
428
ArrayType * policy_roles ;
428
- int num_roles ;
429
429
Datum roles_datum ;
430
430
bool attr_isnull ;
431
- bool noperm = true;
431
+ bool keep_policy = true;
432
432
433
433
Assert (classid == PolicyRelationId );
434
434
@@ -481,31 +481,20 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
481
481
482
482
policy_roles = DatumGetArrayTypePCopy (roles_datum );
483
483
484
- /* We should be removing exactly one entry from the roles array */
485
- num_roles = ARR_DIMS (policy_roles )[0 ] - 1 ;
486
-
487
- Assert (num_roles >= 0 );
488
-
489
484
/* Must own relation. */
490
- if (pg_class_ownercheck (relid , GetUserId ()))
491
- noperm = false; /* user is allowed to modify this policy */
492
- else
485
+ if (!pg_class_ownercheck (relid , GetUserId ()))
493
486
ereport (WARNING ,
494
487
(errcode (ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED ),
495
488
errmsg ("role \"%s\" could not be removed from policy \"%s\" on \"%s\"" ,
496
489
GetUserNameFromId (roleid , false),
497
490
NameStr (((Form_pg_policy ) GETSTRUCT (tuple ))-> polname ),
498
491
RelationGetRelationName (rel ))));
499
-
500
- /*
501
- * If multiple roles exist on this policy, then remove the one we were
502
- * asked to and leave the rest.
503
- */
504
- if (!noperm && num_roles > 0 )
492
+ else
505
493
{
506
494
int i ,
507
495
j ;
508
496
Oid * roles = (Oid * ) ARR_DATA_PTR (policy_roles );
497
+ int num_roles = ARR_DIMS (policy_roles )[0 ];
509
498
Datum * role_oids ;
510
499
char * qual_value ;
511
500
Node * qual_expr ;
@@ -582,16 +571,22 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
582
571
else
583
572
with_check_qual = NULL ;
584
573
585
- /* Rebuild the roles array to then update the pg_policy tuple with */
574
+ /*
575
+ * Rebuild the roles array, without any mentions of the target role.
576
+ * Ordinarily there'd be exactly one, but we must cope with duplicate
577
+ * mentions, since CREATE/ALTER POLICY historically have allowed that.
578
+ */
586
579
role_oids = (Datum * ) palloc (num_roles * sizeof (Datum ));
587
- for (i = 0 , j = 0 ; i < ARR_DIMS ( policy_roles )[ 0 ] ; i ++ )
588
- /* Copy over all of the roles which are not the one being removed */
580
+ for (i = 0 , j = 0 ; i < num_roles ; i ++ )
581
+ {
589
582
if (roles [i ] != roleid )
590
583
role_oids [j ++ ] = ObjectIdGetDatum (roles [i ]);
584
+ }
585
+ num_roles = j ;
591
586
592
- /* We should have only removed the one role */
593
- Assert ( j == num_roles );
594
-
587
+ /* If any roles remain, update the policy entry. */
588
+ if ( num_roles > 0 )
589
+ {
595
590
/* This is the array for the new tuple */
596
591
role_ids = construct_array (role_oids , num_roles , OIDOID ,
597
592
sizeof (Oid ), true, TYPALIGN_INT );
@@ -646,8 +641,17 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
646
641
647
642
heap_freetuple (new_tuple );
648
643
644
+ /* Make updates visible */
645
+ CommandCounterIncrement ();
646
+
649
647
/* Invalidate Relation Cache */
650
648
CacheInvalidateRelcache (rel );
649
+ }
650
+ else
651
+ {
652
+ /* No roles would remain, so drop the policy instead */
653
+ keep_policy = false;
654
+ }
651
655
}
652
656
653
657
/* Clean up. */
@@ -657,7 +661,7 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
657
661
658
662
table_close (pg_policy_rel , RowExclusiveLock );
659
663
660
- return ( noperm || num_roles > 0 ) ;
664
+ return keep_policy ;
661
665
}
662
666
663
667
/*
0 commit comments