diff options
author | Stephen Frost <sfrost@snowman.net> | 2015-04-24 20:34:26 -0400 |
---|---|---|
committer | Stephen Frost <sfrost@snowman.net> | 2015-04-24 20:34:26 -0400 |
commit | e89bd02f58ac07e44e0388a32b7ee1b42f1fd7c6 (patch) | |
tree | e6f42eb3a1d58bf7ff874bc72ae29467cb0bc14f /src/backend/executor/nodeModifyTable.c | |
parent | c8aa893862275614d54a0657d1fb336020c98f60 (diff) | |
download | postgresql-e89bd02f58ac07e44e0388a32b7ee1b42f1fd7c6.tar.gz postgresql-e89bd02f58ac07e44e0388a32b7ee1b42f1fd7c6.zip |
Perform RLS WITH CHECK before constraints, etc
The RLS capability is built on top of the WITH CHECK OPTION
system which was added for auto-updatable views, however, unlike
WCOs on views (which are mandated by the SQL spec to not fire until
after all other constraints and checks are done), it makes much more
sense for RLS checks to happen earlier than constraint and uniqueness
checks.
This patch reworks the structure which holds the WCOs a bit to be
explicitly either VIEW or RLS checks and the RLS-related checks are
done prior to the constraint and uniqueness checks. This also allows
better error reporting as we are now reporting when a violation is due
to a WITH CHECK OPTION and when it's due to an RLS policy violation,
which was independently noted by Craig Ringer as being confusing.
The documentation is also updated to include a paragraph about when RLS
WITH CHECK handling is performed, as there have been a number of
questions regarding that and the documentation was previously silent on
the matter.
Author: Dean Rasheed, with some kabitzing and comment changes by me.
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index f96fb2432b6..06ec82e2461 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -253,6 +253,16 @@ ExecInsert(TupleTableSlot *slot, tuple->t_tableOid = RelationGetRelid(resultRelationDesc); /* + * Check any RLS INSERT WITH CHECK policies + * + * ExecWithCheckOptions() will skip any WCOs which are not of + * the kind we are looking for at this point. + */ + if (resultRelInfo->ri_WithCheckOptions != NIL) + ExecWithCheckOptions(WCO_RLS_INSERT_CHECK, + resultRelInfo, slot, estate); + + /* * Check the constraints of the tuple */ if (resultRelationDesc->rd_att->constr) @@ -287,9 +297,21 @@ ExecInsert(TupleTableSlot *slot, list_free(recheckIndexes); - /* Check any WITH CHECK OPTION constraints */ + /* + * Check any WITH CHECK OPTION constraints from parent views. We + * are required to do this after testing all constraints and + * uniqueness violations per the SQL spec, so we do it after actually + * inserting the record into the heap and all indexes. + * + * ExecWithCheckOptions will elog(ERROR) if a violation is found, so + * the tuple will never be seen, if it violates the the WITH CHECK + * OPTION. + * + * ExecWithCheckOptions() will skip any WCOs which are not of + * the kind we are looking for at this point. + */ if (resultRelInfo->ri_WithCheckOptions != NIL) - ExecWithCheckOptions(resultRelInfo, slot, estate); + ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate); /* Process RETURNING if present */ if (resultRelInfo->ri_projectReturning) @@ -653,15 +675,25 @@ ExecUpdate(ItemPointer tupleid, tuple->t_tableOid = RelationGetRelid(resultRelationDesc); /* - * Check the constraints of the tuple + * Check any RLS UPDATE WITH CHECK policies * * If we generate a new candidate tuple after EvalPlanQual testing, we - * must loop back here and recheck constraints. (We don't need to - * redo triggers, however. If there are any BEFORE triggers then - * trigger.c will have done heap_lock_tuple to lock the correct tuple, - * so there's no need to do them again.) + * must loop back here and recheck any RLS policies and constraints. + * (We don't need to redo triggers, however. If there are any BEFORE + * triggers then trigger.c will have done heap_lock_tuple to lock the + * correct tuple, so there's no need to do them again.) + * + * ExecWithCheckOptions() will skip any WCOs which are not of + * the kind we are looking for at this point. */ lreplace:; + if (resultRelInfo->ri_WithCheckOptions != NIL) + ExecWithCheckOptions(WCO_RLS_UPDATE_CHECK, + resultRelInfo, slot, estate); + + /* + * Check the constraints of the tuple + */ if (resultRelationDesc->rd_att->constr) ExecConstraints(resultRelInfo, slot, estate); @@ -780,9 +812,17 @@ lreplace:; list_free(recheckIndexes); - /* Check any WITH CHECK OPTION constraints */ + /* + * Check any WITH CHECK OPTION constraints from parent views. We + * are required to do this after testing all constraints and + * uniqueness violations per the SQL spec, so we do it after actually + * updating the record in the heap and all indexes. + * + * ExecWithCheckOptions() will skip any WCOs which are not of + * the kind we are looking for at this point. + */ if (resultRelInfo->ri_WithCheckOptions != NIL) - ExecWithCheckOptions(resultRelInfo, slot, estate); + ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate); /* Process RETURNING if present */ if (resultRelInfo->ri_projectReturning) |