diff --git a/docs/changelog/106810.yaml b/docs/changelog/106810.yaml
new file mode 100644
index 0000000000000..e93e5cf1e5361
--- /dev/null
+++ b/docs/changelog/106810.yaml
@@ -0,0 +1,5 @@
+pr: 106810
+summary: "ES|QL: Improve support for TEXT fields in functions"
+area: ES|QL
+type: bug
+issues: []
diff --git a/docs/reference/esql/functions/description/date_format.asciidoc b/docs/reference/esql/functions/description/date_format.asciidoc
new file mode 100644
index 0000000000000..ef9873bdeffe6
--- /dev/null
+++ b/docs/reference/esql/functions/description/date_format.asciidoc
@@ -0,0 +1,5 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Description*
+
+Returns a string representation of a date, in the provided format.
diff --git a/docs/reference/esql/functions/layout/date_format.asciidoc b/docs/reference/esql/functions/layout/date_format.asciidoc
new file mode 100644
index 0000000000000..1f9199afc812c
--- /dev/null
+++ b/docs/reference/esql/functions/layout/date_format.asciidoc
@@ -0,0 +1,14 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+[discrete]
+[[esql-date_format]]
+=== `DATE_FORMAT`
+
+*Syntax*
+
+[.text-center]
+image::esql/functions/signature/date_format.svg[Embedded,opts=inline]
+
+include::../parameters/date_format.asciidoc[]
+include::../description/date_format.asciidoc[]
+include::../types/date_format.asciidoc[]
diff --git a/docs/reference/esql/functions/parameters/date_format.asciidoc b/docs/reference/esql/functions/parameters/date_format.asciidoc
new file mode 100644
index 0000000000000..7b000418b961c
--- /dev/null
+++ b/docs/reference/esql/functions/parameters/date_format.asciidoc
@@ -0,0 +1,7 @@
+*Parameters*
+
+`dateFormat`::
+A valid date pattern
+
+`date`::
+Date expression
diff --git a/docs/reference/esql/functions/signature/date_format.svg b/docs/reference/esql/functions/signature/date_format.svg
new file mode 100644
index 0000000000000..961fcff51d42b
--- /dev/null
+++ b/docs/reference/esql/functions/signature/date_format.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/reference/esql/functions/types/date_extract.asciidoc b/docs/reference/esql/functions/types/date_extract.asciidoc
index 08bc0f6b51357..43702ef0671a7 100644
--- a/docs/reference/esql/functions/types/date_extract.asciidoc
+++ b/docs/reference/esql/functions/types/date_extract.asciidoc
@@ -6,4 +6,5 @@
|===
datePart | date | result
keyword | datetime | long
+text | datetime | long
|===
diff --git a/docs/reference/esql/functions/types/date_format.asciidoc b/docs/reference/esql/functions/types/date_format.asciidoc
new file mode 100644
index 0000000000000..a76f38653b9b8
--- /dev/null
+++ b/docs/reference/esql/functions/types/date_format.asciidoc
@@ -0,0 +1,10 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Supported types*
+
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+dateFormat | date | result
+keyword | datetime | keyword
+text | datetime | keyword
+|===
diff --git a/docs/reference/esql/functions/types/date_parse.asciidoc b/docs/reference/esql/functions/types/date_parse.asciidoc
index 0d9e4b30c7c7b..82ae8253baa26 100644
--- a/docs/reference/esql/functions/types/date_parse.asciidoc
+++ b/docs/reference/esql/functions/types/date_parse.asciidoc
@@ -7,4 +7,5 @@
datePattern | dateString | result
keyword | keyword | datetime
keyword | text | datetime
+text | text | datetime
|===
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec
index cd94ae793516e..7d1617b208f34 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec
@@ -12,7 +12,7 @@ auto_bucket |"double|date auto_bucket(field:integer|long|double|dat
avg |"double avg(number:double|integer|long)" |number |"double|integer|long" | "" |double | "The average of a numeric field." | false | false | true
case |"boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version case(condition:boolean, trueValue...:boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version)" |[condition, trueValue] |["boolean", "boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version"] |["", ""] |"boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version" | "Accepts pairs of conditions and values. The function returns the value that belongs to the first condition that evaluates to true." | [false, false] | true | false
ceil |"double|integer|long|unsigned_long ceil(number:double|integer|long|unsigned_long)" |number |"double|integer|long|unsigned_long" | "Numeric expression. If `null`, the function returns `null`." | "double|integer|long|unsigned_long" | "Round a number up to the nearest integer." | false | false | false
-cidr_match |boolean cidr_match(ip:ip, blockX...:keyword) |[ip, blockX] |[ip, keyword] |["", "CIDR block to test the IP against."] |boolean | "Returns true if the provided IP is contained in one of the provided CIDR blocks." | [false, false] | true | false
+cidr_match |"boolean cidr_match(ip:ip, blockX...:keyword|text)" |[ip, blockX] |[ip, "keyword|text"] |["", "CIDR block to test the IP against."] |boolean | "Returns true if the provided IP is contained in one of the provided CIDR blocks." | [false, false] | true | false
coalesce |"boolean|text|integer|keyword|long coalesce(first:boolean|text|integer|keyword|long, ?rest...:boolean|text|integer|keyword|long)" |first | "boolean|text|integer|keyword|long" | "Expression to evaluate" |"boolean|text|integer|keyword|long" | "Returns the first of its arguments that is not null. If all arguments are null, it returns `null`." | false | true | false
concat |"keyword concat(string1:keyword|text, string2...:keyword|text)" |[string1, string2] |["keyword|text", "keyword|text"] |["", ""] |keyword | "Concatenates two or more strings." | [false, false] | true | false
cos |"double cos(number:double|integer|long|unsigned_long)" |number |"double|integer|long|unsigned_long" | "An angle, in radians" |double | "Returns the trigonometric cosine of an angle" | false | false | false
@@ -20,10 +20,10 @@ cosh |"double cosh(number:double|integer|long|unsigned_long)
count |"long count(?field:boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version)" |field |"boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version" | "Column or literal for which to count the number of values." |long | "Returns the total number (count) of input values." | true | false | true
count_distinct |"long count_distinct(field:boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|version, ?precision:integer)" |[field, precision] |["boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|version, integer"] |["Column or literal for which to count the number of distinct values.", ""] |long | "Returns the approximate number of distinct values." | [false, true] | false | true
date_diff |"integer date_diff(unit:keyword|text, startTimestamp:date, endTimestamp:date)"|[unit, startTimestamp, endTimestamp] |["keyword|text", "date", "date"] |["A valid date unit", "A string representing a start timestamp", "A string representing an end timestamp"] |integer | "Subtract 2 dates and return their difference in multiples of a unit specified in the 1st argument" | [false, false, false] | false | false
-date_extract |long date_extract(datePart:keyword, date:date) |[datePart, date] |[keyword, date] |["Part of the date to extract. Can be: aligned_day_of_week_in_month; aligned_day_of_week_in_year; aligned_week_of_month; aligned_week_of_year; ampm_of_day; clock_hour_of_ampm; clock_hour_of_day; day_of_month; day_of_week; day_of_year; epoch_day; era; hour_of_ampm; hour_of_day; instant_seconds; micro_of_day; micro_of_second; milli_of_day; milli_of_second; minute_of_day; minute_of_hour; month_of_year; nano_of_day; nano_of_second; offset_seconds; proleptic_month; second_of_day; second_of_minute; year; or year_of_era.", "Date expression"] |long | "Extracts parts of a date, like year, month, day, hour." | [false, false] | false | false
-date_format |keyword date_format(?dateFormat:keyword, date:date) |[dateFormat, date] |[keyword, date] |["A valid date pattern", "Date expression"] |keyword | "Returns a string representation of a date, in the provided format." | [true, false] | false | false
-date_parse |"date date_parse(?datePattern:keyword, dateString:keyword|text)"|[datePattern, dateString]|["keyword", "keyword|text"]|["A valid date pattern", "A string representing a date"]|date |Parses a string into a date value | [true, false] | false | false
-date_trunc |"date date_trunc(interval:keyword, date:date)" |[interval, date] |[keyword, date] |["Interval; expressed using the timespan literal syntax.", "Date expression"] |date | "Rounds down a date to the closest interval." | [false, false] | false | false
+date_extract |"long date_extract(datePart:keyword|text, date:date)" |[datePart, date] |["keyword|text", date] |["Part of the date to extract. Can be: aligned_day_of_week_in_month; aligned_day_of_week_in_year; aligned_week_of_month; aligned_week_of_year; ampm_of_day; clock_hour_of_ampm; clock_hour_of_day; day_of_month; day_of_week; day_of_year; epoch_day; era; hour_of_ampm; hour_of_day; instant_seconds; micro_of_day; micro_of_second; milli_of_day; milli_of_second; minute_of_day; minute_of_hour; month_of_year; nano_of_day; nano_of_second; offset_seconds; proleptic_month; second_of_day; second_of_minute; year; or year_of_era.", "Date expression"] |long | "Extracts parts of a date, like year, month, day, hour." | [false, false] | false | false
+date_format |"keyword date_format(?dateFormat:keyword|text, date:date)" |[dateFormat, date] |["keyword|text", date] |["A valid date pattern", "Date expression"] |keyword | "Returns a string representation of a date, in the provided format." | [true, false] | false | false
+date_parse |"date date_parse(?datePattern:keyword|text, dateString:keyword|text)"|[datePattern, dateString]|["keyword|text", "keyword|text"]|["A valid date pattern", "A string representing a date"]|date |Parses a string into a date value | [true, false] | false | false
+date_trunc |"date date_trunc(interval:keyword, date:date)" |[interval, date] |["keyword", date] |["Interval; expressed using the timespan literal syntax.", "Date expression"] |date | "Rounds down a date to the closest interval." | [false, false] | false | false
e |double e() | null | null | null |double | "Euler’s number." | null | false | false
ends_with |"boolean ends_with(str:keyword|text, suffix:keyword|text)" |[str, suffix] |["keyword|text", "keyword|text"] |["", ""] |boolean | "Returns a boolean that indicates whether a keyword string ends with another string" | [false, false] | false | false
floor |"double|integer|long|unsigned_long floor(number:double|integer|long|unsigned_long)" |number |"double|integer|long|unsigned_long" | "" |"double|integer|long|unsigned_long" | "Round a number down to the nearest integer." | false | false | false
@@ -116,7 +116,7 @@ synopsis:keyword
"double avg(number:double|integer|long)"
"boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version case(condition:boolean, trueValue...:boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version)"
"double|integer|long|unsigned_long ceil(number:double|integer|long|unsigned_long)"
-boolean cidr_match(ip:ip, blockX...:keyword)
+"boolean cidr_match(ip:ip, blockX...:keyword|text)"
"boolean|text|integer|keyword|long coalesce(first:boolean|text|integer|keyword|long, ?rest...:boolean|text|integer|keyword|long)"
"keyword concat(string1:keyword|text, string2...:keyword|text)"
"double cos(number:double|integer|long|unsigned_long)"
@@ -124,9 +124,9 @@ boolean cidr_match(ip:ip, blockX...:keyword)
"long count(?field:boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version)"
"long count_distinct(field:boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|version, ?precision:integer)"
"integer date_diff(unit:keyword|text, startTimestamp:date, endTimestamp:date)"
-long date_extract(datePart:keyword, date:date)
-keyword date_format(?dateFormat:keyword, date:date)
-"date date_parse(?datePattern:keyword, dateString:keyword|text)"
+"long date_extract(datePart:keyword|text, date:date)"
+"keyword date_format(?dateFormat:keyword|text, date:date)"
+"date date_parse(?datePattern:keyword|text, dateString:keyword|text)"
"date date_trunc(interval:keyword, date:date)"
double e()
"boolean ends_with(str:keyword|text, suffix:keyword|text)"
diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec
index 06fca2682bbb9..d9c9e535c2c45 100644
--- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec
+++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec
@@ -1160,3 +1160,11 @@ required_feature: esql.agg_values
null | null
// end::values-grouped-result[]
;
+
+
+splitBasedOnField
+from employees | where emp_no == 10001 | eval split = split("fooMbar", gender) | keep gender, split;
+
+gender:keyword | split:keyword
+M | [foo, bar]
+;
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java
index 0379f1a5d3614..85d5357d7c1ef 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/EsqlTypeResolutions.java
@@ -27,6 +27,15 @@
public class EsqlTypeResolutions {
+ public static Expression.TypeResolution isStringAndExact(Expression e, String operationName, TypeResolutions.ParamOrdinal paramOrd) {
+ Expression.TypeResolution resolution = TypeResolutions.isString(e, operationName, paramOrd);
+ if (resolution.unresolved()) {
+ return resolution;
+ }
+
+ return isExact(e, operationName, paramOrd);
+ }
+
public static Expression.TypeResolution isExact(Expression e, String operationName, TypeResolutions.ParamOrdinal paramOrd) {
if (e instanceof FieldAttribute fa) {
if (DataTypes.isString(fa.dataType())) {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtract.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtract.java
index 4f31f73963569..544f284791919 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtract.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtract.java
@@ -14,6 +14,7 @@
import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
import org.elasticsearch.xpack.esql.expression.function.Param;
import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlConfigurationFunction;
+import org.elasticsearch.xpack.esql.type.EsqlDataTypes;
import org.elasticsearch.xpack.ql.InvalidArgumentException;
import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.expression.TypeResolutions;
@@ -28,10 +29,10 @@
import java.util.List;
import java.util.function.Function;
+import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact;
import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.EsqlConverter.STRING_TO_CHRONO_FIELD;
import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.chronoToLong;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isDate;
-import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isStringAndExact;
public class DateExtract extends EsqlConfigurationFunction {
@@ -42,7 +43,7 @@ public DateExtract(
Source source,
// Need to replace the commas in the description here with semi-colon as there's a bug in the CSV parser
// used in the CSVTests and fixing it is not trivial
- @Param(name = "datePart", type = { "keyword" }, description = """
+ @Param(name = "datePart", type = { "keyword", "text" }, description = """
Part of the date to extract.
Can be: aligned_day_of_week_in_month; aligned_day_of_week_in_year; aligned_week_of_month;
aligned_week_of_year; ampm_of_day; clock_hour_of_ampm; clock_hour_of_day; day_of_month; day_of_week;
@@ -76,7 +77,7 @@ private ChronoField chronoField() {
if (chronoField == null) {
Expression field = children().get(0);
try {
- if (field.foldable() && field.dataType() == DataTypes.KEYWORD) {
+ if (field.foldable() && EsqlDataTypes.isString(field.dataType())) {
chronoField = (ChronoField) STRING_TO_CHRONO_FIELD.convert(field.fold());
}
} catch (Exception e) {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormat.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormat.java
index 85e8a0f3aec47..6a6e523f81974 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormat.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateFormat.java
@@ -16,6 +16,7 @@
import org.elasticsearch.xpack.esql.expression.function.Param;
import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlConfigurationFunction;
import org.elasticsearch.xpack.esql.session.EsqlConfiguration;
+import org.elasticsearch.xpack.esql.type.EsqlDataTypes;
import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.expression.function.OptionalArgument;
import org.elasticsearch.xpack.ql.session.Configuration;
@@ -28,12 +29,12 @@
import java.util.Locale;
import java.util.function.Function;
+import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact;
import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.DEFAULT_DATE_TIME_FORMATTER;
import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToString;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isDate;
-import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isStringAndExact;
public class DateFormat extends EsqlConfigurationFunction implements OptionalArgument {
@@ -43,7 +44,7 @@ public class DateFormat extends EsqlConfigurationFunction implements OptionalArg
@FunctionInfo(returnType = "keyword", description = "Returns a string representation of a date, in the provided format.")
public DateFormat(
Source source,
- @Param(optional = true, name = "dateFormat", type = { "keyword" }, description = "A valid date pattern") Expression format,
+ @Param(optional = true, name = "dateFormat", type = { "keyword", "text" }, description = "A valid date pattern") Expression format,
@Param(name = "date", type = { "date" }, description = "Date expression") Expression date,
Configuration configuration
) {
@@ -96,23 +97,17 @@ static BytesRef process(long val, BytesRef formatter, @Fixed Locale locale) {
public ExpressionEvaluator.Factory toEvaluator(Function toEvaluator) {
var fieldEvaluator = toEvaluator.apply(field);
if (format == null) {
- return dvrCtx -> new DateFormatConstantEvaluator(source(), fieldEvaluator.get(dvrCtx), DEFAULT_DATE_TIME_FORMATTER, dvrCtx);
+ return new DateFormatConstantEvaluator.Factory(source(), fieldEvaluator, DEFAULT_DATE_TIME_FORMATTER);
}
- if (format.dataType() != DataTypes.KEYWORD) {
+ if (EsqlDataTypes.isString(format.dataType()) == false) {
throw new IllegalArgumentException("unsupported data type for format [" + format.dataType() + "]");
}
if (format.foldable()) {
DateFormatter formatter = toFormatter(format.fold(), ((EsqlConfiguration) configuration()).locale());
- return dvrCtx -> new DateFormatConstantEvaluator(source(), fieldEvaluator.get(dvrCtx), formatter, dvrCtx);
+ return new DateFormatConstantEvaluator.Factory(source(), fieldEvaluator, formatter);
}
var formatEvaluator = toEvaluator.apply(format);
- return dvrCtx -> new DateFormatEvaluator(
- source(),
- fieldEvaluator.get(dvrCtx),
- formatEvaluator.get(dvrCtx),
- ((EsqlConfiguration) configuration()).locale(),
- dvrCtx
- );
+ return new DateFormatEvaluator.Factory(source(), fieldEvaluator, formatEvaluator, ((EsqlConfiguration) configuration()).locale());
}
private static DateFormatter toFormatter(Object format, Locale locale) {
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParse.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParse.java
index 0bb9a5dde1959..b356dbccbeb4c 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParse.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateParse.java
@@ -15,6 +15,7 @@
import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
import org.elasticsearch.xpack.esql.expression.function.Param;
import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction;
+import org.elasticsearch.xpack.esql.type.EsqlDataTypes;
import org.elasticsearch.xpack.ql.InvalidArgumentException;
import org.elasticsearch.xpack.ql.expression.Expression;
import org.elasticsearch.xpack.ql.expression.function.OptionalArgument;
@@ -28,12 +29,12 @@
import java.util.function.Function;
import static org.elasticsearch.common.time.DateFormatter.forPattern;
+import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact;
import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.DEFAULT_DATE_TIME_FORMATTER;
import static org.elasticsearch.xpack.esql.type.EsqlDataTypeConverter.dateTimeToLong;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString;
-import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isStringAndExact;
import static org.elasticsearch.xpack.ql.util.DateUtils.UTC;
public class DateParse extends EsqlScalarFunction implements OptionalArgument {
@@ -44,7 +45,7 @@ public class DateParse extends EsqlScalarFunction implements OptionalArgument {
@FunctionInfo(returnType = "date", description = "Parses a string into a date value")
public DateParse(
Source source,
- @Param(name = "datePattern", type = { "keyword" }, description = "A valid date pattern", optional = true) Expression first,
+ @Param(name = "datePattern", type = { "keyword", "text" }, description = "A valid date pattern", optional = true) Expression first,
@Param(name = "dateString", type = { "keyword", "text" }, description = "A string representing a date") Expression second
) {
super(source, second != null ? List.of(first, second) : List.of(first));
@@ -99,7 +100,7 @@ public ExpressionEvaluator.Factory toEvaluator(Function matches
+ @Param(name = "blockX", type = { "keyword", "text" }, description = "CIDR block to test the IP against.") List matches
) {
super(source, CollectionUtils.combine(singletonList(ipField), matches));
this.ipField = ipField;
@@ -76,11 +76,10 @@ public boolean foldable() {
@Override
public ExpressionEvaluator.Factory toEvaluator(Function toEvaluator) {
var ipEvaluatorSupplier = toEvaluator.apply(ipField);
- return dvrCtx -> new CIDRMatchEvaluator(
+ return new CIDRMatchEvaluator.Factory(
source(),
- ipEvaluatorSupplier.get(dvrCtx),
- matches.stream().map(x -> toEvaluator.apply(x).get(dvrCtx)).toArray(EvalOperator.ExpressionEvaluator[]::new),
- dvrCtx
+ ipEvaluatorSupplier,
+ matches.stream().map(x -> toEvaluator.apply(x)).toArray(EvalOperator.ExpressionEvaluator.Factory[]::new)
);
}
diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Split.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Split.java
index 4ecc7fa1a96a7..611fc9947d3db 100644
--- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Split.java
+++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/Split.java
@@ -25,10 +25,9 @@
import java.util.function.Function;
+import static org.elasticsearch.xpack.esql.expression.EsqlTypeResolutions.isStringAndExact;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.FIRST;
import static org.elasticsearch.xpack.ql.expression.TypeResolutions.ParamOrdinal.SECOND;
-import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString;
-import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isStringAndExact;
/**
* Splits a string on some delimiter into a multivalued string field.
@@ -59,7 +58,7 @@ protected TypeResolution resolveType() {
return resolution;
}
- return isString(right(), sourceText(), SECOND);
+ return isStringAndExact(right(), sourceText(), SECOND);
}
@Override
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java
index 755e5fcf25b9b..78c1c57e07782 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java
@@ -896,6 +896,7 @@ protected static String typeErrorMessage(boolean includeOrdinal, List validTypes) {
if (withoutNull.equals(List.of(DataTypes.DATETIME))) {
return "datetime";
}
+ if (withoutNull.equals(List.of(DataTypes.IP))) {
+ return "ip";
+ }
List negations = Stream.concat(Stream.of(numerics()), Stream.of(EsqlDataTypes.DATE_PERIOD, EsqlDataTypes.TIME_DURATION))
.sorted(Comparator.comparing(DataType::name))
.toList();
diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractTests.java
index 3a6a5d8eabae3..1e2c24062b07a 100644
--- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractTests.java
+++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DateExtractTests.java
@@ -53,6 +53,18 @@ public static Iterable