Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed Parser Where Queries Improperly Parsed As Alias #128

Closed
wants to merge 6 commits into from
Closed
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
6 * 2
6 *2
6* 2
6*2
6 + 2
6 +2
6+ 2
6+2
6 - 2
6 -2
6- 2
6-2
6 / 2
6 /2
6/ 2
6/2
6 % 2
6 %2
6% 2
6%2
1 + 2
-1.0 + 1.234
10 - 5
Expand Down
12 changes: 11 additions & 1 deletion sql/src/main/antlr/OpenSearchSQLIdentifierParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ options { tokenVocab=OpenSearchSQLLexer; }
// Identifiers

tableName
: qualifiedName
: indexName
;

columnName
Expand All @@ -47,6 +47,10 @@ alias
: ident
;

indexName
: index (DOT index)*
;

qualifiedName
: ident (DOT ident)*
;
Expand All @@ -57,6 +61,12 @@ ident
| keywordsCanBeId
;

index
: FROM_CLAUSE_DOT? IND
| BACKTICK_QUOTE_ID
| keywordsCanBeId
;

keywordsCanBeId
: FULL
| FIELD | D | T | TS // OD SQL and ODBC special
Expand Down
49 changes: 47 additions & 2 deletions sql/src/main/antlr/OpenSearchSQLLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ EXISTS: 'EXISTS';
FALSE: 'FALSE';
FLOAT: 'FLOAT';
FIRST: 'FIRST';
FROM: 'FROM';
FROM: 'FROM' -> pushMode (FROM_CLAUSE);
GROUP: 'GROUP';
HAVING: 'HAVING';
IN: 'IN';
Expand Down Expand Up @@ -438,7 +438,7 @@ BACKTICK_QUOTE_ID: BQUOTA_STRING;

// Fragments for Literal primitives
fragment EXPONENT_NUM_PART: 'E' [-+]? DEC_DIGIT+;
fragment ID_LITERAL: [@*A-Z]+?[*A-Z_\-0-9]*;
fragment ID_LITERAL: [A-Z]+?[A-Z_\-0-9]*;
fragment DQUOTA_STRING: '"' ( '\\'. | '""' | ~('"'| '\\') )* '"';
fragment SQUOTA_STRING: '\'' ('\\'. | '\'\'' | ~('\'' | '\\'))* '\'';
fragment BQUOTA_STRING: '`' ( '\\'. | '``' | ~('`'|'\\'))* '`';
Expand All @@ -449,3 +449,48 @@ fragment BIT_STRING_L: 'B' '\'' [01]+ '\'';
// Last tokens must generate Errors

ERROR_RECOGNITION: . -> channel(ERRORCHANNEL);


// FROM_CLAUSE table names are identifiers that have extra characters beyond what MySQL accepts.
// We use the FROM_CLAUSE mode to enter a separate rule set (defined below).
// In this rule set, table names can be defined according to what is required by OpenSearch without affecting rules used for lexing the rest of a SQL query.
// Once the table name is defined, we can exit from this FROM_CLAUSE and return to the default set of tokens
// see: https://opensearch.org/docs/latest/search-plugins/sql/identifiers/
mode FROM_CLAUSE;
FROM_CLAUSE_SPACE: [ \t\r\n]+ -> channel(HIDDEN);
FROM_CLAUSE_SPEC_SQL_COMMENT: '/*!' .+? '*/' -> channel(SQLCOMMENT);
FROM_CLAUSE_COMMENT_INPUT: '/*' .*? '*/' -> channel(HIDDEN);
FROM_CLAUSE_LINE_COMMENT: (
('-- ' | '#') ~[\r\n]* ('\r'? '\n' | EOF)
| '--' ('\r'? '\n' | EOF)
) -> channel(HIDDEN);

FROM_CLAUSE_DOT: '.';
FROM_CLAUSE_LT_SQR_PRTHS: '[';
FROM_CLAUSE_RT_SQR_PRTHS: ']';
FROM_CLAUSE_SEMI: ';';
FROM_CLAUSE_AT_SIGN: '@';
FROM_CLAUSE_ZERO_DECIMAL: '0';
FROM_CLAUSE_ONE_DECIMAL: '1';
FROM_CLAUSE_TWO_DECIMAL: '2';
FROM_CLAUSE_SINGLE_QUOTE_SYMB: '\'';
FROM_CLAUSE_DOUBLE_QUOTE_SYMB: '"';
FROM_CLAUSE_REVERSE_QUOTE_SYMB: '`';
FROM_CLAUSE_COLON_SYMB: ':';

//TODO: Implement the following
//FROM_CLAUSE_LR_BRACKET: '(';
//FROM_CLAUSE_RR_BRACKET: ')';
//FROM_CLAUSE_COMMA: ',';

FROM_CLAUSE_DECIMAL_LITERAL: DECIMAL_LITERAL;

IND: INDEX -> popMode;

INDEX: INDEX_FRAGMENT | BACKTICK_QUOTE_IND;

fragment INDEX_FRAGMENT: [*@A-Z]+?[*A-Z_\-0-9]*;
fragment BACKTICK_QUOTE_IND: '`' ( '\\'. | '``' | ~('`'|'\\'))* '`';


FROM_CLAUSE_ERROR_RECOGNITION: . -> channel(ERRORCHANNEL);
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public class AstExpressionBuilder extends OpenSearchSQLParserBaseVisitor<Unresol

@Override
public UnresolvedExpression visitTableName(TableNameContext ctx) {
return visit(ctx.qualifiedName());
return visit(ctx.indexName());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,9 @@ public void can_parse_query_string_relevance_function() {
assertNotNull(parser.parse(
"SELECT id FROM test WHERE query_string([address], 'query')"));
assertNotNull(parser.parse(
"SELECT id FROM test WHERE query_string([addr*], 'query')"));
"SELECT id FROM test WHERE query_string(['addr*'], 'query')"));
assertNotNull(parser.parse(
"SELECT id FROM test WHERE query_string([*ss], 'query')"));
"SELECT id FROM test WHERE query_string(['*ss'], 'query')"));
assertNotNull(parser.parse(
"SELECT id FROM test WHERE query_string([address, notes], 'query')"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ public void canBuildRegularIdentifierForSQLStandard() {
@Test
public void canBuildRegularIdentifierForOpenSearch() {
buildFromTableName(".opensearch_dashboards").expectQualifiedName(".opensearch_dashboards");
buildFromIdentifier("@timestamp").expectQualifiedName("@timestamp");
buildFromIdentifier("logs-2020-01").expectQualifiedName("logs-2020-01");
buildFromIdentifier("*logs*").expectQualifiedName("*logs*");
buildFromIdentifier("`*logs*`").expectQualifiedName("*logs*");
}

@Test
Expand Down