Skip to content

[SPARK-59091][SQL] Emit the NaN guard in transpiled equality only for floating-point columns - #58901

Open
jzhan-2026 wants to merge 1 commit into
apache:masterfrom
jzhan-2026:spark-59091-nan-guard
Open

jzhan-2026 wants to merge 1 commit into
apache:masterfrom
jzhan-2026:spark-59091-nan-guard

Conversation

@jzhan-2026

@jzhan-2026 jzhan-2026 commented Sep 17, 2026

Copy link
Copy Markdown

What changes were proposed in this pull request?

Split the transpiler's "numeric" category into "integer" (IntegralType) and "float"
(FractionalType, excluding DecimalType). The NaN guard in _lower_eq is now only emitted
when at least one operand has category "float".

  • transpile.py: _category returns "integer" / "float" instead of "numeric" for
    literals and parameters; _param_category_combos tries ["integer", "float", "string"]
    per parameter; _lower_eq gates the guard on lc == "float" or rc == "float";
    _convert_chunk BinOp dispatch uses _is_numeric_cat() for all three sub-categories.
  • ResolveTranspiledPythonUDFOptions.scala: adds "integer" → IntegralType and "float"
    → FractionalType (excluding Decimal) cases to optionMatchesTypes.

Why are the changes needed?

For integer columns (e.g. BIGINT), the old plan for x == y included isnan(cast(x AS DOUBLE)), which is always false—integers can't be NaN. The NaN guard only makes sense for floating-point types.

Does this PR introduce any user-facing change?

No. The generated Catalyst plan for integer-column equality no longer contains dead isnan guards, but the query results are identical.

How was this patch tested?

New Python tests in test_udf_transpile_unit:

  • test_udf_transpile_integer_eq_no_nan_guard — no isnan in plan for BIGINT ==
  • test_udf_transpile_float_eq_nan_semanticsisnan present for DOUBLE ==; NaN and null semantics verified end-to-end
  • test_udf_transpile_int_float_annotation_categories — unit tests for new category names

New Scala tests in ResolveTranspiledPythonUDFOptionsSuite: "integer" / "float" matching, cross-type rejection, DecimalType exclusion, FloatType matching.

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

Co-authored by: Claude Sonnet 4.6

@jzhan-2026
jzhan-2026 marked this pull request as ready for review September 17, 2026 23:11
@jzhan-2026

Copy link
Copy Markdown
Author

@holdenk PTAL when you get a chance! Thanks in advance!

@holdenk holdenk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, some questions :)

Comment on lines +85 to +86
# Categories that represent numeric (non-string) scalar types.
_NUMERIC_CATS = frozenset(("numeric", "integer", "float"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So as it's written down bellow numeric is "an unknown numeric type" but elsewhere we treat numeric as the tightest of them. This kind of changes the logic needed in both the widening sub function and the comparison check function (if it's unknown then we should have the NaN check there too for numeric) and then also numeric should be the widest not least wide.

Comment on lines +94 to +100
def _wider_numeric(lc: str, rc: str) -> str:
"""Return the wider of two numeric categories (float > integer > numeric)."""
if "float" in (lc, rc):
return "float"
if "integer" in (lc, rc):
return "integer"
return "numeric"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, although for a little extra safety let's just raise or none on a non-numeric input col

Comment on lines +357 to +358
has_float = lc == "float" or rc == "float"
if has_float:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personally I'd move these two lines together but nit

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.

2 participants