You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@quickstep.apache.org by zu...@apache.org on 2016/06/25 02:01:45 UTC

incubator-quickstep git commit: Added Window Aggregation Function in optimizer.

Repository: incubator-quickstep
Updated Branches:
  refs/heads/master d64289148 -> 714874ce5


Added Window Aggregation Function in optimizer.

  - The resolver could understand optional window clause w/ aggregation functions.
  - Only one window aggregation function is allowed.


Project: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/commit/714874ce
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/tree/714874ce
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/diff/714874ce

Branch: refs/heads/master
Commit: 714874ce54e12972285a43f92784ef6954a8b6fd
Parents: d642891
Author: shixuan <sh...@wisc.edu>
Authored: Tue Jun 21 20:08:52 2016 +0000
Committer: Zuyu Zhang <zu...@apache.org>
Committed: Fri Jun 24 18:59:47 2016 -0700

----------------------------------------------------------------------
 query_optimizer/expressions/CMakeLists.txt      |  17 +-
 query_optimizer/expressions/ExpressionType.hpp  |   3 +-
 query_optimizer/expressions/PatternMatcher.hpp  |   3 +
 .../expressions/WindowAggregateFunction.cpp     | 193 ++++++++++++
 .../expressions/WindowAggregateFunction.hpp     | 246 +++++++++++++++
 query_optimizer/logical/CMakeLists.txt          |  18 +-
 query_optimizer/logical/LogicalType.hpp         |   3 +-
 query_optimizer/logical/PatternMatcher.hpp      |   2 +
 query_optimizer/logical/WindowAggregate.cpp     |  85 +++++
 query_optimizer/logical/WindowAggregate.hpp     | 123 ++++++++
 query_optimizer/resolver/CMakeLists.txt         |   2 +
 query_optimizer/resolver/Resolver.cpp           | 314 ++++++++++++++++++-
 query_optimizer/resolver/Resolver.hpp           |  66 +++-
 query_optimizer/strategy/CMakeLists.txt         |   3 +-
 query_optimizer/strategy/OneToOne.cpp           |   5 +
 .../tests/logical_generator/Select.test         | 162 ++++++++++
 query_optimizer/tests/resolver/Select.test      | 162 ++++++++++
 17 files changed, 1387 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/expressions/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/CMakeLists.txt b/query_optimizer/expressions/CMakeLists.txt
index 6c40741..08d7df5 100644
--- a/query_optimizer/expressions/CMakeLists.txt
+++ b/query_optimizer/expressions/CMakeLists.txt
@@ -43,6 +43,7 @@ add_library(quickstep_queryoptimizer_expressions_SearchedCase SearchedCase.cpp S
 add_library(quickstep_queryoptimizer_expressions_SimpleCase SimpleCase.cpp SimpleCase.hpp)
 add_library(quickstep_queryoptimizer_expressions_SubqueryExpression SubqueryExpression.cpp SubqueryExpression.hpp)
 add_library(quickstep_queryoptimizer_expressions_UnaryExpression UnaryExpression.cpp UnaryExpression.hpp)
+add_library(quickstep_queryoptimizer_expressions_WindowAggregateFunction WindowAggregateFunction.cpp WindowAggregateFunction.hpp)
 
 # Link dependencies:
 target_link_libraries(quickstep_queryoptimizer_expressions_AggregateFunction
@@ -301,6 +302,19 @@ target_link_libraries(quickstep_queryoptimizer_expressions_UnaryExpression
                       quickstep_types_operations_unaryoperations_UnaryOperation
                       quickstep_types_operations_unaryoperations_UnaryOperationID
                       quickstep_utility_Macros)
+target_link_libraries(quickstep_queryoptimizer_expressions_WindowAggregateFunction
+                      glog
+                      quickstep_expressions_aggregation_AggregateFunction
+                      quickstep_queryoptimizer_OptimizerTree
+                      quickstep_queryoptimizer_expressions_AttributeReference
+                      quickstep_queryoptimizer_expressions_Expression
+                      quickstep_queryoptimizer_expressions_ExpressionType
+                      quickstep_queryoptimizer_expressions_PatternMatcher
+                      quickstep_queryoptimizer_expressions_Scalar
+                      quickstep_types_Type
+                      quickstep_utility_Cast
+                      quickstep_utility_Macros)
+
 
 # Module all-in-one library:
 add_library(quickstep_queryoptimizer_expressions ../../empty_src.cpp OptimizerExpressionsModule.hpp)
@@ -330,4 +344,5 @@ target_link_libraries(quickstep_queryoptimizer_expressions
                       quickstep_queryoptimizer_expressions_SearchedCase
                       quickstep_queryoptimizer_expressions_SimpleCase
                       quickstep_queryoptimizer_expressions_SubqueryExpression
-                      quickstep_queryoptimizer_expressions_UnaryExpression)
+                      quickstep_queryoptimizer_expressions_UnaryExpression
+                      quickstep_queryoptimizer_expressions_WindowAggregateFunction)

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/expressions/ExpressionType.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/ExpressionType.hpp b/query_optimizer/expressions/ExpressionType.hpp
index 23770e0..77e0874 100644
--- a/query_optimizer/expressions/ExpressionType.hpp
+++ b/query_optimizer/expressions/ExpressionType.hpp
@@ -49,7 +49,8 @@ enum class ExpressionType {
   kSearchedCase,
   kSimpleCase,
   kSubqueryExpression,
-  kUnaryExpression
+  kUnaryExpression,
+  kWindowAggregateFunction
 };
 
 /** @} */

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/expressions/PatternMatcher.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/PatternMatcher.hpp b/query_optimizer/expressions/PatternMatcher.hpp
index 87bc52a..2cc91d6 100644
--- a/query_optimizer/expressions/PatternMatcher.hpp
+++ b/query_optimizer/expressions/PatternMatcher.hpp
@@ -52,6 +52,7 @@ class Scalar;
 class ScalarLiteral;
 class Sum;
 class UnaryExpression;
+class WindowAggregateFunction;
 
 /** \addtogroup OptimizerExpressions
  *  @{
@@ -155,6 +156,8 @@ using SomeScalar = SomeExpressionNode<Scalar,
                                       ExpressionType::kUnaryExpression>;
 using SomeScalarLiteral = SomeExpressionNode<ScalarLiteral, ExpressionType::kScalarLiteral>;
 using SomeUnaryExpression = SomeExpressionNode<UnaryExpression, ExpressionType::kUnaryExpression>;
+using SomeWindowAggregateFunction = SomeExpressionNode<WindowAggregateFunction,
+                                                       ExpressionType::kWindowAggregateFunction>;
 
 using SomeAggregateFunction = SomeExpressionNode<AggregateFunction,
                                                  ExpressionType::kAggregateFunction>;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/expressions/WindowAggregateFunction.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/WindowAggregateFunction.cpp b/query_optimizer/expressions/WindowAggregateFunction.cpp
new file mode 100644
index 0000000..7b1f304
--- /dev/null
+++ b/query_optimizer/expressions/WindowAggregateFunction.cpp
@@ -0,0 +1,193 @@
+/**
+ *   Copyright 2015 Pivotal Software, Inc.
+ *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+ *     University of Wisconsin\u2014Madison.
+ *
+ *   Licensed 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.
+ **/
+
+#include "query_optimizer/expressions/WindowAggregateFunction.hpp"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "expressions/aggregation/AggregateFunction.hpp"
+#include "query_optimizer/expressions/AttributeReference.hpp"
+#include "query_optimizer/expressions/Expression.hpp"
+#include "query_optimizer/expressions/PatternMatcher.hpp"
+#include "query_optimizer/expressions/Scalar.hpp"
+#include "types/Type.hpp"
+#include "utility/Cast.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+namespace optimizer {
+namespace expressions {
+
+bool WindowAggregateFunction::isNullable() const {
+  std::vector<const Type*> argument_types;
+  for (const ScalarPtr &argument : arguments_) {
+    argument_types.emplace_back(&argument->getValueType());
+  }
+
+  const Type *return_type = window_aggregate_.resultTypeForArgumentTypes(argument_types);
+  DCHECK(return_type != nullptr);
+  return return_type->isNullable();
+}
+
+const Type& WindowAggregateFunction::getValueType() const {
+  std::vector<const Type*> argument_types;
+  for (const ScalarPtr &argument : arguments_) {
+    argument_types.emplace_back(&argument->getValueType());
+  }
+
+  const Type *return_type = window_aggregate_.resultTypeForArgumentTypes(argument_types);
+  DCHECK(return_type != nullptr);
+  return *return_type;
+}
+
+WindowAggregateFunctionPtr WindowAggregateFunction::Create(
+    const ::quickstep::AggregateFunction &window_aggregate,
+    const std::vector<ScalarPtr> &arguments,
+    const WindowInfo &window_info,
+    const std::string &window_name,
+    const bool is_distinct) {
+#ifdef QUICKSTEP_DEBUG
+  std::vector<const Type*> argument_types;
+  for (const ScalarPtr &argument : arguments) {
+    argument_types.emplace_back(&argument->getValueType());
+  }
+  DCHECK(window_aggregate.canApplyToTypes(argument_types));
+#endif  // QUICKSTEP_DEBUG
+
+  return WindowAggregateFunctionPtr(
+      new WindowAggregateFunction(window_aggregate, arguments, window_info, window_name, is_distinct));
+}
+
+ExpressionPtr WindowAggregateFunction::copyWithNewChildren(
+    const std::vector<ExpressionPtr> &new_children) const {
+  std::vector<ScalarPtr> new_arguments;
+  for (const ExpressionPtr &expression_ptr : new_children) {
+    ScalarPtr expr_as_scalar;
+    CHECK(SomeScalar::MatchesWithConditionalCast(expression_ptr, &expr_as_scalar))
+        << expression_ptr->toString();
+    new_arguments.emplace_back(std::move(expr_as_scalar));
+  }
+
+  return WindowAggregateFunctionPtr(
+      new WindowAggregateFunction(window_aggregate_,
+                                  new_arguments,
+                                  window_info_,
+                                  window_name_,
+                                  is_distinct_));
+}
+
+std::vector<AttributeReferencePtr> WindowAggregateFunction::getReferencedAttributes() const {
+  std::vector<AttributeReferencePtr> referenced_attributes;
+  for (const ScalarPtr &argument : arguments_) {
+    const std::vector<AttributeReferencePtr> referenced_attributes_in_argument =
+        argument->getReferencedAttributes();
+    referenced_attributes.insert(referenced_attributes.end(),
+                                 referenced_attributes_in_argument.begin(),
+                                 referenced_attributes_in_argument.end());
+  }
+
+  referenced_attributes.insert(referenced_attributes.end(),
+                               window_info_.partition_by_attributes.begin(),
+                               window_info_.partition_by_attributes.end());
+
+  referenced_attributes.insert(referenced_attributes.end(),
+                               window_info_.order_by_attributes.begin(),
+                               window_info_.order_by_attributes.end());
+
+  return referenced_attributes;
+}
+
+void WindowAggregateFunction::getFieldStringItems(
+    std::vector<std::string> *inline_field_names,
+    std::vector<std::string> *inline_field_values,
+    std::vector<std::string> *non_container_child_field_names,
+    std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
+    std::vector<std::string> *container_child_field_names,
+    std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const {
+  inline_field_names->push_back("function");
+  inline_field_values->push_back(window_aggregate_.getName());
+
+  container_child_field_names->push_back("arguments");
+  container_child_fields->emplace_back(CastSharedPtrVector<OptimizerTreeBase>(arguments_));
+
+  inline_field_names->push_back("window_name");
+  inline_field_values->push_back(window_name_);
+
+  container_child_field_names->push_back("partition_by");
+  container_child_fields->emplace_back(
+      CastSharedPtrVector<OptimizerTreeBase>(window_info_.partition_by_attributes));
+
+  container_child_field_names->push_back("order_by");
+  container_child_fields->emplace_back(
+      CastSharedPtrVector<OptimizerTreeBase>(window_info_.order_by_attributes));
+
+  inline_field_names->push_back("is_ascending");
+  std::string ascending_list("[");
+  for (const bool is_ascending : window_info_.order_by_directions) {
+    if (is_ascending) {
+      ascending_list.append("true,");
+    } else {
+      ascending_list.append("false,");
+    }
+  }
+  if (!window_info_.order_by_directions.empty()) {
+    ascending_list.pop_back();
+  }
+  ascending_list.append("]");
+  inline_field_values->push_back(ascending_list);
+
+  inline_field_names->push_back("nulls_first");
+  std::string nulls_first_flags("[");
+  for (const bool nulls_first_flag : window_info_.nulls_first) {
+    if (nulls_first_flag) {
+      nulls_first_flags.append("true,");
+    } else {
+      nulls_first_flags.append("false,");
+    }
+  }
+  if (!window_info_.nulls_first.empty()) {
+    nulls_first_flags.pop_back();
+  }
+  nulls_first_flags.append("]");
+  inline_field_values->push_back(nulls_first_flags);
+
+  if (window_info_.frame_info != nullptr) {
+    const WindowFrameInfo *frame_info = window_info_.frame_info;
+
+    inline_field_names->push_back("frame_mode");
+    inline_field_values->push_back(frame_info->is_row ? "row" : "range");
+
+    inline_field_names->push_back("num_preceding");
+    inline_field_values->push_back(std::to_string(frame_info->num_preceding));
+
+    inline_field_names->push_back("num_following");
+    inline_field_values->push_back(std::to_string(frame_info->num_following));
+  }
+
+  if (is_distinct_) {
+    inline_field_names->push_back("is_distinct");
+    inline_field_values->push_back("true");
+  }
+}
+
+}  // namespace expressions
+}  // namespace optimizer
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/expressions/WindowAggregateFunction.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/WindowAggregateFunction.hpp b/query_optimizer/expressions/WindowAggregateFunction.hpp
new file mode 100644
index 0000000..0bee28f
--- /dev/null
+++ b/query_optimizer/expressions/WindowAggregateFunction.hpp
@@ -0,0 +1,246 @@
+/**
+ *   Copyright 2011-2015 Quickstep Technologies LLC.
+ *   Copyright 2015 Pivotal Software, Inc.
+ *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+ *     University of Wisconsin\u2014Madison.
+ *
+ *   Licensed 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.
+ **/
+
+#ifndef QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_WINDOW_AGGREGATE_FUNCTION_HPP_
+#define QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_WINDOW_AGGREGATE_FUNCTION_HPP_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "query_optimizer/OptimizerTree.hpp"
+#include "query_optimizer/expressions/AttributeReference.hpp"
+#include "query_optimizer/expressions/Expression.hpp"
+#include "query_optimizer/expressions/ExpressionType.hpp"
+#include "query_optimizer/expressions/Scalar.hpp"
+#include "utility/Macros.hpp"
+
+namespace quickstep {
+
+class AggregateFunction;
+class Type;
+
+namespace optimizer {
+namespace expressions {
+
+/** \addtogroup OptimizerExpressions
+ *  @{
+ */
+
+struct WindowFrameInfo {
+  /**
+   * @brief Cosntructor.
+   *
+   * @param is_row_in True if this window frame is defined by ROWS, false if
+   *                  defined by RANGE.
+   * @param num_preceding_in The number of preceding tuples the window frame
+   *                         will cover, -1 means UNBOUNDED.
+   * @param num_following_in The number of following tuples the window frame
+   *                         will cover, -1 means UNBOUNDED.
+   **/
+  WindowFrameInfo(const bool is_row_in,
+                  const int num_preceding_in,
+                  const int num_following_in)
+      : is_row(is_row_in),
+        num_preceding(num_preceding_in),
+        num_following(num_following_in) {}
+
+  const bool is_row;
+  const int num_preceding;
+  const int num_following;
+};
+
+struct WindowInfo {
+  /**
+   * @brief Constructor.
+   *
+   * @param partition_by_attributes_in The partition keys for the window.
+   * @param order_by_attributes_in The order keys for the window.
+   * @param order_by_directions_in The order direction for order key.
+   * @param nulls_first_in The nulls' position for order key.
+   * @param frame_info_in The window frame information for the window. Null
+   *        means there is no explicit window frame definition.
+   **/
+  WindowInfo(const std::vector<AttributeReferencePtr> &partition_by_attributes_in,
+             const std::vector<AttributeReferencePtr> &order_by_attributes_in,
+             const std::vector<bool> &order_by_directions_in,
+             const std::vector<bool> &nulls_first_in,
+             const WindowFrameInfo *frame_info_in)
+      : partition_by_attributes(partition_by_attributes_in),
+        order_by_attributes(order_by_attributes_in),
+        order_by_directions(order_by_directions_in),
+        nulls_first(nulls_first_in),
+        frame_info(frame_info_in) {}
+
+  const std::vector<AttributeReferencePtr> partition_by_attributes;
+  const std::vector<AttributeReferencePtr> order_by_attributes;
+  const std::vector<bool> order_by_directions;
+  const std::vector<bool> nulls_first;
+  const WindowFrameInfo *frame_info;
+};
+
+class WindowAggregateFunction;
+typedef std::shared_ptr<const WindowAggregateFunction> WindowAggregateFunctionPtr;
+
+/**
+ * @brief Represents a window aggregate function and its arguments in the
+ *        optimizer. This class wraps some of the functionality from
+ *        quickstep::AggregateFunction and represents a particular instance
+ *        of an aggregate during query optimization.
+ **/
+class WindowAggregateFunction : public Expression {
+ public:
+  /**
+   * @brief Destructor.
+   */
+  ~WindowAggregateFunction() override {}
+
+  ExpressionType getExpressionType() const override {
+    return ExpressionType::kWindowAggregateFunction;
+  }
+
+  std::string getName() const override {
+    return "WindowAggregateFunction";
+  }
+
+  const Type& getValueType() const override;
+
+  bool isConstant() const override {
+    // Window aggregate function is never considered as a constant expression.
+    return false;
+  }
+
+  ExpressionPtr copyWithNewChildren(
+      const std::vector<ExpressionPtr> &new_children) const override;
+
+  std::vector<AttributeReferencePtr> getReferencedAttributes() const override;
+
+  /**
+   * @return Whether the type of the return value is nullable.
+   **/
+  bool isNullable() const;
+
+  /**
+   * @return The WindowAggregateFunction singleton (from the expression system)
+   *         for this node.
+   **/
+  inline const ::quickstep::AggregateFunction& window_aggregate() const {
+    return window_aggregate_;
+  }
+
+  /**
+   * @return The list of scalar arguments to this aggregate.
+   **/
+  inline const std::vector<ScalarPtr>& arguments() const {
+    return arguments_;
+  }
+
+  /**
+   * @return The window info of this window aggregate function.
+   **/
+  inline const WindowInfo window_info() const {
+    return window_info_;
+  }
+
+  /**
+   * @return The name of the window.
+   **/
+  inline const std::string window_name() const {
+    return window_name_;
+  }
+
+  /**
+   * @return Whether this is a DISTINCT aggregation.
+   **/
+  inline bool is_distinct() const {
+    return is_distinct_;
+  }
+
+  /**
+   * @brief Create a new WindowAggregateFunction by directly defined window.
+   *
+   * @warning It is an error to call this with arguments that the given
+   *          aggregate can not apply to.
+   *
+   * @param aggregate The underlying WindowAggregateFunction from the expression
+   *        system.
+   * @param arguments A list of arguments to the window aggregate function.
+   * @param window_info The window info of the window aggregate function.
+   * @param is_distinct Whether this is a DISTINCT aggregation.
+   * @return A new AggregateFunctionPtr.
+   **/
+  static WindowAggregateFunctionPtr Create(const ::quickstep::AggregateFunction &window_aggregate,
+                                           const std::vector<ScalarPtr> &arguments,
+                                           const WindowInfo &window_info,
+                                           const std::string &window_name,
+                                           const bool is_distinct);
+
+ protected:
+  void getFieldStringItems(
+      std::vector<std::string> *inline_field_names,
+      std::vector<std::string> *inline_field_values,
+      std::vector<std::string> *non_container_child_field_names,
+      std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
+      std::vector<std::string> *container_child_field_names,
+      std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const override;
+
+ private:
+  /**
+   * @brief Constructor.
+   *
+   * @param window_aggregate The actual AggregateFunction to use.
+   * @param arguments A list of arguments to the window aggregate function.
+   * @param window_info The window info of the window aggregate function.
+   * @param is_distinct Indicates whether this is a DISTINCT aggregation.
+   */
+  WindowAggregateFunction(const ::quickstep::AggregateFunction &window_aggregate,
+                          const std::vector<ScalarPtr> &arguments,
+                          const WindowInfo &window_info,
+                          const std::string &window_name,
+                          const bool is_distinct)
+      : window_aggregate_(window_aggregate),
+        arguments_(arguments),
+        window_info_(window_info),
+        window_name_(window_name),
+        is_distinct_(is_distinct) {
+    for (const ScalarPtr &child : arguments_) {
+      addChild(child);
+    }
+  }
+
+  // TODO(Shixuan): Currently this class uses AggregationFunction as
+  // window_aggregate_. If it really needs to be seperated from the
+  // AggregationFunction, a new class for WindowAggregationFunction should be
+  // created as quickstep::WindowAggregateFunction.
+  const ::quickstep::AggregateFunction &window_aggregate_;
+  std::vector<ScalarPtr> arguments_;
+  const WindowInfo window_info_;
+  const std::string window_name_;
+  const bool is_distinct_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowAggregateFunction);
+};
+
+/** @} */
+
+}  // namespace expressions
+}  // namespace optimizer
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_QUERY_OPTIMIZER_EXPRESSIONS_WINDOW_AGGREGATE_FUNCTION_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/logical/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/logical/CMakeLists.txt b/query_optimizer/logical/CMakeLists.txt
index 61c6234..b787c60 100644
--- a/query_optimizer/logical/CMakeLists.txt
+++ b/query_optimizer/logical/CMakeLists.txt
@@ -43,6 +43,7 @@ add_library(quickstep_queryoptimizer_logical_TableReference TableReference.cpp T
 add_library(quickstep_queryoptimizer_logical_TableGenerator ../../empty_src.cpp TableGenerator.hpp)
 add_library(quickstep_queryoptimizer_logical_TopLevelPlan TopLevelPlan.cpp TopLevelPlan.hpp)
 add_library(quickstep_queryoptimizer_logical_UpdateTable UpdateTable.cpp UpdateTable.hpp)
+add_library(quickstep_queryoptimizer_logical_WindowAggregate WindowAggregate.cpp WindowAggregate.hpp)
 
 # Link dependencies:
 target_link_libraries(quickstep_queryoptimizer_logical_Aggregate
@@ -259,6 +260,20 @@ target_link_libraries(quickstep_queryoptimizer_logical_UpdateTable
                       quickstep_queryoptimizer_logical_LogicalType
                       quickstep_utility_Cast
                       quickstep_utility_Macros)
+target_link_libraries(quickstep_queryoptimizer_logical_WindowAggregate
+                      glog
+                      quickstep_queryoptimizer_expressions_Alias
+                      quickstep_queryoptimizer_expressions_AttributeReference
+                      quickstep_queryoptimizer_expressions_Expression
+                      quickstep_queryoptimizer_expressions_ExpressionUtil
+                      quickstep_queryoptimizer_expressions_NamedExpression
+                      quickstep_queryoptimizer_expressions_PatternMatcher
+                      quickstep_queryoptimizer_logical_Logical
+                      quickstep_queryoptimizer_logical_LogicalType
+                      quickstep_queryoptimizer_OptimizerTree
+                      quickstep_utility_Cast
+                      quickstep_utility_Macros)
+
 
 # Module all-in-one library:
 add_library(quickstep_queryoptimizer_logical ../../empty_src.cpp OptimizerLogicalModule.hpp)
@@ -287,4 +302,5 @@ target_link_libraries(quickstep_queryoptimizer_logical
                       quickstep_queryoptimizer_logical_TableGenerator
                       quickstep_queryoptimizer_logical_TableReference
                       quickstep_queryoptimizer_logical_TopLevelPlan
-                      quickstep_queryoptimizer_logical_UpdateTable)
+                      quickstep_queryoptimizer_logical_UpdateTable
+                      quickstep_queryoptimizer_logical_WindowAggregate)

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/logical/LogicalType.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/logical/LogicalType.hpp b/query_optimizer/logical/LogicalType.hpp
index 1b9366e..c82fb47 100644
--- a/query_optimizer/logical/LogicalType.hpp
+++ b/query_optimizer/logical/LogicalType.hpp
@@ -49,7 +49,8 @@ enum class LogicalType {
   kTableGenerator,
   kTableReference,
   kTopLevelPlan,
-  kUpdateTable
+  kUpdateTable,
+  kWindowAggregate
 };
 
 /** @} */

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/logical/PatternMatcher.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/logical/PatternMatcher.hpp b/query_optimizer/logical/PatternMatcher.hpp
index ff8f3d0..de8609e 100644
--- a/query_optimizer/logical/PatternMatcher.hpp
+++ b/query_optimizer/logical/PatternMatcher.hpp
@@ -45,6 +45,7 @@ class Sort;
 class TableReference;
 class TopLevelPlan;
 class UpdateTable;
+class WindowAggregate;
 
 /** \addtogroup OptimizerLogical
  *  @{
@@ -130,6 +131,7 @@ using SomeSort = SomeLogicalNode<Sort, LogicalType::kSort>;
 using SomeTableReference = SomeLogicalNode<TableReference, LogicalType::kTableReference>;
 using SomeTopLevelPlan = SomeLogicalNode<TopLevelPlan, LogicalType::kTopLevelPlan>;
 using SomeUpdateTable = SomeLogicalNode<UpdateTable, LogicalType::kUpdateTable>;
+using SomeWindowAggregate = SomeLogicalNode<WindowAggregate, LogicalType::kWindowAggregate>;
 
 /** @} */
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/logical/WindowAggregate.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/logical/WindowAggregate.cpp b/query_optimizer/logical/WindowAggregate.cpp
new file mode 100644
index 0000000..0d747b6
--- /dev/null
+++ b/query_optimizer/logical/WindowAggregate.cpp
@@ -0,0 +1,85 @@
+/**
+ *   Copyright 2011-2015 Quickstep Technologies LLC.
+ *   Copyright 2015 Pivotal Software, Inc.
+ *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+ *     University of Wisconsin\u2014Madison.
+ *
+ *   Licensed 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.
+ **/
+
+#include "query_optimizer/logical/WindowAggregate.hpp"
+
+#include <string>
+#include <vector>
+
+#include "query_optimizer/OptimizerTree.hpp"
+#include "query_optimizer/expressions/Alias.hpp"
+#include "query_optimizer/expressions/AttributeReference.hpp"
+#include "query_optimizer/expressions/ExpressionUtil.hpp"
+#include "query_optimizer/expressions/NamedExpression.hpp"
+#include "query_optimizer/expressions/PatternMatcher.hpp"
+#include "utility/Cast.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+namespace optimizer {
+namespace logical {
+
+namespace E = ::quickstep::optimizer::expressions;
+
+LogicalPtr WindowAggregate::copyWithNewChildren(
+    const std::vector<LogicalPtr> &new_children) const {
+  DCHECK_EQ(getNumChildren(), new_children.size());
+  return Create(new_children[0], window_aggregate_expression_);
+}
+
+std::vector<E::AttributeReferencePtr> WindowAggregate::getOutputAttributes() const {
+  std::vector<E::AttributeReferencePtr> output_attributes(input_->getOutputAttributes());
+  output_attributes.push_back(E::ToRef(window_aggregate_expression_));
+  return output_attributes;
+}
+
+std::vector<E::AttributeReferencePtr> WindowAggregate::getReferencedAttributes() const {
+  return window_aggregate_expression_->getReferencedAttributes();
+}
+
+LogicalPtr WindowAggregate::copyWithNewInputExpressions(
+    const std::vector<E::ExpressionPtr> &input_expressions) const {
+  // Only one expression needed
+  DCHECK_EQ(1u, input_expressions.size());
+
+  E::AliasPtr window_aggregate_expression;
+  E::SomeAlias::MatchesWithConditionalCast(input_expressions[0],
+                                           &window_aggregate_expression);
+
+  return Create(input_, window_aggregate_expression);
+}
+
+void WindowAggregate::getFieldStringItems(
+    std::vector<std::string> *inline_field_names,
+    std::vector<std::string> *inline_field_values,
+    std::vector<std::string> *non_container_child_field_names,
+    std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
+    std::vector<std::string> *container_child_field_names,
+    std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const {
+  non_container_child_field_names->push_back("input");
+  non_container_child_fields->push_back(input_);
+
+  non_container_child_field_names->push_back("window_aggregate_expression");
+  non_container_child_fields->push_back(window_aggregate_expression_);
+}
+
+}  // namespace logical
+}  // namespace optimizer
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/logical/WindowAggregate.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/logical/WindowAggregate.hpp b/query_optimizer/logical/WindowAggregate.hpp
new file mode 100644
index 0000000..dcd9a7d
--- /dev/null
+++ b/query_optimizer/logical/WindowAggregate.hpp
@@ -0,0 +1,123 @@
+/**
+ *   Copyright 2011-2015 Quickstep Technologies LLC.
+ *   Copyright 2015 Pivotal Software, Inc.
+ *   Copyright 2016, Quickstep Research Group, Computer Sciences Department,
+ *     University of Wisconsin\u2014Madison.
+ *
+ *   Licensed 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.
+ **/
+
+#ifndef QUICKSTEP_QUERY_OPTIMIZER_LOGICAL_WINDOW_AGGREGATE_HPP_
+#define QUICKSTEP_QUERY_OPTIMIZER_LOGICAL_WINDOW_AGGREGATE_HPP_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "query_optimizer/OptimizerTree.hpp"
+#include "query_optimizer/expressions/Alias.hpp"
+#include "query_optimizer/expressions/AttributeReference.hpp"
+#include "query_optimizer/expressions/Expression.hpp"
+#include "query_optimizer/expressions/NamedExpression.hpp"
+#include "query_optimizer/logical/Logical.hpp"
+#include "query_optimizer/logical/LogicalType.hpp"
+#include "utility/Macros.hpp"
+
+namespace quickstep {
+namespace optimizer {
+namespace logical {
+
+/** \addtogroup OptimizerLogical
+ *  @{
+ */
+
+class WindowAggregate;
+typedef std::shared_ptr<const WindowAggregate> WindowAggregatePtr;
+
+/**
+ * @brief Window aggregate operator that computes window aggregate expressions.
+ */
+class WindowAggregate : public Logical {
+ public:
+  LogicalType getLogicalType() const override {
+    return LogicalType::kWindowAggregate;
+  }
+
+  std::string getName() const override { return "WindowAggregate"; }
+
+  /**
+   * @return The input logical node.
+   */
+  const LogicalPtr& input() const { return input_; }
+
+  /**
+   * @return PARTITION BY expressions.
+   */
+  const expressions::AliasPtr window_aggregate_expression() const {
+    return window_aggregate_expression_;
+  }
+
+  LogicalPtr copyWithNewChildren(
+      const std::vector<LogicalPtr> &new_children) const override;
+
+  LogicalPtr copyWithNewInputExpressions(
+      const std::vector<expressions::ExpressionPtr> &input_expressions) const override;
+
+  std::vector<expressions::AttributeReferencePtr> getOutputAttributes() const override;
+
+  std::vector<expressions::AttributeReferencePtr> getReferencedAttributes() const override;
+
+  /**
+   * @brief Creates an Aggregate logical node.
+   *
+   * @param input The input node.
+   * @param window_aggregate_expression The window aggregate expression.
+   * @return An immutable WindowAggregate node.
+   */
+  static WindowAggregatePtr Create(
+      const LogicalPtr &input,
+      const expressions::AliasPtr &window_aggregate_expression) {
+    return WindowAggregatePtr(new WindowAggregate(input, window_aggregate_expression));
+  }
+
+ protected:
+  void getFieldStringItems(
+      std::vector<std::string> *inline_field_names,
+      std::vector<std::string> *inline_field_values,
+      std::vector<std::string> *non_container_child_field_names,
+      std::vector<OptimizerTreeBaseNodePtr> *non_container_child_fields,
+      std::vector<std::string> *container_child_field_names,
+      std::vector<std::vector<OptimizerTreeBaseNodePtr>> *container_child_fields) const override;
+
+ private:
+  WindowAggregate(const LogicalPtr &input,
+                  const expressions::AliasPtr &window_aggregate_expression)
+      : input_(input),
+        window_aggregate_expression_(window_aggregate_expression) {
+    addChild(input_);
+    addInputExpression(window_aggregate_expression_);
+  }
+
+  const LogicalPtr input_;
+  const expressions::AliasPtr window_aggregate_expression_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowAggregate);
+};
+
+/** @} */
+
+}  // namespace logical
+}  // namespace optimizer
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_QUERY_OPTIMIZER_LOGICAL_WINDOW_AGGREGATE_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/resolver/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/CMakeLists.txt b/query_optimizer/resolver/CMakeLists.txt
index dc7eac0..fb75767 100644
--- a/query_optimizer/resolver/CMakeLists.txt
+++ b/query_optimizer/resolver/CMakeLists.txt
@@ -89,6 +89,7 @@ target_link_libraries(quickstep_queryoptimizer_resolver_Resolver
                       quickstep_queryoptimizer_expressions_SimpleCase
                       quickstep_queryoptimizer_expressions_SubqueryExpression
                       quickstep_queryoptimizer_expressions_UnaryExpression
+                      quickstep_queryoptimizer_expressions_WindowAggregateFunction
                       quickstep_queryoptimizer_logical_Aggregate
                       quickstep_queryoptimizer_logical_CopyFrom
                       quickstep_queryoptimizer_logical_CreateIndex
@@ -109,6 +110,7 @@ target_link_libraries(quickstep_queryoptimizer_resolver_Resolver
                       quickstep_queryoptimizer_logical_TableReference
                       quickstep_queryoptimizer_logical_TopLevelPlan
                       quickstep_queryoptimizer_logical_UpdateTable
+                      quickstep_queryoptimizer_logical_WindowAggregate
                       quickstep_queryoptimizer_resolver_NameResolver
                       quickstep_storage_StorageBlockLayout_proto
                       quickstep_storage_StorageConstants

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/resolver/Resolver.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/Resolver.cpp b/query_optimizer/resolver/Resolver.cpp
index ffc173a..f880ce7 100644
--- a/query_optimizer/resolver/Resolver.cpp
+++ b/query_optimizer/resolver/Resolver.cpp
@@ -85,6 +85,7 @@
 #include "query_optimizer/expressions/SimpleCase.hpp"
 #include "query_optimizer/expressions/SubqueryExpression.hpp"
 #include "query_optimizer/expressions/UnaryExpression.hpp"
+#include "query_optimizer/expressions/WindowAggregateFunction.hpp"
 #include "query_optimizer/logical/Aggregate.hpp"
 #include "query_optimizer/logical/CopyFrom.hpp"
 #include "query_optimizer/logical/CreateIndex.hpp"
@@ -104,6 +105,7 @@
 #include "query_optimizer/logical/TableReference.hpp"
 #include "query_optimizer/logical/TopLevelPlan.hpp"
 #include "query_optimizer/logical/UpdateTable.hpp"
+#include "query_optimizer/logical/WindowAggregate.hpp"
 #include "query_optimizer/resolver/NameResolver.hpp"
 #include "storage/StorageBlockLayout.pb.h"
 #include "storage/StorageConstants.hpp"
@@ -164,9 +166,11 @@ struct Resolver::ExpressionResolutionInfo {
    */
   ExpressionResolutionInfo(const NameResolver &name_resolver_in,
                            QueryAggregationInfo *query_aggregation_info_in,
+                           WindowAggregationInfo *window_aggregation_info_in,
                            SelectListInfo *select_list_info_in)
       : name_resolver(name_resolver_in),
         query_aggregation_info(query_aggregation_info_in),
+        window_aggregation_info(window_aggregation_info_in),
         select_list_info(select_list_info_in) {}
 
   /**
@@ -180,6 +184,7 @@ struct Resolver::ExpressionResolutionInfo {
       : name_resolver(parent.name_resolver),
         not_allow_aggregate_here(parent.not_allow_aggregate_here),
         query_aggregation_info(parent.query_aggregation_info),
+        window_aggregation_info(parent.window_aggregation_info),
         select_list_info(parent.select_list_info) {}
 
   /**
@@ -187,16 +192,29 @@ struct Resolver::ExpressionResolutionInfo {
    */
   bool hasAggregate() const { return parse_aggregate_expression != nullptr; }
 
+  /**
+   * @return True if the expression contains a window aggregate function.
+   **/
+  bool hasWindowAggregate() const {
+    return parse_window_aggregate_expression != nullptr;
+  }
+
   const NameResolver &name_resolver;
   // Empty if aggregations are allowed.
   const std::string not_allow_aggregate_here;
 
   // Can be NULL if aggregations are not allowed.
   QueryAggregationInfo *query_aggregation_info = nullptr;
+
+  // Alias expressions that wraps window aggregate functions.
+  WindowAggregationInfo *window_aggregation_info = nullptr;
+
   // Can be NULL if alias references to SELECT-list expressions are not allowed.
   SelectListInfo *select_list_info = nullptr;
   // The first aggregate in the expression.
   const ParseTreeNode *parse_aggregate_expression = nullptr;
+  // The first window aggregate in the expression.
+  const ParseTreeNode *parse_window_aggregate_expression = nullptr;
 };
 
 struct Resolver::QueryAggregationInfo {
@@ -209,6 +227,26 @@ struct Resolver::QueryAggregationInfo {
   std::vector<E::AliasPtr> aggregate_expressions;
 };
 
+struct Resolver::WindowPlan {
+  WindowPlan(const E::WindowInfo &window_info_in,
+             const L::LogicalPtr &logical_plan_in)
+      : window_info(window_info_in),
+        logical_plan(logical_plan_in) {}
+
+  const E::WindowInfo window_info;
+  const L::LogicalPtr logical_plan;
+};
+
+struct Resolver::WindowAggregationInfo {
+  explicit WindowAggregationInfo(const std::unordered_map<std::string, WindowPlan> &window_map_in)
+      : window_map(window_map_in) {}
+
+  // Whether the current query block has a GROUP BY.
+  const std::unordered_map<std::string, WindowPlan> window_map;
+  // Alias expressions that wraps window aggregate functions.
+  std::vector<E::AliasPtr> window_aggregate_expressions;
+};
+
 struct Resolver::SelectListInfo {
  public:
   /**
@@ -973,8 +1011,36 @@ L::LogicalPtr Resolver::resolveSelect(
         logical_plan, resolvePredicate(parse_predicate, &expr_resolution_info));
   }
 
+  // Resolve WINDOW clause.
+  std::unordered_map<std::string, WindowPlan> sorted_window_map;
+  if (select_query.window_list() != nullptr) {
+    if (select_query.window_list()->size() > 1) {
+      THROW_SQL_ERROR_AT(&(*select_query.window_list()->begin()))
+          << "Currently we don't support multiple window aggregation functions";
+    }
+
+    // Sort the table according to the window.
+    for (const ParseWindow &window : *select_query.window_list()) {
+      // Check for duplicate definition.
+      // Currently this is useless since we only support one window.
+      if (sorted_window_map.find(window.name()->value()) != sorted_window_map.end()) {
+        THROW_SQL_ERROR_AT(window.name())
+            << "Duplicate definition of window " << window.name()->value();
+      }
+
+      E::WindowInfo resolved_window = resolveWindow(window, *name_resolver);
+      L::LogicalPtr sorted_logical_plan = resolveSortInWindow(logical_plan,
+                                                              resolved_window);
+
+      WindowPlan window_plan(resolved_window, sorted_logical_plan);
+
+      sorted_window_map.emplace(window.name()->value(), window_plan);
+    }
+  }
+
   QueryAggregationInfo query_aggregation_info(
       (select_query.group_by() != nullptr));
+  WindowAggregationInfo window_aggregation_info(sorted_window_map);
 
   // Resolve SELECT-list clause.
   std::vector<E::NamedExpressionPtr> select_list_expressions;
@@ -984,6 +1050,7 @@ L::LogicalPtr Resolver::resolveSelect(
                       type_hints,
                       *name_resolver,
                       &query_aggregation_info,
+                      &window_aggregation_info,
                       &select_list_expressions,
                       &has_aggregate_per_expression);
   DCHECK_EQ(has_aggregate_per_expression.size(),
@@ -992,6 +1059,29 @@ L::LogicalPtr Resolver::resolveSelect(
   SelectListInfo select_list_info(select_list_expressions,
                                   has_aggregate_per_expression);
 
+  // Create window aggregate node if needed
+  for (const E::AliasPtr &alias : window_aggregation_info.window_aggregate_expressions) {
+    E::WindowAggregateFunctionPtr window_aggregate_function;
+    if (!E::SomeWindowAggregateFunction::MatchesWithConditionalCast(alias->expression(),
+                                                                    &window_aggregate_function)) {
+      THROW_SQL_ERROR()
+          << "Unexpected expression in window aggregation function";
+    }
+    L::LogicalPtr sorted_logical_plan;
+
+    // Get the sorted logical plan
+    const std::string window_name = window_aggregate_function->window_name();
+    if (!window_name.empty()) {
+      sorted_logical_plan = sorted_window_map.at(window_name).logical_plan;
+    } else {
+      sorted_logical_plan = resolveSortInWindow(logical_plan,
+                                                window_aggregate_function->window_info());
+    }
+
+    logical_plan = L::WindowAggregate::Create(sorted_logical_plan,
+                                              alias);
+  }
+
   // Resolve GROUP BY.
   std::vector<E::NamedExpressionPtr> group_by_expressions;
   if (select_query.group_by() != nullptr) {
@@ -1039,7 +1129,7 @@ L::LogicalPtr Resolver::resolveSelect(
   E::PredicatePtr having_predicate;
   if (select_query.having() != nullptr) {
     ExpressionResolutionInfo expr_resolution_info(
-        *name_resolver, &query_aggregation_info, &select_list_info);
+        *name_resolver, &query_aggregation_info, &window_aggregation_info, &select_list_info);
     having_predicate = resolvePredicate(
         *select_query.having()->having_predicate(), &expr_resolution_info);
   }
@@ -1053,7 +1143,7 @@ L::LogicalPtr Resolver::resolveSelect(
     for (const ParseOrderByItem &order_by_item :
          *select_query.order_by()->order_by_items()) {
       ExpressionResolutionInfo expr_resolution_info(
-          *name_resolver, &query_aggregation_info, &select_list_info);
+          *name_resolver, &query_aggregation_info, &window_aggregation_info, &select_list_info);
       E::ScalarPtr order_by_scalar = resolveExpression(
           *order_by_item.ordering_expression(),
           nullptr,  // No Type hint.
@@ -1528,6 +1618,89 @@ L::LogicalPtr Resolver::RenameOutputColumns(
   return L::Project::Create(logical_plan, project_expressions);
 }
 
+E::WindowInfo Resolver::resolveWindow(const ParseWindow &parse_window,
+                                      const NameResolver &name_resolver) {
+  std::vector<E::AttributeReferencePtr> partition_by_attributes;
+  std::vector<E::AttributeReferencePtr> order_by_attributes;
+  std::vector<bool> order_by_directions;
+  std::vector<bool> nulls_first;
+  E::WindowFrameInfo *frame_info = nullptr;
+
+  // Resolve PARTITION BY
+  if (parse_window.partition_by_expressions() != nullptr) {
+    for (const ParseExpression &unresolved_partition_by_expression :
+         *parse_window.partition_by_expressions()) {
+      ExpressionResolutionInfo expr_resolution_info(
+          name_resolver,
+          "PARTITION BY clause" /* clause_name */,
+          nullptr /* select_list_info */);
+      E::ScalarPtr partition_by_scalar = resolveExpression(
+          unresolved_partition_by_expression,
+          nullptr,  // No Type hint.
+          &expr_resolution_info);
+
+      if (partition_by_scalar->isConstant()) {
+        THROW_SQL_ERROR_AT(&unresolved_partition_by_expression)
+            << "Constant expression not allowed in PARTITION BY";
+      }
+
+      E::AttributeReferencePtr partition_by_attribute;
+      if (!E::SomeAttributeReference::MatchesWithConditionalCast(partition_by_scalar,
+                                                                 &partition_by_attribute)) {
+        THROW_SQL_ERROR_AT(&unresolved_partition_by_expression)
+            << "Only attribute name allowed in PARTITION BY in window definition";
+      }
+
+      partition_by_attributes.push_back(partition_by_attribute);
+    }
+  }
+
+  // Resolve ORDER BY
+  if (parse_window.order_by_expressions() != nullptr) {
+    for (const ParseOrderByItem &order_by_item :
+         *parse_window.order_by_expressions()) {
+      ExpressionResolutionInfo expr_resolution_info(
+          name_resolver,
+          "ORDER BY clause" /* clause name */,
+          nullptr /* select_list_info */);
+      E::ScalarPtr order_by_scalar = resolveExpression(
+          *order_by_item.ordering_expression(),
+          nullptr,  // No Type hint.
+          &expr_resolution_info);
+
+      if (order_by_scalar->isConstant()) {
+        THROW_SQL_ERROR_AT(&order_by_item)
+            << "Constant expression not allowed in ORDER BY";
+      }
+
+      E::AttributeReferencePtr order_by_attribute;
+      if (!E::SomeAttributeReference::MatchesWithConditionalCast(order_by_scalar,
+                                                                 &order_by_attribute)) {
+        THROW_SQL_ERROR_AT(&order_by_item)
+            << "Only attribute name allowed in ORDER BY in window definition";
+      }
+
+      order_by_attributes.push_back(order_by_attribute);
+      order_by_directions.push_back(order_by_item.is_ascending());
+      nulls_first.push_back(order_by_item.nulls_first());
+    }
+  }
+
+  // Resolve window frame
+  if (parse_window.frame_info() != nullptr) {
+    const quickstep::ParseFrameInfo *parse_frame_info = parse_window.frame_info();
+    frame_info = new E::WindowFrameInfo(parse_frame_info->is_row,
+                                        parse_frame_info->num_preceding,
+                                        parse_frame_info->num_following);
+  }
+
+  return E::WindowInfo(partition_by_attributes,
+                       order_by_attributes,
+                       order_by_directions,
+                       nulls_first,
+                       frame_info);
+}
+
 const CatalogRelation* Resolver::resolveRelationName(
     const ParseString *relation_name) {
   const CatalogRelation *relation =
@@ -1684,13 +1857,45 @@ L::LogicalPtr Resolver::resolveJoinedTableReference(
   THROW_SQL_ERROR_AT(&joined_table_reference) << "Full outer join is not supported yet";
 }
 
+L::LogicalPtr Resolver::resolveSortInWindow(
+    const L::LogicalPtr &logical_plan,
+    const E::WindowInfo &window_info) {
+  // Sort the table by (p_key, o_key)
+  std::vector<E::AttributeReferencePtr> sort_attributes(window_info.partition_by_attributes);
+  sort_attributes.insert(sort_attributes.end(),
+                         window_info.order_by_attributes.begin(),
+                         window_info.order_by_attributes.end());
+
+  std::vector<bool> sort_directions(
+      window_info.partition_by_attributes.size(), true);
+  sort_directions.insert(sort_directions.end(),
+                         window_info.order_by_directions.begin(),
+                         window_info.order_by_directions.end());
+
+  std::vector<bool> sort_nulls_first(
+      window_info.partition_by_attributes.size(), false);
+  sort_nulls_first.insert(sort_nulls_first.end(),
+                          window_info.nulls_first.begin(),
+                          window_info.nulls_first.end());
+
+  L::LogicalPtr sorted_logical_plan =
+      L::Sort::Create(logical_plan,
+                      sort_attributes,
+                      sort_directions,
+                      sort_nulls_first,
+                      -1 /* limit */);
+
+  return sorted_logical_plan;
+}
+
 void Resolver::resolveSelectClause(
     const ParseSelectionClause &parse_selection,
     const std::string &select_name,
     const std::vector<const Type*> *type_hints,
     const NameResolver &name_resolver,
     QueryAggregationInfo *query_aggregation_info,
-    std::vector<expressions::NamedExpressionPtr> *project_expressions,
+    WindowAggregationInfo *window_aggregation_info,
+    std::vector<E::NamedExpressionPtr> *project_expressions,
     std::vector<bool> *has_aggregate_per_expression) {
   project_expressions->clear();
   switch (parse_selection.getSelectionType()) {
@@ -1720,6 +1925,7 @@ void Resolver::resolveSelectClause(
         ExpressionResolutionInfo expr_resolution_info(
             name_resolver,
             query_aggregation_info,
+            window_aggregation_info,
             nullptr /* select_list_info */);
         const E::ScalarPtr project_scalar =
             resolveExpression(*parse_project_expression,
@@ -2362,16 +2568,12 @@ E::ScalarPtr Resolver::resolveSimpleCaseExpression(
 
 // TODO(chasseur): For now this only handles resolving aggregate functions. In
 // the future it should be extended to resolve scalar functions as well.
+// TODO(Shixuan): This will handle resolving window aggregation function as well,
+// which could be extended to general scalar functions.
 E::ScalarPtr Resolver::resolveFunctionCall(
     const ParseFunctionCall &parse_function_call,
     ExpressionResolutionInfo *expression_resolution_info) {
-  std::string function_name = ToLower(parse_function_call.name()->value());
-
-  // TODO(Shixuan): Add support for window aggregation function.
-  if (parse_function_call.isWindow()) {
-    THROW_SQL_ERROR_AT(&parse_function_call)
-        << "Window Aggregation Function is not supported currently";
-  }
+  const std::string function_name = ToLower(parse_function_call.name()->value());
 
   // First check for the special case COUNT(*).
   bool count_star = false;
@@ -2386,8 +2588,9 @@ E::ScalarPtr Resolver::resolveFunctionCall(
   std::vector<E::ScalarPtr> resolved_arguments;
   const PtrList<ParseExpression> *unresolved_arguments =
       parse_function_call.arguments();
-  // The first aggregate function in the arguments.
+  // The first aggregate function and window aggregate function in the arguments.
   const ParseTreeNode *first_aggregate_function = nullptr;
+  const ParseTreeNode *first_window_aggregate_function = nullptr;
   if (unresolved_arguments != nullptr) {
     for (const ParseExpression &unresolved_argument : *unresolved_arguments) {
       ExpressionResolutionInfo expr_resolution_info(
@@ -2401,6 +2604,13 @@ E::ScalarPtr Resolver::resolveFunctionCall(
         first_aggregate_function =
             expr_resolution_info.parse_aggregate_expression;
       }
+
+      if (expr_resolution_info.hasWindowAggregate() &&
+          first_window_aggregate_function == nullptr &&
+          parse_function_call.isWindow()) {
+          first_window_aggregate_function =
+              expr_resolution_info.parse_window_aggregate_expression;
+      }
     }
   }
 
@@ -2431,6 +2641,15 @@ E::ScalarPtr Resolver::resolveFunctionCall(
         << "Aggregation of Aggregates are not allowed";
   }
 
+  // TODO(Shixuan): We currently don't support nested window aggregation since
+  // TPC-DS doesn't have that. However, it is essentially a nested scalar
+  // function, which should be supported in the future version of Quickstep.
+  if (parse_function_call.isWindow() &&
+      first_window_aggregate_function != nullptr) {
+    THROW_SQL_ERROR_AT(first_window_aggregate_function)
+        << "Window aggregation of window aggregates is not allowed";
+  }
+
   // Make sure a naked COUNT() with no arguments wasn't specified.
   if ((aggregate->getAggregationID() == AggregationID::kCount)
       && (resolved_arguments.empty())
@@ -2452,6 +2671,13 @@ E::ScalarPtr Resolver::resolveFunctionCall(
         << " can not apply to the given argument(s).";
   }
 
+  if (parse_function_call.isWindow()) {
+    return resolveWindowAggregateFunction(parse_function_call,
+                                          expression_resolution_info,
+                                          aggregate,
+                                          resolved_arguments);
+  }
+
   // Create the optimizer representation of the resolved aggregate and an alias
   // for it to appear in the output relation.
   const E::AggregateFunctionPtr aggregate_function
@@ -2471,6 +2697,62 @@ E::ScalarPtr Resolver::resolveFunctionCall(
   return E::ToRef(aggregate_alias);
 }
 
+E::ScalarPtr Resolver::resolveWindowAggregateFunction(
+    const ParseFunctionCall &parse_function_call,
+    ExpressionResolutionInfo *expression_resolution_info,
+    const ::quickstep::AggregateFunction *window_aggregate,
+    const std::vector<E::ScalarPtr> &resolved_arguments) {
+  // A window aggregate function might be defined OVER a window name or a window.
+  E::WindowAggregateFunctionPtr window_aggregate_function;
+  if (parse_function_call.window_name() != nullptr) {
+    std::unordered_map<std::string, WindowPlan> window_map
+        = expression_resolution_info->window_aggregation_info->window_map;
+    std::string window_name = parse_function_call.window_name()->value();
+    std::unordered_map<std::string, WindowPlan>::const_iterator map_it
+        = window_map.find(window_name);
+
+    if (map_it == window_map.end()) {
+      THROW_SQL_ERROR_AT(parse_function_call.window_name())
+          << "Undefined window " << window_name;
+    }
+
+    window_aggregate_function =
+        E::WindowAggregateFunction::Create(*window_aggregate,
+                                           resolved_arguments,
+                                           map_it->second.window_info,
+                                           parse_function_call.window_name()->value(),
+                                           parse_function_call.is_distinct());
+  } else {
+    E::WindowInfo resolved_window = resolveWindow(*parse_function_call.window(),
+                                                  expression_resolution_info->name_resolver);
+
+    window_aggregate_function =
+        E::WindowAggregateFunction::Create(*window_aggregate,
+                                           resolved_arguments,
+                                           resolved_window,
+                                           "" /* window name */,
+                                           parse_function_call.is_distinct());
+  }
+
+  const std::string internal_alias = GenerateWindowAggregateAttributeAlias(
+      expression_resolution_info->query_aggregation_info->aggregate_expressions.size());
+  const E::AliasPtr aggregate_alias = E::Alias::Create(context_->nextExprId(),
+                                                       window_aggregate_function,
+                                                       "" /* attribute_name */,
+                                                       internal_alias,
+                                                       "$window_aggregate" /* relation_name */);
+
+  if (!expression_resolution_info->window_aggregation_info->window_aggregate_expressions.empty()) {
+    THROW_SQL_ERROR_AT(&parse_function_call)
+        << "Currently we only support single window aggregate in the query";
+  }
+
+  expression_resolution_info->window_aggregation_info
+      ->window_aggregate_expressions.emplace_back(aggregate_alias);
+  expression_resolution_info->parse_window_aggregate_expression = &parse_function_call;
+  return E::ToRef(aggregate_alias);
+}
+
 std::vector<E::PredicatePtr> Resolver::resolvePredicates(
     const PtrList<ParsePredicate> &parse_predicates,
     ExpressionResolutionInfo *expression_resolution_info) {
@@ -2794,16 +3076,20 @@ void Resolver::rewriteIfOrdinalReference(
   }
 }
 
+std::string Resolver::GenerateWindowAggregateAttributeAlias(int index) {
+  return "$window_aggregate" + std::to_string(index);
+}
+
 std::string Resolver::GenerateAggregateAttributeAlias(int index) {
-  return std::string("$aggregate").append(std::to_string(index));
+  return "$aggregate" + std::to_string(index);
 }
 
 std::string Resolver::GenerateGroupingAttributeAlias(int index) {
-  return std::string("$groupby").append(std::to_string(index));
+  return "$groupby" + std::to_string(index);
 }
 
 std::string Resolver::GenerateOrderingAttributeAlias(int index) {
-  return std::string("$orderby").append(std::to_string(index));
+  return "$orderby" + std::to_string(index);
 }
 
 }  // namespace resolver

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/resolver/Resolver.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/Resolver.hpp b/query_optimizer/resolver/Resolver.hpp
index a84c61c..f4024e9 100644
--- a/query_optimizer/resolver/Resolver.hpp
+++ b/query_optimizer/resolver/Resolver.hpp
@@ -24,11 +24,13 @@
 #include <vector>
 
 #include "query_optimizer/expressions/AggregateFunction.hpp"
+#include "query_optimizer/expressions/Alias.hpp"
 #include "query_optimizer/expressions/ExprId.hpp"
 #include "query_optimizer/expressions/NamedExpression.hpp"
 #include "query_optimizer/expressions/Predicate.hpp"
 #include "query_optimizer/expressions/SubqueryExpression.hpp"
 #include "query_optimizer/expressions/Scalar.hpp"
+#include "query_optimizer/expressions/WindowAggregateFunction.hpp"
 #include "query_optimizer/logical/Logical.hpp"
 #include "utility/Macros.hpp"
 #include "utility/PtrVector.hpp"
@@ -65,6 +67,7 @@ class ParseSubqueryExpression;
 class ParseTableReference;
 class ParseTableReferenceSignature;
 class ParseTreeNode;
+class ParseWindow;
 template <class T>
 class PtrList;
 class StorageBlockLayoutDescription;
@@ -123,6 +126,17 @@ class Resolver {
   struct QueryAggregationInfo;
 
   /**
+   * @brief Query-scoped info that contains window aggregate expressions and a
+   *        window map.
+   **/
+  struct WindowAggregationInfo;
+
+  /**
+   * @brief A wrapper for resolved window and the corresponding sorted plan.
+   **/
+  struct WindowPlan;
+
+  /**
    * @brief Query-scoped info that contains select-list expressions
    *        and whether an expression is referenced by an
    *        ordinal or alias reference.
@@ -271,6 +285,8 @@ class Resolver {
    * @param name_resolver NameResolver to resolve the relation/attribute names.
    * @param query_aggregation_info Passed down to each expression to collects
    *                               aggregate expressions.
+   * @param window_aggregate_expressions Passed down to each expressions to
+   *                                     collects window aggregate expressions.
    * @param project_expressions Converted SELECT-list expressions.
    * @param has_aggregate_per_expression For each SELECT-list expression,
    *                                     indicates whether it contains
@@ -282,6 +298,7 @@ class Resolver {
       const std::vector<const Type*> *type_hints,
       const NameResolver &name_resolver,
       QueryAggregationInfo *query_aggregation_info,
+      WindowAggregationInfo *window_aggregation_info,
       std::vector<expressions::NamedExpressionPtr> *project_expressions,
       std::vector<bool> *has_aggregate_per_expression);
 
@@ -359,6 +376,17 @@ class Resolver {
       const ParseTableReferenceSignature &table_signature);
 
   /**
+   * @brief Sort the input table in (p_key, o_key) order specified by the window.
+   *
+   * @param logical_plan The input logical node.
+   * @param window_info The window that the input table has to be sorted accordingly.
+   * @return A logical plan that sorts the table according to window_info.
+   **/
+  logical::LogicalPtr resolveSortInWindow(
+      const logical::LogicalPtr &logical_plan,
+      const expressions::WindowInfo &window_info);
+
+  /**
    * @brief Resolves a parse expression and converts it to a scalar expression
    *        in the query optimizer. A non-scalar parse expression is resolved
    *        to an AttributeReference to another optimizer expression.
@@ -412,7 +440,8 @@ class Resolver {
    * @brief Resolves a function call. For a non-scalar function, the returned
    *        expression is an AttributeReference to the actual resolved expression.
    *
-   * @note This currently only handles resolving aggregate functions.
+   * @note This currently only handles resolving aggregate functions and window
+   *       aggregate functions.
    *
    * @param parse_function_call The function call to be resolved.
    * @param expression_resolution_info Resolution info that contains the name
@@ -425,6 +454,23 @@ class Resolver {
       ExpressionResolutionInfo *expression_resolution_info);
 
   /**
+   * @brief Resolves a window aggregate function.
+   *
+   * @param parse_function_call The function call to be resolved.
+   * @param expression_resolution_info Resolution info that contains the name
+   *                                   resolver and info to be updated after
+   *                                   resolution.
+   * @param aggregate The aggregate function.
+   * @param resolved_arguments The resolved arguments.
+   * @return An expression in the query optimizer.
+   */
+  expressions::ScalarPtr resolveWindowAggregateFunction(
+      const ParseFunctionCall &parse_function_call,
+      ExpressionResolutionInfo *expression_resolution_info,
+      const ::quickstep::AggregateFunction *aggregate,
+      const std::vector<expressions::ScalarPtr> &resolved_arguments);
+
+  /**
    * @brief Resolves a parse Predicate and converts it to a predicate in the
    *        query optimizer.
    *
@@ -469,6 +515,15 @@ class Resolver {
       const bool has_single_column);
 
   /**
+   * @brief Resolves a window definition.
+   *
+   * @param parse_window The parsed window definition.
+   * @param name_resolver The resolver to resolve names.
+   **/
+  expressions::WindowInfo resolveWindow(const ParseWindow &parse_window,
+                                        const NameResolver &name_resolver);
+
+  /**
    * @brief Resolves a relation name to a pointer to the corresponding
    *        CatalogRelation with the name.
    *
@@ -501,6 +556,15 @@ class Resolver {
   static std::string GenerateAggregateAttributeAlias(int index);
 
   /**
+   * @brief Generates an internal alias for a window aggregate attribute.
+   *
+   * @param index The index of the window aggregate attribute used for
+   *              generating the name.
+   * @return A string for the name.
+   */
+  static std::string GenerateWindowAggregateAttributeAlias(int index);
+
+  /**
    * @brief Generates an internal alias for a grouping attribute.
    *
    * @param index The index of the grouping attribute used for generating the

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/strategy/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/strategy/CMakeLists.txt b/query_optimizer/strategy/CMakeLists.txt
index 74f5a4b..84e151e 100644
--- a/query_optimizer/strategy/CMakeLists.txt
+++ b/query_optimizer/strategy/CMakeLists.txt
@@ -105,7 +105,8 @@ target_link_libraries(quickstep_queryoptimizer_strategy_OneToOne
                       quickstep_queryoptimizer_physical_TopLevelPlan
                       quickstep_queryoptimizer_physical_UpdateTable
                       quickstep_queryoptimizer_strategy_Strategy
-                      quickstep_utility_Macros)
+                      quickstep_utility_Macros
+                      quickstep_utility_SqlError)
 target_link_libraries(quickstep_queryoptimizer_strategy_Selection
                       glog
                       quickstep_queryoptimizer_LogicalToPhysicalMapper

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/strategy/OneToOne.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/strategy/OneToOne.cpp b/query_optimizer/strategy/OneToOne.cpp
index 7f59151..f49a25c 100644
--- a/query_optimizer/strategy/OneToOne.cpp
+++ b/query_optimizer/strategy/OneToOne.cpp
@@ -55,6 +55,7 @@
 #include "query_optimizer/physical/TableReference.hpp"
 #include "query_optimizer/physical/TopLevelPlan.hpp"
 #include "query_optimizer/physical/UpdateTable.hpp"
+#include "utility/SqlError.hpp"
 
 namespace quickstep {
 namespace optimizer {
@@ -208,6 +209,10 @@ bool OneToOne::generatePlan(const L::LogicalPtr &logical_input,
           update_table->predicate());
       return true;
     }
+    case L::LogicalType::kWindowAggregate: {
+      THROW_SQL_ERROR()
+          << "Window aggregate function is not supported currently :(";
+    }
     default:
       return false;
   }

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/tests/logical_generator/Select.test
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/logical_generator/Select.test b/query_optimizer/tests/logical_generator/Select.test
index 3c152e8..e0003bf 100644
--- a/query_optimizer/tests/logical_generator/Select.test
+++ b/query_optimizer/tests/logical_generator/Select.test
@@ -1354,3 +1354,165 @@ TopLevelPlan
 +-output_attributes=
   +-AttributeReference[id=5,name=x,relation=,type=Int]
   +-AttributeReference[id=6,name=y,relation=,type=Int]
+==
+
+# Window Aggregate Function Test.
+SELECT avg(int_col) OVER w FROM test
+WINDOW w AS
+(PARTITION BY char_col
+ ORDER BY long_col DESC NULLS LAST
+ ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW);
+--
+TopLevelPlan
++-plan=Project
+| +-input=WindowAggregate
+| | +-input=Sort[is_ascending=[true,false],nulls_first=[false,false]]
+| | | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | | +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | | |   type=VarChar(20) NULL]
+| | | +-sort_expressions=
+| | |   +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | |   +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | +-window_aggregate_expression=Alias[id=6,name=,alias=$window_aggregate0,
+| |   relation=$window_aggregate,type=Double NULL]
+| |   +-WindowAggregateFunction[function=AVG,window_name=w,is_ascending=[false],
+| |     nulls_first=[false],frame_mode=row,num_preceding=-1,num_following=0]
+| |     +-arguments=
+| |     | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| |     +-partition_by=
+| |     | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| |     +-order_by=
+| |       +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| +-project_list=
+|   +-Alias[id=6,name=,alias=avg(int_col),relation=,type=Double NULL]
+|     +-AttributeReference[id=6,name=,alias=$window_aggregate0,
+|       relation=$window_aggregate,type=Double NULL]
++-output_attributes=
+  +-AttributeReference[id=6,name=,alias=avg(int_col),relation=,type=Double NULL]
+==
+
+SELECT int_col, sum(float_col) OVER
+(PARTITION BY vchar_col, long_col
+ ORDER BY double_col DESC NULLS LAST, int_col ASC NULLS FIRST
+ RANGE BETWEEN 3 PRECEDING AND 3 FOLLOWING)
+FROM test;
+--
+TopLevelPlan
++-plan=Project
+| +-input=WindowAggregate
+| | +-input=Sort[is_ascending=[true,true,false,true],
+| | | nulls_first=[false,false,false,true]]
+| | | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | | +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | | |   type=VarChar(20) NULL]
+| | | +-sort_expressions=
+| | |   +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | |   | type=VarChar(20) NULL]
+| | |   +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | |   +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | |   +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | +-window_aggregate_expression=Alias[id=6,name=,alias=$window_aggregate0,
+| |   relation=$window_aggregate,type=Double NULL]
+| |   +-WindowAggregateFunction[function=SUM,window_name=,
+| |     is_ascending=[false,true],nulls_first=[false,true],frame_mode=range,
+| |     num_preceding=3,num_following=3]
+| |     +-arguments=
+| |     | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| |     +-partition_by=
+| |     | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| |     | | type=VarChar(20) NULL]
+| |     | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| |     +-order_by=
+| |       +-AttributeReference[id=3,name=double_col,relation=test,
+| |       | type=Double NULL]
+| |       +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| +-project_list=
+|   +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+|   +-Alias[id=6,name=,alias=sum(float_col),relation=,type=Double NULL]
+|     +-AttributeReference[id=6,name=,alias=$window_aggregate0,
+|       relation=$window_aggregate,type=Double NULL]
++-output_attributes=
+  +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+  +-AttributeReference[id=6,name=,alias=sum(float_col),relation=,
+    type=Double NULL]
+==
+
+SELECT sum(avg(int_col) OVER w) FROM test
+WINDOW w AS
+(PARTITION BY char_col
+ ORDER BY long_col
+ ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW);
+--
+TopLevelPlan
++-plan=Project
+| +-input=Aggregate
+| | +-input=WindowAggregate
+| | | +-input=Sort[is_ascending=[true,true],nulls_first=[false,false]]
+| | | | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | | | +-AttributeReference[id=3,name=double_col,relation=test,
+| | | | | | type=Double NULL]
+| | | | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | | | |   type=VarChar(20) NULL]
+| | | | +-sort_expressions=
+| | | |   +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | |   +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | +-window_aggregate_expression=Alias[id=6,name=,alias=$window_aggregate0,
+| | |   relation=$window_aggregate,type=Double NULL]
+| | |   +-WindowAggregateFunction[function=AVG,window_name=w,
+| | |     is_ascending=[true],nulls_first=[false],frame_mode=row,
+| | |     num_preceding=-1,num_following=0]
+| | |     +-arguments=
+| | |     | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | |     +-partition_by=
+| | |     | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | |     +-order_by=
+| | |       +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | +-grouping_expressions=
+| | | +-[]
+| | +-aggregate_expressions=
+| |   +-Alias[id=7,name=,alias=$aggregate0,relation=$aggregate,type=Double NULL]
+| |     +-AggregateFunction[function=SUM]
+| |       +-AttributeReference[id=6,name=,alias=$window_aggregate0,
+| |         relation=$window_aggregate,type=Double NULL]
+| +-project_list=
+|   +-Alias[id=7,name=,alias=sum(avg(int_col)),relation=,type=Double NULL]
+|     +-AttributeReference[id=7,name=,alias=$aggregate0,relation=$aggregate,
+|       type=Double NULL]
++-output_attributes=
+  +-AttributeReference[id=7,name=,alias=sum(avg(int_col)),relation=,
+    type=Double NULL]
+==
+
+SELECT int_col, sum(float_col) OVER w1 FROM test
+WINDOW w2 AS
+(PARTITION BY vchar_col, long_col
+ ORDER BY double_col DESC NULLS LAST, int_col ASC NULLS FIRST
+ RANGE BETWEEN 3 PRECEDING AND 3 FOLLOWING);
+--
+ERROR: Undefined window w1 (1 : 37)
+SELECT int_col, sum(float_col) OVER w1 FROM test
+                                    ^
+==
+
+SELECT sum(avg(int_col)) OVER w FROM test
+WINDOW w AS
+(PARTITION BY double_col
+ ORDER BY char_col)
+--
+ERROR: Aggregation of Aggregates are not allowed (1 : 12)
+SELECT sum(avg(int_col)) OVER w FROM test
+           ^

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/714874ce/query_optimizer/tests/resolver/Select.test
----------------------------------------------------------------------
diff --git a/query_optimizer/tests/resolver/Select.test b/query_optimizer/tests/resolver/Select.test
index 141bfa0..89ab84d 100644
--- a/query_optimizer/tests/resolver/Select.test
+++ b/query_optimizer/tests/resolver/Select.test
@@ -3126,3 +3126,165 @@ FROM test;
 ERROR: The substring length must be greater than 0 (1 : 8)
 SELECT SUBSTRING(char_col FROM 1 FOR ...
        ^
+==
+
+# Window Aggregate Function Test.
+SELECT avg(int_col) OVER w FROM test
+WINDOW w AS
+(PARTITION BY char_col
+ ORDER BY long_col DESC NULLS LAST
+ ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW);
+--
+TopLevelPlan
++-plan=Project
+| +-input=WindowAggregate
+| | +-input=Sort[is_ascending=[true,false],nulls_first=[false,false]]
+| | | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | | +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | | |   type=VarChar(20) NULL]
+| | | +-sort_expressions=
+| | |   +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | |   +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | +-window_aggregate_expression=Alias[id=6,name=,alias=$window_aggregate0,
+| |   relation=$window_aggregate,type=Double NULL]
+| |   +-WindowAggregateFunction[function=AVG,window_name=w,is_ascending=[false],
+| |     nulls_first=[false],frame_mode=row,num_preceding=-1,num_following=0]
+| |     +-arguments=
+| |     | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| |     +-partition_by=
+| |     | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| |     +-order_by=
+| |       +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| +-project_list=
+|   +-Alias[id=6,name=,alias=avg(int_col),relation=,type=Double NULL]
+|     +-AttributeReference[id=6,name=,alias=$window_aggregate0,
+|       relation=$window_aggregate,type=Double NULL]
++-output_attributes=
+  +-AttributeReference[id=6,name=,alias=avg(int_col),relation=,type=Double NULL]
+==
+
+SELECT int_col, sum(float_col) OVER
+(PARTITION BY vchar_col, long_col
+ ORDER BY double_col DESC NULLS LAST, int_col ASC NULLS FIRST
+ RANGE BETWEEN 3 PRECEDING AND 3 FOLLOWING)
+FROM test;
+--
+TopLevelPlan
++-plan=Project
+| +-input=WindowAggregate
+| | +-input=Sort[is_ascending=[true,true,false,true],
+| | | nulls_first=[false,false,false,true]]
+| | | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | | +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | | |   type=VarChar(20) NULL]
+| | | +-sort_expressions=
+| | |   +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | |   | type=VarChar(20) NULL]
+| | |   +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | |   +-AttributeReference[id=3,name=double_col,relation=test,type=Double NULL]
+| | |   +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | +-window_aggregate_expression=Alias[id=6,name=,alias=$window_aggregate0,
+| |   relation=$window_aggregate,type=Double NULL]
+| |   +-WindowAggregateFunction[function=SUM,window_name=,
+| |     is_ascending=[false,true],nulls_first=[false,true],frame_mode=range,
+| |     num_preceding=3,num_following=3]
+| |     +-arguments=
+| |     | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| |     +-partition_by=
+| |     | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| |     | | type=VarChar(20) NULL]
+| |     | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| |     +-order_by=
+| |       +-AttributeReference[id=3,name=double_col,relation=test,
+| |       | type=Double NULL]
+| |       +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| +-project_list=
+|   +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+|   +-Alias[id=6,name=,alias=sum(float_col),relation=,type=Double NULL]
+|     +-AttributeReference[id=6,name=,alias=$window_aggregate0,
+|       relation=$window_aggregate,type=Double NULL]
++-output_attributes=
+  +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+  +-AttributeReference[id=6,name=,alias=sum(float_col),relation=,
+    type=Double NULL]
+==
+
+SELECT sum(avg(int_col) OVER w) FROM test
+WINDOW w AS
+(PARTITION BY char_col
+ ORDER BY long_col
+ ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW);
+--
+TopLevelPlan
++-plan=Project
+| +-input=Aggregate
+| | +-input=WindowAggregate
+| | | +-input=Sort[is_ascending=[true,true],nulls_first=[false,false]]
+| | | | +-input=TableReference[relation_name=Test,relation_alias=test]
+| | | | | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | | | | +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | | | +-AttributeReference[id=2,name=float_col,relation=test,type=Float]
+| | | | | +-AttributeReference[id=3,name=double_col,relation=test,
+| | | | | | type=Double NULL]
+| | | | | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | | | +-AttributeReference[id=5,name=vchar_col,relation=test,
+| | | | |   type=VarChar(20) NULL]
+| | | | +-sort_expressions=
+| | | |   +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | | |   +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | | +-window_aggregate_expression=Alias[id=6,name=,alias=$window_aggregate0,
+| | |   relation=$window_aggregate,type=Double NULL]
+| | |   +-WindowAggregateFunction[function=AVG,window_name=w,
+| | |     is_ascending=[true],nulls_first=[false],frame_mode=row,
+| | |     num_preceding=-1,num_following=0]
+| | |     +-arguments=
+| | |     | +-AttributeReference[id=0,name=int_col,relation=test,type=Int NULL]
+| | |     +-partition_by=
+| | |     | +-AttributeReference[id=4,name=char_col,relation=test,type=Char(20)]
+| | |     +-order_by=
+| | |       +-AttributeReference[id=1,name=long_col,relation=test,type=Long]
+| | +-grouping_expressions=
+| | | +-[]
+| | +-aggregate_expressions=
+| |   +-Alias[id=7,name=,alias=$aggregate0,relation=$aggregate,type=Double NULL]
+| |     +-AggregateFunction[function=SUM]
+| |       +-AttributeReference[id=6,name=,alias=$window_aggregate0,
+| |         relation=$window_aggregate,type=Double NULL]
+| +-project_list=
+|   +-Alias[id=7,name=,alias=sum(avg(int_col)),relation=,type=Double NULL]
+|     +-AttributeReference[id=7,name=,alias=$aggregate0,relation=$aggregate,
+|       type=Double NULL]
++-output_attributes=
+  +-AttributeReference[id=7,name=,alias=sum(avg(int_col)),relation=,
+    type=Double NULL]
+==
+
+SELECT int_col, sum(float_col) OVER w1 FROM test
+WINDOW w2 AS
+(PARTITION BY vchar_col, long_col
+ ORDER BY double_col DESC NULLS LAST, int_col ASC NULLS FIRST
+ RANGE BETWEEN 3 PRECEDING AND 3 FOLLOWING);
+--
+ERROR: Undefined window w1 (1 : 37)
+SELECT int_col, sum(float_col) OVER w1 FROM test
+                                    ^
+==
+
+SELECT sum(avg(int_col)) OVER w FROM test
+WINDOW w AS
+(PARTITION BY double_col
+ ORDER BY char_col)
+--
+ERROR: Aggregation of Aggregates are not allowed (1 : 12)
+SELECT sum(avg(int_col)) OVER w FROM test
+           ^