Skip to content

[SPARK-58213][SQL] corr should return NULL when a column has zero variance#57369

Open
jiangxt2 wants to merge 3 commits into
apache:masterfrom
jiangxt2:fix/corr-constant-zero-denominator
Open

[SPARK-58213][SQL] corr should return NULL when a column has zero variance#57369
jiangxt2 wants to merge 3 commits into
apache:masterfrom
jiangxt2:fix/corr-constant-zero-denominator

Conversation

@jiangxt2

Copy link
Copy Markdown

What changes were proposed in this pull request?

Add a guard xMk === 0.0 || yMk === 0.0 in Corr.evaluateExpression, branching to the existing divideByZeroEvalResult before evaluating ck / sqrt(xMk * yMk).

Why are the changes needed?

When one of the input columns is constant, the corresponding Welford variance term (xMk or yMk) is exactly 0.0, making the denominator zero. This produces DIVIDE_BY_ZERO in ANSI mode and NaN or ±Infinity in non-ANSI mode.

The sibling function regr_r2 (same PearsonCorrelation base class) already guards against yMk === 0.0 and xMk === 0.0. The Spark 3.1 migration guide lists corr among functions that should return NULL on divide-by-zero, but the guard was never added.

SET spark.sql.ansi.enabled = true;
SELECT corr(CAST(x AS DOUBLE), CAST(y AS DOUBLE))
FROM VALUES (1, 1), (1, 2), (1, 3) AS t(x, y);
-- Before: DIVIDE_BY_ZERO
-- After:  NULL

Does this PR introduce any user-facing change?

Yes. corr on a constant column now returns NULL instead of throwing DIVIDE_BY_ZERO (ANSI mode) or returning NaN/Infinity (non-ANSI mode).

How was this patch tested?

  • linear-regression.sql: x-constant and y-constant cases, both returning NULL
  • Corresponding analyzer golden file regenerated
  • SQLQueryTestSuite passes

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code with Claude Opus 4.8

jiangxt2 and others added 3 commits July 20, 2026 14:55
…iance

corr computes ck / sqrt(xMk * yMk). When a column is constant,
the corresponding Welford variance term is exactly 0.0, making
the denominator zero — DIVIDE_BY_ZERO in ANSI mode, NaN/Infinity
in non-ANSI mode.

Add a guard xMk === 0.0 || yMk === 0.0 in evaluateExpression,
branching to the existing divideByZeroEvalResult — the same
mechanism used by n === 1.0 and the sibling function regr_r2.
The guard prevents the division from ever being evaluated when
the denominator is zero.

Closes #58213

Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Co-Authored-By: Zhang Dong <zdcheerful@hotmail.com>
Co-Authored-By: ArtificialIdoit <bill.sea@hotmail.com>
Co-Authored-By: cwq222 <15503804976@163.com>
…ariance fix

The corr zero-variance guard (xMk === 0.0 || yMk === 0.0) changed
query apache#26 of window.sql from DIVIDE_BY_ZERO to returning actual row
data with NULL for corr when variance is zero.

Regenerate both window.sql.out and udf/udf-window.sql.out.

Closes #58213

Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Co-Authored-By: Zhang Dong <zdcheerful@hotmail.com>
Co-Authored-By: ArtificialIdoit <bill.sea@hotmail.com>
Co-Authored-By: cwq222 <15503804976@163.com>
The original guard (xMk === 0.0 || yMk === 0.0) redirected to
divideByZeroEvalResult, which returns NaN in legacy statistical
aggregate mode. The old code path (ck / sqrt(xMk * yMk) =
0.0 / 0.0) relied on Spark's Divide expression returning null for
any zero divisor in non-ANSI mode, regardless of legacy settings.

Use Literal.create(null, DoubleType) directly — matching how the
sibling function regr_r2 handles the same case — so the zero-
variance case always returns null.

Closes #58213

Signed-off-by: jiangxt2 <jiangxt2@vip.qq.com>
Co-Authored-By: Zhang Dong <zdcheerful@hotmail.com>
Co-Authored-By: ArtificialIdoit <bill.sea@hotmail.com>
Co-Authored-By: cwq222 <15503804976@163.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant