Skip to content

Commit a759375

Browse files
emasabmatriv
authored andcommitted
SQL: Failing Group By queries due to different ExpressionIds (#43072)
Fix an issue that arises from the use of ExpressionIds as keys in a lookup map that helps the QueryTranslator to identify the grouping columns. The issue is that the same expression in different parts of the query (SELECT clause and GROUP BY clause) ends up with different ExpressionIds so the lookup fails. So, instead of ExpressionIds use the hashCode() of NamedExpression. Fixes: #41159 Fixes: #40001 Fixes: #40240 Fixes: #33361 Fixes: #46316 Fixes: #36074 Fixes: #34543 Fixes: #37044 Fixes: #42041 (cherry picked from commit 3c38ea5)
1 parent 5dc1761 commit a759375

File tree

25 files changed

+627
-121
lines changed

25 files changed

+627
-121
lines changed

x-pack/plugin/sql/qa/src/main/resources/agg.csv-spec

+188
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,194 @@ TRUNCATE(YEAR("birth_date"), -2)
244244
null
245245
1900
246246
;
247+
// Fails for H2
248+
groupByCastScalarWithNumericRef
249+
SELECT CAST(ABS(EXTRACT(YEAR FROM "birth_date")) AS BIGINT) FROM test_emp GROUP BY 1 ORDER BY 1 NULLS FIRST;
250+
251+
CAST(ABS(EXTRACT(YEAR FROM "birth_date")) AS BIGINT):l
252+
------------------------------------------------------
253+
null
254+
1952
255+
1953
256+
1954
257+
1955
258+
1956
259+
1957
260+
1958
261+
1959
262+
1960
263+
1961
264+
1962
265+
1963
266+
1964
267+
1965
268+
;
269+
270+
groupByConvertScalar
271+
SELECT CONVERT(ABS(EXTRACT(YEAR FROM "birth_date")), SQL_BIGINT) FROM test_emp GROUP BY CONVERT(ABS(EXTRACT(YEAR FROM "birth_date")), SQL_BIGINT) ORDER BY CONVERT(ABS(EXTRACT(YEAR FROM "birth_date")), SQL_BIGINT) NULLS FIRST;
272+
273+
274+
CONVERT(ABS(EXTRACT(YEAR FROM "birth_date")), SQL_BIGINT):l
275+
-----------------------------------------------------------
276+
null
277+
1952
278+
1953
279+
1954
280+
1955
281+
1956
282+
1957
283+
1958
284+
1959
285+
1960
286+
1961
287+
1962
288+
1963
289+
1964
290+
1965
291+
;
292+
293+
294+
groupByConvertScalarWithAlias
295+
SELECT CONVERT(ABS(EXTRACT(YEAR FROM "birth_date")), SQL_BIGINT) as "convert" FROM test_emp GROUP BY "convert" ORDER BY "convert" NULLS FIRST;
296+
297+
convert:l
298+
---------
299+
null
300+
1952
301+
1953
302+
1954
303+
1955
304+
1956
305+
1957
306+
1958
307+
1959
308+
1960
309+
1961
310+
1962
311+
1963
312+
1964
313+
1965
314+
;
315+
316+
groupByConvertScalarWithNumericRef
317+
SELECT CONVERT(ABS(EXTRACT(YEAR FROM "birth_date")), SQL_BIGINT) FROM test_emp GROUP BY 1 ORDER BY 1 NULLS FIRST;
318+
319+
CONVERT(ABS(EXTRACT(YEAR FROM "birth_date")), SQL_BIGINT):l
320+
-----------------------------------------------------------
321+
null
322+
1952
323+
1953
324+
1954
325+
1955
326+
1956
327+
1957
328+
1958
329+
1959
330+
1960
331+
1961
332+
1962
333+
1963
334+
1964
335+
1965
336+
;
337+
338+
groupByConstantScalar
339+
SELECT PI() * emp_no FROM test_emp GROUP BY PI() * emp_no ORDER BY PI() * emp_no LIMIT 10;
340+
341+
PI() * emp_no:d
342+
---------------
343+
31419.06812855152
344+
31422.209721205112
345+
31425.3513138587
346+
31428.49290651229
347+
31431.63449916588
348+
31434.77609181947
349+
31437.91768447306
350+
31441.05927712665
351+
31444.200869780238
352+
31447.34246243383
353+
;
354+
355+
groupByConstantScalarWithOrderByDesc
356+
SELECT PI() * emp_no FROM test_emp GROUP BY PI() * emp_no ORDER BY PI() * emp_no DESC LIMIT 10;
357+
358+
PI() * emp_no:d
359+
-------
360+
31730.08580125691
361+
31726.94420860332
362+
31723.80261594973
363+
31720.66102329614
364+
31717.51943064255
365+
31714.377837988963
366+
31711.23624533537
367+
31708.094652681782
368+
31704.95306002819
369+
31701.811467374602
370+
;
371+
372+
groupByConstantScalarWithAlias
373+
SELECT PI() * emp_no AS "value" FROM test_emp GROUP BY value ORDER BY value LIMIT 10;
374+
375+
value:d
376+
------------------
377+
31419.06812855152
378+
31422.209721205112
379+
31425.3513138587
380+
31428.49290651229
381+
31431.63449916588
382+
31434.77609181947
383+
31437.91768447306
384+
31441.05927712665
385+
31444.200869780238
386+
31447.34246243383
387+
;
388+
389+
groupByConstantScalarWithNumericRef
390+
SELECT PI() * emp_no FROM test_emp GROUP BY 1 ORDER BY 1 DESC LIMIT 10;
391+
392+
PI() * emp_no:d
393+
------------------
394+
31730.08580125691
395+
31726.94420860332
396+
31723.80261594973
397+
31720.66102329614
398+
31717.51943064255
399+
31714.377837988963
400+
31711.23624533537
401+
31708.094652681782
402+
31704.95306002819
403+
31701.811467374602
404+
;
405+
406+
groupByFieldAndConstantScalarWithMultipleOrderBy
407+
SELECT gender, emp_no % 3 + PI() FROM test_emp GROUP BY gender, emp_no % 3 + PI() ORDER BY gender, emp_no % 3 + PI() DESC LIMIT 8;
408+
409+
gender:s |emp_no % 3 + PI():d
410+
------------+------------------
411+
null |5.141592653589793
412+
null |4.141592653589793
413+
null |3.141592653589793
414+
F |5.141592653589793
415+
F |4.141592653589793
416+
F |3.141592653589793
417+
M |5.141592653589793
418+
M |4.141592653589793
419+
;
420+
421+
groupByFieldAndConstantScalarWithAliasWithOrderByDesc
422+
SELECT gender, emp_no % 3 + PI() as p FROM test_emp GROUP BY gender, emp_no % 3 + PI() ORDER BY gender DESC, p DESC LIMIT 8;
423+
424+
gender:s |p:d
425+
------------+------------------
426+
M |5.141592653589793
427+
M |4.141592653589793
428+
M |3.141592653589793
429+
F |5.141592653589793
430+
F |4.141592653589793
431+
F |3.141592653589793
432+
null |5.141592653589793
433+
null |4.141592653589793
434+
;
247435

248436
//
249437
// Grouping functions

x-pack/plugin/sql/qa/src/main/resources/agg.sql-spec

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ groupByMulScalar
4949
SELECT emp_no * 2 AS e FROM test_emp GROUP BY e ORDER BY e;
5050
groupByModScalar
5151
SELECT (emp_no % 3) + 1 AS e FROM test_emp GROUP BY e ORDER BY e;
52+
groupByCastScalar
53+
SELECT CAST(ABS(EXTRACT(YEAR FROM "birth_date")) AS BIGINT) FROM test_emp GROUP BY CAST(ABS(EXTRACT(YEAR FROM "birth_date")) AS BIGINT) ORDER BY CAST(ABS(EXTRACT(YEAR FROM "birth_date")) AS BIGINT) NULLS FIRST;
54+
groupByCastScalarWithAlias
55+
SELECT CAST(ABS(EXTRACT(YEAR FROM "birth_date")) AS BIGINT) as "cast" FROM test_emp GROUP BY "cast" ORDER BY "cast" NULLS FIRST;
5256

5357
// group by nested functions with no alias
5458
groupByTruncate

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Analyzer.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import java.util.Map;
6666
import java.util.Objects;
6767
import java.util.Set;
68+
import java.util.stream.Collectors;
6869

6970
import static java.util.Collections.emptyList;
7071
import static java.util.Collections.singletonList;
@@ -624,12 +625,15 @@ protected LogicalPlan rule(LogicalPlan plan) {
624625
.map(or -> tryResolveExpression(or, o.child()))
625626
.collect(toList());
626627

627-
AttributeSet resolvedRefs = Expressions.references(maybeResolved.stream()
628-
.filter(Expression::resolved)
629-
.collect(toList()));
630628

629+
Set<Expression> resolvedRefs = maybeResolved.stream()
630+
.filter(Expression::resolved)
631+
.collect(Collectors.toSet());
631632

632-
AttributeSet missing = resolvedRefs.subtract(o.child().outputSet());
633+
AttributeSet missing = Expressions.filterReferences(
634+
resolvedRefs,
635+
o.child().outputSet()
636+
);
633637

634638
if (!missing.isEmpty()) {
635639
// Add missing attributes but project them away afterwards

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/VerificationException.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ protected VerificationException(Collection<Failure> sources) {
2727
public String getMessage() {
2828
return failures.stream()
2929
.map(f -> {
30-
Location l = f.source().source().source();
30+
Location l = f.node().source().source();
3131
return "line " + l.getLineNumber() + ":" + l.getColumnNumber() + ": " + f.message();
3232
})
3333
.collect(Collectors.joining(StringUtils.NEW_LINE, "Found " + failures.size() + " problem(s)\n", StringUtils.EMPTY));

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/analysis/analyzer/Verifier.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,16 @@ public Verifier(Metrics metrics) {
7878
}
7979

8080
static class Failure {
81-
private final Node<?> source;
81+
private final Node<?> node;
8282
private final String message;
8383

84-
Failure(Node<?> source, String message) {
85-
this.source = source;
84+
Failure(Node<?> node, String message) {
85+
this.node = node;
8686
this.message = message;
8787
}
8888

89-
Node<?> source() {
90-
return source;
89+
Node<?> node() {
90+
return node;
9191
}
9292

9393
String message() {
@@ -96,7 +96,7 @@ String message() {
9696

9797
@Override
9898
public int hashCode() {
99-
return source.hashCode();
99+
return Objects.hash(node);
100100
}
101101

102102
@Override
@@ -110,7 +110,7 @@ public boolean equals(Object obj) {
110110
}
111111

112112
Verifier.Failure other = (Verifier.Failure) obj;
113-
return Objects.equals(source, other.source);
113+
return Objects.equals(node, other.node);
114114
}
115115

116116
@Override
@@ -125,7 +125,7 @@ private static Failure fail(Node<?> source, String message, Object... args) {
125125

126126
public Map<Node<?>, String> verifyFailures(LogicalPlan plan) {
127127
Collection<Failure> failures = verify(plan);
128-
return failures.stream().collect(toMap(Failure::source, Failure::message));
128+
return failures.stream().collect(toMap(Failure::node, Failure::message));
129129
}
130130

131131
Collection<Failure> verify(LogicalPlan plan) {

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/AttributeMap.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ static class AttributeWrapper {
3232

3333
@Override
3434
public int hashCode() {
35-
return attr.semanticHash();
35+
return attr.hashCode();
3636
}
3737

3838
@Override
3939
public boolean equals(Object obj) {
4040
if (obj instanceof AttributeWrapper) {
4141
AttributeWrapper aw = (AttributeWrapper) obj;
42-
return attr.semanticEquals(aw.attr);
42+
return attr.equals(aw.attr);
4343
}
4444

4545
return false;
@@ -368,4 +368,4 @@ public boolean equals(Object obj) {
368368
public String toString() {
369369
return delegate.toString();
370370
}
371-
}
371+
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/Expression.java

-3
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ public boolean resolved() {
126126

127127
public abstract DataType dataType();
128128

129-
@Override
130-
public abstract int hashCode();
131-
132129
@Override
133130
public String toString() {
134131
return nodeName() + "[" + propertiesToString(false) + "]";

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/Expressions.java

+28
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111

1212
import java.util.ArrayList;
1313
import java.util.Collection;
14+
import java.util.LinkedHashSet;
1415
import java.util.List;
16+
import java.util.Set;
1517
import java.util.function.Predicate;
18+
import java.util.stream.Collectors;
1619

1720
import static java.util.Collections.emptyList;
1821
import static java.util.Collections.emptyMap;
@@ -99,6 +102,31 @@ public static AttributeSet references(List<? extends Expression> exps) {
99102
return set;
100103
}
101104

105+
public static AttributeSet filterReferences(Set<? extends Expression> exps, AttributeSet excluded) {
106+
AttributeSet ret = new AttributeSet();
107+
while (exps.size() > 0) {
108+
109+
Set<Expression> filteredExps = new LinkedHashSet<>();
110+
for (Expression exp : exps) {
111+
Expression attr = Expressions.attribute(exp);
112+
if (attr == null || (excluded.contains(attr) == false)) {
113+
filteredExps.add(exp);
114+
}
115+
}
116+
117+
ret.addAll(new AttributeSet(
118+
filteredExps.stream().filter(c->c.children().isEmpty())
119+
.flatMap(exp->exp.references().stream())
120+
.collect(Collectors.toSet())
121+
));
122+
123+
exps = filteredExps.stream()
124+
.flatMap((Expression exp)->exp.children().stream())
125+
.collect(Collectors.toSet());
126+
}
127+
return ret;
128+
}
129+
102130
public static String name(Expression e) {
103131
return e instanceof NamedExpression ? ((NamedExpression) e).name() : e.nodeName();
104132
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/FieldAttribute.java

-5
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,6 @@ private FieldAttribute innerField(EsField type) {
9797
return new FieldAttribute(source(), this, name() + "." + type.getName(), type, qualifier(), nullable(), id(), synthetic());
9898
}
9999

100-
@Override
101-
protected Expression canonicalize() {
102-
return new FieldAttribute(source(), null, "<none>", field, null, Nullability.TRUE, id(), false);
103-
}
104-
105100
@Override
106101
protected Attribute clone(Source source, String name, String qualifier, Nullability nullable, ExpressionId id, boolean synthetic) {
107102
FieldAttribute qualifiedParent = parent != null ? (FieldAttribute) parent.withQualifier(qualifier) : null;

0 commit comments

Comments
 (0)