diff --git a/paimon-api/src/main/java/org/apache/paimon/types/MapType.java b/paimon-api/src/main/java/org/apache/paimon/types/MapType.java index 75ea5fbb7cc2..4c3344dad60d 100644 --- a/paimon-api/src/main/java/org/apache/paimon/types/MapType.java +++ b/paimon-api/src/main/java/org/apache/paimon/types/MapType.java @@ -19,6 +19,7 @@ package org.apache.paimon.types; import org.apache.paimon.annotation.Public; +import org.apache.paimon.utils.MathUtils; import org.apache.paimon.utils.Preconditions; import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.core.JsonGenerator; @@ -66,7 +67,7 @@ public DataType getValueType() { @Override public int defaultSize() { - return keyType.defaultSize() + valueType.defaultSize(); + return MathUtils.addSafely(keyType.defaultSize(), valueType.defaultSize()); } @Override diff --git a/paimon-api/src/main/java/org/apache/paimon/types/MultisetType.java b/paimon-api/src/main/java/org/apache/paimon/types/MultisetType.java index e211e1d8b29b..76101a0d498a 100644 --- a/paimon-api/src/main/java/org/apache/paimon/types/MultisetType.java +++ b/paimon-api/src/main/java/org/apache/paimon/types/MultisetType.java @@ -19,6 +19,7 @@ package org.apache.paimon.types; import org.apache.paimon.annotation.Public; +import org.apache.paimon.utils.MathUtils; import org.apache.paimon.utils.Preconditions; import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.core.JsonGenerator; @@ -63,7 +64,7 @@ public DataType getElementType() { @Override public int defaultSize() { - return elementType.defaultSize() + 4; + return MathUtils.addSafely(elementType.defaultSize(), 4); } @Override diff --git a/paimon-api/src/main/java/org/apache/paimon/types/RowType.java b/paimon-api/src/main/java/org/apache/paimon/types/RowType.java index e592ff71619b..30b357f5b944 100644 --- a/paimon-api/src/main/java/org/apache/paimon/types/RowType.java +++ b/paimon-api/src/main/java/org/apache/paimon/types/RowType.java @@ -21,6 +21,7 @@ import org.apache.paimon.annotation.Public; import org.apache.paimon.schema.Schema; import org.apache.paimon.table.SpecialFields; +import org.apache.paimon.utils.MathUtils; import org.apache.paimon.utils.Preconditions; import org.apache.paimon.utils.StringUtils; @@ -158,7 +159,9 @@ public int getFieldIndexByFieldId(int fieldId) { @Override public int defaultSize() { - return fields.stream().mapToInt(f -> f.type().defaultSize()).sum(); + return fields.stream() + .mapToInt(f -> f.type().defaultSize()) + .reduce(0, MathUtils::addSafely); } @Override diff --git a/paimon-api/src/test/java/org/apache/paimon/types/DefaultSizeOverflowTest.java b/paimon-api/src/test/java/org/apache/paimon/types/DefaultSizeOverflowTest.java new file mode 100644 index 000000000000..11cb08ce0f4a --- /dev/null +++ b/paimon-api/src/test/java/org/apache/paimon/types/DefaultSizeOverflowTest.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.paimon.types; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests that {@link RowType}, {@link MapType} and {@link MultisetType} saturate their {@code + * defaultSize()} at {@link Integer#MAX_VALUE} instead of overflowing to a negative value. + */ +class DefaultSizeOverflowTest { + + @Test + void testRowTypeDefaultSize() { + assertThat(DataTypes.ROW(DataTypes.INT(), DataTypes.BIGINT()).defaultSize()).isEqualTo(12); + } + + @Test + void testRowTypeDefaultSizeOverflowReturnsMaxValue() { + assertThat( + DataTypes.ROW( + DataTypes.VECTOR(Integer.MAX_VALUE, DataTypes.FLOAT()), + DataTypes.VECTOR(Integer.MAX_VALUE, DataTypes.FLOAT())) + .defaultSize()) + .isEqualTo(Integer.MAX_VALUE); + } + + @Test + void testMapTypeDefaultSize() { + assertThat(DataTypes.MAP(DataTypes.INT(), DataTypes.BIGINT()).defaultSize()).isEqualTo(12); + } + + @Test + void testMapTypeDefaultSizeOverflowReturnsMaxValue() { + assertThat( + DataTypes.MAP( + DataTypes.VECTOR(Integer.MAX_VALUE, DataTypes.FLOAT()), + DataTypes.VECTOR(Integer.MAX_VALUE, DataTypes.FLOAT())) + .defaultSize()) + .isEqualTo(Integer.MAX_VALUE); + } + + @Test + void testMultisetTypeDefaultSize() { + assertThat(DataTypes.MULTISET(DataTypes.INT()).defaultSize()).isEqualTo(8); + } + + @Test + void testMultisetTypeDefaultSizeOverflowReturnsMaxValue() { + assertThat( + DataTypes.MULTISET(DataTypes.VECTOR(Integer.MAX_VALUE, DataTypes.FLOAT())) + .defaultSize()) + .isEqualTo(Integer.MAX_VALUE); + } +}