morrySnow commented on code in PR #14397:
URL: https://github.com/apache/doris/pull/14397#discussion_r1100123071


##########
fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4:
##########
@@ -332,6 +337,33 @@ functionIdentifier
     | LEFT | RIGHT
     ;
 
+windowSpec
+    // todo: name for windowRef; we haven't support it
+    : name=identifier
+    | LEFT_PAREN name=identifier RIGHT_PAREN

Review Comment:
   remove it, and add it back when we want to support it?



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java:
##########
@@ -161,7 +160,8 @@ public Plan plan(LogicalPlan plan, PhysicalProperties 
requireProperties, Explain
                     return analyzedPlan;
                 }
             }
-
+            
System.out.println(cascadesContext.getMemo().copyOut().treeString());
+            System.out.println("-------------------------------");

Review Comment:
   remove println



##########
fe/fe-core/src/main/java/org/apache/doris/planner/AnalyticEvalNode.java:
##########
@@ -262,4 +260,8 @@ public String getNodeExplainString(String prefix, 
TExplainLevel detailLevel) {
 
         return output.toString();
     }
+
+    public void finalizeForNereids() {
+        this.substitutedPartitionExprs = partitionExprs;
+    }

Review Comment:
   could we use a new constructor to avoid do finalizeForNereids?



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/ExpressionTranslator.java:
##########
@@ -293,13 +294,59 @@ public Expr visitCast(Cast cast, PlanTranslatorContext 
context) {
     @Override
     public Expr visitInPredicate(InPredicate inPredicate, 
PlanTranslatorContext context) {
         List<Expr> inList = inPredicate.getOptions().stream()
-                .map(e -> translate(e, context))
+                .map(e -> e.accept(this, context))
                 .collect(Collectors.toList());
         return new 
org.apache.doris.analysis.InPredicate(inPredicate.getCompareExpr().accept(this, 
context),
                 inList,
                 false);
     }
 
+    @Override
+    public Expr visitWindowFunction(WindowFunction function, 
PlanTranslatorContext context) {
+        // translate argument types from DataType to Type
+        List<Expr> catalogArguments = function.getArguments()
+                .stream()
+                .map(arg -> arg.accept(this, context))
+                .collect(ImmutableList.toImmutableList());
+        ImmutableList<Type> argTypes = catalogArguments.stream()
+                .map(arg -> arg.getType())
+                .collect(ImmutableList.toImmutableList());
+
+        // translate argument from List<Expression> to FunctionParams
+        List<Expr> arguments = function.getArguments()
+                .stream()
+                .map(arg -> new SlotRef(arg.getDataType().toCatalogDataType(), 
arg.nullable()))
+                .collect(ImmutableList.toImmutableList());
+        FunctionParams windowFnParams = new FunctionParams(false, arguments);
+
+        // translate isNullable()
+        NullableMode nullableMode = function.nullable()
+                ? NullableMode.ALWAYS_NULLABLE
+                : NullableMode.ALWAYS_NOT_NULLABLE;
+
+        // translate function from WindowFunction to old AggregateFunction
+        boolean isAnalyticFunction = true;
+        org.apache.doris.catalog.AggregateFunction catalogFunction = new 
org.apache.doris.catalog.AggregateFunction(
+                new FunctionName(function.getName()), argTypes,
+                function.getDataType().toCatalogDataType(),
+                function.getDataType().toCatalogDataType(),
+                function.hasVarArguments(),
+                null, "", "", null, "",
+                null, "", null, false,
+                isAnalyticFunction, false, TFunctionBinaryType.BUILTIN,
+                true, true, nullableMode
+        );
+
+        // generate FunctionCallExpr
+        boolean isMergeFn = false;
+        FunctionCallExpr functionCallExpr =
+                new FunctionCallExpr(catalogFunction, windowFnParams, 
windowFnParams, isMergeFn, catalogArguments);
+        functionCallExpr.setIsAnalyticFnCall(true);
+        return functionCallExpr;
+
+    }
+
+    // TODO: Supports for `distinct`

Review Comment:
   what's this TODO mean?



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/WindowFrame.java:
##########
@@ -0,0 +1,280 @@
+// 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.trees.expressions;
+
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * window frame
+ */
+public class WindowFrame extends Expression implements PropagateNullable, 
LeafExpression {
+
+    private FrameUnitsType frameUnits;
+
+    private FrameBoundary leftBoundary;
+
+    private FrameBoundary rightBoundary;
+
+    public WindowFrame(FrameUnitsType frameUnits, FrameBoundary leftBoundary) {
+        this(frameUnits, leftBoundary, new 
FrameBoundary(FrameBoundType.EMPTY_BOUNDARY));
+    }
+
+    public WindowFrame(FrameUnitsType frameUnits, FrameBoundary leftBoundary, 
FrameBoundary rightBoundary) {
+        this.frameUnits = frameUnits;
+        this.leftBoundary = leftBoundary;
+        this.rightBoundary = rightBoundary;
+    }
+
+    public FrameUnitsType getFrameUnits() {
+        return frameUnits;
+    }
+
+    public FrameBoundary getLeftBoundary() {
+        return leftBoundary;
+    }
+
+    public FrameBoundary getRightBoundary() {
+        return rightBoundary;
+    }
+
+    public void setRightBoundary(FrameBoundary rightBoundary) {
+        this.rightBoundary = rightBoundary;
+    }
+
+    /**
+     * reverse left & right boundary; reverse each boundary's upper and lower 
bound
+     */
+    public WindowFrame reverseWindow() {
+        return new WindowFrame(frameUnits, rightBoundary.reverse(), 
leftBoundary.reverse());
+    }
+
+    public WindowFrame withRightBoundary(FrameBoundary newRightBoundary) {
+        return new WindowFrame(frameUnits, leftBoundary, newRightBoundary);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        WindowFrame other = (WindowFrame) o;
+        return Objects.equals(this.frameUnits, other.frameUnits)
+            && Objects.equals(this.leftBoundary, other.leftBoundary)
+            && Objects.equals(this.rightBoundary, other.rightBoundary);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(frameUnits, leftBoundary, rightBoundary);
+    }
+
+    @Override
+    public String toSql() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(frameUnits + " ");
+        if (rightBoundary != null) {
+            sb.append("BETWEEN " + leftBoundary + " AND " + rightBoundary);
+        } else {
+            sb.append(leftBoundary);
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("WindowFrame(");
+        sb.append(frameUnits + ", ");
+        sb.append(leftBoundary + ", ");
+        if (rightBoundary != null) {
+            sb.append(rightBoundary);
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitWindowFrame(this, context);
+    }
+
+    /**
+     * frame units types
+     */
+    public enum FrameUnitsType {
+        ROWS(),
+        RANGE()
+    }
+
+    /**
+     * frame boundary
+     */
+    public static class FrameBoundary {
+
+        private Optional<Expression> boundOffset;
+        private FrameBoundType frameBoundType;

Review Comment:
   final



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/WindowFrame.java:
##########
@@ -0,0 +1,280 @@
+// 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.trees.expressions;
+
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * window frame
+ */
+public class WindowFrame extends Expression implements PropagateNullable, 
LeafExpression {
+
+    private FrameUnitsType frameUnits;
+
+    private FrameBoundary leftBoundary;
+
+    private FrameBoundary rightBoundary;
+
+    public WindowFrame(FrameUnitsType frameUnits, FrameBoundary leftBoundary) {
+        this(frameUnits, leftBoundary, new 
FrameBoundary(FrameBoundType.EMPTY_BOUNDARY));
+    }
+
+    public WindowFrame(FrameUnitsType frameUnits, FrameBoundary leftBoundary, 
FrameBoundary rightBoundary) {
+        this.frameUnits = frameUnits;
+        this.leftBoundary = leftBoundary;
+        this.rightBoundary = rightBoundary;
+    }
+
+    public FrameUnitsType getFrameUnits() {
+        return frameUnits;
+    }
+
+    public FrameBoundary getLeftBoundary() {
+        return leftBoundary;
+    }
+
+    public FrameBoundary getRightBoundary() {
+        return rightBoundary;
+    }
+
+    public void setRightBoundary(FrameBoundary rightBoundary) {
+        this.rightBoundary = rightBoundary;
+    }
+
+    /**
+     * reverse left & right boundary; reverse each boundary's upper and lower 
bound
+     */
+    public WindowFrame reverseWindow() {
+        return new WindowFrame(frameUnits, rightBoundary.reverse(), 
leftBoundary.reverse());
+    }
+
+    public WindowFrame withRightBoundary(FrameBoundary newRightBoundary) {
+        return new WindowFrame(frameUnits, leftBoundary, newRightBoundary);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        WindowFrame other = (WindowFrame) o;
+        return Objects.equals(this.frameUnits, other.frameUnits)
+            && Objects.equals(this.leftBoundary, other.leftBoundary)
+            && Objects.equals(this.rightBoundary, other.rightBoundary);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(frameUnits, leftBoundary, rightBoundary);
+    }
+
+    @Override
+    public String toSql() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(frameUnits + " ");
+        if (rightBoundary != null) {
+            sb.append("BETWEEN " + leftBoundary + " AND " + rightBoundary);
+        } else {
+            sb.append(leftBoundary);
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("WindowFrame(");
+        sb.append(frameUnits + ", ");
+        sb.append(leftBoundary + ", ");
+        if (rightBoundary != null) {
+            sb.append(rightBoundary);
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitWindowFrame(this, context);
+    }
+
+    /**
+     * frame units types
+     */
+    public enum FrameUnitsType {
+        ROWS(),
+        RANGE()

Review Comment:
   ```suggestion
           ROWS,
           RANGE
   ```



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/WindowFrame.java:
##########
@@ -0,0 +1,280 @@
+// 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.trees.expressions;
+
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * window frame
+ */
+public class WindowFrame extends Expression implements PropagateNullable, 
LeafExpression {
+
+    private FrameUnitsType frameUnits;
+
+    private FrameBoundary leftBoundary;
+
+    private FrameBoundary rightBoundary;
+
+    public WindowFrame(FrameUnitsType frameUnits, FrameBoundary leftBoundary) {
+        this(frameUnits, leftBoundary, new 
FrameBoundary(FrameBoundType.EMPTY_BOUNDARY));
+    }
+
+    public WindowFrame(FrameUnitsType frameUnits, FrameBoundary leftBoundary, 
FrameBoundary rightBoundary) {
+        this.frameUnits = frameUnits;
+        this.leftBoundary = leftBoundary;
+        this.rightBoundary = rightBoundary;
+    }
+
+    public FrameUnitsType getFrameUnits() {
+        return frameUnits;
+    }
+
+    public FrameBoundary getLeftBoundary() {
+        return leftBoundary;
+    }
+
+    public FrameBoundary getRightBoundary() {
+        return rightBoundary;
+    }
+
+    public void setRightBoundary(FrameBoundary rightBoundary) {
+        this.rightBoundary = rightBoundary;
+    }
+
+    /**
+     * reverse left & right boundary; reverse each boundary's upper and lower 
bound
+     */
+    public WindowFrame reverseWindow() {
+        return new WindowFrame(frameUnits, rightBoundary.reverse(), 
leftBoundary.reverse());
+    }
+
+    public WindowFrame withRightBoundary(FrameBoundary newRightBoundary) {
+        return new WindowFrame(frameUnits, leftBoundary, newRightBoundary);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        WindowFrame other = (WindowFrame) o;
+        return Objects.equals(this.frameUnits, other.frameUnits)
+            && Objects.equals(this.leftBoundary, other.leftBoundary)
+            && Objects.equals(this.rightBoundary, other.rightBoundary);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(frameUnits, leftBoundary, rightBoundary);
+    }
+
+    @Override
+    public String toSql() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(frameUnits + " ");
+        if (rightBoundary != null) {
+            sb.append("BETWEEN " + leftBoundary + " AND " + rightBoundary);
+        } else {
+            sb.append(leftBoundary);
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("WindowFrame(");
+        sb.append(frameUnits + ", ");
+        sb.append(leftBoundary + ", ");
+        if (rightBoundary != null) {
+            sb.append(rightBoundary);
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitWindowFrame(this, context);
+    }
+
+    /**
+     * frame units types
+     */
+    public enum FrameUnitsType {
+        ROWS(),
+        RANGE()
+    }
+
+    /**
+     * frame boundary
+     */
+    public static class FrameBoundary {
+
+        private Optional<Expression> boundOffset;
+        private FrameBoundType frameBoundType;
+
+        public FrameBoundary(FrameBoundType frameBoundType) {
+            this.boundOffset = Optional.empty();
+            this.frameBoundType = frameBoundType;
+        }
+
+        public FrameBoundary(Optional<Expression> boundOffset, FrameBoundType 
frameBoundType) {
+            this.boundOffset = boundOffset;
+            this.frameBoundType = frameBoundType;
+        }
+
+        public static FrameBoundary newPrecedingBoundary() {
+            return new FrameBoundary(FrameBoundType.UNBOUNDED_PRECEDING);
+        }
+
+        public static FrameBoundary newPrecedingBoundary(Expression 
boundValue) {
+            return new FrameBoundary(Optional.of(boundValue), 
FrameBoundType.PRECEDING);
+        }
+
+        public static FrameBoundary newFollowingBoundary() {
+            return new FrameBoundary(FrameBoundType.UNBOUNDED_FOLLOWING);
+        }
+
+        public static FrameBoundary newFollowingBoundary(Expression 
boundValue) {
+            return new FrameBoundary(Optional.of(boundValue), 
FrameBoundType.FOLLOWING);
+        }
+
+        public static FrameBoundary newCurrentRowBoundary() {
+            return new FrameBoundary(FrameBoundType.CURRENT_ROW);
+        }
+
+        public boolean is(FrameBoundType otherType) {
+            return this.frameBoundType == otherType;
+        }
+
+        public boolean isNot(FrameBoundType otherType) {
+            return this.frameBoundType != otherType;
+        }
+
+        public boolean isNull() {
+            return this.frameBoundType == FrameBoundType.EMPTY_BOUNDARY;
+        }
+
+        public boolean hasOffset() {
+            return frameBoundType == FrameBoundType.PRECEDING || 
frameBoundType == FrameBoundType.FOLLOWING;
+        }
+
+        public boolean asPreceding() {
+            return frameBoundType == FrameBoundType.PRECEDING || 
frameBoundType == FrameBoundType.UNBOUNDED_PRECEDING;
+        }
+
+        public boolean asFollowing() {
+            return frameBoundType == FrameBoundType.FOLLOWING || 
frameBoundType == FrameBoundType.UNBOUNDED_FOLLOWING;
+        }
+
+        public FrameBoundary reverse() {
+            return new FrameBoundary(boundOffset, frameBoundType.reverse());
+        }
+
+        public FrameBoundType getFrameBoundType() {
+            return frameBoundType;
+        }
+
+        public Optional<Expression> getBoundOffset() {
+            return boundOffset;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            boundOffset.ifPresent(value -> sb.append(value + " "));
+            sb.append(frameBoundType);
+
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            FrameBoundary other = (FrameBoundary) o;
+            return Objects.equals(this.frameBoundType, other.frameBoundType)
+                && Objects.equals(this.boundOffset, other.boundOffset);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(boundOffset, frameBoundType);
+        }
+    }
+
+    /**
+     * frame bound types
+     */
+    public enum FrameBoundType {
+
+        UNBOUNDED_PRECEDING("UNBOUNDED_PRECEDING"),
+        UNBOUNDED_FOLLOWING("UNBOUNDED_FOLLOWING"),
+        CURRENT_ROW("CURRENT_ROW"),
+        PRECEDING("PRECEDING"),
+        FOLLOWING("FOLLOWING"),
+
+        // represents that the boundary is null. We use this value as default
+        // to avoid checking if a boundary is null frequently.
+        EMPTY_BOUNDARY("EMPTY_BOUNDARY");
+
+        private final String description;

Review Comment:
   description is useless



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalWindowToPhysicalWindow.java:
##########
@@ -0,0 +1,545 @@
+// 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.implementation;
+
+import org.apache.doris.nereids.annotation.DependsRules;
+import org.apache.doris.nereids.properties.DistributionSpecHash;
+import org.apache.doris.nereids.properties.OrderKey;
+import org.apache.doris.nereids.properties.OrderSpec;
+import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.properties.RequireProperties;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import 
org.apache.doris.nereids.rules.rewrite.logical.CheckAndStandardizeWindowFunctionAndFrame;
+import 
org.apache.doris.nereids.rules.rewrite.logical.ExtractAndNormalizeWindowExpression;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.OrderExpression;
+import org.apache.doris.nereids.trees.expressions.WindowExpression;
+import org.apache.doris.nereids.trees.expressions.WindowFrame;
+import org.apache.doris.nereids.trees.plans.GroupPlan;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalWindow;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalWindow;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Implementation rule that convert logical window to physical window, and add 
RequiredProperties
+ *
+ * step 1: compute three kinds of group:
+ *      WindowFrameGroup: maintain windows with same PartitionKey, OrderKey 
and WindowFrame
+ *      OrderKeyGroup: maintain windows with same PartitionKey and OrderKey
+ *      PartitionKeyGroup: maintain windows with same PartitionKey
+ * step 2: sort PartitionKeyGroup with increasing order of tupleSize
+ * step 3: for every WindowFrameGroup of each SortGroup, generate one 
PhysicalWindow node, with common PartitionKeys,
+ *  OrderKeys, unique WindowFrame and a function list.
+ * step 4: for each PhysicalWindow, generate RequiredProperties, including 
PartitionKey for DistributionSpec,
+ *  and (PartitionKey + OrderKey) for OrderSpec.
+ */
+@DependsRules({
+    CheckAndStandardizeWindowFunctionAndFrame.class,
+    ExtractAndNormalizeWindowExpression.class
+})
+public class LogicalWindowToPhysicalWindow extends 
OneImplementationRuleFactory {
+
+    @Override
+    public Rule build() {
+
+        return RuleType.LOGICAL_WINDOW_TO_PHYSICAL_WINDOW_RULE.build(
+            
logicalWindow().when(LogicalWindow::isChecked).then(this::implement)

Review Comment:
   why need isChecked?



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/WindowFrame.java:
##########
@@ -0,0 +1,280 @@
+// 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.trees.expressions;
+
+import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable;
+import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * window frame
+ */
+public class WindowFrame extends Expression implements PropagateNullable, 
LeafExpression {
+
+    private FrameUnitsType frameUnits;
+
+    private FrameBoundary leftBoundary;
+
+    private FrameBoundary rightBoundary;

Review Comment:
   final



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriteJobExecutor.java:
##########
@@ -90,6 +92,11 @@ public NereidsRewriteJobExecutor(CascadesContext 
cascadesContext) {
                 .add(bottomUpBatch(ImmutableList.of(new 
AdjustAggregateNullableForEmptySet())))
                 .add(topDownBatch(ImmutableList.of(new 
EliminateGroupByConstant())))
                 .add(topDownBatch(ImmutableList.of(new NormalizeAggregate())))
+                .add(topDownBatch(ImmutableList.of(new 
ExtractAndNormalizeWindowExpression())))
+                //execute NormalizeAggregate() again to resolve nested 
AggregateFunctions in WindowExpression,
+                //e.g. sum(sum(c1)) over(partition by avg(c1))
+                .add(topDownBatch(ImmutableList.of(new NormalizeAggregate())))

Review Comment:
   it is weird, i think after normalize aggregate we should get
   ```
   project(sum(a1) over (partition by a2))
   +---agg(sum(c1) as a1, avg(c1) as c2)
   ```
   and then we do extract window expression



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


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

Reply via email to