ALTER POLICY

On this page Carat arrow pointing down

The ALTER POLICY statement changes an existing row-level security (RLS) policy on a table.

Allowed changes to a policy using ALTER POLICY include:

Note:

You cannot use ALTER POLICY to change the PERMISSIVE or RESTRICTIVE nature of the policy, nor its applicable FOR command (as defined by CREATE POLICY ... ON ... { PERMISSIVE | RESTRICTIVE } ... FOR { ALL | SELECT | ... }). If you want to make these changes, you must start over with DROP POLICY and CREATE POLICY. For an example, see Replace a policy.

Syntax

icon/buttons/copy
ALTER POLICY policy_name ON table_name RENAME TO new_policy_name;

ALTER POLICY policy_name ON table_name
    [ TO { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ]
    [ USING ( using_expression ) ]
    [ WITH CHECK ( check_expression ) ];

Parameters

Parameter Description
policy_name The identifier of the existing policy to be modified. Must be unique for the specified table_name.
ON table_name The name of the table on which the policy policy_name is defined.
RENAME TO { new_policy_name } The new identifier for the policy. The new_policy_name must be a unique name on table_name.
`TO { role_name PUBLIC
USING ( using_expression ) Replaces the previous value of this expression. For details about this expression, see CREATE POLICY.
WITH CHECK ( check_expression ) Replaces the previous value of this expression. For details about this expression, see CREATE POLICY.

Examples

In this example, we start by only allowing users to see or modify their own rows in an orders table. Then, as the schema is updated due to business requirements, we must refine the policy to take into account the new requirements.

icon/buttons/copy
CREATE TABLE orders (user_id TEXT PRIMARY KEY, order_details TEXT);

The original policy on the table was as follows:

icon/buttons/copy
    CREATE POLICY user_orders_policy ON orders
        FOR ALL
        TO PUBLIC
        USING ( user_id = current_user )
        WITH CHECK ( user_id = current_user );

However, the orders table schema has been updated to include an is_archived flag, and the initial policy needs refinement.

icon/buttons/copy
-- Assume this change was made after the initial policy was created
ALTER TABLE orders ADD COLUMN is_archived BOOLEAN DEFAULT FALSE NOT NULL;
CREATE INDEX idx_orders_user_id_is_archived ON orders(user_id, is_archived); -- For performance

The policy requirements have changed as follows:

  1. The policy should now only apply to users belonging to the customer_service role, not PUBLIC.
  2. Users (in customer_service) should only be able to view and modify orders that are not archived (is_archived = FALSE). Archived orders should be invisible/immutable via this policy.

This assumes the customer_service role has been created:

icon/buttons/copy
CREATE ROLE customer_service;

This leads to the following ALTER POLICY statement:

icon/buttons/copy
ALTER POLICY user_orders_policy ON orders
    -- 1. Change the applicable role(s)
    TO customer_service
    -- 2. Update the USING clause to filter out archived orders
    USING ( user_id = current_user AND is_archived = FALSE )
    -- 3. Update the WITH CHECK clause to prevent archiving/modifying archived orders via this policy
    WITH CHECK ( user_id = current_user AND is_archived = FALSE );

The changes to the ALTER POLICY statement can be explained as follows:

  • TO customer_service: Restricts the policy's application from all users (PUBLIC) to only those who are members of the customer_service role. Other users will no longer be affected by this specific policy (they would need other applicable policies or RLS would deny access by default).
  • USING ( user_id = current_user AND is_archived = FALSE ): Modifies the visibility rule. Now, customer_service users can only see rows matching their user_id and where is_archived is false.
  • WITH CHECK ( user_id = current_user AND is_archived = FALSE ): Modifies the constraint for INSERT/UPDATE. Users attempting modifications must satisfy the user_id match, and the resulting row must have is_archived = FALSE. This prevents them from inserting archived orders or updating an order to set is_archived = TRUE via operations governed by this policy.

This ALTER POLICY statement reflects a typical evolution: refining role targeting and adapting the policy logic to accommodate schema changes and evolving access control requirements.

See also


Yes No
On this page

Yes No