Skip to content

Commit 6028380

Browse files
committed
[FLINK-37913][table] Validate first argumante for null
1 parent ea8d655 commit 6028380

File tree

3 files changed

+39
-9
lines changed

3 files changed

+39
-9
lines changed

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,21 @@ public Optional<Integer> getMaxCount() {
9090
}
9191
};
9292

93-
private static void validateFieldName(
93+
private static void validateClassInput(
94+
final CallContext callContext, final List<DataType> argumentDataTypes) {
95+
final LogicalType classArgumentType = argumentDataTypes.get(0).getLogicalType();
96+
97+
final String errorMessage =
98+
"The first argument must be a STRING/VARCHAR type representing the class name.";
99+
if (!classArgumentType.is(LogicalTypeFamily.CHARACTER_STRING)) {
100+
throw new ValidationException(errorMessage);
101+
}
102+
103+
final Optional<String> className = callContext.getArgumentValue(0, String.class);
104+
className.orElseThrow(() -> new ValidationException(errorMessage));
105+
}
106+
107+
private static void validateFieldNameInput(
94108
final CallContext callContext,
95109
final int idx,
96110
final LogicalType logicalType,
@@ -127,17 +141,12 @@ public ArgumentCount getArgumentCount() {
127141
public Optional<List<DataType>> inferInputTypes(
128142
final CallContext callContext, final boolean throwOnFailure) {
129143
final List<DataType> argumentDataTypes = callContext.getArgumentDataTypes();
130-
final LogicalType classTypeArgument = argumentDataTypes.get(0).getLogicalType();
131-
132-
if (!classTypeArgument.is(LogicalTypeFamily.CHARACTER_STRING)) {
133-
throw new ValidationException(
134-
"The first argument must be a STRING/VARCHAR type representing the class name.");
135-
}
144+
validateClassInput(callContext, argumentDataTypes);
136145

137146
final Set<String> fieldNames = new HashSet<>();
138147
for (int i = 1; i < argumentDataTypes.size(); i += 2) {
139148
final LogicalType fieldNameLogicalType = argumentDataTypes.get(i).getLogicalType();
140-
validateFieldName(callContext, i, fieldNameLogicalType, fieldNames);
149+
validateFieldNameInput(callContext, i, fieldNameLogicalType, fieldNames);
141150
}
142151

143152
return Optional.of(argumentDataTypes);

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ class ObjectOfInputTypeStrategyTest extends InputTypeStrategiesTestBase {
3333
BuiltInFunctionDefinitions.OBJECT_OF
3434
.getTypeInference(new DataTypeFactoryMock())
3535
.getInputTypeStrategy();
36+
private static final String USER_CLASS_PATH = "com.example.User";
3637

3738
@Override
3839
protected Stream<TestSpec> testData() {
3940
return Stream.of(
4041
TestSpec.forStrategy("Valid OBJECT_OF with class", OBJECT_OF_INPUT_STRATEGY)
4142
.calledWithArgumentTypes(DataTypes.STRING()) // field value
43+
.calledWithLiteralAt(0, USER_CLASS_PATH)
4244
.expectSignature("f(STRING, [STRING, ANY]*...)")
4345
.expectArgumentTypes(DataTypes.STRING()),
4446
// Basic test case - valid number of arguments (odd number >= 1)
@@ -49,6 +51,7 @@ protected Stream<TestSpec> testData() {
4951
DataTypes.STRING(), // implementation class type
5052
DataTypes.STRING(), // field name
5153
DataTypes.INT()) // field value
54+
.calledWithLiteralAt(0, USER_CLASS_PATH)
5255
.expectArgumentTypes(
5356
DataTypes.STRING(), DataTypes.STRING(), DataTypes.INT()),
5457

@@ -65,6 +68,7 @@ protected Stream<TestSpec> testData() {
6568
DataTypes.STRUCTURED(
6669
"c2",
6770
DataTypes.FIELD("f1", DataTypes.FLOAT()))) // field2 value
71+
.calledWithLiteralAt(0, USER_CLASS_PATH)
6872
.expectArgumentTypes(
6973
DataTypes.STRING(),
7074
DataTypes.STRING(),
@@ -73,13 +77,23 @@ protected Stream<TestSpec> testData() {
7377
DataTypes.STRUCTURED(
7478
"c2", DataTypes.FIELD("f1", DataTypes.FLOAT()))),
7579

80+
// Invalid test case - first argument is null
81+
TestSpec.forStrategy(
82+
"Invalid OBJECT_OF with first argument as null",
83+
OBJECT_OF_INPUT_STRATEGY)
84+
.calledWithArgumentTypes(DataTypes.NULL())
85+
.calledWithLiteralAt(0, null)
86+
.expectErrorMessage(
87+
"The first argument must be a STRING/VARCHAR type representing the class name."),
88+
7689
// Invalid test case - even number of arguments
7790
TestSpec.forStrategy(
7891
"Invalid OBJECT_OF with even number of arguments",
7992
OBJECT_OF_INPUT_STRATEGY)
8093
.calledWithArgumentTypes(
8194
DataTypes.STRING(), // implementation class
8295
DataTypes.STRING()) // only field name, missing value
96+
.calledWithLiteralAt(0, USER_CLASS_PATH)
8397
.expectErrorMessage("Invalid number of arguments."),
8498

8599
// Invalid test case - no arguments
@@ -92,6 +106,7 @@ protected Stream<TestSpec> testData() {
92106
TestSpec.forStrategy(
93107
"OBJECT_OF with non-string class name", OBJECT_OF_INPUT_STRATEGY)
94108
.calledWithArgumentTypes(DataTypes.INT())
109+
.calledWithLiteralAt(0, 72)
95110
.expectArgumentTypes(DataTypes.INT())
96111
.expectErrorMessage(
97112
"The first argument must be a STRING/VARCHAR type representing the class name."),
@@ -103,6 +118,7 @@ protected Stream<TestSpec> testData() {
103118
DataTypes.STRING(), // implementation class
104119
DataTypes.INT(), // field name (not a string)
105120
DataTypes.INT()) // field value
121+
.calledWithLiteralAt(0, USER_CLASS_PATH)
106122
.calledWithLiteralAt(1, 5)
107123
.expectArgumentTypes(DataTypes.STRING(), DataTypes.INT(), DataTypes.INT())
108124
.expectErrorMessage(
@@ -117,6 +133,7 @@ protected Stream<TestSpec> testData() {
117133
DataTypes.INT(),
118134
DataTypes.STRING(),
119135
DataTypes.INT())
136+
.calledWithLiteralAt(0, USER_CLASS_PATH)
120137
.calledWithLiteralAt(1, "field1")
121138
.calledWithLiteralAt(3, "field1")
122139
.expectArgumentTypes(

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,11 @@ private static Stream<TestSetSpec> objectOfTestCases() {
138138
+ Type1.class.getName()
139139
+ "', 'a', 42, 'b', 'Bob'))",
140140
Type1.TYPE,
141-
DataTypes.STRING()));
141+
DataTypes.STRING())
142+
// Invalid Test - first argument is type string but null
143+
.testSqlValidationError(
144+
"OBJECT_OF(cast(null as string), 'a', '12', 'b', 'Alice')",
145+
"The first argument must be a STRING/VARCHAR type representing the class name."));
142146
}
143147

144148
// --------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)