This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new ed613d6abc [format] Support numeric type widening when reading Avro
files (#9362)
ed613d6abc is described below
commit ed613d6abc27ff5d3b6d313346af23af47316030
Author: Arnav Balyan <[email protected]>
AuthorDate: Sun Aug 23 20:48:09 2026 +0530
[format] Support numeric type widening when reading Avro files (#9362)
---
.../paimon/format/avro/FieldReaderFactory.java | 44 ++++++++++++++++++
.../paimon/format/avro/AvroFileFormatTest.java | 52 ++++++++++++++++++++++
2 files changed, 96 insertions(+)
diff --git
a/paimon-format/src/main/java/org/apache/paimon/format/avro/FieldReaderFactory.java
b/paimon-format/src/main/java/org/apache/paimon/format/avro/FieldReaderFactory.java
index 1369a359eb..6c5a4d018e 100644
---
a/paimon-format/src/main/java/org/apache/paimon/format/avro/FieldReaderFactory.java
+++
b/paimon-format/src/main/java/org/apache/paimon/format/avro/FieldReaderFactory.java
@@ -76,10 +76,16 @@ public class FieldReaderFactory implements
AvroSchemaVisitor<FieldReader> {
private static final FieldReader INT_READER = new IntReader();
+ private static final FieldReader INT_TO_BIGINT_READER = new
IntToBigIntReader();
+
+ private static final FieldReader INT_TO_DOUBLE_READER = new
IntToDoubleReader();
+
private static final FieldReader BIGINT_READER = new BigIntReader();
private static final FieldReader FLOAT_READER = new FloatReader();
+ private static final FieldReader FLOAT_TO_DOUBLE_READER = new
FloatToDoubleReader();
+
private static final FieldReader DOUBLE_READER = new DoubleReader();
private static final FieldReader TIMESTAMP_MILLS_READER = new
TimestampMillsReader();
@@ -93,6 +99,20 @@ public class FieldReaderFactory implements
AvroSchemaVisitor<FieldReader> {
&& type.getTypeRoot() == DataTypeRoot.BLOB) {
return new BlobBytesReader(uriReader);
}
+ if (type != null && primitive.getLogicalType() == null) {
+ if (primitive.getType() == Schema.Type.INT) {
+ if (type.getTypeRoot() == DataTypeRoot.BIGINT) {
+ return INT_TO_BIGINT_READER;
+ }
+ if (type.getTypeRoot() == DataTypeRoot.DOUBLE) {
+ return INT_TO_DOUBLE_READER;
+ }
+ }
+ if (primitive.getType() == Schema.Type.FLOAT
+ && type.getTypeRoot() == DataTypeRoot.DOUBLE) {
+ return FLOAT_TO_DOUBLE_READER;
+ }
+ }
return AvroSchemaVisitor.super.primitive(primitive, type);
}
@@ -335,6 +355,22 @@ public class FieldReaderFactory implements
AvroSchemaVisitor<FieldReader> {
}
}
+ private static class IntToBigIntReader extends IntReader {
+
+ @Override
+ public Object read(Decoder decoder, Object reuse) throws IOException {
+ return (long) decoder.readInt();
+ }
+ }
+
+ private static class IntToDoubleReader extends IntReader {
+
+ @Override
+ public Object read(Decoder decoder, Object reuse) throws IOException {
+ return (double) decoder.readInt();
+ }
+ }
+
private static class BigIntReader implements FieldReader {
@Override
@@ -361,6 +397,14 @@ public class FieldReaderFactory implements
AvroSchemaVisitor<FieldReader> {
}
}
+ private static class FloatToDoubleReader extends FloatReader {
+
+ @Override
+ public Object read(Decoder decoder, Object reuse) throws IOException {
+ return (double) decoder.readFloat();
+ }
+ }
+
private static class DoubleReader implements FieldReader {
@Override
diff --git
a/paimon-format/src/test/java/org/apache/paimon/format/avro/AvroFileFormatTest.java
b/paimon-format/src/test/java/org/apache/paimon/format/avro/AvroFileFormatTest.java
index ed60c016a7..0bcc799b3b 100644
---
a/paimon-format/src/test/java/org/apache/paimon/format/avro/AvroFileFormatTest.java
+++
b/paimon-format/src/test/java/org/apache/paimon/format/avro/AvroFileFormatTest.java
@@ -37,6 +37,10 @@ import org.apache.paimon.types.RowType;
import org.apache.avro.Schema;
import org.apache.avro.SchemaBuilder;
+import org.apache.avro.file.DataFileWriter;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DecoderFactory;
@@ -52,6 +56,7 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@@ -271,6 +276,53 @@ public class AvroFileFormatTest {
assertThat(decoder.isEnd()).isTrue();
}
+ @Test
+ void testReadNumericTypeWidening() throws IOException {
+ Schema writerSchema =
+ SchemaBuilder.record("record")
+ .fields()
+ .requiredInt("int_to_bigint")
+ .requiredInt("int_to_double")
+ .requiredFloat("float_to_double")
+ .endRecord();
+ LocalFileIO fileIO = LocalFileIO.create();
+ Path file = new Path(new Path(tempPath.toUri()),
UUID.randomUUID().toString());
+
+ try (PositionOutputStream out = fileIO.newOutputStream(file, false);
+ DataFileWriter<GenericRecord> writer =
+ new DataFileWriter<>(new
GenericDatumWriter<>(writerSchema))) {
+ writer.create(writerSchema, out);
+ GenericRecord record = new GenericData.Record(writerSchema);
+ record.put("int_to_bigint", 42);
+ record.put("int_to_double", 21);
+ record.put("float_to_double", 10.5f);
+ writer.append(record);
+ }
+
+ RowType tableType =
+ RowType.builder()
+ .field("int_to_bigint", DataTypes.BIGINT().notNull())
+ .field("int_to_double", DataTypes.DOUBLE().notNull())
+ .field("float_to_double", DataTypes.DOUBLE().notNull())
+ .build();
+ List<Object> values = new ArrayList<>();
+ try (RecordReader<InternalRow> reader =
+ fileFormat
+ .createReaderFactory(tableType, tableType, new
ArrayList<>())
+ .createReader(
+ new FormatReaderContext(
+ fileIO, file,
fileIO.getFileSize(file), null, null))) {
+ reader.forEachRemaining(
+ row -> {
+ values.add(row.getLong(0));
+ values.add(row.getDouble(1));
+ values.add(row.getDouble(2));
+ });
+ }
+
+ assertThat(values).containsExactly(42L, 21.0d, 10.5d);
+ }
+
@Test
void testReadsLargeZstdBlock() throws IOException {
RowType rowType =