Does the short-circuit evaluation described in the documentation for CASE
and COALESCE()
apply to sequences when used in SQL? This does not appear
For PL/SQL Oracle assures that it will use short-circuit evaluation:
When evaluating a logical expression, PL/SQL uses short-circuit evaluation. That is, PL/SQL stops evaluating the expression as soon as it can determine the result. Therefore, you can write expressions that might otherwise cause errors.
From: 2 PL/SQL Language Fundamentals
When you use the nextval
in SQL code, we have a different situation.
First of all we have to keep in mind that currval
and nextval
are pseudocolumns:
A pseudocolumn behaves like a table column, but is not actually stored in the table. You can select from pseudocolumns, but you cannot insert, update, or delete their values. A pseudocolumn is also similar to a function without arguments (please refer to Chapter 5, "Functions". However, functions without arguments typically return the same value for every row in the result set, whereas pseudocolumns typically return a different value for each row.
From: 3 Pseudocolumns.
The question now is: why Oracle evaluate nextval
? or Is this behaviour stated somewhere?
Within a single SQL statement containing a reference to NEXTVAL, Oracle increments the sequence once:
For each row returned by the outer query block of a SELECT statement. Such a query block can appear in the following places:
- A top-level SELECT statement
- An INSERT ... SELECT statement (either single-table or multitable). For a multitable insert, the reference to NEXTVAL must appear in the VALUES clause, and the sequence is updated once for each row returned by the subquery, even though NEXTVAL may be referenced in multiple branches of the multitable insert.
- A CREATE TABLE ... AS SELECT statement
- A CREATE MATERIALIZED VIEW ... AS SELECT statement
For each row updated in an UPDATE statement
For each INSERT statement containing a VALUES clause
For each row merged by a MERGE statement. The reference to NEXTVAL can appear in the merge_insert_clause or the merge_update_clause or both. The NEXTVALUE value is incremented for each row updated and for each row inserted, even if the sequence number is not actually used in the update or insert operation. If NEXTVAL is specified more than once in any of these locations, then the sequence is incremented once for each row and returns the same value for all occurrences of NEXTVAL for that row.
From: Sequence Pseudocolumns
Your case is clearly "1. A top-level SELECT statement", but it doesn't mean that the short-circuit logic is not in place, but only that nextval
is always evaluated.
If you are interested to the short-circuit logic, then it's better to remove the nextval
from the equation.
A query like this doesn't evaluate the subquery:
select 6 c
from dual
where 'a' = 'a' or 'a' = (select dummy from dual)
But if try to do something similar with coalesce
or case
we will see that the Oracle Optimizer decides to execute the subqueries:
select 6 c
from dual
where 'a' = coalesce('a', (select dummy from dual) )
I created annotated tests in this demo in SQLFiddle to show this.
It looks like Oracle applies the short-circuit logic only if with OR condition, but with coalesce
and case
it has to evaluate all branches.
I think your first tests in PL/SQL shows that coalsce
and case
use a short-circuit logic in PL/SQL, as Oracle states. Your second test, including the sequence in SQL statements, shows that in that case the nextval
is evaluated anyway, even if the result is not used, and Oracle also documents that.
Putting together the two things looks a bit odd, because coalesce
and case
behaviour seems to be really inconsistent too me too, but we have also to keep in mind that the implementation of that logic is implementation dependent (here my source)