diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java index f484ac40cb..baa45ca017 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java @@ -239,6 +239,59 @@ public class Analyzer { return globalState.autoBroadcastJoinThreshold; } + private static class InferPredicateState { + // map from two table tuple ids to JoinOperator between two tables. + // NOTE: first tupleId's position in front of the second tupleId. + public final Map, JoinOperator> anyTwoTalesJoinOperator = Maps.newHashMap(); + + // slotEqSlotExpr: Record existing and infer equivalent connections + private final List onSlotEqSlotExpr = new ArrayList<>(); + + // slotEqSlotDeDuplication: De-Duplication for slotEqSlotExpr + private final Set> onSlotEqSlotDeDuplication = Sets.newHashSet(); + + // slotToLiteralExpr: Record existing and infer expr which slot and literal are equal + private final List onSlotToLiteralExpr = new ArrayList<>(); + + // slotToLiteralDeDuplication: De-Duplication for slotToLiteralExpr + private final Set> onSlotToLiteralDeDuplication = Sets.newHashSet(); + + // inExpr: Recoud existing and infer expr which in predicate + private final List onInExpr = new ArrayList<>(); + + // inExprDeDuplication: De-Duplication for inExpr + private final Set onInDeDuplication = Sets.newHashSet(); + + // isNullExpr: Record existing and infer not null predicate + private final List onIsNullExpr = new ArrayList<>(); + + //isNullDeDuplication: De-Duplication for isNullExpr + private final Set onIsNullDeDuplication = Sets.newHashSet(); + + // slotToLiteralDeDuplication: De-Duplication for slotToLiteralExpr. Contain on and where. + private final Set> globalSlotToLiteralDeDuplication = Sets.newHashSet(); + + // inExprDeDuplication: De-Duplication for inExpr. Contain on and where + private final Set globalInDeDuplication = Sets.newHashSet(); + + public InferPredicateState() { + } + + public InferPredicateState(InferPredicateState that) { + anyTwoTalesJoinOperator.putAll(that.anyTwoTalesJoinOperator); + onSlotEqSlotExpr.addAll(that.onSlotEqSlotExpr); + onSlotEqSlotDeDuplication.addAll(that.onSlotEqSlotDeDuplication); + onSlotToLiteralExpr.addAll(that.onSlotToLiteralExpr); + onSlotToLiteralDeDuplication.addAll(that.onSlotToLiteralDeDuplication); + onInExpr.addAll(that.onInExpr); + onInDeDuplication.addAll(that.onInDeDuplication); + onIsNullExpr.addAll(that.onIsNullExpr); + onIsNullDeDuplication.addAll(that.onIsNullDeDuplication); + globalSlotToLiteralDeDuplication.addAll(that.globalSlotToLiteralDeDuplication); + globalInDeDuplication.addAll(that.globalInDeDuplication); + } + } + // state shared between all objects of an Analyzer tree // TODO: Many maps here contain properties about tuples, e.g., whether // a tuple is outer/semi joined, etc. Remove the maps in favor of making @@ -322,40 +375,6 @@ public class Analyzer { // TODO chenhao16, to save conjuncts, which children are constant public final Map> constantConjunct = Maps.newHashMap(); - // map from two table tuple ids to JoinOperator between two tables. - // NOTE: first tupleId's position in front of the second tupleId. - public final Map, JoinOperator> anyTwoTalesJoinOperator = Maps.newHashMap(); - - // slotEqSlotExpr: Record existing and infer equivalent connections - private final List onSlotEqSlotExpr = new ArrayList<>(); - - // slotEqSlotDeDuplication: De-Duplication for slotEqSlotExpr - private final Set> onSlotEqSlotDeDuplication = Sets.newHashSet(); - - // slotToLiteralExpr: Record existing and infer expr which slot and literal are equal - private final List onSlotToLiteralExpr = new ArrayList<>(); - - // slotToLiteralDeDuplication: De-Duplication for slotToLiteralExpr - private final Set> onSlotToLiteralDeDuplication = Sets.newHashSet(); - - // inExpr: Recoud existing and infer expr which in predicate - private final List onInExpr = new ArrayList<>(); - - // inExprDeDuplication: De-Duplication for inExpr - private final Set onInDeDuplication = Sets.newHashSet(); - - // isNullExpr: Record existing and infer not null predicate - private final List onIsNullExpr = new ArrayList<>(); - - //isNullDeDuplication: De-Duplication for isNullExpr - private final Set onIsNullDeDuplication = Sets.newHashSet(); - - // slotToLiteralDeDuplication: De-Duplication for slotToLiteralExpr. Contain on and where. - private final Set> globalSlotToLiteralDeDuplication = Sets.newHashSet(); - - // inExprDeDuplication: De-Duplication for inExpr. Contain on and where - private final Set globalInDeDuplication = Sets.newHashSet(); - // map from slot id to the analyzer/block in which it was registered private final Map blockBySlot = Maps.newHashMap(); @@ -426,6 +445,8 @@ public class Analyzer { private final GlobalState globalState; + private final InferPredicateState inferPredicateState; + // An analyzer stores analysis state for a single select block. A select block can be // a top level select statement, or an inline view select block. // ancestors contains the Analyzers of the enclosing select blocks of 'this' @@ -460,6 +481,7 @@ public class Analyzer { public Analyzer(Env env, ConnectContext context) { ancestors = Lists.newArrayList(); globalState = new GlobalState(env, context); + inferPredicateState = new InferPredicateState(); } /** @@ -469,7 +491,7 @@ public class Analyzer { * @param parentAnalyzer the analyzer of the enclosing select block */ public Analyzer(Analyzer parentAnalyzer) { - this(parentAnalyzer, parentAnalyzer.globalState); + this(parentAnalyzer, parentAnalyzer.globalState, parentAnalyzer.inferPredicateState); if (parentAnalyzer.isSubquery) { this.isSubquery = true; } @@ -478,10 +500,11 @@ public class Analyzer { /** * Analyzer constructor for nested select block with the specified global state. */ - private Analyzer(Analyzer parentAnalyzer, GlobalState globalState) { + private Analyzer(Analyzer parentAnalyzer, GlobalState globalState, InferPredicateState inferPredicateState) { ancestors = Lists.newArrayList(parentAnalyzer); ancestors.addAll(parentAnalyzer.ancestors); this.globalState = globalState; + this.inferPredicateState = new InferPredicateState(inferPredicateState); } /** @@ -490,7 +513,7 @@ public class Analyzer { */ public static Analyzer createWithNewGlobalState(Analyzer parentAnalyzer) { GlobalState globalState = new GlobalState(parentAnalyzer.globalState.env, parentAnalyzer.getContext()); - return new Analyzer(parentAnalyzer, globalState); + return new Analyzer(parentAnalyzer, globalState, new InferPredicateState()); } public void setIsExplain() { @@ -1038,47 +1061,47 @@ public class Analyzer { if (joinOperator == null) { joinOperator = JoinOperator.INNER_JOIN; } - globalState.anyTwoTalesJoinOperator.put(tids, joinOperator); + inferPredicateState.anyTwoTalesJoinOperator.put(tids, joinOperator); } public void registerOnSlotEqSlotExpr(Expr expr) { - globalState.onSlotEqSlotExpr.add(expr); + inferPredicateState.onSlotEqSlotExpr.add(expr); } public void registerOnSlotEqSlotDeDuplication(Pair pair) { - globalState.onSlotEqSlotDeDuplication.add(pair); + inferPredicateState.onSlotEqSlotDeDuplication.add(pair); } public void registerOnSlotToLiteralExpr(Expr expr) { - globalState.onSlotToLiteralExpr.add(expr); + inferPredicateState.onSlotToLiteralExpr.add(expr); } public void registerOnSlotToLiteralDeDuplication(Pair pair) { - globalState.onSlotToLiteralDeDuplication.add(pair); + inferPredicateState.onSlotToLiteralDeDuplication.add(pair); } public void registerInExpr(Expr expr) { - globalState.onInExpr.add(expr); + inferPredicateState.onInExpr.add(expr); } public void registerInDeDuplication(Expr expr) { - globalState.onInDeDuplication.add(expr); + inferPredicateState.onInDeDuplication.add(expr); } public void registerOnIsNullExpr(Expr expr) { - globalState.onIsNullExpr.add(expr); + inferPredicateState.onIsNullExpr.add(expr); } public void registerOnIsNullDeDuplication(Expr expr) { - globalState.onIsNullDeDuplication.add(expr); + inferPredicateState.onIsNullDeDuplication.add(expr); } public void registerGlobalSlotToLiteralDeDuplication(Pair pair) { - globalState.globalSlotToLiteralDeDuplication.add(pair); + inferPredicateState.globalSlotToLiteralDeDuplication.add(pair); } public void registerGlobalInDeDuplication(Expr expr) { - globalState.globalInDeDuplication.add(expr); + inferPredicateState.globalInDeDuplication.add(expr); } public void registerConjunct(Expr e, TupleId tupleId) throws AnalysisException { @@ -1417,11 +1440,11 @@ public class Analyzer { * Return JoinOperator between two tables */ public JoinOperator getAnyTwoTablesJoinOp(Pair tids) { - return globalState.anyTwoTalesJoinOperator.get(tids); + return inferPredicateState.anyTwoTalesJoinOperator.get(tids); } public boolean isContainTupleIds(Pair tids) { - return globalState.anyTwoTalesJoinOperator.containsKey(tids); + return inferPredicateState.anyTwoTalesJoinOperator.containsKey(tids); } public boolean isWhereClauseConjunct(Expr e) { @@ -1518,43 +1541,43 @@ public class Analyzer { } public List getOnSlotEqSlotExpr() { - return new ArrayList<>(globalState.onSlotEqSlotExpr); + return new ArrayList<>(inferPredicateState.onSlotEqSlotExpr); } public Set> getOnSlotEqSlotDeDuplication() { - return Sets.newHashSet(globalState.onSlotEqSlotDeDuplication); + return Sets.newHashSet(inferPredicateState.onSlotEqSlotDeDuplication); } public List getOnSlotToLiteralExpr() { - return new ArrayList<>(globalState.onSlotToLiteralExpr); + return new ArrayList<>(inferPredicateState.onSlotToLiteralExpr); } public Set> getOnSlotToLiteralDeDuplication() { - return Sets.newHashSet(globalState.onSlotToLiteralDeDuplication); + return Sets.newHashSet(inferPredicateState.onSlotToLiteralDeDuplication); } public List getInExpr() { - return new ArrayList<>(globalState.onInExpr); + return new ArrayList<>(inferPredicateState.onInExpr); } public Set getInDeDuplication() { - return Sets.newHashSet(globalState.onInDeDuplication); + return Sets.newHashSet(inferPredicateState.onInDeDuplication); } public List getOnIsNullExpr() { - return new ArrayList<>(globalState.onIsNullExpr); + return new ArrayList<>(inferPredicateState.onIsNullExpr); } public Set getOnIsNullDeDuplication() { - return Sets.newHashSet(globalState.onIsNullDeDuplication); + return Sets.newHashSet(inferPredicateState.onIsNullDeDuplication); } public Set> getGlobalSlotToLiteralDeDuplication() { - return Sets.newHashSet(globalState.globalSlotToLiteralDeDuplication); + return Sets.newHashSet(inferPredicateState.globalSlotToLiteralDeDuplication); } public Set getGlobalInDeDuplication() { - return Sets.newHashSet(globalState.globalInDeDuplication); + return Sets.newHashSet(inferPredicateState.globalInDeDuplication); } /** diff --git a/regression-test/suites/correctness/test_infer_predicate.groovy b/regression-test/suites/correctness/test_infer_predicate.groovy new file mode 100644 index 0000000000..24ff31ac5b --- /dev/null +++ b/regression-test/suites/correctness/test_infer_predicate.groovy @@ -0,0 +1,114 @@ +// Licensed to the Apache Software Foundation (ASF) under one + // or more contributor license agreements. See the NOTICE file + // distributed with this work for additional information + // regarding copyright ownership. The ASF licenses this file + // to you under the Apache License, Version 2.0 (the + // "License"); you may not use this file except in compliance + // with the License. You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, + // software distributed under the License is distributed on an + // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + // KIND, either express or implied. See the License for the + // specific language governing permissions and limitations + // under the License. + +suite("test_infer_predicate") { + sql """ DROP TABLE IF EXISTS infer_predicate_t1 """ + sql """ DROP TABLE IF EXISTS infer_predicate_t2 """ + sql """ DROP VIEW IF EXISTS infer_predicate_v1 """ + sql """ DROP TABLE IF EXISTS infer_predicate_t4 """ + sql """ DROP TABLE IF EXISTS infer_predicate_t5 """ + sql""" + CREATE TABLE infer_predicate_t2 ( + a varchar(1) NULL COMMENT "", + x varchar(1) NULL COMMENT "", + c varchar(1) NULL COMMENT "" + ) ENGINE=OLAP + UNIQUE KEY(a) + DISTRIBUTED BY HASH(a) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default:1", + "in_memory" = "false", + "storage_format" = "V2" + ); + """ + + + sql""" + CREATE TABLE infer_predicate_t5 ( + x varchar(5) NULL COMMENT "", + d varchar(3) NULL COMMENT "" + ) ENGINE=OLAP + UNIQUE KEY(x) + DISTRIBUTED BY HASH(x) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default:1", + "in_memory" = "false", + "storage_format" = "V2" + ); + """ + + sql""" + CREATE TABLE infer_predicate_t4 ( + a varchar(1) NULL COMMENT "", + e varchar(1) NULL COMMENT "" + ) ENGINE=OLAP + UNIQUE KEY(a) + DISTRIBUTED BY HASH(a) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default:1", + "in_memory" = "false", + "storage_format" = "V2" + ); + """ + + + sql""" + CREATE TABLE infer_predicate_t1 ( + k1 varchar(20) NULL COMMENT "", + dt date NULL COMMENT "" + ) ENGINE=OLAP + UNIQUE KEY(k1) + DISTRIBUTED BY HASH(k1) BUCKETS 6 + PROPERTIES ( + "replication_allocation" = "tag.location.default:1", + "in_memory" = "false", + "storage_format" = "V2" + ); + """ + + sql""" + CREATE VIEW infer_predicate_v1 + AS + SELECT k1 + FROM infer_predicate_t1 + WHERE dt = ( + SELECT max(dt) + FROM infer_predicate_t1 + ); + """ + + try { + sql """ + select + f1.k1 + from ( + select + infer_predicate_t2.c as k1 + from infer_predicate_t5 + inner join infer_predicate_t2 on infer_predicate_t2.x=infer_predicate_t5.x + inner join infer_predicate_t4 on infer_predicate_t2.a=infer_predicate_t4.a and infer_predicate_t2.x in ('ZCR', 'ZDR') + ) f1 + left join infer_predicate_v1 on f1.k1=infer_predicate_v1.k1; + """ + } finally { + sql """ DROP TABLE IF EXISTS infer_predicate_t1 """ + sql """ DROP TABLE IF EXISTS infer_predicate_t2 """ + sql """ DROP VIEW IF EXISTS infer_predicate_v1 """ + sql """ DROP TABLE IF EXISTS infer_predicate_t4 """ + sql """ DROP TABLE IF EXISTS infer_predicate_t5 """ + } +}