Max Gekk created SPARK-60377:
--------------------------------

             Summary: FilterExec hoists an IsNotNull check on a non-attribute 
expression ahead of an earlier conjunct under whole-stage codegen
                 Key: SPARK-60377
                 URL: https://issues.apache.org/jira/browse/SPARK-60377
             Project: Spark
          Issue Type: Bug
          Components: SQL
    Affects Versions: 5.0.0
            Reporter: Max Gekk


Since SPARK-51356, FilterExec under whole-stage codegen generates an IsNotNull 
check on a non-attribute null-intolerant expression just before the first other 
conjunct that contains the expression, in both 
GeneratePredicateHelper.generatePredicateCode and the CSE branch of 
FilterExec.doConsume. It does so even when the check is written after that 
conjunct in the condition. If the conjunct is FALSE, And.eval never evaluates 
the later check in interpreted mode, but the generated code evaluates it first, 
so an error the check raises on the row is raised under codegen only.

Reproduction with ANSI on and Parquet filter pushdown off:

{code:sql}
CREATE TABLE t USING parquet AS SELECT * FROM VALUES (0, 1, 0, 1, 'x') AS v(a, 
b, y, x, s);
SELECT a FROM t
WHERE NOT (a > 0 AND b > 0) AND coalesce(b, cast(s AS INT)) < 0 AND cast(s AS 
INT) IS NOT NULL;
{code}

The first conjunct is TRUE and the second is FALSE, so the query returns no 
rows with spark.sql.codegen.wholeStage=false. With whole-stage codegen it 
raises CAST_INVALID_INPUT, because the check cast(s AS INT) IS NOT NULL is 
generated before the second conjunct. This happens regardless of 
spark.sql.legacy.filterShortCircuitOnNullConjunct.

SPARK-60315 (PR #59573) restricts the hoisting once a conjunct that can be NULL 
has been generated, since the NULL-conjunct flag made the hoisted check 
reachable on more rows. This ticket is for the remaining case: the nested 
IsNotNull check should be hoisted only when it is written before the conjunct 
in the condition, i.e. only the checks with an index below 
precedingNotNulls(k), so that the generated code follows the evaluation order 
of And.eval. The hoisting is then no longer needed for a check written after 
the conjunct, which the leftover checks at the end of the condition cover.




--
This message was sent by Atlassian Jira
(v8.20.10#820010)

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

Reply via email to