sepuri sai krishna created SPARK-61009:
------------------------------------------
Summary: RANGE window frames over integral columns return wrong
results when the offset or the frame bound does not fit in the column type
Key: SPARK-61009
URL: https://issues.apache.org/jira/browse/SPARK-61009
Project: Spark
Issue Type: Bug
Components: SQL
Affects Versions: 4.0.3, 4.4.0, 5.0.0
Reporter: sepuri sai krishna
For a {{RANGE}} frame with an offset ordered by a {{TINYINT}}, {{SMALLINT}},
{{INT}} or {{BIGINT}} column, Spark casts the offset to the type of the column
and computes the frame bound ({{value + offset}}) in that type. When the offset
does not fit in the type, or the addition overflows, the value wraps around
with ANSI mode off, so the frame gets the wrong rows, and the query fails with
ANSI mode on, although the frame is well defined.
{code:sql}
CREATE TABLE t USING parquet AS
SELECT CAST(id AS INT) AS id, CAST(id * 10 AS TINYINT) AS b FROM range(0, 6);
SELECT id, b, count(*) OVER (ORDER BY b RANGE BETWEEN 200 PRECEDING AND CURRENT
ROW) AS cnt
FROM t ORDER BY id;
{code}
With {{spark.sql.ansi.enabled=false}}, {{cnt}} is 0 for every row (expected 1,
2, ..., 6), on 4.0.3 and master: the offset 200 is cast to {{TINYINT}} and
wraps to -56. With ANSI mode on, the query fails with {{[CAST_OVERFLOW] The
value -200 of the type "INT" cannot be cast to "TINYINT"}}. The same happens
for an {{INT}} column with {{3000000000 PRECEDING}}.
The bound addition also overflows near the limits of the type, even when the
offset fits:
{code:sql}
CREATE TABLE scores USING parquet AS
SELECT CAST(id AS INT) AS id, CAST(id * 5 AS TINYINT) AS score FROM range(0,
21);
-- number of scores in [score, score + 30]
SELECT id, score,
count(*) OVER (ORDER BY score DESC RANGE BETWEEN 30 PRECEDING AND CURRENT
ROW) AS cnt
FROM scores ORDER BY id;
{code}
With {{spark.sql.ansi.enabled=false}} the rows with a score of 70 or more are
wrong (on 4.0.3 and master):
{noformat}
score cnt expected
70 6 7
75 5 6
80 4 5
85 3 4
90 2 3
95 1 2
100 0 1
{noformat}
The last row counts 0 rows, although the frame always contains the current row.
With {{spark.sql.ansi.enabled=true}} (the default) the query fails:
{noformat}
[BINARY_ARITHMETIC_OVERFLOW] 100S + 30S caused overflow. Use `try_add` to
ignore overflow problem and return NULL.
{noformat}
The same happens for the other integral types near their limits, for example
{{count(*) OVER (ORDER BY i RANGE BETWEEN CURRENT ROW AND 100 FOLLOWING)}}
returns 0 (and {{sum}} returns NULL) for {{INT}} values near 2147483647, and
{{n PRECEDING}} in ascending order near the minimum.
The offset is cast by {{WindowFrameTypeCoercion}} ({{TypeCoercionHelper}}), and
the bound is built by {{WindowEvaluatorFactoryBase.createBoundOrdering}} as
{{Add(expr, boundOffset)}} with the eval mode of the session. SPARK-41793 fixed
the same problem for {{DECIMAL}} order columns ({{DecimalAddNoOverflowCheck}}).
For integral types, the frame bounds could be compared exactly, without
computing them in the column type.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]