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:
parent
5b65e2ccbf
commit
20ea72e2f2
|
@ -243,7 +243,12 @@ functionExpression
|
|||
;
|
||||
|
||||
functionTemplate
|
||||
: identifier '(' (setQuantifier? expression (',' expression)*)? ')'
|
||||
: functionName '(' (setQuantifier? expression (',' expression)*)? ')'
|
||||
;
|
||||
functionName
|
||||
: LEFT
|
||||
| RIGHT
|
||||
| identifier
|
||||
;
|
||||
|
||||
constant
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
*
|
||||
|
|
|
@ -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}
|
||||
*
|
||||
|
|
|
@ -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}.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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}.
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)));
|
||||
|
|
Loading…
Reference in New Issue