SQL: allow LEFT and RIGHT as function names (#32066)

Due to the way ANTLR works, any declared tokens need to be accounted for
manually inside function names (otherwise a different rule gets applied).

Fix #32046
This commit is contained in:
Costin Leau 2018-07-16 23:42:44 +03:00 committed by GitHub
parent 5b65e2ccbf
commit 20ea72e2f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 961 additions and 804 deletions

View File

@ -243,7 +243,12 @@ functionExpression
;
functionTemplate
: identifier '(' (setQuantifier? expression (',' expression)*)? ')'
: functionName '(' (setQuantifier? expression (',' expression)*)? ')'
;
functionName
: LEFT
| RIGHT
| identifier
;
constant

View File

@ -396,8 +396,7 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
@Override
public Function visitFunctionExpression(FunctionExpressionContext ctx) {
FunctionTemplateContext template = ctx.functionTemplate();
String name = visitIdentifier(template.identifier());
String name = template.functionName().getText();
boolean isDistinct = template.setQuantifier() != null && template.setQuantifier().DISTINCT() != null;
UnresolvedFunction.ResolutionType resolutionType =
isDistinct ? UnresolvedFunction.ResolutionType.DISTINCT : UnresolvedFunction.ResolutionType.STANDARD;

View File

@ -803,6 +803,18 @@ class SqlBaseBaseListener implements SqlBaseListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFunctionTemplate(SqlBaseParser.FunctionTemplateContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterFunctionName(SqlBaseParser.FunctionNameContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFunctionName(SqlBaseParser.FunctionNameContext ctx) { }
/**
* {@inheritDoc}
*

View File

@ -473,6 +473,13 @@ class SqlBaseBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements SqlBa
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunctionTemplate(SqlBaseParser.FunctionTemplateContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitFunctionName(SqlBaseParser.FunctionNameContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*

View File

@ -745,6 +745,16 @@ interface SqlBaseListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitFunctionTemplate(SqlBaseParser.FunctionTemplateContext ctx);
/**
* Enter a parse tree produced by {@link SqlBaseParser#functionName}.
* @param ctx the parse tree
*/
void enterFunctionName(SqlBaseParser.FunctionNameContext ctx);
/**
* Exit a parse tree produced by {@link SqlBaseParser#functionName}.
* @param ctx the parse tree
*/
void exitFunctionName(SqlBaseParser.FunctionNameContext ctx);
/**
* Enter a parse tree produced by the {@code nullLiteral}
* labeled alternative in {@link SqlBaseParser#constant}.

View File

@ -445,6 +445,12 @@ interface SqlBaseVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitFunctionTemplate(SqlBaseParser.FunctionTemplateContext ctx);
/**
* Visit a parse tree produced by {@link SqlBaseParser#functionName}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitFunctionName(SqlBaseParser.FunctionNameContext ctx);
/**
* Visit a parse tree produced by the {@code nullLiteral}
* labeled alternative in {@link SqlBaseParser#constant}.

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.sql.parser;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.Literal;
import org.elasticsearch.xpack.sql.expression.function.UnresolvedFunction;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Neg;
import org.elasticsearch.xpack.sql.type.DataType;
@ -15,6 +16,13 @@ public class ExpressionTests extends ESTestCase {
private final SqlParser parser = new SqlParser();
public void testTokenFunctionName() throws Exception {
Expression lt = parser.createExpression("LEFT()");
assertEquals(UnresolvedFunction.class, lt.getClass());
UnresolvedFunction uf = (UnresolvedFunction) lt;
assertEquals("LEFT", uf.functionName());
}
public void testLiteralLong() throws Exception {
Expression lt = parser.createExpression(String.valueOf(Long.MAX_VALUE));
assertEquals(Literal.class, lt.getClass());

View File

@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
public class SqlParserTests extends ESTestCase {
public void testSelectStar() {
singleProjection(project(parseStatement("SELECT * FROM foo")), UnresolvedStar.class);
}
@ -44,6 +45,11 @@ public class SqlParserTests extends ESTestCase {
assertEquals("SCORE", f.functionName());
}
public void testSelectRightFunction() {
UnresolvedFunction f = singleProjection(project(parseStatement("SELECT RIGHT()")), UnresolvedFunction.class);
assertEquals("RIGHT", f.functionName());
}
public void testOrderByField() {
Order.OrderDirection dir = randomFrom(Order.OrderDirection.values());
OrderBy ob = orderBy(parseStatement("SELECT * FROM foo ORDER BY bar" + stringForDirection(dir)));