Skip to content

Commit d28c23a

Browse files
Marios Trivyzasmatriv
Marios Trivyzas
authored andcommitted
SQL: Fix result column names for arithmetic functions (elastic#33500)
Previously, when an arithmetic function got applied on a table column in the `SELECT` clause, the name of the result column contained weird characters used internally when processing the SQL statement e.g.: SELECT CHAR(emp_no % 10000) FROM "test_emp" returned: CHAR((emp_no{f}elastic#14) % 10000)) as the column name instead of: CHAR((emp_no) % 10000)) Also, fix an issue that causes a ClassCastException to be thrown when using functions where both arguments are literals. Closes elastic#31869 Closes elastic#33461
1 parent f4ab6c2 commit d28c23a

File tree

8 files changed

+66
-18
lines changed

8 files changed

+66
-18
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,13 @@ public static AttributeSet references(List<? extends Expression> exps) {
8282
}
8383

8484
public static String name(Expression e) {
85-
return e instanceof NamedExpression ? ((NamedExpression) e).name() : e.nodeName();
85+
if (e instanceof NamedExpression) {
86+
return ((NamedExpression) e).name();
87+
} else if (e instanceof Literal) {
88+
return e.toString();
89+
} else {
90+
return e.nodeName();
91+
}
8692
}
8793

8894
public static List<String> names(Collection<? extends Expression> e) {
@@ -120,4 +126,4 @@ public static TypeResolution typeMustBeNumeric(Expression e) {
120126
return e.dataType().isNumeric()? TypeResolution.TYPE_RESOLVED : new TypeResolution(
121127
"Argument required to be numeric ('" + Expressions.name(e) + "' of type '" + e.dataType().esType + "')");
122128
}
123-
}
129+
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/ScalarFunction.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.elasticsearch.xpack.sql.expression.Expression;
1111
import org.elasticsearch.xpack.sql.expression.Expressions;
1212
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
13+
import org.elasticsearch.xpack.sql.expression.LiteralAttribute;
1314
import org.elasticsearch.xpack.sql.expression.function.Function;
1415
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute;
1516
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinition;
@@ -68,6 +69,9 @@ protected ScriptTemplate asScript(Expression exp) {
6869
if (attr instanceof AggregateFunctionAttribute) {
6970
return asScriptFrom((AggregateFunctionAttribute) attr);
7071
}
72+
if (attr instanceof LiteralAttribute) {
73+
return asScriptFrom((LiteralAttribute) attr);
74+
}
7175
// fall-back to
7276
return asScriptFrom((FieldAttribute) attr);
7377
}
@@ -98,6 +102,12 @@ protected ScriptTemplate asScriptFrom(AggregateFunctionAttribute aggregate) {
98102
aggregate.dataType());
99103
}
100104

105+
protected ScriptTemplate asScriptFrom(LiteralAttribute literal) {
106+
return new ScriptTemplate(formatScript("{}"),
107+
paramsBuilder().variable(literal.literal()).build(),
108+
literal.dataType());
109+
}
110+
101111
protected String formatScript(String scriptTemplate) {
102112
return formatTemplate(scriptTemplate);
103113
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/arithmetic/ArithmeticFunction.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic;
77

88
import org.elasticsearch.xpack.sql.expression.Expression;
9+
import org.elasticsearch.xpack.sql.expression.Expressions;
910
import org.elasticsearch.xpack.sql.expression.Literal;
1011
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation;
1112
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryNumericFunction;
@@ -65,7 +66,7 @@ protected ProcessorDefinition makeProcessorDefinition() {
6566
public String name() {
6667
StringBuilder sb = new StringBuilder();
6768
sb.append("(");
68-
sb.append(left());
69+
sb.append(Expressions.name(left()));
6970
if (!(left() instanceof Literal)) {
7071
sb.insert(1, "(");
7172
sb.append(")");
@@ -74,7 +75,7 @@ public String name() {
7475
sb.append(operation);
7576
sb.append(" ");
7677
int pos = sb.length();
77-
sb.append(right());
78+
sb.append(Expressions.name(right()));
7879
if (!(right() instanceof Literal)) {
7980
sb.insert(pos, "(");
8081
sb.append(")");
@@ -87,8 +88,4 @@ public String name() {
8788
public String toString() {
8889
return name() + "#" + functionId();
8990
}
90-
91-
protected boolean useParanthesis() {
92-
return !(left() instanceof Literal) || !(right() instanceof Literal);
93-
}
94-
}
91+
}

x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/NamedExpressionTests.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@
66
package org.elasticsearch.xpack.sql.expression.function;
77

88
import org.elasticsearch.test.ESTestCase;
9+
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
910
import org.elasticsearch.xpack.sql.expression.Literal;
1011
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Add;
1112
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Div;
1213
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Mod;
1314
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Mul;
1415
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Neg;
1516
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Sub;
17+
import org.elasticsearch.xpack.sql.type.DataType;
18+
import org.elasticsearch.xpack.sql.type.EsField;
1619

20+
import static java.util.Collections.emptyMap;
1721
import static org.elasticsearch.xpack.sql.tree.Location.EMPTY;
1822

1923
public class NamedExpressionTests extends ESTestCase {
@@ -38,6 +42,12 @@ public void testArithmeticFunctionName() {
3842
assertEquals("-5", neg.name());
3943
}
4044

45+
public void testNameForArithmeticFunctionAppliedOnTableColumn() {
46+
FieldAttribute fa = new FieldAttribute(EMPTY, "myField", new EsField("myESField", DataType.INTEGER, emptyMap(), true));
47+
Add add = new Add(EMPTY, fa, l(10));
48+
assertEquals("((myField) + 10)", add.name());
49+
}
50+
4151
private static Literal l(Object value) {
4252
return Literal.of(EMPTY, value);
4353
}

x-pack/qa/sql/src/main/java/org/elasticsearch/xpack/qa/sql/jdbc/CsvTestUtils.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,18 @@ private static Tuple<String, String> extractColumnTypesAndStripCli(String expect
113113
}
114114

115115
private static Tuple<String, String> extractColumnTypesFromHeader(String header) {
116-
String[] columnTypes = Strings.delimitedListToStringArray(header, "|", " \t");
116+
String[] columnTypes = Strings.tokenizeToStringArray(header, "|");
117117
StringBuilder types = new StringBuilder();
118118
StringBuilder columns = new StringBuilder();
119119
for (String column : columnTypes) {
120-
String[] nameType = Strings.delimitedListToStringArray(column, ":");
120+
String[] nameType = Strings.delimitedListToStringArray(column.trim(), ":");
121121
assertThat("If at least one column has a type associated with it, all columns should have types", nameType, arrayWithSize(2));
122122
if (types.length() > 0) {
123123
types.append(",");
124124
columns.append("|");
125125
}
126-
columns.append(nameType[0]);
127-
types.append(resolveColumnType(nameType[1]));
126+
columns.append(nameType[0].trim());
127+
types.append(resolveColumnType(nameType[1].trim()));
128128
}
129129
return new Tuple<>(columns.toString(), types.toString());
130130
}
@@ -206,4 +206,4 @@ public static class CsvTestCase {
206206
public String query;
207207
public String expectedResults;
208208
}
209-
}
209+
}

x-pack/qa/sql/src/main/java/org/elasticsearch/xpack/qa/sql/jdbc/JdbcAssert.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ private static void doAssertResultSetData(ResultSet expected, ResultSet actual,
176176
Object expectedObject = expected.getObject(column);
177177
Object actualObject = lenient ? actual.getObject(column, expectedColumnClass) : actual.getObject(column);
178178

179-
String msg = format(Locale.ROOT, "Different result for column [" + metaData.getColumnName(column) + "], "
180-
+ "entry [" + (count + 1) + "]");
179+
String msg = format(Locale.ROOT, "Different result for column [%s], entry [%d]",
180+
metaData.getColumnName(column), count + 1);
181181

182182
// handle nulls first
183183
if (expectedObject == null || actualObject == null) {
@@ -230,4 +230,4 @@ private static int typeOf(int columnType, boolean lenient) {
230230

231231
return columnType;
232232
}
233-
}
233+
}

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,26 @@ SELECT CONCAT(CONCAT(SUBSTRING("first_name",1,LENGTH("first_name")-2),UCASE(LEFT
407407
---------------+---------------------------------------------
408408
AlejandRo |2
409409
;
410+
411+
412+
checkColumnNameWithNestedArithmeticFunctionCallsOnTableColumn
413+
SELECT CHAR(emp_no % 10000) FROM "test_emp" WHERE emp_no > 10064 ORDER BY emp_no LIMIT 1;
414+
415+
CHAR(((emp_no) % 10000)):s
416+
A
417+
;
418+
419+
checkColumnNameWithComplexNestedArithmeticFunctionCallsOnTableColumn1
420+
SELECT CHAR(emp_no % (7000 + 3000)) FROM "test_emp" WHERE emp_no > 10065 ORDER BY emp_no LIMIT 1;
421+
422+
CHAR(((emp_no) % ((7000 + 3000)))):s
423+
B
424+
;
425+
426+
427+
checkColumnNameWithComplexNestedArithmeticFunctionCallsOnTableColumn2
428+
SELECT CHAR((emp_no % (emp_no - 1 + 1)) + 67) FROM "test_emp" WHERE emp_no > 10066 ORDER BY emp_no LIMIT 1;
429+
430+
CHAR(((((emp_no) % (((((emp_no) - 1)) + 1)))) + 67)):s
431+
C
432+
;

x-pack/qa/sql/src/main/resources/math.sql-spec

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ mathATan2
128128
// tag::atan2
129129
SELECT ATAN2(emp_no, emp_no) m, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
130130
// end::atan2
131-
mathPower
132131
// tag::power
132+
mathPowerPositive
133133
SELECT POWER(emp_no, 2) m, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
134+
mathPowerNegative
135+
SELECT POWER(salary, -1) m, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
134136
// end::power

0 commit comments

Comments
 (0)