Skip to content

Conversation

@mihaibudiu
Copy link
Contributor

Fixes #5378
Fixes #5389
Fixes #5390
Fixes #5391

Most changes in this PR are due to automatic refactoring. I split the code to implement complex casts into two classes, handling safe and unsafe casts separately (they were unified, which made everything unreadable).

I have also cut the Gordian knot and removed from our SQL dialect (in the documentation and validation) several kinds of operations, including creating MAP values with MAP keys or using SAFE_CAST on ROW values. This bounded the implementation effort; we can bring these back later if anyone asks.

SAFE_CASTs are supposed to attempt a conversion and return NULL if the conversion fails. This is easy for scalar values, but gets trickier for nested objects like MAP, ARRAY, and ROW, or, if you like, MAP<ARRAY, ROW>. This is now implemented by essentially using the SqlResult type (which is just an instance of Rust's Result type) to signal errors in cast expression evaluation, and handling these errors at the appropriate place (the outermost scope).

The compiler now distinguishes between two kinds of casts: high-level SQL casts, and low-level Rust casts. (They are represented by the same Java class, with different flags.) They used to be conflated previously, which made things REALLY confusing. (Note to self: don't do this again.)

Signed-off-by: Mihai Budiu <mbudiu@feldera.com>
Copilot AI review requested due to automatic review settings January 15, 2026 02:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR reworks the SAFE_CAST implementation to properly handle complex nested types (MAP, ARRAY, ROW). The key innovation is distinguishing between SQL-level casts (which may fail) and Rust-level casts (which return SqlResult), then using error handlers to convert failures into NULL values for safe casts or panics for unsafe casts.

Changes:

  • Introduced DBSPTypeSqlResult type and CastType enum to distinguish SQL vs Rust casts
  • Split cast expansion into ExpandSafeCasts and ExpandUnsafeCasts classes
  • Added safe conversion functions to Rust sqllib (array_map_safe, map_map_safe)
  • Restricted SQL dialect to disallow MAP keys of type MAP and SAFE_CAST on ROW types
  • Updated error handling to use RuntimeBehavior enum in DBSPHandleErrorExpression

Reviewed changes

Copilot reviewed 120 out of 122 changed files in this pull request and generated no comments.

Show a summary per file
File Description
DBSPCastExpression.java Added CastType enum (SqlSafe/SqlUnsafe/RustCast/UnwrapResultSafe/UnwrapResultUnsafe)
DBSPTypeSqlResult.java New type representing SqlResult[T] from sqllib
ExpandSafeCasts.java New visitor for expanding safe casts into recursive safe conversions
ExpandUnsafeCasts.java New visitor for expanding unsafe casts with panic behavior
DBSPHandleErrorExpression.java Updated to use RuntimeBehavior enum and handle SqlResult unwrapping
CreateRuntimeErrorWrappers.java Refactored to call expandCasts and wrap errors
ExpressionCompiler.java Updated cast validation and all cast call sites to use CastType enum
Test files Added comprehensive tests for safe cast on arrays, maps, and edge cases
sqllib (Rust) Added array_map_safe and map_map_safe functions for safe conversions
Documentation Updated casts.md and map.md with new restrictions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants