While addressing Thomas's point about test scenarios not yet covered, I observed the following ...
Suppose an UPDATE RLS policy with a WITH CHECK clause is defined on the target table. Now In ExecUpdate(), the corresponding WCO qual gets executed *before* the partition constraint check, as per existing behaviour. And the qual succeeds. And then because of partition-key updated, the row is moved to another partition. Here, suppose there is a BR INSERT trigger which modifies the row, and the resultant row actually would *not* pass the UPDATE RLS policy. But for this partition, since it is an INSERT, only INSERT RLS WCO quals are executed. So effectively, with a user-perspective, an RLS WITH CHECK policy that was defined to reject an updated row, is getting updated successfully. This is because the policy is not checked *after* a row trigger in the new partition is executed. Attached is a test case that reproduces this issue. I think, in case of row-movement, we should defer calling ExecWithCheckOptions() until the row is being inserted using ExecInsert(). And then in ExecInsert(), ExecWithCheckOptions() should be called using WCO_RLS_UPDATE_CHECK rather than WCO_RLS_INSERT_CHECK (I recall Amit Langote was of this opinion) as below : --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -510,7 +510,9 @@ ExecInsert(ModifyTableState *mtstate, * we are looking for at this point. */ if (resultRelInfo->ri_WithCheckOptions != NIL) - ExecWithCheckOptions(WCO_RLS_INSERT_CHECK, + ExecWithCheckOptions((mtstate->operation == CMD_UPDATE ? + WCO_RLS_UPDATE_CHECK : WCO_RLS_INSERT_CHECK), resultRelInfo, slot, estate); It can be argued that since in case of triggers we always execute INSERT row triggers for rows inserted as part of update-row-movement, we should be consistent and execute INSERT WCOs and not UPDATE WCOs for such rows. But note that, the row triggers we execute are defined on the leaf partitions. But the RLS policies being executed are defined for the target partitioned table, and not the leaf partition. Hence it makes sense to execute them as per the original operation on the target table. This is similar to why we execute UPDATE statement triggers even when the row is eventually inserted into another partition. This is because UPDATE statement trigger was defined for the target table, not the leaf partition. Barring any objections, I am going to send a revised patch that fixes the above issue as described. Thanks -Amit Khandekar
wco_rls_issue.sql
Description: Binary data