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(