Skip to content

fix(arrow): include REE value nullability in type equality - #1158

Merged
zeroshade merged 2 commits into
apache:mainfrom
fallintoplace:fix/ree-nullability-equality
Aug 26, 2026
Merged

fix(arrow): include REE value nullability in type equality#1158
zeroshade merged 2 commits into
apache:mainfrom
fallintoplace:fix/ree-nullability-equality

Conversation

@fallintoplace

@fallintoplace fallintoplace commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Rationale for this change

TypeEqual compares run-end and value data types for run-end encoded types, but it does not compare whether the value field is nullable. Structurally different types can therefore compare equal and produce the same type fingerprint.

What changes are included in this PR?

Include ValueNullable in run-end encoded type equality and fingerprints.

Are these changes tested?

Yes. The regression test verifies both comparison directions and distinct fingerprints for nullable and non-nullable value fields. The full arrow package suite passes.

Are there any user-facing changes?

Run-end encoded types with different value nullability now compare unequal and have different fingerprints.

@fallintoplace
fallintoplace force-pushed the fix/ree-nullability-equality branch from cc1f953 to cfda77b Compare August 9, 2026 22:51
@fallintoplace
fallintoplace marked this pull request as ready for review August 9, 2026 22:51
@fallintoplace
fallintoplace marked this pull request as draft August 9, 2026 22:54
@fallintoplace
fallintoplace force-pushed the fix/ree-nullability-equality branch from cfda77b to 36f906a Compare August 23, 2026 21:56
@fallintoplace
fallintoplace marked this pull request as ready for review August 23, 2026 21:56

@zeroshade zeroshade left a comment

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.

Found two blocking API consistency issues: timestamp-with-offset still accepts a nullable REE offset type that is unequal to its canonical type, and strict REE equality leaves no public array constructor that can preserve ValueNullable=false. The branch also currently conflicts with main and has a failing Verify check.


This review was drafted by an AI-assisted tool and confirmed by an Apache Arrow Go maintainer. After you've addressed the points above and pushed an update, an Apache Arrow Go maintainer — a real person — will take the next look at the PR. If you think one of the findings is misapplied, please reply on the PR and a maintainer will weigh in.

More on how Apache Arrow Go handles maintainer review:
CONTRIBUTING.md.

@@ -46,10 +46,6 @@ func isOffsetTypeOk(offsetType arrow.DataType) bool {
case *arrow.RunEndEncodedType:
return offsetType.ValidRunEndsType(offsetType.RunEnds()) &&
arrow.TypeEqual(offsetType.Encoded(), arrow.PrimitiveTypes.Int16)

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.

Blocking: Now that IPC preserves ValueNullable, this compatibility check still ignores it. RunEndEncodedOf(Int16, Int16) defaults to ValueNullable=true and is accepted by NewTimestampWithOffsetTypeCustomOffset, while the canonical NewTimestampWithOffsetTypeRunEndEncoded constructor explicitly sets it to false. These accepted extension types now compare unequal and have different fingerprints; a nullable REE can deserialize successfully but fail ExtensionEquals against the canonical type. The removed FIXME said this check was disabled only because IPC lost the flag. Please either require !offsetType.ValueNullable or normalize legacy input explicitly, with rejection/round-trip coverage.

Comment thread arrow/compare.go
return TypeEqual(l.Encoded(), r.Encoded(), opts...) &&
TypeEqual(l.runEnds, r.runEnds, opts...)
TypeEqual(l.runEnds, r.runEnds, opts...) &&
l.ValueNullable == r.ValueNullable

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.

Blocking: Making equality strict exposes a public API gap: array.NewRunEndEncodedArray always calls RunEndEncodedOf, which resets ValueNullable to true. Existing code that defines a non-nullable REE schema and constructs its column with this public helper now gets unequal types and a NewRecordBatch type-mismatch panic—even though both types print identically. This PR works around the same problem with a private typed helper in arrdata. Please add a public constructor that accepts/preserves the *RunEndEncodedType and cover record construction and concatenation with ValueNullable=false.

@fallintoplace
fallintoplace force-pushed the fix/ree-nullability-equality branch from 36f906a to 120bf15 Compare August 25, 2026 19:32

@zeroshade zeroshade left a comment

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.

The previous blockers are resolved. REE value nullability is now consistently represented in equality and fingerprints, preserved through array construction and serialization paths, and enforced for timestamp-with-offset storage types. The affected package, race, roundtrip, and tagged C Data tests passed locally.

@zeroshade
zeroshade merged commit 3a9323d into apache:main Aug 26, 2026
26 of 27 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.

2 participants