Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-42041: [Swift] Fix nullable type decoder issue #42043

Merged
merged 1 commit into from
Jun 9, 2024
Merged

Conversation

abandy
Copy link
Contributor

@abandy abandy commented Jun 9, 2024

Rationale for this change

There is an issue when decoding nullable types. The previous method of checking for nil values always returned false for nullable types due too the ArrowArray types being non nullable.

What changes are included in this PR?

This PR adds a IsNull method to the ArrowDecoder to be used for null checks. Also, a check for nullable types has been added to the Unkeyed decode method.

Are these changes tested?

Yes, tests have been added/modified to test this fix.

@abandy abandy requested a review from kou as a code owner June 9, 2024 15:28
Copy link

github-actions bot commented Jun 9, 2024

⚠️ GitHub issue #42041 has been automatically assigned in GitHub to PR creator.

Copy link
Member

@kou kou left a comment

Choose a reason for hiding this comment

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

+1

@@ -173,7 +191,7 @@ private struct ArrowKeyedDecoding<Key: CodingKey>: KeyedDecodingContainerProtoco
}

func decodeNil(forKey key: Key) throws -> Bool {
return try self.decoder.doDecode(key) == nil
try self.decoder.isNull(key)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
try self.decoder.isNull(key)
try self.decoder.isNull(key)

Hmm. It seems that this file isn't lint target. Could you check it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! The file is being checked by the linter but apparently a space off doesn't cause it to fail :). I will update accordingly.

Comment on lines 143 to 151
if type == Int8?.self || type == Int16?.self ||
type == Int32?.self || type == Int64?.self ||
type == UInt8?.self || type == UInt16?.self ||
type == UInt32?.self || type == UInt64?.self ||
type == String?.self || type == Double?.self ||
type == Float?.self || type == Date?.self {
defer {increment()}
return try self.decoder.doDecode(self.currentIndex)!
} else if type == Int8.self || type == Int16.self ||
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 not familiar with Swift but can we unify this if and else if? It seems that body codes of them are same.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They can be unified. I had separated them to delineate the nullable and non nullable types but I can merge them.

Comment on lines 190 to 218
let stringWNilBuilder = try ArrowArrayBuilders.loadStringArrayBuilder()
stringWNilBuilder.append(nil, "test1", nil, "test3")
let resultWNil = RecordBatch.Builder()
.addColumn("propInt8", arrowArray: try int8Builder.toHolder())
.addColumn("propString", arrowArray: try stringWNilBuilder.toHolder())
.finish()
switch resultWNil {
case .success(let rb):
let decoder = ArrowDecoder(rb)
let testData = try decoder.decode([Int8: String?].self)
var index: Int8 = 0
for data in testData {
let str = data[10 + index]
if index % 2 == 0 {
XCTAssertNil(str!)
} else {
XCTAssertEqual(str, "test\(index)")
}
index += 1
}
case .failure(let err):
throw err
}
Copy link
Member

Choose a reason for hiding this comment

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

How about creating a new separated test for this?

Comment on lines +145 to +160
let int8WNilBuilder: NumberArrayBuilder<Int8> = try ArrowArrayBuilders.loadNumberArrayBuilder()
int8WNilBuilder.append(10, nil, 12, nil)
let resultWNil = RecordBatch.Builder()
.addColumn("propInt8", arrowArray: try int8WNilBuilder.toHolder())
.finish()
switch resultWNil {
case .success(let rb):
let decoder = ArrowDecoder(rb)
let testData = try decoder.decode(Int8?.self)
for index in 0..<testData.count {
let val: Int8? = testData[index]
if index % 2 == 1 {
XCTAssertNil(val)
} else {
Copy link
Member

Choose a reason for hiding this comment

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

How about creating a new separated test for this case?
testArrowSingleDecoderWithoutNull() and testArrowSingleDecoderWithNull()?

@github-actions github-actions bot added awaiting merge Awaiting merge and removed awaiting review Awaiting review labels Jun 9, 2024
Copy link
Member

@kou kou left a comment

Choose a reason for hiding this comment

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

+1

@kou kou changed the title GH-42041: [Swift ] Fix nullable type decoder issue GH-42041: [Swift] Fix nullable type decoder issue Jun 9, 2024
@kou kou merged commit 7aaea3d into apache:main Jun 9, 2024
8 checks passed
@kou kou removed the awaiting merge Awaiting merge label Jun 9, 2024
@github-actions github-actions bot added the awaiting merge Awaiting merge label Jun 9, 2024
@abandy abandy deleted the GH-42041 branch June 10, 2024 13:59
Copy link

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7aaea3d.

There were no benchmark performance regressions. 🎉

The full Conbench report has more details. It also includes information about 2 possible false positives for unstable benchmarks that are known to sometimes produce them.

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

Successfully merging this pull request may close these issues.

2 participants