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 f47c96f171 [core] Fix nullability parsing for nested types (#9381)
f47c96f171 is described below

commit f47c96f17152c7a5b906e6ddefe87ec75c1f6910
Author: zhoulii <[email protected]>
AuthorDate: Wed Aug 26 10:25:35 2026 +0800

    [core] Fix nullability parsing for nested types (#9381)
---
 .../apache/paimon/types/DataTypeJsonParser.java    | 16 ++++++++++-----
 .../paimon/schema/DataTypeJsonParserTest.java      | 23 ++++++++++++++++++++++
 2 files changed, 34 insertions(+), 5 deletions(-)

diff --git 
a/paimon-api/src/main/java/org/apache/paimon/types/DataTypeJsonParser.java 
b/paimon-api/src/main/java/org/apache/paimon/types/DataTypeJsonParser.java
index f808114666..5076b57781 100644
--- a/paimon-api/src/main/java/org/apache/paimon/types/DataTypeJsonParser.java
+++ b/paimon-api/src/main/java/org/apache/paimon/types/DataTypeJsonParser.java
@@ -75,20 +75,21 @@ public final class DataTypeJsonParser {
             return parseAtomicTypeSQLString(json.asText());
         } else if (json.isObject()) {
             String typeString = json.get("type").asText();
+            boolean isNullable = isNullable(json, typeString);
             if (typeString.startsWith("ARRAY")) {
                 DataType element = parseDataType(json.get("element"), fieldId);
-                return new ArrayType(!typeString.contains("NOT NULL"), 
element);
+                return new ArrayType(isNullable, element);
             } else if (typeString.startsWith("VECTOR")) {
                 DataType element = parseDataType(json.get("element"), fieldId);
                 int length = json.get("length").asInt();
-                return new VectorType(!typeString.contains("NOT NULL"), 
length, element);
+                return new VectorType(isNullable, length, element);
             } else if (typeString.startsWith("MULTISET")) {
                 DataType element = parseDataType(json.get("element"), fieldId);
-                return new MultisetType(!typeString.contains("NOT NULL"), 
element);
+                return new MultisetType(isNullable, element);
             } else if (typeString.startsWith("MAP")) {
                 DataType key = parseDataType(json.get("key"), fieldId);
                 DataType value = parseDataType(json.get("value"), fieldId);
-                return new MapType(!typeString.contains("NOT NULL"), key, 
value);
+                return new MapType(isNullable, key, value);
             } else if (typeString.startsWith("ROW")) {
                 JsonNode fieldArray = json.get("fields");
                 Iterator<JsonNode> iterator = fieldArray.elements();
@@ -96,13 +97,18 @@ public final class DataTypeJsonParser {
                 while (iterator.hasNext()) {
                     fields.add(parseDataField(iterator.next(), fieldId));
                 }
-                return new RowType(!typeString.contains("NOT NULL"), fields);
+                return new RowType(isNullable, fields);
             }
         }
 
         throw new IllegalArgumentException("Can not parse: " + json);
     }
 
+    private static boolean isNullable(JsonNode json, String typeString) {
+        JsonNode nullableNode = json.get("nullable");
+        return nullableNode == null ? !typeString.endsWith(" NOT NULL") : 
nullableNode.asBoolean();
+    }
+
     public static DataType parseAtomicTypeSQLString(String string) {
         List<Token> tokens = tokenize(string);
         TokenParser converter = new TokenParser(string, tokens);
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/schema/DataTypeJsonParserTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/schema/DataTypeJsonParserTest.java
index 369010a0f2..d32765d66d 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/schema/DataTypeJsonParserTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/schema/DataTypeJsonParserTest.java
@@ -135,6 +135,9 @@ public class DataTypeJsonParserTest {
                 TestSpec.forString(
                                 "{\"type\":\"VECTOR NOT 
NULL\",\"element\":\"TINYINT NOT NULL\",\"length\":11}")
                         .expectType(DataTypes.VECTOR(11, 
DataTypes.TINYINT().notNull()).notNull()),
+                TestSpec.forString(
+                                "{\"type\":\"VECTOR<INT NOT NULL, 
5>\",\"element\":\"INT NOT NULL\",\"length\":5}")
+                        .expectType(DataTypes.VECTOR(5, 
DataTypes.INT().notNull())),
                 TestSpec.forString(
                                 
"{\"type\":\"ARRAY\",\"element\":\"TIMESTAMP(3) WITH LOCAL TIME ZONE\"}")
                         .expectType(new ArrayType(new 
LocalZonedTimestampType(3))),
@@ -146,6 +149,9 @@ public class DataTypeJsonParserTest {
                         .expectType(new ArrayType(new IntType(false))),
                 TestSpec.forString("{\"type\":\"ARRAY NOT 
NULL\",\"element\":\"INT\"}")
                         .expectType(new ArrayType(false, new IntType())),
+                TestSpec.forString(
+                                "{\"type\":\"ARRAY<INT NOT 
NULL>\",\"element\":\"INT NOT NULL\"}")
+                        .expectType(new ArrayType(new IntType(false))),
                 TestSpec.forString("{\"type\":\"MULTISET\",\"element\":\"INT 
NOT NULL\"}")
                         .expectType(new MultisetType(new IntType(false))),
                 
TestSpec.forString("{\"type\":\"MULTISET\",\"element\":\"INT\"}")
@@ -154,8 +160,19 @@ public class DataTypeJsonParserTest {
                         .expectType(new MultisetType(new IntType(false))),
                 TestSpec.forString("{\"type\":\"MULTISET NOT 
NULL\",\"element\":\"INT\"}")
                         .expectType(new MultisetType(false, new IntType())),
+                TestSpec.forString(
+                                "{\"type\":\"MULTISET<INT NOT 
NULL>\",\"element\":\"INT NOT NULL\"}")
+                        .expectType(new MultisetType(new IntType(false))),
                 
TestSpec.forString("{\"type\":\"MAP\",\"key\":\"BIGINT\",\"value\":\"BOOLEAN\"}")
                         .expectType(new MapType(new BigIntType(), new 
BooleanType())),
+                TestSpec.forString(
+                                "{\"type\":\"MAP<STRING NOT NULL, 
BLOB>\",\"key\":\"STRING NOT NULL\",\"value\":\"BLOB\",\"nullable\":true}")
+                        .expectType(
+                                new MapType(true, 
DataTypes.STRING().notNull(), new BlobType())),
+                TestSpec.forString(
+                                "{\"type\":\"MAP<STRING NOT NULL, 
BLOB>\",\"key\":\"STRING NOT NULL\",\"value\":\"BLOB\",\"nullable\":false}")
+                        .expectType(
+                                new MapType(false, 
DataTypes.STRING().notNull(), new BlobType())),
                 TestSpec.forString(
                                 
"{\"type\":\"ROW\",\"fields\":[{\"id\":0,\"name\":\"f0\",\"type\":\"INT NOT 
NULL\"},{\"id\":1,\"name\":\"f1\",\"type\":\"BOOLEAN\"}]}")
                         .expectType(
@@ -163,6 +180,12 @@ public class DataTypeJsonParserTest {
                                         Arrays.asList(
                                                 new DataField(0, "f0", new 
IntType(false)),
                                                 new DataField(1, "f1", new 
BooleanType())))),
+                TestSpec.forString(
+                                "{\"type\":\"ROW<f0 INT NOT 
NULL>\",\"fields\":[{\"id\":0,\"name\":\"f0\",\"type\":\"INT NOT NULL\"}]}")
+                        .expectType(
+                                new RowType(
+                                        Collections.singletonList(
+                                                new DataField(0, "f0", new 
IntType(false))))),
                 TestSpec.forString(
                                 
"{\"type\":\"ROW\",\"fields\":[{\"id\":0,\"name\":\"f0\",\"type\":\"INT NOT 
NULL\"},{\"id\":1,\"name\":\"f1\",\"type\":\"BOOLEAN\"}]}")
                         .expectType(

Reply via email to