Mercurial > gemma
comparison schema/auth.sql @ 4161:64cd18281c76
Improve performance of row level security policies
Using constraint_column_usage instead of key_column_usage makes
the query twice as fast. I did not explore why. Let's just take it.
Using 'EXISTS(... WHERE ... = value) is often more efficient than
value IN(...) since it allows the inner query to be executed only
up to the point where it turns out to return more than nothing with
filtering directly in place.
author | Tom Gottfried <tom@intevation.de> |
---|---|
date | Fri, 02 Aug 2019 17:14:13 +0200 |
parents | 5466562cca60 |
children | 27ed6f709195 |
comparison
equal
deleted
inserted
replaced
4160:7cccf7fef3e8 | 4161:64cd18281c76 |
---|---|
74 -- | 74 -- |
75 -- RLS policies for waterway_user | 75 -- RLS policies for waterway_user |
76 -- | 76 -- |
77 -- Sometimes using FOR ALL because we rely on GRANTed privileges for allowing | 77 -- Sometimes using FOR ALL because we rely on GRANTed privileges for allowing |
78 -- data modifications generally. | 78 -- data modifications generally. |
79 -- Sometimes using 'username IN(SELECT username FROM users.list_users)' instead | 79 -- Sometimes using 'EXISTS(SELECT 1 FROM list_users WHERE username = ...)' |
80 -- of 'username = current_user', because waterway_admin is intentionally | 80 -- instead of 'username = current_user', since waterway_admin is intentionally |
81 -- allowed more with these policies (note that the subselect implies different | 81 -- allowed more with these policies (note that the subselect implies different |
82 -- filtering on list_users depending on current_user). | 82 -- filtering on list_users depending on current_user). |
83 -- | 83 -- |
84 | 84 |
85 -- Staging area | 85 -- Staging area |
174 AS $$ | 174 AS $$ |
175 DECLARE columnname varchar; | 175 DECLARE columnname varchar; |
176 DECLARE ret boolean; | 176 DECLARE ret boolean; |
177 BEGIN | 177 BEGIN |
178 columnname = (SELECT column_name | 178 columnname = (SELECT column_name |
179 FROM information_schema.key_column_usage k | 179 FROM information_schema.constraint_column_usage k |
180 JOIN information_schema.table_constraints USING (constraint_name) | 180 JOIN information_schema.table_constraints USING (constraint_name) |
181 WHERE k.table_name = tablename and constraint_type = 'PRIMARY KEY'); | 181 WHERE k.table_name = tablename and constraint_type = 'PRIMARY KEY'); |
182 EXECUTE format('SELECT NOT $1 = ANY(SELECT %I FROM import.%I)', | 182 EXECUTE format('SELECT NOT EXISTS(SELECT 1 FROM import.%I WHERE %I = $1)', |
183 columnname, tablename) | 183 tablename, columnname) |
184 INTO ret | 184 INTO ret |
185 USING kv; | 185 USING kv; |
186 RETURN ret; | 186 RETURN ret; |
187 END; | 187 END; |
188 $$ | 188 $$ |
190 SECURITY DEFINER | 190 SECURITY DEFINER |
191 STABLE PARALLEL SAFE; | 191 STABLE PARALLEL SAFE; |
192 | 192 |
193 CREATE POLICY parent_allowed ON import.import_logs | 193 CREATE POLICY parent_allowed ON import.import_logs |
194 FOR ALL TO waterway_admin | 194 FOR ALL TO waterway_admin |
195 USING (import_id IN (SELECT id FROM import.imports)) | 195 USING (EXISTS(SELECT 1 FROM import.imports WHERE id = import_id)) |
196 WITH CHECK (import.is_new_key('imports', import_id) | 196 WITH CHECK (import.is_new_key('imports', import_id) |
197 OR import_id IN (SELECT id FROM import.imports)); | 197 OR EXISTS(SELECT 1 FROM import.imports WHERE id = import_id)); |
198 ALTER table import.import_logs ENABLE ROW LEVEL SECURITY; | 198 ALTER table import.import_logs ENABLE ROW LEVEL SECURITY; |
199 | 199 |
200 CREATE POLICY parent_allowed ON import.track_imports | 200 CREATE POLICY parent_allowed ON import.track_imports |
201 FOR ALL TO waterway_admin | 201 FOR ALL TO waterway_admin |
202 USING (import_id IN (SELECT id FROM import.imports)) | 202 USING (EXISTS(SELECT 1 FROM import.imports WHERE id = import_id)) |
203 WITH CHECK (import.is_new_key('imports', import_id) | 203 WITH CHECK (import.is_new_key('imports', import_id) |
204 OR import_id IN (SELECT id FROM import.imports)); | 204 OR EXISTS(SELECT 1 FROM import.imports WHERE id = import_id)); |
205 ALTER table import.track_imports ENABLE ROW LEVEL SECURITY; | 205 ALTER table import.track_imports ENABLE ROW LEVEL SECURITY; |
206 | 206 |
207 CREATE POLICY import_configuration_policy ON import.import_configuration | 207 CREATE POLICY import_configuration_policy ON import.import_configuration |
208 FOR ALL TO waterway_admin | 208 FOR ALL TO waterway_admin |
209 USING ( | 209 -- Relies on a user seeing only users from his own country: |
210 (SELECT country FROM users.list_users WHERE username = current_user) = ( | 210 USING (EXISTS(SELECT 1 FROM users.list_users lu |
211 SELECT country FROM users.list_users lu | 211 WHERE lu.username = import_configuration.username)); |
212 WHERE lu.username = import.import_configuration.username)); | |
213 | 212 |
214 CREATE POLICY import_configuration_policy_sys_admin ON import.import_configuration | 213 CREATE POLICY import_configuration_policy_sys_admin ON import.import_configuration |
215 FOR ALL TO sys_admin | 214 FOR ALL TO sys_admin |
216 USING (true); | 215 USING (true); |
217 | 216 |
218 ALTER table import.import_configuration ENABLE ROW LEVEL SECURITY; | 217 ALTER table import.import_configuration ENABLE ROW LEVEL SECURITY; |
219 | 218 |
220 CREATE POLICY parent_allowed ON import.import_configuration_attributes | 219 CREATE POLICY parent_allowed ON import.import_configuration_attributes |
221 FOR ALL TO waterway_admin | 220 FOR ALL TO waterway_admin |
222 USING (import_configuration_id IN ( | 221 USING (EXISTS(SELECT 1 FROM import.import_configuration |
223 SELECT id FROM import.import_configuration)) | 222 WHERE id = import_configuration_id)) |
224 WITH CHECK ( | 223 WITH CHECK ( |
225 import.is_new_key('import_configuration', import_configuration_id) | 224 import.is_new_key('import_configuration', import_configuration_id) |
226 OR import_configuration_id IN ( | 225 OR EXISTS(SELECT 1 FROM import.import_configuration |
227 SELECT id FROM import.import_configuration)); | 226 WHERE id = import_configuration_id)); |
228 ALTER table import.import_configuration_attributes ENABLE ROW LEVEL SECURITY; | 227 ALTER table import.import_configuration_attributes ENABLE ROW LEVEL SECURITY; |
229 | 228 |
230 COMMIT; | 229 COMMIT; |