Skip to content

Commit

Permalink
fix leading subquery
Browse files Browse the repository at this point in the history
  • Loading branch information
LiBinfeng-01 committed Aug 22, 2023
1 parent 8c99cac commit a878b9c
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.doris.nereids.glue.LogicalPlanAdapter;
import org.apache.doris.nereids.glue.translator.PhysicalPlanTranslator;
import org.apache.doris.nereids.glue.translator.PlanTranslatorContext;
import org.apache.doris.nereids.hint.Hint;
import org.apache.doris.nereids.jobs.executor.Optimizer;
import org.apache.doris.nereids.jobs.executor.Rewriter;
import org.apache.doris.nereids.memo.Group;
Expand Down Expand Up @@ -59,6 +60,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -342,36 +344,77 @@ private ScheduledExecutorService runTimeoutExecutor() {
return executor;
}

/**
* getting hints explain string, which specified by enumerate and show in lists
* @param hintMap hint map recorded in statement context
* @return explain string shows using of hint
*/
public String getHintExplainString(Map<String, Hint> hintMap) {
String used = "";
String unUsed = "";
String syntaxError = "";
for (Map.Entry<String, Hint> entry : hintMap.entrySet()) {
switch (entry.getValue().getStatus()) {
case UNUSED:
unUsed = unUsed + " " + entry.getValue().getExplainString();
break;
case SYNTAX_ERROR:
syntaxError = syntaxError + " " + entry.getValue().getExplainString()
+ " Msg:" + entry.getValue().getErrorMessage();
break;
case SUCCESS:
used = used + " " + entry.getValue().getExplainString();
break;
default:
break;
}
}
return "\nUsed: " + used + "\nUnUsed: " + unUsed + "\nSyntaxError: " + syntaxError;
}

@Override
public String getExplainString(ExplainOptions explainOptions) {
ExplainLevel explainLevel = getExplainLevel(explainOptions);
String plan = "";
switch (explainLevel) {
case PARSED_PLAN:
return parsedPlan.treeString();
plan = parsedPlan.treeString();
break;
case ANALYZED_PLAN:
return analyzedPlan.treeString();
plan = analyzedPlan.treeString();
break;
case REWRITTEN_PLAN:
return rewrittenPlan.treeString();
plan = rewrittenPlan.treeString();
break;
case OPTIMIZED_PLAN:
return "cost = " + cost + "\n" + optimizedPlan.treeString();
plan = "cost = " + cost + "\n" + optimizedPlan.treeString();
break;
case SHAPE_PLAN:
return optimizedPlan.shape("");
plan = optimizedPlan.shape("");
break;
case MEMO_PLAN:
return cascadesContext.getMemo().toString()
plan = cascadesContext.getMemo().toString()
+ "\n\n========== OPTIMIZED PLAN ==========\n"
+ optimizedPlan.treeString();
break;
case ALL_PLAN:
return "========== PARSED PLAN ==========\n"
plan = "========== PARSED PLAN ==========\n"
+ parsedPlan.treeString() + "\n\n"
+ "========== ANALYZED PLAN ==========\n"
+ analyzedPlan.treeString() + "\n\n"
+ "========== REWRITTEN PLAN ==========\n"
+ rewrittenPlan.treeString() + "\n\n"
+ "========== OPTIMIZED PLAN ==========\n"
+ optimizedPlan.treeString();
break;
default:
return super.getExplainString(explainOptions);
plan = super.getExplainString(explainOptions);
}
if (!cascadesContext.getStatementContext().getHintMap().isEmpty()) {
String hint = getHintExplainString(cascadesContext.getStatementContext().getHintMap());
return plan + hint;
}
return plan;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public class StatementContext {
private boolean isDpHyp = false;
private boolean isOtherJoinReorder = false;

private boolean isLeadingJoin = false;

private final IdGenerator<ExprId> exprIdGenerator = ExprId.createGenerator();
private final IdGenerator<ObjectId> objectIdGenerator = ObjectId.createGenerator();
private final IdGenerator<RelationId> relationIdGenerator = RelationId.createGenerator();
Expand Down Expand Up @@ -134,6 +136,14 @@ public void setDpHyp(boolean dpHyp) {
isDpHyp = dpHyp;
}

public boolean isLeadingJoin() {
return isLeadingJoin;
}

public void setLeadingJoin(boolean leadingJoin) {
isLeadingJoin = leadingJoin;
}

public boolean isOtherJoinReorder() {
return isOtherJoinReorder;
}
Expand Down
16 changes: 15 additions & 1 deletion fe/fe-core/src/main/java/org/apache/doris/nereids/hint/Hint.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class Hint {

private HintStatus status;

private final String errorMessage = "";
private String errorMessage = "";

/**
* hint status which need to show in explain when it is not used or have syntax error
Expand Down Expand Up @@ -68,4 +68,18 @@ public boolean isSyntaxError() {
public String getHintName() {
return hintName;
}

public String getErrorMessage() {
return errorMessage;
}

public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}

public String getExplainString() {
StringBuilder out = new StringBuilder();
out.append("\nHint:\n");
return out.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
* e.g. set_var(query_timeout='1800', exec_mem_limit='2147483648')
*/
public class LeadingHint extends Hint {
// e.g. query_timeout='1800', exec_mem_limit='2147483648'
private String originalString = "";
private final List<String> tablelist = new ArrayList<>();
private final List<Integer> levellist = new ArrayList<>();

Expand All @@ -72,8 +72,9 @@ public LeadingHint(String hintName) {
* @param hintName Leading
* @param parameters table name mixed with left and right brace
*/
public LeadingHint(String hintName, List<String> parameters) {
public LeadingHint(String hintName, List<String> parameters, String originalString) {
super(hintName);
this.originalString = originalString;
int level = 0;
for (String parameter : parameters) {
if (parameter.equals("{")) {
Expand All @@ -99,8 +100,26 @@ public Map<RelationId, LogicalPlan> getRelationIdToScanMap() {
return relationIdToScanMap;
}

@Override
public String getExplainString() {
StringBuilder out = new StringBuilder();
out.append(originalString);
return out.toString();
}

/**
* Get logical plan by table name recorded in leading hint. if can not get, means leading has syntax error
* or need to update. So return null should be deal with when call
* @param name table name
* @return logical plan recorded when binding
*/
public LogicalPlan getLogicalPlanByName(String name) {
RelationId id = findRelationIdAndTableName(name);
if (id == null) {
this.setStatus(HintStatus.SYNTAX_ERROR);
this.setErrorMessage("can not find table: " + name);
return null;
}
return relationIdToScanMap.get(id);
}

Expand Down Expand Up @@ -310,6 +329,9 @@ public Plan generateLeadingJoinPlan() {
Stack<Pair<Integer, LogicalPlan>> stack = new Stack<>();
int index = 0;
LogicalPlan logicalPlan = getLogicalPlanByName(getTablelist().get(index));
if (logicalPlan == null) {
return null;
}
logicalPlan = makeFilterPlanIfExist(getFilters(), logicalPlan);
assert (logicalPlan != null);
stack.push(Pair.of(getLevellist().get(index), logicalPlan));
Expand All @@ -319,6 +341,9 @@ public Plan generateLeadingJoinPlan() {
if (currentLevel == stackTopLevel) {
// should return error if can not found table
logicalPlan = getLogicalPlanByName(getTablelist().get(index++));
if (logicalPlan == null) {
return null;
}
logicalPlan = makeFilterPlanIfExist(getFilters(), logicalPlan);
Pair<Integer, LogicalPlan> newStackTop = stack.peek();
while (!(stack.isEmpty() || stackTopLevel != newStackTop.first)) {
Expand Down Expand Up @@ -353,6 +378,9 @@ public Plan generateLeadingJoinPlan() {
} else {
// push
logicalPlan = getLogicalPlanByName(getTablelist().get(index++));
if (logicalPlan == null) {
return null;
}
logicalPlan = makeFilterPlanIfExist(getFilters(), logicalPlan);
stack.push(Pair.of(currentLevel, logicalPlan));
stackTopLevel = currentLevel;
Expand Down Expand Up @@ -440,15 +468,13 @@ private Long getBitmap(LogicalPlan root) {
public Long getLeadingTableBitmap() {
Long totalBitmap = 0L;
for (int index = 0; index < getTablelist().size(); index++) {
totalBitmap = LongBitmap.set(totalBitmap, findRelationIdAndTableName(getTablelist().get(index)).asInt());
}
return totalBitmap;
}

public Long computeTableBitmap(Set<RelationId> relationIdSet) {
Long totalBitmap = 0L;
for (RelationId id : relationIdSet) {
totalBitmap = LongBitmap.set(totalBitmap, (id.asInt()));
RelationId id = findRelationIdAndTableName(getTablelist().get(index));
if (id == null) {
this.setStatus(HintStatus.SYNTAX_ERROR);
this.setErrorMessage("can not find table: " + getTablelist().get(index));
return totalBitmap;
}
totalBitmap = LongBitmap.set(totalBitmap, id.asInt());
}
return totalBitmap;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,15 @@ public class Rewriter extends AbstractBatchJobExecutor {
bottomUp(new EliminateNotNull()),
topDown(new ConvertInnerOrCrossJoin())
),
topic("LEADING JOIN",
bottomUp(
new CollectJoinConstraint()
),
custom(RuleType.LEADING_JOIN, LeadingJoin::new),
bottomUp(
new ExpressionRewrite(CheckLegalityAfterRewrite.INSTANCE)
)
),
topic("Column pruning and infer predicate",
custom(RuleType.COLUMN_PRUNING, ColumnPruning::new),
custom(RuleType.INFER_PREDICATES, InferPredicates::new),
Expand Down Expand Up @@ -317,15 +326,6 @@ public class Rewriter extends AbstractBatchJobExecutor {

topic("eliminate empty relation",
bottomUp(new EliminateEmptyRelation())
),
topic("LEADING JOIN",
bottomUp(
new CollectJoinConstraint()
),
custom(RuleType.LEADING_JOIN, LeadingJoin::new),
bottomUp(
new ExpressionRewrite(CheckLegalityAfterRewrite.INSTANCE)
)
)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@

package org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap;

import org.apache.doris.nereids.trees.plans.RelationId;

import java.util.BitSet;
import java.util.Set;

/**
* This is helper class for some bitmap operation
Expand Down Expand Up @@ -147,6 +150,14 @@ public static int lowestOneIndex(long bitmap) {
return Long.numberOfTrailingZeros(bitmap);
}

public static Long computeTableBitmap(Set<RelationId> relationIdSet) {
Long totalBitmap = 0L;
for (RelationId id : relationIdSet) {
totalBitmap = LongBitmap.set(totalBitmap, (id.asInt()));
}
return totalBitmap;
}

public static String toString(long bitmap) {
long[] longs = {bitmap};
BitSet bitSet = BitSet.valueOf(longs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ private void setVar(SelectHintSetVar selectHint, StatementContext context) {
}

private void extractLeading(SelectHintLeading selectHint, StatementContext context) {
LeadingHint hint = new LeadingHint("Leading", selectHint.getParameters());
LeadingHint hint = new LeadingHint("Leading", selectHint.getParameters(), selectHint.toString());
context.getHintMap().put("Leading", hint);
context.setLeadingJoin(true);
assert (selectHint != null);
assert (context != null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public List<String> getParameters() {
public String toString() {
String leadingString = parameters
.stream()
.collect(Collectors.joining(", "));
.collect(Collectors.joining(" "));
return super.getHintName() + "(" + leadingString + ")";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
import org.apache.doris.nereids.trees.plans.logical.LogicalJdbcScan;
import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalSchemaScan;
import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
import org.apache.doris.nereids.util.RelationUtil;
Expand Down Expand Up @@ -130,11 +129,11 @@ private LogicalPlan bindWithCurrentDb(CascadesContext cascadesContext, UnboundRe
if (analyzedCte.isPresent()) {
LogicalCTEConsumer consumer = new LogicalCTEConsumer(unboundRelation.getRelationId(),
cteContext.getCteId(), tableName, analyzedCte.get());
if (cascadesContext.getStatementContext().getHintMap().get("Leading") != null) {
((LeadingHint) cascadesContext.getStatementContext().getHintMap().get("Leading"))
.putRelationIdAndTableName(Pair.of(consumer.getRelationId(), tableName));
((LeadingHint) cascadesContext.getStatementContext().getHintMap().get("Leading"))
.getRelationIdToScanMap().put(consumer.getRelationId(), consumer);
if (cascadesContext.getStatementContext().isLeadingJoin()) {
LeadingHint leading = (LeadingHint) cascadesContext.getStatementContext()
.getHintMap().get("Leading");
leading.putRelationIdAndTableName(Pair.of(consumer.getRelationId(), tableName));
leading.getRelationIdToScanMap().put(consumer.getRelationId(), consumer);
}
return consumer;
}
Expand All @@ -158,11 +157,10 @@ private LogicalPlan bindWithCurrentDb(CascadesContext cascadesContext, UnboundRe

// TODO: should generate different Scan sub class according to table's type
LogicalPlan scan = getLogicalPlan(table, unboundRelation, tableQualifier, cascadesContext);
if (cascadesContext.getStatementContext().getHintMap().get("Leading") != null) {
((LeadingHint) cascadesContext.getStatementContext().getHintMap().get("Leading"))
.putRelationIdAndTableName(Pair.of(((LogicalRelation) scan).getRelationId(), tableName));
((LeadingHint) cascadesContext.getStatementContext().getHintMap().get("Leading"))
.getRelationIdToScanMap().put(((LogicalRelation) scan).getRelationId(), scan);
if (cascadesContext.getStatementContext().isLeadingJoin()) {
LeadingHint leading = (LeadingHint) cascadesContext.getStatementContext().getHintMap().get("Leading");
leading.putRelationIdAndTableName(Pair.of(unboundRelation.getRelationId(), tableName));
leading.getRelationIdToScanMap().put(unboundRelation.getRelationId(), scan);
}
return scan;
}
Expand Down
Loading

0 comments on commit a878b9c

Please sign in to comment.