This is an automated email from the ASF dual-hosted git repository. panxiaolei pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new f4ed52906a [Feature](Materialized-View) change mv rewrite from bottom up to up bottom && Compatible with old … (#16750) f4ed52906a is described below commit f4ed52906ac5783858f22a5e10e318b4bea986f2 Author: Pxl <pxl...@qq.com> AuthorDate: Wed Feb 15 17:24:46 2023 +0800 [Feature](Materialized-View) change mv rewrite from bottom up to up bottom && Compatible with old … (#16750) 1.change mv rewrite from bottom up to up bottom 2.compatible with old version mv 3.restore some ut codes (but disable) 4. fix some ut introduced by [fix](planner)fix bug for missing slot #16601 and [Feature](Materialized-View) support multiple slot on one column in materialized view #16378 --- .../doris/analysis/CreateMaterializedViewStmt.java | 17 ++ .../java/org/apache/doris/analysis/QueryStmt.java | 1 + .../main/java/org/apache/doris/catalog/Column.java | 12 ++ .../doris/catalog/MaterializedIndexMeta.java | 52 +++++- .../java/org/apache/doris/catalog/OlapTable.java | 6 +- .../main/java/org/apache/doris/catalog/Table.java | 2 +- .../apache/doris/planner/SingleNodePlanner.java | 4 +- .../org/apache/doris/rewrite/ExprRewriter.java | 72 +++++++-- .../doris/rewrite/mvrewrite/ExprToSlotRefRule.java | 2 +- .../planner/MaterializedViewFunctionTest.java | 3 +- .../planner/MaterializedViewSelectorTest.java | 177 +++++++++++++++++++++ 11 files changed, 322 insertions(+), 26 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java index 5fe8244019..76c86c62b3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java @@ -496,6 +496,23 @@ public class CreateMaterializedViewStmt extends DdlStmt { return name; } + public static String oldmvColumnBreaker(String name) { + if (name.startsWith(MATERIALIZED_VIEW_NAME_PREFIX)) { + // mv_count_k2 -> k2 + name = name.substring(MATERIALIZED_VIEW_NAME_PREFIX.length()); + for (String prefix : FN_NAME_TO_PATTERN.keySet()) { + if (name.startsWith(prefix)) { + return name.substring(prefix.length() + 1); + } + } + } + if (name.startsWith(MATERIALIZED_VIEW_NAME_PREFIX)) { + // mv_k2 -> k2 + return mvColumnBreaker(name.substring(MATERIALIZED_VIEW_NAME_PREFIX.length())); + } + return name; + } + public static boolean isMVColumn(String name) { return isMVColumnAggregate(name) || isMVColumnNormal(name); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/QueryStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/QueryStmt.java index 2181d30fd3..3564cb2927 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/QueryStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/QueryStmt.java @@ -281,6 +281,7 @@ public abstract class QueryStmt extends StatementBase implements Queriable { ExprRewriter rewriter = analyzer.getMVExprRewriter(); rewriter.reset(); rewriter.setDisableTuplesMVRewriter(disableTuplesMVRewriter); + rewriter.setUpBottom(); Expr result = rewriter.rewrite(expr, analyzer); if (result != expr) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java index 3c0da6dab2..2a1f5de023 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java @@ -111,6 +111,7 @@ public class Column implements Writable, GsonPostProcessable { // so the define expr in RollupJob must be analyzed. // In other cases, such as define expr in `MaterializedIndexMeta`, it may not be analyzed after being replayed. private Expr defineExpr; // use to define column in materialize view + private String defineName = null; @SerializedName(value = "visible") private boolean visible; @SerializedName(value = "defaultValueExprDef") @@ -236,6 +237,17 @@ public class Column implements Writable, GsonPostProcessable { this.children.add(column); } + public void setDefineName(String defineName) { + this.defineName = defineName; + } + + public String getDefineName() { + if (defineName != null) { + return defineName; + } + return name; + } + public void setName(String newName) { this.name = newName; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/MaterializedIndexMeta.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/MaterializedIndexMeta.java index a45ebdbfca..455a86b88e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/MaterializedIndexMeta.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/MaterializedIndexMeta.java @@ -19,6 +19,7 @@ package org.apache.doris.catalog; import org.apache.doris.analysis.CreateMaterializedViewStmt; import org.apache.doris.analysis.Expr; +import org.apache.doris.analysis.SlotRef; import org.apache.doris.analysis.SqlParser; import org.apache.doris.analysis.SqlScanner; import org.apache.doris.common.io.Text; @@ -40,6 +41,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.StringReader; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -136,14 +138,62 @@ public class MaterializedIndexMeta implements Writable, GsonPostProcessable { return schemaVersion; } - private void setColumnsDefineExpr(Map<String, Expr> columnNameToDefineExpr) { + private void setColumnsDefineExpr(Map<String, Expr> columnNameToDefineExpr) throws IOException { for (Map.Entry<String, Expr> entry : columnNameToDefineExpr.entrySet()) { + boolean match = false; for (Column column : schema) { if (column.getName().equals(entry.getKey())) { column.setDefineExpr(entry.getValue()); + match = true; break; } } + + if (!match) { + // Compatibility code for older versions of mv + // store_id -> mv_store_id + // sale_amt -> mva_SUM__`sale_amt` + // mv_count_sale_amt -> mva_SUM__CASE WHEN `sale_amt` IS NULL THEN 0 ELSE 1 END + List<SlotRef> slots = new ArrayList<>(); + entry.getValue().collect(SlotRef.class, slots); + if (slots.size() > 1) { + throw new IOException("DefineExpr have multiple slot in MaterializedIndex, Expr=" + entry.getKey()); + } + + String name = MaterializedIndexMeta.normalizeName(slots.get(0).toSqlWithoutTbl()); + Column matchedColumn = null; + + String columnList = "["; + for (Column column : schema) { + if (columnList.length() != 1) { + columnList += ", "; + } + columnList += column.getName(); + } + columnList += "]"; + + for (Column column : schema) { + if (CreateMaterializedViewStmt.oldmvColumnBreaker(column.getName()).equals(name)) { + if (matchedColumn == null) { + matchedColumn = column; + } else { + LOG.warn("DefineExpr match multiple column in MaterializedIndex, ExprName=" + entry.getKey() + + ", Expr=" + entry.getValue().toSqlWithoutTbl() + ", Slot=" + name + + ", Columns=" + columnList); + } + } + } + if (matchedColumn != null) { + LOG.debug("trans old MV, MV: {}, DefineExpr:{}, DefineName:{}", + matchedColumn.getName(), entry.getValue().toSqlWithoutTbl(), entry.getKey()); + matchedColumn.setDefineExpr(entry.getValue()); + matchedColumn.setDefineName(entry.getKey()); + } else { + LOG.warn("DefineExpr does not match any column in MaterializedIndex, ExprName=" + entry.getKey() + + ", Expr=" + entry.getValue().toSqlWithoutTbl() + ", Slot=" + name + + ", Columns=" + columnList); + } + } } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java index b6bfa3edb8..e570274625 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java @@ -333,9 +333,9 @@ public class OlapTable extends Table { } for (MaterializedIndexMeta indexMeta : indexIdToMeta.values()) { for (Column column : indexMeta.getSchema()) { - if (!nameToColumn.containsKey(column.getName())) { + if (!nameToColumn.containsKey(column.getDefineName())) { fullSchema.add(column); - nameToColumn.put(column.getName(), column); + nameToColumn.put(column.getDefineName(), column); } } } @@ -403,7 +403,7 @@ public class OlapTable extends Table { public Column getVisibleColumn(String columnName) { for (MaterializedIndexMeta meta : getVisibleIndexIdToMeta().values()) { for (Column column : meta.getSchema()) { - if (MaterializedIndexMeta.matchColumnName(column.getName(), columnName)) { + if (MaterializedIndexMeta.matchColumnName(column.getDefineName(), columnName)) { return column; } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java index 9ba5253883..3f8597f1e0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Table.java @@ -124,7 +124,7 @@ public abstract class Table extends MetaObject implements Writable, TableIf { this.nameToColumn = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); if (this.fullSchema != null) { for (Column col : this.fullSchema) { - nameToColumn.put(col.getName(), col); + nameToColumn.put(col.getDefineName(), col); } } else { // Only view in with-clause have null base diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java b/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java index 318ebb270c..619ee2efe5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java @@ -1193,10 +1193,10 @@ public class SingleNodePlanner { // create left-deep sequence of binary hash joins; assign node ids as we go along TableRef tblRef = selectStmt.getTableRefs().get(0); materializeTableResultForCrossJoinOrCountStar(tblRef, analyzer); - if (selectStmt.getSelectList().getItems().size() == 1) { + if (selectStmt.getResultExprs().size() == 1) { final List<SlotId> slotIds = Lists.newArrayList(); final List<TupleId> tupleIds = Lists.newArrayList(); - Expr resultExprSelected = selectStmt.getSelectList().getItems().get(0).getExpr(); + Expr resultExprSelected = selectStmt.getResultExprs().get(0); if (resultExprSelected != null && resultExprSelected instanceof SlotRef) { resultExprSelected.getIds(tupleIds, slotIds); for (SlotId id : slotIds) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/ExprRewriter.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/ExprRewriter.java index 7ffb42c0e7..43e9994a1e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/rewrite/ExprRewriter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/ExprRewriter.java @@ -34,10 +34,12 @@ import java.util.Map; import java.util.Set; /** - * Helper class that drives the transformation of Exprs according to a given list of + * Helper class that drives the transformation of Exprs according to a given + * list of * ExprRewriteRules. The rules are applied as follows: - * - a single rule is applied repeatedly to the Expr and all its children in a bottom-up - * fashion until there are no more changes + * - a single rule is applied repeatedly to the Expr and all its children in a + * bottom-up + * fashion until there are no more changes * - the rule list is applied repeatedly until no rule has made any changes * - the rules are applied in the order they appear in the rule list * Keeps track of how many transformations were applied. @@ -51,11 +53,13 @@ import java.util.Set; * Doris match different Rewriter framework execution. */ public class ExprRewriter { + private boolean useUpBottom = false; private int numChanges = 0; private final List<ExprRewriteRule> rules; // The type of clause that executes the rule. - // This type is only used in InferFiltersRule, RewriteDateLiteralRule, other rules are not used + // This type is only used in InferFiltersRule, RewriteDateLiteralRule, other + // rules are not used public enum ClauseType { INNER_JOIN_CLAUSE, LEFT_OUTER_JOIN_CLAUSE, @@ -71,18 +75,27 @@ public class ExprRewriter { public static ClauseType fromJoinType(JoinOperator joinOp) { switch (joinOp) { - case INNER_JOIN: return INNER_JOIN_CLAUSE; - case LEFT_OUTER_JOIN: return LEFT_OUTER_JOIN_CLAUSE; - case RIGHT_OUTER_JOIN: return RIGHT_OUTER_JOIN_CLAUSE; - case FULL_OUTER_JOIN: return FULL_OUTER_JOIN_CLAUSE; - case LEFT_SEMI_JOIN: return LEFT_SEMI_JOIN_CLAUSE; - case RIGHT_SEMI_JOIN: return RIGHT_SEMI_JOIN_CLAUSE; + case INNER_JOIN: + return INNER_JOIN_CLAUSE; + case LEFT_OUTER_JOIN: + return LEFT_OUTER_JOIN_CLAUSE; + case RIGHT_OUTER_JOIN: + return RIGHT_OUTER_JOIN_CLAUSE; + case FULL_OUTER_JOIN: + return FULL_OUTER_JOIN_CLAUSE; + case LEFT_SEMI_JOIN: + return LEFT_SEMI_JOIN_CLAUSE; + case RIGHT_SEMI_JOIN: + return RIGHT_SEMI_JOIN_CLAUSE; case NULL_AWARE_LEFT_ANTI_JOIN: case LEFT_ANTI_JOIN: return LEFT_ANTI_JOIN_CLAUSE; - case RIGHT_ANTI_JOIN: return RIGHT_ANTI_JOIN_CLAUSE; - case CROSS_JOIN: return CROSS_JOIN_CLAUSE; - default: return OTHER_CLAUSE; + case RIGHT_ANTI_JOIN: + return RIGHT_ANTI_JOIN_CLAUSE; + case CROSS_JOIN: + return CROSS_JOIN_CLAUSE; + default: + return OTHER_CLAUSE; } } @@ -126,6 +139,10 @@ public class ExprRewriter { } } + public void setUpBottom() { + useUpBottom = true; + } + public Expr rewrite(Expr expr, Analyzer analyzer) throws AnalysisException { ClauseType clauseType = ClauseType.OTHER_CLAUSE; return rewrite(expr, analyzer, clauseType); @@ -138,7 +155,8 @@ public class ExprRewriter { do { oldNumChanges = numChanges; for (ExprRewriteRule rule : rules) { - // when foldConstantByBe is on, fold all constant expr by BE instead of applying FoldConstantsRule in FE + // when foldConstantByBe is on, fold all constant expr by BE instead of applying + // FoldConstantsRule in FE if (rule instanceof FoldConstantsRule && analyzer.safeIsEnableFoldConstantByBe()) { continue; } @@ -181,7 +199,8 @@ public class ExprRewriter { } /** - * Applies 'rule' on the Expr tree rooted at 'expr' until there are no more changes. + * Applies 'rule' on the Expr tree rooted at 'expr' until there are no more + * changes. * Returns the transformed Expr or 'expr' if there were no changes. */ private Expr applyRuleRepeatedly(Expr expr, ExprRewriteRule rule, Analyzer analyzer, ClauseType clauseType) @@ -190,11 +209,20 @@ public class ExprRewriter { Expr rewrittenExpr = expr; do { oldNumChanges = numChanges; - rewrittenExpr = applyRuleBottomUp(rewrittenExpr, rule, analyzer, clauseType); + rewrittenExpr = applyRule(rewrittenExpr, rule, analyzer, clauseType); } while (oldNumChanges != numChanges); return rewrittenExpr; } + private Expr applyRule(Expr expr, ExprRewriteRule rule, Analyzer analyzer, ClauseType clauseType) + throws AnalysisException { + if (useUpBottom) { + return applyRuleUpBottom(expr, rule, analyzer, clauseType); + } else { + return applyRuleBottomUp(expr, rule, analyzer, clauseType); + } + } + /** * Applies 'rule' on 'expr' and all its children in a bottom-up fashion. * Returns the transformed Expr or 'expr' if there were no changes. @@ -211,6 +239,18 @@ public class ExprRewriter { return rewrittenExpr; } + private Expr applyRuleUpBottom(Expr expr, ExprRewriteRule rule, Analyzer analyzer, ClauseType clauseType) + throws AnalysisException { + Expr rewrittenExpr = rule.apply(expr, analyzer, clauseType); + if (rewrittenExpr != expr) { + ++numChanges; + } + for (int i = 0; i < expr.getChildren().size(); ++i) { + expr.setChild(i, applyRuleUpBottom(expr.getChild(i), rule, analyzer, clauseType)); + } + return rewrittenExpr; + } + public void rewriteList(List<Expr> exprs, Analyzer analyzer) throws AnalysisException { for (int i = 0; i < exprs.size(); ++i) { exprs.set(i, rewrite(exprs.get(i), analyzer)); diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/mvrewrite/ExprToSlotRefRule.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/mvrewrite/ExprToSlotRefRule.java index 3d58c68fd5..ea03d0af62 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/rewrite/mvrewrite/ExprToSlotRefRule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/mvrewrite/ExprToSlotRefRule.java @@ -267,7 +267,7 @@ public class ExprToSlotRefRule implements ExprRewriteRule { private Expr rewriteExpr(TableName tableName, Column mvColumn, Analyzer analyzer) { Preconditions.checkNotNull(mvColumn); Preconditions.checkNotNull(tableName); - SlotRef mvSlotRef = new SlotRef(tableName, mvColumn.getName()); + SlotRef mvSlotRef = new SlotRef(tableName, mvColumn.getDefineName()); mvSlotRef.analyzeNoThrow(analyzer); return mvSlotRef; } diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/MaterializedViewFunctionTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/MaterializedViewFunctionTest.java index 60a813b2cf..501e203ae3 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/planner/MaterializedViewFunctionTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/planner/MaterializedViewFunctionTest.java @@ -550,8 +550,7 @@ public class MaterializedViewFunctionTest { dorisAssert.withMaterializedView(createEmpsMVsql).query(query).explainContains(QUERY_USE_EMPS_MV, 2); } - // Can not support match multiple mv now - //@Test + @Test public void testMultiMVMultiUsage() throws Exception { String createEmpsMVSql01 = "create materialized view emp_mv_01 as select deptno, empid, salary " + "from " + EMPS_TABLE_NAME + " order by deptno;"; diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/MaterializedViewSelectorTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/MaterializedViewSelectorTest.java index 2e8e2ebc2e..7767fc71ab 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/planner/MaterializedViewSelectorTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/planner/MaterializedViewSelectorTest.java @@ -156,6 +156,137 @@ public class MaterializedViewSelectorTest { Assert.assertTrue("MAX".equalsIgnoreCase(aggregatedColumn2.getFnName().getFunction())); } + @Disabled + public void testCheckCompensatingPredicates(@Injectable SelectStmt selectStmt, @Injectable Analyzer analyzer, + @Injectable MaterializedIndexMeta indexMeta1, + @Injectable MaterializedIndexMeta indexMeta2, + @Injectable MaterializedIndexMeta indexMeta3, + @Injectable MaterializedIndexMeta indexMeta4, @Injectable SlotRef slotRef1, @Injectable SlotRef slotRef2) { + Set<String> tableAColumnNames = Sets.newHashSet(); + tableAColumnNames.add("C1"); + Map<Long, MaterializedIndexMeta> candidateIndexIdToSchema = Maps.newHashMap(); + List<Column> index1Columns = Lists.newArrayList(); + Column index1Column1 = new Column("c1", Type.INT, true, null, true, "", ""); + index1Columns.add(index1Column1); + index1Column1.setDefineExpr(slotRef1); + candidateIndexIdToSchema.put(new Long(1), indexMeta1); + List<Column> index2Columns = Lists.newArrayList(); + Column index2Column1 = new Column("c1", Type.INT, false, AggregateType.NONE, true, "", ""); + index2Columns.add(index2Column1); + index2Column1.setDefineExpr(slotRef1); + candidateIndexIdToSchema.put(new Long(2), indexMeta2); + List<Column> index3Columns = Lists.newArrayList(); + Column index3Column1 = new Column("c1", Type.INT, false, AggregateType.SUM, true, "", ""); + index3Column1.setDefineExpr(slotRef1); + index3Columns.add(index3Column1); + candidateIndexIdToSchema.put(new Long(3), indexMeta3); + List<Column> index4Columns = Lists.newArrayList(); + Column index4Column2 = new Column("c2", Type.INT, true, null, true, "", ""); + index4Column2.setDefineExpr(slotRef2); + index4Columns.add(index4Column2); + candidateIndexIdToSchema.put(new Long(4), indexMeta4); + + List<Expr> whereList = Lists.newArrayList(); + whereList.add(slotRef1); + new Expectations() { + { + selectStmt.getAggInfo(); + result = null; + selectStmt.getWhereClause(); + result = whereList; + indexMeta1.getSchema(); + result = index1Columns; + indexMeta2.getSchema(); + result = index2Columns; + indexMeta3.getSchema(); + result = index3Columns; + indexMeta4.getSchema(); + result = index4Columns; + slotRef1.toSqlWithoutTbl(); + result = "c1"; + } + }; + + MaterializedViewSelector selector = new MaterializedViewSelector(selectStmt, analyzer); + try { + Deencapsulation.invoke(selector, "checkCompensatingPredicates", tableAColumnNames, + candidateIndexIdToSchema); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + + Assert.assertEquals(2, candidateIndexIdToSchema.size()); + Assert.assertTrue(candidateIndexIdToSchema.keySet().contains(new Long(1))); + Assert.assertTrue(candidateIndexIdToSchema.keySet().contains(new Long(2))); + } + + @Disabled + public void testCheckGrouping(@Injectable SelectStmt selectStmt, @Injectable Analyzer analyzer, + @Injectable OlapTable table, + @Injectable MaterializedIndexMeta indexMeta1, + @Injectable MaterializedIndexMeta indexMeta2, + @Injectable MaterializedIndexMeta indexMeta3, @Injectable SlotRef slotRef1, @Injectable SlotRef slotRef2) { + Set<String> tableAColumnNames = Sets.newHashSet(); + tableAColumnNames.add("C1"); + Map<Long, MaterializedIndexMeta> candidateIndexIdToSchema = Maps.newHashMap(); + List<Column> index1Columns = Lists.newArrayList(); + Column index1Column1 = new Column("c2", Type.INT, true, null, true, "", ""); + index1Column1.setDefineExpr(slotRef2); + index1Columns.add(index1Column1); + candidateIndexIdToSchema.put(new Long(1), indexMeta1); + List<Column> index2Columns = Lists.newArrayList(); + Column index2Column1 = new Column("c1", Type.INT, true, null, true, "", ""); + index2Column1.setDefineExpr(slotRef1); + index2Columns.add(index2Column1); + Column index2Column2 = new Column("c2", Type.INT, false, AggregateType.SUM, true, "", ""); + index2Column2.setDefineExpr(slotRef2); + index2Columns.add(index2Column2); + candidateIndexIdToSchema.put(new Long(2), indexMeta2); + List<Column> index3Columns = Lists.newArrayList(); + Column index3Column1 = new Column("c2", Type.INT, true, null, true, "", ""); + index3Column1.setDefineExpr(slotRef2); + index3Columns.add(index3Column1); + Column index3Column2 = new Column("c1", Type.INT, false, AggregateType.SUM, true, "", ""); + index3Column1.setDefineExpr(slotRef1); + index3Columns.add(index3Column2); + candidateIndexIdToSchema.put(new Long(3), indexMeta3); + List<Expr> groupingList = Lists.newArrayList(); + groupingList.add(slotRef1); + List<Expr> aggList = Lists.newArrayList(); + new Expectations() { + { + selectStmt.getAggInfo().getGroupingExprs(); + result = groupingList; + selectStmt.getAggInfo().getAggregateExprs(); + result = aggList; + indexMeta1.getSchema(); + result = index1Columns; + indexMeta1.getKeysType(); + result = KeysType.DUP_KEYS; + indexMeta2.getSchema(); + result = index2Columns; + indexMeta3.getSchema(); + result = index3Columns; + slotRef1.toSqlWithoutTbl(); + result = "c1"; + } + }; + + try { + MaterializedViewSelector selector = new MaterializedViewSelector(selectStmt, analyzer); + Deencapsulation.setField(selector, "isSPJQuery", false); + Deencapsulation.invoke(selector, "checkGrouping", table, tableAColumnNames, candidateIndexIdToSchema); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + + Assert.assertEquals(2, candidateIndexIdToSchema.size()); + Assert.assertTrue(candidateIndexIdToSchema.keySet().contains(new Long(1))); + Assert.assertTrue(candidateIndexIdToSchema.keySet().contains(new Long(2))); + } + @Disabled public void testCheckAggregationFunction(@Injectable SelectStmt selectStmt, @Injectable Analyzer analyzer, @Injectable OlapTable table, @@ -213,6 +344,52 @@ public class MaterializedViewSelectorTest { Assert.assertTrue(candidateIndexIdToSchema.keySet().contains(new Long(3))); } + @Disabled + public void testCheckOutputColumns(@Injectable SelectStmt selectStmt, @Injectable Analyzer analyzer, + @Injectable MaterializedIndexMeta indexMeta1, + @Injectable MaterializedIndexMeta indexMeta2, + @Injectable MaterializedIndexMeta indexMeta3) { + Map<Long, MaterializedIndexMeta> candidateIndexIdToSchema = Maps.newHashMap(); + List<Column> index1Columns = Lists.newArrayList(); + Column index1Column1 = new Column("c2", Type.INT, true, null, true, "", ""); + index1Columns.add(index1Column1); + candidateIndexIdToSchema.put(new Long(1), indexMeta1); + List<Column> index2Columns = Lists.newArrayList(); + Column index2Column1 = new Column("c1", Type.INT, true, null, true, "", ""); + index2Columns.add(index2Column1); + Column index2Column2 = new Column("c2", Type.INT, false, AggregateType.NONE, true, "", ""); + index2Columns.add(index2Column2); + candidateIndexIdToSchema.put(new Long(2), indexMeta2); + List<Column> index3Columns = Lists.newArrayList(); + Column index3Column1 = new Column("C2", Type.INT, true, null, true, "", ""); + index3Columns.add(index3Column1); + Column index3Column2 = new Column("c1", Type.INT, false, AggregateType.SUM, true, "", ""); + index3Columns.add(index3Column2); + candidateIndexIdToSchema.put(new Long(3), indexMeta3); + new Expectations() { + { + selectStmt.getAggInfo(); + result = null; + indexMeta1.getSchema(); + result = index1Columns; + indexMeta2.getSchema(); + result = index2Columns; + indexMeta3.getSchema(); + result = index3Columns; + } + }; + + MaterializedViewSelector selector = new MaterializedViewSelector(selectStmt, analyzer); + Set<String> columnNamesInQueryOutput = Sets.newHashSet(); + columnNamesInQueryOutput.add("c1"); + columnNamesInQueryOutput.add("c2"); + Deencapsulation.invoke(selector, "checkOutputColumns", columnNamesInQueryOutput, + candidateIndexIdToSchema); + Assert.assertEquals(2, candidateIndexIdToSchema.size()); + Assert.assertTrue(candidateIndexIdToSchema.keySet().contains(new Long(2))); + Assert.assertTrue(candidateIndexIdToSchema.keySet().contains(new Long(3))); + } + @Test public void testCompensateIndex(@Injectable SelectStmt selectStmt, @Injectable Analyzer analyzer, @Injectable OlapTable table) { --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org