diff --git a/doc/src/sgml/func/func-subquery.sgml b/doc/src/sgml/func/func-subquery.sgml index a9f2b12e48c..f954f3bf133 100644 --- a/doc/src/sgml/func/func-subquery.sgml +++ b/doc/src/sgml/func/func-subquery.sgml @@ -70,8 +70,14 @@ EXISTS (subquery) and not on the contents of those rows, the output list of the subquery is normally unimportant. A common coding convention is to write all EXISTS tests in the form - EXISTS(SELECT 1 WHERE ...). There are exceptions to - this rule however, such as subqueries that use INTERSECT. + EXISTS(SELECT * FROM ... WHERE ...), another common + convention is to write EXISTS(SELECT 1 FROM ... WHERE + ...) or some other dummy constant. These conventions are + actually equivalent in PostgreSQL, which + will optimize away evaluation of the subquery's output list altogether + when it cannot affect the number of rows returned. (An example + that cannot be optimized away is an output list containing a + set-returning function, since the function might return zero rows.) diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index e6bc7023562..d7f3cedf3d5 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -1643,7 +1643,13 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink, * Note: by suppressing the targetlist we could cause an observable behavioral * change, namely that any errors that might occur in evaluating the tlist * won't occur, nor will other side-effects of volatile functions. This seems - * unlikely to bother anyone in practice. + * unlikely to bother anyone in practice. Note that any column privileges are + * still checked even if the reference is removed here. + * + * The SQL standard specifies that a SELECT * immediately inside EXISTS + * expands to not all columns but an arbitrary literal. That is kind of the + * same idea, but our optimization goes further in that it throws away the + * entire targetlist, and not only if it was written as *. * * Returns true if was able to discard the targetlist, else false. */