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

liyang pushed a commit to branch kylin5
in repository https://gitbox.apache.org/repos/asf/kylin.git

commit dc344ce2fff2b2ca1ece1955b98c4e4130fecbd3
Author: Yu Gan <yu....@kyligence.io>
AuthorDate: Fri Aug 25 16:01:23 2023 +0800

    KYLIN-5800 & KYLIN-5812 Support scalar subquery join aggregate pushdown
---
 .../org/apache/kylin/common/KylinConfigBase.java   |   4 +
 .../query/rules/ScalarSubqueryJoinRuleTest.java    | 112 +++
 .../query/rules/ScalarSubqueryJoinRuleTest.xml     | 778 ++++++++++++++++++++
 .../query/sql_scalar_subquery/query01.sql          |  26 +
 .../query/sql_scalar_subquery/query02.sql          |  30 +
 .../query/sql_scalar_subquery/query03.sql          |  32 +
 .../query/sql_scalar_subquery/query04.sql          |  28 +
 .../query/sql_scalar_subquery/query05.sql          |  37 +
 .../query/sql_scalar_subquery/query06.sql          |  35 +
 .../query/sql_scalar_subquery/query07.sql          |  33 +
 .../query/sql_scalar_subquery/query08.sql          |  36 +
 .../query/sql_scalar_subquery/query09.sql          |  36 +
 .../query/sql_scalar_subquery/query10.sql          |  33 +
 .../query/sql_scalar_subquery/query11.sql          |  32 +
 .../query/sql_scalar_subquery/query12.sql          |  41 ++
 .../query/sql_scalar_subquery/query13.sql          |  36 +
 .../query/sql_scalar_subquery/query14.sql          |  32 +
 .../query/sql_scalar_subquery/query15.sql          |  27 +
 .../query/sql_scalar_subquery/query16.sql          |  33 +
 .../query/sql_scalar_subquery/query17.sql          |  31 +
 .../query/sql_scalar_subquery/query18.sql          |  65 ++
 .../query/sql_scalar_subquery/query19.sql          |  26 +
 .../apache/kylin/query/relnode/KapValuesRel.java   |  21 +-
 .../apache/kylin/query/relnode/OLAPValuesRel.java  |  13 +-
 .../kyligence/kap/query/optrule/KAPValuesRule.java |  11 +-
 .../kap/query/optrule/ScalarSubqueryJoinRule.java  | 799 +++++++++++++++++++++
 .../org/apache/kylin/query/engine/QueryExec.java   |   4 +
 .../java/org/apache/kylin/query/util/HepUtils.java |  20 +-
 28 files changed, 2393 insertions(+), 18 deletions(-)

diff --git 
a/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java 
b/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
index 8b9a0308f7..64b4a775d4 100644
--- a/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
+++ b/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
@@ -2532,6 +2532,10 @@ public abstract class KylinConfigBase implements 
Serializable {
         return 
Boolean.parseBoolean(getOptional("kylin.query.calcite.aggregate-pushdown-enabled",
 FALSE));
     }
 
+    public boolean isScalarSubqueryJoinEnabled() {
+        return 
Boolean.parseBoolean(getOptional("kylin.query.scalar-subquery-join-enabled", 
FALSE));
+    }
+
     public int getCalciteBindableCacheSize() {
         return 
Integer.parseInt(getOptional("kylin.query.calcite.bindable.cache.maxSize", 
"10"));
     }
diff --git 
a/src/kylin-it/src/test/java/org/apache/kylin/query/rules/ScalarSubqueryJoinRuleTest.java
 
b/src/kylin-it/src/test/java/org/apache/kylin/query/rules/ScalarSubqueryJoinRuleTest.java
new file mode 100644
index 0000000000..0c8c75ac89
--- /dev/null
+++ 
b/src/kylin-it/src/test/java/org/apache/kylin/query/rules/ScalarSubqueryJoinRuleTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.kylin.query.rules;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.rel.rules.AggregateProjectMergeRule;
+import org.apache.calcite.rel.rules.ProjectMergeRule;
+import org.apache.calcite.test.DiffRepository;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.util.Pair;
+import org.apache.kylin.guava30.shaded.common.collect.ImmutableList;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import io.kyligence.kap.query.optrule.AggregateProjectReduceRule;
+import io.kyligence.kap.query.optrule.KapAggregateRule;
+import io.kyligence.kap.query.optrule.KapJoinRule;
+import io.kyligence.kap.query.optrule.KapProjectRule;
+import io.kyligence.kap.query.optrule.ScalarSubqueryJoinRule;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class ScalarSubqueryJoinRuleTest extends CalciteRuleTestBase {
+
+    private final String project = "default";
+    private final String sqlFolder = "query/sql_scalar_subquery";
+    //
+    private final DiffRepository diff = 
DiffRepository.lookup(ScalarSubqueryJoinRuleTest.class);
+
+    @Before
+    public void setup() {
+        createTestMetadata();
+    }
+
+    @After
+    public void cleanUp() {
+        cleanupTestMetadata();
+    }
+
+    @Override
+    protected DiffRepository getDiffRepo() {
+        return diff;
+    }
+
+    @Test
+    public void testPushDownAggregate() throws IOException {
+        KylinConfig config = KylinConfig.getInstanceFromEnv();
+        List<Pair<String, String>> queries = readALLSQLs(config, project, 
sqlFolder);
+        List<RelOptRule> rulesToAdd = getTransformRules();
+
+        queries.forEach(p -> doCheckTransform(p.getFirst(), p.getSecond(), 
rulesToAdd));
+    }
+
+    private void doCheckTransform(String prefix, String sql, List<RelOptRule> 
rulesToAdd) {
+        checkSQLPostOptimize(project, sql, prefix, null, rulesToAdd);
+    }
+
+    @Test
+    @Ignore("Dev only")
+    public void testSingle() throws IOException {
+        KylinConfig config = KylinConfig.getInstanceFromEnv();
+        List<RelOptRule> rulesToAdd = getTransformRules();
+        Pair<String, String> q = readOneSQL(config, project, sqlFolder, 
"query03.sql");
+        doCheckTransform(q.getFirst(), q.getSecond(), rulesToAdd);
+    }
+
+    @Test
+    @Ignore("Dev only")
+    public void dumpPlans() throws IOException {
+        List<Pair<String, String>> queries = 
readALLSQLs(KylinConfig.getInstanceFromEnv(), project, sqlFolder);
+        CalciteRuleTestBase.StringOutput output = new 
CalciteRuleTestBase.StringOutput(false);
+        final List<RelOptRule> rulesToAdd = getTransformRules();
+        queries.forEach(p -> checkSQLPostOptimize(project, p.getSecond(), 
p.getFirst(), output, rulesToAdd));
+        output.dump(log);
+    }
+
+    private List<RelOptRule> getTransformRules() {
+        return ImmutableList.of(// basic rules
+                KapAggregateRule.INSTANCE, //
+                KapProjectRule.INSTANCE, //
+                KapJoinRule.INSTANCE, //
+                // relative rules
+                ProjectMergeRule.INSTANCE, //
+                AggregateProjectMergeRule.INSTANCE, //
+                AggregateProjectReduceRule.INSTANCE, //
+                // target rules
+                ScalarSubqueryJoinRule.AGG_JOIN, //
+                ScalarSubqueryJoinRule.AGG_PRJ_JOIN, //
+                ScalarSubqueryJoinRule.AGG_PRJ_FLT_JOIN);
+    }
+}
diff --git 
a/src/kylin-it/src/test/resources/org/apache/kylin/query/rules/ScalarSubqueryJoinRuleTest.xml
 
b/src/kylin-it/src/test/resources/org/apache/kylin/query/rules/ScalarSubqueryJoinRuleTest.xml
new file mode 100644
index 0000000000..55c9a36a16
--- /dev/null
+++ 
b/src/kylin-it/src/test/resources/org/apache/kylin/query/rules/ScalarSubqueryJoinRuleTest.xml
@@ -0,0 +1,778 @@
+<?xml version="1.0" ?>
+<!--
+  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.
+-->
+
+<Root>
+    <TestCase name="testPushDownAggregate">
+        <Resource name="query01.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 1]], groups=[null], TOTAL=[SUM($2)], ctx=[])
+    KapProjectRel(D_DATEKEY=[$1], DATE_TIME=[$0], D_YEAR=[$5], ctx=[])
+      KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+        KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+          KapValuesRel(tuples=[[{ 0 }]])
+        KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query01.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$1], DATE_TIME=[$0], TOTAL=[$2], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], TOTAL=[SUM($2)], ctx=[])
+      KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+        KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+          KapValuesRel(tuples=[[{ 0 }]])
+        KapAggregateRel(group-set=[[0]], groups=[null], TOTAL=[SUM($4)], 
ctx=[])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query02.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 1]], groups=[null], TOTAL=[SUM($2)], ctx=[])
+    KapProjectRel(D_DATEKEY=[$1], DATE_TIME=[$0], D_YEAR=[$5], ctx=[])
+      KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query02.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$1], DATE_TIME=[$0], TOTAL=[$2], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], TOTAL=[SUM($2)], ctx=[])
+      KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapAggregateRel(group-set=[[0]], groups=[null], TOTAL=[SUM($4)], 
ctx=[])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query03.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($2)], ctx=[])
+    KapProjectRel(D_DATE=[$2], DATE_TIME=[$0], D_YEAR=[$5], ctx=[])
+      KapNonEquiJoinRel(condition=[AND(<=($2, $0), >=($2, CONCAT(SUBSTRING($0, 
1, 8), '01')))], joinType=[left], ctx=[])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query03.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATE=[$1], DATE_TIME=[$0], EXPR$2=[$2], SY=[$3], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$2=[$SUM0($2)], 
SY=[SUM($3)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_DATE=[$1], $f2=[CASE(IS NULL($2), 
CAST(1):BIGINT, $2)], SY=[$3], ctx=[])
+        KapNonEquiJoinRel(condition=[AND(<=($1, $0), >=($1, 
CONCAT(SUBSTRING($0, 1, 8), '01')))], joinType=[left], ctx=[])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapAggregateRel(group-set=[[1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($4)], ctx=[])
+            KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query04.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$0], TOTAL=[$2], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], TOTAL=[SUM($2)], ctx=[])
+      KapProjectRel(D_DATEKEY=[$1], DATE_TIME=[$0], D_YEAR=[$5], ctx=[])
+        KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+          KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query04.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$1], TOTAL=[$2], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], TOTAL=[SUM($2)], ctx=[])
+      KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+        KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+          KapValuesRel(tuples=[[{ 0 }]])
+        KapAggregateRel(group-set=[[0]], groups=[null], TOTAL=[SUM($4)], 
ctx=[])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query05.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(SD=[$3], D_DATE=[$0], EXPR$2=[$4], DATE_TIME=[$1], SY=[$5], 
SR=[$6], LO_ORDERDATE=[$2], ctx=[])
+    KapAggregateRel(group-set=[[0, 1, 2]], groups=[null], SD=[SUM($3)], 
EXPR$2=[COUNT()], SY=[SUM($4)], SR=[SUM($5)], ctx=[])
+      KapProjectRel(D_DATE=[$2], DATE_TIME=[$0], LO_ORDERDATE=[$23], 
D_DATEKEY=[$1], D_YEAR=[$5], LO_REVENUE=[$30], ctx=[])
+        KapJoinRel(condition=[=($0, $23)], joinType=[inner], ctx=[])
+          KapNonEquiJoinRel(condition=[AND(<=($2, $0), >=($2, 
CONCAT(SUBSTRING($0, 1, 8), '01')))], joinType=[left], ctx=[])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+          KapTableScan(table=[[SSB, LINEORDER]], ctx=[], fields=[[0, 1, 2, 3, 
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]])
+]]>
+        </Resource>
+        <Resource name="query05.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(SD=[$3], D_DATE=[$1], EXPR$2=[$4], DATE_TIME=[$0], SY=[$5], 
SR=[$6], LO_ORDERDATE=[$2], ctx=[])
+    KapAggregateRel(group-set=[[0, 1, 2]], groups=[null], SD=[SUM($8)], 
EXPR$2=[$SUM0($9)], SY=[SUM($10)], SR=[SUM($11)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_DATE=[$1], LO_ORDERDATE=[$5], 
EXPR$2=[$3], SY=[$4], SD=[$2], $f1=[$6], SR=[$7], $f8=[CAST(*($2, $6)):BIGINT], 
$f9=[*($3, $6)], $f10=[CAST(*($4, $6)):BIGINT], $f11=[CAST(*($3, $7)):BIGINT], 
ctx=[])
+        KapJoinRel(condition=[=($0, $5)], joinType=[inner], ctx=[])
+          KapAggregateRel(group-set=[[0, 1]], groups=[null], SD=[SUM($2)], 
EXPR$2=[$SUM0($3)], SY=[SUM($4)], ctx=[])
+            KapProjectRel(DATE_TIME=[$0], D_DATE=[$1], SD=[$2], $f3=[CASE(IS 
NULL($3), CAST(1):BIGINT, $3)], SY=[$4], ctx=[])
+              KapNonEquiJoinRel(condition=[AND(<=($1, $0), >=($1, 
CONCAT(SUBSTRING($0, 1, 8), '01')))], joinType=[left], ctx=[])
+                KapUnionRel(all=[true], ctx=[], all=[true])
+                  KapUnionRel(all=[true], ctx=[], all=[true])
+                    KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                      KapValuesRel(tuples=[[{ 0 }]])
+                    KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                      KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapAggregateRel(group-set=[[1]], groups=[null], SD=[SUM($0)], 
EXPR$2=[COUNT()], SY=[SUM($4)], ctx=[])
+                  KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+          KapAggregateRel(group-set=[[5]], groups=[null], agg#0=[COUNT()], 
SR=[SUM($12)], ctx=[])
+            KapTableScan(table=[[SSB, LINEORDER]], ctx=[], fields=[[0, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]])
+]]>
+        </Resource>
+        <Resource name="query06.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($2)], ctx=[])
+    KapProjectRel(D_DATE=[$4], DATE_TIME=[$0], D_YEAR=[$2], ctx=[])
+      KapNonEquiJoinRel(condition=[AND(<=($4, $0), >=($4, CONCAT(SUBSTRING($0, 
1, 8), '01')))], joinType=[left], ctx=[])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapProjectRel(D_DATEKEY=[$0], D_YEAR=[$4], D_HOLIDAYFL=[$15], 
D_DATE=[$1], ctx=[])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query06.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATE=[$1], DATE_TIME=[$0], EXPR$2=[$2], SY=[$3], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$2=[$SUM0($2)], 
SY=[SUM($3)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_DATE=[$1], $f2=[CASE(IS NULL($2), 
CAST(1):BIGINT, $2)], SY=[$3], ctx=[])
+        KapNonEquiJoinRel(condition=[AND(<=($1, $0), >=($1, 
CONCAT(SUBSTRING($0, 1, 8), '01')))], joinType=[left], ctx=[])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapAggregateRel(group-set=[[1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($4)], ctx=[])
+            KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query07.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($2)], ctx=[])
+    KapProjectRel(D_DATE=[$1], DATE_TIME=[$17], D_YEAR=[$4], ctx=[])
+      KapNonEquiJoinRel(condition=[AND(<=($1, $17), >=($1, 
CONCAT(SUBSTRING($17, 1, 8), '01')))], joinType=[left], ctx=[])
+        KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query07.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 3]], groups=[null], EXPR$2=[$SUM0($1)], 
SY=[SUM($2)], ctx=[])
+    KapNonEquiJoinRel(condition=[AND(<=($0, $3), >=($0, CONCAT(SUBSTRING($3, 
1, 8), '01')))], joinType=[left], ctx=[])
+      KapAggregateRel(group-set=[[1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($4)], ctx=[])
+        KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+      KapUnionRel(all=[true], ctx=[], all=[true])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+          KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query08.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($2)], ctx=[])
+    KapProjectRel(D_DATE=[$3], DATE_TIME=[$4], D_YEAR=[$1], ctx=[])
+      KapNonEquiJoinRel(condition=[AND(<=($3, $4), >=($3, CONCAT(SUBSTRING($4, 
1, 8), '01')))], joinType=[left], ctx=[])
+        KapProjectRel(D_DATEKEY=[$0], D_YEAR=[$4], D_HOLIDAYFL=[$15], 
D_DATE=[$1], ctx=[])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query08.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 3]], groups=[null], EXPR$2=[$SUM0($1)], 
SY=[SUM($2)], ctx=[])
+    KapNonEquiJoinRel(condition=[AND(<=($0, $3), >=($0, CONCAT(SUBSTRING($3, 
1, 8), '01')))], joinType=[left], ctx=[])
+      KapAggregateRel(group-set=[[1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($4)], ctx=[])
+        KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+      KapUnionRel(all=[true], ctx=[], all=[true])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+          KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query09.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($2)], ctx=[])
+    KapProjectRel(D_DATE=[$4], DATE_TIME=[$0], D_YEAR=[$3], ctx=[])
+      KapNonEquiJoinRel(condition=[AND(<=($4, $0), >=($4, CONCAT(SUBSTRING($0, 
1, 8), '01')))], joinType=[left], ctx=[])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapProjectRel(D_DATEKEY=[$0], EXPR$1=[$3], D_YEAR=[$2], D_DATE=[$1], 
ctx=[])
+          KapAggregateRel(group-set=[[0, 1, 2]], groups=[null], 
EXPR$1=[SUM($2)], ctx=[])
+            KapProjectRel(D_DATEKEY=[$0], D_DATE=[$1], D_YEAR=[$4], ctx=[])
+              KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query09.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATE=[$1], DATE_TIME=[$0], EXPR$2=[$2], SY=[$3], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$2=[$SUM0($2)], 
SY=[SUM($3)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_DATE=[$1], $f2=[CASE(IS NULL($2), 
CAST(1):BIGINT, $2)], SY=[$3], ctx=[])
+        KapNonEquiJoinRel(condition=[AND(<=($1, $0), >=($1, 
CONCAT(SUBSTRING($0, 1, 8), '01')))], joinType=[left], ctx=[])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapAggregateRel(group-set=[[1]], groups=[null], EXPR$2=[COUNT()], 
SY=[SUM($2)], ctx=[])
+            KapAggregateRel(group-set=[[0, 1, 4]], groups=[null], 
EXPR$1=[SUM($4)], ctx=[])
+              KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query10.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(EXPR$0=[$1], SY=[$2], ctx=[])
+    KapAggregateRel(group-set=[[0]], groups=[null], EXPR$0=[COUNT()], 
SY=[SUM($1)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_YEAR=[$5], ctx=[])
+        KapNonEquiJoinRel(condition=[AND(<=(CAST($1):BIGINT, CAST($0):BIGINT 
NOT NULL), >=(CAST($1):BIGINT, CAST(CONCAT(SUBSTRING($0, 1, 8), '01')):BIGINT 
NOT NULL))], joinType=[left], ctx=[])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapUnionRel(all=[true], ctx=[], all=[true])
+                  KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['2300-03-03'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query10.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(EXPR$0=[$1], SY=[$2], ctx=[])
+    KapAggregateRel(group-set=[[0]], groups=[null], EXPR$0=[$SUM0($2)], 
SY=[SUM($3)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_DATEKEY=[$1], $f2=[CASE(IS NULL($2), 
CAST(1):BIGINT, $2)], SY=[$3], ctx=[])
+        KapNonEquiJoinRel(condition=[AND(<=(CAST($1):BIGINT, CAST($0):BIGINT 
NOT NULL), >=(CAST($1):BIGINT, CAST(CONCAT(SUBSTRING($0, 1, 8), '01')):BIGINT 
NOT NULL))], joinType=[left], ctx=[])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapUnionRel(all=[true], ctx=[], all=[true])
+                  KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['2300-03-03'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapAggregateRel(group-set=[[0]], groups=[null], EXPR$0=[COUNT()], 
SY=[SUM($4)], ctx=[])
+            KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query11.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[]], groups=[null], EXPR$0=[COUNT()], 
SY=[SUM($0)], ctx=[])
+    KapProjectRel(D_YEAR=[$5], ctx=[])
+      KapNonEquiJoinRel(condition=[AND(<=(CAST($1):BIGINT, CAST($0):BIGINT NOT 
NULL), >=(CAST($1):BIGINT, CAST(CONCAT(SUBSTRING($0, 1, 8), '01')):BIGINT NOT 
NULL))], joinType=[left], ctx=[])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['2300-03-03'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query11.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapAggregateRel(group-set=[[]], groups=[null], EXPR$0=[$SUM0($2)], 
SY=[SUM($3)], ctx=[])
+    KapProjectRel(DATE_TIME=[$0], D_DATEKEY=[$1], $f2=[CASE(IS NULL($2), 
CAST(1):BIGINT, $2)], SY=[$3], ctx=[])
+      KapNonEquiJoinRel(condition=[AND(<=(CAST($1):BIGINT, CAST($0):BIGINT NOT 
NULL), >=(CAST($1):BIGINT, CAST(CONCAT(SUBSTRING($0, 1, 8), '01')):BIGINT NOT 
NULL))], joinType=[left], ctx=[])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['2300-03-03'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+        KapAggregateRel(group-set=[[0]], groups=[null], EXPR$0=[COUNT()], 
SY=[SUM($4)], ctx=[])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query12.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(DATE_TIME=[$0], EXPR$1=[$1], EXPR$2=[$2], EXPR$3=[$3], 
EXPR$4=[$3], EXPR$5=[$4], SY=[$5], SR=[$6], ctx=[])
+    KapAggregateRel(group-set=[[0]], groups=[null], EXPR$1=[COUNT($1, $2)], 
EXPR$2=[COUNT($1)], EXPR$3=[COUNT()], EXPR$5=[COUNT($2)], SY=[SUM($3)], 
SR=[SUM($4)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_HOLIDAYFL=[$16], LO_CUSTKEY=[$20], 
D_YEAR=[$5], LO_REVENUE=[$30], ctx=[])
+        KapJoinRel(condition=[=($0, $23)], joinType=[inner], ctx=[])
+          KapNonEquiJoinRel(condition=[AND(<=($2, $0), >=($2, 
CONCAT(SUBSTRING($0, 1, 8), '01')))], joinType=[left], ctx=[])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapUnionRel(all=[true], ctx=[], all=[true])
+                  KapUnionRel(all=[true], ctx=[], all=[true])
+                    KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                      KapValuesRel(tuples=[[{ 0 }]])
+                    KapProjectRel(DATE_TIME=['2050-03-02'], ctx=[])
+                      KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+          KapTableScan(table=[[SSB, LINEORDER]], ctx=[], fields=[[0, 1, 2, 3, 
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]])
+]]>
+        </Resource>
+        <Resource name="query12.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(DATE_TIME=[$0], EXPR$1=[$1], EXPR$2=[$2], EXPR$3=[$3], 
EXPR$4=[$3], EXPR$5=[$4], SY=[$5], SR=[$6], ctx=[])
+    KapAggregateRel(group-set=[[0]], groups=[null], EXPR$1=[$SUM0($8)], 
EXPR$2=[$SUM0($9)], EXPR$3=[$SUM0($10)], EXPR$5=[$SUM0($11)], SY=[SUM($12)], 
SR=[SUM($13)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], $f1=[$1], EXPR$3=[$2], SY=[$3], 
LO_ORDERDATE=[$4], $f10=[$5], $f2=[$6], SR=[$7], $f8=[*($1, $5)], $f9=[*($1, 
$6)], $f1011=[*($2, $6)], $f11=[*($2, $5)], $f12=[CAST(*($3, $6)):BIGINT], 
$f13=[CAST(*($2, $7)):BIGINT], ctx=[])
+        KapJoinRel(condition=[=($0, $4)], joinType=[inner], ctx=[])
+          KapAggregateRel(group-set=[[0]], groups=[null], agg#0=[$SUM0($2)], 
EXPR$3=[$SUM0($3)], SY=[SUM($4)], ctx=[])
+            KapProjectRel(DATE_TIME=[$0], D_DATE=[$1], $f2=[CASE(IS NULL($2), 
CAST(0):BIGINT, $2)], $f3=[CASE(IS NULL($3), CAST(1):BIGINT, $3)], SY=[$4], 
ctx=[])
+              KapNonEquiJoinRel(condition=[AND(<=($1, $0), >=($1, 
CONCAT(SUBSTRING($0, 1, 8), '01')))], joinType=[left], ctx=[])
+                KapUnionRel(all=[true], ctx=[], all=[true])
+                  KapUnionRel(all=[true], ctx=[], all=[true])
+                    KapUnionRel(all=[true], ctx=[], all=[true])
+                      KapUnionRel(all=[true], ctx=[], all=[true])
+                        KapProjectRel(DATE_TIME=['1995-03-01'], ctx=[])
+                          KapValuesRel(tuples=[[{ 0 }]])
+                        KapProjectRel(DATE_TIME=['2050-03-02'], ctx=[])
+                          KapValuesRel(tuples=[[{ 0 }]])
+                      KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                        KapValuesRel(tuples=[[{ 0 }]])
+                    KapProjectRel(DATE_TIME=['1995-03-02'], ctx=[])
+                      KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-03-03'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapAggregateRel(group-set=[[1]], groups=[null], 
agg#0=[COUNT($15)], EXPR$3=[COUNT()], SY=[SUM($4)], ctx=[])
+                  KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+          KapAggregateRel(group-set=[[5]], groups=[null], agg#0=[COUNT($2)], 
agg#1=[COUNT()], SR=[SUM($12)], ctx=[])
+            KapTableScan(table=[[SSB, LINEORDER]], ctx=[], fields=[[0, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]])
+]]>
+        </Resource>
+        <Resource name="query13.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$2], MIN_DAYOFWEEK=[$3], DATE_TIME=[$1], 
D_DATE=[$0], ctx=[])
+    KapAggregateRel(group-set=[[0, 1, 2]], groups=[null], 
MIN_DAYOFWEEK=[COUNT($3)], ctx=[])
+      KapProjectRel(D_DATE=[$1], DATE_TIME=[$17], D_DATEKEY=[$0], 
D_DAYOFWEEK=[$2], ctx=[])
+        KapJoinRel(condition=[=($0, $17)], joinType=[inner], ctx=[])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapUnionRel(all=[false], ctx=[], all=[false])
+                  KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-05-17'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query13.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$0], MIN_DAYOFWEEK=[$3], DATE_TIME=[$2], 
D_DATE=[$1], ctx=[])
+    KapAggregateRel(group-set=[[0, 1, 3]], groups=[null], 
MIN_DAYOFWEEK=[$SUM0($2)], ctx=[])
+      KapJoinRel(condition=[=($0, $3)], joinType=[inner], ctx=[])
+        KapAggregateRel(group-set=[[0, 1]], groups=[null], 
MIN_DAYOFWEEK=[COUNT($2)], ctx=[])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+        KapUnionRel(all=[true], ctx=[], all=[true])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[false], ctx=[], all=[false])
+                KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(DATE_TIME=['1995-05-17'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query14.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$1], SUM_YEAR=[$2], DATE_TIME=[$0], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], SUM_YEAR=[COUNT($2)], 
ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_DATEKEY=[$1], D_YEAR=[$5], ctx=[])
+        KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapUnionRel(all=[false], ctx=[], all=[false])
+                  KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-05-17'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query14.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$1], SUM_YEAR=[$2], DATE_TIME=[$0], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], SUM_YEAR=[$SUM0($2)], 
ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_DATEKEY=[$1], $f2=[CASE(IS NULL($2), 
CAST(0):BIGINT, $2)], ctx=[])
+        KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapUnionRel(all=[false], ctx=[], all=[false])
+                  KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-05-17'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapAggregateRel(group-set=[[0]], groups=[null], 
SUM_YEAR=[COUNT($4)], ctx=[])
+            KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query15.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(C_NAME=[$0], COUNT_ORDER=[$2], LO_ORDERDATE=[$1], 
SUM_CUSTKEY=[$3], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], 
COUNT_ORDER=[COUNT($2)], SUM_CUSTKEY=[SUM($3)], ctx=[])
+      KapProjectRel(C_NAME=[$22], LO_ORDERDATE=[$5], LO_ORDERKEY=[$0], 
C_CUSTKEY=[$21], ctx=[])
+        KapJoinRel(condition=[=($2, $21)], joinType=[inner], ctx=[])
+          KapTableScan(table=[[SSB, LINEORDER]], ctx=[], fields=[[0, 1, 2, 3, 
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]])
+          KapTableScan(table=[[SSB, CUSTOMER]], ctx=[], fields=[[0, 1, 2, 3, 
4, 5, 6, 7]])
+]]>
+        </Resource>
+        <Resource name="query15.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(C_NAME=[$1], COUNT_ORDER=[$2], LO_ORDERDATE=[$0], 
SUM_CUSTKEY=[$3], ctx=[])
+    KapAggregateRel(group-set=[[5, 22]], groups=[null], 
COUNT_ORDER=[COUNT($0)], SUM_CUSTKEY=[SUM($21)], ctx=[])
+      KapJoinRel(condition=[=($2, $21)], joinType=[inner], ctx=[])
+        KapTableScan(table=[[SSB, LINEORDER]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]])
+        KapTableScan(table=[[SSB, CUSTOMER]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7]])
+]]>
+        </Resource>
+        <Resource name="query16.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$1], COUNT_YEAR=[$2], DATE_TIME=[$0], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], COUNT_YEAR=[COUNT($2)], 
ctx=[])
+      KapProjectRel(DATE_TIME=[$0], D_DATEKEY=[$1], D_YEAR=[$5], ctx=[])
+        KapFilterRel(condition=[=($4, 'May')], ctx=[])
+          KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapUnionRel(all=[true], ctx=[], all=[true])
+                  KapUnionRel(all=[false], ctx=[], all=[false])
+                    KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                      KapValuesRel(tuples=[[{ 0 }]])
+                    KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                      KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-05-17'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query16.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(D_DATEKEY=[$1], COUNT_YEAR=[$2], DATE_TIME=[$0], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], COUNT_YEAR=[COUNT($5)], 
ctx=[])
+      KapFilterRel(condition=[=($4, 'May')], ctx=[])
+        KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+          KapUnionRel(all=[true], ctx=[], all=[true])
+            KapUnionRel(all=[true], ctx=[], all=[true])
+              KapUnionRel(all=[true], ctx=[], all=[true])
+                KapUnionRel(all=[false], ctx=[], all=[false])
+                  KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                  KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                    KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+            KapProjectRel(DATE_TIME=['1995-05-17'], ctx=[])
+              KapValuesRel(tuples=[[{ 0 }]])
+          KapTableScan(table=[[SSB, DATES]], ctx=[], fields=[[0, 1, 2, 3, 4, 
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]])
+]]>
+        </Resource>
+        <Resource name="query17.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(C_NAME=[$0], COUNT_ORDER=[$3], LO_ORDERDATE=[$1], 
DATE_TIME=[$2], SUM_CUSTKEY=[$4], ctx=[])
+    KapAggregateRel(group-set=[[0, 1, 2]], groups=[null], 
COUNT_ORDER=[COUNT($3)], SUM_CUSTKEY=[SUM($4)], ctx=[])
+      KapProjectRel(C_NAME=[$22], LO_ORDERDATE=[$5], DATE_TIME=[$29], 
LO_ORDERKEY=[$0], C_CUSTKEY=[$21], ctx=[])
+        KapJoinRel(condition=[=($5, $29)], joinType=[inner], ctx=[])
+          KapJoinRel(condition=[=($2, $21)], joinType=[inner], ctx=[])
+            KapTableScan(table=[[SSB, LINEORDER]], ctx=[], fields=[[0, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]])
+            KapTableScan(table=[[SSB, CUSTOMER]], ctx=[], fields=[[0, 1, 2, 3, 
4, 5, 6, 7]])
+          KapProjectRel(DATE_TIME=['1996-01-02'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query17.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(C_NAME=[$1], COUNT_ORDER=[$3], LO_ORDERDATE=[$0], 
DATE_TIME=[$2], SUM_CUSTKEY=[$4], ctx=[])
+    KapAggregateRel(group-set=[[0, 1, 4]], groups=[null], 
COUNT_ORDER=[$SUM0($2)], SUM_CUSTKEY=[SUM($3)], ctx=[])
+      KapJoinRel(condition=[=($0, $4)], joinType=[inner], ctx=[])
+        KapAggregateRel(group-set=[[5, 22]], groups=[null], 
COUNT_ORDER=[COUNT($0)], SUM_CUSTKEY=[SUM($21)], ctx=[])
+          KapJoinRel(condition=[=($2, $21)], joinType=[inner], ctx=[])
+            KapTableScan(table=[[SSB, LINEORDER]], ctx=[], fields=[[0, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]])
+            KapTableScan(table=[[SSB, CUSTOMER]], ctx=[], fields=[[0, 1, 2, 3, 
4, 5, 6, 7]])
+        KapProjectRel(DATE_TIME=['1996-01-02'], ctx=[])
+          KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query18.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(C_NAME=[$0], COUNT_ORDER=[$4], LO_ORDERDATE=[$1], 
DATE_TIME=[$2], DATE_TIME0=[$3], SUM_CUSTKEY=[$5], ctx=[])
+    KapAggregateRel(group-set=[[0, 1, 2, 3]], groups=[null], 
COUNT_ORDER=[COUNT($4)], SUM_CUSTKEY=[SUM($5)], ctx=[])
+      KapProjectRel(C_NAME=[$3], LO_ORDERDATE=[$1], DATE_TIME=[$0], $f3=[$5], 
LO_ORDERKEY=[$2], C_CUSTKEY=[$4], ctx=[])
+        KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+          KapProjectRel(DATE_TIME=['1996-01-02'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+          KapProjectRel(LO_ORDERDATE=[$0], LO_ORDERKEY=[$1], C_NAME=[$2], 
C_CUSTKEY=[$3], DATE_TIME=[$4], ctx=[])
+            KapProjectRel(LO_ORDERDATE=[$0], LO_ORDERKEY=[$1], C_NAME=[$2], 
C_CUSTKEY=[$3], DATE_TIME=[$5], ctx=[])
+              KapJoinRel(condition=[=($0, $5)], joinType=[inner], ctx=[])
+                KapProjectRel(LO_ORDERDATE=[$5], LO_ORDERKEY=[$0], 
C_NAME=[$22], C_CUSTKEY=[$21], DATE_TIME=[$29], ctx=[])
+                  KapJoinRel(condition=[=($5, $29)], joinType=[inner], ctx=[])
+                    KapJoinRel(condition=[=($2, $21)], joinType=[inner], 
ctx=[])
+                      KapTableScan(table=[[SSB, LINEORDER]], ctx=[], 
fields=[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 
20]])
+                      KapTableScan(table=[[SSB, CUSTOMER]], ctx=[], 
fields=[[0, 1, 2, 3, 4, 5, 6, 7]])
+                    KapUnionRel(all=[false], ctx=[], all=[false])
+                      KapUnionRel(all=[true], ctx=[], all=[true])
+                        KapUnionRel(all=[true], ctx=[], all=[true])
+                          KapUnionRel(all=[true], ctx=[], all=[true])
+                            KapUnionRel(all=[false], ctx=[], all=[false])
+                              KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                                KapValuesRel(tuples=[[{ 0 }]])
+                              KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                                KapValuesRel(tuples=[[{ 0 }]])
+                            KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                              KapValuesRel(tuples=[[{ 0 }]])
+                          KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                            KapValuesRel(tuples=[[{ 0 }]])
+                        KapProjectRel(DATE_TIME=['1996-01-02'], ctx=[])
+                          KapValuesRel(tuples=[[{ 0 }]])
+                      KapProjectRel(DATE_TIME=['1995-06-01'], ctx=[])
+                        KapValuesRel(tuples=[[{ 0 }]])
+                KapProjectRel(DATE_TIME=['1996-01-02'], ctx=[])
+                  KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query18.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(C_NAME=[$2], COUNT_ORDER=[$4], LO_ORDERDATE=[$1], 
DATE_TIME=[$0], DATE_TIME0=[$3], SUM_CUSTKEY=[$5], ctx=[])
+    KapAggregateRel(group-set=[[0, 1, 2, 3]], groups=[null], 
COUNT_ORDER=[$SUM0($4)], SUM_CUSTKEY=[SUM($5)], ctx=[])
+      KapProjectRel(DATE_TIME=[$0], LO_ORDERDATE=[$1], C_NAME=[$2], 
DATE_TIME0=[$3], $f4=[CASE(IS NULL($4), CAST(0):BIGINT, $4)], SUM_CUSTKEY=[$5], 
ctx=[])
+        KapJoinRel(condition=[=($0, $1)], joinType=[left], ctx=[])
+          KapProjectRel(DATE_TIME=['1996-01-02'], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+          KapAggregateRel(group-set=[[0, 1, 4]], groups=[null], 
COUNT_ORDER=[$SUM0($2)], SUM_CUSTKEY=[SUM($3)], ctx=[])
+            KapJoinRel(condition=[=($0, $4)], joinType=[inner], ctx=[])
+              KapAggregateRel(group-set=[[0, 1]], groups=[null], 
COUNT_ORDER=[$SUM0($2)], SUM_CUSTKEY=[SUM($3)], ctx=[])
+                KapJoinRel(condition=[=($0, $4)], joinType=[inner], ctx=[])
+                  KapAggregateRel(group-set=[[5, 22]], groups=[null], 
COUNT_ORDER=[COUNT($0)], SUM_CUSTKEY=[SUM($21)], ctx=[])
+                    KapJoinRel(condition=[=($2, $21)], joinType=[inner], 
ctx=[])
+                      KapTableScan(table=[[SSB, LINEORDER]], ctx=[], 
fields=[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 
20]])
+                      KapTableScan(table=[[SSB, CUSTOMER]], ctx=[], 
fields=[[0, 1, 2, 3, 4, 5, 6, 7]])
+                  KapUnionRel(all=[false], ctx=[], all=[false])
+                    KapUnionRel(all=[true], ctx=[], all=[true])
+                      KapUnionRel(all=[true], ctx=[], all=[true])
+                        KapUnionRel(all=[true], ctx=[], all=[true])
+                          KapUnionRel(all=[false], ctx=[], all=[false])
+                            KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                              KapValuesRel(tuples=[[{ 0 }]])
+                            KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                              KapValuesRel(tuples=[[{ 0 }]])
+                          KapProjectRel(DATE_TIME=['1995-03-29'], ctx=[])
+                            KapValuesRel(tuples=[[{ 0 }]])
+                        KapProjectRel(DATE_TIME=['1995-04-01'], ctx=[])
+                          KapValuesRel(tuples=[[{ 0 }]])
+                      KapProjectRel(DATE_TIME=['1996-01-02'], ctx=[])
+                        KapValuesRel(tuples=[[{ 0 }]])
+                    KapProjectRel(DATE_TIME=['1995-06-01'], ctx=[])
+                      KapValuesRel(tuples=[[{ 0 }]])
+              KapProjectRel(DATE_TIME=['1996-01-02'], ctx=[])
+                KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query19.planBefore">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(EXPR$0=[$2], LO_ORDERDATE=[$0], DATE_TIME=[$1], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$0=[SUM($2)], 
ctx=[])
+      KapProjectRel(LO_ORDERDATE=[$5], DATE_TIME=[$18], $f2=[*($9, 3)], ctx=[])
+        KapJoinRel(condition=[=($5, $18)], joinType=[inner], ctx=[])
+          KapTableScan(table=[[SSB, P_LINEORDER]], ctx=[], fields=[[0, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]])
+          KapProjectRel(DATE_TIME=[19931014], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+        <Resource name="query19.planAfter">
+            <![CDATA[
+KapOLAPToEnumerableConverter
+  KapProjectRel(EXPR$0=[$2], LO_ORDERDATE=[$0], DATE_TIME=[$1], ctx=[])
+    KapAggregateRel(group-set=[[0, 1]], groups=[null], EXPR$0=[SUM($2)], 
ctx=[])
+      KapProjectRel(LO_ORDERDATE=[$5], DATE_TIME=[$18], $f2=[*($9, 3)], ctx=[])
+        KapJoinRel(condition=[=($5, $18)], joinType=[inner], ctx=[])
+          KapTableScan(table=[[SSB, P_LINEORDER]], ctx=[], fields=[[0, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]])
+          KapProjectRel(DATE_TIME=[19931014], ctx=[])
+            KapValuesRel(tuples=[[{ 0 }]])
+]]>
+        </Resource>
+
+    </TestCase>
+</Root>
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query01.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query01.sql
new file mode 100644
index 0000000000..b757e10ec3
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query01.sql
@@ -0,0 +1,26 @@
+--
+-- 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.
+--
+
+
+SELECT D_DATEKEY,
+       DATE_TIME,
+       sum(D_YEAR) total
+FROM (SELECT '1995-03-01' AS DATE_TIME) dt
+         LEFT JOIN SSB.DATES t2 ON dt.DATE_TIME = t2.D_DATEKEY
+GROUP BY D_DATEKEY,
+         DATE_TIME
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query02.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query02.sql
new file mode 100644
index 0000000000..dec0698161
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query02.sql
@@ -0,0 +1,30 @@
+--
+-- 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.
+--
+
+
+SELECT D_DATEKEY,
+       DATE_TIME,
+       sum(D_YEAR) total
+FROM (SELECT '1995-03-01' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME) dt
+         LEFT JOIN SSB.DATES t2 ON dt.DATE_TIME = t2.D_DATEKEY
+GROUP BY D_DATEKEY,
+         DATE_TIME
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query03.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query03.sql
new file mode 100644
index 0000000000..a7221b72cc
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query03.sql
@@ -0,0 +1,32 @@
+--
+-- 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.
+--
+
+
+SELECT D_DATE,
+       DATE_TIME,
+       count(*),
+       sum(D_YEAR) sy
+FROM (SELECT '1995-03-01' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME) t1
+         LEFT JOIN SSB.DATES t2 ON t2.D_DATE <= t1.DATE_TIME
+    AND t2.D_DATE >= CONCAT(SUBSTR(t1.DATE_TIME, 1, 8), '01')
+GROUP BY D_DATE,
+         DATE_TIME
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query04.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query04.sql
new file mode 100644
index 0000000000..30d8a26b5c
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query04.sql
@@ -0,0 +1,28 @@
+--
+-- 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.
+--
+
+
+SELECT D_DATEKEY,
+       total
+FROM (SELECT D_DATEKEY,
+             DATE_TIME,
+             sum(D_YEAR) total
+      FROM (SELECT '1995-03-01' AS DATE_TIME) dt
+               LEFT JOIN SSB.DATES t2 ON dt.DATE_TIME = t2.D_DATEKEY
+      GROUP BY D_DATEKEY,
+               DATE_TIME)
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query05.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query05.sql
new file mode 100644
index 0000000000..710afa2e03
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query05.sql
@@ -0,0 +1,37 @@
+--
+-- 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.
+--
+
+
+SELECT sum(D_DATEKEY) as sd,
+       D_DATE,
+       count(*),
+       DATE_TIME,
+       sum(D_YEAR)       sy,
+       sum(LO_REVENUE)   sr,
+       LO_ORDERDATE
+FROM (SELECT '1995-03-01' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME) t1
+         LEFT JOIN SSB.DATES t2 ON t2.D_DATE <= t1.DATE_TIME
+    AND t2.D_DATE >= CONCAT(SUBSTR(t1.DATE_TIME, 1, 8), '01')
+         INNER JOIN SSB.LINEORDER t3 ON t3.LO_ORDERDATE = t1.DATE_TIME
+GROUP BY D_DATE,
+         DATE_TIME,
+         LO_ORDERDATE
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query06.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query06.sql
new file mode 100644
index 0000000000..9c765a7b12
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query06.sql
@@ -0,0 +1,35 @@
+--
+-- 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.
+--
+
+
+SELECT D_DATE,
+       DATE_TIME,
+       count(*),
+       sum(D_YEAR) sy
+FROM (SELECT '1995-03-01' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME) t1
+         LEFT JOIN (
+    SELECT D_DATEKEY, D_YEAR, D_HOLIDAYFL, D_DATE
+    from SSB.DATES
+) t2 ON t2.D_DATE <= t1.DATE_TIME
+    AND t2.D_DATE >= CONCAT(SUBSTR(t1.DATE_TIME, 1, 8), '01')
+GROUP BY D_DATE,
+         DATE_TIME
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query07.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query07.sql
new file mode 100644
index 0000000000..85ce225b0e
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query07.sql
@@ -0,0 +1,33 @@
+--
+-- 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.
+--
+
+
+SELECT D_DATE,
+       DATE_TIME,
+       count(*),
+       sum(D_YEAR) sy
+FROM SSB.DATES t1
+         LEFT JOIN (SELECT '1995-03-01' AS DATE_TIME
+                    UNION ALL
+                    SELECT '1995-03-02' AS DATE_TIME
+                    UNION ALL
+                    SELECT '1995-03-03' AS DATE_TIME) t2
+                   ON t1.D_DATE <= t2.DATE_TIME
+                       AND t1.D_DATE >= CONCAT(SUBSTR(t2.DATE_TIME, 1, 8), 
'01')
+GROUP BY D_DATE,
+         DATE_TIME
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query08.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query08.sql
new file mode 100644
index 0000000000..2981e00b2c
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query08.sql
@@ -0,0 +1,36 @@
+--
+-- 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.
+--
+
+
+SELECT D_DATE,
+       DATE_TIME,
+       count(*),
+       sum(D_YEAR) sy
+FROM (
+         SELECT D_DATEKEY, D_YEAR, D_HOLIDAYFL, D_DATE
+         from SSB.DATES
+     ) t1
+         LEFT JOIN (SELECT '1995-03-01' AS DATE_TIME
+                    UNION ALL
+                    SELECT '1995-03-02' AS DATE_TIME
+                    UNION ALL
+                    SELECT '1995-03-03' AS DATE_TIME) t2
+                   ON t1.D_DATE <= t2.DATE_TIME
+                       AND t1.D_DATE >= CONCAT(SUBSTR(t2.DATE_TIME, 1, 8), 
'01')
+GROUP BY D_DATE,
+         DATE_TIME
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query09.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query09.sql
new file mode 100644
index 0000000000..571cb26cdd
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query09.sql
@@ -0,0 +1,36 @@
+--
+-- 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.
+--
+
+
+SELECT D_DATE,
+       DATE_TIME,
+       count(*),
+       sum(D_YEAR) sy
+FROM (SELECT '1995-03-01' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME) t1
+         LEFT JOIN (
+    SELECT D_DATEKEY, SUM(D_YEAR), D_YEAR, D_DATE
+    from SSB.DATES
+    GROUP BY D_DATEKEY, D_DATE, D_YEAR
+) t2 ON t2.D_DATE <= t1.DATE_TIME
+    AND t2.D_DATE >= CONCAT(SUBSTR(t1.DATE_TIME, 1, 8), '01')
+GROUP BY D_DATE,
+         DATE_TIME
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query10.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query10.sql
new file mode 100644
index 0000000000..3db46727bc
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query10.sql
@@ -0,0 +1,33 @@
+--
+-- 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.
+--
+
+
+SELECT count(*),
+       sum(D_YEAR) sy
+FROM (SELECT '1995-03-01' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '2300-03-03' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME) t1
+         LEFT JOIN SSB.DATES t2 ON t2.D_DATEKEY <= t1.DATE_TIME
+    AND t2.D_DATEKEY >= CONCAT(SUBSTR(t1.DATE_TIME, 1, 8), '01')
+GROUP BY DATE_TIME
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query11.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query11.sql
new file mode 100644
index 0000000000..29e3687de6
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query11.sql
@@ -0,0 +1,32 @@
+--
+-- 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.
+--
+
+
+SELECT count(*),
+       sum(D_YEAR) sy
+FROM (SELECT '1995-03-01' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '2300-03-03' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME) t1
+         LEFT JOIN SSB.DATES t2 ON t2.D_DATEKEY <= t1.DATE_TIME
+    AND t2.D_DATEKEY >= CONCAT(SUBSTR(t1.DATE_TIME, 1, 8), '01')
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query12.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query12.sql
new file mode 100644
index 0000000000..218cc57a5d
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query12.sql
@@ -0,0 +1,41 @@
+--
+-- 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.
+--
+
+
+SELECT DATE_TIME,
+       count(D_HOLIDAYFL, LO_CUSTKEY),
+       count(D_HOLIDAYFL),
+       count(*),
+       count(1),
+       count(LO_CUSTKEY),
+       sum(D_YEAR)     sy,
+       sum(LO_REVENUE) sr
+FROM (SELECT '1995-03-01' AS DATE_TIME
+      UNION ALL
+      SELECT '2050-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-02' AS DATE_TIME
+      UNION ALL
+      SELECT '1995-03-03' AS DATE_TIME) t1
+         LEFT JOIN SSB.DATES t2
+                   ON t2.D_DATE <= t1.DATE_TIME
+                       AND t2.D_DATE >= CONCAT(SUBSTR(t1.DATE_TIME, 1, 8), 
'01')
+         INNER JOIN SSB.LINEORDER t3 ON t3.LO_ORDERDATE = t1.DATE_TIME
+GROUP BY DATE_TIME
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query13.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query13.sql
new file mode 100644
index 0000000000..a026843a08
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query13.sql
@@ -0,0 +1,36 @@
+--
+-- 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.
+--
+
+
+select DATES.D_DATEKEY,
+       count(DATES.D_DAYOFWEEK) min_dayofweek,
+       DT.DATE_TIME,
+       DATES.D_DATE
+from SSB.DATES
+         inner join
+     (select '1995-03-29' as DATE_TIME
+      union
+      select '1995-04-01' as DATE_TIME
+      union all
+      select '1995-03-29' as DATE_TIME
+      union all
+      select '1995-04-01' as DATE_TIME
+      union all
+      select '1995-05-17' as DATE_TIME) DT
+     on DT.DATE_TIME = DATES.D_DATEKEY
+group by DATES.D_DATE, date_time, DATES.D_DATEKEY
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query14.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query14.sql
new file mode 100644
index 0000000000..fea673ec28
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query14.sql
@@ -0,0 +1,32 @@
+--
+-- 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.
+--
+
+
+select DATES.D_DATEKEY, count(DATES.D_YEAR) sum_year, DT.DATE_TIME
+from (select '1995-03-29' as DATE_TIME
+      union
+      select '1995-04-01' as DATE_TIME
+      union all
+      select '1995-03-29' as DATE_TIME
+      union all
+      select '1995-04-01' as DATE_TIME
+      union all
+      select '1995-05-17' as DATE_TIME) DT
+         left join SSB.DATES
+                   on DT.DATE_TIME = DATES.D_DATEKEY
+group by dt.date_time, DATES.D_DATEKEY
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query15.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query15.sql
new file mode 100644
index 0000000000..760bb2d3d2
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query15.sql
@@ -0,0 +1,27 @@
+--
+-- 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.
+--
+
+
+SELECT CUSTOMER.C_NAME,
+       count(LINEORDER.LO_ORDERKEY) count_order,
+       LINEORDER.LO_ORDERDATE,
+       sum(CUSTOMER.C_CUSTKEY)      sum_custkey
+FROM SSB.LINEORDER
+         INNER JOIN SSB.CUSTOMER ON LINEORDER.LO_CUSTKEY = CUSTOMER.C_CUSTKEY
+GROUP BY CUSTOMER.C_NAME,
+         LINEORDER.LO_ORDERDATE
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query16.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query16.sql
new file mode 100644
index 0000000000..1415b5025e
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query16.sql
@@ -0,0 +1,33 @@
+--
+-- 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.
+--
+
+
+select DATES.D_DATEKEY, count(DATES.D_YEAR) count_year, DT.DATE_TIME
+from (select '1995-03-29' as DATE_TIME
+      union
+      select '1995-04-01' as DATE_TIME
+      union all
+      select '1995-03-29' as DATE_TIME
+      union all
+      select '1995-04-01' as DATE_TIME
+      union all
+      select '1995-05-17' as DATE_TIME) DT
+         left join SSB.DATES on DT.DATE_TIME = DATES.D_DATEKEY
+where DATES.D_MONTH = 'May'
+group by dt.date_time, DATES.D_DATEKEY
+
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query17.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query17.sql
new file mode 100644
index 0000000000..7ca20a33a6
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query17.sql
@@ -0,0 +1,31 @@
+--
+-- 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.
+--
+
+
+SELECT CUSTOMER.C_NAME,
+       count(LINEORDER.LO_ORDERKEY) count_order,
+       LINEORDER.LO_ORDERDATE,
+       dt.DATE_TIME,
+       sum(CUSTOMER.C_CUSTKEY)      sum_custkey
+FROM "SSB"."LINEORDER" as "LINEORDER"
+         INNER JOIN "SSB"."CUSTOMER" as "CUSTOMER"
+                    on "LINEORDER"."LO_CUSTKEY" = "CUSTOMER"."C_CUSTKEY"
+         inner join (select '1996-01-02' as DATE_TIME) dt
+                    on LINEORDER.LO_ORDERDATE = dt.DATE_TIME
+group by CUSTOMER.C_NAME, LINEORDER.LO_ORDERDATE, dt.DATE_TIME
+
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query18.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query18.sql
new file mode 100644
index 0000000000..fc433c7e4b
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query18.sql
@@ -0,0 +1,65 @@
+--
+-- 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.
+--
+
+
+SELECT li.C_NAME,
+       count(li.LO_ORDERKEY) count_order,
+       li.LO_ORDERDATE,
+       dt1.DATE_TIME,
+       li.DATE_TIME,
+       sum(li.C_CUSTKEY)     sum_custkey
+FROM (SELECT '1996-01-02' AS DATE_TIME) dt1
+         LEFT JOIN
+     (SELECT third.LO_ORDERDATE,
+             third.LO_ORDERKEY,
+             third.C_NAME,
+             third.C_CUSTKEY,
+             third.DATE_TIME
+      FROM (SELECT dt2.LO_ORDERDATE,
+                   dt2.LO_ORDERKEY,
+                   dt2.C_NAME,
+                   dt2.C_CUSTKEY,
+                   dt4.DATE_TIME
+            FROM (SELECT LINEORDER.LO_ORDERDATE,
+                         LINEORDER.LO_ORDERKEY,
+                         CUSTOMER.C_NAME,
+                         CUSTOMER.C_CUSTKEY,
+                         dt.DATE_TIME
+                  FROM "SSB"."LINEORDER" AS "LINEORDER"
+                           INNER JOIN "SSB"."CUSTOMER" AS "CUSTOMER"
+                                      ON "LINEORDER"."LO_CUSTKEY" = 
"CUSTOMER"."C_CUSTKEY"
+                           INNER JOIN
+                       (SELECT '1995-03-29' AS DATE_TIME
+                        UNION
+                        SELECT '1995-04-01' AS DATE_TIME
+                        UNION ALL
+                        SELECT '1995-03-29' AS DATE_TIME
+                        UNION ALL
+                        SELECT '1995-04-01' AS DATE_TIME
+                        UNION ALL
+                        SELECT '1996-01-02' AS DATE_TIME
+                        UNION
+                        SELECT CASE WHEN 1 = 1 THEN '1995-06-01' ELSE 
'1995-07-01' END AS DATE_TIME) dt
+                       ON LINEORDER.LO_ORDERDATE = dt.DATE_TIME) dt2
+                     INNER JOIN
+                     (SELECT '1996-01-02' AS DATE_TIME) dt4 ON 
dt2.LO_ORDERDATE = dt4.DATE_TIME) third) li
+     ON dt1.DATE_TIME = li.LO_ORDERDATE
+GROUP BY li.C_NAME,
+         li.LO_ORDERDATE,
+         dt1.DATE_TIME,
+         li.DATE_TIME
\ No newline at end of file
diff --git 
a/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query19.sql 
b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query19.sql
new file mode 100644
index 0000000000..fe4e25e39c
--- /dev/null
+++ b/src/kylin-it/src/test/resources/query/sql_scalar_subquery/query19.sql
@@ -0,0 +1,26 @@
+--
+-- 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.
+--
+
+-- SQL not supported when there was RexCall in AggregateCall arguments.
+select sum(LINEORDER.LO_EXTENDEDPRICE * 3),
+       LINEORDER.LO_ORDERDATE,
+       dt.DATE_TIME
+from SSB.P_LINEORDER as LINEORDER
+         inner join (select 19931014 as DATE_TIME) dt
+                    on LINEORDER.LO_ORDERDATE = dt.DATE_TIME
+group by LO_ORDERDATE, dt.DATE_TIME
\ No newline at end of file
diff --git 
a/src/query-common/src/main/java/org/apache/kylin/query/relnode/KapValuesRel.java
 
b/src/query-common/src/main/java/org/apache/kylin/query/relnode/KapValuesRel.java
index 352c108961..cf8188d0ed 100644
--- 
a/src/query-common/src/main/java/org/apache/kylin/query/relnode/KapValuesRel.java
+++ 
b/src/query-common/src/main/java/org/apache/kylin/query/relnode/KapValuesRel.java
@@ -18,17 +18,15 @@
 
 package org.apache.kylin.query.relnode;
 
+import java.util.List;
 import java.util.Set;
 
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
-import org.apache.calcite.rel.RelCollationTraitDef;
-import org.apache.calcite.rel.RelDistributionTraitDef;
-import org.apache.calcite.rel.metadata.RelMdCollation;
-import org.apache.calcite.rel.metadata.RelMdDistribution;
-import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexLiteral;
+import org.apache.kylin.guava30.shaded.common.base.Preconditions;
 import org.apache.kylin.guava30.shaded.common.collect.Sets;
 import org.apache.kylin.query.util.ICutContextStrategy;
 
@@ -37,18 +35,15 @@ import com.google.common.collect.ImmutableList;
 public class KapValuesRel extends OLAPValuesRel implements KapRel {
     private Set<OLAPContext> subContexts = Sets.newHashSet();
 
-    private KapValuesRel(RelOptCluster cluster, RelDataType rowType, 
ImmutableList<ImmutableList<RexLiteral>> tuples,
+    public KapValuesRel(RelOptCluster cluster, RelDataType rowType, 
ImmutableList<ImmutableList<RexLiteral>> tuples,
             RelTraitSet traitSet) {
         super(cluster, rowType, tuples, traitSet);
     }
 
-    public static KapValuesRel create(RelOptCluster cluster, final RelDataType 
rowType,
-            final ImmutableList<ImmutableList<RexLiteral>> tuples) {
-        final RelMetadataQuery mq = cluster.getMetadataQuery();
-        final RelTraitSet traitSet = cluster.traitSetOf(OLAPRel.CONVENTION)
-                .replaceIfs(RelCollationTraitDef.INSTANCE, () -> 
RelMdCollation.values(mq, rowType, tuples))
-                .replaceIf(RelDistributionTraitDef.INSTANCE, () -> 
RelMdDistribution.values(rowType, tuples));
-        return new KapValuesRel(cluster, rowType, tuples, traitSet);
+    @Override
+    public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
+        Preconditions.checkArgument(inputs.isEmpty());
+        return new KapValuesRel(getCluster(), rowType, tuples, 
replaceTraitSet(getCluster(), rowType, tuples));
     }
 
     @Override
diff --git 
a/src/query-common/src/main/java/org/apache/kylin/query/relnode/OLAPValuesRel.java
 
b/src/query-common/src/main/java/org/apache/kylin/query/relnode/OLAPValuesRel.java
index 098e7712f8..55992e448f 100644
--- 
a/src/query-common/src/main/java/org/apache/kylin/query/relnode/OLAPValuesRel.java
+++ 
b/src/query-common/src/main/java/org/apache/kylin/query/relnode/OLAPValuesRel.java
@@ -38,6 +38,7 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexLiteral;
+import org.apache.kylin.guava30.shaded.common.base.Preconditions;
 import org.apache.kylin.guava30.shaded.common.collect.Lists;
 import org.apache.kylin.metadata.model.TblColRef;
 
@@ -69,8 +70,8 @@ public class OLAPValuesRel extends Values implements OLAPRel {
 
     @Override
     public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
-        assert inputs.isEmpty();
-        return create(getCluster(), rowType, tuples);
+        Preconditions.checkArgument(inputs.isEmpty());
+        return new OLAPValuesRel(getCluster(), rowType, tuples, 
replaceTraitSet(getCluster(), rowType, tuples));
     }
 
     @Override
@@ -119,4 +120,12 @@ public class OLAPValuesRel extends Values implements 
OLAPRel {
     public EnumerableRel implementEnumerable(List<EnumerableRel> inputs) {
         return EnumerableValues.create(getCluster(), getRowType(), 
getTuples());
     }
+
+    public static RelTraitSet replaceTraitSet(RelOptCluster cluster, 
RelDataType rowType, //
+            ImmutableList<ImmutableList<RexLiteral>> tuples) {
+        final RelMetadataQuery mq = cluster.getMetadataQuery();
+        return cluster.traitSetOf(OLAPRel.CONVENTION)
+                .replaceIfs(RelCollationTraitDef.INSTANCE, () -> 
RelMdCollation.values(mq, rowType, tuples))
+                .replaceIf(RelDistributionTraitDef.INSTANCE, () -> 
RelMdDistribution.values(rowType, tuples));
+    }
 }
diff --git 
a/src/query/src/main/java/io/kyligence/kap/query/optrule/KAPValuesRule.java 
b/src/query/src/main/java/io/kyligence/kap/query/optrule/KAPValuesRule.java
index f9db2c1ba9..de867da672 100644
--- a/src/query/src/main/java/io/kyligence/kap/query/optrule/KAPValuesRule.java
+++ b/src/query/src/main/java/io/kyligence/kap/query/optrule/KAPValuesRule.java
@@ -18,11 +18,15 @@
 package io.kyligence.kap.query.optrule;
 
 import org.apache.calcite.plan.Convention;
+import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.core.Values;
-import org.apache.kylin.query.relnode.OLAPRel;
+import org.apache.calcite.rel.type.RelDataType;
 import org.apache.kylin.query.relnode.KapValuesRel;
+import org.apache.kylin.query.relnode.OLAPRel;
+import org.apache.kylin.query.relnode.OLAPValuesRel;
 
 public class KAPValuesRule extends ConverterRule {
     public static final KAPValuesRule INSTANCE = new KAPValuesRule();
@@ -34,6 +38,9 @@ public class KAPValuesRule extends ConverterRule {
     @Override
     public RelNode convert(RelNode rel) {
         Values values = (Values) rel;
-        return KapValuesRel.create(values.getCluster(), values.getRowType(), 
values.getTuples());
+        RelOptCluster cluster = values.getCluster();
+        RelDataType rowType = values.getRowType();
+        RelTraitSet relTraits = OLAPValuesRel.replaceTraitSet(cluster, 
rowType, values.getTuples());
+        return new KapValuesRel(cluster, rowType, values.getTuples(), 
relTraits);
     }
 }
diff --git 
a/src/query/src/main/java/io/kyligence/kap/query/optrule/ScalarSubqueryJoinRule.java
 
b/src/query/src/main/java/io/kyligence/kap/query/optrule/ScalarSubqueryJoinRule.java
new file mode 100644
index 0000000000..e4b335334d
--- /dev/null
+++ 
b/src/query/src/main/java/io/kyligence/kap/query/optrule/ScalarSubqueryJoinRule.java
@@ -0,0 +1,799 @@
+/*
+ * 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 io.kyligence.kap.query.optrule;
+
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.apache.calcite.linq4j.Ord;
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptRuleOperand;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.hep.HepRelVertex;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.AggregateCall;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.metadata.RelMetadataQuery;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.SqlAggFunction;
+import org.apache.calcite.sql.SqlSplittableAggFunction;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.mapping.Mapping;
+import org.apache.calcite.util.mapping.MappingType;
+import org.apache.calcite.util.mapping.Mappings;
+import org.apache.kylin.guava30.shaded.common.base.Preconditions;
+import org.apache.kylin.guava30.shaded.common.collect.ImmutableList;
+import org.apache.kylin.guava30.shaded.common.collect.Lists;
+import org.apache.kylin.guava30.shaded.common.collect.Maps;
+import org.apache.kylin.query.relnode.KapAggregateRel;
+import org.apache.kylin.query.relnode.KapFilterRel;
+import org.apache.kylin.query.relnode.KapJoinRel;
+import org.apache.kylin.query.relnode.KapNonEquiJoinRel;
+import org.apache.kylin.query.relnode.KapProjectRel;
+import org.apache.kylin.query.relnode.KapValuesRel;
+
+public class ScalarSubqueryJoinRule extends RelOptRule {
+
+    // JOIN_PREDICATE from guava's Predicate,
+
+    public static final ScalarSubqueryJoinRule AGG_JOIN = new 
ScalarSubqueryJoinRule(//
+            operand(KapAggregateRel.class, //
+                    operand(Join.class, //
+                            null, j -> j instanceof KapJoinRel || j instanceof 
KapNonEquiJoinRel, any())),
+            RelFactories.LOGICAL_BUILDER, "ScalarSubqueryJoinRule:AGG_JOIN");
+
+    public static final ScalarSubqueryJoinRule AGG_PRJ_JOIN = new 
ScalarSubqueryJoinRule(//
+            operand(KapAggregateRel.class, //
+                    operand(KapProjectRel.class, //
+                            operand(Join.class, //
+                                    null, j -> j instanceof KapJoinRel || j 
instanceof KapNonEquiJoinRel, any()))),
+            RelFactories.LOGICAL_BUILDER, 
"ScalarSubqueryJoinRule:AGG_PRJ_JOIN");
+
+    public static final ScalarSubqueryJoinRule AGG_PRJ_FLT_JOIN = new 
ScalarSubqueryJoinRule(//
+            operand(KapAggregateRel.class, //
+                    operand(KapProjectRel.class, //
+                            operand(KapFilterRel.class, //
+                                    operand(Join.class, //
+                                            null, //
+                                            j -> j instanceof KapJoinRel || j 
instanceof KapNonEquiJoinRel, any())))), //
+            RelFactories.LOGICAL_BUILDER, 
"ScalarSubqueryJoinRule:AGG_PRJ_FLT_JOIN");
+
+    public ScalarSubqueryJoinRule(RelOptRuleOperand operand, RelBuilderFactory 
relBuilderFactory, String description) {
+        super(operand, relBuilderFactory, description);
+    }
+
+    @Override
+    public boolean matches(RelOptRuleCall call) {
+        Join join = call.rel(call.rels.length - 1);
+        switch (join.getJoinType()) {
+        case INNER:
+        case LEFT:
+            break;
+        default:
+            return false;
+        }
+
+        KapAggregateRel aggregate = call.rel(0);
+        if (!aggregate.isSimpleGroupType() || 
aggregate.getAggCallList().isEmpty()) {
+            return false;
+        }
+
+        // If any aggregate functions do not support splitting, bail outer
+        // If any aggregate call has a filter or is distinct, bail out.
+        // To-do: Count-distinct is currently not supported,
+        //  but this can be achieved in case of scalar-subquery with distinct 
values.
+        if (aggregate.getAggCallList().stream().anyMatch(a -> a.hasFilter() //
+                || a.isDistinct() //
+                || 
Objects.isNull(a.getAggregation().unwrap(SqlSplittableAggFunction.class)))) {
+            return false;
+        }
+
+        return !(call.rel(1) instanceof KapProjectRel) || 
canApplyRule(call.rel(1));
+    }
+
+    @Override
+    public void onMatch(RelOptRuleCall call) {
+        Transposer transposer = new Transposer(call);
+        if (!transposer.canTranspose()) {
+            return;
+        }
+
+        RelNode relNode = transposer.getTransposedRel();
+        call.transformTo(relNode);
+    }
+
+    private boolean canApplyRule(KapProjectRel project) {
+        if 
(project.getProjects().stream().anyMatch(RexCall.class::isInstance)) {
+            // to-do: maybe we should support this.
+            return false;
+        }
+        final ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
+        project.getProjects().forEach(p -> 
builder.addAll(RelOptUtil.InputFinder.bits(p)));
+        // Avoid re-entry of rule.
+        return project.getProjects().size() <= builder.build().cardinality();
+    }
+
+    private <E> SqlSplittableAggFunction.Registry<E> createRegistry(final 
List<E> list) {
+        return e -> {
+            int i = list.indexOf(e);
+            if (i < 0) {
+                i = list.size();
+                list.add(e);
+            }
+            return i;
+        };
+    }
+
+    private class Transposer {
+        // base variables
+        private final RelOptRuleCall call;
+        private final AggregateUnit aggUnit;
+        private final Join join;
+
+        // join sides
+        private final LeftSide left;
+        private final RightSide right;
+
+        // maintainer
+        public Transposer(RelOptRuleCall ruleCall) {
+            // call -> "aggunit, join"
+            call = ruleCall;
+            aggUnit = createAggUnit(ruleCall);
+            join = ruleCall.rel(ruleCall.rels.length - 1);
+
+            // join sides
+            RelMetadataQuery mq = call.getMetadataQuery();
+            ImmutableBitSet joinCondSet = 
RelOptUtil.InputFinder.bits(join.getCondition());
+            ImmutableBitSet aggUnitJoinSet = 
aggUnit.getUnitSet().union(joinCondSet);
+            left = new LeftSide(join.getLeft(), join.getInput(0), mq, 
aggUnitJoinSet);
+            right = new RightSide(left, join.getRight(), join.getInput(1), mq, 
aggUnitJoinSet);
+        }
+
+        public boolean canTranspose() {
+            if (left.hasRelValues() && right.isAggregable()) {
+                return true;
+            }
+
+            return right.hasRelValues() && left.isAggregable();
+        }
+
+        public RelNode getTransposedRel() {
+            // builders
+            final RelBuilder relBuilder = call.builder();
+            final RexBuilder rexBuilder = aggUnit.getRexBuilder();
+
+            // below aggregate
+            left.modifyAggregate(aggUnit, relBuilder, rexBuilder);
+            right.modifyAggregate(aggUnit, relBuilder, rexBuilder);
+
+            // aggunit-join mapping
+            final Mapping aggUnitJoinMapping = getAggUnitJoinMapping();
+
+            // create new join
+            final RexNode joinCond = RexUtil.apply(aggUnitJoinMapping, 
join.getCondition());
+            
relBuilder.push(left.getNewInput()).push(right.getNewInput()).join(join.getJoinType(),
 joinCond);
+
+            if (aggUnit instanceof AggregateProjectFilter) {
+                // create new filter
+                // To-do: maybe we could also push down the relative filter.
+                final RexNode filterCond = RexUtil.apply(aggUnitJoinMapping, //
+                        ((AggregateProjectFilter) aggUnit).getFilterCond());
+                relBuilder.filter(filterCond);
+            }
+
+            // agg-project mapping
+            final Mapping projectMapping = getProjectMapping(relBuilder, 
aggUnitJoinMapping);
+
+            // aggregate above to sum up the sub-totals
+            final List<RexNode> projectList = //
+                    Mappings.apply(projectMapping, //
+                            
Lists.newArrayList(rexBuilder.identityProjects(relBuilder.peek().getRowType())));
+
+            final List<AggregateCall> aggCallList = Lists.newArrayList();
+            aggregateAbove(projectList, aggCallList, relBuilder, rexBuilder);
+
+            // create new project
+            relBuilder.project(projectList);
+
+            // above aggregate
+            // To-do: maybe we could convert aggregate into projects when 
inner-join.
+            final RelBuilder.GroupKey groupKey = //
+                    relBuilder.groupKey(Mappings.apply(projectMapping, //
+                            Mappings.apply(aggUnitJoinMapping, 
aggUnit.getGroupSet())), //
+                            Mappings.apply2(projectMapping, //
+                                    Mappings.apply2(aggUnitJoinMapping, 
aggUnit.getGroupSets())));
+            relBuilder.aggregate(groupKey, aggCallList);
+
+            return relBuilder.build();
+        }
+
+        private Mapping getProjectMapping(final RelBuilder relBuilder, final 
Mapping aggMapping) {
+            final List<Integer> fieldList = //
+                    IntStream.range(0, 
relBuilder.peek().getRowType().getFieldList().size()) //
+                            .boxed().collect(Collectors.toList());
+            final List<Integer> groupList = //
+                    
aggUnit.getGroupList().stream().map(aggMapping::getTarget).collect(Collectors.toList());
+
+            // [i0, i1, i2, i3, i4] -> [i1, i3, i0, i2, i4]
+            final Mapping projectMapping = //
+                    Mappings.create(MappingType.BIJECTION, fieldList.size(), 
fieldList.size());
+
+            Ord.zip(fieldList).forEach(o -> projectMapping.set(o.i, o.e));
+            Ord.zip(groupList).forEach(o -> projectMapping.set(o.e, o.i));
+
+            return projectMapping;
+        }
+
+        private AggregateUnit createAggUnit(RelOptRuleCall call) {
+            if (call.rels.length > 3) {
+                return new AggregateProjectFilter(call.rel(0), call.rel(1), 
call.rel(2));
+            }
+            if (call.rels.length > 2) {
+                return new AggregateProject(call.rel(0), call.rel(1));
+            }
+            return new AggregateUnit(call.rel(0));
+        }
+
+        private void aggregateAbove(final List<RexNode> projectList, //
+                final List<AggregateCall> aggCallList, //
+                final RelBuilder relBuilder, //
+                final RexBuilder rexBuilder) {
+            final int newLeftWidth = left.getNewInputFieldCount();
+            final int groupIndicatorCount = aggUnit.getGroupIndicatorCount();
+            final SqlSplittableAggFunction.Registry<RexNode> projectRegistry = 
createRegistry(projectList);
+            Ord.zip(aggUnit.getAggCallList()).forEach(aggCallOrd -> {
+                // No need to care about args' mapping.
+                AggregateCall aggCall = aggCallOrd.e;
+                SqlAggFunction aggFunc = aggCall.getAggregation();
+                SqlSplittableAggFunction splitAggFunc = Preconditions
+                        
.checkNotNull(aggFunc.unwrap(SqlSplittableAggFunction.class));
+                Integer lst = left.getAggOrdinal(aggCallOrd.i);
+                Integer rst = right.getAggOrdinal(aggCallOrd.i);
+                final AggregateCall newAggCall = //
+                        splitAggFunc.topSplit(rexBuilder, projectRegistry, 
groupIndicatorCount, //
+                                relBuilder.peek().getRowType(), aggCall, //
+                                Objects.isNull(lst) ? -1 : lst, //
+                                Objects.isNull(rst) ? -1 : rst + newLeftWidth);
+
+                if (aggCall.getAggregation() == SqlStdOperatorTable.COUNT //
+                        && newAggCall.getAggregation() == 
SqlStdOperatorTable.SUM0) {
+                    aboveCountSum0(rexBuilder, aggCall, newAggCall, 
projectList);
+                }
+
+                aggCallList.add(newAggCall);
+            });
+        }
+
+        private void aboveCountSum0(final RexBuilder rexBuilder, //
+                AggregateCall aggCall, //
+                AggregateCall newAggCall, //
+                final List<RexNode> projectList) {
+            // COUNT(*), COUNT(1), COUNT(COL), COUNT(COL1, COL2, ...)
+            final boolean nullAsOne = aggCall.getArgList().isEmpty();
+            newAggCall.getArgList().forEach(i -> {
+                // old project node
+                RexNode p = projectList.get(i);
+                // when-then-else
+                List<RexNode> wte = Lists.newLinkedList();
+                wte.add(rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, p));
+                if (nullAsOne) {
+                    wte.add(rexBuilder.makeLiteral(BigDecimal.ONE, 
p.getType(), true));
+                } else {
+                    wte.add(rexBuilder.makeZeroLiteral(p.getType()));
+                }
+
+                wte.add(p);
+                // new project node
+                RexNode np = rexBuilder.makeCall(p.getType(), 
SqlStdOperatorTable.CASE, wte);
+                projectList.set(i, np);
+            });
+        }
+
+        private Mapping getAggUnitJoinMapping() {
+            final Map<Integer, Integer> map = Maps.newHashMap();
+            map.putAll(left.getAggUnitJoinMap());
+            map.putAll(right.getAggUnitJoinMap());
+            final int sourceCount = join.getRowType().getFieldCount();
+            final int targetCount = left.getNewInputFieldCount() + 
right.getNewInputFieldCount();
+            return (Mapping) Mappings.target(map::get, sourceCount, 
targetCount);
+        }
+
+    } // end of Transposer
+
+    private static class AggregateUnit {
+        // base variables
+        protected final KapAggregateRel aggregate;
+
+        // immediate variables
+        private RexBuilder rexBuilder;
+
+        public AggregateUnit(KapAggregateRel aggregate) {
+            this.aggregate = aggregate;
+        }
+
+        public RexBuilder getRexBuilder() {
+            if (Objects.isNull(rexBuilder)) {
+                rexBuilder = aggregate.getCluster().getRexBuilder();
+            }
+            return rexBuilder;
+        }
+
+        public ImmutableBitSet getUnitSet() {
+            return getGroupSet();
+        }
+
+        public ImmutableBitSet getGroupSet() {
+            return aggregate.getGroupSet();
+        }
+
+        public ImmutableList<ImmutableBitSet> getGroupSets() {
+            return ImmutableList.<ImmutableBitSet> 
builder().addAll(aggregate.groupSets).build();
+        }
+
+        public int getGroupCount() {
+            return aggregate.getGroupCount();
+        }
+
+        public int getGroupIndicatorCount() {
+            return getGroupCount() + aggregate.getIndicatorCount();
+        }
+
+        public List<AggregateCall> getAggCallList() {
+            return aggregate.getAggCallList();
+        }
+
+        public List<Integer> getGroupList() {
+            return aggregate.getGroupSet().asList();
+        }
+
+    } // end of AggregateUnit
+
+    private static class AggregateProject extends AggregateUnit {
+        // base variables
+        private final KapProjectRel project;
+        private final Mappings.TargetMapping targetMapping;
+
+        // immediate variables
+        private ImmutableBitSet groupSet;
+        private ImmutableList<ImmutableBitSet> groupSets;
+        private List<AggregateCall> aggCallList;
+
+        public AggregateProject(KapAggregateRel aggregate, KapProjectRel 
project) {
+            super(aggregate);
+            this.project = project;
+            this.targetMapping = createTargetMapping();
+        }
+
+        @Override
+        public ImmutableBitSet getGroupSet() {
+            if (Objects.isNull(groupSet)) {
+                groupSet = Mappings.apply((Mapping) targetMapping, 
aggregate.getGroupSet());
+            }
+            return groupSet;
+        }
+
+        @Override
+        public ImmutableList<ImmutableBitSet> getGroupSets() {
+            if (Objects.isNull(groupSets)) {
+                groupSets = ImmutableList.<ImmutableBitSet> builder() //
+                        .addAll(Mappings.apply2((Mapping) targetMapping, 
aggregate.getGroupSets())) //
+                        .build();
+            }
+            return groupSets;
+        }
+
+        @Override
+        public List<AggregateCall> getAggCallList() {
+            if (Objects.isNull(aggCallList)) {
+                aggCallList = aggregate.getAggCallList().stream() //
+                        .map(a -> a.transform(targetMapping)) //
+                        
.collect(Collectors.collectingAndThen(Collectors.toList(), //
+                                Collections::unmodifiableList));
+            }
+            return aggCallList;
+        }
+
+        @Override
+        public List<Integer> getGroupList() {
+            return 
super.getGroupList().stream().map(targetMapping::getTarget).collect(Collectors.toList());
+        }
+
+        private Mappings.TargetMapping createTargetMapping() {
+            if (Objects.isNull(project.getMapping())) {
+                return 
Mappings.createIdentity(project.getRowType().getFieldCount());
+            }
+            return project.getMapping().inverse();
+        }
+
+    } // end of AggregateProject
+
+    private static class AggregateProjectFilter extends AggregateProject {
+
+        private final KapFilterRel filter;
+
+        public AggregateProjectFilter(KapAggregateRel aggregate, KapProjectRel 
project, KapFilterRel filter) {
+            super(aggregate, project);
+            this.filter = filter;
+        }
+
+        @Override
+        public ImmutableBitSet getUnitSet() {
+            ImmutableBitSet filterSet = 
RelOptUtil.InputFinder.bits(filter.getCondition());
+            return getGroupSet().union(filterSet);
+        }
+
+        public RexNode getFilterCond() {
+            return filter.getCondition();
+        }
+
+    } // end of AggregateProjectFilter
+
+    private abstract class JoinSide {
+        // base variables
+        private final boolean isRelValues;
+        private final boolean hasRelValues;
+        private final RelNode input;
+        private final ImmutableBitSet aggUnitJoinSet;
+
+        // util variables
+        protected ImmutableBitSet fieldSet;
+        protected ImmutableBitSet sideAggUnitJoinSet;
+        protected ImmutableBitSet belowAggGroupSet;
+
+        // immediate variables
+        private Map<Integer, Integer> aggOrdinalMap;
+        private List<AggregateCall> belowAggCallList;
+        private SqlSplittableAggFunction.Registry<AggregateCall> 
belowAggCallRegistry;
+
+        private RelNode newInput;
+
+        private Map<Integer, Integer> aggUnitJoinMap;
+
+        public JoinSide(RelNode relNode, RelNode input, ImmutableBitSet 
aggUnitJoinSet) {
+            this.isRelValues = isRelValues(relNode);
+            this.hasRelValues = hasRelValues(relNode);
+            this.input = input;
+            this.aggUnitJoinSet = aggUnitJoinSet;
+        }
+
+        public boolean hasRelValues() {
+            return hasRelValues;
+        }
+
+        public boolean isRelValues() {
+            return isRelValues;
+        }
+
+        public abstract boolean isAggregable();
+
+        public RelNode getNewInput() {
+            return newInput;
+        }
+
+        public Integer getAggOrdinal(int i) {
+            return getAggOrdinalMap().get(i);
+        }
+
+        public Map<Integer, Integer> getAggUnitJoinMap() {
+            if (Objects.isNull(aggUnitJoinMap)) {
+                final int belowOffset = getBelowOffset();
+                final Map<Integer, Integer> map = Maps.newHashMap();
+                Ord.zip(getSideAggUnitJoinSet()).forEach(o -> map.put(o.e, 
belowOffset + o.i));
+                aggUnitJoinMap = map;
+            }
+            return aggUnitJoinMap;
+        }
+
+        public void modifyAggregate(AggregateUnit aggUnit, RelBuilder 
relBuilder, RexBuilder rexBuilder) {
+            if (isRelValues()) {
+                newInput = convertSingleton(aggUnit, relBuilder, rexBuilder);
+                return;
+            }
+
+            if (isAggregable()) {
+                newInput = convertSplit(aggUnit, relBuilder, rexBuilder);
+                return;
+            }
+
+            newInput = convertSingleton(aggUnit, relBuilder, rexBuilder);
+        }
+
+        protected final boolean hasRelValues(RelNode node) {
+            if (node instanceof HepRelVertex) {
+                RelNode current = ((HepRelVertex) node).getCurrentRel();
+                if (current instanceof Join) {
+                    final Join join = (Join) current;
+                    return isRelValues(join.getLeft()) || 
isRelValues(join.getRight());
+                }
+                return isRelValues(node);
+            }
+            return false;
+        }
+
+        protected final boolean isRelValues(RelNode node) {
+            if (node instanceof HepRelVertex) {
+                RelNode current = ((HepRelVertex) node).getCurrentRel();
+                if (current instanceof KapValuesRel) {
+                    return true;
+                }
+
+                if (current.getInputs().isEmpty()) {
+                    return false;
+                }
+
+                return 
current.getInputs().stream().allMatch(this::isRelValues);
+            }
+            return false;
+        }
+
+        protected final boolean isAggregable(RelNode input, RelMetadataQuery 
mq) {
+            // No need to do aggregation. There is nothing to be gained by 
this rule.
+            Boolean unique = mq.areColumnsUnique(input, getBelowAggGroupSet());
+            return Objects.isNull(unique) || !unique;
+        }
+
+        protected int getInputFieldCount() {
+            return input.getRowType().getFieldCount();
+        }
+
+        protected int getNewInputFieldCount() {
+            return 
Preconditions.checkNotNull(newInput).getRowType().getFieldCount();
+        }
+
+        protected abstract int getOffset();
+
+        protected abstract int getBelowOffset();
+
+        protected abstract Mappings.TargetMapping getTargetMapping();
+
+        private Map<Integer, Integer> getAggOrdinalMap() {
+            if (Objects.isNull(aggOrdinalMap)) {
+                aggOrdinalMap = Maps.newHashMap();
+            }
+            return aggOrdinalMap;
+        }
+
+        private void registryAggCall(int i, int offset, AggregateCall aggCall) 
{
+            getAggOrdinalMap().put(i, offset + registry(aggCall));
+        }
+
+        private void registryOther(int i, int ordinal) {
+            getAggOrdinalMap().put(i, ordinal);
+        }
+
+        private ImmutableBitSet getFieldSet() {
+            if (Objects.isNull(fieldSet)) {
+                int offset = getOffset();
+                fieldSet = ImmutableBitSet.range(offset, offset + 
getInputFieldCount());
+            }
+            return fieldSet;
+        }
+
+        private ImmutableBitSet getBelowAggGroupSet() {
+            if (Objects.isNull(belowAggGroupSet)) {
+                int offset = getOffset();
+                belowAggGroupSet = getSideAggUnitJoinSet().shift(-offset);
+            }
+            return belowAggGroupSet;
+        }
+
+        private ImmutableBitSet getSideAggUnitJoinSet() {
+            if (Objects.isNull(sideAggUnitJoinSet)) {
+                ImmutableBitSet fieldSet0 = getFieldSet();
+                sideAggUnitJoinSet = 
Preconditions.checkNotNull(aggUnitJoinSet).intersect(fieldSet0);
+            }
+            return sideAggUnitJoinSet;
+        }
+
+        private RelNode convertSplit(AggregateUnit aggUnit, RelBuilder 
relBuilder, RexBuilder rexBuilder) {
+            final ImmutableBitSet fields = getFieldSet();
+            final int oldGroupSetCount = aggUnit.getGroupCount();
+            final int newGroupSetCount = getBelowAggGroupSet().cardinality();
+            Ord.zip(aggUnit.getAggCallList()).forEach(aggCallOrd -> {
+                AggregateCall aggCall = aggCallOrd.e;
+                SqlAggFunction aggFunc = aggCall.getAggregation();
+                SqlSplittableAggFunction splitAggFunc = Preconditions
+                        
.checkNotNull(aggFunc.unwrap(SqlSplittableAggFunction.class));
+                ImmutableBitSet aggArgSet = 
ImmutableBitSet.of(aggCall.getArgList());
+                final AggregateCall newAggCall;
+                if (fields.contains(aggArgSet)) {
+                    // convert split
+                    AggregateCall splitAggCall = splitAggFunc.split(aggCall, 
getTargetMapping());
+                    newAggCall = splitAggCall.adaptTo(input, 
splitAggCall.getArgList(), splitAggCall.filterArg, //
+                            oldGroupSetCount, newGroupSetCount);
+                } else {
+                    newAggCall = splitOther(splitAggFunc, rexBuilder, aggCall, 
fields, aggArgSet);
+                }
+
+                if (Objects.isNull(newAggCall)) {
+                    return;
+                }
+                registryAggCall(aggCallOrd.i, newGroupSetCount, newAggCall);
+            });
+
+            return relBuilder.push(input) //
+                    .aggregate(relBuilder.groupKey(belowAggGroupSet, null), //
+                            Preconditions.checkNotNull(belowAggCallList)) //
+                    .build();
+        }
+
+        private AggregateCall splitOther(SqlSplittableAggFunction 
splitAggFunc, //
+                RexBuilder rexBuilder, //
+                AggregateCall aggCall, //
+                ImmutableBitSet fields, //
+                ImmutableBitSet args) {
+            // Thinking...aggCall not transformed?
+            AggregateCall other = 
splitAggFunc.other(rexBuilder.getTypeFactory(), aggCall);
+            if (Objects.isNull(other)) {
+                return null;
+            }
+
+            ImmutableBitSet newArgSet = Mappings.apply((Mapping) 
getTargetMapping(), args.intersect(fields));
+            return AggregateCall.create(other.getAggregation(), 
other.isDistinct(), //
+                    other.isApproximate(), newArgSet.asList(), //
+                    other.filterArg, other.getType(), other.getName());
+
+        }
+
+        private RelNode convertSingleton(AggregateUnit aggUnit, RelBuilder 
relBuilder, RexBuilder rexBuilder) {
+            relBuilder.push(input);
+            final ImmutableBitSet fieldSet0 = getFieldSet();
+            final List<RexNode> projectList = Lists.newArrayList();
+            getBelowAggGroupSet().forEach(i -> 
projectList.add(relBuilder.field(i)));
+            Ord.zip(aggUnit.getAggCallList()).forEach(aggCallOrd -> {
+                AggregateCall aggCall = aggCallOrd.e;
+                SqlAggFunction aggFunc = aggCall.getAggregation();
+                SqlSplittableAggFunction splitAggFunc = Preconditions
+                        
.checkNotNull(aggFunc.unwrap(SqlSplittableAggFunction.class));
+                if (aggCall.getArgList().isEmpty()) {
+                    return;
+                }
+                ImmutableBitSet aggArgSet = 
ImmutableBitSet.of(aggCall.getArgList());
+                if (!fieldSet0.contains(aggArgSet)) {
+                    return;
+                }
+
+                // convert singleton
+                RexNode singleton = splitAggFunc.singleton(rexBuilder, 
input.getRowType(), //
+                        aggCall.transform(getTargetMapping()));
+                if (singleton instanceof RexInputRef) {
+                    registryOther(aggCallOrd.i, ((RexInputRef) 
singleton).getIndex());
+                    return;
+                }
+                int ordinal = projectList.size();
+                projectList.add(singleton);
+                registryOther(aggCallOrd.i, ordinal);
+            });
+
+            relBuilder.project(projectList);
+
+            return relBuilder.build();
+        }
+
+        private int registry(AggregateCall aggCall) {
+            if (Objects.isNull(belowAggCallRegistry)) {
+                if (Objects.isNull(belowAggCallList)) {
+                    belowAggCallList = Lists.newArrayList();
+                }
+                belowAggCallRegistry = createRegistry(belowAggCallList);
+            }
+            return belowAggCallRegistry.register(aggCall);
+        }
+
+    } // end of side
+
+    private class LeftSide extends JoinSide {
+
+        private final boolean isAggregable;
+
+        private final Mappings.TargetMapping targetMapping;
+
+        public LeftSide(RelNode relNode, RelNode input, RelMetadataQuery mq, 
ImmutableBitSet aggUnitJoinSet) {
+            super(relNode, input, aggUnitJoinSet);
+            this.isAggregable = isAggregable(input, mq);
+            this.targetMapping = createTargetMapping();
+        }
+
+        @Override
+        public boolean isAggregable() {
+            return isAggregable;
+        }
+
+        @Override
+        protected int getOffset() {
+            return 0;
+        }
+
+        @Override
+        protected int getBelowOffset() {
+            return 0;
+        }
+
+        @Override
+        protected Mappings.TargetMapping getTargetMapping() {
+            return targetMapping;
+        }
+
+        private Mappings.TargetMapping createTargetMapping() {
+            int fieldCount = getInputFieldCount();
+            return Mappings.createIdentity(fieldCount);
+        }
+
+    } // end of LeftSide
+
+    private class RightSide extends JoinSide {
+
+        private final LeftSide left;
+
+        private final boolean isAggregable;
+
+        private final Mappings.TargetMapping targetMapping;
+
+        public RightSide(LeftSide left, //
+                RelNode relNode, RelNode input, //
+                RelMetadataQuery mq, ImmutableBitSet aggUnitJoinSet) {
+            super(relNode, input, aggUnitJoinSet);
+            this.left = left;
+            this.isAggregable = isAggregable(input, mq);
+            this.targetMapping = createTargetMapping();
+        }
+
+        @Override
+        public boolean isAggregable() {
+            return isAggregable;
+        }
+
+        @Override
+        protected int getOffset() {
+            return left.getInputFieldCount();
+        }
+
+        @Override
+        protected int getBelowOffset() {
+            return left.getNewInputFieldCount();
+        }
+
+        @Override
+        protected Mappings.TargetMapping getTargetMapping() {
+            return targetMapping;
+        }
+
+        private Mappings.TargetMapping createTargetMapping() {
+            int offset = getOffset();
+            int fieldCount = getInputFieldCount();
+            return Mappings.createShiftMapping(fieldCount + offset, 0, offset, 
fieldCount);
+        }
+
+    } // end of RightSide
+
+}
diff --git 
a/src/query/src/main/java/org/apache/kylin/query/engine/QueryExec.java 
b/src/query/src/main/java/org/apache/kylin/query/engine/QueryExec.java
index 51e4e4261d..dc0572b6f8 100644
--- a/src/query/src/main/java/org/apache/kylin/query/engine/QueryExec.java
+++ b/src/query/src/main/java/org/apache/kylin/query/engine/QueryExec.java
@@ -267,6 +267,10 @@ public class QueryExec {
             postOptRules.addAll(HepUtils.AggPushDownRules);
         }
 
+        if(kylinConfig.isScalarSubqueryJoinEnabled()) {
+            postOptRules.addAll(HepUtils.ScalarSubqueryJoinRules);
+        }
+
         if (kylinConfig.isOptimizedSumCastDoubleRuleEnabled()) {
             postOptRules.addAll(HepUtils.SumCastDoubleRules);
         }
diff --git a/src/query/src/main/java/org/apache/kylin/query/util/HepUtils.java 
b/src/query/src/main/java/org/apache/kylin/query/util/HepUtils.java
index bea632f49f..92be45067d 100644
--- a/src/query/src/main/java/org/apache/kylin/query/util/HepUtils.java
+++ b/src/query/src/main/java/org/apache/kylin/query/util/HepUtils.java
@@ -25,11 +25,13 @@ import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.hep.HepPlanner;
 import org.apache.calcite.plan.hep.HepProgram;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.rules.AggregateProjectMergeRule;
 import org.apache.calcite.rel.rules.FilterMergeRule;
+import org.apache.calcite.rel.rules.ProjectMergeRule;
 import org.apache.calcite.rel.rules.ProjectRemoveRule;
-
 import org.apache.kylin.guava30.shaded.common.collect.ImmutableList;
 
+import io.kyligence.kap.query.optrule.AggregateProjectReduceRule;
 import io.kyligence.kap.query.optrule.CountDistinctCaseWhenFunctionRule;
 import io.kyligence.kap.query.optrule.FilterJoinConditionMergeRule;
 import io.kyligence.kap.query.optrule.FilterSimplifyRule;
@@ -49,6 +51,7 @@ import io.kyligence.kap.query.optrule.KapProjectMergeRule;
 import io.kyligence.kap.query.optrule.KapProjectRule;
 import io.kyligence.kap.query.optrule.KapSumCastTransposeRule;
 import io.kyligence.kap.query.optrule.KapSumTransCastToThenRule;
+import io.kyligence.kap.query.optrule.ScalarSubqueryJoinRule;
 import io.kyligence.kap.query.optrule.SumBasicOperatorRule;
 import io.kyligence.kap.query.optrule.SumCaseWhenFunctionRule;
 import io.kyligence.kap.query.optrule.SumConstantConvertRule;
@@ -97,6 +100,21 @@ public class HepUtils {
             KapJoinRule.INSTANCE
     );
 
+    public static final ImmutableList<RelOptRule> ScalarSubqueryJoinRules = 
ImmutableList.of(
+            // base rules
+            KapAggregateRule.INSTANCE, //
+            KapProjectRule.INSTANCE, //
+            KapJoinRule.INSTANCE, //
+            // relative rules
+            ProjectMergeRule.INSTANCE, //
+            AggregateProjectMergeRule.INSTANCE, //
+            AggregateProjectReduceRule.INSTANCE, //
+            // target rules
+            ScalarSubqueryJoinRule.AGG_JOIN, //
+            ScalarSubqueryJoinRule.AGG_PRJ_JOIN, //
+            ScalarSubqueryJoinRule.AGG_PRJ_FLT_JOIN
+    );
+
     public static final ImmutableList<RelOptRule> CountDistinctExprRules = 
ImmutableList.of(
             CountDistinctCaseWhenFunctionRule.INSTANCE,
             KapProjectRule.INSTANCE,

Reply via email to