SQL: Improve grammar to better handle quotes (elastic/x-pack-elasticsearch#3051)

SQL: Improve grammar to better handle quotes

Fix typo in handling (back)quoted identifiers
Clarify use of unquote (dedicated for literals) and text (generic)
Address feedback
clarify that ` are picked up but not supported/recommended
Fix merge and adjust json errors to work on windows

Original commit: elastic/x-pack-elasticsearch@67e0f3f38e
This commit is contained in:
Costin Leau 2017-11-29 15:42:04 +02:00 committed by GitHub
parent d5525f38f3
commit c08eb56238
15 changed files with 272 additions and 177 deletions

View File

@ -392,11 +392,11 @@ DIGIT_IDENTIFIER
;
QUOTED_IDENTIFIER
: '"' ( ~['"'|'.'] | '"' )* '"'
: '"' ( ~'"' | '""' )* '"'
;
BACKQUOTED_IDENTIFIER
: '`' ( ~['`'|'.'] | '``' )* '`'
: '`' ( ~'`' | '``' )* '`'
;
fragment EXPONENT

View File

@ -57,11 +57,11 @@ public class PlanExecutor {
}
public SearchSourceBuilder searchSource(String sql, Configuration settings) {
PhysicalPlan executable = newSession(settings).executable(sql);
public SearchSourceBuilder searchSource(String sql, Configuration cfg) {
PhysicalPlan executable = newSession(cfg).executable(sql);
if (executable instanceof EsQueryExec) {
EsQueryExec e = (EsQueryExec) executable;
return SourceGenerator.sourceBuilder(e.queryContainer(), settings.filter(), settings.pageSize());
return SourceGenerator.sourceBuilder(e.queryContainer(), cfg.filter(), cfg.pageSize());
}
else {
throw new PlanningException("Cannot generate a query DSL for %s", sql);
@ -72,8 +72,8 @@ public class PlanExecutor {
sql(Configuration.DEFAULT, sql, listener);
}
public void sql(Configuration sqlSettings, String sql, ActionListener<SchemaRowSet> listener) {
SqlSession session = newSession(sqlSettings);
public void sql(Configuration cfg, String sql, ActionListener<SchemaRowSet> listener) {
SqlSession session = newSession(cfg);
try {
PhysicalPlan executable = session.executable(sql);
executable.execute(session, listener);

View File

@ -11,7 +11,6 @@ import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.type.DataType;
import org.elasticsearch.xpack.sql.util.CollectionUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@ -19,7 +18,6 @@ import static java.lang.String.format;
public class UnresolvedAttribute extends Attribute implements Unresolvable {
private final List<String> nameParts;
private final String unresolvedMsg;
public UnresolvedAttribute(Location location, String name) {
@ -32,14 +30,9 @@ public class UnresolvedAttribute extends Attribute implements Unresolvable {
public UnresolvedAttribute(Location location, String name, String qualifier, String unresolvedMessage) {
super(location, name, qualifier, null);
nameParts = Arrays.asList(name.split("\\."));
this.unresolvedMsg = unresolvedMessage == null ? errorMessage(qualifiedName(), null) : unresolvedMessage;
}
public List<String> nameParts() {
return nameParts;
}
@Override
public boolean resolved() {
return false;

View File

@ -5,20 +5,16 @@
*/
package org.elasticsearch.xpack.sql.parser;
import java.util.List;
import java.util.Optional;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.elasticsearch.common.Strings;
import org.elasticsearch.xpack.sql.parser.SqlBaseBaseVisitor;
import org.elasticsearch.xpack.sql.plan.logical.LogicalPlan;
import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.util.Check;
import static java.util.stream.Collectors.toList;
import java.util.ArrayList;
import java.util.List;
abstract class AbstractBuilder extends SqlBaseBaseVisitor<Object> {
@ -29,10 +25,11 @@ abstract class AbstractBuilder extends SqlBaseBaseVisitor<Object> {
return result;
}
@SuppressWarnings("unchecked")
protected <T> T typedParsing(ParseTree ctx, Class<T> type) {
Object result = ctx.accept(this);
if (type.isInstance(result)) {
return type.cast(result);
return (T) result;
}
throw new ParsingException(source(ctx), "Invalid query '%s'[%s] given; expected %s but found %s",
@ -44,23 +41,16 @@ abstract class AbstractBuilder extends SqlBaseBaseVisitor<Object> {
return typedParsing(ctx, LogicalPlan.class);
}
protected List<LogicalPlan> plans(List<? extends ParserRuleContext> ctxs) {
return visitList(ctxs, LogicalPlan.class);
}
// Helpers
protected <T> Optional<T> visitIfPresent(ParserRuleContext context, Class<T> clazz) {
return Optional.ofNullable(context)
.map(this::visit)
.map(clazz::cast);
}
protected <T> List<T> visitList(List<? extends ParserRuleContext> contexts, Class<T> clazz) {
return contexts.stream()
.map(this::visit)
.map(clazz::cast)
.collect(toList());
List<T> results = new ArrayList<>(contexts.size());
for (ParserRuleContext context : contexts) {
results.add(clazz.cast(visit(context)));
}
return results;
}
static Location source(ParseTree ctx) {
@ -85,26 +75,23 @@ abstract class AbstractBuilder extends SqlBaseBaseVisitor<Object> {
return new Location(token.getLine(), token.getCharPositionInLine());
}
/**
* Retrieves the raw text of the node (without interpreting it as a string literal).
*/
static String text(ParseTree node) {
return node == null ? null : text(node.getText());
return node == null ? null : node.getText();
}
static List<String> texts(List<? extends ParseTree> list) {
return list.stream()
.map(AbstractBuilder::text)
.collect(toList());
/**
* Extracts the actual unescaped string (literal) value of a token.
*/
static String string(Token token) {
return token == null ? null : unquoteString(token.getText());
}
static String text(Token token) {
return token == null ? null : text(token.getText());
}
private static String text(String text) {
String txt = text != null && Strings.hasText(text) ? text.trim() : null;
if (txt != null && txt.startsWith("'") && txt.endsWith("'") && txt.length() > 1) {
txt = txt.substring(1, txt.length() - 1);
}
return txt;
static String unquoteString(String text) {
// remove leading and trailing ' for strings and also eliminate escaped single quotes
return text == null ? null : text.substring(1, text.length() - 1).replace("''", "'");
}
@Override

View File

@ -97,12 +97,12 @@ abstract class CommandBuilder extends LogicalPlanBuilder {
@Override
public Object visitShowFunctions(ShowFunctionsContext ctx) {
return new ShowFunctions(source(ctx), text(ctx.pattern));
return new ShowFunctions(source(ctx), string(ctx.pattern));
}
@Override
public Object visitShowTables(ShowTablesContext ctx) {
return new ShowTables(source(ctx), text(ctx.pattern));
return new ShowTables(source(ctx), string(ctx.pattern));
}
@Override

View File

@ -23,8 +23,8 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Add;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Div;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Mod;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Mul;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Sub;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Neg;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Sub;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Extract;
import org.elasticsearch.xpack.sql.expression.predicate.And;
import org.elasticsearch.xpack.sql.expression.predicate.Equals;
@ -79,7 +79,6 @@ import org.elasticsearch.xpack.sql.type.DataTypes;
import java.math.BigDecimal;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import static java.lang.String.format;
@ -266,17 +265,17 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
//
@Override
public Object visitStringQuery(StringQueryContext ctx) {
return new StringQueryPredicate(source(ctx), text(ctx.queryString), text(ctx.options));
return new StringQueryPredicate(source(ctx), string(ctx.queryString), string(ctx.options));
}
@Override
public Object visitMatchQuery(MatchQueryContext ctx) {
return new MatchQueryPredicate(source(ctx), new UnresolvedAttribute(source(ctx.singleField), visitQualifiedName(ctx.singleField)), text(ctx.queryString), text(ctx.options));
return new MatchQueryPredicate(source(ctx), new UnresolvedAttribute(source(ctx.singleField), visitQualifiedName(ctx.singleField)), string(ctx.queryString), string(ctx.options));
}
@Override
public Object visitMultiMatchQuery(MultiMatchQueryContext ctx) {
return new MultiMatchQueryPredicate(source(ctx), text(ctx.multiFields), text(ctx.queryString), text(ctx.options));
return new MultiMatchQueryPredicate(source(ctx), string(ctx.multiFields), string(ctx.queryString), string(ctx.options));
}
@Override
@ -405,7 +404,11 @@ abstract class ExpressionBuilder extends IdentifierBuilder {
@Override
public Expression visitStringLiteral(StringLiteralContext ctx) {
return new Literal(source(ctx), ctx.STRING().stream().map(AbstractBuilder::text).collect(Collectors.joining()), DataTypes.KEYWORD);
StringBuilder sb = new StringBuilder();
for (TerminalNode node : ctx.STRING()) {
sb.append(unquoteString(text(node)));
}
return new Literal(source(ctx), sb.toString(), DataTypes.KEYWORD);
}
@Override

View File

@ -43,7 +43,7 @@ abstract class IdentifierBuilder extends AbstractBuilder {
@Override
public String visitIdentifier(IdentifierContext ctx) {
return ctx == null ? null : ctx.quoteIdentifier() != null ? text(ctx.quoteIdentifier()) : text(ctx.unquoteIdentifier());
return ctx == null ? null : ctx.getText();
}
@Override

View File

@ -147,7 +147,7 @@ class SqlBaseLexer extends Lexer {
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2m\u0386\b\1\4\2\t"+
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2m\u0387\b\1\4\2\t"+
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
@ -193,79 +193,79 @@ class SqlBaseLexer extends Lexer {
"\nd\rd\16d\u030b\3d\6d\u030f\nd\rd\16d\u0310\3d\3d\7d\u0315\nd\fd\16d"+
"\u0318\13d\5d\u031a\nd\3d\3d\3d\3d\6d\u0320\nd\rd\16d\u0321\3d\3d\5d\u0326"+
"\nd\3e\3e\5e\u032a\ne\3e\3e\3e\7e\u032f\ne\fe\16e\u0332\13e\3f\3f\3f\3"+
"f\6f\u0338\nf\rf\16f\u0339\3g\3g\3g\7g\u033f\ng\fg\16g\u0342\13g\3g\3"+
"g\3h\3h\3h\3h\7h\u034a\nh\fh\16h\u034d\13h\3h\3h\3i\3i\5i\u0353\ni\3i"+
"\6i\u0356\ni\ri\16i\u0357\3j\3j\3k\3k\3l\3l\3l\3l\7l\u0362\nl\fl\16l\u0365"+
"\13l\3l\5l\u0368\nl\3l\5l\u036b\nl\3l\3l\3m\3m\3m\3m\3m\7m\u0374\nm\f"+
"m\16m\u0377\13m\3m\3m\3m\3m\3m\3n\6n\u037f\nn\rn\16n\u0380\3n\3n\3o\3"+
"o\3\u0375\2p\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16"+
"\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34"+
"\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g"+
"\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083C\u0085D\u0087E\u0089F"+
"\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009d"+
"f\6f\u0338\nf\rf\16f\u0339\3g\3g\3g\3g\7g\u0340\ng\fg\16g\u0343\13g\3"+
"g\3g\3h\3h\3h\3h\7h\u034b\nh\fh\16h\u034e\13h\3h\3h\3i\3i\5i\u0354\ni"+
"\3i\6i\u0357\ni\ri\16i\u0358\3j\3j\3k\3k\3l\3l\3l\3l\7l\u0363\nl\fl\16"+
"l\u0366\13l\3l\5l\u0369\nl\3l\5l\u036c\nl\3l\3l\3m\3m\3m\3m\3m\7m\u0375"+
"\nm\fm\16m\u0378\13m\3m\3m\3m\3m\3m\3n\6n\u0380\nn\rn\16n\u0381\3n\3n"+
"\3o\3o\3\u0376\2p\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31"+
"\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65"+
"\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63e\64"+
"g\65i\66k\67m8o9q:s;u<w=y>{?}@\177A\u0081B\u0083C\u0085D\u0087E\u0089"+
"F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095L\u0097M\u0099N\u009bO\u009d"+
"P\u009fQ\u00a1R\u00a3S\u00a5T\u00a7U\u00a9V\u00abW\u00adX\u00afY\u00b1"+
"Z\u00b3[\u00b5\\\u00b7]\u00b9^\u00bb_\u00bd`\u00bfa\u00c1b\u00c3c\u00c5"+
"d\u00c7e\u00c9f\u00cbg\u00cdh\u00cfi\u00d1\2\u00d3\2\u00d5\2\u00d7j\u00d9"+
"k\u00dbl\u00ddm\3\2\13\3\2))\5\2<<BBaa\6\2$$))\60\60~~\6\2))\60\60bb~"+
"~\4\2--//\3\2\62;\3\2C\\\4\2\f\f\17\17\5\2\13\f\17\17\"\"\u03a4\2\3\3"+
"\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2"+
"\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3"+
"\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2"+
"%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61"+
"\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2"+
"\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I"+
"\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2"+
"\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2"+
"\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o"+
"\3\2\2\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2"+
"\2\2\2}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085"+
"\3\2\2\2\2\u0087\3\2\2\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2"+
"\2\2\u008f\3\2\2\2\2\u0091\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097"+
"\3\2\2\2\2\u0099\3\2\2\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2"+
"\2\2\u00a1\3\2\2\2\2\u00a3\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9"+
"\3\2\2\2\2\u00ab\3\2\2\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2"+
"\2\2\u00b3\3\2\2\2\2\u00b5\3\2\2\2\2\u00b7\3\2\2\2\2\u00b9\3\2\2\2\2\u00bb"+
"\3\2\2\2\2\u00bd\3\2\2\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2"+
"\2\2\u00c5\3\2\2\2\2\u00c7\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00cd"+
"\3\2\2\2\2\u00cf\3\2\2\2\2\u00d7\3\2\2\2\2\u00d9\3\2\2\2\2\u00db\3\2\2"+
"\2\2\u00dd\3\2\2\2\3\u00df\3\2\2\2\5\u00e1\3\2\2\2\7\u00e3\3\2\2\2\t\u00e5"+
"\3\2\2\2\13\u00e7\3\2\2\2\r\u00eb\3\2\2\2\17\u00f3\3\2\2\2\21\u00fc\3"+
"\2\2\2\23\u0100\3\2\2\2\25\u0104\3\2\2\2\27\u0107\3\2\2\2\31\u010b\3\2"+
"\2\2\33\u0113\3\2\2\2\35\u0116\3\2\2\2\37\u011b\3\2\2\2!\u0122\3\2\2\2"+
"#\u012a\3\2\2\2%\u0130\3\2\2\2\'\u0136\3\2\2\2)\u013b\3\2\2\2+\u0144\3"+
"\2\2\2-\u014d\3\2\2\2/\u0158\3\2\2\2\61\u015f\3\2\2\2\63\u0167\3\2\2\2"+
"\65\u016f\3\2\2\2\67\u0175\3\2\2\29\u0179\3\2\2\2;\u0180\3\2\2\2=\u0185"+
"\3\2\2\2?\u018a\3\2\2\2A\u0194\3\2\2\2C\u019d\3\2\2\2E\u01a3\3\2\2\2G"+
"\u01ac\3\2\2\2I\u01b3\3\2\2\2K\u01b6\3\2\2\2M\u01bc\3\2\2\2O\u01c4\3\2"+
"\2\2Q\u01c9\3\2\2\2S\u01cc\3\2\2\2U\u01d1\3\2\2\2W\u01d6\3\2\2\2Y\u01db"+
"\3\2\2\2[\u01e0\3\2\2\2]\u01e6\3\2\2\2_\u01ee\3\2\2\2a\u01f5\3\2\2\2c"+
"\u01fb\3\2\2\2e\u0203\3\2\2\2g\u0206\3\2\2\2i\u020a\3\2\2\2k\u020f\3\2"+
"\2\2m\u0212\3\2\2\2o\u021c\3\2\2\2q\u0223\3\2\2\2s\u0226\3\2\2\2u\u022c"+
"\3\2\2\2w\u0232\3\2\2\2y\u0239\3\2\2\2{\u0242\3\2\2\2}\u0247\3\2\2\2\177"+
"\u024d\3\2\2\2\u0081\u0253\3\2\2\2\u0083\u0259\3\2\2\2\u0085\u025f\3\2"+
"\2\2\u0087\u0267\3\2\2\2\u0089\u026e\3\2\2\2\u008b\u0276\3\2\2\2\u008d"+
"\u027a\3\2\2\2\u008f\u027f\3\2\2\2\u0091\u0284\3\2\2\2\u0093\u028a\3\2"+
"\2\2\u0095\u0291\3\2\2\2\u0097\u0296\3\2\2\2\u0099\u029b\3\2\2\2\u009b"+
"\u029e\3\2\2\2\u009d\u02a3\3\2\2\2\u009f\u02a8\3\2\2\2\u00a1\u02ac\3\2"+
"\2\2\u00a3\u02b2\3\2\2\2\u00a5\u02b9\3\2\2\2\u00a7\u02be\3\2\2\2\u00a9"+
"\u02c4\3\2\2\2\u00ab\u02c9\3\2\2\2\u00ad\u02d2\3\2\2\2\u00af\u02d4\3\2"+
"\2\2\u00b1\u02d6\3\2\2\2\u00b3\u02d9\3\2\2\2\u00b5\u02db\3\2\2\2\u00b7"+
"\u02de\3\2\2\2\u00b9\u02e0\3\2\2\2\u00bb\u02e2\3\2\2\2\u00bd\u02e4\3\2"+
"\2\2\u00bf\u02e6\3\2\2\2\u00c1\u02e8\3\2\2\2\u00c3\u02eb\3\2\2\2\u00c5"+
"\u02f7\3\2\2\2\u00c7\u0325\3\2\2\2\u00c9\u0329\3\2\2\2\u00cb\u0333\3\2"+
"\2\2\u00cd\u033b\3\2\2\2\u00cf\u0345\3\2\2\2\u00d1\u0350\3\2\2\2\u00d3"+
"\u0359\3\2\2\2\u00d5\u035b\3\2\2\2\u00d7\u035d\3\2\2\2\u00d9\u036e\3\2"+
"\2\2\u00db\u037e\3\2\2\2\u00dd\u0384\3\2\2\2\u00df\u00e0\7*\2\2\u00e0"+
"\4\3\2\2\2\u00e1\u00e2\7+\2\2\u00e2\6\3\2\2\2\u00e3\u00e4\7.\2\2\u00e4"+
"\b\3\2\2\2\u00e5\u00e6\7\60\2\2\u00e6\n\3\2\2\2\u00e7\u00e8\7C\2\2\u00e8"+
"\u00e9\7N\2\2\u00e9\u00ea\7N\2\2\u00ea\f\3\2\2\2\u00eb\u00ec\7C\2\2\u00ec"+
"\u00ed\7P\2\2\u00ed\u00ee\7C\2\2\u00ee\u00ef\7N\2\2\u00ef\u00f0\7[\2\2"+
"\u00f0\u00f1\7\\\2\2\u00f1\u00f2\7G\2\2\u00f2\16\3\2\2\2\u00f3\u00f4\7"+
"C\2\2\u00f4\u00f5\7P\2\2\u00f5\u00f6\7C\2\2\u00f6\u00f7\7N\2\2\u00f7\u00f8"+
"\7[\2\2\u00f8\u00f9\7\\\2\2\u00f9\u00fa\7G\2\2\u00fa\u00fb\7F\2\2\u00fb"+
"\20\3\2\2\2\u00fc\u00fd\7C\2\2\u00fd\u00fe\7P\2\2\u00fe\u00ff\7F\2\2\u00ff"+
"\22\3\2\2\2\u0100\u0101\7C\2\2\u0101\u0102\7P\2\2\u0102\u0103\7[\2\2\u0103"+
"\24\3\2\2\2\u0104\u0105\7C\2\2\u0105\u0106\7U\2\2\u0106\26\3\2\2\2\u0107"+
"k\u00dbl\u00ddm\3\2\13\3\2))\5\2<<BBaa\3\2$$\3\2bb\4\2--//\3\2\62;\3\2"+
"C\\\4\2\f\f\17\17\5\2\13\f\17\17\"\"\u03a5\2\3\3\2\2\2\2\5\3\2\2\2\2\7"+
"\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2"+
"\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2"+
"\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2"+
"\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2"+
"\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2"+
"\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M"+
"\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2"+
"\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2\2"+
"\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2\2\2q\3\2\2\2\2s"+
"\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2\2{\3\2\2\2\2}\3\2\2\2\2\177"+
"\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2\2\2\2\u0085\3\2\2\2\2\u0087\3\2\2"+
"\2\2\u0089\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f\3\2\2\2\2\u0091"+
"\3\2\2\2\2\u0093\3\2\2\2\2\u0095\3\2\2\2\2\u0097\3\2\2\2\2\u0099\3\2\2"+
"\2\2\u009b\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2\2\2\u00a1\3\2\2\2\2\u00a3"+
"\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2\2\2\2\u00a9\3\2\2\2\2\u00ab\3\2\2"+
"\2\2\u00ad\3\2\2\2\2\u00af\3\2\2\2\2\u00b1\3\2\2\2\2\u00b3\3\2\2\2\2\u00b5"+
"\3\2\2\2\2\u00b7\3\2\2\2\2\u00b9\3\2\2\2\2\u00bb\3\2\2\2\2\u00bd\3\2\2"+
"\2\2\u00bf\3\2\2\2\2\u00c1\3\2\2\2\2\u00c3\3\2\2\2\2\u00c5\3\2\2\2\2\u00c7"+
"\3\2\2\2\2\u00c9\3\2\2\2\2\u00cb\3\2\2\2\2\u00cd\3\2\2\2\2\u00cf\3\2\2"+
"\2\2\u00d7\3\2\2\2\2\u00d9\3\2\2\2\2\u00db\3\2\2\2\2\u00dd\3\2\2\2\3\u00df"+
"\3\2\2\2\5\u00e1\3\2\2\2\7\u00e3\3\2\2\2\t\u00e5\3\2\2\2\13\u00e7\3\2"+
"\2\2\r\u00eb\3\2\2\2\17\u00f3\3\2\2\2\21\u00fc\3\2\2\2\23\u0100\3\2\2"+
"\2\25\u0104\3\2\2\2\27\u0107\3\2\2\2\31\u010b\3\2\2\2\33\u0113\3\2\2\2"+
"\35\u0116\3\2\2\2\37\u011b\3\2\2\2!\u0122\3\2\2\2#\u012a\3\2\2\2%\u0130"+
"\3\2\2\2\'\u0136\3\2\2\2)\u013b\3\2\2\2+\u0144\3\2\2\2-\u014d\3\2\2\2"+
"/\u0158\3\2\2\2\61\u015f\3\2\2\2\63\u0167\3\2\2\2\65\u016f\3\2\2\2\67"+
"\u0175\3\2\2\29\u0179\3\2\2\2;\u0180\3\2\2\2=\u0185\3\2\2\2?\u018a\3\2"+
"\2\2A\u0194\3\2\2\2C\u019d\3\2\2\2E\u01a3\3\2\2\2G\u01ac\3\2\2\2I\u01b3"+
"\3\2\2\2K\u01b6\3\2\2\2M\u01bc\3\2\2\2O\u01c4\3\2\2\2Q\u01c9\3\2\2\2S"+
"\u01cc\3\2\2\2U\u01d1\3\2\2\2W\u01d6\3\2\2\2Y\u01db\3\2\2\2[\u01e0\3\2"+
"\2\2]\u01e6\3\2\2\2_\u01ee\3\2\2\2a\u01f5\3\2\2\2c\u01fb\3\2\2\2e\u0203"+
"\3\2\2\2g\u0206\3\2\2\2i\u020a\3\2\2\2k\u020f\3\2\2\2m\u0212\3\2\2\2o"+
"\u021c\3\2\2\2q\u0223\3\2\2\2s\u0226\3\2\2\2u\u022c\3\2\2\2w\u0232\3\2"+
"\2\2y\u0239\3\2\2\2{\u0242\3\2\2\2}\u0247\3\2\2\2\177\u024d\3\2\2\2\u0081"+
"\u0253\3\2\2\2\u0083\u0259\3\2\2\2\u0085\u025f\3\2\2\2\u0087\u0267\3\2"+
"\2\2\u0089\u026e\3\2\2\2\u008b\u0276\3\2\2\2\u008d\u027a\3\2\2\2\u008f"+
"\u027f\3\2\2\2\u0091\u0284\3\2\2\2\u0093\u028a\3\2\2\2\u0095\u0291\3\2"+
"\2\2\u0097\u0296\3\2\2\2\u0099\u029b\3\2\2\2\u009b\u029e\3\2\2\2\u009d"+
"\u02a3\3\2\2\2\u009f\u02a8\3\2\2\2\u00a1\u02ac\3\2\2\2\u00a3\u02b2\3\2"+
"\2\2\u00a5\u02b9\3\2\2\2\u00a7\u02be\3\2\2\2\u00a9\u02c4\3\2\2\2\u00ab"+
"\u02c9\3\2\2\2\u00ad\u02d2\3\2\2\2\u00af\u02d4\3\2\2\2\u00b1\u02d6\3\2"+
"\2\2\u00b3\u02d9\3\2\2\2\u00b5\u02db\3\2\2\2\u00b7\u02de\3\2\2\2\u00b9"+
"\u02e0\3\2\2\2\u00bb\u02e2\3\2\2\2\u00bd\u02e4\3\2\2\2\u00bf\u02e6\3\2"+
"\2\2\u00c1\u02e8\3\2\2\2\u00c3\u02eb\3\2\2\2\u00c5\u02f7\3\2\2\2\u00c7"+
"\u0325\3\2\2\2\u00c9\u0329\3\2\2\2\u00cb\u0333\3\2\2\2\u00cd\u033b\3\2"+
"\2\2\u00cf\u0346\3\2\2\2\u00d1\u0351\3\2\2\2\u00d3\u035a\3\2\2\2\u00d5"+
"\u035c\3\2\2\2\u00d7\u035e\3\2\2\2\u00d9\u036f\3\2\2\2\u00db\u037f\3\2"+
"\2\2\u00dd\u0385\3\2\2\2\u00df\u00e0\7*\2\2\u00e0\4\3\2\2\2\u00e1\u00e2"+
"\7+\2\2\u00e2\6\3\2\2\2\u00e3\u00e4\7.\2\2\u00e4\b\3\2\2\2\u00e5\u00e6"+
"\7\60\2\2\u00e6\n\3\2\2\2\u00e7\u00e8\7C\2\2\u00e8\u00e9\7N\2\2\u00e9"+
"\u00ea\7N\2\2\u00ea\f\3\2\2\2\u00eb\u00ec\7C\2\2\u00ec\u00ed\7P\2\2\u00ed"+
"\u00ee\7C\2\2\u00ee\u00ef\7N\2\2\u00ef\u00f0\7[\2\2\u00f0\u00f1\7\\\2"+
"\2\u00f1\u00f2\7G\2\2\u00f2\16\3\2\2\2\u00f3\u00f4\7C\2\2\u00f4\u00f5"+
"\7P\2\2\u00f5\u00f6\7C\2\2\u00f6\u00f7\7N\2\2\u00f7\u00f8\7[\2\2\u00f8"+
"\u00f9\7\\\2\2\u00f9\u00fa\7G\2\2\u00fa\u00fb\7F\2\2\u00fb\20\3\2\2\2"+
"\u00fc\u00fd\7C\2\2\u00fd\u00fe\7P\2\2\u00fe\u00ff\7F\2\2\u00ff\22\3\2"+
"\2\2\u0100\u0101\7C\2\2\u0101\u0102\7P\2\2\u0102\u0103\7[\2\2\u0103\24"+
"\3\2\2\2\u0104\u0105\7C\2\2\u0105\u0106\7U\2\2\u0106\26\3\2\2\2\u0107"+
"\u0108\7C\2\2\u0108\u0109\7U\2\2\u0109\u010a\7E\2\2\u010a\30\3\2\2\2\u010b"+
"\u010c\7D\2\2\u010c\u010d\7G\2\2\u010d\u010e\7V\2\2\u010e\u010f\7Y\2\2"+
"\u010f\u0110\7G\2\2\u0110\u0111\7G\2\2\u0111\u0112\7P\2\2\u0112\32\3\2"+
@ -423,33 +423,34 @@ class SqlBaseLexer extends Lexer {
"j\2\u0334\u0338\5\u00d5k\2\u0335\u0338\5\u00d3j\2\u0336\u0338\t\3\2\2"+
"\u0337\u0334\3\2\2\2\u0337\u0335\3\2\2\2\u0337\u0336\3\2\2\2\u0338\u0339"+
"\3\2\2\2\u0339\u0337\3\2\2\2\u0339\u033a\3\2\2\2\u033a\u00cc\3\2\2\2\u033b"+
"\u0340\7$\2\2\u033c\u033f\n\4\2\2\u033d\u033f\7$\2\2\u033e\u033c\3\2\2"+
"\2\u033e\u033d\3\2\2\2\u033f\u0342\3\2\2\2\u0340\u033e\3\2\2\2\u0340\u0341"+
"\3\2\2\2\u0341\u0343\3\2\2\2\u0342\u0340\3\2\2\2\u0343\u0344\7$\2\2\u0344"+
"\u00ce\3\2\2\2\u0345\u034b\7b\2\2\u0346\u034a\n\5\2\2\u0347\u0348\7b\2"+
"\2\u0348\u034a\7b\2\2\u0349\u0346\3\2\2\2\u0349\u0347\3\2\2\2\u034a\u034d"+
"\3\2\2\2\u034b\u0349\3\2\2\2\u034b\u034c\3\2\2\2\u034c\u034e\3\2\2\2\u034d"+
"\u034b\3\2\2\2\u034e\u034f\7b\2\2\u034f\u00d0\3\2\2\2\u0350\u0352\7G\2"+
"\2\u0351\u0353\t\6\2\2\u0352\u0351\3\2\2\2\u0352\u0353\3\2\2\2\u0353\u0355"+
"\3\2\2\2\u0354\u0356\5\u00d3j\2\u0355\u0354\3\2\2\2\u0356\u0357\3\2\2"+
"\2\u0357\u0355\3\2\2\2\u0357\u0358\3\2\2\2\u0358\u00d2\3\2\2\2\u0359\u035a"+
"\t\7\2\2\u035a\u00d4\3\2\2\2\u035b\u035c\t\b\2\2\u035c\u00d6\3\2\2\2\u035d"+
"\u035e\7/\2\2\u035e\u035f\7/\2\2\u035f\u0363\3\2\2\2\u0360\u0362\n\t\2"+
"\2\u0361\u0360\3\2\2\2\u0362\u0365\3\2\2\2\u0363\u0361\3\2\2\2\u0363\u0364"+
"\3\2\2\2\u0364\u0367\3\2\2\2\u0365\u0363\3\2\2\2\u0366\u0368\7\17\2\2"+
"\u0367\u0366\3\2\2\2\u0367\u0368\3\2\2\2\u0368\u036a\3\2\2\2\u0369\u036b"+
"\7\f\2\2\u036a\u0369\3\2\2\2\u036a\u036b\3\2\2\2\u036b\u036c\3\2\2\2\u036c"+
"\u036d\bl\2\2\u036d\u00d8\3\2\2\2\u036e\u036f\7\61\2\2\u036f\u0370\7,"+
"\2\2\u0370\u0375\3\2\2\2\u0371\u0374\5\u00d9m\2\u0372\u0374\13\2\2\2\u0373"+
"\u0371\3\2\2\2\u0373\u0372\3\2\2\2\u0374\u0377\3\2\2\2\u0375\u0376\3\2"+
"\2\2\u0375\u0373\3\2\2\2\u0376\u0378\3\2\2\2\u0377\u0375\3\2\2\2\u0378"+
"\u0379\7,\2\2\u0379\u037a\7\61\2\2\u037a\u037b\3\2\2\2\u037b\u037c\bm"+
"\2\2\u037c\u00da\3\2\2\2\u037d\u037f\t\n\2\2\u037e\u037d\3\2\2\2\u037f"+
"\u0380\3\2\2\2\u0380\u037e\3\2\2\2\u0380\u0381\3\2\2\2\u0381\u0382\3\2"+
"\2\2\u0382\u0383\bn\2\2\u0383\u00dc\3\2\2\2\u0384\u0385\13\2\2\2\u0385"+
"\u00de\3\2\2\2 \2\u02d2\u02ef\u02f1\u02f9\u02fe\u0304\u030b\u0310\u0316"+
"\u0319\u0321\u0325\u0329\u032e\u0330\u0337\u0339\u033e\u0340\u0349\u034b"+
"\u0352\u0357\u0363\u0367\u036a\u0373\u0375\u0380\3\2\3\2";
"\u0341\7$\2\2\u033c\u0340\n\4\2\2\u033d\u033e\7$\2\2\u033e\u0340\7$\2"+
"\2\u033f\u033c\3\2\2\2\u033f\u033d\3\2\2\2\u0340\u0343\3\2\2\2\u0341\u033f"+
"\3\2\2\2\u0341\u0342\3\2\2\2\u0342\u0344\3\2\2\2\u0343\u0341\3\2\2\2\u0344"+
"\u0345\7$\2\2\u0345\u00ce\3\2\2\2\u0346\u034c\7b\2\2\u0347\u034b\n\5\2"+
"\2\u0348\u0349\7b\2\2\u0349\u034b\7b\2\2\u034a\u0347\3\2\2\2\u034a\u0348"+
"\3\2\2\2\u034b\u034e\3\2\2\2\u034c\u034a\3\2\2\2\u034c\u034d\3\2\2\2\u034d"+
"\u034f\3\2\2\2\u034e\u034c\3\2\2\2\u034f\u0350\7b\2\2\u0350\u00d0\3\2"+
"\2\2\u0351\u0353\7G\2\2\u0352\u0354\t\6\2\2\u0353\u0352\3\2\2\2\u0353"+
"\u0354\3\2\2\2\u0354\u0356\3\2\2\2\u0355\u0357\5\u00d3j\2\u0356\u0355"+
"\3\2\2\2\u0357\u0358\3\2\2\2\u0358\u0356\3\2\2\2\u0358\u0359\3\2\2\2\u0359"+
"\u00d2\3\2\2\2\u035a\u035b\t\7\2\2\u035b\u00d4\3\2\2\2\u035c\u035d\t\b"+
"\2\2\u035d\u00d6\3\2\2\2\u035e\u035f\7/\2\2\u035f\u0360\7/\2\2\u0360\u0364"+
"\3\2\2\2\u0361\u0363\n\t\2\2\u0362\u0361\3\2\2\2\u0363\u0366\3\2\2\2\u0364"+
"\u0362\3\2\2\2\u0364\u0365\3\2\2\2\u0365\u0368\3\2\2\2\u0366\u0364\3\2"+
"\2\2\u0367\u0369\7\17\2\2\u0368\u0367\3\2\2\2\u0368\u0369\3\2\2\2\u0369"+
"\u036b\3\2\2\2\u036a\u036c\7\f\2\2\u036b\u036a\3\2\2\2\u036b\u036c\3\2"+
"\2\2\u036c\u036d\3\2\2\2\u036d\u036e\bl\2\2\u036e\u00d8\3\2\2\2\u036f"+
"\u0370\7\61\2\2\u0370\u0371\7,\2\2\u0371\u0376\3\2\2\2\u0372\u0375\5\u00d9"+
"m\2\u0373\u0375\13\2\2\2\u0374\u0372\3\2\2\2\u0374\u0373\3\2\2\2\u0375"+
"\u0378\3\2\2\2\u0376\u0377\3\2\2\2\u0376\u0374\3\2\2\2\u0377\u0379\3\2"+
"\2\2\u0378\u0376\3\2\2\2\u0379\u037a\7,\2\2\u037a\u037b\7\61\2\2\u037b"+
"\u037c\3\2\2\2\u037c\u037d\bm\2\2\u037d\u00da\3\2\2\2\u037e\u0380\t\n"+
"\2\2\u037f\u037e\3\2\2\2\u0380\u0381\3\2\2\2\u0381\u037f\3\2\2\2\u0381"+
"\u0382\3\2\2\2\u0382\u0383\3\2\2\2\u0383\u0384\bn\2\2\u0384\u00dc\3\2"+
"\2\2\u0385\u0386\13\2\2\2\u0386\u00de\3\2\2\2 \2\u02d2\u02ef\u02f1\u02f9"+
"\u02fe\u0304\u030b\u0310\u0316\u0319\u0321\u0325\u0329\u032e\u0330\u0337"+
"\u0339\u033f\u0341\u034a\u034c\u0353\u0358\u0364\u0368\u036b\u0374\u0376"+
"\u0381\3\2\3\2";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {

View File

@ -14,11 +14,14 @@ import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.plan.logical.LogicalPlan;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class SqlParser {
@ -51,7 +54,7 @@ public class SqlParser {
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
SqlBaseParser parser = new SqlBaseParser(tokenStream);
parser.addParseListener(new PostProcessor());
parser.addParseListener(new PostProcessor(Arrays.asList(parser.getRuleNames())));
parser.removeErrorListeners();
parser.addErrorListener(ERROR_LISTENER);
@ -85,11 +88,17 @@ public class SqlParser {
}
private class PostProcessor extends SqlBaseBaseListener {
private final List<String> ruleNames;
PostProcessor(List<String> ruleNames) {
this.ruleNames = ruleNames;
}
@Override
public void exitBackQuotedIdentifier(SqlBaseParser.BackQuotedIdentifierContext context) {
Token token = context.BACKQUOTED_IDENTIFIER().getSymbol();
throw new ParsingException(
"backquoted identifiers are not supported; use double quotes to quote identifiers",
"backquoted indetifiers not supported; please use double quotes instead",
null,
token.getLine(),
token.getCharPositionInLine());
@ -99,7 +108,7 @@ public class SqlParser {
public void exitDigitIdentifier(SqlBaseParser.DigitIdentifierContext context) {
Token token = context.DIGIT_IDENTIFIER().getSymbol();
throw new ParsingException(
"identifiers must not start with a digit; surround the identifier with double quotes",
"identifiers must not start with a digit; please use double quotes",
null,
token.getLine(),
token.getCharPositionInLine());
@ -121,6 +130,12 @@ public class SqlParser {
@Override
public void exitNonReserved(SqlBaseParser.NonReservedContext context) {
// tree cannot be modified during rule enter/exit _unless_ it's a terminal node
if (!(context.getChild(0) instanceof TerminalNode)) {
int rule = ((ParserRuleContext) context.getChild(0)).getRuleIndex();
throw new ParsingException("nonReserved can only contain tokens. Found nested rule: " + ruleNames.get(rule));
}
// replace nonReserved words with IDENT tokens
context.getParent().removeLastChild();

View File

@ -10,7 +10,6 @@ import org.elasticsearch.xpack.sql.expression.Attribute;
import org.elasticsearch.xpack.sql.expression.RootFieldAttribute;
import org.elasticsearch.xpack.sql.expression.function.FunctionDefinition;
import org.elasticsearch.xpack.sql.expression.function.FunctionRegistry;
import org.elasticsearch.xpack.sql.session.RowSet;
import org.elasticsearch.xpack.sql.session.Rows;
import org.elasticsearch.xpack.sql.session.SchemaRowSet;
import org.elasticsearch.xpack.sql.session.SqlSession;
@ -71,4 +70,4 @@ public class ShowFunctions extends Command {
ShowFunctions other = (ShowFunctions) obj;
return Objects.equals(pattern, other.pattern);
}
}
}

View File

@ -0,0 +1,102 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.sql.expression;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.sql.parser.ParsingException;
import org.elasticsearch.xpack.sql.parser.SqlParser;
import org.elasticsearch.xpack.sql.plan.logical.LogicalPlan;
import org.elasticsearch.xpack.sql.plan.logical.OrderBy;
import org.elasticsearch.xpack.sql.tree.Location;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.nullValue;
public class QuotingTests extends ESTestCase {
private static UnresolvedAttribute from(String s) {
return new UnresolvedAttribute(Location.EMPTY, s);
}
public void testBasicString() {
String s = "someField";
UnresolvedAttribute ua = from(s);
assertThat(ua.name(), equalTo(s));
assertThat(ua.qualifiedName(), equalTo(s));
assertThat(ua.qualifier(), nullValue());
}
public void testSingleQuoteLiteral() {
String name = "@timestamp";
Expression exp = new SqlParser().createExpression("'" + name + "'");
assertThat(exp, instanceOf(Literal.class));
Literal l = (Literal) exp;
assertThat(l.value(), equalTo(name));
}
public void testMultiSingleQuotedLiteral() {
String first = "bucket";
String second = "head";
Expression exp = new SqlParser().createExpression(String.format(Locale.ROOT, "'%s' '%s'", first, second));
assertThat(exp, instanceOf(Literal.class));
Literal l = (Literal) exp;
assertThat(l.value(), equalTo(first + second));
}
public void testQuotedAttribute() {
String quote = "\"";
String name = "@timestamp";
Expression exp = new SqlParser().createExpression(quote + name + quote);
assertThat(exp, instanceOf(UnresolvedAttribute.class));
UnresolvedAttribute ua = (UnresolvedAttribute) exp;
assertThat(ua.name(), equalTo(name));
assertThat(ua.qualifiedName(), equalTo(name));
assertThat(ua.qualifier(), nullValue());
}
public void testBackQuotedAttribute() {
String quote = "`";
String name = "@timestamp";
ParsingException ex = expectThrows(ParsingException.class, () -> new SqlParser().createExpression(quote + name + quote));
assertThat(ex.getMessage(), equalTo("line 1:1: backquoted indetifiers not supported; please use double quotes instead"));
}
public void testQuotedAttributeAndQualifier() {
String quote = "\"";
String qualifier = "table";
String name = "@timestamp";
Expression exp = new SqlParser().createExpression(quote + qualifier + quote + "." + quote + name + quote);
assertThat(exp, instanceOf(UnresolvedAttribute.class));
UnresolvedAttribute ua = (UnresolvedAttribute) exp;
assertThat(ua.name(), equalTo(name));
assertThat(ua.qualifiedName(), equalTo(qualifier + "." + name));
assertThat(ua.qualifier(), equalTo(qualifier));
}
public void testBackQuotedAttributeAndQualifier() {
String quote = "`";
String qualifier = "table";
String name = "@timestamp";
ParsingException ex = expectThrows(ParsingException.class, () -> new SqlParser().createExpression(quote + qualifier + quote + "." + quote + name + quote));
assertThat(ex.getMessage(), equalTo("line 1:1: backquoted indetifiers not supported; please use double quotes instead"));
}
public void testGreedyQuoting() {
LogicalPlan plan = new SqlParser().createStatement("SELECT * FROM \"table\" ORDER BY \"field\"");
final List<LogicalPlan> plans = new ArrayList<>();
plan.forEachDown(plans::add);
assertThat(plans, hasSize(4));
assertThat(plans.get(1), instanceOf(OrderBy.class));
}
}

View File

@ -5,15 +5,14 @@
*/
package org.elasticsearch.xpack.sql.client.shared;
import java.io.IOException;
import java.io.InputStream;
import java.lang.StringBuilder;
import java.nio.file.Files;
import java.util.Locale;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Locale;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.containsString;
@ -61,8 +60,7 @@ public class RemoteFailureTests extends ESTestCase {
public void testNoError() throws IOException {
IOException e = expectThrows(IOException.class, () -> parse("no_error.json"));
assertEquals(
"Can't parse error from Elasticearch [Expected [error] but didn't see it.] at [line 2 col 1]. Response:\n"
+ "{\n}\n",
"Can't parse error from Elasticearch [Expected [error] but didn't see it.] at [line 1 col 2]. Response:\n{}",
e.getMessage());
}
@ -70,8 +68,8 @@ public class RemoteFailureTests extends ESTestCase {
IOException e = expectThrows(IOException.class, () -> parse("bogus_error.json"));
assertEquals(
"Can't parse error from Elasticearch [Expected [error] to be an object but was [VALUE_STRING][bogus]] "
+ "at [line 2 col 12]. Response:\n"
+ "{\n \"error\": \"bogus\"\n}",
+ "at [line 1 col 12]. Response:\n"
+ "{ \"error\": \"bogus\" }",
e.getMessage());
}
@ -93,7 +91,7 @@ public class RemoteFailureTests extends ESTestCase {
assertEquals(
"Can't parse error from Elasticearch [Unrecognized token 'I': was expecting 'null', 'true', 'false' or NaN] "
+ "at [line 1 col 1]. Response:\n"
+ "I'm not json at all\n",
+ "I'm not json at all",
e.getMessage());
}

View File

@ -1,3 +1 @@
{
"error": "bogus"
}
{ "error": "bogus" }

View File

@ -1 +1 @@
I'm not json at all
I'm not json at all