-
Notifications
You must be signed in to change notification settings - Fork 25.2k
SQL: Fix incorrect parameter resolution #63710
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
620d8b4
40254dc
4d0568e
db8ad10
03e9a75
7ae10b2
b61461d
94d734d
c205e9d
f2e46de
2cefcc6
fa1d31c
ecd3087
541b4c9
6bb184d
9cd3dc0
09cfe08
f7fead3
bee8a7d
62a2f90
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
|
||
import org.elasticsearch.test.ESTestCase; | ||
import org.elasticsearch.xpack.ql.tree.Source; | ||
import org.elasticsearch.xpack.ql.type.DataTypes; | ||
|
||
import java.util.Collection; | ||
import java.util.LinkedHashMap; | ||
|
@@ -37,6 +38,47 @@ private static AttributeMap<String> threeMap() { | |
return new AttributeMap<>(map); | ||
} | ||
|
||
public void testAttributeMapWithSameAliasesCanResolveAttributes() { | ||
Alias param1 = createIntParameterAlias(1, 100); | ||
Alias param2 = createIntParameterAlias(2, 100); | ||
assertTrue(param1.equals(param2)); | ||
assertTrue(param1.semanticEquals(param2)); | ||
// equality on literals | ||
assertTrue(param1.child().equals(param2.child())); | ||
assertTrue(param1.child().semanticEquals(param2.child())); | ||
assertTrue(param1.toAttribute().equals(param2.toAttribute())); | ||
assertFalse(param1.toAttribute().semanticEquals(param2.toAttribute())); | ||
|
||
Map<Attribute, Expression> collectRefs = new LinkedHashMap<>(); | ||
for (Alias a : List.of(param1, param2)) { | ||
collectRefs.put(a.toAttribute(), a.child()); | ||
} | ||
// we can look up the same item by both attributes | ||
assertNotNull(collectRefs.get(param1.toAttribute())); | ||
assertNotNull(collectRefs.get(param2.toAttribute())); | ||
AttributeMap<Expression> attributeMap = new AttributeMap<>(collectRefs); | ||
|
||
// validate that all Alias can be e | ||
assertTrue(attributeMap.containsKey(param1.toAttribute())); | ||
assertFalse(attributeMap.containsKey(param2.toAttribute())); // results in unknown attribute exception | ||
|
||
AttributeMap.Builder<Expression> mapBuilder = AttributeMap.builder(); | ||
for (Alias a : List.of(param1, param2)) { | ||
mapBuilder.put(a.toAttribute(), a.child()); | ||
} | ||
AttributeMap<Expression> newAttributeMap = mapBuilder.build(); | ||
|
||
assertTrue(newAttributeMap.containsKey(param1.toAttribute())); | ||
assertTrue(newAttributeMap.containsKey(param2.toAttribute())); // no more unknown attribute exception | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe also check the returned values with get() from the map, can be done in the next PR though. |
||
} | ||
|
||
private Alias createIntParameterAlias(int index, int value) { | ||
Source source = new Source(1, index * 5, "?"); | ||
Literal literal = new Literal(source, value, DataTypes.INTEGER); | ||
Alias alias = new Alias(literal.source(), literal.source().text(), literal); | ||
return alias; | ||
} | ||
|
||
public void testEmptyConstructor() { | ||
AttributeMap<Object> m = new AttributeMap<>(); | ||
assertThat(m.size(), is(0)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,12 @@ SELECT salary, first_name, salary AS x, salary y FROM test_emp ORDER BY y LIMIT | |
|
||
constantWithLimit | ||
SELECT 3 FROM "test_emp" LIMIT 5; | ||
sameConstantsWithLimit | ||
SELECT 3, 3, 5 FROM "test_emp" LIMIT 5; | ||
Comment on lines
+51
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Work adding a few more variations here: |
||
sameConstantsWithLimitV2 | ||
SELECT 5, 3, 3 FROM "test_emp" LIMIT 5; | ||
sameConstantsWithLimitV3 | ||
SELECT 3, 5, 3, 3 FROM "test_emp" LIMIT 5; | ||
constantAndColumnWithLimit | ||
SELECT 3, first_name, last_name FROM "test_emp" ORDER BY emp_no LIMIT 5; | ||
constantComparisonWithLimit | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.sql.parser; | ||
|
||
import org.elasticsearch.test.ESTestCase; | ||
import org.elasticsearch.xpack.ql.expression.Literal; | ||
import org.elasticsearch.xpack.ql.expression.NamedExpression; | ||
import org.elasticsearch.xpack.ql.expression.UnresolvedAlias; | ||
import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.LessThan; | ||
import org.elasticsearch.xpack.ql.plan.logical.Filter; | ||
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; | ||
import org.elasticsearch.xpack.ql.plan.logical.Project; | ||
import org.elasticsearch.xpack.sql.proto.SqlTypedParamValue; | ||
|
||
import java.util.List; | ||
|
||
import static org.elasticsearch.xpack.ql.type.DateUtils.UTC; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.hamcrest.Matchers.everyItem; | ||
import static org.hamcrest.Matchers.instanceOf; | ||
import static org.hamcrest.Matchers.startsWith; | ||
|
||
public class ParamLiteralTests extends ESTestCase { | ||
|
||
private final SqlParser parser = new SqlParser(); | ||
|
||
private LogicalPlan parse(String sql, SqlTypedParamValue... parameters) { | ||
return parser.createStatement(sql, List.of(parameters), UTC); | ||
} | ||
|
||
public void testMultipleParamLiteralsWithUnresolvedAliases() { | ||
LogicalPlan logicalPlan = parse("SELECT ?, ? FROM test", | ||
new SqlTypedParamValue("integer", 100), | ||
new SqlTypedParamValue("integer", 200) | ||
); | ||
List<? extends NamedExpression> projections = ((Project) logicalPlan.children().get(0)).projections(); | ||
assertThat(projections, everyItem(instanceOf(UnresolvedAlias.class))); | ||
assertThat(projections.get(0).toString(), startsWith("100 AS ?")); | ||
assertThat(projections.get(1).toString(), startsWith("200 AS ?")); | ||
} | ||
|
||
public void testMultipleParamLiteralsWithUnresolvedAliasesAndWhereClause() { | ||
LogicalPlan logicalPlan = parse("SELECT ?, ?, (?) FROM test WHERE 1 < ?", | ||
new SqlTypedParamValue("integer", 100), | ||
new SqlTypedParamValue("integer", 100), | ||
new SqlTypedParamValue("integer", 200), | ||
new SqlTypedParamValue("integer", 300) | ||
); | ||
Project project = (Project) logicalPlan.children().get(0); | ||
List<? extends NamedExpression> projections = project.projections(); | ||
assertThat(projections, everyItem(instanceOf(UnresolvedAlias.class))); | ||
assertThat(projections.get(0).toString(), startsWith("100 AS ?")); | ||
assertThat(projections.get(1).toString(), startsWith("100 AS ?")); | ||
assertThat(projections.get(2).toString(), startsWith("200 AS ?")); | ||
assertThat(project.children().get(0), instanceOf(Filter.class)); | ||
Filter filter = (Filter) project.children().get(0); | ||
assertThat(filter.condition(), instanceOf(LessThan.class)); | ||
LessThan condition = (LessThan) filter.condition(); | ||
assertThat(condition.left(), instanceOf(Literal.class)); | ||
assertThat(condition.right(), instanceOf(Literal.class)); | ||
assertThat(((Literal)condition.right()).value(), equalTo(300)); | ||
} | ||
|
||
public void testParamLiteralsWithUnresolvedAliasesAndMixedTypes() { | ||
LogicalPlan logicalPlan = parse("SELECT ?, ? FROM test", | ||
new SqlTypedParamValue("integer", 100), | ||
new SqlTypedParamValue("text", "100") | ||
); | ||
List<? extends NamedExpression> projections = ((Project) logicalPlan.children().get(0)).projections(); | ||
assertThat(projections, everyItem(instanceOf(UnresolvedAlias.class))); | ||
assertThat(projections.get(0).toString(), startsWith("100 AS ?")); | ||
assertThat(projections.get(1).toString(), startsWith("100 AS ?")); | ||
} | ||
|
||
public void testParamLiteralsWithResolvedAndUnresolvedAliases() { | ||
LogicalPlan logicalPlan = parse("SELECT ?, ? as x, ? FROM test", | ||
new SqlTypedParamValue("integer", 100), | ||
new SqlTypedParamValue("integer", 200), | ||
new SqlTypedParamValue("integer", 300) | ||
); | ||
List<? extends NamedExpression> projections = ((Project) logicalPlan.children().get(0)).projections(); | ||
assertThat(projections.get(0).toString(), startsWith("100 AS ?")); | ||
assertThat(projections.get(1).toString(), startsWith("200 AS x#"));; | ||
assertThat(projections.get(2).toString(), startsWith("300 AS ?"));; | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: "~ wrapper collided" or some other comment correction (can be the next PR, obv.)