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?