SQL: Scripting support for casting functions CAST and CONVERT (#36640)

This commit is contained in:
Andrei Stefan 2018-12-17 13:36:48 +02:00 committed by GitHub
parent c0866393ee
commit b15f27f6a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 10 deletions

View File

@ -130,7 +130,7 @@ SELECT MAX(languages) max, MIN(languages) min, SUM(languages) sum, AVG(languages
FROM test_emp GROUP BY languages ORDER BY languages ASC LIMIT 5; FROM test_emp GROUP BY languages ORDER BY languages ASC LIMIT 5;
max:bt | min:bt | sum:bt | avg:d | percent:d | percent_rank:d| kurtosis:d | skewness:d max:bt | min:bt | sum:bt | avg:d | percent:d | percent_rank:d| kurtosis:d | skewness:d
---------------+---------------+---------------+---------------+---------------+---------------+---------------+--------------- ---------------+---------------+---------------+--------------+---------------+---------------+---------------+---------------
null |null |null |null |null |null |null |null null |null |null |null |null |null |null |null
1 |1 |15 |1 |1.0 |100.0 |NaN |NaN 1 |1 |15 |1 |1.0 |100.0 |NaN |NaN
2 |2 |38 |2 |2.0 |100.0 |NaN |NaN 2 |2 |38 |2 |2.0 |100.0 |NaN |NaN
@ -138,6 +138,60 @@ null |null |null |null |null |
4 |4 |72 |4 |4.0 |0.0 |NaN |NaN 4 |4 |72 |4 |4.0 |0.0 |NaN |NaN
; ;
aggByComplexCastedValue
SELECT CONVERT(CONCAT(LTRIM(CONVERT("emp_no", SQL_VARCHAR)), LTRIM(CONVERT("languages", SQL_VARCHAR))), SQL_BIGINT) AS "TEMP"
FROM "test_emp" GROUP BY "TEMP" ORDER BY "TEMP" LIMIT 20;
TEMP:l
---------------
10020
10021
10022
10023
10024
10025
10026
10027
10028
10029
100012
100025
100034
100045
100051
100063
100074
100082
100091
100104
;
aggAndOrderByCastedValue
SELECT CHAR_LENGTH(SPACE(CAST(languages AS SMALLINT))), COUNT(*) FROM test_emp GROUP BY 1 ORDER BY 1 DESC;
CHAR_LENGTH(SPACE(CAST(languages AS SMALLINT))):i| COUNT(1):l
-------------------------------------------------+---------------
5 |21
4 |18
3 |17
2 |19
1 |15
null |10
;
aggAndOrderByCastedFunctionValue
SELECT ROUND(SQRT(CAST(EXP(languages) AS SMALLINT)), 2), COUNT(*) FROM test_emp GROUP BY 1 ORDER BY 1 DESC;
ROUND(SQRT(CAST(EXP(languages) AS SMALLINT)),2):d| COUNT(1):l
-------------------------------------------------+---------------
12.17 |21
7.42 |18
4.47 |17
2.65 |19
1.73 |15
null |10
;
// //
// Grouping functions // Grouping functions

View File

@ -7,14 +7,18 @@ package org.elasticsearch.xpack.sql.expression.function.scalar;
import org.elasticsearch.xpack.sql.expression.Expression; import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor; import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.tree.NodeInfo; import org.elasticsearch.xpack.sql.tree.NodeInfo;
import org.elasticsearch.xpack.sql.type.DataType; import org.elasticsearch.xpack.sql.type.DataType;
import org.elasticsearch.xpack.sql.type.DataTypeConversion; import org.elasticsearch.xpack.sql.type.DataTypeConversion;
import org.elasticsearch.xpack.sql.type.DataTypes; import org.elasticsearch.xpack.sql.type.DataTypes;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
public class Cast extends UnaryScalarFunction { public class Cast extends UnaryScalarFunction {
private final DataType dataType; private final DataType dataType;
@ -74,6 +78,18 @@ public class Cast extends UnaryScalarFunction {
return new CastProcessor(DataTypeConversion.conversionFor(from(), to())); return new CastProcessor(DataTypeConversion.conversionFor(from(), to()));
} }
@Override
public ScriptTemplate asScript() {
ScriptTemplate fieldAsScript = asScript(field());
return new ScriptTemplate(
formatTemplate(String.format(Locale.ROOT, "{sql}.cast(%s,{})", fieldAsScript.template())),
paramsBuilder()
.script(fieldAsScript.params())
.variable(dataType.name())
.build(),
dataType());
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(super.hashCode(), dataType); return Objects.hash(super.hashCode(), dataType);

View File

@ -35,6 +35,7 @@ import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.Bina
import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.InProcessor; import org.elasticsearch.xpack.sql.expression.predicate.operator.comparison.InProcessor;
import org.elasticsearch.xpack.sql.expression.predicate.regex.RegexProcessor.RegexOperation; import org.elasticsearch.xpack.sql.expression.predicate.regex.RegexProcessor.RegexOperation;
import org.elasticsearch.xpack.sql.type.DataType; import org.elasticsearch.xpack.sql.type.DataType;
import org.elasticsearch.xpack.sql.type.DataTypeConversion;
import org.elasticsearch.xpack.sql.util.DateUtils; import org.elasticsearch.xpack.sql.util.DateUtils;
import org.elasticsearch.xpack.sql.util.StringUtils; import org.elasticsearch.xpack.sql.util.StringUtils;
@ -458,4 +459,11 @@ public final class InternalSqlScriptUtils {
public static String ucase(String s) { public static String ucase(String s) {
return (String) StringOperation.UCASE.apply(s); return (String) StringOperation.UCASE.apply(s);
} }
//
// Casting
//
public static Object cast(Object value, String typeName) {
return DataTypeConversion.convert(value, DataType.fromTypeName(typeName));
}
} }

View File

@ -130,4 +130,9 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS
String space(Number) String space(Number)
String substring(String, Number, Number) String substring(String, Number, Number)
String ucase(String) String ucase(String)
#
# Casting
#
def cast(Object, String)
} }

View File

@ -240,10 +240,10 @@ public class QueryFolderTests extends ESTestCase {
assertEquals(EsQueryExec.class, p.getClass()); assertEquals(EsQueryExec.class, p.getClass());
EsQueryExec ee = (EsQueryExec) p; EsQueryExec ee = (EsQueryExec) p;
assertThat(ee.queryContainer().aggs().asAggBuilder().toString().replaceAll("\\s+", ""), assertThat(ee.queryContainer().aggs().asAggBuilder().toString().replaceAll("\\s+", ""),
endsWith("{\"script\":{" + endsWith("{\"script\":{\"source\":\"InternalSqlScriptUtils.cast(" +
"\"source\":\"InternalSqlScriptUtils.docValue(doc,params.v0)\",\"lang\":\"painless\"," + "InternalSqlScriptUtils.docValue(doc,params.v0),params.v1)\"," +
"\"params\":{\"v0\":\"keyword\"}},\"missing_bucket\":true," + "\"lang\":\"painless\",\"params\":{\"v0\":\"keyword\",\"v1\":\"IP\"}}," +
"\"value_type\":\"ip\",\"order\":\"asc\"}}}]}}}")); "\"missing_bucket\":true,\"value_type\":\"ip\",\"order\":\"asc\"}}}]}}}"));
assertEquals(2, ee.output().size()); assertEquals(2, ee.output().size());
assertThat(ee.output().get(0).toString(), startsWith("COUNT(1){a->")); assertThat(ee.output().get(0).toString(), startsWith("COUNT(1){a->"));
assertThat(ee.output().get(1).toString(), startsWith("a{s->")); assertThat(ee.output().get(1).toString(), startsWith("a{s->"));