Skip to content

Commit b3c4854

Browse files
committed
SQL: Fix issue with duplicate columns in SELECT (#42122)
Previously, if a column (field, scalar, alias) appeared more than once in the SELECT list, the value was returned only once (1st appearance) in each row. Fixes: #41811 (cherry picked from commit 097ea36)
1 parent a8dda05 commit b3c4854

File tree

5 files changed

+117
-1
lines changed

5 files changed

+117
-1
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
aggSumWithColumnRepeatedWithOrderAsc
2+
SELECT gender AS g, gender, SUM(salary) AS s3, SUM(salary), SUM(salary) AS s5 FROM test_emp GROUP BY gender ORDER BY SUM(salary);
3+
4+
g:s | gender:s | s3:i | SUM(salary):i | s5:i
5+
null |null |487605 |487605 |487605
6+
F |F |1666196|1666196 |1666196
7+
M |M |2671054|2671054 |2671054
8+
;
9+
10+
aggSumWithAliasWithColumnRepeatedWithOrderDesc
11+
SELECT gender AS g, gender, SUM(salary) AS s3, SUM(salary), SUM(salary) AS s5 FROM test_emp GROUP BY g ORDER BY s5 DESC;
12+
13+
g:s | gender:s | s3:i | SUM(salary):i | s5:i
14+
M |M |2671054|2671054 |2671054
15+
F |F |1666196|1666196 |1666196
16+
null |null |487605 |487605 |487605
17+
;
18+
19+
aggSumWithNumericRefWithColumnRepeatedWithOrderDesc
20+
SELECT gender AS g, gender, SUM(salary) AS s3, SUM(salary), SUM(salary) AS s5 FROM test_emp GROUP BY 2 ORDER BY 3 DESC;
21+
22+
g:s | gender:s | s3:i | SUM(salary):i | s5:i
23+
M |M |2671054|2671054 |2671054
24+
F |F |1666196|1666196 |1666196
25+
null |null |487605 |487605 |487605
26+
;

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,33 @@ null |null |null |null |null |n
146146
4 |4 |72 |4 |4.0 |0.0 |NaN |NaN
147147
;
148148

149+
aggSumWithColumnRepeated
150+
SELECT gender AS g, gender, SUM(salary) AS s3, SUM(salary), SUM(salary) AS s5 FROM test_emp GROUP BY gender;
151+
152+
g:s | gender:s | s3:i | SUM(salary):i | s5:i
153+
null |null |487605 |487605 |487605
154+
F |F |1666196|1666196 |1666196
155+
M |M |2671054|2671054 |2671054
156+
;
157+
158+
aggSumWithAliasWithColumnRepeated
159+
SELECT gender AS g, gender, SUM(salary) AS s3, SUM(salary), SUM(salary) AS s5 FROM test_emp GROUP BY g;
160+
161+
g:s | gender:s | s3:i | SUM(salary):i | s5:i
162+
null |null |487605 |487605 |487605
163+
F |F |1666196|1666196 |1666196
164+
M |M |2671054|2671054 |2671054
165+
;
166+
167+
aggSumWithNumericRefWithColumnRepeated
168+
SELECT gender AS g, gender, SUM(salary) AS s3, SUM(salary), SUM(salary) AS s5 FROM test_emp GROUP BY 2;
169+
170+
g:s | gender:s | s3:i | SUM(salary):i | s5:i
171+
null |null |487605 |487605 |487605
172+
F |F |1666196|1666196 |1666196
173+
M |M |2671054|2671054 |2671054
174+
;
175+
149176
aggByComplexCastedValue
150177
SELECT CONVERT(CONCAT(LTRIM(CONVERT("emp_no", SQL_VARCHAR)), LTRIM(CONVERT("languages", SQL_VARCHAR))), SQL_BIGINT) AS "TEMP"
151178
FROM "test_emp" GROUP BY "TEMP" ORDER BY "TEMP" LIMIT 20;

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ multipleColumnsNoAliasWithLimit
3333
SELECT first_name, last_name FROM "test_emp" ORDER BY emp_no LIMIT 5;
3434
multipleColumnWithAliasWithAndWithoutAsWithLimit
3535
SELECT first_name f, last_name AS l FROM "test_emp" ORDER BY emp_no LIMIT 5;
36+
multipleColumnNoAliasWithColumnRepeatedWithLimit
37+
SELECT salary, first_name, salary FROM test_emp ORDER BY salary LIMIT 3;
38+
multipleColumnWithAliasWithAsWithColumnRepeatedWithLimit
39+
SELECT salary, first_name, salary AS x FROM test_emp ORDER BY x LIMIT 3;
40+
multipleColumnWithAliasWithAndWithoutAsWithColumnRepeatedWithLimit
41+
SELECT salary, first_name, salary AS x, salary y FROM test_emp ORDER BY y LIMIT 3;
3642

3743
//
3844
// SELECT constant literals with FROM

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/querydsl/container/QueryContainer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,9 @@ public BitSet columnMask(List<Attribute> columns) {
175175
.innerId() : alias.id()) : null;
176176
for (int i = 0; i < fields.size(); i++) {
177177
Tuple<FieldExtraction, ExpressionId> tuple = fields.get(i);
178-
if (tuple.v2().equals(id) || (aliasId != null && tuple.v2().equals(aliasId))) {
178+
// if the index is already set there is a collision,
179+
// so continue searching for the other tuple with the same id
180+
if (mask.get(i)==false && (tuple.v2().equals(id) || (aliasId != null && tuple.v2().equals(aliasId)))) {
179181
index = i;
180182
break;
181183
}

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/querydsl/container/QueryContainerTests.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,24 @@
66
package org.elasticsearch.xpack.sql.querydsl.container;
77

88
import org.elasticsearch.test.ESTestCase;
9+
import org.elasticsearch.xpack.sql.expression.Alias;
10+
import org.elasticsearch.xpack.sql.expression.Attribute;
11+
import org.elasticsearch.xpack.sql.expression.AttributeMap;
12+
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
913
import org.elasticsearch.xpack.sql.querydsl.query.BoolQuery;
1014
import org.elasticsearch.xpack.sql.querydsl.query.MatchAll;
1115
import org.elasticsearch.xpack.sql.querydsl.query.NestedQuery;
1216
import org.elasticsearch.xpack.sql.querydsl.query.Query;
1317
import org.elasticsearch.xpack.sql.querydsl.query.RangeQuery;
1418
import org.elasticsearch.xpack.sql.tree.Source;
1519
import org.elasticsearch.xpack.sql.tree.SourceTests;
20+
import org.elasticsearch.xpack.sql.type.DataType;
21+
import org.elasticsearch.xpack.sql.type.EsField;
22+
23+
import java.util.Arrays;
24+
import java.util.BitSet;
25+
import java.util.LinkedHashMap;
26+
import java.util.Map;
1627

1728
import static java.util.Collections.emptyMap;
1829
import static java.util.Collections.singletonMap;
@@ -53,4 +64,48 @@ public void testRewriteToContainsNestedFieldWhenDoesNotContainNestedFieldAndCant
5364
new NestedQuery(source, path, singletonMap(name, hasDocValues), new MatchAll(source)));
5465
assertEquals(expected, QueryContainer.rewriteToContainNestedField(original, source, path, name, hasDocValues));
5566
}
67+
68+
public void testColumnMaskShouldDuplicateSameAttributes() {
69+
70+
EsField esField = new EsField("str", DataType.TEXT, emptyMap(), true);
71+
72+
Attribute first = new FieldAttribute(Source.EMPTY, "first", esField);
73+
Attribute second = new FieldAttribute(Source.EMPTY, "second", esField);
74+
Attribute third = new FieldAttribute(Source.EMPTY, "third", esField);
75+
Attribute fourth = new FieldAttribute(Source.EMPTY, "fourth", esField);
76+
Alias firstAliased = new Alias(Source.EMPTY, "firstAliased", first);
77+
78+
Map<Attribute,Attribute> aliasesMap = new LinkedHashMap<>();
79+
aliasesMap.put(firstAliased.toAttribute(), first);
80+
81+
QueryContainer queryContainer = new QueryContainer()
82+
.withAliases(new AttributeMap<>(aliasesMap))
83+
.addColumn(third)
84+
.addColumn(first)
85+
.addColumn(fourth)
86+
.addColumn(firstAliased.toAttribute())
87+
.addColumn(second)
88+
.addColumn(first)
89+
.addColumn(fourth);
90+
91+
BitSet result = queryContainer.columnMask(Arrays.asList(
92+
first,
93+
first,
94+
second,
95+
third,
96+
firstAliased.toAttribute()
97+
));
98+
99+
BitSet expected = new BitSet();
100+
expected.set(0, true);
101+
expected.set(1, true);
102+
expected.set(2, false);
103+
expected.set(3, true);
104+
expected.set(4, true);
105+
expected.set(5, true);
106+
expected.set(6, false);
107+
108+
109+
assertEquals(expected, result);
110+
}
56111
}

0 commit comments

Comments
 (0)