-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[feat](Nereids) support nereids hint position detaction #39113
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,7 @@ | |
| import org.apache.doris.qe.SessionVariable; | ||
|
|
||
| import com.google.common.collect.Lists; | ||
| import com.google.common.collect.Maps; | ||
| import org.antlr.v4.runtime.CharStreams; | ||
| import org.antlr.v4.runtime.CommonTokenStream; | ||
| import org.antlr.v4.runtime.ParserRuleContext; | ||
|
|
@@ -273,26 +274,56 @@ private <T> T parse(String sql, @Nullable LogicalPlanBuilder logicalPlanBuilder, | |
| Function<DorisParser, ParserRuleContext> parseFunction) { | ||
| ParserRuleContext tree = toAst(sql, parseFunction); | ||
| LogicalPlanBuilder realLogicalPlanBuilder = logicalPlanBuilder == null | ||
| ? new LogicalPlanBuilder() : logicalPlanBuilder; | ||
| ? new LogicalPlanBuilder(getHintMap(sql, DorisParser::selectHint)) : logicalPlanBuilder; | ||
| return (T) realLogicalPlanBuilder.visit(tree); | ||
| } | ||
|
|
||
| public LogicalPlan parseForCreateView(String sql) { | ||
| ParserRuleContext tree = toAst(sql, DorisParser::singleStatement); | ||
| LogicalPlanBuilder realLogicalPlanBuilder = new LogicalPlanBuilderForCreateView(); | ||
| LogicalPlanBuilder realLogicalPlanBuilder = new LogicalPlanBuilderForCreateView( | ||
| getHintMap(sql, DorisParser::selectHint)); | ||
| return (LogicalPlan) realLogicalPlanBuilder.visit(tree); | ||
| } | ||
|
|
||
| public Optional<String> parseForSyncMv(String sql) { | ||
| ParserRuleContext tree = toAst(sql, DorisParser::singleStatement); | ||
| LogicalPlanBuilderForSyncMv logicalPlanBuilderForSyncMv = new LogicalPlanBuilderForSyncMv(); | ||
| LogicalPlanBuilderForSyncMv logicalPlanBuilderForSyncMv = new LogicalPlanBuilderForSyncMv( | ||
| getHintMap(sql, DorisParser::selectHint)); | ||
| logicalPlanBuilderForSyncMv.visit(tree); | ||
| return logicalPlanBuilderForSyncMv.getQuerySql(); | ||
| } | ||
|
|
||
| /** get hint map */ | ||
| public static Map<Integer, ParserRuleContext> getHintMap(String sql, | ||
| Function<DorisParser, ParserRuleContext> parseFunction) { | ||
| // parse hint first round | ||
| DorisLexer hintLexer = new DorisLexer(new CaseInsensitiveStream(CharStreams.fromString(sql))); | ||
| hintLexer.setChannel2(true); | ||
| CommonTokenStream hintTokenStream = new CommonTokenStream(hintLexer); | ||
|
Comment on lines
+300
to
+302
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. antlr could generate one stream and get specific channel token from it by
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. getHiddenTokensToRight does not work in this case, I tried to get it but it failed. I try to use List hintTokens = hintTokenStream.getHiddenTokensToRight(0, 2); but it failed to get token list out from channel2 |
||
|
|
||
| Map<Integer, ParserRuleContext> selectHintMap = Maps.newHashMap(); | ||
|
|
||
| Token hintToken = hintTokenStream.getTokenSource().nextToken(); | ||
| while (hintToken != null && hintToken.getType() != DorisLexer.EOF) { | ||
| int tokenType = hintToken.getType(); | ||
| if (tokenType == DorisLexer.HINT_WITH_CHANNEL) { | ||
| String hintSql = sql.substring(hintToken.getStartIndex(), hintToken.getStopIndex() + 1); | ||
| DorisLexer newHintLexer = new DorisLexer(new CaseInsensitiveStream(CharStreams.fromString(hintSql))); | ||
| newHintLexer.setChannel2(false); | ||
| CommonTokenStream newHintTokenStream = new CommonTokenStream(newHintLexer); | ||
| DorisParser hintParser = new DorisParser(newHintTokenStream); | ||
| ParserRuleContext hintContext = parseFunction.apply(hintParser); | ||
|
Comment on lines
+313
to
+315
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could write a new parser to process hint seperately?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is no need to write a new parser but use exist parser logic as hint syntax, the only thing we need to care about is position and new hint type, position is solved by selectHintMap we added, new hint type is filtered by original hint parser. So it is no needed to add a new parser with same logic, we can only use channel 2 to deal with hint seperately |
||
| selectHintMap.put(hintToken.getStartIndex(), hintContext); | ||
| } | ||
| hintToken = hintTokenStream.getTokenSource().nextToken(); | ||
| } | ||
| return selectHintMap; | ||
| } | ||
|
|
||
| /** toAst */ | ||
| public static ParserRuleContext toAst(String sql, Function<DorisParser, ParserRuleContext> parseFunction) { | ||
| DorisLexer lexer = new DorisLexer(new CaseInsensitiveStream(CharStreams.fromString(sql))); | ||
| lexer.setChannel2(true); | ||
| CommonTokenStream tokenStream = new CommonTokenStream(lexer); | ||
| DorisParser parser = new DorisParser(tokenStream); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,10 @@ | |
| */ | ||
| public class PLSqlLogicalPlanBuilder extends LogicalPlanBuilder { | ||
|
|
||
| public PLSqlLogicalPlanBuilder() { | ||
| super(null); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as create view
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| } | ||
|
|
||
| public List<String> visitMultipartIdentifier(MultipartIdentifierContext ctx) { | ||
| return ctx.parts.stream() | ||
| .map(RuleContext::getText) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why need this var? i think we should always let hint go to channel 2 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when i let channel 2 always open, it would have problem when parsing because in channel lexer would add some char before original string to let parser ignore it. For example: it would make "/* leading(t1 t2) */" into "[@-1,15:36 = '/leading(t1 t2) */', xxx" which when i want to parse it, i would meet eof first then parse exit. So it make a switch to control this behavior