Re: CASE Statement - Order of expression processing

From: Stefan Drees <stefan(at)drees(dot)name>
To: andrea(at)lombardoni(dot)ch
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: CASE Statement - Order of expression processing
Date: 2013-06-17 21:11:06
Message-ID: 51BF7B6A.50301@drees.name
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

On 2013-06-17 22:17 +02:00, Andrea Lombardoni wrote:
> I observed the following behaviour (I tested the following statements in
> 9.0.4, 9.0.5 and 9.3beta1):
>
> $ psql template1
> template1=# SELECT CASE WHEN 0=0 THEN 0 ELSE 1/0 END;
> case
> ------
> 0
> (1 row)
>
> template1=# SELECT CASE WHEN 1=0 THEN 0 ELSE 1/0 END;
> ERROR: division by zero
>
> In this case the CASE behaves as expected.
>
> But in the following expression:
>
> template1=# SELECT CASE WHEN (SELECT 0)=0 THEN 0 ELSE 1/0 END;
> ERROR: division by zero
>
> (Just to be sure, a "SELECT (SELECT 0)=0;" returns true)
>
> It seems that when the "CASE WHEN expression" is a query, the evaluation
> order changes.
> According to the documentation, this behaviour is wrong.
>
> http://www.postgresql.org/docs/9.0/static/sql-expressions.html (4.2.13.
> Expression Evaluation Rules):
> "When it is essential to force evaluation order, a CASE construct (see
> Section 9.16) can be used. "
>
> http://www.postgresql.org/docs/9.0/static/functions-conditional.html
> (9.16.1. CASE):
> "If the condition's result is true, the value of the CASE expression is
> the result that follows the condition, and the remainder of the CASE
> expression is not processed."
> "A CASE expression does not evaluate any subexpressions that are not
> needed to determine the result."
>
> Did I miss anything? Or is this really a bug?

with psql v9.2.4:

pg924=# SELECT CASE WHEN (SELECT 0) = 0 THEN 0 END;
case
------
0
(1 row)

is like documented.

pg924=# SELECT CASE WHEN (SELECT 0) != 0 THEN 0 END;
case
------

(1 row)

also like documented "If no match is found, the result of the ELSE
clause (or a null value) is returned."

pg924=# SELECT CASE WHEN (SELECT 0) != 0 THEN 0 ELSE 1 END;
case
------
1
(1 row)

also ok, now it returns the result of the ELSE clause.

So maybe "The data types of all the result expressions must be
convertible to a single output type. See Section 10.5 for more details."
The checking of convertibility is eagerly tried in case there is a
SELECT expression to be evaluated in the condition?

A simple arithmetic expression does not trigger this:

pg924=# SELECT CASE WHEN (0+0) != 0 THEN 1/0 ELSE 1 END;
case
------
1
(1 row)

Now is a subquery "(SELECT 1) != 1" a valid expression for a condition
:-?) or does it trigger some unwanted checking:

pg924=# SELECT CASE WHEN (SELECT 1) != 1 THEN 1/0 END;
ERROR: division by zero

A subquery inside a "matched" ELSE clause (e.g.) does not trigger
evaluation of the 1/0 inside the unmatched WHEN clause:

pg924=# SELECT CASE WHEN 1 != 1 THEN 1/0 ELSE ((SELECT 1)=1)::integer END;
case
------
1
(1 row)

here the 1/0 is happily ignored.

So it's us two already with a blind spot, or it's a bug.

All the best,
Stefan.

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Bruce Momjian 2013-06-17 23:06:18 Re: pg_upgrade only to 9.0 ?
Previous Message Joshua D. Drake 2013-06-17 21:00:59 Re: PSA: If you are running Precise/12.04 upgrade your kernel.