[ES|QL] To_DatePeriod and To_TimeDuration return better error messages on union_type fields (#114934)

* better error messages with union_type fields
This commit is contained in:
Fang Xing 2024-11-11 20:33:03 -05:00 committed by GitHub
parent dd32cb6439
commit eb6d47f0f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 47 additions and 1 deletions

View file

@ -0,0 +1,6 @@
pr: 114934
summary: "[ES|QL] To_DatePeriod and To_TimeDuration return better error messages on\
\ `union_type` fields"
area: ES|QL
type: bug
issues: []

View file

@ -51,6 +51,7 @@ import org.elasticsearch.xpack.esql.expression.function.UnresolvedFunction;
import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute;
import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction;
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.AbstractConvertFunction;
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.FoldablesConvertFunction;
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToDouble;
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToInteger;
import org.elasticsearch.xpack.esql.expression.function.scalar.convert.ToLong;
@ -1226,6 +1227,16 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
if (convert.field() instanceof FieldAttribute fa && fa.field() instanceof InvalidMappedField imf) {
HashMap<TypeResolutionKey, Expression> typeResolutions = new HashMap<>();
Set<DataType> supportedTypes = convert.supportedTypes();
if (convert instanceof FoldablesConvertFunction fcf) {
// FoldablesConvertFunction does not accept fields as inputs, they only accept constants
String unresolvedMessage = "argument of ["
+ fcf.sourceText()
+ "] must be a constant, received ["
+ Expressions.name(fa)
+ "]";
Expression ua = new UnresolvedAttribute(fa.source(), fa.name(), unresolvedMessage);
return fcf.replaceChildren(Collections.singletonList(ua));
}
imf.types().forEach(type -> {
if (supportedTypes.contains(type.widenSmallNumeric())) {
TypeResolutionKey key = new TypeResolutionKey(fa.name(), type);

View file

@ -59,7 +59,8 @@ public abstract class FoldablesConvertFunction extends AbstractConvertFunction i
@Override
protected final Map<DataType, BuildFactory> factories() {
// TODO if a union type field is provided as an input, the correct error message is not shown, #112668 is a follow up
// This is used by ResolveUnionTypes, which is expected to be applied to ES fields only
// FoldablesConvertFunction takes only constants as inputs, so this is empty
return Map.of();
}

View file

@ -244,6 +244,34 @@ public class VerifierTests extends ESTestCase {
+ " [ip] in [test1, test2, test3] and [2] other indices, [keyword] in [test6]",
error("from test* | where multi_typed is not null", analyzer)
);
for (String functionName : List.of("to_timeduration", "to_dateperiod")) {
String lineNumber = functionName.equalsIgnoreCase("to_timeduration") ? "47" : "45";
String errorType = functionName.equalsIgnoreCase("to_timeduration") ? "time_duration" : "date_period";
assertEquals(
"1:" + lineNumber + ": Cannot use field [unsupported] with unsupported type [flattened]",
error("from test* | eval x = now() + " + functionName + "(unsupported)", analyzer)
);
assertEquals(
"1:" + lineNumber + ": argument of [" + functionName + "(multi_typed)] must be a constant, received [multi_typed]",
error("from test* | eval x = now() + " + functionName + "(multi_typed)", analyzer)
);
assertThat(
error("from test* | eval x = unsupported, y = now() + " + functionName + "(x)", analyzer),
containsString("1:23: Cannot use field [unsupported] with unsupported type [flattened]")
);
assertThat(
error("from test* | eval x = multi_typed, y = now() + " + functionName + "(x)", analyzer),
containsString(
"1:48: argument of ["
+ functionName
+ "(x)] must be ["
+ errorType
+ " or string], "
+ "found value [x] type [unsupported]"
)
);
}
}
public void testRoundFunctionInvalidInputs() {