You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@quickstep.apache.org by sh...@apache.org on 2016/06/21 20:09:45 UTC
incubator-quickstep git commit: Window Aggregation Function in
optimizer::expression added The resolver could understand optional window
clause. The resolver could understand window aggregation functions. Only one
window aggregation function is allowed
Repository: incubator-quickstep
Updated Branches:
refs/heads/SQL-window-aggregation [created] ae66fbe46
Window Aggregation Function in optimizer::expression added
The resolver could understand optional window clause.
The resolver could understand window 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/ae66fbe4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/tree/ae66fbe4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/diff/ae66fbe4
Branch: refs/heads/SQL-window-aggregation
Commit: ae66fbe467cfad0667efe87412f472e673c7cdc7
Parents: 00ca1e4
Author: shixuan <sh...@wisc.edu>
Authored: Tue Jun 21 20:08:52 2016 +0000
Committer: shixuan <sh...@wisc.edu>
Committed: Tue Jun 21 20:08:52 2016 +0000
----------------------------------------------------------------------
query_optimizer/expressions/CMakeLists.txt | 1 +
query_optimizer/expressions/ExpressionType.hpp | 3 +-
.../expressions/WindowAggregateFunction.cpp | 141 +++++++++
.../expressions/WindowAggregateFunction.hpp | 254 ++++++++++++++++
query_optimizer/resolver/Resolver.cpp | 294 ++++++++++++++++++-
query_optimizer/resolver/Resolver.hpp | 41 ++-
6 files changed, 727 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/ae66fbe4/query_optimizer/expressions/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/query_optimizer/expressions/CMakeLists.txt b/query_optimizer/expressions/CMakeLists.txt
index 6c40741..e019c8e 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
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/ae66fbe4/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/ae66fbe4/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..b980c99
--- /dev/null
+++ b/query_optimizer/expressions/WindowAggregateFunction.cpp
@@ -0,0 +1,141 @@
+/**
+ * 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 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, "", is_distinct));
+}
+
+WindowAggregateFunctionPtr WindowAggregateFunction::Create(
+ const ::quickstep::AggregateFunction &window_aggregate,
+ const std::vector<ScalarPtr> &arguments,
+ 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, nullptr, 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 Create(window_aggregate_, new_arguments, window_info_, 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());
+ }
+ 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());
+
+ if (is_distinct_) {
+ inline_field_names->push_back("is_distinct");
+ inline_field_values->push_back("true");
+ }
+
+ container_child_field_names->push_back("");
+ container_child_fields->emplace_back(CastSharedPtrVector<OptimizerTreeBase>(arguments_));
+}
+
+} // namespace expressions
+} // namespace optimizer
+} // namespace quickstep
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/ae66fbe4/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..ca7e449
--- /dev/null
+++ b/query_optimizer/expressions/WindowAggregateFunction.hpp
@@ -0,0 +1,254 @@
+/**
+ * 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.
+ **/
+ explicit 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.
+ **/
+ explicit 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),
+ 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& getWindowAggregate() const {
+ return window_aggregate_;
+ }
+
+ /**
+ * @return The list of scalar arguments to this aggregate.
+ **/
+ inline const std::vector<ScalarPtr>& getArguments() const {
+ return arguments_;
+ }
+
+ /**
+ * @return The window info of this window aggregate function.
+ **/
+ inline const WindowInfo* getWindowInfo() const {
+ return window_info_;
+ }
+
+ /**
+ * @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 bool is_distinct);
+
+ /**
+ * @brief Create a new WindowAggregateFunction by window name.
+ *
+ * @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_name The window name 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 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_AGGREGATE_FUNCTION_HPP_ */
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/ae66fbe4/query_optimizer/resolver/Resolver.cpp
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/Resolver.cpp b/query_optimizer/resolver/Resolver.cpp
index ffc173a..7895f6c 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"
@@ -187,16 +188,28 @@ 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;
+ // Alias expressions that wraps window aggregate functions
+ std::vector<E::AliasPtr> window_aggregate_expressions;
+
// Can be NULL if aggregations are not allowed.
QueryAggregationInfo *query_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 +222,16 @@ struct Resolver::QueryAggregationInfo {
std::vector<E::AliasPtr> aggregate_expressions;
};
+struct Resolver::WindowAggregationInfo {
+ explicit WindowAggregationInfo(E::WindowInfo window_info_in,
+ 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::SelectListInfo {
public:
/**
@@ -973,6 +996,49 @@ L::LogicalPtr Resolver::resolveSelect(
logical_plan, resolvePredicate(parse_predicate, &expr_resolution_info));
}
+ // Resolve WINDOW clause.
+ std::unordered_map<std::string, WindowAggregationInfo> sorted_window_table;
+ 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";
+ }
+
+ for (const ParseWindow &window : *select_query.window_list()) {
+ E::WindowInfo resolved_window = resolveWindow(window, *name_resolver);
+
+ // Sort the table by (p_key, o_key)
+ std::vector<E::AttributeReferencePtr> sort_attributes(resolved_window.partition_by_attributes);
+ sort_attributes.insert(sort_attributes.end(),
+ resolved_window.order_by_attributes.begin(),
+ resolved_window.order_by_attributes.end());
+
+ std::vector<bool> sort_directions(
+ resolved_window.partition_by_attributes.size(), true);
+ sort_directions.insert(sort_directions.end(),
+ resolved_window.order_by_directions.begin(),
+ resolved_window.order_by_directions.end());
+
+ std::vector<bool> sort_nulls_first(
+ resolved_window.partition_by_attributes.size(), false);
+ sort_nulls_first.insert(sort_nulls_first.end(),
+ resolved_window.nulls_first.begin(),
+ resolved_window.nulls_first.end());
+
+ L::LogicalPtr sorted_logical_plan =
+ L::Sort::Create(logical_plan,
+ sort_attributes,
+ sort_directions,
+ sort_nulls_first,
+ -1 /* limit */);
+
+ WindowAggregationInfo window_aggregation_info(resolved_window,
+ sorted_logical_plan);
+
+ sorted_window_table.emplace(window.name()->value(), window_aggregation_info);
+ }
+ }
+
QueryAggregationInfo query_aggregation_info(
(select_query.group_by() != nullptr));
@@ -1528,6 +1594,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 =
@@ -2362,17 +2511,19 @@ 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.
+ // Check if it is a window function.
if (parse_function_call.isWindow()) {
- THROW_SQL_ERROR_AT(&parse_function_call)
- << "Window Aggregation Function is not supported currently";
+ return resolveWindowAggregateFunction(parse_function_call,
+ expression_resolution_info);
}
+ std::string function_name = ToLower(parse_function_call.name()->value());
+
// First check for the special case COUNT(*).
bool count_star = false;
if (parse_function_call.star() != nullptr) {
@@ -2471,6 +2622,135 @@ E::ScalarPtr Resolver::resolveFunctionCall(
return E::ToRef(aggregate_alias);
}
+E::ScalarPtr Resolver::resolveWindowAggregateFunction(
+ const ParseFunctionCall &parse_function_call,
+ ExpressionResolutionInfo *expression_resolution_info) {
+ std::string function_name = ToLower(parse_function_call.name()->value());
+
+ // First check for the special case COUNT(*).
+ bool count_star = false;
+ if (parse_function_call.star() != nullptr) {
+ if (function_name != "count") {
+ THROW_SQL_ERROR_AT(parse_function_call.star())
+ << "Only COUNT can have star (*) as an argument";
+ }
+ count_star = true;
+ }
+
+ std::vector<E::ScalarPtr> resolved_arguments;
+ const PtrList<ParseExpression> *unresolved_arguments =
+ parse_function_call.arguments();
+ // The first 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(
+ *expression_resolution_info);
+ resolved_arguments.push_back(
+ resolveExpression(unresolved_argument,
+ nullptr, // No Type hint.
+ &expr_resolution_info));
+
+ // We don't allow aggregate or window aggregate nested in a window
+ // aggregate function
+ if (expr_resolution_info.hasAggregate() &&
+ first_aggregate_function == nullptr) {
+ first_aggregate_function =
+ expr_resolution_info.parse_aggregate_expression;
+ }
+
+ if (expr_resolution_info.hasWindowAggregate() &&
+ first_window_aggregate_function == nullptr) {
+ first_window_aggregate_function =
+ expr_resolution_info.parse_window_aggregate_expression;
+ }
+ }
+ }
+
+ if (count_star && !resolved_arguments.empty()) {
+ THROW_SQL_ERROR_AT(&parse_function_call)
+ << "COUNT aggregate has both star (*) and non-star arguments.";
+ }
+
+ // Try to look up the AggregateFunction by name using
+ // AggregateFunctionFactory.
+ const ::quickstep::AggregateFunction *window_aggregate
+ = AggregateFunctionFactory::GetByName(function_name);
+ if (window_aggregate == nullptr) {
+ THROW_SQL_ERROR_AT(&parse_function_call)
+ << "Unrecognized function name \""
+ << parse_function_call.name()->value()
+ << "\"";
+ }
+
+ // Make sure aggregates are allowed in this context.
+ if (first_aggregate_function != nullptr) {
+ THROW_SQL_ERROR_AT(first_aggregate_function)
+ << "Window 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 (first_window_aggregate_function != nullptr) {
+ THROW_SQL_ERROR_AT(first_window_aggregate_function)
+ << "Window Aggregation of Window Aggregates are not allowed";
+ }
+
+ // Make sure a naked COUNT() with no arguments wasn't specified.
+ if ((window_aggregate->getAggregationID() == AggregationID::kCount)
+ && (resolved_arguments.empty())
+ && (!count_star)) {
+ THROW_SQL_ERROR_AT(&parse_function_call)
+ << "COUNT aggregate requires an argument (either scalar or star (*))";
+ }
+
+ // Resolve each of the Scalar arguments to the aggregate.
+ std::vector<const Type*> argument_types;
+ for (const E::ScalarPtr &argument : resolved_arguments) {
+ argument_types.emplace_back(&argument->getValueType());
+ }
+
+ // Make sure that the aggregate can apply to the specified argument(s).
+ if (!window_aggregate->canApplyToTypes(argument_types)) {
+ THROW_SQL_ERROR_AT(&parse_function_call)
+ << "Aggregate function " << window_aggregate->getName()
+ << " can not apply to the given argument(s).";
+ }
+
+ // 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) {
+ window_aggregate_function =
+ E::WindowAggregateFunction::Create(*window_aggregate,
+ resolved_arguments,
+ 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,
+ parse_function_call.is_distinct());
+ }
+
+ const std::string internal_alias = GenerateAggregateAttributeAlias(
+ 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 */);
+
+ expression_resolution_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,6 +3074,10 @@ void Resolver::rewriteIfOrdinalReference(
}
}
+std::string Resolver::GenerateWindowAggregateAttributeAlias(int index) {
+ return std::string("$window_aggregate").append(std::to_string(index));
+}
+
std::string Resolver::GenerateAggregateAttributeAlias(int index) {
return std::string("$aggregate").append(std::to_string(index));
}
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/ae66fbe4/query_optimizer/resolver/Resolver.hpp
----------------------------------------------------------------------
diff --git a/query_optimizer/resolver/Resolver.hpp b/query_optimizer/resolver/Resolver.hpp
index a84c61c..1c7dad5 100644
--- a/query_optimizer/resolver/Resolver.hpp
+++ b/query_optimizer/resolver/Resolver.hpp
@@ -29,6 +29,7 @@
#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 +66,7 @@ class ParseSubqueryExpression;
class ParseTableReference;
class ParseTableReferenceSignature;
class ParseTreeNode;
+class ParseWindow;
template <class T>
class PtrList;
class StorageBlockLayoutDescription;
@@ -123,6 +125,11 @@ class Resolver {
struct QueryAggregationInfo;
/**
+ * @brief A wrapper for resolved window and the corresponding sorted plan.
+ **/
+ struct WindowAggregationInfo;
+
+ /**
* @brief Query-scoped info that contains select-list expressions
* and whether an expression is referenced by an
* ordinal or alias reference.
@@ -412,7 +419,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 +433,19 @@ 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.
+ * @return An expression in the query optimizer.
+ */
+ expressions::ScalarPtr resolveWindowAggregateFunction(
+ const ParseFunctionCall &parse_function_call,
+ ExpressionResolutionInfo *expression_resolution_info);
+
+ /**
* @brief Resolves a parse Predicate and converts it to a predicate in the
* query optimizer.
*
@@ -469,6 +490,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 +531,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