Skip to content

Conversation

@asolimando
Copy link
Contributor

Uses schema field nullability when converting Calcite LogicalValues literals back to Substrait, instead of deriving nullability from the RexLiteral type.

Calcite's LogicalValues may have literals with non-nullable types even when the schema field is nullable (Calcite infers the tightest possible type for literals, by design).

Previously this caused a mismatch during roundtrip conversion, as VirtualTableScan requires row field types to exactly match schema field types.

Fixes #683

Copy link
Member

@benbellick benbellick left a comment

Choose a reason for hiding this comment

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

a few small comments but mostly looks good!!

// convert type first to guarantee we can handle the value.
final Type type = typeConverter.toSubstrait(literal.getType());
final boolean n = type.nullable();
return convert(literal, type.nullable());
Copy link
Member

Choose a reason for hiding this comment

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

I'm now wondering if it's the case that type.nullable() will always be false. If nullability of literals is always lost in calcite values, won't this always just be the default?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, null literals have nullable types in Calcite, so it's not always non-nullable.
I have added the nullLiteralRoundTrip test to show this.

@asolimando asolimando requested a review from benbellick January 22, 2026 14:19
Copy link
Member

@benbellick benbellick left a comment

Choose a reason for hiding this comment

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

I think this is great, thanks for your effort! I left a few very minor style comments but it otherwise looks good to me. The style comments are generally about just preferring the shorter ExpressionCreator API.

final Type type = typeConverter.toSubstrait(literal.getType());
final Type typeWithNullability =
nullable ? TypeCreator.asNullable(type) : TypeCreator.asNotNullable(type);
return ExpressionCreator.typedNull(typeWithNullability);
Copy link
Member

Choose a reason for hiding this comment

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

I think that as of #686, it is the case that typedNull will actually throw an exception if it is passed a non-null type. Just commenting so you are aware that if the TypeCreator.asNotNullable case is hit here, an exception will be thrown.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for sharing, I gave it a bit more thinking and I think it's fine and the thrown error will be clear enough, no need to be defensive here nor adjust the error message (which is what you are suggesting, IIUC)

Uses schema field nullability when converting Calcite LogicalValues literals back to Substrait, instead of deriving nullability from the RexLiteral type.

Calcite's LogicalValues may have literals with non-nullable types even when the schema field is nullable. Previously this caused a mismatch during roundtrip conversion, as VirtualTableScan requires row field types to exactly match schema field types.

Fixes substrait-io#683
@asolimando asolimando force-pushed the fix-issue-683-nullability-roundtrip branch from a43ed81 to f22bbcd Compare January 23, 2026 10:53
@asolimando
Copy link
Contributor Author

I think this is great, thanks for your effort! I left a few very minor style comments but it otherwise looks good to me. The style comments are generally about just preferring the shorter ExpressionCreator API.

Thanks Ben, I have addressed the style comments, I took the liberty to force push as the PR was already approved, to be able to resolve conflicts with latest main, but I haven't changed nothing significantly that could invalidate your review outcome.

@benbellick benbellick merged commit e1c5207 into substrait-io:main Jan 23, 2026
12 checks passed
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.

Lost Nullability in Calcite Roundtrip

2 participants