Skip to content
Draft
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
95 changes: 53 additions & 42 deletions jdbc-v2/src/main/javacc/ClickHouseSqlParser.jj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ PARSER_BEGIN(ClickHouseSqlParser)

package com.clickhouse.jdbc.internal.parser.javacc;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StringReader;

import java.util.ArrayList;
Expand All @@ -49,6 +51,32 @@ public class ClickHouseSqlParser {

private static final Logger log = LoggerFactory.getLogger(ClickHouseSqlParser.class);

private static final Set<String> ALLOWED_ALIAS_KEYWORDS = loadKeywords("allowed_keyword_aliases.txt");

private static Set<String> loadKeywords(String resource) {
Set<String> keywords = new HashSet<>();
try (java.io.InputStream in = ClickHouseSqlParser.class.getResourceAsStream("/" + resource)) {
if (in != null) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (!line.isEmpty()) {
keywords.add(line.toUpperCase(Locale.ROOT));
}
}
}
}
} catch (Exception e) {
log.error("Failed to load keywords from " + resource, e);
}
return keywords;
}

private static boolean isAllowedAlias(Token t) {
return t != null && ALLOWED_ALIAS_KEYWORDS.contains(t.image.toUpperCase(Locale.ROOT));
}

private final List<ClickHouseSqlStatement> statements = new ArrayList<>();

private ParseHandler handler;
Expand Down Expand Up @@ -678,6 +706,7 @@ void showStmt(): {} {
(<DATABASE> databaseIdentifier(true))
| LOOKAHEAD(2) (LOOKAHEAD(1) <CREATE>)? (LOOKAHEAD(1) <SETTINGS>)? <PROFILE> anyIdentifier()
| LOOKAHEAD(2) (<DICTIONARY> tableIdentifier(true))
| LOOKAHEAD(2) (LOOKAHEAD(1) <CHANGED>)? <SETTINGS> { token_source.table = "settings"; }
| LOOKAHEAD(2) ((LOOKAHEAD(2) <TEMPORARY>)? (LOOKAHEAD(2) <TABLE>)? tableIdentifier(true))
)
)
Expand Down Expand Up @@ -843,7 +872,7 @@ void outfilePart(): {} {
}

void settingsPart(): {} {
<SETTINGS> { token_source.addPosition(token); } settingExprList()
(LOOKAHEAD(1) <CHANGED>)? <SETTINGS> { token_source.addPosition(token); } (LOOKAHEAD(2) settingExprList())?
}

void withTotalPart(): {} {
Expand Down Expand Up @@ -888,13 +917,25 @@ void anyColumnExpr(): {} {
| nestedIdentifier()
}

Token aliasIdentifier(): { Token t; } {
(
t = <IDENTIFIER>
| t = <BACK_QUOTED_NAME>
| t = <DOUBLE_QUOTED_NAME>
| t = variable()
| LOOKAHEAD({ isAllowedAlias(getToken(1)) })
t = anyKeyword()
)
{ return t; }
}

Token aliasExpr(): { Token t = null; } {
(
LOOKAHEAD(2) <AS> t = anyIdentifier()
LOOKAHEAD(2) <AS> t = aliasIdentifier()
| LOOKAHEAD(2) formatPart()
| LOOKAHEAD(2) settingsPart()
| LOOKAHEAD(2) outfilePart()
| t = identifier()
| t = aliasIdentifier()
)
{ return t; }
}
Expand Down Expand Up @@ -950,10 +991,12 @@ void settingExprList(): {} {
}

void settingExpr(): { String key; } {
identifier() { key = token.image; } <EQ_SINGLE> literal() { token_source.addSetting(key, token.image); }
anyIdentifier() { key = token.image; } <EQ_SINGLE> literal() { token_source.addSetting(key, token.image); }
}

// basics
// --- Base definitions


Token anyIdentifier(): { Token t; } {
(
t = <BACK_QUOTED_NAME>
Expand All @@ -965,17 +1008,6 @@ Token anyIdentifier(): { Token t; } {
{ return t; }
}

Token identifier(): { Token t; } {
(
t = <BACK_QUOTED_NAME>
| t = <DOUBLE_QUOTED_NAME>
| t = variable()
| t = <IDENTIFIER>
| t = keyword()
)
{ return t; }
}

void interval(): {} {
<SECOND> | <MINUTE> | <HOUR> | <DAY> | <WEEK> | <MONTH> | <QUARTER> | <YEAR>
}
Expand Down Expand Up @@ -1045,15 +1077,15 @@ Token anyKeyword(): { Token t; } {
| t = <MOVE> | t = <OPTIMIZE> | t = <RENAME> | t = <REVOKE> | t = <SELECT> | t = <SET> | t = <SHOW> | t = <SYSTEM>
| t = <TRUNCATE> | t = <UPDATE> | t = <USE> | t = <WATCH> | t = <UNDROP>
// others
| t = <ALL> | t = <AND> | t = <APPLY> | t = <ARRAY> | t = <AS> | t = <ASOF> | t = <BETWEEN> | t = <CASE>
| t = <CLUSTER> | t = <COMPRESSION> | t = <DATE> | t = <DATABASE> | t = <DATABASES> | t = <DICTIONARY> | t = <DICTIONARIES>
| t = <ALL> | t = <AND> | t = <APPLY> | t = <ARRAY> | t = <AS> | t = <ASOF> | t = <BEGIN> | t = <BETWEEN> | t = <CASE> | t = <CHANGED>
| t = <CLUSTER> | t = <COMMIT> | t = <COMPRESSION> | t = <DATE> | t = <DATABASE> | t = <DATABASES> | t = <DICTIONARY> | t = <DICTIONARIES>
| t = <DISTINCT> | t = <ELSE> | t = <END> | t = <EXCEPT> | t = <FORMAT> | t = <FROM> | t = <FINAL> | t = <FULL>
| t = <FUNCTION> | t = <GLOBAL> | t = <GROUP> | t = <HAVING> | t = <IF> | t = <ILIKE> | t = <IN> | t = <INFILE> | t = <INNER>
| t = <INPUT> | t = <INTERVAL> | t = <INTO> | t = <IS> | t = <LEVEL> | t = <JOIN> | t = <LEFT> | t = <LIKE> | t = <LIMIT> | t = <LIVE>
| t = <MATERIALIZED> | t = <NOT> | t = <OFFSET> | t = <ON> | t = <OR> | t = <ORDER> | t = <OUTFILE> | t = <POLICY>
| t = <PREWHERE> | t = <PROFILE> | t = <QUOTA> | t = <REPLACE> | t = <RIGHT> | t = <ROLE> | t = <ROW> | t = <SAMPLE>
| t = <PREWHERE> | t = <PROFILE> | t = <QUOTA> | t = <REPLACE> | t = <RIGHT> | t = <ROLE> | t = <ROLLBACK> | t = <ROW> | t = <SAMPLE>
| t = <SETTINGS> | t = <STDOUT> | t = <TEMPORARY> | t = <TABLE> | t = <TABLES> | t = <THEN> | t = <TIES> | t = <TIMESTAMP>
| t = <TOP> | t = <TOTALS> | t = <VALUES> | t = <VIEW> | t = <USER> | t = <UNION> | t = <USING>
| t = <TOP> | t = <TOTALS> | t = <TRANSACTION> | t = <VALUES> | t = <VIEW> | t = <USER> | t = <UNION> | t = <USING>
| t = <WHEN> | t = <WHERE> | t = <WITH> | t = <REGEXP>
// interval
| t = <SECOND> | t = <MINUTE> | t = <HOUR> | t = <DAY> | t = <WEEK> | t = <MONTH> | t = <QUARTER> | t = <YEAR>
Expand All @@ -1063,32 +1095,11 @@ Token anyKeyword(): { Token t; } {
{ return t; }
}

Token keyword(): { Token t; } {
(
// leading keywords(except with)
t = <ALTER> | t = <ATTACH> | t = <CHECK> | t = <CREATE> | t = <DELETE> | t = <DESC> | t = <DESCRIBE>
| t = <DETACH> | t = <DROP> | t = <EXCHANGE> | t = <EXISTS> | t = <EXPLAIN> | t = <GRANT> | t = <INSERT> | t = <KILL>
| t = <MOVE> | t = <OPTIMIZE> | t = <RENAME> | t = <REVOKE> | t = <SELECT> | t = <SET> | t = <SHOW> | t = <SYSTEM>
| t = <TRUNCATE> | t = <UPDATE> | t = <USE> | t = <WATCH> | t = <UNDROP>
// others
| t = <CASE> | t = <CLUSTER> | t = <DATE> | t = <DATABASE> | t = <DATABASES> | t = <DICTIONARY>
| t = <DICTIONARIES> | t = <DISTINCT> | t = <ELSE> | t = <END> | t = <EXCEPT>| t = <FUNCTION>
| t = <IF> | t = <INTERVAL> | t = <IS> | t = <INFILE> | t = <LIVE> | t = <MATERIALIZED> | t = <OUTFILE> | t = <POLICY>
| t = <PROFILE> | t = <QUOTA> | t = <REPLACE> | t = <ROLE> | t = <ROW> | t = <TEMPORARY>
| t = <TABLE> | t = <TABLES> | t = <THEN> | t = <TIES> | t = <TIMESTAMP> | t = <TOP> | t = <TOTALS>
| t = <VALUES> | t = <VIEW> | t = <WHEN> | t = <USER> | t = <REGEXP>
// interval
| t = <SECOND> | t = <MINUTE> | t = <HOUR> | t = <DAY> | t = <WEEK> | t = <MONTH> | t = <QUARTER> | t = <YEAR>
// values
| t = <INF> | t = <NAN> | t = <NULL>
)
{ return t; }
}

// keywords
TOKEN: {
<ALTER : <A> <L> <T> <E> <R>>
| <ATTACH : <A> <T> <T> <A> <C> <H> >
| <CHANGED : <C> <H> <A> <N> <G> <E> <D> >
| <CHECK : <C> <H> <E> <C> <K> >
| <CREATE : <C> <R> <E> <A> <T> <E> >
| <DELETE : <D> <E> <L> <E> <T> <E> >
Expand Down
Loading
Loading