-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Data, Parquet: Fix UUID ClassCastException when reading Parquet files with UUIDs #14027
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
Changes from 1 commit
3c77bba
ebd82de
b51a298
5aa04cf
1a51553
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -119,7 +119,8 @@ public static List<Object> parameters() { | |
| optional(14, "all_nans", DoubleType.get()), | ||
| optional(15, "some_nans", FloatType.get()), | ||
| optional(16, "no_nans", DoubleType.get()), | ||
| optional(17, "some_double_nans", DoubleType.get())); | ||
| optional(17, "some_double_nans", DoubleType.get()), | ||
| optional(18, "uuid_col", Types.UUIDType.get())); | ||
|
|
||
| private static final Types.StructType UNDERSCORE_STRUCT_FIELD_TYPE = | ||
| Types.StructType.of(Types.NestedField.required(8, "_int_field", IntegerType.get())); | ||
|
|
@@ -137,7 +138,8 @@ public static List<Object> parameters() { | |
| optional(14, "_all_nans", Types.DoubleType.get()), | ||
| optional(15, "_some_nans", FloatType.get()), | ||
| optional(16, "_no_nans", Types.DoubleType.get()), | ||
| optional(17, "_some_double_nans", Types.DoubleType.get())); | ||
| optional(17, "_some_double_nans", Types.DoubleType.get()), | ||
| optional(18, "_uuid_col", Types.UUIDType.get())); | ||
|
|
||
| private static final Schema VARIANT_SCHEMA = | ||
| new Schema( | ||
|
|
@@ -157,6 +159,11 @@ public static List<Object> parameters() { | |
| private static final int INT_MIN_VALUE = 30; | ||
| private static final int INT_MAX_VALUE = 79; | ||
|
|
||
| private static final UUID UUID_WITH_ZEROS = | ||
| UUID.fromString("00000000-0000-0000-0000-000000000000"); | ||
| private static final UUID UUID_WITH_ONES = | ||
| UUID.fromString("11111111-1111-1111-1111-111111111111"); | ||
|
|
||
| private File orcFile = null; | ||
| private MessageType parquetSchema = null; | ||
| private BlockMetaData rowGroupMetadata = null; | ||
|
|
@@ -211,6 +218,9 @@ public void createOrcInputFile() throws IOException { | |
| structNotNull.setField("_int_field", INT_MIN_VALUE + i); | ||
| record.setField("_struct_not_null", structNotNull); // struct with int | ||
|
|
||
| record.setField( | ||
| "_uuid_col", (i % 3 == 0) ? UUID_WITH_ZEROS : (i % 3 == 1) ? UUID_WITH_ONES : null); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor: what's the reason for doing the modulo here? why not just write UUID_WITH_ZEROS?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea was to use different values to make sure the filtering works, but now I think just with_zeros and null are enough. WDYT?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it comes down to also testing other expressions. See my other comment on this |
||
|
|
||
| appender.add(record); | ||
| } | ||
| } | ||
|
|
@@ -248,6 +258,10 @@ private void createParquetInputFile() throws IOException { | |
| GenericRecord structNotNull = GenericRecord.create(UNDERSCORE_STRUCT_FIELD_TYPE); | ||
| structNotNull.setField("_int_field", INT_MIN_VALUE + i); | ||
| builder.setField("_struct_not_null", structNotNull); // struct with int | ||
|
|
||
|
nastra marked this conversation as resolved.
Outdated
|
||
| builder.setField( | ||
| "_uuid_col", (i % 3 == 0) ? UUID_WITH_ZEROS : (i % 3 == 1) ? UUID_WITH_ONES : null); | ||
|
|
||
| records.add(builder); | ||
| } | ||
|
|
||
|
|
@@ -1063,6 +1077,18 @@ public void testVariantFieldAllNullsNotNull() throws IOException { | |
| } | ||
| } | ||
|
|
||
| @TestTemplate | ||
| public void testUUIDEq() { | ||
| assumeThat(format).as("Only valid for Parquet").isEqualTo(FileFormat.PARQUET); | ||
|
|
||
| boolean shouldRead = shouldRead(equal("uuid_col", UUID_WITH_ZEROS)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about testing other expressions? |
||
| assertThat(shouldRead).as("Should read: UUID value exists in row group").isTrue(); | ||
|
|
||
| UUID nonExistentUuid = UUID.fromString("99999999-9999-9999-9999-999999999999"); | ||
| boolean shouldSkip = shouldRead(equal("uuid_col", nonExistentUuid)); | ||
| assertThat(shouldSkip).as("Should skip: UUID value does not exist in row group").isFalse(); | ||
| } | ||
|
|
||
| private boolean shouldRead(Expression expression) { | ||
| return shouldRead(expression, true); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -83,6 +83,8 @@ static Function<Object, Object> converterFromParquet( | |
| } else if (icebergType.typeId() == Type.TypeID.DOUBLE | ||
| && parquetType.getPrimitiveTypeName() == PrimitiveType.PrimitiveTypeName.FLOAT) { | ||
| return value -> ((Float) fromParquet.apply(value)).doubleValue(); | ||
| } else if (icebergType.typeId() == Type.TypeID.UUID) { | ||
| return binary -> UUIDUtil.convert(((Binary) binary).toByteBuffer()); | ||
|
Comment on lines
+86
to
+87
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like an odd place to apply this conversion since the rows above are more about schema evolution. However, looking at it a bit closer, I think it makes sense. Other logical types, such as This will just compare the bytes using an unsigned lexicographical binary comparator. |
||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when is this actually used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, the b51a298 commit solves this.