This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 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 93d70104e4 [core, api] Add option to disable explicit type casting
(#5692)
93d70104e4 is described below
commit 93d70104e4c2596d1d941bd71b7014257a7bf280
Author: Ashish Khatkar <[email protected]>
AuthorDate: Thu Jun 5 11:54:49 2025 +0100
[core, api] Add option to disable explicit type casting (#5692)
---
.../shortcodes/generated/core_configuration.html | 6 +++++
.../main/java/org/apache/paimon/CoreOptions.java | 12 ++++++++++
.../org/apache/paimon/types/DataTypeCasts.java | 25 +++++++------------
.../org/apache/paimon/schema/SchemaManager.java | 14 +++++++++--
.../apache/paimon/schema/SchemaMergingUtils.java | 6 +----
.../apache/paimon/table/SchemaEvolutionTest.java | 15 ++++++++++++
.../apache/paimon/flink/SchemaChangeITCase.java | 28 ++++++++++++++++++++++
7 files changed, 83 insertions(+), 23 deletions(-)
diff --git a/docs/layouts/shortcodes/generated/core_configuration.html
b/docs/layouts/shortcodes/generated/core_configuration.html
index 856245b64f..8811915954 100644
--- a/docs/layouts/shortcodes/generated/core_configuration.html
+++ b/docs/layouts/shortcodes/generated/core_configuration.html
@@ -314,6 +314,12 @@ under the License.
<td>Boolean</td>
<td>Whether to enable deletion vectors mode. In this mode, index
files containing deletion vectors are generated when data is written, which
marks the data for deletion. During read operations, by applying these index
files, merging can be avoided.</td>
</tr>
+ <tr>
+ <td><h5>disable-explicit-type-casting</h5></td>
+ <td style="word-wrap: break-word;">false</td>
+ <td>Boolean</td>
+ <td>If true, it disables explicit type casting. For ex: it
disables converting LONG type to INT type. Users can enable this option to
disable explicit type casting</td>
+ </tr>
<tr>
<td><h5>dynamic-bucket.assigner-parallelism</h5></td>
<td style="word-wrap: break-word;">(none)</td>
diff --git a/paimon-api/src/main/java/org/apache/paimon/CoreOptions.java
b/paimon-api/src/main/java/org/apache/paimon/CoreOptions.java
index 88f8ca7582..4d437f19fa 100644
--- a/paimon-api/src/main/java/org/apache/paimon/CoreOptions.java
+++ b/paimon-api/src/main/java/org/apache/paimon/CoreOptions.java
@@ -1736,6 +1736,14 @@ public class CoreOptions implements Serializable {
"If true, it disables altering column type from
null to not null. Default is true. "
+ "Users can disable this option to
explicitly convert null column type to not null.");
+ public static final ConfigOption<Boolean> DISABLE_EXPLICIT_TYPE_CASTING =
+ ConfigOptions.key("disable-explicit-type-casting")
+ .booleanType()
+ .defaultValue(false)
+ .withDescription(
+ "If true, it disables explicit type casting. For
ex: it disables converting LONG type to INT type. "
+ + "Users can enable this option to disable
explicit type casting");
+
private final Options options;
public CoreOptions(Map<String, String> options) {
@@ -2251,6 +2259,10 @@ public class CoreOptions implements Serializable {
return options.get(DISABLE_ALTER_COLUMN_NULL_TO_NOT_NULL);
}
+ public boolean disableExplicitTypeCasting() {
+ return options.get(DISABLE_EXPLICIT_TYPE_CASTING);
+ }
+
public LookupStrategy lookupStrategy() {
return LookupStrategy.from(
mergeEngine().equals(MergeEngine.FIRST_ROW),
diff --git
a/paimon-api/src/main/java/org/apache/paimon/types/DataTypeCasts.java
b/paimon-api/src/main/java/org/apache/paimon/types/DataTypeCasts.java
index 0c0d2a8132..454c1c65d7 100644
--- a/paimon-api/src/main/java/org/apache/paimon/types/DataTypeCasts.java
+++ b/paimon-api/src/main/java/org/apache/paimon/types/DataTypeCasts.java
@@ -178,27 +178,20 @@ public final class DataTypeCasts {
}
/**
- * Returns whether the source type can be safely cast to the target type
without loosing
- * information.
+ * allowExplicit false : Returns whether the source type can be safely
cast to the target type
+ * without loosing information. Implicit casts are used for type widening
and type
+ * generalization (finding a common supertype for a set of types).
Implicit casts are similar to
+ * the Java semantics (e.g. this is not possible: {@code int x = (String)
z}).
*
- * <p>Implicit casts are used for type widening and type generalization
(finding a common
- * supertype for a set of types). Implicit casts are similar to the Java
semantics (e.g. this is
- * not possible: {@code int x = (String) z}).
- */
- public static boolean supportsImplicitCast(DataType sourceType, DataType
targetType) {
- return supportsCasting(sourceType, targetType, false);
- }
-
- /**
- * Returns whether the source type can be cast to the target type.
- *
- * <p>Explicit casts correspond to the SQL cast specification and
represent the logic behind a
+ * <p>allowExplicit true : Returns whether the source type can be cast to
the target type.
+ * Explicit casts correspond to the SQL cast specification and represent
the logic behind a
* {@code CAST(sourceType AS targetType)} operation. For example, it
allows for converting most
* types of the {@link DataTypeFamily#PREDEFINED} family to types of the
{@link
* DataTypeFamily#CHARACTER_STRING} family.
*/
- public static boolean supportsExplicitCast(DataType sourceType, DataType
targetType) {
- return supportsCasting(sourceType, targetType, true);
+ public static boolean supportsCast(
+ DataType sourceType, DataType targetType, boolean allowExplicit) {
+ return supportsCasting(sourceType, targetType, allowExplicit);
}
/**
diff --git
a/paimon-core/src/main/java/org/apache/paimon/schema/SchemaManager.java
b/paimon-core/src/main/java/org/apache/paimon/schema/SchemaManager.java
index 59c3c42dd5..21484cfc84 100644
--- a/paimon-core/src/main/java/org/apache/paimon/schema/SchemaManager.java
+++ b/paimon-core/src/main/java/org/apache/paimon/schema/SchemaManager.java
@@ -308,6 +308,14 @@ public class SchemaManager implements Serializable {
CoreOptions.DISABLE_ALTER_COLUMN_NULL_TO_NOT_NULL
.defaultValue()
.toString()));
+
+ boolean disableExplicitTypeCasting =
+ Boolean.parseBoolean(
+ oldOptions.getOrDefault(
+
CoreOptions.DISABLE_EXPLICIT_TYPE_CASTING.key(),
+ CoreOptions.DISABLE_EXPLICIT_TYPE_CASTING
+ .defaultValue()
+ .toString()));
List<DataField> newFields = new ArrayList<>(oldTableSchema.fields());
AtomicInteger highestFieldId = new
AtomicInteger(oldTableSchema.highestFieldId());
String newComment = oldTableSchema.comment();
@@ -434,8 +442,10 @@ public class SchemaManager implements Serializable {
disableNullToNotNull);
}
checkState(
- DataTypeCasts.supportsExplicitCast(
- sourceRootType,
targetRootType)
+ DataTypeCasts.supportsCast(
+ sourceRootType,
+ targetRootType,
+
!disableExplicitTypeCasting)
&&
CastExecutors.resolve(sourceRootType, targetRootType)
!= null,
String.format(
diff --git
a/paimon-core/src/main/java/org/apache/paimon/schema/SchemaMergingUtils.java
b/paimon-core/src/main/java/org/apache/paimon/schema/SchemaMergingUtils.java
index d7e21cd656..0fff27dce4 100644
--- a/paimon-core/src/main/java/org/apache/paimon/schema/SchemaMergingUtils.java
+++ b/paimon-core/src/main/java/org/apache/paimon/schema/SchemaMergingUtils.java
@@ -220,11 +220,7 @@ public class SchemaMergingUtils {
private static boolean supportsDataTypesCast(
DataType sourceType, DataType targetType, boolean
allowExplicitCast) {
- if (allowExplicitCast) {
- return DataTypeCasts.supportsExplicitCast(sourceType, targetType);
- } else {
- return DataTypeCasts.supportsImplicitCast(sourceType, targetType);
- }
+ return DataTypeCasts.supportsCast(sourceType, targetType,
allowExplicitCast);
}
private static DataField assignIdForNewField(DataField field,
AtomicInteger highestFieldId) {
diff --git
a/paimon-core/src/test/java/org/apache/paimon/table/SchemaEvolutionTest.java
b/paimon-core/src/test/java/org/apache/paimon/table/SchemaEvolutionTest.java
index 951539299c..76a63eb06e 100644
--- a/paimon-core/src/test/java/org/apache/paimon/table/SchemaEvolutionTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/table/SchemaEvolutionTest.java
@@ -314,6 +314,21 @@ public class SchemaEvolutionTest {
assertThat(tableSchema.fields().get(0).type()).isEqualTo(DataTypes.BIGINT());
assertThat(tableSchema.fields().get(0).description()).isEqualTo("f0
field");
+ schemaManager.commitChanges(
+ Collections.singletonList(
+
SchemaChange.setOption("disable-explicit-type-casting", "true")));
+ assertThatThrownBy(
+ () ->
+ schemaManager.commitChanges(
+ Collections.singletonList(
+ SchemaChange.updateColumnType(
+ "f0",
DataTypes.STRING()))))
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessage(
+ "Column type f0[BIGINT] cannot be converted to STRING
without loosing information.");
+ schemaManager.commitChanges(
+ Collections.singletonList(
+
SchemaChange.setOption("disable-explicit-type-casting", "false")));
// bigint to string
tableSchema =
schemaManager.commitChanges(
diff --git
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/SchemaChangeITCase.java
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/SchemaChangeITCase.java
index 03b568202e..da260851a8 100644
---
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/SchemaChangeITCase.java
+++
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/SchemaChangeITCase.java
@@ -423,6 +423,7 @@ public class SchemaChangeITCase extends CatalogITCaseBase {
"+I[3.1400, 1, 123, 3.14, 3]", "+I[4.1300, 2, 456,
3.14, 4]");
sql("CREATE TABLE T1 (a STRING, b STRING)");
+ sql("ALTER TABLE T1 SET ('disable-explicit-type-casting' = 'false')");
sql("INSERT INTO T1 VALUES('test', '3.14')");
sql("ALTER TABLE T1 MODIFY (a INT, b TINYINT)");
@@ -1561,4 +1562,31 @@ public class SchemaChangeITCase extends
CatalogITCaseBase {
.hasStackTraceContaining(
"Cannot update column type from nullable to non
nullable for a.c3.element.value");
}
+
+ @ParameterizedTest
+ @ValueSource(strings = {"orc", "avro", "parquet"})
+ public void testDisableExplicitTypeCasting(String formatType) {
+ sql(
+ "CREATE TABLE T "
+ + "( k INT, v INT, PRIMARY KEY (k) NOT ENFORCED ) "
+ + "WITH ( 'bucket' = '1', 'file.format' = '"
+ + formatType
+ + "' )");
+ sql("ALTER TABLE T SET ('disable-explicit-type-casting' = 'true')");
+ sql("INSERT INTO T VALUES (1, 10), (2, 20)");
+ assertThat(sql("SELECT * FROM T")).containsExactlyInAnyOrder(Row.of(1,
10), Row.of(2, 20));
+ assertThatCode(() -> sql("ALTER TABLE T MODIFY v SMALLINT"))
+ .hasStackTraceContaining(
+ "Column type v[INT] cannot be converted to SMALLINT
without loosing information");
+ sql("ALTER TABLE T MODIFY v BIGINT");
+ assertThat(sql("SELECT * FROM T"))
+ .containsExactlyInAnyOrder(Row.of(1, 10L), Row.of(2, 20L));
+ assertThatCode(() -> sql("ALTER TABLE T MODIFY v INT"))
+ .hasStackTraceContaining(
+ "Column type v[BIGINT] cannot be converted to INT
without loosing information");
+ // disable explicit type casting
+ sql("ALTER TABLE T SET ('disable-explicit-type-casting' = 'false')");
+ sql("ALTER TABLE T MODIFY v INT");
+ assertThat(sql("SELECT * FROM T")).containsExactlyInAnyOrder(Row.of(1,
10), Row.of(2, 20));
+ }
}