Skip to content

[parquet-java 1.18.0] data-corruption for reading NUMERIC arrays #3716

Description

@yimingli-vmware

Describe the bug, including details regarding any error messages, version, and platform.

We have an existing passing test case to write a parquet numeric array and read it back. After upgrading parquet-java from 1.17.1 to 1.18.0, the test failed because of the read mismatch.

For example:

# what we write via a parquet writer
{"12345678901234567890.123456789012345678", "12345678901234567890.123456789012345678"},
{"22.2345", "22.2345"},
# what we read from a parquet reader
row 0: 12345678901234567890.123456789012345678 12345678901234567890.123456789012345678
row 1: 12345678901234567890.123456789012345678 22.234500000000000000 <- the first record is wrong

I can reproduce this issue with the following test code:

importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.Path;
importorg.apache.parquet.example.data.Group;
importorg.apache.parquet.example.data.simple.SimpleGroupFactory;
importorg.apache.parquet.hadoop.ParquetWriter;
importorg.apache.parquet.hadoop.example.ExampleParquetWriter;
importorg.apache.parquet.hadoop.example.GroupWriteSupport;
importorg.apache.parquet.hadoop.metadata.CompressionCodecName;
importorg.apache.parquet.io.api.Binary;
importorg.apache.parquet.schema.MessageType;
importorg.apache.parquet.schema.MessageTypeParser;
importorg.apache.parquet.hadoop.ParquetReader;
importorg.apache.parquet.hadoop.example.GroupReadSupport;
importjava.math.BigDecimal;
importjava.math.BigInteger;
importjava.util.Arrays;
publicclassRepro {
publicstaticvoidmain(String[] args) throwsException {
StringschemaStr = "message test {\n" +
" optional group numeric_array (LIST) {\n" +
" repeated group list {\n" +
" optional fixed_len_byte_array(16) element (DECIMAL(38,18));\n" +
" }\n" +
" }\n" +
"}";
MessageTypeschema = MessageTypeParser.parseMessageType(schemaStr);
Configurationconf = newConfiguration();
GroupWriteSupport.setSchema(schema, conf);
Pathpath = newPath("file:///tmp/parquet-repro/out.parquet");
path.getFileSystem(conf).delete(path, false);
// 2 rows, 2 elements per row -- this is the minimal trigger.// A single element per row does NOT reproduce the bug.String[][] rows = {
{"12345678901234567890.123456789012345678", "12345678901234567890.123456789012345678"},
{"22.2345", "22.2345"},
};
try (ParquetWriter<Group> writer = ExampleParquetWriter.builder(path)
.withConf(conf)
.withType(schema)
.withCompressionCodec(CompressionCodecName.UNCOMPRESSED)
.withDictionaryEncoding(false)
.build()) {
SimpleGroupFactoryfactory = newSimpleGroupFactory(schema);
for (String[] row : rows) {
Groupgroup = factory.newGroup();
GrouplistGroup = group.addGroup(0);
for (StringdecVal : row) {
GrouprepeatedGroup = listGroup.addGroup(0);
byte[] bytes = toFixedLenBytes(decVal, 18, 16);
repeatedGroup.add(0, Binary.fromReusedByteArray(bytes));
}
writer.write(group);
}
}
try (ParquetReader<Group> reader = ParquetReader.builder(newGroupReadSupport(), path)
.withConf(conf)
.build()) {
Groupg;
inti = 0;
while ((g = reader.read()) != null) {
GrouplistGroup = g.getGroup(0, 0);
intcount = listGroup.getFieldRepetitionCount(0);
StringBuildersb = newStringBuilder("row " + i + ": ");
for (intj = 0; j < count; j++) {
GrouprepeatedGroup = listGroup.getGroup(0, j);
byte[] readBytes = repeatedGroup.getBinary(0, 0).getBytes();
BigDecimalbd = newBigDecimal(newBigInteger(readBytes), 18);
sb.append(bd).append(" ");
}
System.out.println(sb);
i++;
}
}
}
privatestaticbyte[] toFixedLenBytes(StringdecStr, intscale, intlen) {
BigDecimalbd = newBigDecimal(decStr).setScale(scale);
BigIntegerunscaled = bd.unscaledValue();
byte[] full = unscaled.toByteArray();
byte[] tgt = newbyte[len];
if (unscaled.signum() == -1) {
Arrays.fill(tgt, (byte) 0xFF);
}
intsrcStart = Math.max(0, full.length - len);
intcopyLen = full.length - srcStart;
System.arraycopy(full, srcStart, tgt, len - copyLen, copyLen);
returntgt;
}
}

Component(s)

No response

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions