Skip to content

Commit a224d1b

Browse files
committed
[FLINK-37913][table] make class field and key fields not nullable
1 parent f57c956 commit a224d1b

File tree

3 files changed

+44
-41
lines changed

3 files changed

+44
-41
lines changed

flink-table/flink-table-common/src/main/java/org/apache/flink/table/types/inference/strategies/ObjectOfInputTypeStrategy.java

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,15 @@ public Optional<Integer> getMaxCount() {
9696
}
9797
};
9898

99-
private static void validateClassInput(
100-
final CallContext callContext, final DataType firstArgumentDataType) {
99+
private static void validateClassArgument(final DataType firstArgumentDataType) {
101100
final LogicalType classArgumentType = firstArgumentDataType.getLogicalType();
102101

103102
final String errorMessage =
104-
"The first argument must be a STRING/VARCHAR type representing the class name.";
105-
if (!classArgumentType.is(LogicalTypeFamily.CHARACTER_STRING)) {
103+
"The first argument must be a non-nullable STRING/VARCHAR type representing the class name.";
104+
if (classArgumentType.isNullable()
105+
|| !classArgumentType.is(LogicalTypeFamily.CHARACTER_STRING)) {
106106
throw new ValidationException(errorMessage);
107107
}
108-
109-
final Optional<String> className = callContext.getArgumentValue(0, String.class);
110-
className.orElseThrow(() -> new ValidationException(errorMessage));
111108
}
112109

113110
private static void validateKeyArguments(
@@ -129,23 +126,25 @@ private static void validateFieldNameArgument(
129126
throw new ValidationException(
130127
"The field key at position "
131128
+ keyIndex
132-
+ " must be a STRING/VARCHAR type, but was "
129+
+ " must be a non-nullable STRING/VARCHAR type, but was "
133130
+ logicalType.asSummaryString()
134131
+ ".");
135132
}
133+
134+
if (logicalType.isNullable()) {
135+
throw new ValidationException(
136+
"The field key at position "
137+
+ keyIndex
138+
+ " must be a non-nullable STRING/VARCHAR type.");
139+
}
140+
136141
final String fieldName =
137142
callContext
138143
.getArgumentValue(idx, String.class)
139-
.orElseThrow(
140-
() ->
141-
new ValidationException(
142-
"Field name at position "
143-
+ keyIndex
144-
+ " must be a non null STRING/VARCHAR type."));
145-
144+
.orElseThrow(IllegalStateException::new);
146145
if (!fieldNames.add(fieldName)) {
147146
throw new ValidationException(
148-
"The field name " + fieldName + " at position " + keyIndex + " is repeated.");
147+
"The field name '" + fieldName + "' at position " + keyIndex + " is repeated.");
149148
}
150149
}
151150

@@ -159,7 +158,7 @@ public Optional<List<DataType>> inferInputTypes(
159158
final CallContext callContext, final boolean throwOnFailure) {
160159
final List<DataType> argumentDataTypes = callContext.getArgumentDataTypes();
161160

162-
validateClassInput(callContext, argumentDataTypes.get(0));
161+
validateClassArgument(argumentDataTypes.get(0));
163162
validateKeyArguments(callContext, argumentDataTypes);
164163

165164
return Optional.of(argumentDataTypes);

flink-table/flink-table-common/src/test/java/org/apache/flink/table/types/inference/strategies/ObjectOfInputTypeStrategyTest.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,43 +40,47 @@ protected Stream<TestSpec> testData() {
4040
return Stream.of(
4141
// Test valid OBJECT_OF with no fields and values
4242
TestSpec.forStrategy("Valid OBJECT_OF with only class", OBJECT_OF_INPUT_STRATEGY)
43-
.calledWithArgumentTypes(DataTypes.STRING())
43+
.calledWithArgumentTypes(DataTypes.STRING().notNull())
4444
.calledWithLiteralAt(0, USER_CLASS_PATH)
4545
.expectSignature("f(STRING, [STRING, ANY]*...)")
46-
.expectArgumentTypes(DataTypes.STRING()),
46+
.expectArgumentTypes(DataTypes.STRING().notNull()),
4747

4848
// Test valid number of arguments (odd number >= 1)
4949
TestSpec.forStrategy(
5050
"Valid OBJECT_OF with class and one field and value",
5151
OBJECT_OF_INPUT_STRATEGY)
5252
.calledWithArgumentTypes(
53-
DataTypes.STRING(), DataTypes.STRING(), DataTypes.INT())
53+
DataTypes.STRING().notNull(),
54+
DataTypes.STRING().notNull(),
55+
DataTypes.INT())
5456
.calledWithLiteralAt(0, USER_CLASS_PATH)
5557
.calledWithLiteralAt(1, "field1")
5658
.expectArgumentTypes(
57-
DataTypes.STRING(), DataTypes.STRING(), DataTypes.INT()),
59+
DataTypes.STRING().notNull(),
60+
DataTypes.STRING().notNull(),
61+
DataTypes.INT()),
5862

5963
// Test with structured fields
6064
TestSpec.forStrategy(
6165
"Valid OBJECT_OF with multiple fields", OBJECT_OF_INPUT_STRATEGY)
6266
.calledWithArgumentTypes(
63-
DataTypes.STRING(), // implementation class
64-
DataTypes.STRING(), // field1 name
67+
DataTypes.STRING().notNull(), // implementation class
68+
DataTypes.STRING().notNull(), // field1 name
6569
DataTypes.STRUCTURED(
6670
"c1",
6771
DataTypes.FIELD("f1", DataTypes.INT())), // field1 value
68-
DataTypes.STRING(), // field2 name
72+
DataTypes.STRING().notNull(), // field2 name
6973
DataTypes.STRUCTURED(
7074
"c2",
7175
DataTypes.FIELD("f1", DataTypes.FLOAT()))) // field2 value
7276
.calledWithLiteralAt(0, USER_CLASS_PATH)
7377
.calledWithLiteralAt(1, "field1")
7478
.calledWithLiteralAt(3, "field2")
7579
.expectArgumentTypes(
76-
DataTypes.STRING(),
77-
DataTypes.STRING(),
80+
DataTypes.STRING().notNull(),
81+
DataTypes.STRING().notNull(),
7882
DataTypes.STRUCTURED("c1", DataTypes.FIELD("f1", DataTypes.INT())),
79-
DataTypes.STRING(),
83+
DataTypes.STRING().notNull(),
8084
DataTypes.STRUCTURED(
8185
"c2", DataTypes.FIELD("f1", DataTypes.FLOAT()))),
8286

@@ -87,15 +91,15 @@ protected Stream<TestSpec> testData() {
8791
.calledWithArgumentTypes(DataTypes.NULL())
8892
.calledWithLiteralAt(0, null)
8993
.expectErrorMessage(
90-
"The first argument must be a STRING/VARCHAR type representing the class name."),
94+
"The first argument must be a non-nullable STRING/VARCHAR type representing the class name."),
9195

9296
// Invalid test case - even number of arguments
9397
TestSpec.forStrategy(
9498
"Invalid OBJECT_OF with even number of arguments",
9599
OBJECT_OF_INPUT_STRATEGY)
96100
.calledWithArgumentTypes(
97-
DataTypes.STRING(), // implementation class
98-
DataTypes.STRING()) // only field name, missing value
101+
DataTypes.STRING().notNull(), // implementation class
102+
DataTypes.STRING().notNull()) // only field name, missing value
99103
.calledWithLiteralAt(0, USER_CLASS_PATH)
100104
.expectErrorMessage("Invalid number of arguments."),
101105

@@ -112,38 +116,38 @@ protected Stream<TestSpec> testData() {
112116
.calledWithLiteralAt(0, 72)
113117
.expectArgumentTypes(DataTypes.INT())
114118
.expectErrorMessage(
115-
"The first argument must be a STRING/VARCHAR type representing the class name."),
119+
"The first argument must be a non-nullable STRING/VARCHAR type representing the class name."),
116120

117121
// Invalid test case - field name not a string
118122
TestSpec.forStrategy(
119123
"OBJECT_OF with non-string field name", OBJECT_OF_INPUT_STRATEGY)
120124
.calledWithArgumentTypes(
121-
DataTypes.STRING(), // implementation class
125+
DataTypes.STRING().notNull(), // implementation class
122126
DataTypes.INT(), // field name (not a string)
123127
DataTypes.INT()) // field value
124128
.calledWithLiteralAt(0, USER_CLASS_PATH)
125129
.calledWithLiteralAt(1, 5)
126130
.expectArgumentTypes(DataTypes.STRING(), DataTypes.INT(), DataTypes.INT())
127131
.expectErrorMessage(
128-
"The field key at position 2 must be a STRING/VARCHAR type, but was INT."),
132+
"The field key at position 2 must be a non-nullable STRING/VARCHAR type, but was INT."),
129133

130134
// Invalid test case - repeated field names
131135
TestSpec.forStrategy(
132136
"OBJECT_OF with repeated field names", OBJECT_OF_INPUT_STRATEGY)
133137
.calledWithArgumentTypes(
134-
DataTypes.STRING(),
135-
DataTypes.STRING(),
138+
DataTypes.STRING().notNull(),
139+
DataTypes.STRING().notNull(),
136140
DataTypes.INT(),
137-
DataTypes.STRING(),
141+
DataTypes.STRING().notNull(),
138142
DataTypes.INT())
139143
.calledWithLiteralAt(0, USER_CLASS_PATH)
140144
.calledWithLiteralAt(1, "field1")
141145
.calledWithLiteralAt(3, "field1")
142146
.expectArgumentTypes(
143-
DataTypes.STRING(),
144-
DataTypes.STRING(),
147+
DataTypes.STRING().notNull(),
148+
DataTypes.STRING().notNull(),
145149
DataTypes.INT(),
146-
DataTypes.STRING(),
150+
DataTypes.STRING().notNull(),
147151
DataTypes.INT())
148152
.expectErrorMessage("The field name 'field1' at position 4 is repeated."));
149153
}

flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/functions/StructuredFunctionsITCase.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,11 @@ private static Stream<TestSetSpec> objectOfTestCases() {
142142
"OBJECT_OF('"
143143
+ Type1.class.getName()
144144
+ "', CAST(NULL AS STRING), 42, 'b', 'Bob')",
145-
"Field name at position 2 must be a non null STRING/VARCHAR type.")
145+
"The field key at position 2 must be a non-nullable STRING/VARCHAR type.")
146146
// Invalid Test - first argument is type string but null
147147
.testSqlValidationError(
148148
"OBJECT_OF(CAST(NULL AS STRING), 'a', '12', 'b', 'Alice')",
149-
"The first argument must be a STRING/VARCHAR type representing the class name."));
149+
"The first argument must be a non-nullable STRING/VARCHAR type representing the class name."));
150150
}
151151

152152
// --------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)