Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Fixed functions work improperly with fieldvalue/constant param for current use #296

Merged
merged 9 commits into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/main/antlr/OpenDistroSqlLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ TABLES: 'TABLES';

ABS: 'ABS';
ACOS: 'ACOS';
ADD: 'ADD';
ASCII: 'ASCII';
ASIN: 'ASIN';
ATAN: 'ATAN';
ATAN2: 'ATAN2';
Expand All @@ -141,26 +143,50 @@ CONCAT: 'CONCAT';
CONCAT_WS: 'CONCAT_WS';
COS: 'COS';
COSH: 'COSH';
COT: 'COT';
CURDATE: 'CURDATE';
DATE: 'DATE';
DATE_FORMAT: 'DATE_FORMAT';
DAYOFMONTH: 'DAYOFMONTH';
DEGREES: 'DEGREES';
E: 'E';
EXP: 'EXP';
EXPM1: 'EXPM1';
FLOOR: 'FLOOR';
IF: 'IF';
IFNULL: 'IFNULL';
ISNULL: 'ISNULL';
LENGTH: 'LENGTH';
LN: 'LN';
LOCATE: 'LOCATE';
LOG: 'LOG';
LOG10: 'LOG10';
LOG2: 'LOG2';
LOWER: 'LOWER';
LTRIM: 'LTRIM';
MAKETIME: 'MAKETIME';
MODULUS: 'MODULUS';
MONTH: 'MONTH';
MONTHNAME: 'MONTHNAME';
MULTIPLY: 'MULTIPLY';
NOW: 'NOW';
PI: 'PI';
POW: 'POW';
POWER: 'POWER';
RADIANS: 'RADIANS';
RANDOM: 'RANDOM';
RAND: 'RAND';
REPLACE: 'REPLACE';
RINT: 'RINT';
ROUND: 'ROUND';
RTRIM: 'RTRIM';
SIGN: 'SIGN';
SIGNUM: 'SIGNUM';
SIN: 'SIN';
SINH: 'SINH';
SQRT: 'SQRT';
SUBTRACT: 'SUBTRACT';
TAN: 'TAN';
TIMESTAMP: 'TIMESTAMP';
UPPER: 'UPPER';

D: 'D';
Expand Down
15 changes: 7 additions & 8 deletions src/main/antlr/OpenDistroSqlParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -408,14 +408,13 @@ keywordsCanBeId

functionNameBase
: esFunctionNameBase
| ABS | ASIN | ATAN | ATAN2 | CBRT | CEIL | CONCAT | CONCAT_WS
| COS | COSH | DATE_FORMAT | DEGREES
| E | EXP | EXPM1 | FLOOR | LOG | LOG10 | LOG2 | LOWER
| PI | POW | RADIANS | RANDOM | RINT | ROUND
| SIN | SINH | SQRT | SUBSTRING | TAN | TRIM | UPPER | YEAR
| MONTH | DAYOFMONTH | DATE | MONTHNAME | TIMESTAMP
| MAKETIME | NOW | CURDATE
| IF | IFNULL | ISNULL
| ABS | ACOS | ADD | ASCII | ASIN | ATAN | ATAN2 | CBRT | CEIL | CONCAT | CONCAT_WS
| COS | COSH | COT | CURDATE | DATE | DATE_FORMAT | DAYOFMONTH | DEGREES
| E | EXP | EXPM1 | FLOOR | IF | IFNULL | ISNULL | LEFT | LENGTH | LN | LOCATE | LOG
| LOG10 | LOG2 | LOWER | LTRIM | MAKETIME | MODULUS | MONTH | MONTHNAME | MULTIPLY
| NOW | PI | POW | POWER | RADIANS | RAND | REPLACE | RIGHT | RINT | ROUND | RTRIM
| SIGN | SIGNUM | SIN | SINH | SQRT | SUBSTRING | SUBTRACT | TAN | TIMESTAMP | TRIM
| UPPER | YEAR
;

esFunctionNameBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
public enum ScalarFunction implements TypeExpression {

ABS(func(T(NUMBER)).to(T)), // translate to Java: <T extends Number> T ABS(T)
ACOS(func(T(NUMBER)).to(T)),
ADD(func(T(NUMBER), NUMBER).to(T)),
ASCII(func(T(STRING)).to(T)),
ASIN(func(T(NUMBER)).to(T)),
ATAN(func(T(NUMBER)).to(T)),
Expand All @@ -44,20 +46,25 @@ public enum ScalarFunction implements TypeExpression {
COS(func(T(NUMBER)).to(T)),
COSH(func(T(NUMBER)).to(T)),
COT(func(T(NUMBER)).to(T)),
CURDATE(func().to(ESDataType.DATE)),
DATE(func(ESDataType.DATE).to(ESDataType.DATE)),
DATE_FORMAT(
func(ESDataType.DATE, STRING).to(STRING),
func(ESDataType.DATE, STRING, STRING).to(STRING)
),
DAYOFMONTH(func(ESDataType.DATE).to(INTEGER)),
DEGREES(func(T(NUMBER)).to(T)),
DIVIDE(func(T(NUMBER), NUMBER).to(T)),
E(func().to(DOUBLE)),
EXP(func(T(NUMBER)).to(T)),
EXPM1(func(T(NUMBER)).to(T)),
FLOOR(func(T(NUMBER)).to(T)),
IF(func(BOOLEAN, ES_TYPE, ES_TYPE).to(ES_TYPE)),
IFNULL(func(ES_TYPE, ES_TYPE).to(ES_TYPE)),
ISNULL(func(ES_TYPE).to(INTEGER)),
LENGTH(func(STRING).to(INTEGER)
),
LEFT(func(T(STRING), INTEGER).to(T)),
LENGTH(func(STRING).to(INTEGER)),
LN(func(T(NUMBER)).to(T)),
LOCATE(
func(STRING, STRING, INTEGER).to(INTEGER),
func(STRING, STRING).to(INTEGER)
Expand All @@ -68,20 +75,33 @@ public enum ScalarFunction implements TypeExpression {
),
LOG2(func(T(NUMBER)).to(T)),
LOG10(func(T(NUMBER)).to(T)),
LN(func(T(NUMBER)).to(T)),
LOWER(
func(T(STRING)).to(T),
func(T(STRING), STRING).to(T)
),
LTRIM(func(T(STRING)).to(T)),
MAKETIME(func(INTEGER, INTEGER, INTEGER).to(ESDataType.DATE)),
MODULUS(func(T(NUMBER), NUMBER).to(T)),
MONTH(func(ESDataType.DATE).to(INTEGER)),
MONTHNAME(func(ESDataType.DATE).to(STRING)),
MULTIPLY(func(T(NUMBER), NUMBER).to(NUMBER)),
NOW(func().to(ESDataType.DATE)),
PI(func().to(DOUBLE)),
POW, POWER(
POW(
func(T(NUMBER)).to(T),
func(T(NUMBER), NUMBER).to(T)
),
POWER(
func(T(NUMBER)).to(T),
func(T(NUMBER), NUMBER).to(T)
),
RADIANS(func(T(NUMBER)).to(T)),
RANDOM(func(T(NUMBER)).to(T)),
RAND(
func().to(NUMBER),
func(T(NUMBER)).to(T)
),
REPLACE(func(T(STRING), STRING, STRING).to(T)),
RIGHT(func(T(STRING), INTEGER).to(T)),
RINT(func(T(NUMBER)).to(T)),
ROUND(func(T(NUMBER)).to(T)),
RTRIM(func(T(STRING)).to(T)),
Expand All @@ -91,20 +111,15 @@ POW, POWER(
SINH(func(T(NUMBER)).to(T)),
SQRT(func(T(NUMBER)).to(T)),
SUBSTRING(func(T(STRING), INTEGER, INTEGER).to(T)),
SUBTRACT(func(T(NUMBER), NUMBER).to(T)),
TAN(func(T(NUMBER)).to(T)),
TIMESTAMP(func(ESDataType.DATE).to(ESDataType.DATE)),
TRIM(func(T(STRING)).to(T)),
UPPER(
func(T(STRING)).to(T),
func(T(STRING), STRING).to(T)
),
YEAR(func(ESDataType.DATE).to(INTEGER)),
MONTH(func(ESDataType.DATE).to(INTEGER)),
MONTHNAME(func(ESDataType.DATE).to(STRING)),
DAYOFMONTH(func(ESDataType.DATE).to(INTEGER)),
DATE(func(ESDataType.DATE).to(ESDataType.DATE)),
TIMESTAMP(func(ESDataType.DATE).to(ESDataType.DATE)),
MAKETIME(func(INTEGER, INTEGER, INTEGER).to(ESDataType.DATE)),
NOW(func().to(ESDataType.DATE)),
CURDATE(func().to(ESDataType.DATE));
YEAR(func(ESDataType.DATE).to(INTEGER));

private final TypeExpressionSpec[] specifications;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.amazon.opendistroforelasticsearch.sql.utils.StringUtils.format;
import static com.amazon.opendistroforelasticsearch.sql.utils.StringUtils.isQuoted;

/**
Expand All @@ -51,7 +52,7 @@ public class SQLFunctions {

private static final Set<String> numberOperators = Sets.newHashSet(
"exp", "expm1", "log", "log2", "log10", "ln", "sqrt", "cbrt", "ceil", "floor", "rint", "pow", "power",
"round", "random", "abs", "sign", "signum"
"round", "rand", "abs", "sign", "signum"
);

private static final Set<String> mathConstants = Sets.newHashSet("e", "pi");
Expand Down Expand Up @@ -246,6 +247,14 @@ public Tuple<String, String> function(String methodName, List<KVValue> paramers,
(SQLExpr) paramers.get(0).value, name);
break;

case "rand":
if (paramers.isEmpty()) {
functionStr = rand();
} else {
functionStr = rand((SQLExpr) paramers.get(0).value);
}
break;

case "cot":
// ES does not support the function name cot
functionStr = mathSingleValueTemplate("1 / Math.tan", methodName,
Expand Down Expand Up @@ -354,6 +363,12 @@ public Tuple<String, String> function(String methodName, List<KVValue> paramers,
case "ascii":
functionStr = ascii((SQLExpr) paramers.get(0).value);
break;
case "left":
functionStr = left((SQLExpr) paramers.get(0).value, (SQLExpr) paramers.get(1).value);
break;
case "right":
functionStr = right((SQLExpr) paramers.get(0).value, (SQLExpr) paramers.get(1).value);
break;

case "if":
functionStr = ifFunc(paramers);
Expand Down Expand Up @@ -391,21 +406,21 @@ public Tuple<String, String> upper(SQLExpr field, String locale, String valueNam
String name = nextId("upper");

if (valueName == null) {
return new Tuple<>(name, def(name, upper(getPropertyOrValue(field), locale)));
return new Tuple<>(name, def(name, upper(getPropertyOrStringValue(field), locale)));
} else {
return new Tuple<>(name, getPropertyOrValue(field) + "; "
+ def(name, valueName + "." + upper(getPropertyOrValue(field), locale)));
return new Tuple<>(name, getPropertyOrStringValue(field) + "; "
+ def(name, valueName + "." + upper(getPropertyOrStringValue(field), locale)));
}
}

public Tuple<String, String> lower(SQLExpr field, String locale, String valueName) {
String name = nextId("lower");

if (valueName == null) {
return new Tuple<>(name, def(name, lower(getPropertyOrValue(field), locale)));
return new Tuple<>(name, def(name, lower(getPropertyOrStringValue(field), locale)));
} else {
return new Tuple<>(name, getPropertyOrValue(field) + "; "
+ def(name, valueName + "." + lower(getPropertyOrValue(field), locale)));
return new Tuple<>(name, getPropertyOrStringValue(field) + "; "
+ def(name, valueName + "." + lower(getPropertyOrStringValue(field), locale)));
}
}

Expand Down Expand Up @@ -650,14 +665,25 @@ private Tuple<String, String> radians(SQLExpr field, String valueName) {
return mathSingleValueTemplate("Math.toRadians", "radians", field, valueName);
}

private Tuple<String, String> rand(SQLExpr expr) {
String name = nextId("rand");
return new Tuple<>(name, def(name, format("new Random(%s).nextDouble()", getPropertyOrValue(expr))));
}

private Tuple<String, String> rand() {
String name = nextId("rand");
return new Tuple<>(name, def(name, "new Random().nextDouble()"));
}

private Tuple<String, String> mathDoubleValueTemplate(String methodName, String fieldName, SQLExpr val1,
String val2, String valueName) {
String name = nextId(fieldName);
if (valueName == null) {
return new Tuple<>(name, def(name, func(methodName, false, getPropertyOrValue(val1), val2)));
return new Tuple<>(name, def(name, func(methodName, false, getPropertyOrValue(val1),
getPropertyOrValue(val2))));
} else {
return new Tuple<>(name, getPropertyOrValue(val1) + "; "
+ def(name, func(methodName, false, valueName, val2)));
+ def(name, func(methodName, false, valueName, getPropertyOrValue(val2))));
}
}

Expand Down Expand Up @@ -688,9 +714,9 @@ private Tuple<String, String> mathConstantTemplate(String methodName, String fie
private Tuple<String, String> strSingleValueTemplate(String methodName, SQLExpr field, String valueName) {
String name = nextId(methodName);
if (valueName == null) {
return new Tuple<>(name, def(name, getPropertyOrValue(field) + "." + func(methodName, false)));
return new Tuple<>(name, def(name, getPropertyOrStringValue(field) + "." + func(methodName, false)));
} else {
return new Tuple<>(name, getPropertyOrValue(field) + "; "
return new Tuple<>(name, getPropertyOrStringValue(field) + "; "
+ def(name, valueName + "." + func(methodName, false)));
}

Expand Down Expand Up @@ -772,6 +798,20 @@ private Tuple<String, String> ascii(SQLExpr field) {
return new Tuple<>(name, def(name, "(int) " + getPropertyOrStringValue(field) + ".charAt(0)"));
}

private Tuple<String, String> left(SQLExpr expr, SQLExpr length) {
String name = nextId("left");
return new Tuple<>(name, StringUtils.format(
"def len = (int) Math.min(%s, %s.length()); def %s = %s.substring(0, len)",
exprString(length), getPropertyOrStringValue(expr), name, getPropertyOrStringValue(expr)));
}

private Tuple<String, String> right(SQLExpr expr, SQLExpr length) {
String name = nextId("right");
return new Tuple<>(name, StringUtils.format(
"def start = (int) Math.max(0, %s.length()-%s); def %s = %s.substring(start)",
getPropertyOrStringValue(expr), exprString(length), name, getPropertyOrStringValue(expr)));
}

private Tuple<String, String> date(SQLExpr field) {
String name = nextId("date");
return new Tuple<>(name, def(name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,15 @@ public void lnInAggregationShouldPass() {
);
}

@Test
public void rand() throws IOException {
SearchHit[] hits = query("SELECT RAND() AS rand", "ORDER BY rand");
for (SearchHit hit : hits) {
double rand = (double) getField(hit, "rand");
assertTrue(rand >= 0 && rand < 1);
}
}

private SearchHit[] query(String select, String... statements) throws IOException {
final String response = executeQueryWithStringOutput(select + " " + FROM + " " + String.join(" ", statements));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,36 @@ public void ascii() throws IOException {
);
}

/**
* The following tests for LEFT and RIGHT are ignored because the ES client fails to parse "LEFT"/"RIGHT" in
* the integTest
*/
@Ignore
@Test
public void left() throws IOException {
assertThat(
executeQuery("SELECT LEFT('sample', 2) AS left FROM " + TEST_INDEX_ACCOUNT + " ORDER BY left"),
hitAny(kvString("/fields/left/0", equalTo("sa")))
);
assertThat(
executeQuery("SELECT LEFT('sample', 20) AS left FROM " + TEST_INDEX_ACCOUNT + " ORDER BY left"),
hitAny(kvString("/fields/left/0", equalTo("sample")))
);
}

@Ignore
@Test
public void right() throws IOException {
assertThat(
executeQuery("SELECT RIGHT('elastic', 3) AS right FROM " + TEST_INDEX_ACCOUNT + " ORDER BY right"),
hitAny(kvString("/fields/right/0", equalTo("tic")))
);
assertThat(
executeQuery("SELECT RIGHT('elastic', 20) AS right FROM " + TEST_INDEX_ACCOUNT + " ORDER BY right"),
hitAny(kvString("/fields/right/0", equalTo("elastic")))
);
}

@Test
public void ifFuncShouldPassJDBC() {
assertThat(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,4 +423,28 @@ public void lnTest() {
scriptFilter,
"Math.log(doc['age'].value)"));
}

@Test
public void randWithoutParamTest() {
String query = "SELECT RAND() FROM bank";
ScriptField scriptField = CheckScriptContents.getScriptFieldFromQuery(query);
assertTrue(
CheckScriptContents.scriptContainsString(
scriptField,
"new Random().nextDouble()"
)
);
}

@Test
public void randWithOneParamTest() {
String query = "SELECT RAND(age) FROM bank";
ScriptField scriptField = CheckScriptContents.getScriptFieldFromQuery(query);
assertTrue(
CheckScriptContents.scriptContainsString(
scriptField,
"new Random(doc['age'].value).nextDouble()"
)
);
}
}
Loading