Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,35 @@ still_hired:boolean | job_positions:keyword
[false, true] | Tech Lead
[false, true] | null
;

implicitCastingEqual
required_feature: esql.string_literal_auto_casting_extended
from employees | where still_hired == "true" | sort emp_no | keep emp_no | limit 1;

emp_no:integer
10001
;

implicitCastingNotEqual
required_feature: esql.string_literal_auto_casting_extended
from employees | where still_hired != "true" | sort emp_no | keep emp_no | limit 1;

emp_no:integer
10003
;

implicitCastingIn
required_feature: esql.string_literal_auto_casting_extended
from employees | where still_hired in ("true", "false") | sort emp_no | keep emp_no | limit 1;

emp_no:integer
10001
;

implicitCastingInField
required_feature: esql.string_literal_auto_casting_extended
from employees | where false in ("true", still_hired) | sort emp_no | keep emp_no | limit 1;

emp_no:integer
10003
;
Original file line number Diff line number Diff line change
Expand Up @@ -1041,3 +1041,33 @@ required_feature: esql.agg_values
[1953-04-20T00:00:00Z, 1954-05-01T00:00:00Z] | Tech Lead
[1955-01-21T00:00:00Z, 1957-05-23T00:00:00Z, 1959-12-03T00:00:00Z] | null
;

implicitCastingNotEqual
required_feature: esql.string_literal_auto_casting
from employees | where birth_date != "1957-05-23T00:00:00Z" | keep emp_no, birth_date | sort emp_no | limit 3;

emp_no:integer | birth_date:datetime
10001 | 1953-09-02T00:00:00Z
10002 | 1964-06-02T00:00:00Z
10003 | 1959-12-03T00:00:00Z
;

implicitCastingLessThanOrEqual
required_feature: esql.string_literal_auto_casting
from employees | where birth_date <= "1957-05-20T00:00:00Z" | keep emp_no, birth_date | sort emp_no | limit 3;

emp_no:integer | birth_date:datetime
10001 | 1953-09-02T00:00:00Z
10004 | 1954-05-01T00:00:00Z
10005 | 1955-01-21T00:00:00Z
;

implicitCastingGreaterThan
required_feature: esql.string_literal_auto_casting
from employees | where birth_date > "1957-05-24T00:00:00Z" | keep emp_no, birth_date | sort emp_no | limit 3;

emp_no:integer | birth_date:datetime
10002 | 1964-06-02T00:00:00Z
10003 | 1959-12-03T00:00:00Z
10008 | 1958-02-19T00:00:00Z
;
53 changes: 53 additions & 0 deletions x-pack/plugin/esql/qa/testFixtures/src/main/resources/ip.csv-spec
Original file line number Diff line number Diff line change
Expand Up @@ -432,3 +432,56 @@ required_feature: esql.agg_values
[fe80::cae2:65ff:fece:feb9, fe80::cae2:65ff:fece:fec0, fe80::cae2:65ff:fece:fec1, fe81::cae2:65ff:fece:feb9, fe82::cae2:65ff:fece:fec0] | epsilon
fe80::cae2:65ff:fece:feb9 | gamma
;

implictCastingEqual
required_feature: esql.string_literal_auto_casting_extended
from hosts | where mv_first(ip0) == "127.0.0.1" | keep host, ip0;

host:keyword | ip0:ip
alpha | 127.0.0.1
beta | 127.0.0.1
beta | 127.0.0.1
beta | 127.0.0.1
;

implictCastingNotEqual
required_feature: esql.string_literal_auto_casting_extended
from hosts | where mv_first(ip0) != "127.0.0.1" | keep host, ip0 | sort host, ip0 | limit 3;

host:keyword | ip0:ip
alpha | ::1
epsilon | [fe80::cae2:65ff:fece:feb9, fe80::cae2:65ff:fece:fec0, fe80::cae2:65ff:fece:fec1]
epsilon | [fe81::cae2:65ff:fece:feb9, fe82::cae2:65ff:fece:fec0]
;

implictCastingGreaterThan
required_feature: esql.string_literal_auto_casting_extended
from hosts | where mv_first(ip0) > "127.0.0.1" | keep host, ip0 | sort host, ip0 | limit 3;

host:keyword | ip0:ip
epsilon | [fe80::cae2:65ff:fece:feb9, fe80::cae2:65ff:fece:fec0, fe80::cae2:65ff:fece:fec1]
epsilon | [fe81::cae2:65ff:fece:feb9, fe82::cae2:65ff:fece:fec0]
gamma | fe80::cae2:65ff:fece:feb9
;

implictCastingLessThanOrEqual
required_feature: esql.string_literal_auto_casting_extended
from hosts | where mv_first(ip0) <= "127.0.0.1" | keep host, ip0 | sort host, ip0 | limit 3;

host:keyword | ip0:ip
alpha | ::1
alpha | 127.0.0.1
beta | 127.0.0.1
;

implictCastingIn
required_feature: esql.string_literal_auto_casting_extended
from hosts | where mv_first(ip0) in ( "127.0.0.1", "::1") | keep host, ip0 | sort host, ip0;

host:keyword | ip0:ip
alpha | ::1
alpha | 127.0.0.1
beta | 127.0.0.1
beta | 127.0.0.1
beta | 127.0.0.1
;
Original file line number Diff line number Diff line change
Expand Up @@ -1424,34 +1424,6 @@ number:double | abs_number:double
-1.0 | 10.0
;

arithmeticOperationWithString
required_feature: esql.string_literal_auto_casting

from employees
| eval s1 = salary + "10000", s2 = height * "2", s3 = avg_worked_seconds / "2", s4 = languages - "1"
| sort emp_no
| keep emp_no, salary, s1, height, s2, avg_worked_seconds, s3, languages, s4
| limit 2;

emp_no:integer | salary:integer | s1:integer | height:double | s2:double | avg_worked_seconds:long | s3:long | languages:integer | s4:integer
10001 | 57305 | 67305 | 2.03 | 4.06 | 268728049 | 134364024 | 2 | 1
10002 | 56371 | 66371 | 2.08 | 4.16 | 328922887 | 164461443 | 5 | 4
;

arithmeticOperationNestedWithString
required_feature: esql.string_literal_auto_casting

from employees
| eval x = languages + "1", y = x * 2
| sort emp_no
| keep emp_no, languages, x, y
| limit 2;

emp_no: integer | languages:integer | x:integer | y:integer
10001 | 2 | 3 | 6
10002 | 5 | 6 | 12
;

functionUnderArithmeticOperationAggString
required_feature: esql.string_literal_auto_casting

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,49 @@ version:version | name:keyword
null | lllll
5.2.9 | mmmmm
;

implictCastingEqual
required_feature: esql.string_literal_auto_casting_extended
from apps | where version == "1.2.3.4" | sort name | keep name, version;

name:keyword | version:version
aaaaa | 1.2.3.4
hhhhh | 1.2.3.4
;

implictCastingNotEqual
required_feature: esql.string_literal_auto_casting_extended
from apps | where version != "1.2.3.4" | sort name, version | keep name, version | limit 2;

name:keyword | version:version
aaaaa | 1
bbbbb | 2.1
;

implictCastingGreaterThan
required_feature: esql.string_literal_auto_casting_extended
from apps | where version > "1.2.3.4" | sort name, version | keep name, version | limit 2;

name:keyword | version:version
bbbbb | 2.1
ccccc | 2.3.4
;

implictCastingLessThanOrEqual
required_feature: esql.string_literal_auto_casting_extended
from apps | where version <= "1.2.3.4" | sort name, version | keep name, version | limit 2;

name:keyword | version:version
aaaaa | 1
aaaaa | 1.2.3.4
;

implictCastingIn
required_feature: esql.string_literal_auto_casting_extended
from apps | where version in ( "1.2.3.4", "bad" ) | sort name | keep name, version;

name:keyword | version:version
aaaaa | 1.2.3.4
hhhhh | 1.2.3.4
iiiii | bad
;
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.elasticsearch.xpack.esql.expression.function.UnsupportedAttribute;
import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction;
import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation;
import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.In;
import org.elasticsearch.xpack.esql.plan.logical.Drop;
import org.elasticsearch.xpack.esql.plan.logical.Enrich;
import org.elasticsearch.xpack.esql.plan.logical.EsqlAggregate;
Expand Down Expand Up @@ -96,6 +97,7 @@
import static org.elasticsearch.xpack.esql.stats.FeatureMetric.LIMIT;
import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_POINT;
import static org.elasticsearch.xpack.esql.type.EsqlDataTypes.GEO_SHAPE;
import static org.elasticsearch.xpack.ql.type.DataTypes.BOOLEAN;
import static org.elasticsearch.xpack.ql.type.DataTypes.DATETIME;
import static org.elasticsearch.xpack.ql.type.DataTypes.DOUBLE;
import static org.elasticsearch.xpack.ql.type.DataTypes.FLOAT;
Expand All @@ -105,6 +107,7 @@
import static org.elasticsearch.xpack.ql.type.DataTypes.LONG;
import static org.elasticsearch.xpack.ql.type.DataTypes.NESTED;
import static org.elasticsearch.xpack.ql.type.DataTypes.TEXT;
import static org.elasticsearch.xpack.ql.type.DataTypes.VERSION;

public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerContext> {
// marker list of attributes for plans that do not have any concrete fields to return, but have other computed columns to return
Expand Down Expand Up @@ -802,6 +805,9 @@ private static Expression cast(ScalarFunction f, EsqlFunctionRegistry registry)
if (f instanceof EsqlArithmeticOperation || f instanceof BinaryComparison) {
return processBinaryOperator((BinaryOperator) f);
}
if (f instanceof In in) {
return processIn(in);
}
return f;
}

Expand Down Expand Up @@ -846,14 +852,14 @@ private static Expression processBinaryOperator(BinaryOperator<?, ?, ?, ?> o) {

if (left.dataType() == KEYWORD
&& left.foldable()
&& (right.dataType().isNumeric() || right.dataType() == DATETIME)
&& (supportsImplicitCasting(right.dataType()))
&& ((left instanceof EsqlScalarFunction) == false)) {
targetDataType = right.dataType();
from = left;
}
if (right.dataType() == KEYWORD
&& right.foldable()
&& (left.dataType().isNumeric() || left.dataType() == DATETIME)
&& (supportsImplicitCasting(left.dataType()))
&& ((right instanceof EsqlScalarFunction) == false)) {
targetDataType = left.dataType();
from = right;
Expand All @@ -867,6 +873,33 @@ private static Expression processBinaryOperator(BinaryOperator<?, ?, ?, ?> o) {
return childrenChanged ? o.replaceChildren(newChildren) : o;
}

private static Expression processIn(In in) {
Expression left = in.value();
List<Expression> right = in.list();

if (left.resolved() == false || supportsImplicitCasting(left.dataType()) == false) {
return in;
}
List<Expression> newChildren = new ArrayList<>(right.size() + 1);
boolean childrenChanged = false;

for (Expression value : right) {
if (value.dataType() == KEYWORD && value.foldable()) {
Expression e = castStringLiteral(value, left.dataType());
newChildren.add(e);
childrenChanged = true;
} else {
newChildren.add(value);
}
}
newChildren.add(left);
return childrenChanged ? in.replaceChildren(newChildren) : in;
}

private static boolean supportsImplicitCasting(DataType type) {
return type == DATETIME || type == IP || type == VERSION || type == BOOLEAN;
}

public static Expression castStringLiteral(Expression from, DataType target) {
assert from.foldable();
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ public class EsqlFeatures implements FeatureSpecification {
*/
public static final NodeFeature METADATA_FIELDS = new NodeFeature("esql.metadata_fields");

/**
* Cast string literals to a desired data type for IN predicate and more types for BinaryComparison.
*/
public static final NodeFeature STRING_LITERAL_AUTO_CASTING_EXTENDED = new NodeFeature("esql.string_literal_auto_casting_extended");

@Override
public Set<NodeFeature> getFeatures() {
return Set.of(
Expand All @@ -132,7 +137,8 @@ public Set<NodeFeature> getFeatures() {
ST_CONTAINS_WITHIN,
ST_DISJOINT,
STRING_LITERAL_AUTO_CASTING,
METADATA_FIELDS
METADATA_FIELDS,
STRING_LITERAL_AUTO_CASTING_EXTENDED
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ public static BytesRef stringToVersion(BytesRef field) {
return new Version(field.utf8ToString()).toBytesRef();
}

public static Version stringToVersion(String field) {
return new Version(field);
public static BytesRef stringToVersion(String field) {
return new Version(field).toBytesRef();
}

public static String versionToString(BytesRef field) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,13 @@ public void testCompareIntToString() {
from test
| where emp_no COMPARISON "foo"
""".replace("COMPARISON", comparison)));
assertThat(e.getMessage(), containsString("Cannot convert string [foo] to [INTEGER]".replace("COMPARISON", comparison)));
assertThat(
e.getMessage(),
containsString(
"first argument of [emp_no COMPARISON \"foo\"] is [numeric] so second argument must also be [numeric] but was [keyword]"
.replace("COMPARISON", comparison)
)
);
}
}

Expand All @@ -1013,7 +1019,13 @@ public void testCompareStringToInt() {
from test
| where "foo" COMPARISON emp_no
""".replace("COMPARISON", comparison)));
assertThat(e.getMessage(), containsString("Cannot convert string [foo] to [INTEGER]".replace("COMPARISON", comparison)));
assertThat(
e.getMessage(),
containsString(
"first argument of [\"foo\" COMPARISON emp_no] is [keyword] so second argument must also be [keyword] but was [integer]"
.replace("COMPARISON", comparison)
)
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ public void testSumOnDate() {

public void testWrongInputParam() {
assertEquals(
"1:29: Cannot convert string [foo] to [INTEGER], error [Cannot parse number [foo]]",
"1:19: first argument of [emp_no == ?] is [numeric] so second argument must also be [numeric] but was [keyword]",
error("from test | where emp_no == ?", "foo")
);

Expand Down
Loading