-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 07/27/2015 01:13 PM, Alvaro Herrera wrote:
> Hmm, these are not ACL objects, so conceptually it seems cleaner to
> use a different symbol for this.  I think the catalog state and the
> error messages would be a bit confusing otherwise.

Ok -- done

> Isn't this leaking the previously allocated array?  Not sure it's
> all that critical, but still.  (I don't think you really need to
> call palloc at all here.)

Agreed -- I think the attached is a bit cleaner.

Any other comments or concerns?

- -- 
Joe Conway
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBAgAGBQJVts3+AAoJEDfy90M199hlzTIQAJ6LEOrEEhHEjsoVvCT6TUAu
pMQl/LWmb0s3/vF9o5VFTpVd21k0LxcggD+DdbxSagiw1WpLK5x67C9Lj5uuFn/d
3a95nFnQje3ciQJaAKS4XcGyx8+6rHPZqfBRC1rARbLuDHrwpKqmbKwvpQCud4xN
kD7OolYk5Gd3cId0xH0XBHuwLVJg4Bt/MAexrcHn+kXuQoF8V6iOjnmBI/BHvTQy
w4j4ov7DpWSAR1ZiCTCkF2ZuNd9TJ8FmAEtSDVrlWMxB9J+9PU5oTfD50jp62BTz
wycANVYmbpCyZ7DAAiqopt3IQFIiF/1bYwzWH3/M8RRMKJF8HNyE8KBPDyC/doO5
0c0poCugJI2wOhumLGJShizgSAS85vqijh2Uxpp2yQxdStMnADykzT4Nb5EnEJVE
i7OKy6w+2xyilfFGEWhHfS7uo5Y0zBorhpjgT9fRaqPBGoK4jYwZoO8w97SUd9aS
kNXOCfmFxvcDFSZIYZP77pOeJZR2dLCbr+X9bF1Fz5S4FVkgCXVOp9rmsqzgxoDh
lcpkDh9zPPezdczRkfq/qCf0lmzGg8apdqdr7+g8DxU+01OvPspEdpovQQN0HXlM
m5Kbny4KCWhAgBTyAsOFTEy6lK7u4KsHV1cee3bG+ev65czbQ14gGRMJc/Lhm6Gg
Apcn/UcF14vLWxYVo6lS
=pS6L
-----END PGP SIGNATURE-----
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 9096ee5..7781c56 100644
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 5793,5798 ****
--- 5793,5808 ----
      </varlistentry>
  
      <varlistentry>
+      <term><symbol>SHARED_DEPENDENCY_POLICY</> (<literal>r</>)</term>
+      <listitem>
+       <para>
+        The referenced object (which must be a role) is mentioned as the
+        target of a dependent policy object.
+       </para>
+      </listitem>
+     </varlistentry>
+ 
+     <varlistentry>
       <term><symbol>SHARED_DEPENDENCY_PIN</> (<literal>p</>)</term>
       <listitem>
        <para>
diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c
index 34fe4e2..43076c9 100644
*** a/src/backend/catalog/pg_shdepend.c
--- b/src/backend/catalog/pg_shdepend.c
*************** storeObjectDescription(StringInfo descs,
*** 1083,1088 ****
--- 1083,1090 ----
  				appendStringInfo(descs, _("owner of %s"), objdesc);
  			else if (deptype == SHARED_DEPENDENCY_ACL)
  				appendStringInfo(descs, _("privileges for %s"), objdesc);
+ 			else if (deptype == SHARED_DEPENDENCY_POLICY)
+ 				appendStringInfo(descs, _("target of %s"), objdesc);
  			else
  				elog(ERROR, "unrecognized dependency type: %d",
  					 (int) deptype);
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 17b48d4..9544f75 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
***************
*** 22,27 ****
--- 22,28 ----
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/objectaccess.h"
+ #include "catalog/pg_authid.h"
  #include "catalog/pg_policy.h"
  #include "catalog/pg_type.h"
  #include "commands/policy.h"
***************
*** 48,54 ****
  static void RangeVarCallbackForPolicy(const RangeVar *rv,
  						  Oid relid, Oid oldrelid, void *arg);
  static char parse_policy_command(const char *cmd_name);
! static ArrayType *policy_role_list_to_array(List *roles);
  
  /*
   * Callback to RangeVarGetRelidExtended().
--- 49,55 ----
  static void RangeVarCallbackForPolicy(const RangeVar *rv,
  						  Oid relid, Oid oldrelid, void *arg);
  static char parse_policy_command(const char *cmd_name);
! static Datum *policy_role_list_to_array(List *roles, int *num_roles);
  
  /*
   * Callback to RangeVarGetRelidExtended().
*************** parse_policy_command(const char *cmd_nam
*** 130,159 ****
  
  /*
   * policy_role_list_to_array
!  *	 helper function to convert a list of RoleSpecs to an array of role ids.
   */
! static ArrayType *
! policy_role_list_to_array(List *roles)
  {
! 	ArrayType  *role_ids;
! 	Datum	   *temp_array;
  	ListCell   *cell;
- 	int			num_roles;
  	int			i = 0;
  
  	/* Handle no roles being passed in as being for public */
  	if (roles == NIL)
  	{
! 		temp_array = (Datum *) palloc(sizeof(Datum));
! 		temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
  
! 		role_ids = construct_array(temp_array, 1, OIDOID, sizeof(Oid), true,
! 								   'i');
! 		return role_ids;
  	}
  
! 	num_roles = list_length(roles);
! 	temp_array = (Datum *) palloc(num_roles * sizeof(Datum));
  
  	foreach(cell, roles)
  	{
--- 131,158 ----
  
  /*
   * policy_role_list_to_array
!  *	 helper function to convert a list of RoleSpecs to an array of
!  *	 role id Datums.
   */
! static Datum *
! policy_role_list_to_array(List *roles, int *num_roles)
  {
! 	Datum	   *role_oids;
  	ListCell   *cell;
  	int			i = 0;
  
  	/* Handle no roles being passed in as being for public */
  	if (roles == NIL)
  	{
! 	   *num_roles = 1;
! 		role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
! 		role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
  
! 		return role_oids;
  	}
  
!    *num_roles = list_length(roles);
! 	role_oids = (Datum *) palloc(*num_roles * sizeof(Datum));
  
  	foreach(cell, roles)
  	{
*************** policy_role_list_to_array(List *roles)
*** 164,187 ****
  		 */
  		if (spec->roletype == ROLESPEC_PUBLIC)
  		{
! 			if (num_roles != 1)
  				ereport(WARNING,
  						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  						 errmsg("ignoring roles specified other than public"),
  					  errhint("All roles are members of the public role.")));
! 			temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
! 			num_roles = 1;
! 			break;
  		}
  		else
! 			temp_array[i++] =
  				ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
  	}
  
! 	role_ids = construct_array(temp_array, num_roles, OIDOID, sizeof(Oid), true,
! 							   'i');
! 
! 	return role_ids;
  }
  
  /*
--- 163,186 ----
  		 */
  		if (spec->roletype == ROLESPEC_PUBLIC)
  		{
! 			if (*num_roles != 1)
! 			{
  				ereport(WARNING,
  						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  						 errmsg("ignoring roles specified other than public"),
  					  errhint("All roles are members of the public role.")));
! 			   *num_roles = 1;
! 			}
! 			role_oids[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
! 
! 			return role_oids;
  		}
  		else
! 			role_oids[i++] =
  				ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
  	}
  
! 	return role_oids;
  }
  
  /*
*************** CreatePolicy(CreatePolicyStmt *stmt)
*** 463,468 ****
--- 462,469 ----
  	Relation	target_table;
  	Oid			table_id;
  	char		polcmd;
+ 	Datum	   *role_oids;
+ 	int			nitems = 0;
  	ArrayType  *role_ids;
  	ParseState *qual_pstate;
  	ParseState *with_check_pstate;
*************** CreatePolicy(CreatePolicyStmt *stmt)
*** 476,481 ****
--- 477,483 ----
  	bool		isnull[Natts_pg_policy];
  	ObjectAddress target;
  	ObjectAddress myself;
+ 	int			i;
  
  	/* Parse command */
  	polcmd = parse_policy_command(stmt->cmd);
*************** CreatePolicy(CreatePolicyStmt *stmt)
*** 498,506 ****
  				(errcode(ERRCODE_SYNTAX_ERROR),
  				 errmsg("only WITH CHECK expression allowed for INSERT")));
  
- 
  	/* Collect role ids */
! 	role_ids = policy_role_list_to_array(stmt->roles);
  
  	/* Parse the supplied clause */
  	qual_pstate = make_parsestate(NULL);
--- 500,509 ----
  				(errcode(ERRCODE_SYNTAX_ERROR),
  				 errmsg("only WITH CHECK expression allowed for INSERT")));
  
  	/* Collect role ids */
! 	role_oids = policy_role_list_to_array(stmt->roles, &nitems);
! 	role_ids = construct_array(role_oids, nitems, OIDOID,
! 							   sizeof(Oid), true, 'i');
  
  	/* Parse the supplied clause */
  	qual_pstate = make_parsestate(NULL);
*************** CreatePolicy(CreatePolicyStmt *stmt)
*** 614,619 ****
--- 617,634 ----
  	recordDependencyOnExpr(&myself, with_check_qual,
  						   with_check_pstate->p_rtable, DEPENDENCY_NORMAL);
  
+ 	/* Register role dependencies */
+ 	target.classId = AuthIdRelationId;
+ 	target.objectSubId = 0;
+ 	for (i = 0; i < nitems; i++)
+ 	{
+ 		target.objectId = DatumGetObjectId(role_oids[i]);
+ 		/* no dependency if public */
+ 		if (target.objectId != ACL_ID_PUBLIC)
+ 			recordSharedDependencyOn(&myself, &target,
+ 									 SHARED_DEPENDENCY_POLICY);
+ 	}
+ 
  	/* Invalidate Relation Cache */
  	CacheInvalidateRelcache(target_table);
  
*************** AlterPolicy(AlterPolicyStmt *stmt)
*** 641,646 ****
--- 656,663 ----
  	Oid			policy_id;
  	Relation	target_table;
  	Oid			table_id;
+ 	Datum	   *role_oids;
+ 	int			nitems = 0;
  	ArrayType  *role_ids = NULL;
  	List	   *qual_parse_rtable = NIL;
  	List	   *with_check_parse_rtable = NIL;
*************** AlterPolicy(AlterPolicyStmt *stmt)
*** 658,667 ****
  	Datum		cmd_datum;
  	char		polcmd;
  	bool		polcmd_isnull;
  
  	/* Parse role_ids */
  	if (stmt->roles != NULL)
! 		role_ids = policy_role_list_to_array(stmt->roles);
  
  	/* Get id of table.  Also handles permissions checks. */
  	table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
--- 675,689 ----
  	Datum		cmd_datum;
  	char		polcmd;
  	bool		polcmd_isnull;
+ 	int			i;
  
  	/* Parse role_ids */
  	if (stmt->roles != NULL)
! 	{
! 		role_oids = policy_role_list_to_array(stmt->roles, &nitems);
! 		role_ids = construct_array(role_oids, nitems, OIDOID,
! 								   sizeof(Oid), true, 'i');
! 	}
  
  	/* Get id of table.  Also handles permissions checks. */
  	table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
*************** AlterPolicy(AlterPolicyStmt *stmt)
*** 825,830 ****
--- 847,865 ----
  	recordDependencyOnExpr(&myself, with_check_qual, with_check_parse_rtable,
  						   DEPENDENCY_NORMAL);
  
+ 	/* Register role dependencies */
+ 	deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
+ 	target.classId = AuthIdRelationId;
+ 	target.objectSubId = 0;
+ 	for (i = 0; i < nitems; i++)
+ 	{
+ 		target.objectId = DatumGetObjectId(role_oids[i]);
+ 		/* no dependency if public */
+ 		if (target.objectId != ACL_ID_PUBLIC)
+ 			recordSharedDependencyOn(&myself, &target,
+ 									 SHARED_DEPENDENCY_POLICY);
+ 	}
+ 
  	heap_freetuple(new_tuple);
  
  	/* Invalidate Relation Cache */
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index aa3f3d9..fbcf904 100644
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
*************** typedef enum DependencyType
*** 96,101 ****
--- 96,105 ----
   * created for the owner of an object; hence two objects may be linked by
   * one or the other, but not both, of these dependency types.)
   *
+  * (d) a SHARED_DEPENDENCY_POLICY entry means that the referenced object is
+  * a role mentioned in a policy object.  The referenced object must be a
+  * pg_authid entry.
+  *
   * SHARED_DEPENDENCY_INVALID is a value used as a parameter in internal
   * routines, and is not valid in the catalog itself.
   */
*************** typedef enum SharedDependencyType
*** 104,109 ****
--- 108,114 ----
  	SHARED_DEPENDENCY_PIN = 'p',
  	SHARED_DEPENDENCY_OWNER = 'o',
  	SHARED_DEPENDENCY_ACL = 'a',
+ 	SHARED_DEPENDENCY_POLICY = 'r',
  	SHARED_DEPENDENCY_INVALID = 0
  } SharedDependencyType;
  
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index e7c242c..0983d5b 100644
*** a/src/test/regress/expected/rowsecurity.out
--- b/src/test/regress/expected/rowsecurity.out
*************** SELECT * FROM coll_t;
*** 2860,2865 ****
--- 2860,2920 ----
  
  ROLLBACK;
  --
+ -- Shared Object Dependencies
+ --
+ RESET SESSION AUTHORIZATION;
+ BEGIN;
+ CREATE ROLE alice;
+ CREATE ROLE bob;
+ CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+ GRANT SELECT ON TABLE tbl1 TO alice;
+ CREATE POLICY P ON tbl1 TO alice, bob USING (true);
+ SELECT refclassid::regclass, deptype
+   FROM pg_depend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid = 'tbl1'::regclass;
+  refclassid | deptype 
+ ------------+---------
+  pg_class   | a
+ (1 row)
+ 
+ SELECT refclassid::regclass, deptype
+   FROM pg_shdepend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid IN ('alice'::regrole, 'bob'::regrole);
+  refclassid | deptype 
+ ------------+---------
+  pg_authid  | r
+  pg_authid  | r
+ (2 rows)
+ 
+ SAVEPOINT q;
+ DROP ROLE alice; --fails due to dependency on POLICY p
+ ERROR:  role "alice" cannot be dropped because some objects depend on it
+ DETAIL:  target of policy p on table tbl1
+ privileges for table tbl1
+ ROLLBACK TO q;
+ ALTER POLICY p ON tbl1 TO bob USING (true);
+ SAVEPOINT q;
+ DROP ROLE alice; --fails due to dependency on GRANT SELECT
+ ERROR:  role "alice" cannot be dropped because some objects depend on it
+ DETAIL:  privileges for table tbl1
+ ROLLBACK TO q;
+ REVOKE ALL ON TABLE tbl1 FROM alice;
+ SAVEPOINT q;
+ DROP ROLE alice; --succeeds
+ ROLLBACK TO q;
+ SAVEPOINT q;
+ DROP ROLE bob; --fails due to dependency on POLICY p
+ ERROR:  role "bob" cannot be dropped because some objects depend on it
+ DETAIL:  target of policy p on table tbl1
+ ROLLBACK TO q;
+ DROP POLICY p ON tbl1;
+ SAVEPOINT q;
+ DROP ROLE bob; -- succeeds
+ ROLLBACK TO q;
+ ROLLBACK; -- cleanup
+ --
  -- Clean up objects
  --
  RESET SESSION AUTHORIZATION;
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index e86f814..a074edd 100644
*** a/src/test/regress/sql/rowsecurity.sql
--- b/src/test/regress/sql/rowsecurity.sql
*************** SELECT * FROM coll_t;
*** 1153,1158 ****
--- 1153,1202 ----
  ROLLBACK;
  
  --
+ -- Shared Object Dependencies
+ --
+ RESET SESSION AUTHORIZATION;
+ BEGIN;
+ CREATE ROLE alice;
+ CREATE ROLE bob;
+ CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+ GRANT SELECT ON TABLE tbl1 TO alice;
+ CREATE POLICY P ON tbl1 TO alice, bob USING (true);
+ SELECT refclassid::regclass, deptype
+   FROM pg_depend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid = 'tbl1'::regclass;
+ SELECT refclassid::regclass, deptype
+   FROM pg_shdepend
+   WHERE classid = 'pg_policy'::regclass
+   AND refobjid IN ('alice'::regrole, 'bob'::regrole);
+ 
+ SAVEPOINT q;
+ DROP ROLE alice; --fails due to dependency on POLICY p
+ ROLLBACK TO q;
+ 
+ ALTER POLICY p ON tbl1 TO bob USING (true);
+ SAVEPOINT q;
+ DROP ROLE alice; --fails due to dependency on GRANT SELECT
+ ROLLBACK TO q;
+ 
+ REVOKE ALL ON TABLE tbl1 FROM alice;
+ SAVEPOINT q;
+ DROP ROLE alice; --succeeds
+ ROLLBACK TO q;
+ 
+ SAVEPOINT q;
+ DROP ROLE bob; --fails due to dependency on POLICY p
+ ROLLBACK TO q;
+ 
+ DROP POLICY p ON tbl1;
+ SAVEPOINT q;
+ DROP ROLE bob; -- succeeds
+ ROLLBACK TO q;
+ 
+ ROLLBACK; -- cleanup
+ 
+ --
  -- Clean up objects
  --
  RESET SESSION AUTHORIZATION;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to