Max Gekk created SPARK-60774:
--------------------------------

             Summary: Common subexpression first referenced in a conditional 
branch of a predicate's conjunct is evaluated before the conjunct
                 Key: SPARK-60774
                 URL: https://issues.apache.org/jira/browse/SPARK-60774
             Project: Spark
          Issue Type: Bug
          Components: SQL
    Affects Versions: 5.0.0
            Reporter: Max Gekk


When a common subexpression of a predicate's conjuncts is evaluated just before 
the first conjunct that references it (the CSE branch of FilterExec.doConsume 
since SPARK-56032, and GeneratePredicate since SPARK-60332), the first 
reference is found with Expression.exists, which also counts an occurrence in a 
conditionally evaluated part of the conjunct: a branch of CASE WHEN or IF, the 
later arguments of COALESCE, or the right side of OR. So the subexpression is 
evaluated before a conjunct that may never evaluate it, and an error it raises 
on the row is raised although the conjunct is FALSE and And.eval would drop the 
row without the error.

Reproducer (ANSI mode, both with whole-stage codegen on and off, Parquet filter 
pushdown off):

{code:sql}
CREATE TABLE t USING parquet AS SELECT * FROM VALUES (NULL, 1, 2147483647), (0, 
1, 0) AS v(a, b, y);
SELECT a FROM t WHERE (CASE WHEN a > 0 THEN y + 1 ELSE 0 END) > 0 AND y + 1 > 0 
AND y + 1 > -1;
{code}

y + 1 is common to the last two conjuncts, but its first occurrence is in the 
THEN branch of the first conjunct, so it is evaluated before that conjunct and 
raises ARITHMETIC_OVERFLOW on the first row, where the first conjunct is FALSE 
(a is NULL, so the CASE gives 0). The interpreted And.eval returns no rows and 
no error.

Evaluating the subexpression at its first unconditional reference instead is 
not enough: the code of the conditional branch is generated through 
Expression.genCode and would read the subexpression's state before it is 
evaluated. The subexpression has to be left out of the elimination, or its 
conditional occurrence left unsubstituted, when its first occurrence is 
conditional. The first reference is computed in one place, 
CodegenContext.firstReferencingExpression, shared by both generators.




--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to