Skip to content

feat: Add Spark-compatible encode function to datafusion-spark - #21331

Merged
Jefffrey merged 22 commits into
apache:mainfrom
JeelRajodiya:feat/spark-encode-function
Sep 7, 2026
Merged

Jefffrey merged 22 commits into
apache:mainfrom
JeelRajodiya:feat/spark-encode-function

Conversation

@JeelRajodiya

@JeelRajodiya JeelRajodiya commented Apr 3, 2026 •

Copy link
Copy Markdown
Contributor

Rationale

The datafusion-spark crate is missing the encode function. Spark's encode(expr, charset) converts a string or binary value into binary using a specified character encoding — commonly used in Spark SQL workloads and needed by engines built on DataFusion that target Spark compatibility.

What changes are included in this PR?

Adds SparkEncode to datafusion-spark's string functions, emulating Spark 3.5 semantics. It supports US-ASCII, ISO-8859-1, UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, and UTF-32LE, including common aliases (UTF8, LATIN1, etc.) and case-insensitive matching. The charset can be a constant or a per-row column. Binary input is decoded as lossy UTF-8 (invalid bytes → U+FFFD) before re-encoding, and unmappable characters are silently replaced with ?, matching Spark.

Are these changes tested?

Yes. Coverage lives in encode.slt (sqllogictest) and exercises all charsets and aliases, case-insensitive matching, null value/charset handling, per-row charsets, binary input (Binary/LargeBinary/BinaryView) with lossy UTF-8, Utf8View input, and the unsupported-charset error. A Rust unit test covers return-field nullability.

Are there any user-facing changes?

New encode scalar function available when using datafusion-spark.

@github-actions github-actions Bot added the spark label Apr 3, 2026
@Zeel-e6x

Zeel-e6x commented Apr 3, 2026

Copy link
Copy Markdown

run benchmarks

@adriangbot

Copy link
Copy Markdown

Comment thread datafusion/spark/src/function/string/encode.rs Outdated
Comment thread datafusion/spark/src/function/string/encode.rs
Comment thread datafusion/spark/src/function/string/encode.rs

@xanderbailey xanderbailey 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.

Looks good to me but you’ll need a committer to Approve also! Thanks for the PR!

@JeelRajodiya

JeelRajodiya commented Apr 7, 2026 •

Copy link
Copy Markdown
Contributor Author

Hey @xanderbailey, Do I need to mention the maintainers for review? if yes please suggest whom incase you know.
I'm planning to open more PRs for implementing other functions but I'm waiting for this PR to get merged.

@xanderbailey

Copy link
Copy Markdown
Contributor

They will normally pick it up within a week or so. If not we can ping them here.

@alamb

alamb commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Thanks @xanderbailey and @JeelRajodiya -- the PR load is pretty intense! I started the CI for this PR

@JeelRajodiya
JeelRajodiya force-pushed the feat/spark-encode-function branch from 22a2705 to bf46433 Compare April 7, 2026 18:54
@JeelRajodiya

Copy link
Copy Markdown
Contributor Author

I pushed the fixes for clippy errors. @alamb Can you rerun the checks please?

@JeelRajodiya

JeelRajodiya commented Apr 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Please rerun the checks

}
Ok(bytes)
}
_ => exec_err!(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Spark also supports UTF-32. It would be worth adding a comment here explaining why this isn't or can't be supported.

  arguments = """
    Arguments:
      * str - a string expression
      * charset - one of the charsets 'US-ASCII', 'ISO-8859-1', 'UTF-8', 'UTF-16BE', 'UTF-16LE', 'UTF-16', 'UTF-32' to encode `str` into a BINARY. It is case insensitive.
  """,

@JeelRajodiya JeelRajodiya Apr 15, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I missed adding support for UTF-32, I've added it now with respective tests.

Comment thread datafusion/spark/src/function/string/encode.rs
@github-actions github-actions Bot added the core Core DataFusion crate label Apr 15, 2026
@JeelRajodiya
JeelRajodiya force-pushed the feat/spark-encode-function branch from 55f4694 to 835ae8d Compare April 15, 2026 05:32
@github-actions github-actions Bot removed the core Core DataFusion crate label Apr 15, 2026
Implements `encode(string_or_binary, charset)` that converts a string
or binary value into binary using the specified character encoding,
matching Apache Spark's behavior.
In ANSI mode (default), encoding a character that cannot be represented
in the target charset (e.g. non-ASCII char in US-ASCII) returns an
error. In legacy mode, unmappable characters are silently replaced
with '?'.
@JeelRajodiya
JeelRajodiya force-pushed the feat/spark-encode-function branch from 835ae8d to 6cb99a7 Compare April 15, 2026 05:40
@JeelRajodiya
JeelRajodiya requested a review from andygrove April 15, 2026 05:43
@andygrove

Copy link
Copy Markdown
Member

Thanks for iterating on this @JeelRajodiya. One issue I noticed:

spark-sql> SELECT hex(encode('A', 'UTF-32'));                                                                                                                                                                        
00000041                                                                 

This PR returns 0000FEFF00000041, with a BOM. Both Spark 3.5 and Spark 4.1 return the four-byte form.

Once challenge for this PR is that there is different behavior across Spark versions for the encode expression. Which Spark version is this PR targeting? It would be good to document that.

@JeelRajodiya
JeelRajodiya requested a review from Jefffrey June 29, 2026 11:17
Comment thread datafusion/spark/src/function/string/encode.rs Outdated
DataType::Utf8
| DataType::LargeUtf8
| DataType::Utf8View
| DataType::Binary

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.

@JeelRajodiya JeelRajodiya Aug 30, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not directly, but Spark Catalyst’s Analyzer inserts the cast specifically through the ImplicitTypeCasts coercion rule.

Thus:

  encode(binary_value, 'UTF-8')

is analyzed as:

  encode(CAST(binary_value AS STRING), 'UTF-8')

We preserve binary input in coerce_types instead of letting DataFusion cast it to a string because:

  • Spark’s binary-to-string cast preserves malformed bytes, and encode later converts them to U+FFFD.
  • DataFusion’s normal Arrow binary-to-UTF8 cast rejects malformed UTF-8 before encode runs.

Example: X'FF' is malformed UTF-8. Spark’s encode path converts it to U+FFFD, while DataFusion’s normal binary-to-UTF8 cast returns an invalid UTF-8 error.

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.

this is worth leaving a comment here about (keep it succinct and to the point)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

@github-actions

Copy link
Copy Markdown

Thank you for your contribution. Unfortunately, this pull request is stale because it has been open 60 days with no activity. Please remove the stale label or comment or this will be closed in 7 days.

@github-actions github-actions Bot added the Stale PR has not had any activity for some time label Aug 30, 2026
@codecov-commenter

codecov-commenter commented Aug 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.06250% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.53%. Comparing base (4b8ad88) to head (2afe5cd).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
datafusion/spark/src/function/string/encode.rs 89.00% 17 Missing and 4 partials ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main   #21331    +/-   ##
========================================
  Coverage   81.53%   81.53%            
========================================
  Files        1123     1124     +1     
  Lines      406042   406294   +252     
  Branches   406042   406294   +252     
========================================
+ Hits       331059   331271   +212     
- Misses      55621    55652    +31     
- Partials    19362    19371     +9     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@JeelRajodiya
JeelRajodiya requested a review from Jefffrey August 30, 2026 09:39
@JeelRajodiya

Copy link
Copy Markdown
Contributor Author

I'm still working on the PR

@Jefffrey Jefffrey removed the Stale PR has not had any activity for some time label Aug 30, 2026
Comment thread datafusion/spark/src/function/string/encode.rs Outdated
Comment thread datafusion/spark/src/function/string/encode.rs Outdated
DataType::Utf8
| DataType::LargeUtf8
| DataType::Utf8View
| DataType::Binary

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.

this is worth leaving a comment here about (keep it succinct and to the point)

JeelRajodiya and others added 2 commits August 30, 2026 18:31
Co-authored-by: Jeffrey Vo <jeffrey.vo.australia@gmail.com>
…ecty

Co-authored-by: Jeffrey Vo <jeffrey.vo.australia@gmail.com>
@github-actions github-actions Bot added the auto detected api change Auto detected API change label Aug 30, 2026
@github-actions github-actions Bot removed the auto detected api change Auto detected API change label Aug 30, 2026
@JeelRajodiya

Copy link
Copy Markdown
Contributor Author

if it looks good, Can we get this merged @Jefffrey ?

@Jefffrey
Jefffrey added this pull request to the merge queue Sep 7, 2026
@Jefffrey

Jefffrey commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

thanks @JeelRajodiya & co

sorry it hung for so long

Merged via the queue into apache:main with commit fdfb67d Sep 7, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spark sqllogictest SQL Logic Tests (.slt) v56.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants