[fix](optimization) InferFiltersRule bug: a self inner join on a view, which contains where clause, will cause mis-inference. (#11566)

This commit is contained in:
minghong
2022-08-11 17:13:26 +08:00
committed by GitHub
parent 9214346603
commit 2d5ffac590
6 changed files with 97 additions and 1 deletions

View File

@ -152,6 +152,17 @@ public class Analyzer {
// Flag indicating if this analyzer instance belongs to a subquery.
private boolean isSubquery = false;
public boolean isInlineView() {
return isInlineView;
}
public void setInlineView(boolean inlineView) {
isInlineView = inlineView;
}
// Flag indicating if this analyzer instance belongs to an inlineview.
private boolean isInlineView = false;
// Flag indicating whether this analyzer belongs to a WITH clause view.
private boolean isWithClause = false;
@ -776,6 +787,21 @@ public class Analyzer {
d = resolveColumnRef(colName);
} else {
d = resolveColumnRef(newTblName, colName);
//in reanalyze, the inferred expr may contain upper level table alias, and the upper level alias has not
// been PROCESSED. So we resolve this column without tbl name.
// For example: a view V "select * from t where t.a>1"
// sql: select * from V as t1 join V as t2 on t1.a=t2.a and t1.a in (1,2)
// after first analyze, sql becomes:
// select * from V as t1 join V as t2 on t1.a=t2.a and t1.a in (1,2) and t2.a in (1, 2)
// in reanalyze, when we process V as t2, we indeed process sql like this:
// select * from t where t.a>1 and t2.a in (1, 2)
// in order to resolve t2.a, we have to ignore "t2"
// ===================================================
// Someone may concern that if t2 is not alias of t, this fix will cause incorrect resolve. In fact,
// this does not happen, since we push t2.a in (1.2) down to this inline view, t2 must be alias of t.
if (d == null && isInlineView) {
d = resolveColumnRef(colName);
}
}
/*
* Now, we only support the columns in the subquery to associate the outer query columns in parent level.

View File

@ -185,7 +185,7 @@ public class InlineViewRef extends TableRef {
// Analyze the inline view query statement with its own analyzer
inlineViewAnalyzer = new Analyzer(analyzer);
inlineViewAnalyzer.setInlineView(true);
queryStmt.analyze(inlineViewAnalyzer);
correlatedTupleIds.addAll(queryStmt.getCorrelatedTupleIds(inlineViewAnalyzer));

View File

@ -1346,6 +1346,11 @@ public class SelectStmt extends QueryStmt {
ref.rewriteExprs(rewriter, analyzer);
}
// Also equal exprs in the statements of subqueries.
// TODO: (minghong) if this a view, even no whereClause,
// we should analyze whereClause to enable filter inference
// for example, a view without where clause, `V`,
// `select * from T join V on T.id = V.id and T.id=1`
// we could infer `V.id=1`
List<Subquery> subqueryExprs = Lists.newArrayList();
if (whereClause != null) {
whereClause = rewriter.rewrite(whereClause, analyzer, ExprRewriter.ClauseType.WHERE_CLAUSE);

View File

@ -129,6 +129,9 @@ public class PredicatePushDown {
}
}
// TODO: (minghong) here is a bug. For example, this is a left join, we cannot infer "t2.id = 1"
// by "t1.id=1" and "t1.id=t2.id".
// we should not do inference work here. it should be done in some rule like InferFilterRule.
// Rewrite the oldPredicate with new leftChild
// For example: oldPredicate is t1.id = 1, leftChild is t2.id, will return t2.id = 1
private static Expr rewritePredicate(Analyzer analyzer, Expr oldPredicate, Expr leftChild) {