You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2025/11/13 08:54:36 UTC

(doris) branch branch-4.0 updated: branch-4.0: [opt](mtmv) Support window function rewrite when materialized view contains window function #55066 (#57839)

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

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new 518105f4587 branch-4.0: [opt](mtmv) Support window function rewrite when materialized view contains window function #55066 (#57839)
518105f4587 is described below

commit 518105f4587d9d8dd2147e2544681f42b98cce2b
Author: github-actions[bot] <41...@users.noreply.github.com>
AuthorDate: Thu Nov 13 16:54:28 2025 +0800

    branch-4.0: [opt](mtmv) Support window function rewrite when materialized view contains window function #55066 (#57839)
    
    Cherry-picked from #55066
    
    Co-authored-by: seawinde <wu...@selectdb.com>
---
 .../joinorder/hypergraph/node/StructInfoNode.java  |   74 +-
 .../org/apache/doris/nereids/rules/RuleSet.java    |    6 +
 .../org/apache/doris/nereids/rules/RuleType.java   |   21 +
 .../mv/AbstractMaterializedViewAggregateRule.java  |    3 +-
 .../mv/AbstractMaterializedViewJoinRule.java       |    2 +-
 .../mv/AbstractMaterializedViewRule.java           |   20 +-
 .../mv/AbstractMaterializedViewScanRule.java       |    2 +-
 .../mv/AbstractMaterializedViewWindowRule.java     |  124 ++
 .../rules/exploration/mv/HyperGraphComparator.java |   25 +-
 .../mv/LogicalCompatibilityContext.java            |   51 +-
 .../mv/MaterializedViewWindowAggregateRule.java    |   87 +
 .../mv/MaterializedViewWindowJoinRule.java         |   97 ++
 .../mv/MaterializedViewWindowScanRule.java         |   96 ++
 .../nereids/rules/exploration/mv/Predicates.java   |   57 +-
 .../nereids/rules/exploration/mv/StructInfo.java   |  197 ++-
 .../rules/rewrite/PushDownFilterThroughWindow.java |    5 +-
 .../nereids/trees/plans/logical/LogicalWindow.java |    9 +
 .../apache/doris/nereids/mv/PredicatesTest.java    |  190 ++
 .../apache/doris/nereids/mv/StructInfoTest.java    |  242 +++
 .../mv/window/window_above_aggregate.out           |  271 +++
 .../mv/window/window_above_join.out                |  453 +++++
 .../mv/window/window_above_scan.out                |  349 ++++
 .../null_aware_left_anti_join.groovy               |    4 +-
 .../mv/pre_rewrite/limit/query_with_limit.groovy   |    4 +-
 .../nereids_rules_p0/mv/tpch/mv_tpch_test.groovy   |    2 +-
 .../mv/window/window_above_aggregate.groovy        | 1821 ++++++++++++++++++++
 .../mv/window/window_above_join.groovy             | 1591 +++++++++++++++++
 .../mv/window/window_above_scan.groovy             | 1329 ++++++++++++++
 28 files changed, 7064 insertions(+), 68 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/node/StructInfoNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/node/StructInfoNode.java
index 28f1ed405e8..3866bef788e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/node/StructInfoNode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/node/StructInfoNode.java
@@ -19,6 +19,9 @@ package org.apache.doris.nereids.jobs.joinorder.hypergraph.node;
 
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.jobs.joinorder.hypergraph.edge.Edge;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanCheckContext;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PredicateCollectorContext;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
@@ -27,6 +30,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
 import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation;
 import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
 import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
 import org.apache.doris.nereids.util.Utils;
 
@@ -39,26 +43,42 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import javax.annotation.Nullable;
 
 /**
  * HyperGraph Node.
  */
 public class StructInfoNode extends AbstractNode {
-    private final List<Set<Expression>> expressions;
+    private final Pair<List<Set<Expression>>, List<Set<Expression>>> expressions;
     private final Set<CatalogRelation> relationSet;
 
+    /**
+     * the constructor of StructInfoNode
+     */
     public StructInfoNode(int index, Plan plan, List<Edge> edges) {
         super(extractPlan(plan), index, edges);
         relationSet = plan.collect(CatalogRelation.class::isInstance);
-        expressions = collectExpressions(plan);
+        // check the node pattern is valid
+        PlanCheckContext checkContext = PlanCheckContext.of(ImmutableSet.of());
+        Boolean checkResult = plan.accept(StructInfo.PLAN_PATTERN_CHECKER, checkContext);
+        if (checkResult && !checkContext.isWindowUnderAggregate() && checkContext.getTopAggregateNum() <= 1
+                && checkContext.getTopWindowNum() <= 1) {
+            expressions = collectExpressions(plan);
+        } else {
+            expressions = null;
+        }
     }
 
     public StructInfoNode(int index, Plan plan) {
         this(index, plan, new ArrayList<>());
     }
 
-    private @Nullable List<Set<Expression>> collectExpressions(Plan plan) {
+    /**
+     * The key of pair is the expression which could be moved around anywhere,
+     * the value of pair is the expression which could not be moved around anywhere.
+     * */
+    private @Nullable Pair<List<Set<Expression>>, List<Set<Expression>>> collectExpressions(Plan plan) {
 
         Pair<Boolean, Builder<Set<Expression>>> collector = Pair.of(true, ImmutableList.builder());
         plan.accept(new DefaultPlanVisitor<Void, Pair<Boolean, ImmutableList.Builder<Set<Expression>>>>() {
@@ -69,7 +89,6 @@ public class StructInfoNode extends AbstractNode {
                     return null;
                 }
                 collector.value().add(ImmutableSet.copyOf(aggregate.getExpressions()));
-                collector.value().add(ImmutableSet.copyOf(((LogicalAggregate<?>) plan).getGroupByExpressions()));
                 return super.visit(aggregate, collector);
             }
 
@@ -93,6 +112,13 @@ public class StructInfoNode extends AbstractNode {
                 return groupActualPlan.accept(this, collector);
             }
 
+            @Override
+            public Void visitLogicalWindow(LogicalWindow<? extends Plan> window,
+                    Pair<Boolean, Builder<Set<Expression>>> context) {
+                collector.value().add(ImmutableSet.copyOf(window.getActualWindowExpressions()));
+                return super.visit(window, context);
+            }
+
             @Override
             public Void visit(Plan plan, Pair<Boolean, ImmutableList.Builder<Set<Expression>>> context) {
                 if (!isValidNodePlan(plan)) {
@@ -102,24 +128,52 @@ public class StructInfoNode extends AbstractNode {
                 return super.visit(plan, context);
             }
         }, collector);
-        return collector.key() ? collector.value().build() : null;
+
+        if (!collector.key()) {
+            return null;
+        }
+        PredicateCollectorContext predicateCollectorContext = new PredicateCollectorContext();
+        plan.accept(StructInfo.PREDICATE_COLLECTOR, predicateCollectorContext);
+        collector.value().add(ImmutableSet.copyOf(predicateCollectorContext.getCouldPullUpPredicates()));
+        if (predicateCollectorContext.getCouldNotPullUpPredicates().isEmpty()) {
+            return Pair.of(collector.value().build(), ImmutableList.of());
+        }
+        return Pair.of(collector.value().build(),
+                ImmutableList.of(predicateCollectorContext.getCouldNotPullUpPredicates()));
     }
 
     private boolean isValidNodePlan(Plan plan) {
         return plan instanceof LogicalProject || plan instanceof LogicalAggregate
-                || plan instanceof LogicalFilter || plan instanceof LogicalCatalogRelation;
+                || plan instanceof LogicalFilter || plan instanceof LogicalCatalogRelation
+                || plan instanceof LogicalWindow;
     }
 
     /**
      * get all expressions of nodes
      */
     public @Nullable List<Expression> getExpressions() {
-        return expressions == null ? null : expressions.stream()
-                .flatMap(Collection::stream)
-                .collect(Collectors.toList());
+        if (expressions == null) {
+            return null;
+        }
+        return Stream.concat(expressions.key().stream().flatMap(Collection::stream),
+                expressions.value().stream().flatMap(Collection::stream)).collect(Collectors.toList());
+    }
+
+    public @Nullable List<Expression> getCouldMoveExpressions() {
+        if (expressions == null) {
+            return null;
+        }
+        return expressions.key().stream().flatMap(Collection::stream).collect(Collectors.toList());
+    }
+
+    public @Nullable List<Expression> getCouldNotMoveExpressions() {
+        if (expressions == null) {
+            return null;
+        }
+        return expressions.value().stream().flatMap(Collection::stream).collect(Collectors.toList());
     }
 
-    public @Nullable List<Set<Expression>> getExprSetList() {
+    public @Nullable Pair<List<Set<Expression>>, List<Set<Expression>>> getExprSetList() {
         return expressions;
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
index 6e47834d6c9..f361348ccad 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
@@ -47,6 +47,9 @@ import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewProjectFilt
 import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewProjectFilterScanRule;
 import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewProjectJoinRule;
 import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewProjectScanRule;
+import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewWindowAggregateRule;
+import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewWindowJoinRule;
+import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewWindowScanRule;
 import org.apache.doris.nereids.rules.expression.ExpressionNormalizationAndOptimization;
 import org.apache.doris.nereids.rules.implementation.AggregateStrategies;
 import org.apache.doris.nereids.rules.implementation.LogicalAssertNumRowsToPhysicalAssertNumRows;
@@ -268,6 +271,9 @@ public class RuleSet {
             .add(MaterializedViewProjectFilterScanRule.INSTANCE)
             .add(MaterializedViewAggregateOnNoneAggregateRule.INSTANCE)
             .add(MaterializedViewOnlyScanRule.INSTANCE)
+            .add(MaterializedViewWindowScanRule.INSTANCE)
+            .add(MaterializedViewWindowJoinRule.INSTANCE)
+            .add(MaterializedViewWindowAggregateRule.INSTANCE)
             .build();
 
     public static final List<Rule> MATERIALIZED_VIEW_IN_RBO_RULES = planRuleFactories()
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
index 85963bf73a6..6e275ec8263 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
@@ -453,6 +453,27 @@ public enum RuleType {
     MATERIALIZED_VIEW_FILTER_PROJECT_JOIN(RuleTypeClass.MATERIALIZE_VIEW),
     MATERIALIZED_VIEW_ONLY_JOIN(RuleTypeClass.MATERIALIZE_VIEW),
 
+    // window above join without aggregate
+    MATERIALIZED_VIEW_PROJECT_WINDOW_JOIN(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_FILTER_WINDOW_JOIN(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_PROJECT_FILTER_WINDOW_JOIN(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_FILTER_PROJECT_WINDOW_JOIN(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_ONLY_WINDOW_JOIN(RuleTypeClass.MATERIALIZE_VIEW),
+
+    // window above scan without aggregate
+    MATERIALIZED_VIEW_FILTER_WINDOW_SCAN(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_PROJECT_WINDOW_SCAN(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_FILTER_PROJECT_WINDOW_SCAN(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_PROJECT_FILTER_WINDOW_SCAN(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_ONLY_WINDOW_SCAN(RuleTypeClass.MATERIALIZE_VIEW),
+
+    // window with aggregate
+    MATERIALIZED_VIEW_PROJECT_WINDOW_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_FILTER_WINDOW_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_PROJECT_FILTER_WINDOW_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_FILTER_PROJECT_WINDOW_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW),
+    MATERIALIZED_VIEW_ONLY_WINDOW_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW),
+
     MATERIALIZED_VIEW_PROJECT_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW),
     MATERIALIZED_VIEW_FILTER_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW),
     MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW),
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
index fb1b13e7d1e..e6e7f395d9b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
@@ -683,7 +683,8 @@ public abstract class AbstractMaterializedViewAggregateRule extends AbstractMate
         PlanCheckContext checkContext = PlanCheckContext.of(SUPPORTED_JOIN_TYPE_SET);
         // if query or mv contains more then one top aggregate, should fail
         return structInfo.getTopPlan().accept(StructInfo.PLAN_PATTERN_CHECKER, checkContext)
-                && checkContext.isContainsTopAggregate() && checkContext.getTopAggregateNum() <= 1;
+                && checkContext.isContainsTopAggregate() && checkContext.getTopAggregateNum() <= 1
+                && !checkContext.isContainsTopWindow();
     }
 
     /**
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
index 122688b766e..cf27aa2982a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
@@ -81,6 +81,6 @@ public abstract class AbstractMaterializedViewJoinRule extends AbstractMateriali
     protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext cascadesContext) {
         PlanCheckContext checkContext = PlanCheckContext.of(SUPPORTED_JOIN_TYPE_SET);
         return structInfo.getTopPlan().accept(StructInfo.PLAN_PATTERN_CHECKER, checkContext)
-                && !checkContext.isContainsTopAggregate();
+                && !checkContext.isContainsTopAggregate() && !checkContext.isContainsTopWindow();
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java
index f8a1a6ed2e9..4c9b71e81fa 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java
@@ -282,7 +282,8 @@ public abstract class AbstractMaterializedViewRule implements ExplorationRuleFac
                 rewrittenPlan = new LogicalFilter<>(Sets.newLinkedHashSet(rewriteCompensatePredicates), mvScan);
             }
             boolean checkResult = rewriteQueryByViewPreCheck(matchMode, queryStructInfo,
-                    viewStructInfo, viewToQuerySlotMapping, rewrittenPlan, materializationContext);
+                    viewStructInfo, viewToQuerySlotMapping, rewrittenPlan, materializationContext,
+                    comparisonResult);
             if (!checkResult) {
                 continue;
             }
@@ -517,7 +518,7 @@ public abstract class AbstractMaterializedViewRule implements ExplorationRuleFac
     */
     protected boolean rewriteQueryByViewPreCheck(MatchMode matchMode, StructInfo queryStructInfo,
             StructInfo viewStructInfo, SlotMapping viewToQuerySlotMapping, Plan tempRewritedPlan,
-            MaterializationContext materializationContext) {
+            MaterializationContext materializationContext, ComparisonResult comparisonResult) {
         if (materializationContext instanceof SyncMaterializationContext
                 && queryStructInfo.getBottomPlan() instanceof LogicalOlapScan) {
             LogicalOlapScan olapScan = (LogicalOlapScan) queryStructInfo.getBottomPlan();
@@ -741,13 +742,13 @@ public abstract class AbstractMaterializedViewRule implements ExplorationRuleFac
         // set pulled up expression to queryStructInfo predicates and update related predicates
         if (!queryPulledUpExpressions.isEmpty()) {
             queryStructInfo = queryStructInfo.withPredicates(
-                    queryStructInfo.getPredicates().merge(queryPulledUpExpressions));
+                    queryStructInfo.getPredicates().mergePulledUpPredicates(queryPulledUpExpressions));
         }
         List<Expression> viewPulledUpExpressions = ImmutableList.copyOf(comparisonResult.getViewExpressions());
         // set pulled up expression to viewStructInfo predicates and update related predicates
         if (!viewPulledUpExpressions.isEmpty()) {
             viewStructInfo = viewStructInfo.withPredicates(
-                    viewStructInfo.getPredicates().merge(viewPulledUpExpressions));
+                    viewStructInfo.getPredicates().mergePulledUpPredicates(viewPulledUpExpressions));
         }
         // if the join type in query and mv plan is different, we should check query is have the
         // filters which rejects null
@@ -760,8 +761,8 @@ public abstract class AbstractMaterializedViewRule implements ExplorationRuleFac
                     queryStructInfo.getPredicates().getPulledUpPredicates(), queryToViewMapping, queryStructInfo,
                     viewStructInfo, cascadesContext);
             if (!valid) {
-                queryStructInfo = queryStructInfo.withPredicates(
-                        queryStructInfo.getPredicates().merge(comparisonResult.getQueryAllPulledUpExpressions()));
+                queryStructInfo = queryStructInfo.withPredicates(queryStructInfo.getPredicates()
+                        .mergePulledUpPredicates(comparisonResult.getQueryAllPulledUpExpressions()));
                 valid = containsNullRejectSlot(requireNoNullableViewSlot,
                         queryStructInfo.getPredicates().getPulledUpPredicates(), queryToViewMapping,
                         queryStructInfo, viewStructInfo, cascadesContext);
@@ -770,6 +771,13 @@ public abstract class AbstractMaterializedViewRule implements ExplorationRuleFac
                 return SplitPredicate.INVALID_INSTANCE;
             }
         }
+        // compensate couldNot PulledUp Conjunctions
+        Map<Expression, ExpressionInfo> couldNotPulledUpCompensateConjunctions =
+                Predicates.compensateCouldNotPullUpPredicates(queryStructInfo, viewStructInfo,
+                viewToQuerySlotMapping, comparisonResult);
+        if (couldNotPulledUpCompensateConjunctions == null) {
+            return SplitPredicate.INVALID_INSTANCE;
+        }
         // viewEquivalenceClass to query based
         // equal predicate compensate
         final Map<Expression, ExpressionInfo> equalCompensateConjunctions = Predicates.compensateEquivalence(
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewScanRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewScanRule.java
index 7b2f685cf30..1e3fdac4be4 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewScanRule.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewScanRule.java
@@ -81,6 +81,6 @@ public abstract class AbstractMaterializedViewScanRule extends AbstractMateriali
     protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext cascadesContext) {
         PlanCheckContext checkContext = PlanCheckContext.of(ImmutableSet.of());
         return structInfo.getTopPlan().accept(StructInfo.SCAN_PLAN_PATTERN_CHECKER, checkContext)
-                && !checkContext.isContainsTopAggregate();
+                && !checkContext.isContainsTopAggregate() && !checkContext.isContainsTopWindow();
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewWindowRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewWindowRule.java
new file mode 100644
index 00000000000..9a2913aca43
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewWindowRule.java
@@ -0,0 +1,124 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping;
+import org.apache.doris.nereids.trees.expressions.Alias;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
+
+import com.google.common.collect.ImmutableMap;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * AbstractMaterializedViewWindowRule
+ */
+public abstract class AbstractMaterializedViewWindowRule extends AbstractMaterializedViewRule {
+
+
+    /**
+     * compensatePredicates should be pulled up through window
+     */
+    @Override
+    protected boolean rewriteQueryByViewPreCheck(MatchMode matchMode, StructInfo queryStructInfo,
+            StructInfo viewStructInfo, SlotMapping viewToQuerySlotMapping, Plan tempRewritedPlan,
+            MaterializationContext materializationContext, ComparisonResult comparisonResult) {
+        boolean superCheck = super.rewriteQueryByViewPreCheck(matchMode, queryStructInfo, viewStructInfo,
+                viewToQuerySlotMapping, tempRewritedPlan, materializationContext, comparisonResult);
+        Optional<LogicalWindow<Plan>> logicalWindow =
+                queryStructInfo.getTopPlan().collectFirst(LogicalWindow.class::isInstance);
+        if (!logicalWindow.isPresent()) {
+            materializationContext.recordFailReason(queryStructInfo,
+                    "Window rewriteQueryByViewPreCheck fail, logical window is not present",
+                    () -> String.format("expressionToRewritten is %s,\n mvExprToMvScanExprMapping is %s,\n"
+                                    + "targetToSourceMapping = %s, tempRewrittenPlan is %s",
+                            queryStructInfo.getExpressions(), materializationContext.getShuttledExprToScanExprMapping(),
+                            viewToQuerySlotMapping, tempRewritedPlan.treeString()));
+            return false;
+        }
+        // if compensatePredicates exists, should be pulled up through window
+        Set<SlotReference> queryCommonPartitionKeySet = logicalWindow.get()
+                .getCommonPartitionKeyFromWindowExpressions();
+        for (Expression conjuct : comparisonResult.getQueryExpressions()) {
+            if (!queryCommonPartitionKeySet.containsAll(conjuct.getInputSlots())) {
+                return false;
+            }
+        }
+        return superCheck;
+    }
+
+    /**
+     * Rewrite query by view
+     *
+     * @param matchMode match mode
+     * @param queryStructInfo query struct info
+     * @param viewStructInfo view struct info
+     * @param viewToQuerySlotMapping slot mapping from view to query
+     * @param tempRewrittenPlan temporary rewritten plan
+     * @param materializationContext materialization context
+     * @param cascadesContext cascades context
+     * @return rewritten plan
+     */
+    @Override
+    protected Plan rewriteQueryByView(MatchMode matchMode, StructInfo queryStructInfo, StructInfo viewStructInfo,
+            SlotMapping viewToQuerySlotMapping, Plan tempRewrittenPlan, MaterializationContext materializationContext,
+            CascadesContext cascadesContext) {
+        if (!StructInfo.checkWindowTmpRewrittenPlanIsValid(tempRewrittenPlan)) {
+            materializationContext.recordFailReason(queryStructInfo,
+                    "Window rewriteQueryByView fail",
+                    () -> String.format("expressionToRewritten is %s,\n mvExprToMvScanExprMapping is %s,\n"
+                                    + "targetToSourceMapping = %s, tempRewrittenPlan is %s",
+                            queryStructInfo.getExpressions(), materializationContext.getShuttledExprToScanExprMapping(),
+                            viewToQuerySlotMapping, tempRewrittenPlan.treeString()));
+            return null;
+        }
+        // Rewrite top projects, represent the query projects by view
+        List<Expression> expressionsRewritten = rewriteExpression(
+                queryStructInfo.getExpressions(),
+                queryStructInfo.getTopPlan(),
+                materializationContext.getShuttledExprToScanExprMapping(),
+                viewToQuerySlotMapping,
+                queryStructInfo.getTableBitSet(),
+                ImmutableMap.of(), cascadesContext
+        );
+        // Can not rewrite, bail out
+        if (expressionsRewritten.isEmpty()) {
+            materializationContext.recordFailReason(queryStructInfo,
+                    "Rewrite expressions by view in window scan fail",
+                    () -> String.format("expressionToRewritten is %s,\n mvExprToMvScanExprMapping is %s,\n"
+                                    + "targetToSourceMapping = %s", queryStructInfo.getExpressions(),
+                            materializationContext.getShuttledExprToScanExprMapping(),
+                            viewToQuerySlotMapping));
+            return null;
+        }
+        return new LogicalProject<>(
+                expressionsRewritten.stream()
+                        .map(expression -> expression instanceof NamedExpression ? expression : new Alias(expression))
+                        .map(NamedExpression.class::cast)
+                        .collect(Collectors.toList()), tempRewrittenPlan);
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparator.java
index fce8e2f520f..f6d23e6a08a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparator.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/HyperGraphComparator.java
@@ -244,8 +244,19 @@ public class HyperGraphComparator {
     }
 
     private boolean compareNodeWithExpr(StructInfoNode query, StructInfoNode view) {
-        List<Set<Expression>> queryExprSetList = query.getExprSetList();
-        List<Set<Expression>> viewExprSetList = view.getExprSetList();
+        Pair<List<Set<Expression>>, List<Set<Expression>>> queryExprSetList = query.getExprSetList();
+        Pair<List<Set<Expression>>, List<Set<Expression>>> viewExprSetList = view.getExprSetList();
+        if (queryExprSetList == null || viewExprSetList == null) {
+            return false;
+        }
+        return compareNodeWithExpr(query, ExpressionPosition.NODE_COULD_MOVE,
+                queryExprSetList.key(), viewExprSetList.key())
+                && compareNodeWithExpr(query, ExpressionPosition.NODE_COULD_NOT_MOVE,
+                queryExprSetList.value(), viewExprSetList.value());
+    }
+
+    private boolean compareNodeWithExpr(StructInfoNode query, ExpressionPosition expressionPosition,
+            List<Set<Expression>> queryExprSetList, List<Set<Expression>> viewExprSetList) {
         if (queryExprSetList == null || viewExprSetList == null
                 || queryExprSetList.size() != viewExprSetList.size()) {
             return false;
@@ -256,8 +267,7 @@ public class HyperGraphComparator {
             Set<Expression> mappingQueryExprSet = new HashSet<>();
             for (Expression queryExpression : queryExpressions) {
                 Optional<Expression> mappingViewExprByQueryExpr = getMappingViewExprByQueryExpr(queryExpression, query,
-                        this.logicalCompatibilityContext,
-                        ExpressionPosition.NODE);
+                        this.logicalCompatibilityContext, expressionPosition);
                 if (!mappingViewExprByQueryExpr.isPresent()) {
                     return false;
                 }
@@ -619,9 +629,12 @@ public class HyperGraphComparator {
         } else if (ExpressionPosition.FILTER_EDGE.equals(expressionPosition)) {
             queryShuttledExpr = context.getQueryFilterShuttledExpr(queryExpression);
             viewExpressions = context.getViewFilterExprFromQuery(queryShuttledExpr);
+        } else if (ExpressionPosition.NODE_COULD_MOVE.equals(expressionPosition)) {
+            queryShuttledExpr = context.getQueryNodeShuttledCouldMoveExpr(queryExpression);
+            viewExpressions = context.getViewNodeCouldMoveExprFromQuery(queryShuttledExpr);
         } else {
-            queryShuttledExpr = context.getQueryNodeShuttledExpr(queryExpression);
-            viewExpressions = context.getViewNodeExprFromQuery(queryShuttledExpr);
+            queryShuttledExpr = context.getQueryNodeShuttledCouldNotMoveExpr(queryExpression);
+            viewExpressions = context.getViewNodeCouldNotMoveExprFromQuery(queryShuttledExpr);
         }
         if (viewExpressions.size() == 1) {
             return Optional.of(viewExpressions.iterator().next().key());
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/LogicalCompatibilityContext.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/LogicalCompatibilityContext.java
index 77ab37873d0..b0438cf59df 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/LogicalCompatibilityContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/LogicalCompatibilityContext.java
@@ -56,8 +56,12 @@ public class LogicalCompatibilityContext {
             queryToViewJoinEdgeExpressionMappingSupplier;
     private final Supplier<Map<Expression, Expression>> queryToQueryShuttledJoinExpressionMappingSupplier;
     private final Supplier<Multimap<Expression, Pair<Expression, HyperElement>>>
-            queryToViewNodeExpressionMappingSupplier;
-    private final Supplier<Map<Expression, Expression>> queryToQueryShuttledNodeExpressionMappingSupplier;
+            queryToViewNodeCouldMoveExpressionMappingSupplier;
+    private final Supplier<Map<Expression, Expression>> queryToQueryShuttledNodeCouldMoveExpressionMappingSupplier;
+
+    private final Supplier<Multimap<Expression, Pair<Expression, HyperElement>>>
+            queryToViewNodeCouldNotMoveExpressionMappingSupplier;
+    private final Supplier<Map<Expression, Expression>> queryToQueryShuttledNodeCouldNotMoveExpressionMappingSupplier;
     private final Supplier<Multimap<Expression, Pair<Expression, HyperElement>>>
             queryToViewFilterEdgeExpressionMappingSupplier;
     private final Supplier<Map<Expression, Expression>> queryToQueryShuttledFilterExpressionMappingSupplier;
@@ -77,13 +81,26 @@ public class LogicalCompatibilityContext {
         this.queryToQueryShuttledJoinExpressionMappingSupplier = Suppliers.memoize(
                 () -> queryStructInfo.getExpressionToShuttledExpressionToMap().get(ExpressionPosition.JOIN_EDGE));
 
-        this.queryToViewNodeExpressionMappingSupplier =
+        this.queryToViewNodeCouldMoveExpressionMappingSupplier =
+                Suppliers.memoize(() -> generateExpressionMapping(viewToQuerySlotMapping,
+                        queryStructInfo.getShuttledExpressionsToExpressionsMap()
+                                .get(ExpressionPosition.NODE_COULD_MOVE),
+                        viewStructInfo.getShuttledExpressionsToExpressionsMap()
+                                .get(ExpressionPosition.NODE_COULD_MOVE)));
+
+        this.queryToQueryShuttledNodeCouldMoveExpressionMappingSupplier = Suppliers.memoize(
+                () -> queryStructInfo.getExpressionToShuttledExpressionToMap().get(ExpressionPosition.NODE_COULD_MOVE));
+
+        this.queryToViewNodeCouldNotMoveExpressionMappingSupplier =
                 Suppliers.memoize(() -> generateExpressionMapping(viewToQuerySlotMapping,
-                        queryStructInfo.getShuttledExpressionsToExpressionsMap().get(ExpressionPosition.NODE),
-                        viewStructInfo.getShuttledExpressionsToExpressionsMap().get(ExpressionPosition.NODE)));
+                        queryStructInfo.getShuttledExpressionsToExpressionsMap()
+                                .get(ExpressionPosition.NODE_COULD_NOT_MOVE),
+                        viewStructInfo.getShuttledExpressionsToExpressionsMap()
+                                .get(ExpressionPosition.NODE_COULD_NOT_MOVE)));
 
-        this.queryToQueryShuttledNodeExpressionMappingSupplier = Suppliers.memoize(
-                () -> queryStructInfo.getExpressionToShuttledExpressionToMap().get(ExpressionPosition.NODE));
+        this.queryToQueryShuttledNodeCouldNotMoveExpressionMappingSupplier = Suppliers.memoize(
+                () -> queryStructInfo.getExpressionToShuttledExpressionToMap()
+                        .get(ExpressionPosition.NODE_COULD_NOT_MOVE));
 
         this.queryToViewFilterEdgeExpressionMappingSupplier =
                 Suppliers.memoize(() -> generateExpressionMapping(viewToQuerySlotMapping,
@@ -125,12 +142,20 @@ public class LogicalCompatibilityContext {
         return queryToQueryShuttledFilterExpressionMappingSupplier.get().get(queryFilterExpr);
     }
 
-    public Collection<Pair<Expression, HyperElement>> getViewNodeExprFromQuery(Expression queryJoinExpr) {
-        return queryToViewNodeExpressionMappingSupplier.get().get(queryJoinExpr);
+    public Collection<Pair<Expression, HyperElement>> getViewNodeCouldMoveExprFromQuery(Expression queryJoinExpr) {
+        return queryToViewNodeCouldMoveExpressionMappingSupplier.get().get(queryJoinExpr);
+    }
+
+    public Expression getQueryNodeShuttledCouldMoveExpr(Expression queryNodeExpr) {
+        return queryToQueryShuttledNodeCouldMoveExpressionMappingSupplier.get().get(queryNodeExpr);
+    }
+
+    public Collection<Pair<Expression, HyperElement>> getViewNodeCouldNotMoveExprFromQuery(Expression queryJoinExpr) {
+        return queryToViewNodeCouldNotMoveExpressionMappingSupplier.get().get(queryJoinExpr);
     }
 
-    public Expression getQueryNodeShuttledExpr(Expression queryNodeExpr) {
-        return queryToQueryShuttledNodeExpressionMappingSupplier.get().get(queryNodeExpr);
+    public Expression getQueryNodeShuttledCouldNotMoveExpr(Expression queryNodeExpr) {
+        return queryToQueryShuttledNodeCouldNotMoveExpressionMappingSupplier.get().get(queryNodeExpr);
     }
 
     /**
@@ -224,8 +249,8 @@ public class LogicalCompatibilityContext {
                 queryToViewJoinEdgeExpressionMappingSupplier.get() == null
                         ? "" : queryToViewJoinEdgeExpressionMappingSupplier.get().toString(),
                 "queryToViewNodeExpressionMapping",
-                queryToViewNodeExpressionMappingSupplier.get() == null
-                        ? "" : queryToViewNodeExpressionMappingSupplier.get().toString(),
+                queryToViewNodeCouldMoveExpressionMappingSupplier.get() == null
+                        ? "" : queryToViewNodeCouldMoveExpressionMappingSupplier.get().toString(),
                 "queryToViewFilterEdgeExpressionMapping",
                 queryToViewFilterEdgeExpressionMappingSupplier.get() == null
                         ? "" : queryToViewFilterEdgeExpressionMappingSupplier.get().toString());
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowAggregateRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowAggregateRule.java
new file mode 100644
index 00000000000..f1b6905e2c3
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowAggregateRule.java
@@ -0,0 +1,87 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanCheckContext;
+import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * AbstractMaterializedViewWindowRule
+ * This is responsible for common window function rewriting
+ */
+public class MaterializedViewWindowAggregateRule extends AbstractMaterializedViewWindowRule {
+
+    public static MaterializedViewWindowAggregateRule INSTANCE = new MaterializedViewWindowAggregateRule();
+
+    @Override
+    protected Plan rewriteQueryByView(MatchMode matchMode, StructInfo queryStructInfo, StructInfo viewStructInfo,
+            SlotMapping viewToQuerySlotMapping, Plan tempRewritedPlan, MaterializationContext materializationContext,
+            CascadesContext cascadesContext) {
+        return super.rewriteQueryByView(matchMode, queryStructInfo, viewStructInfo, viewToQuerySlotMapping,
+                tempRewritedPlan, materializationContext, cascadesContext);
+    }
+
+    /**
+     * Check window pattern is valid or not
+     */
+    @Override
+    protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext cascadesContext) {
+        PlanCheckContext checkContext = PlanCheckContext.of(SUPPORTED_JOIN_TYPE_SET);
+        return structInfo.getTopPlan().accept(StructInfo.PLAN_PATTERN_CHECKER, checkContext)
+                && checkContext.isContainsTopAggregate() && checkContext.isContainsTopWindow()
+                && checkContext.getTopAggregateNum() <= 1 && checkContext.getTopWindowNum() <= 1
+                && !checkContext.isWindowUnderAggregate();
+    }
+
+    @Override
+    public List<Rule> buildRules() {
+        return ImmutableList.of(
+                logicalWindow(logicalAggregate(any().when(LogicalPlan.class::isInstance)))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_ONLY_WINDOW_AGGREGATE),
+                logicalProject(logicalWindow(logicalAggregate(any().when(LogicalPlan.class::isInstance))))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_WINDOW_AGGREGATE),
+                logicalFilter(logicalWindow(logicalAggregate(any().when(LogicalPlan.class::isInstance))))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_WINDOW_AGGREGATE),
+                logicalProject(logicalFilter(logicalWindow(logicalAggregate(
+                        any().when(LogicalPlan.class::isInstance)))))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_FILTER_WINDOW_AGGREGATE),
+                logicalFilter(logicalProject(logicalWindow(logicalAggregate(
+                        any().when(LogicalPlan.class::isInstance)))))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_PROJECT_WINDOW_AGGREGATE)
+        );
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowJoinRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowJoinRule.java
new file mode 100644
index 00000000000..f1f05d25cc3
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowJoinRule.java
@@ -0,0 +1,97 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanCheckContext;
+import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * Materialized view rewrite rule for window on join
+ */
+public class MaterializedViewWindowJoinRule extends AbstractMaterializedViewWindowRule {
+
+    public static MaterializedViewWindowJoinRule INSTANCE = new MaterializedViewWindowJoinRule();
+
+    @Override
+    protected Plan rewriteQueryByView(MatchMode matchMode, StructInfo queryStructInfo, StructInfo viewStructInfo,
+            SlotMapping viewToQuerySlotMapping, Plan tempRewritedPlan, MaterializationContext materializationContext,
+            CascadesContext cascadesContext) {
+        return super.rewriteQueryByView(matchMode, queryStructInfo, viewStructInfo, viewToQuerySlotMapping,
+                tempRewritedPlan, materializationContext, cascadesContext);
+    }
+
+    /**
+     * Check window pattern is valid or not
+     */
+    @Override
+    protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext cascadesContext) {
+        PlanCheckContext checkContext = PlanCheckContext.of(SUPPORTED_JOIN_TYPE_SET);
+        return structInfo.getTopPlan().accept(StructInfo.PLAN_PATTERN_CHECKER, checkContext)
+                && !checkContext.isContainsTopAggregate() && checkContext.isContainsTopWindow()
+                && checkContext.getTopWindowNum() <= 1;
+    }
+
+    @Override
+    public List<Rule> buildRules() {
+        return ImmutableList.of(
+                logicalFilter(logicalWindow(logicalUnary(logicalJoin(any().when(LogicalPlan.class::isInstance),
+                        any().when(LogicalPlan.class::isInstance)))
+                        .when(node -> node instanceof LogicalProject || node instanceof LogicalFilter)))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_WINDOW_JOIN),
+                logicalProject(logicalWindow(logicalUnary(logicalJoin(any().when(LogicalPlan.class::isInstance),
+                        any().when(LogicalPlan.class::isInstance)))
+                        .when(node -> node instanceof LogicalProject || node instanceof LogicalFilter)))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_WINDOW_JOIN),
+                logicalFilter(
+                        logicalProject(logicalWindow(logicalUnary(logicalJoin(any().when(LogicalPlan.class::isInstance),
+                                any().when(LogicalPlan.class::isInstance)))
+                                .when(node -> node instanceof LogicalProject || node instanceof LogicalFilter))))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_PROJECT_WINDOW_JOIN),
+                logicalProject(
+                        logicalFilter(logicalWindow(logicalUnary(logicalJoin(any().when(LogicalPlan.class::isInstance),
+                                any().when(LogicalPlan.class::isInstance)))
+                                .when(node -> node instanceof LogicalProject || node instanceof LogicalFilter))))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_FILTER_WINDOW_JOIN),
+                logicalWindow(logicalUnary(logicalJoin(any().when(LogicalPlan.class::isInstance),
+                        any().when(LogicalPlan.class::isInstance)))
+                        .when(node -> node instanceof LogicalProject || node instanceof LogicalFilter))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            return rewrite(ctx.root, ctx.cascadesContext);
+                        }).toRule(RuleType.MATERIALIZED_VIEW_ONLY_WINDOW_JOIN)
+        );
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowScanRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowScanRule.java
new file mode 100644
index 00000000000..01ffb0ad351
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewWindowScanRule.java
@@ -0,0 +1,96 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration.mv;
+
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanCheckContext;
+import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation;
+import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import java.util.List;
+
+/**
+ * Materialized view rewrite rule for window on scan
+ */
+public class MaterializedViewWindowScanRule extends AbstractMaterializedViewWindowRule {
+
+    public static MaterializedViewWindowScanRule INSTANCE = new MaterializedViewWindowScanRule();
+
+    @Override
+    protected Plan rewriteQueryByView(MatchMode matchMode, StructInfo queryStructInfo, StructInfo viewStructInfo,
+            SlotMapping viewToQuerySlotMapping, Plan tempRewritedPlan, MaterializationContext materializationContext,
+            CascadesContext cascadesContext) {
+        return super.rewriteQueryByView(matchMode, queryStructInfo, viewStructInfo, viewToQuerySlotMapping,
+                tempRewritedPlan, materializationContext, cascadesContext);
+    }
+
+    /**
+     * Check window pattern is valid or not
+     */
+    @Override
+    protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext cascadesContext) {
+        PlanCheckContext checkContext = PlanCheckContext.of(ImmutableSet.of());
+        return structInfo.getTopPlan().accept(StructInfo.SCAN_PLAN_PATTERN_CHECKER, checkContext)
+                && !checkContext.isContainsTopAggregate() && checkContext.isContainsTopWindow()
+                && checkContext.getTopWindowNum() <= 1;
+    }
+
+    @Override
+    public List<Rule> buildRules() {
+        return ImmutableList.of(
+                logicalFilter(logicalProject(logicalWindow(subTree(
+                        LogicalProject.class, LogicalFilter.class, LogicalCatalogRelation.class))))
+                        .thenApplyMultiNoThrow(
+                                ctx -> {
+                                    return rewrite(ctx.root, ctx.cascadesContext);
+                                }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_PROJECT_WINDOW_SCAN),
+                logicalProject(logicalFilter(logicalWindow(subTree(
+                        LogicalProject.class, LogicalFilter.class, LogicalCatalogRelation.class))))
+                        .thenApplyMultiNoThrow(
+                                ctx -> {
+                                    return rewrite(ctx.root, ctx.cascadesContext);
+                                }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_FILTER_WINDOW_SCAN),
+                logicalProject(logicalWindow(subTree(
+                        LogicalProject.class, LogicalFilter.class, LogicalCatalogRelation.class)))
+                        .thenApplyMultiNoThrow(
+                                ctx -> {
+                                    return rewrite(ctx.root, ctx.cascadesContext);
+                                }).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_WINDOW_SCAN),
+                logicalFilter(logicalWindow(subTree(
+                        LogicalProject.class, LogicalFilter.class, LogicalCatalogRelation.class)))
+                        .thenApplyMultiNoThrow(
+                                ctx -> {
+                                    return rewrite(ctx.root, ctx.cascadesContext);
+                                }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_WINDOW_SCAN),
+                logicalWindow(subTree(
+                        LogicalProject.class, LogicalFilter.class, LogicalCatalogRelation.class))
+                        .thenApplyMultiNoThrow(
+                                ctx -> {
+                                    return rewrite(ctx.root, ctx.cascadesContext);
+                                }).toRule(RuleType.MATERIALIZED_VIEW_ONLY_WINDOW_SCAN)
+                );
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Predicates.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Predicates.java
index 18095d5f60c..5ccf624c510 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Predicates.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/Predicates.java
@@ -37,9 +37,11 @@ import org.apache.doris.nereids.util.Utils;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -57,23 +59,30 @@ public class Predicates {
 
     // Predicates that can be pulled up
     private final Set<Expression> pulledUpPredicates;
+    // Predicates that can not be pulled up, should be equals between query and view
+    private final Set<Expression> couldNotPulledUpPredicates;
 
-    public Predicates(Set<Expression> pulledUpPredicates) {
+    public Predicates(Set<Expression> pulledUpPredicates, Set<Expression> couldNotPulledUpPredicates) {
         this.pulledUpPredicates = pulledUpPredicates;
+        this.couldNotPulledUpPredicates = couldNotPulledUpPredicates;
     }
 
-    public static Predicates of(Set<Expression> pulledUpPredicates) {
-        return new Predicates(pulledUpPredicates);
+    public static Predicates of(Set<Expression> pulledUpPredicates, Set<Expression> predicatesUnderBreaker) {
+        return new Predicates(pulledUpPredicates, predicatesUnderBreaker);
     }
 
     public Set<Expression> getPulledUpPredicates() {
         return pulledUpPredicates;
     }
 
-    public Predicates merge(Collection<Expression> predicates) {
+    public Set<Expression> getCouldNotPulledUpPredicates() {
+        return couldNotPulledUpPredicates;
+    }
+
+    public Predicates mergePulledUpPredicates(Collection<Expression> predicates) {
         Set<Expression> mergedPredicates = new HashSet<>(predicates);
         mergedPredicates.addAll(this.pulledUpPredicates);
-        return new Predicates(mergedPredicates);
+        return new Predicates(mergedPredicates, this.couldNotPulledUpPredicates);
     }
 
     /**
@@ -84,6 +93,41 @@ public class Predicates {
         return predicatesSplit.getSplitPredicate();
     }
 
+    /**
+     * try to compensate could not pull up predicates
+     */
+    public static Map<Expression, ExpressionInfo> compensateCouldNotPullUpPredicates(
+            StructInfo queryStructInfo, StructInfo viewStructInfo,
+            SlotMapping viewToQuerySlotMapping, ComparisonResult comparisonResult) {
+
+        Predicates queryStructInfoPredicates = queryStructInfo.getPredicates();
+        Predicates viewStructInfoPredicates = viewStructInfo.getPredicates();
+        if (queryStructInfoPredicates.getCouldNotPulledUpPredicates().isEmpty()
+                && viewStructInfoPredicates.getCouldNotPulledUpPredicates().isEmpty()) {
+            return ImmutableMap.of();
+        }
+        if (queryStructInfoPredicates.getCouldNotPulledUpPredicates().isEmpty()
+                && !viewStructInfoPredicates.getCouldNotPulledUpPredicates().isEmpty()) {
+            return null;
+        }
+        if (!queryStructInfoPredicates.getCouldNotPulledUpPredicates().isEmpty()
+                && viewStructInfoPredicates.getCouldNotPulledUpPredicates().isEmpty()) {
+            return null;
+        }
+
+        List<? extends Expression> viewPredicatesShuttled = ExpressionUtils.shuttleExpressionWithLineage(
+                Lists.newArrayList(viewStructInfoPredicates.getCouldNotPulledUpPredicates()),
+                viewStructInfo.getTopPlan(), new BitSet());
+        List<Expression> viewPredicatesQueryBased = ExpressionUtils.replace((List<Expression>) viewPredicatesShuttled,
+                viewToQuerySlotMapping.toSlotReferenceMap());
+        // could not be pulled up predicates in query and view should be same
+        if (queryStructInfoPredicates.getCouldNotPulledUpPredicates().equals(
+                Sets.newHashSet(viewPredicatesQueryBased))) {
+            return ImmutableMap.of();
+        }
+        return null;
+    }
+
     /**
      * compensate equivalence predicates
      */
@@ -250,7 +294,8 @@ public class Predicates {
 
     @Override
     public String toString() {
-        return Utils.toSqlString("Predicates", "pulledUpPredicates", pulledUpPredicates);
+        return Utils.toSqlString("Predicates", "pulledUpPredicates", pulledUpPredicates,
+                "predicatesUnderBreaker", couldNotPulledUpPredicates);
     }
 
     /**
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java
index 7b8b976295d..ed232041d4a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java
@@ -28,6 +28,7 @@ import org.apache.doris.nereids.jobs.joinorder.hypergraph.node.StructInfoNode;
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewUtils.TableQueryOperatorChecker;
 import org.apache.doris.nereids.rules.exploration.mv.Predicates.SplitPredicate;
+import org.apache.doris.nereids.rules.rewrite.PushDownFilterThroughWindow;
 import org.apache.doris.nereids.trees.copier.DeepCopierContext;
 import org.apache.doris.nereids.trees.copier.LogicalPlanDeepCopier;
 import org.apache.doris.nereids.trees.expressions.EqualTo;
@@ -53,7 +54,9 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
 import org.apache.doris.nereids.trees.plans.logical.LogicalRepeat;
+import org.apache.doris.nereids.trees.plans.logical.LogicalSink;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSort;
+import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
 import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter;
 import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
 import org.apache.doris.nereids.util.ExpressionUtils;
@@ -65,6 +68,7 @@ import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -83,7 +87,7 @@ public class StructInfo {
     public static final ScanPlanPatternChecker SCAN_PLAN_PATTERN_CHECKER = new ScanPlanPatternChecker();
     // struct info splitter
     public static final PlanSplitter PLAN_SPLITTER = new PlanSplitter();
-    private static final PredicateCollector PREDICATE_COLLECTOR = new PredicateCollector();
+    public static final PredicateCollector PREDICATE_COLLECTOR = new PredicateCollector();
     // source data
     private final Plan originalPlan;
     private final ObjectId originalPlanId;
@@ -185,15 +189,26 @@ public class StructInfo {
             relations.addAll(structInfoNode.getCatalogRelation());
             nodeRelations.forEach(relation -> hyperTableBitSet.set(relation.getRelationId().asInt()));
             // record expressions in node
-            List<Expression> nodeExpressions = structInfoNode.getExpressions();
+            List<Expression> nodeExpressions = structInfoNode.getCouldMoveExpressions();
             if (nodeExpressions != null) {
                 List<? extends Expression> shuttledExpressions = ExpressionUtils.shuttleExpressionWithLineage(
                         nodeExpressions, structInfoNode.getPlan(),
                         new BitSet());
                 for (int index = 0; index < nodeExpressions.size(); index++) {
                     putShuttledExpressionToExpressionsMap(shuttledExpressionsToExpressionsMap,
-                            expressionToShuttledExpressionToMap,
-                            ExpressionPosition.NODE, shuttledExpressions.get(index), nodeExpressions.get(index), node);
+                            expressionToShuttledExpressionToMap, ExpressionPosition.NODE_COULD_MOVE,
+                            shuttledExpressions.get(index), nodeExpressions.get(index), node);
+                }
+            }
+            nodeExpressions = structInfoNode.getCouldNotMoveExpressions();
+            if (nodeExpressions != null) {
+                List<? extends Expression> shuttledExpressions = ExpressionUtils.shuttleExpressionWithLineage(
+                        nodeExpressions, structInfoNode.getPlan(),
+                        new BitSet());
+                for (int index = 0; index < nodeExpressions.size(); index++) {
+                    putShuttledExpressionToExpressionsMap(shuttledExpressionsToExpressionsMap,
+                            expressionToShuttledExpressionToMap, ExpressionPosition.NODE_COULD_NOT_MOVE,
+                            shuttledExpressions.get(index), nodeExpressions.get(index), node);
                 }
             }
             // every node should only have one relation, this is for LogicalCompatibilityContext
@@ -318,9 +333,10 @@ public class StructInfo {
                 ((AbstractPlan) relation).accept(TableQueryOperatorChecker.INSTANCE, null));
         valid = valid && !invalid;
         // collect predicate from top plan which not in hyper graph
-        Set<Expression> topPlanPredicates = new LinkedHashSet<>();
-        topPlan.accept(PREDICATE_COLLECTOR, topPlanPredicates);
-        Predicates predicates = Predicates.of(topPlanPredicates);
+        PredicateCollectorContext predicateCollectorContext = new PredicateCollectorContext();
+        topPlan.accept(PREDICATE_COLLECTOR, predicateCollectorContext);
+        Predicates predicates = Predicates.of(predicateCollectorContext.getCouldPullUpPredicates(),
+                predicateCollectorContext.getCouldNotPullUpPredicates());
         // this should use the output of originalPlan to make sure the output right order
         List<? extends Expression> planOutputShuttledExpressions =
                 ExpressionUtils.shuttleExpressionWithLineage(originalPlan.getOutput(), originalPlan, new BitSet());
@@ -452,21 +468,75 @@ public class StructInfo {
         return "StructInfo{ originalPlanId = " + originalPlanId + ", relations = " + relations + '}';
     }
 
-    private static class PredicateCollector extends DefaultPlanVisitor<Void, Set<Expression>> {
+    private static class RelationCollector extends DefaultPlanVisitor<Void, List<CatalogRelation>> {
         @Override
-        public Void visit(Plan plan, Set<Expression> predicates) {
-            // Just collect the filter in top plan, if meet other node except project and filter, return
-            if (!(plan instanceof LogicalProject)
+        public Void visit(Plan plan, List<CatalogRelation> collectedRelations) {
+            if (plan instanceof CatalogRelation) {
+                collectedRelations.add((CatalogRelation) plan);
+            }
+            return super.visit(plan, collectedRelations);
+        }
+    }
+
+    private static class PredicateCollector extends DefaultPlanVisitor<Void, PredicateCollectorContext> {
+        @Override
+        public Void visit(Plan plan, PredicateCollectorContext collectorContext) {
+            // Just collect the filter in top plan, if meet other node except the following node, return
+            if (!(plan instanceof LogicalSink)
+                    && !(plan instanceof LogicalProject)
                     && !(plan instanceof LogicalFilter)
                     && !(plan instanceof LogicalAggregate)
+                    && !(plan instanceof LogicalWindow)
                     && !(plan instanceof LogicalSort)
                     && !(plan instanceof LogicalRepeat)) {
                 return null;
             }
-            if (plan instanceof LogicalFilter) {
-                predicates.addAll(ExpressionUtils.extractConjunction(((LogicalFilter) plan).getPredicate()));
+            return super.visit(plan, collectorContext);
+        }
+
+        @Override
+        public Void visitLogicalFilter(LogicalFilter<? extends Plan> filter, PredicateCollectorContext context) {
+            if (context.getWindowCommonPartitionKeys().isEmpty()) {
+                context.getCouldPullUpPredicates().addAll(filter.getConjuncts());
+            } else {
+                // if the filter contains the partition key of window, it can be pulled up
+                for (Expression conjunct : filter.getConjuncts()) {
+                    if (PushDownFilterThroughWindow.canPushDown(conjunct, context.getWindowCommonPartitionKeys())) {
+                        context.getCouldPullUpPredicates().add(conjunct);
+                    } else {
+                        context.getCouldNotPullUpPredicates().add(conjunct);
+                    }
+                }
             }
-            return super.visit(plan, predicates);
+            return super.visit(filter, context);
+        }
+
+        @Override
+        public Void visitLogicalWindow(LogicalWindow<? extends Plan> window, PredicateCollectorContext context) {
+            Set<SlotReference> commonPartitionKeys = window.getCommonPartitionKeyFromWindowExpressions();
+            context.getWindowCommonPartitionKeys().addAll(commonPartitionKeys);
+            return super.visit(window, context);
+        }
+    }
+
+    /**
+     * PredicateCollectorContext
+     */
+    public static class PredicateCollectorContext {
+        private Set<Expression> couldPullUpPredicates = new HashSet<>();
+        private Set<Expression> couldNotPullUpPredicates = new HashSet<>();
+        private Set<SlotReference> windowCommonPartitionKeys = new HashSet<>();
+
+        public Set<Expression> getCouldPullUpPredicates() {
+            return couldPullUpPredicates;
+        }
+
+        public Set<Expression> getCouldNotPullUpPredicates() {
+            return couldNotPullUpPredicates;
+        }
+
+        public Set<SlotReference> getWindowCommonPartitionKeys() {
+            return windowCommonPartitionKeys;
         }
     }
 
@@ -553,10 +623,19 @@ public class StructInfo {
      * The context for plan check context, make sure that the plan in query and mv is valid or not
      */
     public static class PlanCheckContext {
-        // the aggregate above join
+        // Record if aggregate is above join or not
         private boolean containsTopAggregate = false;
         private int topAggregateNum = 0;
+        // This indicates whether the operators above the join contain any window operator.
+        private boolean containsTopWindow = false;
+        // This records the number of window operators above the join.
+        private int topWindowNum = 0;
         private boolean alreadyMeetJoin = false;
+        // Records whether an Aggregate operator has been meet when check window operator
+        private boolean alreadyMeetAggregate = false;
+        // Indicates if a window operator is under an Aggregate operator, because the window operator under
+        // aggregate is not supported now.
+        private boolean windowUnderAggregate = false;
         private final Set<JoinType> supportJoinTypes;
 
         public PlanCheckContext(Set<JoinType> supportJoinTypes) {
@@ -571,6 +650,22 @@ public class StructInfo {
             this.containsTopAggregate = containsTopAggregate;
         }
 
+        public boolean isContainsTopWindow() {
+            return containsTopWindow;
+        }
+
+        public void setContainsTopWindow(boolean containsTopWindow) {
+            this.containsTopWindow = containsTopWindow;
+        }
+
+        public int getTopWindowNum() {
+            return topWindowNum;
+        }
+
+        public void plusTopWindowNum() {
+            this.topWindowNum += 1;
+        }
+
         public boolean isAlreadyMeetJoin() {
             return alreadyMeetJoin;
         }
@@ -591,6 +686,22 @@ public class StructInfo {
             this.topAggregateNum += 1;
         }
 
+        public boolean isAlreadyMeetAggregate() {
+            return alreadyMeetAggregate;
+        }
+
+        public void setAlreadyMeetAggregate(boolean alreadyMeetAggregate) {
+            this.alreadyMeetAggregate = alreadyMeetAggregate;
+        }
+
+        public boolean isWindowUnderAggregate() {
+            return windowUnderAggregate;
+        }
+
+        public void setWindowUnderAggregate(boolean windowUnderAggregate) {
+            this.windowUnderAggregate = windowUnderAggregate;
+        }
+
         public static PlanCheckContext of(Set<JoinType> supportJoinTypes) {
             return new PlanCheckContext(supportJoinTypes);
         }
@@ -615,11 +726,25 @@ public class StructInfo {
                 PlanCheckContext checkContext) {
             if (!checkContext.isAlreadyMeetJoin()) {
                 checkContext.setContainsTopAggregate(true);
+                checkContext.setAlreadyMeetAggregate(true);
                 checkContext.plusTopAggregateNum();
             }
             return visit(aggregate, checkContext);
         }
 
+        @Override
+        public Boolean visitLogicalWindow(LogicalWindow<? extends Plan> window, PlanCheckContext checkContext) {
+            if (!checkContext.isAlreadyMeetJoin()) {
+                if (checkContext.isAlreadyMeetAggregate()) {
+                    checkContext.setWindowUnderAggregate(true);
+                    return false;
+                }
+                checkContext.setContainsTopWindow(true);
+                checkContext.plusTopWindowNum();
+            }
+            return visit(window, checkContext);
+        }
+
         @Override
         public Boolean visitGroupPlan(GroupPlan groupPlan, PlanCheckContext checkContext) {
             return groupPlan.getGroup().getLogicalExpressions().stream()
@@ -635,7 +760,8 @@ public class StructInfo {
                     || plan instanceof LogicalSort
                     || plan instanceof LogicalAggregate
                     || plan instanceof GroupPlan
-                    || plan instanceof LogicalRepeat) {
+                    || plan instanceof LogicalRepeat
+                    || plan instanceof LogicalWindow) {
                 return doVisit(plan, checkContext);
             }
             return false;
@@ -663,13 +789,21 @@ public class StructInfo {
                     .anyMatch(logicalExpression -> logicalExpression.getPlan().accept(this, checkContext));
         }
 
+        @Override
+        public Boolean visitLogicalWindow(LogicalWindow<? extends Plan> window, PlanCheckContext checkContext) {
+            checkContext.setContainsTopWindow(true);
+            checkContext.plusTopWindowNum();
+            return visit(window, checkContext);
+        }
+
         @Override
         public Boolean visit(Plan plan, PlanCheckContext checkContext) {
             if (plan instanceof Filter
                     || plan instanceof Project
                     || plan instanceof CatalogRelation
                     || plan instanceof GroupPlan
-                    || plan instanceof LogicalRepeat) {
+                    || plan instanceof LogicalRepeat
+                    || plan instanceof LogicalWindow) {
                 return doVisit(plan, checkContext);
             }
             return false;
@@ -745,7 +879,34 @@ public class StructInfo {
      */
     public static enum ExpressionPosition {
         JOIN_EDGE,
-        NODE,
+        NODE_COULD_MOVE,
+        NODE_COULD_NOT_MOVE,
         FILTER_EDGE
     }
+
+    /**
+     * Check the tempRewrittenPlan is valid, should only contain project, scan or filter
+     */
+    public static boolean checkWindowTmpRewrittenPlanIsValid(Plan tempRewrittenPlan) {
+        if (tempRewrittenPlan == null) {
+            return false;
+        }
+        return tempRewrittenPlan.accept(new DefaultPlanVisitor<Boolean, Void>() {
+            @Override
+            public Boolean visit(Plan plan, Void context) {
+                if (plan instanceof LogicalProject || plan instanceof CatalogRelation
+                        || plan instanceof LogicalFilter) {
+                    boolean isValid;
+                    for (Plan child : plan.children()) {
+                        isValid = child.accept(this, context);
+                        if (!isValid) {
+                            return false;
+                        }
+                    }
+                    return true;
+                }
+                return false;
+            }
+        }, null);
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownFilterThroughWindow.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownFilterThroughWindow.java
index a949cbc9453..678e19da169 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownFilterThroughWindow.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownFilterThroughWindow.java
@@ -64,7 +64,7 @@ public class PushDownFilterThroughWindow extends OneRewriteRuleFactory {
             Set<Expression> bottomConjuncts = Sets.newHashSet();
             Set<Expression> upperConjuncts = Sets.newHashSet();
             for (Expression expr : filter.getConjuncts()) {
-                if (commonPartitionKeys.containsAll(expr.getInputSlots())) {
+                if (canPushDown(expr, commonPartitionKeys)) {
                     bottomConjuncts.add(expr);
                 } else {
                     upperConjuncts.add(expr);
@@ -86,4 +86,7 @@ public class PushDownFilterThroughWindow extends OneRewriteRuleFactory {
         }).toRule(RuleType.PUSH_DOWN_FILTER_THROUGH_WINDOW);
     }
 
+    public static boolean canPushDown(Expression conjunct, Set<SlotReference> commonPartitionKeys) {
+        return commonPartitionKeys.containsAll(conjunct.getInputSlots());
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalWindow.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalWindow.java
index fde80a4d5b6..72067d73ef8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalWindow.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalWindow.java
@@ -50,6 +50,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -97,6 +98,14 @@ public class LogicalWindow<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_T
         return windowExpressions;
     }
 
+    public List<WindowExpression> getActualWindowExpressions() {
+        List<WindowExpression> actualWindowExpressions = new ArrayList<>();
+        for (NamedExpression expr : windowExpressions) {
+            actualWindowExpressions.add((WindowExpression) (expr.child(0)));
+        }
+        return actualWindowExpressions;
+    }
+
     public LogicalWindow<Plan> withExpressionsAndChild(List<NamedExpression> windowExpressions, Plan child) {
         return new LogicalWindow<>(windowExpressions, isChecked, child);
     }
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/mv/PredicatesTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/mv/PredicatesTest.java
new file mode 100644
index 00000000000..6b5e0596205
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/mv/PredicatesTest.java
@@ -0,0 +1,190 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.mv;
+
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.rules.exploration.mv.ComparisonResult;
+import org.apache.doris.nereids.rules.exploration.mv.HyperGraphComparator;
+import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewUtils;
+import org.apache.doris.nereids.rules.exploration.mv.Predicates;
+import org.apache.doris.nereids.rules.exploration.mv.Predicates.ExpressionInfo;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo;
+import org.apache.doris.nereids.rules.exploration.mv.mapping.RelationMapping;
+import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping;
+import org.apache.doris.nereids.sqltest.SqlTestBase;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.util.PlanChecker;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.BitSet;
+import java.util.Map;
+
+/** Test the method in Predicates*/
+public class PredicatesTest extends SqlTestBase {
+
+    @Override
+    protected void runBeforeAll() throws Exception {
+        createDatabase("predicates_test");
+        useDatabase("predicates_test");
+
+        createTables(
+                "CREATE TABLE IF NOT EXISTS T1 (\n"
+                        + "    id bigint,\n"
+                        + "    score bigint\n"
+                        + ")\n"
+                        + "DUPLICATE KEY(id)\n"
+                        + "DISTRIBUTED BY HASH(id, score) BUCKETS 10\n"
+                        + "PROPERTIES (\n"
+                        + "  \"replication_num\" = \"1\", \n"
+                        + "  \"colocate_with\" = \"T0\"\n"
+                        + ")\n"
+        );
+
+        // Should not make scan to empty relation when the table used by materialized view has no data
+        connectContext.getSessionVariable().setDisableNereidsRules(
+                "OLAP_SCAN_PARTITION_PRUNE"
+                        + ",PRUNE_EMPTY_PARTITION"
+                        + ",ELIMINATE_GROUP_BY_KEY_BY_UNIFORM"
+                        + ",ELIMINATE_CONST_JOIN_CONDITION"
+                        + ",CONSTANT_PROPAGATION"
+                        + ",INFER_PREDICATES"
+        );
+    }
+
+    @Test
+    public void testCompensateCouldNotPullUpPredicatesFail() {
+        CascadesContext mvContext = createCascadesContext(
+                "select \n"
+                        + "id,\n"
+                        + "FIRST_VALUE(id) OVER (\n"
+                        + "        PARTITION BY score \n"
+                        + "        ORDER BY score NULLS LAST\n"
+                        + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                        + "    ) AS first_value\n"
+                        + "from \n"
+                        + "T1\n"
+                        + "where score > 10 and id < 5;",
+                connectContext
+        );
+        Plan mvPlan = PlanChecker.from(mvContext)
+                .analyze()
+                .rewrite()
+                .getPlan().child(0);
+
+        CascadesContext queryContext = createCascadesContext(
+                "select \n"
+                        + "id,\n"
+                        + "FIRST_VALUE(id) OVER (\n"
+                        + "        PARTITION BY score \n"
+                        + "        ORDER BY score NULLS LAST\n"
+                        + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                        + "    ) AS first_value\n"
+                        + "from \n"
+                        + "T1\n"
+                        + "where score > 10 and id < 1;",
+                connectContext
+        );
+        Plan queryPlan = PlanChecker.from(queryContext)
+                .analyze()
+                .rewrite()
+                .getAllPlan().get(0).child(0);
+
+        StructInfo mvStructInfo = MaterializedViewUtils.extractStructInfo(mvPlan, mvPlan,
+                mvContext, new BitSet()).get(0);
+        StructInfo queryStructInfo = MaterializedViewUtils.extractStructInfo(queryPlan, queryPlan,
+                queryContext, new BitSet()).get(0);
+        RelationMapping relationMapping = RelationMapping.generate(mvStructInfo.getRelations(),
+                        queryStructInfo.getRelations(), 16).get(0);
+
+        SlotMapping mvToQuerySlotMapping = SlotMapping.generate(relationMapping);
+        ComparisonResult comparisonResult = HyperGraphComparator.isLogicCompatible(
+                queryStructInfo.getHyperGraph(),
+                mvStructInfo.getHyperGraph(),
+                constructContext(queryPlan, mvPlan, queryContext));
+
+        Map<Expression, ExpressionInfo> expressionExpressionInfoMap = Predicates.compensateCouldNotPullUpPredicates(
+                queryStructInfo, mvStructInfo, mvToQuerySlotMapping, comparisonResult);
+        Assertions.assertNull(expressionExpressionInfoMap);
+    }
+
+    @Test
+    public void testCompensateCouldNotPullUpPredicatesSuccess() {
+        CascadesContext mvContext = createCascadesContext(
+                "select \n"
+                        + "id,\n"
+                        + "FIRST_VALUE(id) OVER (\n"
+                        + "        PARTITION BY score \n"
+                        + "        ORDER BY score NULLS LAST\n"
+                        + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                        + "    ) AS first_value\n"
+                        + "from \n"
+                        + "T1\n"
+                        + "where score > 10 and id < 5;",
+                connectContext
+        );
+        Plan mvPlan = PlanChecker.from(mvContext)
+                .analyze()
+                .rewrite()
+                .getPlan().child(0);
+
+        CascadesContext queryContext = createCascadesContext(
+                "select \n"
+                        + "id,\n"
+                        + "FIRST_VALUE(id) OVER (\n"
+                        + "        PARTITION BY score \n"
+                        + "        ORDER BY score NULLS LAST\n"
+                        + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                        + "    ) AS first_value\n"
+                        + "from \n"
+                        + "T1\n"
+                        + "where score > 15 and id < 5;",
+                connectContext
+        );
+        Plan queryPlan = PlanChecker.from(queryContext)
+                .analyze()
+                .rewrite()
+                .getAllPlan().get(0).child(0);
+
+        StructInfo mvStructInfo = MaterializedViewUtils.extractStructInfo(mvPlan, mvPlan,
+                mvContext, new BitSet()).get(0);
+        StructInfo queryStructInfo = MaterializedViewUtils.extractStructInfo(queryPlan, queryPlan,
+                queryContext, new BitSet()).get(0);
+        RelationMapping relationMapping = RelationMapping.generate(mvStructInfo.getRelations(),
+                queryStructInfo.getRelations(), 16).get(0);
+
+        SlotMapping mvToQuerySlotMapping = SlotMapping.generate(relationMapping);
+        ComparisonResult comparisonResult = HyperGraphComparator.isLogicCompatible(
+                queryStructInfo.getHyperGraph(),
+                mvStructInfo.getHyperGraph(),
+                constructContext(queryPlan, mvPlan, queryContext));
+
+        Map<Expression, ExpressionInfo> compensateCouldNotPullUpPredicates = Predicates.compensateCouldNotPullUpPredicates(
+                queryStructInfo, mvStructInfo, mvToQuerySlotMapping, comparisonResult);
+        Assertions.assertNotNull(compensateCouldNotPullUpPredicates);
+        Assertions.assertTrue(compensateCouldNotPullUpPredicates.isEmpty());
+
+        Map<Expression, ExpressionInfo> compensateRangePredicates = Predicates.compensateRangePredicate(
+                queryStructInfo, mvStructInfo, mvToQuerySlotMapping, comparisonResult,
+                queryContext);
+        Assertions.assertNotNull(compensateRangePredicates);
+        Assertions.assertEquals(1, compensateRangePredicates.size());
+    }
+}
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/mv/StructInfoTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/mv/StructInfoTest.java
new file mode 100644
index 00000000000..3e720b93f4c
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/mv/StructInfoTest.java
@@ -0,0 +1,242 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.mv;
+
+import org.apache.doris.nereids.rules.exploration.mv.AbstractMaterializedViewJoinRule;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanCheckContext;
+import org.apache.doris.nereids.rules.exploration.mv.StructInfo.PredicateCollectorContext;
+import org.apache.doris.nereids.sqltest.SqlTestBase;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.util.PlanChecker;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test the methods in StructInfo.
+ */
+public class StructInfoTest extends SqlTestBase {
+
+    @Override
+    protected void runBeforeAll() throws Exception {
+        createDatabase("struct_info_test");
+        useDatabase("struct_info_test");
+        createTables("CREATE TABLE IF NOT EXISTS orders_arr  (\n"
+                + "  o_orderkey       INTEGER NOT NULL,\n"
+                + "  o_orderstatus    CHAR(1) NOT NULL,\n"
+                + "  o_totalprice     DECIMALV3(15,2) NOT NULL,\n"
+                + "  o_custkey        INTEGER NOT NULL,\n"
+                + "  o_orderdate      DATE NOT NULL,\n"
+                + "  o_orderpriority  CHAR(15) NOT NULL,  \n"
+                + "  o_shippriority   INTEGER NOT NULL,\n"
+                + "  o_comment        VARCHAR(79) NOT NULL,\n"
+                + "  o_array1 ARRAY<int(11)> NULL,\n"
+                + "  o_array2 ARRAY<int(11)> NULL\n"
+                + ")\n"
+                + "DUPLICATE KEY(o_orderkey, o_orderstatus)\n"
+                + "DISTRIBUTED BY HASH(o_orderkey) BUCKETS 3\n"
+                + "PROPERTIES (\n"
+                + "  \"replication_num\" = \"1\"\n"
+                + ");");
+        // Should not make scan to empty relation when the table used by materialized view has no data
+        connectContext.getSessionVariable().setDisableNereidsRules(
+                "OLAP_SCAN_PARTITION_PRUNE"
+                        + ",PRUNE_EMPTY_PARTITION"
+                        + ",ELIMINATE_GROUP_BY_KEY_BY_UNIFORM"
+                        + ",ELIMINATE_CONST_JOIN_CONDITION"
+                        + ",CONSTANT_PROPAGATION"
+        );
+    }
+
+    @Test
+    public void testPlanPatternCheckerWindowAboveAgg() {
+        PlanChecker.from(connectContext)
+                .checkExplain("select \n"
+                                + "o_orderkey,\n"
+                                + "FIRST_VALUE(o_custkey) OVER (\n"
+                                + "        PARTITION BY o_orderdate \n"
+                                + "        ORDER BY o_totalprice NULLS LAST\n"
+                                + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                                + "    ) AS first_value,\n"
+                                + "RANK() OVER (\n"
+                                + "        PARTITION BY o_orderdate, o_orderstatus \n"
+                                + "        ORDER BY o_totalprice NULLS LAST\n"
+                                + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                                + "    ) AS rank_value,\n"
+                                + "count(*)    \n"
+                                + "from \n"
+                                + "orders_arr\n"
+                                + "group by o_orderkey,\n"
+                                + "o_custkey,\n"
+                                + "o_orderdate,\n"
+                                + "o_orderstatus,\n"
+                                + "o_totalprice;",
+                        nereidsPlanner -> {
+                            Plan rewrittenPlan = nereidsPlanner.getRewrittenPlan();
+                            PlanCheckContext planCheckContext = new PlanCheckContext(
+                                    AbstractMaterializedViewJoinRule.SUPPORTED_JOIN_TYPE_SET);
+                            Boolean valid = rewrittenPlan.child(0).accept(
+                                    StructInfo.PLAN_PATTERN_CHECKER, planCheckContext);
+                            Assertions.assertTrue(valid);
+                            Assertions.assertEquals(1, planCheckContext.getTopWindowNum());
+                            Assertions.assertTrue(planCheckContext.isContainsTopWindow());
+                            Assertions.assertFalse(planCheckContext.isWindowUnderAggregate());
+                        });
+    }
+
+    @Test
+    public void testPlanPatternCheckerWindowUnderAgg() {
+        PlanChecker.from(connectContext)
+                .checkExplain("select o_orderkey, first_value, count(*)\n"
+                                + "from\n"
+                                + "(\n"
+                                + "select \n"
+                                + "o_orderkey, o_orderdate,\n"
+                                + "FIRST_VALUE(o_custkey) OVER (\n"
+                                + "        PARTITION BY o_orderdate \n"
+                                + "        ORDER BY o_totalprice NULLS LAST\n"
+                                + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                                + "    ) AS first_value,\n"
+                                + "RANK() OVER (\n"
+                                + "        PARTITION BY o_orderdate, o_orderstatus \n"
+                                + "        ORDER BY o_totalprice NULLS LAST\n"
+                                + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                                + "    ) AS rank_value\n"
+                                + "from \n"
+                                + "orders_arr\n"
+                                + ") t\n"
+                                + "group by o_orderkey, first_value;",
+                        nereidsPlanner -> {
+
+                            Plan rewrittenPlan = nereidsPlanner.getRewrittenPlan();
+                            PlanCheckContext planCheckContext = new PlanCheckContext(
+                                    AbstractMaterializedViewJoinRule.SUPPORTED_JOIN_TYPE_SET);
+                            Boolean valid = rewrittenPlan.child(0).accept(
+                                    StructInfo.PLAN_PATTERN_CHECKER, planCheckContext);
+                            Assertions.assertFalse(valid);
+                            Assertions.assertEquals(0, planCheckContext.getTopWindowNum());
+                            Assertions.assertFalse(planCheckContext.isContainsTopWindow());
+                            Assertions.assertTrue(planCheckContext.isWindowUnderAggregate());
+                        });
+    }
+
+    @Test
+    public void testCheckWindowTmpRewrittenPlanInValid() {
+        PlanChecker.from(connectContext)
+                .checkExplain("select o_orderkey, c2\n"
+                                + "from (select o_orderkey from orders_arr limit 1) orders_a\n"
+                                + "LATERAL VIEW explode_numbers(0) t1 as c2\n"
+                                + "order by c2;",
+                        nereidsPlanner -> {
+                            Plan rewrittenPlan = nereidsPlanner.getRewrittenPlan().child(0);
+                            Assertions.assertFalse(StructInfo.checkWindowTmpRewrittenPlanIsValid(rewrittenPlan));
+                        });
+    }
+
+    @Test
+    public void testCheckWindowTmpRewrittenPlanIsValid() {
+        PlanChecker.from(connectContext)
+                .checkExplain("select o_orderkey from orders_arr where o_orderkey > 1",
+                        nereidsPlanner -> {
+                            Plan rewrittenPlan = nereidsPlanner.getRewrittenPlan().child(0);
+                            Assertions.assertTrue(StructInfo.checkWindowTmpRewrittenPlanIsValid(rewrittenPlan));
+                        });
+    }
+
+    @Test
+    public void testPredicateCollectorWithCouldPullUp() {
+        PlanChecker.from(connectContext)
+                .checkExplain("select \n"
+                                + "o_orderkey, o_orderdate,\n"
+                                + "FIRST_VALUE(o_custkey) OVER (\n"
+                                + "        PARTITION BY o_orderdate \n"
+                                + "        ORDER BY o_totalprice NULLS LAST\n"
+                                + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                                + "    ) AS first_value\n"
+                                + "from \n"
+                                + "(\n"
+                                + "select * from orders_arr where o_orderdate > '2025-01-01' and o_custkey = 1\n"
+                                + ") t;",
+                        nereidsPlanner -> {
+
+                            Plan rewrittenPlan = nereidsPlanner.getRewrittenPlan().child(0);
+                            PredicateCollectorContext predicateCollectorContext = new PredicateCollectorContext();
+                            rewrittenPlan.accept(StructInfo.PREDICATE_COLLECTOR, predicateCollectorContext);
+                            Assertions.assertEquals(1,
+                                    predicateCollectorContext.getCouldPullUpPredicates().size());
+                            Assertions.assertTrue(
+                                    predicateCollectorContext.getCouldPullUpPredicates().stream().allMatch(
+                                            expr -> expr.collectFirst(
+                                                            node -> node instanceof SlotReference
+                                                                    && ((SlotReference) node).getName()
+                                                                    .equalsIgnoreCase("o_orderdate"))
+                                                    .isPresent()));
+                            Assertions.assertEquals(1,
+                                    predicateCollectorContext.getCouldNotPullUpPredicates().size());
+                            Assertions.assertTrue(
+                                    predicateCollectorContext.getCouldNotPullUpPredicates().stream().allMatch(
+                                            expr -> expr.collectFirst(
+                                                            node -> node instanceof SlotReference
+                                                                    && ((SlotReference) node).getName()
+                                                                    .equalsIgnoreCase("o_custkey"))
+                                                    .isPresent()));
+                        });
+    }
+
+    @Test
+    public void testPredicateCollectorWithCouldNotPullUp() {
+        PlanChecker.from(connectContext)
+                .checkExplain("select o_orderkey, first_value\n"
+                                + "from\n"
+                                + "(\n"
+                                + "select \n"
+                                + "o_orderkey, o_orderdate,\n"
+                                + "FIRST_VALUE(o_custkey) OVER (\n"
+                                + "        PARTITION BY o_orderdate \n"
+                                + "        ORDER BY o_totalprice NULLS LAST\n"
+                                + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                                + "    ) AS first_value,\n"
+                                + "RANK() OVER (\n"
+                                + "        PARTITION BY o_orderdate, o_orderstatus \n"
+                                + "        ORDER BY o_totalprice NULLS LAST\n"
+                                + "        RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n"
+                                + "    ) AS rank_value\n"
+                                + "from \n"
+                                + "orders_arr\n"
+                                + ") t\n"
+                                + "where first_value > 0;",
+                        nereidsPlanner -> {
+                            Plan rewrittenPlan = nereidsPlanner.getRewrittenPlan().child(0);
+                            PredicateCollectorContext predicateCollectorContext = new PredicateCollectorContext();
+                            rewrittenPlan.accept(StructInfo.PREDICATE_COLLECTOR, predicateCollectorContext);
+                            Assertions.assertEquals(1,
+                                    predicateCollectorContext.getCouldPullUpPredicates().size());
+                            Assertions.assertEquals(0,
+                                    predicateCollectorContext.getCouldNotPullUpPredicates().size());
+                            Assertions.assertTrue(
+                                    predicateCollectorContext.getCouldPullUpPredicates().stream().allMatch(
+                                            expr -> expr.collectFirst(
+                                                            node -> node instanceof SlotReference
+                                                                    && ((SlotReference) node).getName()
+                                                                    .equalsIgnoreCase("first_value"))
+                                                    .isPresent()));
+                        });
+    }
+}
diff --git a/regression-test/data/nereids_rules_p0/mv/window/window_above_aggregate.out b/regression-test/data/nereids_rules_p0/mv/window/window_above_aggregate.out
new file mode 100644
index 00000000000..a4b4db2fecf
--- /dev/null
+++ b/regression-test/data/nereids_rules_p0/mv/window/window_above_aggregate.out
@@ -0,0 +1,271 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !query1_0_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query1_0_after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query1_1_before --
+
+-- !query1_1_after --
+
+-- !query2_0_before --
+3	1	6.50	1	1	0.00
+3	1	6.50	1	2	6.50
+4	2	6.50	2	1	0.00
+5	2	8.50	2	1	0.00
+5	2	8.50	2	2	8.50
+
+-- !query2_0_after --
+3	1	6.50	1	1	0.00
+3	1	6.50	1	2	6.50
+4	2	6.50	2	1	0.00
+5	2	8.50	2	1	0.00
+5	2	8.50	2	2	8.50
+
+-- !query2_1_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query2_1_after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query2_2_before --
+3	1	6.50	1	1	0.00	3
+3	1	6.50	1	2	6.50	3
+4	2	6.50	2	1	0.00	\N
+5	2	8.50	2	1	0.00	3
+5	2	8.50	2	2	8.50	3
+
+-- !query2_2_after --
+3	1	6.50	1	1	0.00	3
+3	1	6.50	1	2	6.50	3
+4	2	6.50	2	1	0.00	\N
+5	2	8.50	2	1	0.00	3
+5	2	8.50	2	2	8.50	3
+
+-- !query2_3_before --
+2	1	6.50	1	1	0.00	\N
+3	1	6.50	1	1	0.00	3
+3	1	6.50	1	2	6.50	3
+4	2	6.50	2	1	0.00	\N
+5	2	8.50	2	1	0.00	3
+5	2	8.50	2	2	8.50	3
+
+-- !query2_3_after --
+2	1	6.50	1	1	0.00	\N
+3	1	6.50	1	1	0.00	3
+3	1	6.50	1	2	6.50	3
+4	2	6.50	2	1	0.00	\N
+5	2	8.50	2	1	0.00	3
+5	2	8.50	2	2	8.50	3
+
+-- !query3_0_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query3_0_after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query3_1_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query3_1after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query4_0_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query4_0after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query4_1_before --
+6.50	2023-12-08	1	10.50	o	6.50	2023-12-08	5.50	1	1	2	6.50
+6.50	2023-12-08	1	9.50	o	6.50	2023-12-08	5.50	1	1	1	0.00
+6.50	2023-12-09	1	11.50	o	6.50	2023-12-09	5.50	2	1	1	0.00
+6.50	2023-12-09	1	11.50	o	6.50	2023-12-09	5.50	2	1	1	6.50
+6.50	2023-12-10	1	12.50	o	6.50	2023-12-10	5.50	3	1	1	0.00
+6.50	2023-12-10	1	12.50	o	6.50	2023-12-10	5.50	3	1	1	6.50
+6.50	2023-12-10	1	33.50	o	6.50	2023-12-10	5.50	3	1	4	6.50
+6.50	2023-12-11	2	43.20	o	6.50	2023-12-11	5.50	4	2	1	0.00
+6.50	2023-12-11	2	43.20	o	6.50	2023-12-11	5.50	4	2	1	6.50
+8.50	2023-12-12	2	1.20	o	8.50	2023-12-12	7.50	5	2	1	0.00
+8.50	2023-12-12	2	56.20	o	8.50	2023-12-12	7.50	5	2	2	8.50
+
+-- !query4_1after --
+6.50	2023-12-08	1	10.50	o	6.50	2023-12-08	5.50	1	1	2	6.50
+6.50	2023-12-08	1	9.50	o	6.50	2023-12-08	5.50	1	1	1	0.00
+6.50	2023-12-09	1	11.50	o	6.50	2023-12-09	5.50	2	1	1	0.00
+6.50	2023-12-09	1	11.50	o	6.50	2023-12-09	5.50	2	1	1	6.50
+6.50	2023-12-10	1	12.50	o	6.50	2023-12-10	5.50	3	1	1	0.00
+6.50	2023-12-10	1	12.50	o	6.50	2023-12-10	5.50	3	1	1	6.50
+6.50	2023-12-10	1	33.50	o	6.50	2023-12-10	5.50	3	1	4	6.50
+6.50	2023-12-11	2	43.20	o	6.50	2023-12-11	5.50	4	2	1	0.00
+6.50	2023-12-11	2	43.20	o	6.50	2023-12-11	5.50	4	2	1	6.50
+8.50	2023-12-12	2	1.20	o	8.50	2023-12-12	7.50	5	2	1	0.00
+8.50	2023-12-12	2	56.20	o	8.50	2023-12-12	7.50	5	2	2	8.50
+
+-- !query5_0_before --
+
+-- !query5_0_after --
+
+-- !query5_1_before --
+
+-- !query5_1_after --
+
+-- !query6_0_before --
+3	1	6.50	1	1	0.00
+3	1	6.50	1	2	6.50
+4	2	6.50	2	1	0.00
+5	2	8.50	2	1	0.00
+5	2	8.50	2	2	8.50
+
+-- !query6_0_after --
+3	1	6.50	1	1	0.00
+3	1	6.50	1	2	6.50
+4	2	6.50	2	1	0.00
+5	2	8.50	2	1	0.00
+5	2	8.50	2	2	8.50
+
+-- !query6_1_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query6_1_after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query7_0_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query7_0_after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query7_1_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query7_1after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query7_2_before --
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query7_2after --
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query8_0_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query8_0after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query8_1_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query8_1after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query9_0_before --
+
+-- !query9_0_after --
+
+-- !query9_1_before --
+
+-- !query9_1_after --
+
+-- !query9_2_before --
+
+-- !query9_2_after --
+
+-- !query10_0_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query10_0_after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query10_1_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query10_1_after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query11_0_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query11_0_after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query11_1_before --
+
+-- !query11_1after --
+
+-- !query12_0_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query12_0after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query12_1_before --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
+-- !query12_1after --
+4	2023-12-11	2	6.50	2	1	0.00
+5	2023-12-12	2	8.50	2	1	0.00
+5	2023-12-12	2	8.50	2	2	8.50
+
diff --git a/regression-test/data/nereids_rules_p0/mv/window/window_above_join.out b/regression-test/data/nereids_rules_p0/mv/window/window_above_join.out
new file mode 100644
index 00000000000..427fac89370
--- /dev/null
+++ b/regression-test/data/nereids_rules_p0/mv/window/window_above_join.out
@@ -0,0 +1,453 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !query1_0_before --
+4	2	1	0.00
+4	2	1	6.50
+4	2	1	6.50
+5	2	1	0.00
+5	2	2	8.50
+5	2	2	8.50
+5	2	2	8.50
+
+-- !query1_0_after --
+4	2	1	0.00
+4	2	1	6.50
+4	2	1	6.50
+5	2	1	0.00
+5	2	2	8.50
+5	2	2	8.50
+5	2	2	8.50
+
+-- !query1_1_before --
+
+-- !query1_1_after --
+
+-- !query2_0_before --
+3	1	1	0.00
+3	1	1	6.50
+3	1	1	6.50
+3	1	4	6.50
+4	2	1	0.00
+4	2	1	6.50
+4	2	1	6.50
+5	2	1	0.00
+5	2	2	8.50
+5	2	2	8.50
+5	2	2	8.50
+
+-- !query2_0_after --
+3	1	1	0.00
+3	1	1	6.50
+3	1	1	6.50
+3	1	4	6.50
+4	2	1	0.00
+4	2	1	6.50
+4	2	1	6.50
+5	2	1	0.00
+5	2	2	8.50
+5	2	2	8.50
+5	2	2	8.50
+
+-- !query2_1_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query2_1_after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query2_2_before --
+3	1	1	0.00	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	7	6.50	3
+3	1	7	6.50	3
+4	2	1	0.00	\N
+4	2	1	6.50	\N
+4	2	1	6.50	\N
+5	2	1	0.00	3
+5	2	1	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+
+-- !query2_2_after --
+3	1	1	0.00	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	7	6.50	3
+3	1	7	6.50	3
+4	2	1	0.00	\N
+4	2	1	6.50	\N
+4	2	1	6.50	\N
+5	2	1	0.00	3
+5	2	1	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+
+-- !query2_3_before --
+2	1	1	0.00	\N
+2	1	1	6.50	\N
+2	1	1	6.50	\N
+3	1	1	0.00	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	7	6.50	3
+3	1	7	6.50	3
+4	2	1	0.00	\N
+4	2	1	6.50	\N
+4	2	1	6.50	\N
+5	2	1	0.00	3
+5	2	1	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+
+-- !query2_3_after --
+2	1	1	0.00	\N
+2	1	1	6.50	\N
+2	1	1	6.50	\N
+3	1	1	0.00	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	1	6.50	3
+3	1	7	6.50	3
+3	1	7	6.50	3
+4	2	1	0.00	\N
+4	2	1	6.50	\N
+4	2	1	6.50	\N
+5	2	1	0.00	3
+5	2	1	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+5	2	3	8.50	3
+
+-- !query3_0_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query3_0_after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query3_1_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query3_1after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query4_0_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query4_0after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query5_0_before --
+
+-- !query5_0_after --
+
+-- !query5_1_before --
+
+-- !query5_1_after --
+
+-- !query6_0_before --
+3	1	1	0.00
+3	1	1	6.50
+3	1	1	6.50
+3	1	4	6.50
+4	2	1	0.00
+4	2	1	6.50
+4	2	1	6.50
+5	2	1	0.00
+5	2	2	8.50
+5	2	2	8.50
+5	2	2	8.50
+
+-- !query6_0_after --
+3	1	1	0.00
+3	1	1	6.50
+3	1	1	6.50
+3	1	4	6.50
+4	2	1	0.00
+4	2	1	6.50
+4	2	1	6.50
+5	2	1	0.00
+5	2	2	8.50
+5	2	2	8.50
+5	2	2	8.50
+
+-- !query6_1_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query6_1_after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query7_0_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query7_0_after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query7_1_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query7_1after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query7_2_before --
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query7_2after --
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query8_0_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query8_0after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query8_1_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query8_1after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query9_0_before --
+
+-- !query9_0_after --
+
+-- !query9_1_before --
+
+-- !query9_1_after --
+
+-- !query9_2_before --
+
+-- !query9_2_after --
+
+-- !query10_0_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query10_0_after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query10_1_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query10_1_after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query11_0_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query11_0_after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query11_1_before --
+
+-- !query11_1after --
+
+-- !query12_0_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query12_0after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query12_1_before --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
+-- !query12_1after --
+4	2023-12-11	2	1	0.00
+4	2023-12-11	2	1	6.50
+4	2023-12-11	2	1	6.50
+5	2023-12-12	2	1	0.00
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+5	2023-12-12	2	2	8.50
+
diff --git a/regression-test/data/nereids_rules_p0/mv/window/window_above_scan.out b/regression-test/data/nereids_rules_p0/mv/window/window_above_scan.out
new file mode 100644
index 00000000000..4747d542741
--- /dev/null
+++ b/regression-test/data/nereids_rules_p0/mv/window/window_above_scan.out
@@ -0,0 +1,349 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !query1_0_before --
+
+-- !query1_0_after --
+
+-- !query1_1_before --
+
+-- !query1_1_after --
+
+-- !query2_0_before --
+3	1	1
+3	1	1
+3	1	1
+3	1	4
+4	2	1
+4	2	1
+4	2	1
+5	2	1
+5	2	2
+5	2	2
+5	2	2
+
+-- !query2_0_after --
+3	1	1
+3	1	1
+3	1	1
+3	1	4
+4	2	1
+4	2	1
+4	2	1
+5	2	1
+5	2	2
+5	2	2
+5	2	2
+
+-- !query2_1_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query2_1_after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query3_0_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query3_0_after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query3_1_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query3_1after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query4_0_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query4_0after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query5_0_before --
+
+-- !query5_0_after --
+
+-- !query5_1_before --
+
+-- !query5_1_after --
+
+-- !query6_0_before --
+3	1	1
+3	1	1
+3	1	1
+3	1	4
+4	2	1
+4	2	1
+4	2	1
+5	2	1
+5	2	2
+5	2	2
+5	2	2
+
+-- !query6_0_after --
+3	1	1
+3	1	1
+3	1	1
+3	1	4
+4	2	1
+4	2	1
+4	2	1
+5	2	1
+5	2	2
+5	2	2
+5	2	2
+
+-- !query6_1_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query6_1_after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query7_0_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query7_0_after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query7_1_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query7_1after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query7_2_before --
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query7_2after --
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query8_0_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query8_0after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query8_1_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query8_1after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query9_0_before --
+
+-- !query9_0_after --
+
+-- !query9_1_before --
+
+-- !query9_1_after --
+
+-- !query9_2_before --
+
+-- !query9_2_after --
+
+-- !query10_0_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query10_0_after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query10_1_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query10_1_after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query11_0_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query11_0_after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query11_1_before --
+
+-- !query11_1after --
+
+-- !query12_0_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query12_0after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query12_1_before --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
+-- !query12_1after --
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+4	2023-12-11	2	1
+5	2023-12-12	2	1
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+5	2023-12-12	2	2
+
diff --git a/regression-test/suites/nereids_rules_p0/mv/join/null_aware_anti/null_aware_left_anti_join.groovy b/regression-test/suites/nereids_rules_p0/mv/join/null_aware_anti/null_aware_left_anti_join.groovy
index 108fc77c863..a019ccb365b 100644
--- a/regression-test/suites/nereids_rules_p0/mv/join/null_aware_anti/null_aware_left_anti_join.groovy
+++ b/regression-test/suites/nereids_rules_p0/mv/join/null_aware_anti/null_aware_left_anti_join.groovy
@@ -624,7 +624,7 @@ suite("null_aware_anti") {
             );
             """
     order_qt_query7_0_before "${query7_0}"
-    async_mv_rewrite_fail(db, mv7_0, query7_0, "mv7_0")
+    async_mv_rewrite_success(db, mv7_0, query7_0, "mv7_0")
     order_qt_query7_0_after "${query7_0}"
     sql """ DROP MATERIALIZED VIEW IF EXISTS mv7_0"""
 
@@ -661,7 +661,7 @@ suite("null_aware_anti") {
             );
             """
     order_qt_query7_1_before "${query7_1}"
-    async_mv_rewrite_fail(db, mv7_1, query7_1, "mv7_1")
+    async_mv_rewrite_success(db, mv7_1, query7_1, "mv7_1")
     order_qt_query7_1_after "${query7_1}"
     sql """ DROP MATERIALIZED VIEW IF EXISTS mv7_1"""
 
diff --git a/regression-test/suites/nereids_rules_p0/mv/pre_rewrite/limit/query_with_limit.groovy b/regression-test/suites/nereids_rules_p0/mv/pre_rewrite/limit/query_with_limit.groovy
index 22f31ae2957..f3db2c06aa9 100644
--- a/regression-test/suites/nereids_rules_p0/mv/pre_rewrite/limit/query_with_limit.groovy
+++ b/regression-test/suites/nereids_rules_p0/mv/pre_rewrite/limit/query_with_limit.groovy
@@ -960,7 +960,7 @@ suite("query_with_limit") {
                   orders on l_orderkey = o_orderkey
                 limit 2 offset 1;
             """
-    async_mv_rewrite_fail(db, mv3_1, query3_1, "mv3_1")
+    async_mv_rewrite_success(db, mv3_1, query3_1, "mv3_1")
     sql """ DROP MATERIALIZED VIEW IF EXISTS mv3_1"""
 
 
@@ -999,7 +999,7 @@ suite("query_with_limit") {
                 order by l_orderkey
                 limit 2 offset 1;
             """
-    async_mv_rewrite_fail(db, mv3_2, query3_2, "mv3_2")
+    async_mv_rewrite_success(db, mv3_2, query3_2, "mv3_2")
     sql """ DROP MATERIALIZED VIEW IF EXISTS mv3_2"""
 
     // query is union all + limit offset
diff --git a/regression-test/suites/nereids_rules_p0/mv/tpch/mv_tpch_test.groovy b/regression-test/suites/nereids_rules_p0/mv/tpch/mv_tpch_test.groovy
index eff733a2fec..ffb2bd5a6d9 100644
--- a/regression-test/suites/nereids_rules_p0/mv/tpch/mv_tpch_test.groovy
+++ b/regression-test/suites/nereids_rules_p0/mv/tpch/mv_tpch_test.groovy
@@ -228,7 +228,7 @@ suite("mv_tpch_test") {
     """
     // contains limit, doesn't support now
     order_qt_query2_before "${query2}"
-    async_mv_rewrite_fail(db, mv2, query2, "mv2")
+    async_mv_rewrite_success(db, mv2, query2, "mv2")
     order_qt_query2_after "${query2}"
     sql """ DROP MATERIALIZED VIEW IF EXISTS mv2"""
 
diff --git a/regression-test/suites/nereids_rules_p0/mv/window/window_above_aggregate.groovy b/regression-test/suites/nereids_rules_p0/mv/window/window_above_aggregate.groovy
new file mode 100644
index 00000000000..033a54c64c2
--- /dev/null
+++ b/regression-test/suites/nereids_rules_p0/mv/window/window_above_aggregate.groovy
@@ -0,0 +1,1821 @@
+package mv.window
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("window_above_aggregate") {
+    String db = context.config.getDbNameByFile(context.file)
+    sql "use ${db}"
+    sql "set runtime_filter_mode=OFF";
+    sql "SET ignore_shape_nodes='PhysicalDistribute,PhysicalProject'"
+    sql "set disable_nereids_rules='ELIMINATE_CONST_JOIN_CONDITION,CONSTANT_PROPAGATION'"
+
+    sql """
+    drop table if exists orders3
+    """
+
+    sql """
+    CREATE TABLE IF NOT EXISTS orders3  (
+      o_orderkey       INTEGER NOT NULL,
+      o_custkey        INTEGER NOT NULL,
+      o_orderstatus    CHAR(1) NOT NULL,
+      o_totalprice     DECIMALV3(15,2) NOT NULL,
+      o_orderdate      DATE NOT NULL,
+      o_orderpriority  CHAR(15) NOT NULL,  
+      o_clerk          CHAR(15) NOT NULL, 
+      o_shippriority   INTEGER NOT NULL,
+      O_COMMENT        VARCHAR(79) NOT NULL
+    )
+    DUPLICATE KEY(o_orderkey, o_custkey)
+    DISTRIBUTED BY HASH(o_orderkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    );
+    """
+
+    sql """
+    drop table if exists lineitem3
+    """
+
+    sql"""
+    CREATE TABLE IF NOT EXISTS lineitem3 (
+      l_orderkey    INTEGER NOT NULL,
+      l_partkey     INTEGER NOT NULL,
+      l_suppkey     INTEGER NOT NULL,
+      l_linenumber  INTEGER NOT NULL,
+      l_quantity    DECIMALV3(15,2) NOT NULL,
+      l_extendedprice  DECIMALV3(15,2) NOT NULL,
+      l_discount    DECIMALV3(15,2) NOT NULL,
+      l_tax         DECIMALV3(15,2) NOT NULL,
+      l_returnflag  CHAR(1) NOT NULL,
+      l_linestatus  CHAR(1) NOT NULL,
+      l_shipdate    DATE NOT NULL,
+      l_commitdate  DATE NOT NULL,
+      l_receiptdate DATE NOT NULL,
+      l_shipinstruct CHAR(25) NOT NULL,
+      l_shipmode     CHAR(10) NOT NULL,
+      l_comment      VARCHAR(44) NOT NULL
+    )
+    DUPLICATE KEY(l_orderkey, l_partkey, l_suppkey, l_linenumber)
+    DISTRIBUTED BY HASH(l_orderkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    )
+    """
+
+    sql """
+    drop table if exists partsupp3
+    """
+
+    sql """
+    CREATE TABLE IF NOT EXISTS partsupp3 (
+      ps_partkey     INTEGER NOT NULL,
+      ps_suppkey     INTEGER NOT NULL,
+      ps_availqty    INTEGER NOT NULL,
+      ps_supplycost  DECIMALV3(15,2)  NOT NULL,
+      ps_comment     VARCHAR(199) NOT NULL 
+    )
+    DUPLICATE KEY(ps_partkey, ps_suppkey)
+    DISTRIBUTED BY HASH(ps_partkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    )
+    """
+
+    sql """ insert into lineitem3 values
+    (1, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-08', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (2, 4, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-09', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (3, 2, 4, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-10', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (4, 3, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-11', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (5, 2, 3, 6, 7.5, 8.5, 9.5, 10.5, 'k', 'o', '2023-12-12', '2023-12-12', '2023-12-13', 'c', 'd', 'xxxxxxxxx');
+    """
+
+    sql """
+    insert into orders3 values
+    (1, 1, 'o', 9.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 33.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 1.2, '2023-12-12', 'c','d',2, 'mi');  
+    """
+
+    sql """
+    insert into partsupp3 values
+    (2, 3, 9, 10.01, 'supply1'),
+    (2, 3, 10, 11.01, 'supply2');
+    """
+
+    sql """analyze table partsupp3 with sync"""
+    sql """analyze table lineitem3 with sync"""
+    sql """analyze table orders3 with sync"""
+    sql """alter table lineitem3 modify column l_comment set stats ('row_count'='5');"""
+    sql """alter table orders3 modify column O_COMMENT set stats ('row_count'='18');"""
+    sql """alter table partsupp3 modify column ps_comment set stats ('row_count'='2');"""
+
+    // multi table or single table
+    // top filter(project) + window + middle filter(project) + aggregate + bottom filter(project) + scan
+    // query has only top filter, view has both top and middle filter
+    def mv1_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 3;
+            """
+    def query1_0 =
+            """
+            select * from (
+            select
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query1_0_before "${query1_0}"
+    async_mv_rewrite_fail(db, mv1_0, query1_0, "agg_mv1_0")
+    order_qt_query1_0_after "${query1_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv1_0"""
+
+
+    def mv1_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 7
+            """
+    def query1_1 =
+            """
+            select 
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 6;
+            """
+    order_qt_query1_1_before "${query1_1}"
+    async_mv_rewrite_fail(db, mv1_1, query1_1, "agg_mv1_1")
+    order_qt_query1_1_after "${query1_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv1_1"""
+
+
+    // query has only top filter, view has only top filter
+    def mv2_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 2;
+            """
+    order_qt_query2_0_before "${query2_0}"
+    async_mv_rewrite_success(db, mv2_0, query2_0, "agg_mv2_0")
+    order_qt_query2_0_after "${query2_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv2_0"""
+
+
+    def mv2_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query2_1_before "${query2_1}"
+    async_mv_rewrite_fail(db, mv2_1, query2_1, "agg_mv2_1")
+    order_qt_query2_1_after "${query2_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv2_1"""
+
+
+    def mv2_2 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value,
+            max_suppkey
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            left join (
+                select ps_partkey, 
+                ps_suppkey,
+                MAX(ps_suppkey) OVER (
+                    PARTITION BY ps_partkey 
+                    ORDER BY ps_supplycost NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS max_suppkey
+                from
+                partsupp3
+                where ps_suppkey > 1
+                group by ps_partkey, ps_suppkey, ps_supplycost
+            ) window_partsupp3 ON l_partkey = ps_partkey
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey, max_suppkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_2 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value,
+            max_suppkey
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            left join (
+                select ps_partkey, 
+                ps_suppkey,
+                MAX(ps_suppkey) OVER (
+                    PARTITION BY ps_partkey 
+                    ORDER BY ps_supplycost NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) as max_suppkey
+                from
+                partsupp3
+                where ps_suppkey > 1
+                group by ps_partkey, ps_suppkey, ps_supplycost
+            ) window_partsupp3 ON l_partkey = ps_partkey
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey, max_suppkey
+            ) t
+            where o_orderkey > 2;
+            """
+    order_qt_query2_2_before "${query2_2}"
+    async_mv_rewrite_success(db, mv2_2, query2_2, "agg_mv2_2")
+    order_qt_query2_2_after "${query2_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv2_2"""
+
+
+    def mv2_3 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value,
+            max_suppkey
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            left join (
+                select ps_partkey, 
+                ps_suppkey,
+                MAX(ps_suppkey) OVER (
+                    PARTITION BY ps_partkey 
+                    ORDER BY ps_supplycost NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS max_suppkey
+                from
+                partsupp3
+                where ps_suppkey > 1
+                group by ps_partkey, ps_suppkey, ps_supplycost
+            ) window_partsupp3 ON l_partkey = ps_partkey
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey, max_suppkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_3 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value,
+            max_suppkey
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            left join (
+                select *
+                from
+                (
+                select ps_partkey, 
+                ps_suppkey,
+                MAX(ps_suppkey) OVER (
+                    PARTITION BY ps_partkey 
+                    ORDER BY ps_supplycost NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS max_suppkey
+                from
+                partsupp3
+                group by ps_partkey, ps_suppkey, ps_supplycost
+                ) ps_sub
+                where ps_suppkey > 1
+            ) window_partsupp3 ON l_partkey = ps_partkey
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey, max_suppkey
+            ) t
+            where o_orderkey > 1;
+            """
+    order_qt_query2_3_before "${query2_3}"
+    // the filter ps_suppkey > 1 on the partsupp3 can not be pushed down, so fail
+    async_mv_rewrite_fail(db, mv2_3, query2_3, "agg_mv2_3")
+    order_qt_query2_3_after "${query2_3}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv2_3"""
+
+
+    // query has only top filter, view has only middle filter
+    def mv3_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-09'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query3_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query3_0_before "${query3_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_success(db, mv3_0, query3_0, "agg_mv3_0")
+    order_qt_query3_0_after "${query3_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv3_0"""
+
+
+    def mv3_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query3_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query3_1_before "${query3_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_fail(db, mv3_1, query3_1, "agg_mv3_1")
+    order_qt_query3_1after "${query3_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv3_1"""
+
+
+    // query has only top filter, view has no filter
+    def mv4_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query4_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query4_0_before "${query4_0}"
+    async_mv_rewrite_success(db, mv4_0, query4_0, "agg_mv4_0")
+    order_qt_query4_0after "${query4_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv4_0"""
+
+
+    def mv4_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query4_1 =
+            """
+            select 
+            MAX(l_extendedprice) as max_extendedprice,
+            o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey,
+            first_value, rank_value, lag_value
+            from
+            (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey,
+            first_value, rank_value, lag_value;
+            """
+    order_qt_query4_1_before "${query4_1}"
+    // because aggregate and window order is different
+    async_mv_rewrite_fail(db, mv4_1, query4_1, "agg_mv4_1")
+    order_qt_query4_1after "${query4_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv4_1"""
+
+
+    // query has only middle filter, view has both top and middle filter
+    def mv5_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 6
+            """
+    def query5_0 =
+            """
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query5_0_before "${query5_0}"
+    async_mv_rewrite_fail(db, mv5_0, query5_0, "agg_mv5_0")
+    order_qt_query5_0_after "${query5_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv5_0"""
+
+
+    def mv5_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 7
+            """
+    def query5_1 =
+            """
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query5_1_before "${query5_1}"
+    async_mv_rewrite_fail(db, mv5_1, query5_1, "agg_mv5_1")
+    order_qt_query5_1_after "${query5_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv5_1"""
+
+    // query has only middle filter, view has only top filter
+    def mv6_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query6_0 =
+            """
+            select 
+            o_orderkey,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 2
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query6_0_before "${query6_0}"
+    async_mv_rewrite_fail(db, mv6_0, query6_0, "agg_mv6_0")
+    order_qt_query6_0_after "${query6_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv6_0"""
+
+
+    def mv6_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query6_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query6_1_before "${query6_1}"
+    async_mv_rewrite_fail(db, mv6_1, query6_1, "agg_mv6_1")
+    order_qt_query6_1_after "${query6_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv6_1"""
+
+    // query has only middle filter, view has only middle filter
+    def mv7_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-09'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query7_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query7_0_before "${query7_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_success(db, mv7_0, query7_0, "agg_mv7_0")
+    order_qt_query7_0_after "${query3_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv7_0"""
+
+    def mv7_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query7_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query7_1_before "${query7_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_success(db, mv7_1, query7_1, "agg_mv7_1")
+    order_qt_query7_1after "${query7_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv7_1"""
+
+
+    def mv7_2 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query7_2 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 4
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query7_2_before "${query7_2}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_fail(db, mv7_2, query7_2, "agg_mv7_2")
+    order_qt_query7_2after "${query7_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv7_2"""
+
+    // query has only middle filter, view has no filter
+    def mv8_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query8_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query8_0_before "${query8_0}"
+    async_mv_rewrite_fail(db, mv8_0, query8_0, "agg_mv8_0")
+    order_qt_query8_0after "${query8_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv8_0"""
+
+
+    def mv8_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query8_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    order_qt_query8_1_before "${query8_1}"
+    async_mv_rewrite_success(db, mv8_1, query8_1, "agg_mv8_1")
+    order_qt_query8_1after "${query8_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv8_1"""
+
+
+    // query has both top and middle filter, view has both top and middle filter
+    def mv9_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 6
+            """
+    order_qt_query9_0_before "${query9_0}"
+    // cbo should chose mv9_0 but not
+    async_mv_rewrite_success_without_check_chosen(db, mv9_0, query9_0, "agg_mv9_0")
+    order_qt_query9_0_after "${query9_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv9_0"""
+
+
+    def mv9_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 7
+            """
+    order_qt_query9_1_before "${query9_1}"
+    // cbo should chose mv9_0 but not
+    async_mv_rewrite_success_without_check_chosen(db, mv9_1, query9_1, "agg_mv9_1")
+    order_qt_query9_1_after "${query9_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv9_1"""
+
+
+    def mv9_2 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_2 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 7
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 6
+            """
+    order_qt_query9_2_before "${query9_2}"
+    async_mv_rewrite_fail(db, mv9_2, query9_2, "agg_mv9_2")
+    order_qt_query9_2_after "${query9_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv9_2"""
+
+    // query has both top and middle filter, view has only top filter
+    def mv10_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query10_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 2;
+            """
+    order_qt_query10_0_before "${query10_0}"
+    async_mv_rewrite_success(db, mv10_0, query10_0, "agg_mv10_0")
+    order_qt_query10_0_after "${query10_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv10_0"""
+
+
+    def mv10_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query10_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 1
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query10_1_before "${query10_1}"
+    async_mv_rewrite_fail(db, mv10_1, query10_1, "agg_mv10_1")
+    order_qt_query10_1_after "${query10_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv10_1"""
+
+
+    // query has both top and middle filter, view has only middle filter
+    def mv11_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-09'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query11_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 1
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query11_0_before "${query11_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_fail(db, mv11_0, query11_0, "agg_mv11_0")
+    order_qt_query11_0_after "${query11_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv11_0"""
+
+
+    def mv11_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query11_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 7;
+            """
+    order_qt_query11_1_before "${query11_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_success(db, mv11_1, query11_1, "agg_mv11_1")
+    order_qt_query11_1after "${query11_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv11_1"""
+
+    // query has both top and middle filter, view has no filter
+    def mv12_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query12_0 =
+            """
+            select
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query12_0_before "${query12_0}"
+    async_mv_rewrite_success(db, mv12_0, query12_0, "agg_mv12_0")
+    order_qt_query12_0after "${query12_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv12_0"""
+
+
+    def mv12_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey;
+            """
+    def query12_1 =
+            """
+            select
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            o_orderdate,
+            o_custkey,
+            MAX(l_extendedprice) as max_extendedprice,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem3
+            left join orders3 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            group by o_orderdate, o_custkey, o_totalprice, o_orderstatus, l_extendedprice, l_shipdate, l_quantity, o_orderkey
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query12_1_before "${query12_1}"
+    async_mv_rewrite_fail(db, mv12_1, query12_1, "agg_mv12_1")
+    order_qt_query12_1after "${query12_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS agg_mv12_1"""
+}
diff --git a/regression-test/suites/nereids_rules_p0/mv/window/window_above_join.groovy b/regression-test/suites/nereids_rules_p0/mv/window/window_above_join.groovy
new file mode 100644
index 00000000000..98326a43b03
--- /dev/null
+++ b/regression-test/suites/nereids_rules_p0/mv/window/window_above_join.groovy
@@ -0,0 +1,1591 @@
+package mv.window
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("window_above_join") {
+    String db = context.config.getDbNameByFile(context.file)
+    sql "use ${db}"
+    sql "set runtime_filter_mode=OFF";
+    sql "SET ignore_shape_nodes='PhysicalDistribute,PhysicalProject'"
+    sql "set disable_nereids_rules='ELIMINATE_CONST_JOIN_CONDITION,CONSTANT_PROPAGATION'"
+
+    sql """
+    drop table if exists orders2
+    """
+
+    sql """
+    CREATE TABLE IF NOT EXISTS orders2  (
+      o_orderkey       INTEGER NOT NULL,
+      o_custkey        INTEGER NOT NULL,
+      o_orderstatus    CHAR(1) NOT NULL,
+      o_totalprice     DECIMALV3(15,2) NOT NULL,
+      o_orderdate      DATE NOT NULL,
+      o_orderpriority  CHAR(15) NOT NULL,  
+      o_clerk          CHAR(15) NOT NULL, 
+      o_shippriority   INTEGER NOT NULL,
+      O_COMMENT        VARCHAR(79) NOT NULL
+    )
+    DUPLICATE KEY(o_orderkey, o_custkey)
+    DISTRIBUTED BY HASH(o_orderkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    );
+    """
+
+    sql """
+    drop table if exists lineitem2
+    """
+
+    sql"""
+    CREATE TABLE IF NOT EXISTS lineitem2 (
+      l_orderkey    INTEGER NOT NULL,
+      l_partkey     INTEGER NOT NULL,
+      l_suppkey     INTEGER NOT NULL,
+      l_linenumber  INTEGER NOT NULL,
+      l_quantity    DECIMALV3(15,2) NOT NULL,
+      l_extendedprice  DECIMALV3(15,2) NOT NULL,
+      l_discount    DECIMALV3(15,2) NOT NULL,
+      l_tax         DECIMALV3(15,2) NOT NULL,
+      l_returnflag  CHAR(1) NOT NULL,
+      l_linestatus  CHAR(1) NOT NULL,
+      l_shipdate    DATE NOT NULL,
+      l_commitdate  DATE NOT NULL,
+      l_receiptdate DATE NOT NULL,
+      l_shipinstruct CHAR(25) NOT NULL,
+      l_shipmode     CHAR(10) NOT NULL,
+      l_comment      VARCHAR(44) NOT NULL
+    )
+    DUPLICATE KEY(l_orderkey, l_partkey, l_suppkey, l_linenumber)
+    DISTRIBUTED BY HASH(l_orderkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    )
+    """
+
+    sql """
+    drop table if exists partsupp2
+    """
+
+    sql """
+    CREATE TABLE IF NOT EXISTS partsupp2 (
+      ps_partkey     INTEGER NOT NULL,
+      ps_suppkey     INTEGER NOT NULL,
+      ps_availqty    INTEGER NOT NULL,
+      ps_supplycost  DECIMALV3(15,2)  NOT NULL,
+      ps_comment     VARCHAR(199) NOT NULL 
+    )
+    DUPLICATE KEY(ps_partkey, ps_suppkey)
+    DISTRIBUTED BY HASH(ps_partkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    )
+    """
+
+    sql """ insert into lineitem2 values
+    (1, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-08', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (2, 4, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-09', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (3, 2, 4, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-10', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (4, 3, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-11', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (5, 2, 3, 6, 7.5, 8.5, 9.5, 10.5, 'k', 'o', '2023-12-12', '2023-12-12', '2023-12-13', 'c', 'd', 'xxxxxxxxx');
+    """
+
+    sql """
+    insert into orders2 values
+    (1, 1, 'o', 9.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 33.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 1.2, '2023-12-12', 'c','d',2, 'mi');  
+    """
+
+    sql """
+    insert into partsupp2 values
+    (2, 3, 9, 10.01, 'supply1'),
+    (2, 3, 10, 11.01, 'supply2');
+    """
+
+    sql """analyze table partsupp2 with sync"""
+    sql """analyze table lineitem2 with sync"""
+    sql """analyze table orders2 with sync"""
+    sql """alter table lineitem2 modify column l_comment set stats ('row_count'='5');"""
+    sql """alter table orders2 modify column O_COMMENT set stats ('row_count'='18');"""
+    sql """alter table partsupp2 modify column ps_comment set stats ('row_count'='2');"""
+
+
+    // top filter(project) + window + bottom filter(project) + join
+    // query has only top filter, view has both top and bottom filter
+    def mv1_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 3;
+            """
+    def query1_0 =
+            """
+            select * from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query1_0_before "${query1_0}"
+    async_mv_rewrite_fail(db, mv1_0, query1_0, "join_mv1_0")
+    order_qt_query1_0_after "${query1_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv1_0"""
+
+
+    def mv1_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6
+            ) t
+            where o_orderkey > 7
+            """
+    def query1_1 =
+            """
+            select 
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 6;
+            """
+    order_qt_query1_1_before "${query1_1}"
+    async_mv_rewrite_fail(db, mv1_1, query1_1, "join_mv1_1")
+    order_qt_query1_1_after "${query1_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv1_1"""
+
+
+    // query has only top filter, view has only top filter
+    def mv2_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 2;
+            """
+    order_qt_query2_0_before "${query2_0}"
+    async_mv_rewrite_success(db, mv2_0, query2_0, "join_mv2_0")
+    order_qt_query2_0_after "${query2_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv2_0"""
+
+
+    def mv2_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query2_1_before "${query2_1}"
+    async_mv_rewrite_fail(db, mv2_1, query2_1, "join_mv2_1")
+    order_qt_query2_1_after "${query2_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv2_1"""
+
+
+    def mv2_2 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value,
+            max_suppkey
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            left join (
+                select ps_partkey, 
+                ps_suppkey,
+                MAX(ps_suppkey) OVER (
+                    PARTITION BY ps_partkey 
+                    ORDER BY ps_supplycost NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS max_suppkey
+                from
+                partsupp2
+                where ps_suppkey > 1
+            ) window_partsupp2 ON l_partkey = ps_partkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_2 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value,
+            max_suppkey
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            left join (
+                select ps_partkey, 
+                ps_suppkey,
+                MAX(ps_suppkey) OVER (
+                    PARTITION BY ps_partkey 
+                    ORDER BY ps_supplycost NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS max_suppkey
+                from
+                partsupp2
+                where ps_suppkey > 1
+            ) window_partsupp2 ON l_partkey = ps_partkey
+            ) t
+            where o_orderkey > 2;
+            """
+    order_qt_query2_2_before "${query2_2}"
+    async_mv_rewrite_success(db, mv2_2, query2_2, "join_mv2_2")
+    order_qt_query2_2_after "${query2_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv2_2"""
+
+
+    def mv2_3 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value,
+            max_suppkey
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            left join (
+                select ps_partkey, 
+                ps_suppkey,
+                MAX(ps_suppkey) OVER (
+                    PARTITION BY ps_partkey 
+                    ORDER BY ps_supplycost NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS max_suppkey
+                from
+                partsupp2
+                where ps_suppkey > 1
+            ) window_partsupp2 ON l_partkey = ps_partkey
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_3 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value,
+            max_suppkey
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            left join (
+                select *
+                from
+                (
+                select ps_partkey, 
+                ps_suppkey,
+                MAX(ps_suppkey) OVER (
+                    PARTITION BY ps_partkey 
+                    ORDER BY ps_supplycost NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS max_suppkey
+                from
+                partsupp2
+                ) ps_sub
+                where ps_suppkey > 1
+            ) window_partsupp2 ON l_partkey = ps_partkey
+            ) t
+            where o_orderkey > 1;
+            """
+    order_qt_query2_3_before "${query2_3}"
+    // the filter ps_suppkey > 1 on the partsupp2 can not be pushed down, so fail
+    async_mv_rewrite_fail(db, mv2_3, query2_3, "join_mv2_3")
+    order_qt_query2_3_after "${query2_3}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv2_3"""
+
+
+    // query has only top filter, view has only bottom filter
+    def mv3_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-09';
+            """
+    def query3_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query3_0_before "${query3_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_success(db, mv3_0, query3_0, "join_mv3_0")
+    order_qt_query3_0_after "${query3_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv3_0"""
+
+
+    def mv3_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3;
+            """
+    def query3_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query3_1_before "${query3_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_fail(db, mv3_1, query3_1, "join_mv3_1")
+    order_qt_query3_1after "${query3_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv3_1"""
+
+
+    // query has only top filter, view has no filter
+    def mv4_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate;
+            """
+    def query4_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query4_0_before "${query4_0}"
+    async_mv_rewrite_success(db, mv4_0, query4_0, "join_mv4_0")
+    order_qt_query4_0after "${query4_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv4_0"""
+
+
+    // query has only bottom filter, view has both top and bottom filter
+    def mv5_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    def query5_0 =
+            """
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6;
+            """
+    order_qt_query5_0_before "${query5_0}"
+    async_mv_rewrite_fail(db, mv5_0, query5_0, "join_mv5_0")
+    order_qt_query5_0_after "${query5_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv5_0"""
+
+
+    def mv5_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6
+            ) t
+            where o_orderkey > 7
+            """
+    def query5_1 =
+            """
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6;
+            """
+    order_qt_query5_1_before "${query5_1}"
+    async_mv_rewrite_fail(db, mv5_1, query5_1, "join_mv5_1")
+    order_qt_query5_1_after "${query5_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv5_1"""
+
+    // query has only bottom filter, view has only top filter
+    def mv6_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 1;
+            """
+    def query6_0 =
+            """
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 2;
+            """
+    order_qt_query6_0_before "${query6_0}"
+    async_mv_rewrite_fail(db, mv6_0, query6_0, "join_mv6_0")
+    order_qt_query6_0_after "${query6_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv6_0"""
+
+
+    def mv6_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 1;
+            """
+    def query6_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query6_1_before "${query6_1}"
+    async_mv_rewrite_fail(db, mv6_1, query6_1, "join_mv6_1")
+    order_qt_query6_1_after "${query6_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv6_1"""
+
+    // query has only bottom filter, view has only bottom filter
+    def mv7_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-09';
+            """
+    def query7_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query7_0_before "${query7_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_success(db, mv7_0, query7_0, "join_mv7_0")
+    order_qt_query7_0_after "${query3_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv7_0"""
+
+    def mv7_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3;
+            """
+    def query7_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3;
+            """
+    order_qt_query7_1_before "${query7_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_success(db, mv7_1, query7_1, "join_mv7_1")
+    order_qt_query7_1after "${query7_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv7_1"""
+
+
+    def mv7_2 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3;
+            """
+    def query7_2 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 4;
+            """
+    order_qt_query7_2_before "${query7_2}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_fail(db, mv7_2, query7_2, "join_mv7_2")
+    order_qt_query7_2after "${query7_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv7_2"""
+
+    // query has only bottom filter, view has no filter
+    def mv8_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate;
+            """
+    def query8_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3;
+            """
+    order_qt_query8_0_before "${query8_0}"
+    async_mv_rewrite_fail(db, mv8_0, query8_0, "join_mv8_0")
+    order_qt_query8_0after "${query8_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv8_0"""
+
+
+    def mv8_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate;
+            """
+    def query8_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query8_1_before "${query8_1}"
+    async_mv_rewrite_success(db, mv8_1, query8_1, "join_mv8_1")
+    order_qt_query8_1after "${query8_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv8_1"""
+
+
+    // query has both top and bottom filter, view has both top and bottom filter
+    def mv9_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    order_qt_query9_0_before "${query9_0}"
+    async_mv_rewrite_success_without_check_chosen(db, mv9_0, query9_0, "join_mv9_0")
+    order_qt_query9_0_after "${query9_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv9_0"""
+
+
+    def mv9_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_1 =
+            """
+                        select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 7
+            """
+    order_qt_query9_1_before "${query9_1}"
+    async_mv_rewrite_success_without_check_chosen(db, mv9_1, query9_1, "join_mv9_1")
+    order_qt_query9_1_after "${query9_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv9_1"""
+
+
+    def mv9_2 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 6
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_2 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 7
+            ) t
+            where o_orderkey > 6
+            """
+    order_qt_query9_2_before "${query9_2}"
+    async_mv_rewrite_fail(db, mv9_2, query9_2, "join_mv9_2")
+    order_qt_query9_2_after "${query9_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv9_2"""
+
+
+    // query has both top and bottom filter, view has only top filter
+    def mv10_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 1;
+            """
+    def query10_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 2;
+            """
+    order_qt_query10_0_before "${query10_0}"
+    async_mv_rewrite_success(db, mv10_0, query10_0, "join_mv10_0")
+    order_qt_query10_0_after "${query10_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv10_0"""
+
+
+    def mv10_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            ) t
+            where o_orderkey > 1;
+            """
+    def query10_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 1
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query10_1_before "${query10_1}"
+    async_mv_rewrite_fail(db, mv10_1, query10_1, "join_mv10_1")
+    order_qt_query10_1_after "${query10_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv10_1"""
+
+
+    // query has both top and bottom filter, view has only bottom filter
+    def mv11_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-09';
+            """
+    def query11_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 1
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query11_0_before "${query11_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_fail(db, mv11_0, query11_0, "join_mv11_0")
+    order_qt_query11_0_after "${query11_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv11_0"""
+
+
+    def mv11_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3;
+            """
+    def query11_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            ) t
+            where o_orderkey > 7;
+            """
+    order_qt_query11_1_before "${query11_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_success(db, mv11_1, query11_1, "join_mv11_1")
+    order_qt_query11_1after "${query11_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv11_1"""
+
+    // query has both top and bottom filter, view has no filter
+    def mv12_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate;
+            """
+    def query12_0 =
+            """
+            select
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query12_0_before "${query12_0}"
+    async_mv_rewrite_success(db, mv12_0, query12_0, "join_mv12_0")
+    order_qt_query12_0after "${query12_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv12_0"""
+
+
+    def mv12_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate;
+            """
+    def query12_1 =
+            """
+            select
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value,
+            LAG(l_extendedprice, 1, 0) over (partition by o_orderdate, l_shipdate order by l_quantity) AS lag_value 
+            from 
+            lineitem2
+            left join orders2 on l_orderkey = o_orderkey and l_shipdate = o_orderdate
+            where o_orderkey > 3
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query12_1_before "${query12_1}"
+    async_mv_rewrite_fail(db, mv12_1, query12_1, "join_mv12_1")
+    order_qt_query12_1after "${query12_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS join_mv12_1"""
+}
diff --git a/regression-test/suites/nereids_rules_p0/mv/window/window_above_scan.groovy b/regression-test/suites/nereids_rules_p0/mv/window/window_above_scan.groovy
new file mode 100644
index 00000000000..de1c9225a3e
--- /dev/null
+++ b/regression-test/suites/nereids_rules_p0/mv/window/window_above_scan.groovy
@@ -0,0 +1,1329 @@
+package mv.window
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("window_above_scan") {
+    String db = context.config.getDbNameByFile(context.file)
+    sql "use ${db}"
+    sql "set runtime_filter_mode=OFF";
+    sql "SET ignore_shape_nodes='PhysicalDistribute,PhysicalProject'"
+    sql "set disable_nereids_rules='ELIMINATE_CONST_JOIN_CONDITION,CONSTANT_PROPAGATION'"
+
+    sql """
+    drop table if exists orders1
+    """
+
+    sql """
+    CREATE TABLE IF NOT EXISTS orders1  (
+      o_orderkey       INTEGER NOT NULL,
+      o_custkey        INTEGER NOT NULL,
+      o_orderstatus    CHAR(1) NOT NULL,
+      o_totalprice     DECIMALV3(15,2) NOT NULL,
+      o_orderdate      DATE NOT NULL,
+      o_orderpriority  CHAR(15) NOT NULL,  
+      o_clerk          CHAR(15) NOT NULL, 
+      o_shippriority   INTEGER NOT NULL,
+      O_COMMENT        VARCHAR(79) NOT NULL
+    )
+    DUPLICATE KEY(o_orderkey, o_custkey)
+    DISTRIBUTED BY HASH(o_orderkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    );
+    """
+
+    sql """
+    drop table if exists lineitem1
+    """
+
+    sql"""
+    CREATE TABLE IF NOT EXISTS lineitem1 (
+      l_orderkey    INTEGER NOT NULL,
+      l_partkey     INTEGER NOT NULL,
+      l_suppkey     INTEGER NOT NULL,
+      l_linenumber  INTEGER NOT NULL,
+      l_quantity    DECIMALV3(15,2) NOT NULL,
+      l_extendedprice  DECIMALV3(15,2) NOT NULL,
+      l_discount    DECIMALV3(15,2) NOT NULL,
+      l_tax         DECIMALV3(15,2) NOT NULL,
+      l_returnflag  CHAR(1) NOT NULL,
+      l_linestatus  CHAR(1) NOT NULL,
+      l_shipdate    DATE NOT NULL,
+      l_commitdate  DATE NOT NULL,
+      l_receiptdate DATE NOT NULL,
+      l_shipinstruct CHAR(25) NOT NULL,
+      l_shipmode     CHAR(10) NOT NULL,
+      l_comment      VARCHAR(44) NOT NULL
+    )
+    DUPLICATE KEY(l_orderkey, l_partkey, l_suppkey, l_linenumber)
+    DISTRIBUTED BY HASH(l_orderkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    )
+    """
+
+    sql """
+    drop table if exists partsupp1
+    """
+
+    sql """
+    CREATE TABLE IF NOT EXISTS partsupp1 (
+      ps_partkey     INTEGER NOT NULL,
+      ps_suppkey     INTEGER NOT NULL,
+      ps_availqty    INTEGER NOT NULL,
+      ps_supplycost  DECIMALV3(15,2)  NOT NULL,
+      ps_comment     VARCHAR(199) NOT NULL 
+    )
+    DUPLICATE KEY(ps_partkey, ps_suppkey)
+    DISTRIBUTED BY HASH(ps_partkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    )
+    """
+
+    sql """ insert into lineitem1 values
+    (1, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-08', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (2, 4, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-09', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (3, 2, 4, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-10', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (4, 3, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-11', '2023-12-09', '2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (5, 2, 3, 6, 7.5, 8.5, 9.5, 10.5, 'k', 'o', '2023-12-12', '2023-12-12', '2023-12-13', 'c', 'd', 'xxxxxxxxx');
+    """
+
+    sql """
+    insert into orders1 values
+    (1, 1, 'o', 9.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 33.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 1.2, '2023-12-12', 'c','d',2, 'mi');  
+    """
+
+    sql """
+    insert into partsupp1 values
+    (2, 3, 9, 10.01, 'supply1'),
+    (2, 3, 10, 11.01, 'supply2');
+    """
+
+    sql """analyze table partsupp1 with sync"""
+    sql """analyze table lineitem1 with sync"""
+    sql """analyze table orders1 with sync"""
+    sql """alter table lineitem1 modify column l_comment set stats ('row_count'='5');"""
+    sql """alter table orders1 modify column O_COMMENT set stats ('row_count'='18');"""
+    sql """alter table partsupp1 modify column ps_comment set stats ('row_count'='2');"""
+
+    // top filter(project) + window + bottom filter(project) + scan
+    // query has only top filter, view has both top and bottom filter
+    def mv1_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    def query1_0 =
+            """
+            select * from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 6;
+            """
+    order_qt_query1_0_before "${query1_0}"
+    async_mv_rewrite_fail(db, mv1_0, query1_0, "mv1_0")
+    order_qt_query1_0_after "${query1_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv1_0"""
+
+
+    def mv1_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 6
+            ) t
+            where o_orderkey > 7
+            """
+    def query1_1 =
+            """
+            select 
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 6;
+            """
+    order_qt_query1_1_before "${query1_1}"
+    async_mv_rewrite_fail(db, mv1_1, query1_1, "mv1_1")
+    order_qt_query1_1_after "${query1_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv1_1"""
+
+
+    // query has only top filter, view has only top filter
+    def mv2_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 2;
+            """
+    order_qt_query2_0_before "${query2_0}"
+    async_mv_rewrite_success(db, mv2_0, query2_0, "mv2_0")
+    order_qt_query2_0_after "${query2_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv2_0"""
+
+
+    def mv2_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 1;
+            """
+    def query2_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query2_1_before "${query2_1}"
+    async_mv_rewrite_fail(db, mv2_1, query2_1, "mv2_1")
+    order_qt_query2_1_after "${query2_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv2_1"""
+
+    // query has only top filter, view has only bottom filter
+    def mv3_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-09';
+            """
+    def query3_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query3_0_before "${query3_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_success(db, mv3_0, query3_0, "mv3_0")
+    order_qt_query3_0_after "${query3_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv3_0"""
+
+
+    def mv3_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 3;
+            """
+    def query3_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query3_1_before "${query3_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_fail(db, mv3_1, query3_1, "mv3_1")
+    order_qt_query3_1after "${query3_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv3_1"""
+
+
+    // query has only top filter, view has no filter
+    def mv4_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1;
+            """
+    def query4_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query4_0_before "${query4_0}"
+    async_mv_rewrite_success(db, mv4_0, query4_0, "mv4_0")
+    order_qt_query4_0after "${query4_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv4_0"""
+
+
+    // query has only bottom filter, view has both top and bottom filter
+    def mv5_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    def query5_0 =
+            """
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 6;
+            """
+    order_qt_query5_0_before "${query5_0}"
+    async_mv_rewrite_fail(db, mv5_0, query5_0, "mv5_0")
+    order_qt_query5_0_after "${query5_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv5_0"""
+
+
+    def mv5_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 6
+            ) t
+            where o_orderkey > 7
+            """
+    def query5_1 =
+            """
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 6;
+            """
+    order_qt_query5_1_before "${query5_1}"
+    async_mv_rewrite_fail(db, mv5_1, query5_1, "mv5_1")
+    order_qt_query5_1_after "${query5_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv5_1"""
+
+    // query has only bottom filter, view has only top filter
+    def mv6_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 1;
+            """
+    def query6_0 =
+            """
+            select 
+            o_orderkey,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 2;
+            """
+    order_qt_query6_0_before "${query6_0}"
+    async_mv_rewrite_fail(db, mv6_0, query6_0, "mv6_0")
+    order_qt_query6_0_after "${query6_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv6_0"""
+
+
+    def mv6_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 1;
+            """
+    def query6_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query6_1_before "${query6_1}"
+    async_mv_rewrite_fail(db, mv6_1, query6_1, "mv6_1")
+    order_qt_query6_1_after "${query6_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv6_1"""
+
+    // query has only bottom filter, view has only bottom filter
+    def mv7_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-09';
+            """
+    def query7_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query7_0_before "${query7_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_success(db, mv7_0, query7_0, "mv7_0")
+    order_qt_query7_0_after "${query3_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv7_0"""
+
+    def mv7_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 3;
+            """
+    def query7_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 3;
+            """
+    order_qt_query7_1_before "${query7_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_success(db, mv7_1, query7_1, "mv7_1")
+    order_qt_query7_1after "${query7_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv7_1"""
+
+
+    def mv7_2 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 3;
+            """
+    def query7_2 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 4;
+            """
+    order_qt_query7_2_before "${query7_2}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_fail(db, mv7_2, query7_2, "mv7_2")
+    order_qt_query7_2after "${query7_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv7_2"""
+
+    // query has only bottom filter, view has no filter
+    def mv8_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1;
+            """
+    def query8_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 3;
+            """
+    order_qt_query8_0_before "${query8_0}"
+    async_mv_rewrite_fail(db, mv8_0, query8_0, "mv8_0")
+    order_qt_query8_0after "${query8_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv8_0"""
+
+
+    def mv8_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1;
+            """
+    def query8_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query8_1_before "${query8_1}"
+    async_mv_rewrite_success(db, mv8_1, query8_1, "mv8_1")
+    order_qt_query8_1after "${query8_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv8_1"""
+
+
+    // query has both top and bottom filter, view has both top and bottom filter
+    def mv9_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_0 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    order_qt_query9_0_before "${query9_0}"
+    async_mv_rewrite_success_without_check_chosen(db, mv9_0, query9_0, "mv9_0")
+    order_qt_query9_0_after "${query9_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv9_0"""
+
+
+    def mv9_1 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_1 =
+            """
+                        select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 7
+            """
+    order_qt_query9_1_before "${query9_1}"
+    async_mv_rewrite_success_without_check_chosen(db, mv9_1, query9_1, "mv9_1")
+    order_qt_query9_1_after "${query9_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv9_1"""
+
+
+    def mv9_2 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 6
+            ) t
+            where o_orderkey > 6
+            """
+    def query9_2 =
+            """
+            select * from (
+            select 
+            o_orderkey, o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 7
+            ) t
+            where o_orderkey > 6
+            """
+    order_qt_query9_2_before "${query9_2}"
+    async_mv_rewrite_fail(db, mv9_2, query9_2, "mv9_2")
+    order_qt_query9_2_after "${query9_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv9_2"""
+
+
+    // query has both top and bottom filter, view has only top filter
+    def mv10_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 1;
+            """
+    def query10_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 2;
+            """
+    order_qt_query10_0_before "${query10_0}"
+    async_mv_rewrite_success(db, mv10_0, query10_0, "mv10_0")
+    order_qt_query10_0_after "${query10_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv10_0"""
+
+
+    def mv10_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            ) t
+            where o_orderkey > 1;
+            """
+    def query10_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 1
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query10_1_before "${query10_1}"
+    async_mv_rewrite_fail(db, mv10_1, query10_1, "mv10_1")
+    order_qt_query10_1_after "${query10_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv10_1"""
+
+
+    // query has both top and bottom filter, view has only bottom filter
+    def mv11_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-09';
+            """
+    def query11_0 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 1
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query11_0_before "${query11_0}"
+    // filter can be pushed down, should success
+    async_mv_rewrite_fail(db, mv11_0, query11_0, "mv11_0")
+    order_qt_query11_0_after "${query11_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv11_0"""
+
+
+    def mv11_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 3;
+            """
+    def query11_1 =
+            """
+            select *
+            from (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 3
+            ) t
+            where o_orderkey > 7;
+            """
+    order_qt_query11_1_before "${query11_1}"
+    // filter can not be pushed down, should success
+    async_mv_rewrite_success(db, mv11_1, query11_1, "mv11_1")
+    order_qt_query11_1after "${query11_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv11_1"""
+
+    // query has both top and bottom filter, view has no filter
+    def mv12_0 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1;
+            """
+    def query12_0 =
+            """
+            select
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderdate > '2023-12-10'
+            ) t
+            where o_orderkey > 3;
+            """
+    order_qt_query12_0_before "${query12_0}"
+    async_mv_rewrite_success(db, mv12_0, query12_0, "mv12_0")
+    order_qt_query12_0after "${query12_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv12_0"""
+
+
+    def mv12_1 =
+            """
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1;
+            """
+    def query12_1 =
+            """
+            select
+            *
+            from
+            (
+            select 
+            o_orderkey,
+            o_orderdate,
+            FIRST_VALUE(o_custkey) OVER (
+                    PARTITION BY o_orderdate 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS first_value,
+            RANK() OVER (
+                    PARTITION BY o_orderdate, o_orderstatus 
+                    ORDER BY o_totalprice NULLS LAST
+                    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+                ) AS rank_value
+            from 
+            orders1
+            where o_orderkey > 3
+            ) t
+            where o_orderdate > '2023-12-10';
+            """
+    order_qt_query12_1_before "${query12_1}"
+    async_mv_rewrite_fail(db, mv12_1, query12_1, "mv12_1")
+    order_qt_query12_1after "${query12_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv12_1"""
+
+}


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