@@ -49,6 +49,8 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
4949 in <literal>WITH CHECK</literal>. When a <literal>USING</literal>
5050 expression returns true for a given row then that row is visible to the
5151 user, while if false or null is returned then the row is not visible.
52+ Typically, no error occurs when a row is not visible, but see
53+ <xref linkend="sql-createpolicy-summary"/> for exceptions.
5254 When a <literal>WITH CHECK</literal> expression returns true for a row
5355 then that row is inserted or updated, while if false or null is returned
5456 then an error occurs.
@@ -193,8 +195,9 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
193195 rows for which the expression returns false or null will not be
194196 visible to the user (in a <command>SELECT</command>), and will not be
195197 available for modification (in an <command>UPDATE</command>
196- or <command>DELETE</command>). Such rows are silently suppressed; no error
197- is reported.
198+ or <command>DELETE</command>). Typically, such rows are silently
199+ suppressed; no error is reported (but see
200+ <xref linkend="sql-createpolicy-summary"/> for exceptions).
198201 </para>
199202 </listitem>
200203 </varlistentry>
@@ -250,8 +253,10 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
250253 otherwise). If an <command>INSERT</command>
251254 or <command>UPDATE</command> command attempts to add rows to the
252255 table that do not pass the <literal>ALL</literal>
253- policy's <literal>WITH CHECK</literal> expression, the entire
254- command will be aborted.
256+ policy's <literal>WITH CHECK</literal> expression (or its
257+ <literal>USING</literal> expression, if it does not have a
258+ <literal>WITH CHECK</literal> expression), the entire command will
259+ be aborted.
255260 </para>
256261 </listitem>
257262 </varlistentry>
@@ -267,11 +272,39 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
267272 relation that pass the <literal>SELECT</literal> policy will be
268273 returned during a <literal>SELECT</literal> query, and that queries
269274 that require <literal>SELECT</literal> permissions, such as
270- <literal>UPDATE</literal>, will also only see those records
275+ <literal>UPDATE</literal> and <literal>DELETE</literal>,
276+ will also only see those records
271277 that are allowed by the <literal>SELECT</literal> policy.
272278 A <literal>SELECT</literal> policy cannot have a <literal>WITH
273279 CHECK</literal> expression, as it only applies in cases where
274- records are being retrieved from the relation.
280+ records are being retrieved from the relation, except as described
281+ below.
282+ </para>
283+ <para>
284+ If a data-modifying query has a <literal>RETURNING</literal> clause,
285+ <literal>SELECT</literal> permissions are required on the relation,
286+ and any newly inserted or updated rows from the relation must satisfy
287+ the relation's <literal>SELECT</literal> policies in order to be
288+ available to the <literal>RETURNING</literal> clause. If a newly
289+ inserted or updated row does not satisfy the relation's
290+ <literal>SELECT</literal> policies, an error will be thrown (inserted
291+ or updated rows to be returned are <emphasis>never</emphasis>
292+ silently ignored).
293+ </para>
294+ <para>
295+ If an <literal>INSERT</literal> has an <literal>ON CONFLICT DO
296+ NOTHING/UPDATE</literal> clause, <literal>SELECT</literal>
297+ permissions are required on the relation, and the rows proposed for
298+ insertion are checked using the relation's <literal>SELECT</literal>
299+ policies. If a row proposed for insertion does not satisfy the
300+ relation's <literal>SELECT</literal> policies, an error is thrown
301+ (the <literal>INSERT</literal> is <emphasis>never</emphasis> silently
302+ avoided). In addition, if the <literal>UPDATE</literal> path is
303+ taken, the row to be updated and the new updated row are checked
304+ against the relation's <literal>SELECT</literal> policies, and an
305+ error is thrown if they are not satisfied (an auxiliary
306+ <literal>UPDATE</literal> is <emphasis>never</emphasis> silently
307+ avoided).
275308 </para>
276309 </listitem>
277310 </varlistentry>
@@ -289,10 +322,11 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
289322 where records are being added to the relation.
290323 </para>
291324 <para>
292- Note that <literal>INSERT</literal> with <literal>ON CONFLICT DO
293- UPDATE</literal> checks <literal>INSERT</literal> policies'
294- <literal>WITH CHECK</literal> expressions only for rows appended
295- to the relation by the <literal>INSERT</literal> path.
325+ Note that an <literal>INSERT</literal> with an <literal>ON CONFLICT
326+ DO NOTHING/UPDATE</literal> clause will check the
327+ <literal>INSERT</literal> policies' <literal>WITH CHECK</literal>
328+ expressions for all rows proposed for insertion, regardless of
329+ whether or not they end up being inserted.
296330 </para>
297331 </listitem>
298332 </varlistentry>
@@ -363,10 +397,10 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
363397 Using <literal>DELETE</literal> for a policy means that it will apply
364398 to <literal>DELETE</literal> commands. Only rows that pass this
365399 policy will be seen by a <literal>DELETE</literal> command. There can
366- be rows that are visible through a <literal>SELECT</literal> that are
367- not available for deletion, if they do not pass the
368- <literal>USING</literal> expression for
369- the <literal>DELETE</literal> policy.
400+ be rows that are visible through a <literal>SELECT</literal> policy
401+ that are not available for deletion, if they do not pass the
402+ <literal>USING</literal> expression for the <literal>DELETE</literal>
403+ policy.
370404 </para>
371405
372406 <para>
@@ -395,6 +429,15 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
395429
396430 </variablelist>
397431
432+ <para>
433+ <xref linkend="sql-createpolicy-summary"/> summarizes how the different
434+ types of policy apply to specific commands. In the table,
435+ <quote>check</quote> means that the policy expression is checked and an
436+ error is thrown if it returns false or null, whereas <quote>filter</quote>
437+ means that the row is silently ignored if the policy expression returns
438+ false or null.
439+ </para>
440+
398441 <table id="sql-createpolicy-summary">
399442 <title>Policies Applied by Command Type</title>
400443 <tgroup cols="6">
@@ -419,71 +462,91 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
419462 </thead>
420463 <tbody>
421464 <row>
422- <entry><command>SELECT</command></entry>
423- <entry>Existing row</entry>
465+ <entry><command>SELECT</command> / <command>COPY ... TO</command> </entry>
466+ <entry>Filter existing row</entry>
424467 <entry>—</entry>
425468 <entry>—</entry>
426469 <entry>—</entry>
427470 <entry>—</entry>
428471 </row>
429472 <row>
430473 <entry><command>SELECT FOR UPDATE/SHARE</command></entry>
431- <entry>Existing row</entry>
474+ <entry>Filter existing row</entry>
432475 <entry>—</entry>
433- <entry>Existing row</entry>
476+ <entry>Filter existing row</entry>
434477 <entry>—</entry>
435478 <entry>—</entry>
436479 </row>
437480 <row>
438481 <entry><command>INSERT</command></entry>
439- <entry>—</entry>
440- <entry>New row</entry>
441- <entry>—</entry>
442- <entry>—</entry>
443- <entry>—</entry>
444- </row>
445- <row>
446- <entry><command>INSERT ... RETURNING</command></entry>
447482 <entry>
448- New row <footnote id="rls-select-priv">
483+ Check new row <footnote id="rls-select-priv">
449484 <para>
450- If read access is required to the existing or new row (for example,
451- a <literal>WHERE</literal> or <literal>RETURNING</literal> clause
452- that refers to columns from the relation).
485+ If read access is required to either the existing or new row (for
486+ example, a <literal>WHERE</literal> or <literal>RETURNING</literal>
487+ clause that refers to columns from the relation).
453488 </para>
454489 </footnote>
455490 </entry>
456- <entry>New row</entry>
491+ <entry>Check new row</entry>
457492 <entry>—</entry>
458493 <entry>—</entry>
459494 <entry>—</entry>
460495 </row>
461496 <row>
462497 <entry><command>UPDATE</command></entry>
463498 <entry>
464- Existing & new rows <footnoteref linkend="rls-select-priv"/>
499+ Filter existing row <footnoteref linkend="rls-select-priv"/> &
500+ check new row <footnoteref linkend="rls-select-priv"/>
465501 </entry>
466502 <entry>—</entry>
467- <entry>Existing row</entry>
468- <entry>New row</entry>
503+ <entry>Filter existing row</entry>
504+ <entry>Check new row</entry>
469505 <entry>—</entry>
470506 </row>
471507 <row>
472508 <entry><command>DELETE</command></entry>
473509 <entry>
474- Existing row <footnoteref linkend="rls-select-priv"/>
510+ Filter existing row <footnoteref linkend="rls-select-priv"/>
511+ </entry>
512+ <entry>—</entry>
513+ <entry>—</entry>
514+ <entry>—</entry>
515+ <entry>Filter existing row</entry>
516+ </row>
517+ <row>
518+ <entry><command>INSERT ... ON CONFLICT</command></entry>
519+ <entry>
520+ Check new row <footnote id="rls-on-conflict-priv">
521+ <para>
522+ Row proposed for insertion is checked regardless of whether or not a
523+ conflict occurs.
524+ </para>
525+ </footnote>
526+ </entry>
527+ <entry>
528+ Check new row <footnoteref linkend="rls-on-conflict-priv"/>
475529 </entry>
476530 <entry>—</entry>
477531 <entry>—</entry>
478532 <entry>—</entry>
479- <entry>Existing row</entry>
480533 </row>
481534 <row>
482535 <entry><command>ON CONFLICT DO UPDATE</command></entry>
483- <entry>Existing & new rows</entry>
536+ <entry>
537+ Check existing & new rows <footnote id="rls-on-conflict-update-priv">
538+ <para>
539+ New row of the auxiliary <command>UPDATE</command> command, which
540+ might be different from the new row of the original
541+ <command>INSERT</command> command.
542+ </para>
543+ </footnote>
544+ </entry>
484545 <entry>—</entry>
485- <entry>Existing row</entry>
486- <entry>New row</entry>
546+ <entry>Check existing row</entry>
547+ <entry>
548+ Check new row <footnoteref linkend="rls-on-conflict-update-priv"/>
549+ </entry>
487550 <entry>—</entry>
488551 </row>
489552 </tbody>
0 commit comments