Oracle Violates Short-circuit in CASE Statement
-1
votes
1
answer
76
views
**Problem**
I am well aware that SQL is a declarative language and does not enforce short-circuiting. Oracle, on the other hand, explicitly states that short-circuiting takes place for CASE statements.
I have the following example:
-- Query 1
SELECT
CASE
WHEN ASCII(SUBSTR(test_texts, 5, 1)) < 110 THEN 1
ELSE 0
END
FROM test_data_types ORDER BY ID OFFSET 1 ROWS FETCH FIRST 1 ROWS ONLY;
-- Query 2
SELECT
CASE
WHEN ASCII(SUBSTR(test_texts, 5, 1)) < 110 THEN 1
ELSE 0/0 -- zero division
END
FROM test_data_types ORDER BY ID OFFSET 1 ROWS FETCH FIRST 1 ROWS ONLY;
Query1 returns 1 because the 5th character of the row ('world'
) is 'd'
with ASCII value 100 but Query2 raises a zero division error, meaning the short-circuiting did not take place.
I assumed this was because the expression 0/0
is constant and optimization kicked is, however, expression ln(ora_hash(test_texts) - 10)
, which is equivalent to ln(0)
, throws an error unconditionally as well. Hence, eager evaluation of constant expressions is not the (sole) reason.
Surprisingly enough, short-circuiting does take place when I increase the upper bound to 120, i.e., ASCII(...) < 120
. Again, the selected letter is 'd'
with ASCII value of 100, which is less than both 110 and 120, but only 120 works for some reason. I really can't wrap my mind around this.
**Additional Context**
I am doing research on blind SQL injection optimization so I'm limited to SELECT queries. Also, the error forcing is intentional, I'm just looking for a way to make it conditional. Lastly, I'm using Oracle Database 23ai Free.
**Setup for Reproduction**
CREATE TABLE test_data_types (
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
test_texts CLOB
);
INSERT INTO test_data_types (test_texts) VALUES ('hello');
INSERT INTO test_data_types (test_texts) VALUES ('world');
INSERT INTO test_data_types (test_texts) VALUES ('hello world');
INSERT INTO test_data_types (test_texts) VALUES ('hello world');
INSERT INTO test_data_types (test_texts) VALUES ('hello world');
INSERT INTO test_data_types (test_texts) VALUES ('hello world');
INSERT INTO test_data_types (test_texts) VALUES ('hello world');
INSERT INTO test_data_types (test_texts) VALUES ('hello world');
INSERT INTO test_data_types (test_texts) VALUES ('hello world');
INSERT INTO test_data_types (test_texts) VALUES ('hello');
COMMIT;
**Question(s)**
1) Why is short-circuiting not respected here?
2) If it's is due to optimization, are there some expressions (e.g., heavy computation) that are evaluated last?
3) As a last resort, are there some other SELECT constructs that produce the desired behavior (conditional errors)?
**TL;DR of the Bellow Discussion**
The issue is not that CASE short-circuiting is violated, but that the SELECT part has precedence over the OFFSET and FETCH parts, leading to evaluation of the first row ("hello"
) which triggers the zero division.
Asked by Pruzo
(3 rep)
May 31, 2025, 11:09 AM
Last activity: Jun 2, 2025, 02:07 PM
Last activity: Jun 2, 2025, 02:07 PM