Reputation: 113
I'm currently applying this predicate on a VPD policy:
CREATE OR REPLACE FUNCTION limit_table(
schema_p IN VARCHAR2,
table_p IN VARCHAR2)
RETURN VARCHAR2
AS
pred VARCHAR2 (400);
BEGIN
pred := ' ((select count(granted_role) from user_role_privs where (granted_role = Jurisdiction OR granted_role = Business_Domain)) = 2) OR
((Jurisdiction = '''' OR Jurisdiction IS NULL) AND (Business_Domain = '''' OR Business_Domain IS NULL)) ' ;
RETURN pred;
END;
/
What it does is checking if the user has roles matching both the Jurisdiction and Business domain (of the table I assigned the policy to) and also if they are null or empty. In those cases, the row is whitelisted and the user can see it. The problem is that this policy slows down the queries made by the users affected by it more than I would like. The bottleneck is the first clause of the predicate. I also tried with dba_role_privs which allegedly should be faster but performance stays the same.
I followed what this page suggests https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:484621563404 but unfortunately I'm not able to try the third method because my client tells me the sys.user$ table does not exist.
Also tried indexes on jurisdiction and business domain and they don't improve anything.
Originally, the predicate was
pred := '(
(
(
(Business_Domain IS NULL OR
Business_Domain = '''' OR
Business_Domain IN (select granted_role from user_role_privs)
)
AND
(Jurisdiction IS NULL OR
Jurisdiction = '''' OR
Jurisdiction IN (select granted_role from user_role_privs)
)
) )
)';
RETURN pred;
But it was way slower.
Does anyone know ways I can speed up that predicate? Thanks.
Upvotes: 1
Views: 328
Reputation: 113
Thanks to the suggestion by the very kind @WilliamRobertson, I switched the predicate to:
' ((sys_context(''SYS_SESSION_ROLES'', jurisdiction) = ''TRUE'' AND sys_context(''SYS_SESSION_ROLES'', business_domain) = ''TRUE'') OR
((Jurisdiction = '''' OR Jurisdiction IS NULL) AND (Business_Domain = '''' OR Business_Domain IS NULL))) ' ;
This required, however, to make the roles granted by the users defaults, otherwise they would not appear in the session_roles. I did it with:
ALTER USER <name> DEFAULT ROLE ALL;
Upvotes: 2