You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2020/10/13 02:12:50 UTC

[incubator-doris] branch master updated: [Bug] Add regular column when materialized slot is empty in tuple (#4719)

This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new bf8f68f  [Bug] Add regular column when materialized slot is empty in tuple (#4719)
bf8f68f is described below

commit bf8f68f751765284fcf5466301230e53d1c3d595
Author: EmmyMiao87 <52...@qq.com>
AuthorDate: Tue Oct 13 10:12:03 2020 +0800

    [Bug] Add regular column when materialized slot is empty in tuple (#4719)
    
    If the materialized slot is empty in inline view, the scanner will throw exception 'no materialized slot!'.
    When the outer query does not need any real columns of the inner query at all, such as the outer query only contains constant calculations,
    all slots in the inner query will not be materialized.
    For example:
    ```
    select c1 from (select 'xx' c1, k1 from test) t1;
    ```
    
    But this does not mean that the inner query (select 'xx' c1, k1 from test) does not need to be executed.
    Because the number of rows in the outer result needs to be determined by the number of rows in the inner query.
    In this case, the inner query scan node needs to add a column to ensure the correct result.
    At the same time it can avoid the scan node reporting errors.
---
 .../apache/doris/planner/SingleNodePlanner.java    | 18 ++++--
 .../doris/planner/SingleNodePlannerTest.java       | 74 ++++++++++++++++++++++
 2 files changed, 88 insertions(+), 4 deletions(-)

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 69ae7fc..5384bcc 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
@@ -1887,7 +1887,7 @@ public class SingleNodePlanner {
      */
     private void materializeTableResultForCrossJoinOrCountStar(TableRef tblRef, Analyzer analyzer) {
         if (tblRef instanceof BaseTableRef) {
-            materializeBaseTableRefResultForCrossJoinOrCountStar((BaseTableRef) tblRef, analyzer);
+            materializeSlotForEmptyMaterializedTableRef((BaseTableRef) tblRef, analyzer);
         } else if (tblRef instanceof InlineViewRef) {
             materializeInlineViewResultExprForCrossJoinOrCountStar((InlineViewRef) tblRef, analyzer);
         } else {
@@ -1896,13 +1896,23 @@ public class SingleNodePlanner {
     }
 
     /**
-     * materialize BaseTableRef result' exprs for Cross Join or Count Star
+     * When materialized table ref is a empty tbl ref, the planner should add a mini column for this tuple.
+     * There are two situation:
+     * 1. The tbl ref is empty, such as select a from (select 'c1' a from test) t;
+     * Inner tuple: tuple 0 without slot
+     * 2. The materialized slot in tbl ref is empty, such as select a from (select 'c1' a, k1 from test) t;
+     * Inner tuple: tuple 0 with a not materialized slot k1
+     * In the above two cases, it is necessary to add a mini column to the inner tuple
+     * to ensure that the number of rows in the inner query result is the number of rows in the table.
      *
+     * After this function, the inner tuple is following:
+     * case1. tuple 0: slot<k1> materialized true (new slot)
+     * case2. tuple 0: slot<k1> materialized true (changed)
      * @param tblRef
      * @param analyzer
      */
-    private void materializeBaseTableRefResultForCrossJoinOrCountStar(BaseTableRef tblRef, Analyzer analyzer) {
-        if (tblRef.getDesc().getSlots().isEmpty()) {
+    private void materializeSlotForEmptyMaterializedTableRef(BaseTableRef tblRef, Analyzer analyzer) {
+        if (tblRef.getDesc().getMaterializedSlots().isEmpty()) {
             Column minimuColumn = null;
             for (Column col : tblRef.getTable().getBaseSchema()) {
                 if (minimuColumn == null || col.getDataType().getSlotSize() < minimuColumn
diff --git a/fe/fe-core/src/test/java/org/apache/doris/planner/SingleNodePlannerTest.java b/fe/fe-core/src/test/java/org/apache/doris/planner/SingleNodePlannerTest.java
new file mode 100644
index 0000000..b2fdfe2
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/planner/SingleNodePlannerTest.java
@@ -0,0 +1,74 @@
+/*
+ * // 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.
+ *
+ */
+
+package org.apache.doris.planner;
+
+import org.apache.doris.analysis.Analyzer;
+import org.apache.doris.analysis.BaseTableRef;
+import org.apache.doris.analysis.SlotDescriptor;
+import org.apache.doris.analysis.SlotId;
+import org.apache.doris.analysis.TableName;
+import org.apache.doris.analysis.TableRef;
+import org.apache.doris.analysis.TupleDescriptor;
+import org.apache.doris.analysis.TupleId;
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.Table;
+import org.apache.doris.common.jmockit.Deencapsulation;
+
+import com.google.common.collect.Lists;
+
+import org.junit.Test;
+
+import java.util.List;
+
+import mockit.Expectations;
+import mockit.Injectable;
+
+public class SingleNodePlannerTest {
+
+    @Test
+    public void testMaterializeBaseTableRefResultForCrossJoinOrCountStar(@Injectable Table table,
+                                                                         @Injectable TableName tableName,
+                                                                         @Injectable Analyzer analyzer,
+                                                                         @Injectable PlannerContext plannerContext,
+                                                                         @Injectable Column column) {
+        TableRef tableRef = new TableRef();
+        Deencapsulation.setField(tableRef, "isAnalyzed", true);
+        BaseTableRef baseTableRef = new BaseTableRef(tableRef, table, tableName);
+        TupleDescriptor tupleDescriptor = new TupleDescriptor(new TupleId(1));
+        SlotDescriptor slotDescriptor = new SlotDescriptor(new SlotId(1), tupleDescriptor);
+        slotDescriptor.setIsMaterialized(false);
+        tupleDescriptor.addSlot(slotDescriptor);
+        Deencapsulation.setField(tableRef, "desc", tupleDescriptor);
+        Deencapsulation.setField(baseTableRef, "desc", tupleDescriptor);
+        tupleDescriptor.setTable(table);
+        List<Column> columnList = Lists.newArrayList();
+        columnList.add(column);
+        new Expectations() {
+            {
+                table.getBaseSchema();
+                result = columnList;
+            }
+        };
+        SingleNodePlanner singleNodePlanner = new SingleNodePlanner(plannerContext);
+        Deencapsulation.invoke(singleNodePlanner, "materializeBaseTableRefResultForCrossJoinOrCountStar",
+                               baseTableRef, analyzer);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org