Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5b51683

Browse files
committed
Improve documentation about CASE and constant subexpressions.
The possibility that constant subexpressions of a CASE might be evaluated at planning time was touched on in 9.17.1 (CASE expressions), but it really ought to be explained in 4.2.14 (Expression Evaluation Rules) which is the primary discussion of such topics. Add text and an example there, and revise the <note> under CASE to link there. Back-patch to all supported branches, since it's acted like this for a long time (though 9.2+ is probably worse because of its more aggressive use of constant-folding via replanning of nominally-prepared statements). Pre-9.4, also back-patch text added in commit 0ce627d about CASE versus aggregate functions. Tom Lane and David Johnston, per discussion of bug #12273.
1 parent cd6e665 commit 5b51683

File tree

2 files changed

+36
-7
lines changed

2 files changed

+36
-7
lines changed

doc/src/sgml/func.sgml

+7-5
Original file line numberDiff line numberDiff line change
@@ -11179,11 +11179,13 @@ SELECT ... WHERE CASE WHEN x &lt;&gt; 0 THEN y/x &gt; 1.5 ELSE false END;
1117911179

1118011180
<note>
1118111181
<para>
11182-
As described in <xref linkend="xfunc-volatility">, functions and
11183-
operators marked <literal>IMMUTABLE</literal> can be evaluated when
11184-
the query is planned rather than when it is executed. This means
11185-
that constant parts of a subexpression that is not evaluated during
11186-
query execution might still be evaluated during query planning.
11182+
As described in <xref linkend="syntax-express-eval">, there are various
11183+
situations in which subexpressions of an expression are evaluated at
11184+
different times, so that the principle that <quote><token>CASE</token>
11185+
evaluates only necessary subexpressions</quote> is not ironclad. For
11186+
example a constant <literal>1/0</> subexpression will usually result in
11187+
a division-by-zero failure at planning time, even if it's within
11188+
a <token>CASE</token> arm that would never be entered at run time.
1118711189
</para>
1118811190
</note>
1118911191
</sect2>

doc/src/sgml/syntax.sgml

+29-2
Original file line numberDiff line numberDiff line change
@@ -2439,9 +2439,36 @@ SELECT ... WHERE CASE WHEN x &gt; 0 THEN y/x &gt; 1.5 ELSE false END;
24392439
</para>
24402440

24412441
<para>
2442-
A limitation of this technique is that a <literal>CASE</> cannot
2442+
<literal>CASE</> is not a cure-all for such issues, however.
2443+
One limitation of the technique illustrated above is that it does not
2444+
prevent early evaluation of constant subexpressions.
2445+
As described in <xref linkend="xfunc-volatility">, functions and
2446+
operators marked <literal>IMMUTABLE</literal> can be evaluated when
2447+
the query is planned rather than when it is executed. Thus for example
2448+
<programlisting>
2449+
SELECT CASE WHEN x &gt; 0 THEN x ELSE 1/0 END FROM tab;
2450+
</programlisting>
2451+
is likely to result in a division-by-zero failure due to the planner
2452+
trying to simplify the constant subexpression,
2453+
even if every row in the table has <literal>x &gt; 0</> so that the
2454+
<literal>ELSE</> arm would never be entered at run time.
2455+
</para>
2456+
2457+
<para>
2458+
While that particular example might seem silly, related cases that don't
2459+
obviously involve constants can occur in queries executed within
2460+
functions, since the values of function arguments and local variables
2461+
can be inserted into queries as constants for planning purposes.
2462+
Within <application>PL/pgSQL</> functions, for example, using an
2463+
<literal>IF</>-<literal>THEN</>-<literal>ELSE</> statement to protect
2464+
a risky computation is much safer than just nesting it in a
2465+
<literal>CASE</> expression.
2466+
</para>
2467+
2468+
<para>
2469+
Another limitation of the same kind is that a <literal>CASE</> cannot
24432470
prevent evaluation of an aggregate expression contained within it,
2444-
because aggregate expressions are computed before <quote>scalar</>
2471+
because aggregate expressions are computed before other
24452472
expressions in a <literal>SELECT</> list or <literal>HAVING</> clause
24462473
are considered. For example, the following query can cause a
24472474
division-by-zero error despite seemingly having protected against it:

0 commit comments

Comments
 (0)