diff --git a/doc/src/sgml/ref/create_policy.sgml b/doc/src/sgml/ref/create_policy.sgml
index e76c342d3da..42d43ad7bf4 100644
--- a/doc/src/sgml/ref/create_policy.sgml
+++ b/doc/src/sgml/ref/create_policy.sgml
@@ -49,6 +49,8 @@ CREATE POLICY name ON WITH CHECK. When a USING
expression returns true for a given row then that row is visible to the
user, while if false or null is returned then the row is not visible.
+ Typically, no error occurs when a row is not visible, but see
+ for exceptions.
When a WITH CHECK expression returns true for a row
then that row is inserted or updated, while if false or null is returned
then an error occurs.
@@ -194,8 +196,9 @@ CREATE POLICY name ON SELECT), and will not be
available for modification (in an UPDATE
- or DELETE). Such rows are silently suppressed; no error
- is reported.
+ or DELETE). Typically, such rows are silently
+ suppressed; no error is reported (but see
+ for exceptions).
@@ -251,8 +254,10 @@ CREATE POLICY name ON INSERT
or UPDATE command attempts to add rows to the
table that do not pass the ALL
- policy's WITH CHECK expression, the entire
- command will be aborted.
+ policy's WITH CHECK expression (or its
+ USING expression, if it does not have a
+ WITH CHECK expression), the entire command will
+ be aborted.
@@ -268,11 +273,50 @@ CREATE POLICY name ON SELECT policy will be
returned during a SELECT query, and that queries
that require SELECT permissions, such as
- UPDATE, will also only see those records
+ UPDATE, DELETE, and
+ MERGE, will also only see those records
that are allowed by the SELECT policy.
A SELECT policy cannot have a WITH
CHECK expression, as it only applies in cases where
- records are being retrieved from the relation.
+ records are being retrieved from the relation, except as described
+ below.
+
+
+ If a data-modifying query has a RETURNING clause,
+ SELECT permissions are required on the relation,
+ and any newly inserted or updated rows from the relation must satisfy
+ the relation's SELECT policies in order to be
+ available to the RETURNING clause. If a newly
+ inserted or updated row does not satisfy the relation's
+ SELECT policies, an error will be thrown (inserted
+ or updated rows to be returned are never
+ silently ignored).
+
+
+ If an INSERT has an ON CONFLICT DO
+ NOTHING/UPDATE clause, SELECT
+ permissions are required on the relation, and the rows proposed for
+ insertion are checked using the relation's SELECT
+ policies. If a row proposed for insertion does not satisfy the
+ relation's SELECT policies, an error is thrown
+ (the INSERT is never silently
+ avoided). In addition, if the UPDATE path is
+ taken, the row to be updated and the new updated row are checked
+ against the relation's SELECT policies, and an
+ error is thrown if they are not satisfied (an auxiliary
+ UPDATE is never silently
+ avoided).
+
+
+ A MERGE command requires SELECT
+ permissions on both the source and target relations, and so each
+ relation's SELECT policies are applied before they
+ are joined, and the MERGE actions will only see
+ those records that are allowed by those policies. In addition, if
+ an UPDATE action is executed, the target relation's
+ SELECT policies are applied to the updated row, as
+ for a standalone UPDATE, except that an error is
+ thrown if they are not satisfied.
@@ -292,10 +336,11 @@ CREATE POLICY name ON
- Note that INSERT with ON CONFLICT DO
- UPDATE checks INSERT policies'
- WITH CHECK expressions only for rows appended
- to the relation by the INSERT path.
+ Note that an INSERT with an ON CONFLICT
+ DO NOTHING/UPDATE clause will check the
+ INSERT policies' WITH CHECK
+ expressions for all rows proposed for insertion, regardless of
+ whether or not they end up being inserted.
@@ -305,12 +350,12 @@ CREATE POLICY name ON
Using UPDATE for a policy means that it will apply
- to UPDATE, SELECT FOR UPDATE
+ to UPDATE, SELECT FOR UPDATE,
and SELECT FOR SHARE commands, as well as
auxiliary ON CONFLICT DO UPDATE clauses of
- INSERT commands.
- MERGE commands containing UPDATE
- actions are affected as well. Since UPDATE
+ INSERT commands, and MERGE
+ commands containing UPDATE actions.
+ Since an UPDATE command
involves pulling an existing record and replacing it with a new
modified record, UPDATE
policies accept both a USING expression and
@@ -356,7 +401,8 @@ CREATE POLICY name ON USING expressions, an error will be thrown (the
UPDATE path will never be silently
- avoided).
+ avoided). The same applies to an UPDATE action
+ of a MERGE command.
@@ -366,12 +412,18 @@ CREATE POLICY name ON
Using DELETE for a policy means that it will apply
- to DELETE commands. Only rows that pass this
- policy will be seen by a DELETE command. There can
- be rows that are visible through a SELECT that are
- not available for deletion, if they do not pass the
- USING expression for
- the DELETE policy.
+ to DELETE commands and MERGE
+ commands containing DELETE actions. For a
+ DELETE command, only rows that pass this policy
+ will be seen by the DELETE command. There can
+ be rows that are visible through a SELECT policy
+ that are not available for deletion, if they do not pass the
+ USING expression for the DELETE
+ policy. Note, however, that a DELETE action in a
+ MERGE command will see rows that are visible
+ through SELECT policies, and if the
+ DELETE policy does not pass for such a row, an
+ error will be thrown.
@@ -400,6 +452,15 @@ CREATE POLICY name ON
+
+ summarizes how the different
+ types of policy apply to specific commands. In the table,
+ check
means that the policy expression is checked and an
+ error is thrown if it returns false or null, whereas filter
+ means that the row is silently ignored if the policy expression returns
+ false or null.
+
+
Policies Applied by Command Type
@@ -424,8 +485,8 @@ CREATE POLICY name ON
- SELECT
- Existing row
+ SELECT / COPY ... TO
+ Filter existing row
—
—
—
@@ -433,64 +494,118 @@ CREATE POLICY name ON
SELECT FOR UPDATE/SHARE
- Existing row
+ Filter existing row
—
- Existing row
+ Filter existing row
—
—
- INSERT / MERGE ... THEN INSERT
- —
- New row
- —
- —
- —
-
-
- INSERT ... RETURNING
+ INSERT
- New row
+ Check new row
- If read access is required to the existing or new row (for example,
- a WHERE or RETURNING clause
- that refers to columns from the relation).
+ If read access is required to either the existing or new row (for
+ example, a WHERE or RETURNING
+ clause that refers to columns from the relation).
- New row
+ Check new row
—
—
—
- UPDATE / MERGE ... THEN UPDATE
+ UPDATE
- Existing & new rows
+ Filter existing row &
+ check new row
—
- Existing row
- New row
+ Filter existing row
+ Check new row
—
DELETE
- Existing row
+ Filter existing row
+
+ —
+ —
+ —
+ Filter existing row
+
+
+ INSERT ... ON CONFLICT
+
+ Check new row
+
+ Row proposed for insertion is checked regardless of whether or not a
+ conflict occurs.
+
+
+
+
+ Check new row
—
—
—
- Existing row
ON CONFLICT DO UPDATE
- Existing & new rows
+
+ Check existing & new rows
+
+ New row of the auxiliary UPDATE command, which
+ might be different from the new row of the original
+ INSERT command.
+
+
+
—
- Existing row
- New row
+ Check existing row
+
+ Check new row
+
—
+
+ MERGE
+ Filter source & target rows
+ —
+ —
+ —
+ —
+
+
+ MERGE ... THEN INSERT
+
+ Check new row
+
+ Check new row
+ —
+ —
+ —
+
+
+ MERGE ... THEN UPDATE
+ Check new row
+ —
+ Check existing row
+ Check new row
+ —
+
+
+ MERGE ... THEN DELETE
+ —
+ —
+ —
+ —
+ Check existing row
+