diff --git a/fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergComplexTypeDiff.java b/fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergComplexTypeDiff.java index ad8ab08a917ce2..a7fae7b79683fd 100644 --- a/fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergComplexTypeDiff.java +++ b/fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergComplexTypeDiff.java @@ -22,6 +22,7 @@ import org.apache.iceberg.UpdateSchema; import org.apache.iceberg.types.Type; +import org.apache.iceberg.types.TypeUtil; import org.apache.iceberg.types.Types; import java.util.HashSet; @@ -50,7 +51,7 @@ * {@code UpdateSchema.commit()}, so any guard throwing aborts the whole change atomically.
* *Supported shape changes (legacy parity): widen an existing nested field's primitive type (only the - * iceberg-representable safe promotions int→long, float→double, or an exact match), change a nested + * iceberg-representable safe promotions, including same-scale decimal precision widening), change a nested * field's comment, widen a NOT NULL nested field to nullable, and append new (nullable) STRUCT fields. The * category of every nested level must stay the same (struct/array/map); struct fields may not be renamed, * reordered, dropped, or narrowed to NOT NULL; a MAP key type may not change.
@@ -310,21 +311,13 @@ private static void requireValueNotNarrowed(Types.MapType oldMap, Types.MapType /** * Whether changing a nested primitive {@code oldType} to {@code newType} is a legal promotion, mirroring - * legacy {@code ColumnType.checkSupportSchemaChangeForNestedPrimitive} restricted to the iceberg-representable - * cases: an exact match (covers VARCHAR length growth, which both map to iceberg STRING), INT→BIGINT - * (iceberg INTEGER→LONG), and FLOAT→DOUBLE. Everything else (e.g. a nested DECIMAL precision change, - * any narrowing, a category change) is rejected — matching legacy's restrictive nested rule. + * Iceberg's primitive-promotion rules. Besides INTEGER→LONG and FLOAT→DOUBLE, Iceberg allows a + * DECIMAL precision increase when scale is unchanged. Delegating to Iceberg keeps the connector's validation + * aligned with the UpdateSchema operation it is about to commit. */ private static boolean isLegalNestedPrimitivePromotion(Type oldType, Type newType) { - if (oldType.equals(newType)) { - return true; - } - Type.TypeID oldId = oldType.typeId(); - Type.TypeID newId = newType.typeId(); - if (oldId == Type.TypeID.INTEGER && newId == Type.TypeID.LONG) { - return true; - } - return oldId == Type.TypeID.FLOAT && newId == Type.TypeID.DOUBLE; + return newType.isPrimitiveType() + && TypeUtil.isPromotionAllowed(oldType, newType.asPrimitiveType()); } /** The iceberg type category (struct/list/map) of {@code newType} must equal {@code oldType}'s. */ diff --git a/fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/CatalogBackedIcebergCatalogOpsColumnEvolutionTest.java b/fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/CatalogBackedIcebergCatalogOpsColumnEvolutionTest.java index 450ae232695798..e23b0cfb309aae 100644 --- a/fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/CatalogBackedIcebergCatalogOpsColumnEvolutionTest.java +++ b/fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/CatalogBackedIcebergCatalogOpsColumnEvolutionTest.java @@ -606,17 +606,18 @@ public void testModifyStructNewFieldNotNullableFailsLoud() { } @Test - public void testModifyNestedDecimalPrecisionFailsLoud() { - // Legacy parity: a nested primitive change is restricted to int->long / float->double / exact; a - // DECIMAL precision change inside a struct is rejected (checkSupportSchemaChangeForNestedPrimitive). + public void testModifyNestedDecimalPrecisionWidens() { + // Iceberg permits a nested DECIMAL precision increase when the scale stays fixed. createTable("s_dec", new ConnectorColumn("st", structType(Arrays.asList("a"), Arrays.asList(ConnectorType.of("DECIMALV3", 10, 2)), Arrays.asList(true), Arrays.asList((String) null)), "", true, null, false)); - DorisConnectorException ex = Assertions.assertThrows(DorisConnectorException.class, - () -> modifyComplex("s_dec", "st", - structType(Arrays.asList("a"), Arrays.asList(ConnectorType.of("DECIMALV3", 20, 2)), - Arrays.asList(true), Arrays.asList((String) null)), true)); - Assertions.assertTrue(ex.getMessage().contains("nested")); + modifyComplex("s_dec", "st", + structType(Arrays.asList("a"), Arrays.asList(ConnectorType.of("DECIMALV3", 20, 2)), + Arrays.asList(true), Arrays.asList((String) null)), true); + Types.DecimalType amount = (Types.DecimalType) reload("s_dec").findField("st") + .type().asStructType().field("a").type(); + Assertions.assertEquals(20, amount.precision()); + Assertions.assertEquals(2, amount.scale()); } @Test diff --git a/fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/IcebergNestedColumnEvolutionTest.java b/fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/IcebergNestedColumnEvolutionTest.java index 0f74d82f7358db..c2029243c3a709 100644 --- a/fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/IcebergNestedColumnEvolutionTest.java +++ b/fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/IcebergNestedColumnEvolutionTest.java @@ -713,6 +713,26 @@ public void testModifyNestedPrimitivePromotionAllowed() { Assertions.assertEquals(Type.TypeID.LONG, metric.type().typeId()); } + @Test + public void testModifyNestedStructDecimalPrecisionPromotionAllowed() { + // Iceberg permits DECIMAL precision widening when the scale stays fixed. This is the same complex MODIFY + // issued by the Trino product test for STRUCT