cherry-pick: #39113 When use hint in wrong position or use unsupport hint, use channel(2) to filter it out ## Proposed changes Issue Number: close #xxx <!--Describe your changes.-->
This commit is contained in:
@ -499,6 +499,12 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
return pos1.getCharPositionInLine() - pos2.getCharPositionInLine();
|
||||
});
|
||||
|
||||
private final Map<Integer, ParserRuleContext> selectHintMap;
|
||||
|
||||
public LogicalPlanBuilder(Map<Integer, ParserRuleContext> selectHintMap) {
|
||||
this.selectHintMap = selectHintMap;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T typedVisit(ParseTree ctx) {
|
||||
return (T) ctx.accept(this);
|
||||
@ -1331,7 +1337,16 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
Optional.ofNullable(ctx.aggClause()),
|
||||
Optional.ofNullable(ctx.havingClause()));
|
||||
selectPlan = withQueryOrganization(selectPlan, ctx.queryOrganization());
|
||||
return withSelectHint(selectPlan, selectCtx.selectHint());
|
||||
if ((selectHintMap == null) || selectHintMap.isEmpty()) {
|
||||
return selectPlan;
|
||||
}
|
||||
List<ParserRuleContext> selectHintContexts = Lists.newArrayList();
|
||||
for (Integer key : selectHintMap.keySet()) {
|
||||
if (key > selectCtx.getStart().getStopIndex() && key < selectCtx.getStop().getStartIndex()) {
|
||||
selectHintContexts.add(selectHintMap.get(key));
|
||||
}
|
||||
}
|
||||
return withSelectHint(selectPlan, selectHintContexts);
|
||||
});
|
||||
}
|
||||
|
||||
@ -3068,47 +3083,50 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
|
||||
return last;
|
||||
}
|
||||
|
||||
private LogicalPlan withSelectHint(LogicalPlan logicalPlan, SelectHintContext hintContext) {
|
||||
if (hintContext == null) {
|
||||
private LogicalPlan withSelectHint(LogicalPlan logicalPlan, List<ParserRuleContext> hintContexts) {
|
||||
if (hintContexts.isEmpty()) {
|
||||
return logicalPlan;
|
||||
}
|
||||
Map<String, SelectHint> hints = Maps.newLinkedHashMap();
|
||||
for (HintStatementContext hintStatement : hintContext.hintStatements) {
|
||||
String hintName = hintStatement.hintName.getText().toLowerCase(Locale.ROOT);
|
||||
switch (hintName) {
|
||||
case "set_var":
|
||||
Map<String, Optional<String>> parameters = Maps.newLinkedHashMap();
|
||||
for (HintAssignmentContext kv : hintStatement.parameters) {
|
||||
if (kv.key != null) {
|
||||
String parameterName = visitIdentifierOrText(kv.key);
|
||||
Optional<String> value = Optional.empty();
|
||||
if (kv.constantValue != null) {
|
||||
Literal literal = (Literal) visit(kv.constantValue);
|
||||
value = Optional.ofNullable(literal.toLegacyLiteral().getStringValue());
|
||||
} else if (kv.identifierValue != null) {
|
||||
// maybe we should throw exception when the identifierValue is quoted identifier
|
||||
value = Optional.ofNullable(kv.identifierValue.getText());
|
||||
for (ParserRuleContext hintContext : hintContexts) {
|
||||
SelectHintContext selectHintContext = (SelectHintContext) hintContext;
|
||||
for (HintStatementContext hintStatement : selectHintContext.hintStatements) {
|
||||
String hintName = hintStatement.hintName.getText().toLowerCase(Locale.ROOT);
|
||||
switch (hintName) {
|
||||
case "set_var":
|
||||
Map<String, Optional<String>> parameters = Maps.newLinkedHashMap();
|
||||
for (HintAssignmentContext kv : hintStatement.parameters) {
|
||||
if (kv.key != null) {
|
||||
String parameterName = visitIdentifierOrText(kv.key);
|
||||
Optional<String> value = Optional.empty();
|
||||
if (kv.constantValue != null) {
|
||||
Literal literal = (Literal) visit(kv.constantValue);
|
||||
value = Optional.ofNullable(literal.toLegacyLiteral().getStringValue());
|
||||
} else if (kv.identifierValue != null) {
|
||||
// maybe we should throw exception when the identifierValue is quoted identifier
|
||||
value = Optional.ofNullable(kv.identifierValue.getText());
|
||||
}
|
||||
parameters.put(parameterName, value);
|
||||
}
|
||||
parameters.put(parameterName, value);
|
||||
}
|
||||
}
|
||||
hints.put(hintName, new SelectHintSetVar(hintName, parameters));
|
||||
break;
|
||||
case "leading":
|
||||
List<String> leadingParameters = new ArrayList<String>();
|
||||
for (HintAssignmentContext kv : hintStatement.parameters) {
|
||||
if (kv.key != null) {
|
||||
String parameterName = visitIdentifierOrText(kv.key);
|
||||
leadingParameters.add(parameterName);
|
||||
hints.put(hintName, new SelectHintSetVar(hintName, parameters));
|
||||
break;
|
||||
case "leading":
|
||||
List<String> leadingParameters = new ArrayList<String>();
|
||||
for (HintAssignmentContext kv : hintStatement.parameters) {
|
||||
if (kv.key != null) {
|
||||
String parameterName = visitIdentifierOrText(kv.key);
|
||||
leadingParameters.add(parameterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
hints.put(hintName, new SelectHintLeading(hintName, leadingParameters));
|
||||
break;
|
||||
case "ordered":
|
||||
hints.put(hintName, new SelectHintOrdered(hintName));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
hints.put(hintName, new SelectHintLeading(hintName, leadingParameters));
|
||||
break;
|
||||
case "ordered":
|
||||
hints.put(hintName, new SelectHintOrdered(hintName));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new LogicalSelectHint<>(hints, logicalPlan);
|
||||
|
||||
@ -52,10 +52,15 @@ import org.apache.doris.qe.ConnectContext;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**LogicalPlanBuilderForCreateView*/
|
||||
public class LogicalPlanBuilderForCreateView extends LogicalPlanBuilder {
|
||||
public LogicalPlanBuilderForCreateView(Map<Integer, ParserRuleContext> selectHintMap) {
|
||||
super(selectHintMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LogicalPlan withGenerate(LogicalPlan plan, LateralViewContext ctx) {
|
||||
ConnectContext.get().getStatementContext().addIndexInSqlToString(
|
||||
|
||||
@ -36,6 +36,7 @@ import org.apache.doris.qe.ConnectContext;
|
||||
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,16 +274,41 @@ public class NereidsParser {
|
||||
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);
|
||||
}
|
||||
|
||||
/** 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)));
|
||||
CommonTokenStream hintTokenStream = new CommonTokenStream(hintLexer);
|
||||
|
||||
Map<Integer, ParserRuleContext> selectHintMap = Maps.newHashMap();
|
||||
|
||||
Token hintToken = hintTokenStream.getTokenSource().nextToken();
|
||||
while (hintToken != null && hintToken.getType() != DorisLexer.EOF) {
|
||||
if (hintToken.getChannel() == 2 && sql.charAt(hintToken.getStartIndex() + 2) == '+') {
|
||||
String hintSql = sql.substring(hintToken.getStartIndex() + 3, hintToken.getStopIndex() + 1);
|
||||
DorisLexer newHintLexer = new DorisLexer(new CaseInsensitiveStream(CharStreams.fromString(hintSql)));
|
||||
CommonTokenStream newHintTokenStream = new CommonTokenStream(newHintLexer);
|
||||
DorisParser hintParser = new DorisParser(newHintTokenStream);
|
||||
ParserRuleContext hintContext = parseFunction.apply(hintParser);
|
||||
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)));
|
||||
|
||||
@ -36,6 +36,10 @@ import java.util.List;
|
||||
*/
|
||||
public class PLSqlLogicalPlanBuilder extends LogicalPlanBuilder {
|
||||
|
||||
public PLSqlLogicalPlanBuilder() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public List<String> visitMultipartIdentifier(MultipartIdentifierContext ctx) {
|
||||
return ctx.parts.stream()
|
||||
.map(RuleContext::getText)
|
||||
|
||||
Reference in New Issue
Block a user