I have an application with the following requirements:
Before a predefined event (in my application) occurs, I need to update and insert rows in different tables.
After the event, certain rows in various tables should be set to "ReadOnly," meaning no updates or deletes are allowed on these specific rows.
To implement this, I added an IsReadOnly column to all relevant tables and created functions and security policies to enforce these restrictions.
-- Create schema-bound filter predicate function CREATE FUNCTION dbo.ReadOnlyFilterPredicate(@IsReadOnly BIT) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT 1 AS Result; -- Create schema-bound block predicate function CREATE FUNCTION dbo.ReadOnlyBlockPredicate(@IsReadOnly BIT) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT 1 AS Result WHERE @IsReadOnly = 0; -- Create the security policy with the filter predicate CREATE SECURITY POLICY ReadOnlyPolicy ADD FILTER PREDICATE dbo.ReadOnlyFilterPredicate(IsReadOnly) ON dbo.Plant WITH (STATE = ON); -- Alter the security policy to add block predicates for UPDATE and DELETE ALTER SECURITY POLICY ReadOnlyPolicy ADD BLOCK PREDICATE dbo.ReadOnlyBlockPredicate(IsReadOnly) ON dbo.Plant When a row has IsReadOnly = 0, I can update or delete it as expected. Conversely, if a row has IsReadOnly = 1, updates or deletes are not permitted, which is also as expected.
However, when the event occurs and I attempt to change IsReadOnly from 0 to 1, I encounter an error:
The attempted operation failed because the target object ‘MyTablent' has a block predicate that conflicts with this operation. If the operation is performed on a view, the block predicate might be enforced on the underlying table. Modify the operation to target only the rows that are allowed by the block predicate.
Disabling the security policy temporarily allows me to set IsReadOnly to 1 and then re-enable the policy, which resolves the issue.
However, during the brief period when the security policy is disabled, there is a risk that unauthorized changes could be made to rows.
The problem seems to be that the predicate evaluates the "new" value (e.g., IsReadOnly = 1) instead of the actual value in the table, preventing me from changing IsReadOnly.
I am seeking ideas on how to address this requirement effectively.
dbo.ReadOnlyFilterPredicatethe parameter@IsReadOnlywhen it doesn't make use of it?