@@ -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.
@@ -194,8 +196,9 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
194196 rows for which the expression returns false or null will not be
195197 visible to the user (in a <command>SELECT</command>), and will not be
196198 available for modification (in an <command>UPDATE</command>
197- or <command>DELETE</command>). Such rows are silently suppressed; no error
198- is reported.
199+ or <command>DELETE</command>). Typically, such rows are silently
200+ suppressed; no error is reported (but see
201+ <xref linkend="sql-createpolicy-summary"/> for exceptions).
199202 </para>
200203 </listitem>
201204 </varlistentry>
@@ -251,8 +254,10 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
251254 otherwise). If an <command>INSERT</command>
252255 or <command>UPDATE</command> command attempts to add rows to the
253256 table that do not pass the <literal>ALL</literal>
254- policy's <literal>WITH CHECK</literal> expression, the entire
255- command will be aborted.
257+ policy's <literal>WITH CHECK</literal> expression (or its
258+ <literal>USING</literal> expression, if it does not have a
259+ <literal>WITH CHECK</literal> expression), the entire command will
260+ be aborted.
256261 </para>
257262 </listitem>
258263 </varlistentry>
@@ -268,11 +273,50 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
268273 relation that pass the <literal>SELECT</literal> policy will be
269274 returned during a <literal>SELECT</literal> query, and that queries
270275 that require <literal>SELECT</literal> permissions, such as
271- <literal>UPDATE</literal>, will also only see those records
276+ <literal>UPDATE</literal>, <literal>DELETE</literal>, and
277+ <literal>MERGE</literal>, will also only see those records
272278 that are allowed by the <literal>SELECT</literal> policy.
273279 A <literal>SELECT</literal> policy cannot have a <literal>WITH
274280 CHECK</literal> expression, as it only applies in cases where
275- records are being retrieved from the relation.
281+ records are being retrieved from the relation, except as described
282+ below.
283+ </para>
284+ <para>
285+ If a data-modifying query has a <literal>RETURNING</literal> clause,
286+ <literal>SELECT</literal> permissions are required on the relation,
287+ and any newly inserted or updated rows from the relation must satisfy
288+ the relation's <literal>SELECT</literal> policies in order to be
289+ available to the <literal>RETURNING</literal> clause. If a newly
290+ inserted or updated row does not satisfy the relation's
291+ <literal>SELECT</literal> policies, an error will be thrown (inserted
292+ or updated rows to be returned are <emphasis>never</emphasis>
293+ silently ignored).
294+ </para>
295+ <para>
296+ If an <literal>INSERT</literal> has an <literal>ON CONFLICT DO
297+ NOTHING/UPDATE</literal> clause, <literal>SELECT</literal>
298+ permissions are required on the relation, and the rows proposed for
299+ insertion are checked using the relation's <literal>SELECT</literal>
300+ policies. If a row proposed for insertion does not satisfy the
301+ relation's <literal>SELECT</literal> policies, an error is thrown
302+ (the <literal>INSERT</literal> is <emphasis>never</emphasis> silently
303+ avoided). In addition, if the <literal>UPDATE</literal> path is
304+ taken, the row to be updated and the new updated row are checked
305+ against the relation's <literal>SELECT</literal> policies, and an
306+ error is thrown if they are not satisfied (an auxiliary
307+ <literal>UPDATE</literal> is <emphasis>never</emphasis> silently
308+ avoided).
309+ </para>
310+ <para>
311+ A <literal>MERGE</literal> command requires <literal>SELECT</literal>
312+ permissions on both the source and target relations, and so each
313+ relation's <literal>SELECT</literal> policies are applied before they
314+ are joined, and the <literal>MERGE</literal> actions will only see
315+ those records that are allowed by those policies. In addition, if
316+ an <literal>UPDATE</literal> action is executed, the target relation's
317+ <literal>SELECT</literal> policies are applied to the updated row, as
318+ for a standalone <literal>UPDATE</literal>, except that an error is
319+ thrown if they are not satisfied.
276320 </para>
277321 </listitem>
278322 </varlistentry>
@@ -292,10 +336,11 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
292336 where records are being added to the relation.
293337 </para>
294338 <para>
295- Note that <literal>INSERT</literal> with <literal>ON CONFLICT DO
296- UPDATE</literal> checks <literal>INSERT</literal> policies'
297- <literal>WITH CHECK</literal> expressions only for rows appended
298- to the relation by the <literal>INSERT</literal> path.
339+ Note that an <literal>INSERT</literal> with an <literal>ON CONFLICT
340+ DO NOTHING/UPDATE</literal> clause will check the
341+ <literal>INSERT</literal> policies' <literal>WITH CHECK</literal>
342+ expressions for all rows proposed for insertion, regardless of
343+ whether or not they end up being inserted.
299344 </para>
300345 </listitem>
301346 </varlistentry>
@@ -305,12 +350,12 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
305350 <listitem>
306351 <para>
307352 Using <literal>UPDATE</literal> for a policy means that it will apply
308- to <literal>UPDATE</literal>, <literal>SELECT FOR UPDATE</literal>
353+ to <literal>UPDATE</literal>, <literal>SELECT FOR UPDATE</literal>,
309354 and <literal>SELECT FOR SHARE</literal> commands, as well as
310355 auxiliary <literal>ON CONFLICT DO UPDATE</literal> clauses of
311- <literal>INSERT</literal> commands.
312- <literal>MERGE</literal> commands containing <literal>UPDATE</literal>
313- actions are affected as well. Since <literal>UPDATE</literal>
356+ <literal>INSERT</literal> commands, and <literal>MERGE</literal>
357+ commands containing <literal>UPDATE</literal> actions.
358+ Since an <literal>UPDATE</literal> command
314359 involves pulling an existing record and replacing it with a new
315360 modified record, <literal>UPDATE</literal>
316361 policies accept both a <literal>USING</literal> expression and
@@ -356,7 +401,8 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
356401 command, if the existing row does not pass the
357402 <literal>USING</literal> expressions, an error will be thrown (the
358403 <literal>UPDATE</literal> path will <emphasis>never</emphasis> be silently
359- avoided).
404+ avoided). The same applies to an <literal>UPDATE</literal> action
405+ of a <command>MERGE</command> command.
360406 </para>
361407 </listitem>
362408 </varlistentry>
@@ -366,12 +412,18 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
366412 <listitem>
367413 <para>
368414 Using <literal>DELETE</literal> for a policy means that it will apply
369- to <literal>DELETE</literal> commands. Only rows that pass this
370- policy will be seen by a <literal>DELETE</literal> command. There can
371- be rows that are visible through a <literal>SELECT</literal> that are
372- not available for deletion, if they do not pass the
373- <literal>USING</literal> expression for
374- the <literal>DELETE</literal> policy.
415+ to <literal>DELETE</literal> commands and <literal>MERGE</literal>
416+ commands containing <literal>DELETE</literal> actions. For a
417+ <literal>DELETE</literal> command, only rows that pass this policy
418+ will be seen by the <literal>DELETE</literal> command. There can
419+ be rows that are visible through a <literal>SELECT</literal> policy
420+ that are not available for deletion, if they do not pass the
421+ <literal>USING</literal> expression for the <literal>DELETE</literal>
422+ policy. Note, however, that a <literal>DELETE</literal> action in a
423+ <literal>MERGE</literal> command will see rows that are visible
424+ through <literal>SELECT</literal> policies, and if the
425+ <literal>DELETE</literal> policy does not pass for such a row, an
426+ error will be thrown.
375427 </para>
376428
377429 <para>
@@ -400,6 +452,15 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
400452
401453 </variablelist>
402454
455+ <para>
456+ <xref linkend="sql-createpolicy-summary"/> summarizes how the different
457+ types of policy apply to specific commands. In the table,
458+ <quote>check</quote> means that the policy expression is checked and an
459+ error is thrown if it returns false or null, whereas <quote>filter</quote>
460+ means that the row is silently ignored if the policy expression returns
461+ false or null.
462+ </para>
463+
403464 <table id="sql-createpolicy-summary">
404465 <title>Policies Applied by Command Type</title>
405466 <tgroup cols="6">
@@ -424,72 +485,126 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
424485 </thead>
425486 <tbody>
426487 <row>
427- <entry><command>SELECT</command></entry>
428- <entry>Existing row</entry>
488+ <entry><command>SELECT</command> / <command>COPY ... TO</command> </entry>
489+ <entry>Filter existing row</entry>
429490 <entry>—</entry>
430491 <entry>—</entry>
431492 <entry>—</entry>
432493 <entry>—</entry>
433494 </row>
434495 <row>
435496 <entry><command>SELECT FOR UPDATE/SHARE</command></entry>
436- <entry>Existing row</entry>
497+ <entry>Filter existing row</entry>
437498 <entry>—</entry>
438- <entry>Existing row</entry>
499+ <entry>Filter existing row</entry>
439500 <entry>—</entry>
440501 <entry>—</entry>
441502 </row>
442503 <row>
443- <entry><command>INSERT</command> / <command>MERGE ... THEN INSERT</command></entry>
504+ <entry><command>INSERT</command></entry>
505+ <entry>
506+ Check new row <footnote id="rls-select-priv">
507+ <para>
508+ If read access is required to either the existing or new row (for
509+ example, a <literal>WHERE</literal> or <literal>RETURNING</literal>
510+ clause that refers to columns from the relation).
511+ </para>
512+ </footnote>
513+ </entry>
514+ <entry>Check new row</entry>
444515 <entry>—</entry>
445- <entry>New row</entry>
446516 <entry>—</entry>
447517 <entry>—</entry>
518+ </row>
519+ <row>
520+ <entry><command>UPDATE</command></entry>
521+ <entry>
522+ Filter existing row <footnoteref linkend="rls-select-priv"/> &
523+ check new row <footnoteref linkend="rls-select-priv"/>
524+ </entry>
525+ <entry>—</entry>
526+ <entry>Filter existing row</entry>
527+ <entry>Check new row</entry>
448528 <entry>—</entry>
449529 </row>
450530 <row>
451- <entry><command>INSERT ... RETURNING </command></entry>
531+ <entry><command>DELETE </command></entry>
452532 <entry>
453- New row <footnote id="rls-select-priv">
533+ Filter existing row <footnoteref linkend="rls-select-priv"/>
534+ </entry>
535+ <entry>—</entry>
536+ <entry>—</entry>
537+ <entry>—</entry>
538+ <entry>Filter existing row</entry>
539+ </row>
540+ <row>
541+ <entry><command>INSERT ... ON CONFLICT</command></entry>
542+ <entry>
543+ Check new row <footnote id="rls-on-conflict-priv">
454544 <para>
455- If read access is required to the existing or new row (for example,
456- a <literal>WHERE</literal> or <literal>RETURNING</literal> clause
457- that refers to columns from the relation).
545+ Row proposed for insertion is checked regardless of whether or not a
546+ conflict occurs.
458547 </para>
459548 </footnote>
460549 </entry>
461- <entry>New row</entry>
550+ <entry>
551+ Check new row <footnoteref linkend="rls-on-conflict-priv"/>
552+ </entry>
462553 <entry>—</entry>
463554 <entry>—</entry>
464555 <entry>—</entry>
465556 </row>
466557 <row>
467- <entry><command>UPDATE</command> / <command>MERGE ... THEN UPDATE</command></entry>
558+ <entry><command>ON CONFLICT DO UPDATE</command></entry>
468559 <entry>
469- Existing & new rows <footnoteref linkend="rls-select-priv"/>
560+ Check existing & new rows <footnote id="rls-on-conflict-update-priv">
561+ <para>
562+ New row of the auxiliary <command>UPDATE</command> command, which
563+ might be different from the new row of the original
564+ <command>INSERT</command> command.
565+ </para>
566+ </footnote>
470567 </entry>
471568 <entry>—</entry>
472- <entry>Existing row</entry>
473- <entry>New row</entry>
569+ <entry>Check existing row</entry>
570+ <entry>
571+ Check new row <footnoteref linkend="rls-on-conflict-update-priv"/>
572+ </entry>
474573 <entry>—</entry>
475574 </row>
476575 <row>
477- <entry><command>DELETE</command></entry>
576+ <entry><command>MERGE</command></entry>
577+ <entry>Filter source & target rows</entry>
578+ <entry>—</entry>
579+ <entry>—</entry>
580+ <entry>—</entry>
581+ <entry>—</entry>
582+ </row>
583+ <row>
584+ <entry><command>MERGE ... THEN INSERT</command></entry>
478585 <entry>
479- Existing row <footnoteref linkend="rls-select-priv"/>
586+ Check new row <footnoteref linkend="rls-select-priv"/>
480587 </entry>
588+ <entry>Check new row</entry>
481589 <entry>—</entry>
482590 <entry>—</entry>
483591 <entry>—</entry>
484- <entry>Existing row</entry>
485592 </row>
486593 <row>
487- <entry><command>ON CONFLICT DO UPDATE</command></entry>
488- <entry>Existing & new rows</entry>
594+ <entry><command>MERGE ... THEN UPDATE</command></entry>
595+ <entry>Check new row</entry>
596+ <entry>—</entry>
597+ <entry>Check existing row</entry>
598+ <entry>Check new row</entry>
599+ <entry>—</entry>
600+ </row>
601+ <row>
602+ <entry><command>MERGE ... THEN DELETE</command></entry>
603+ <entry>—</entry>
604+ <entry>—</entry>
489605 <entry>—</entry>
490- <entry>Existing row</entry>
491- <entry>New row</entry>
492606 <entry>—</entry>
607+ <entry>Check existing row</entry>
493608 </row>
494609 </tbody>
495610 </tgroup>
0 commit comments