#include #include #include #include #include #include #include #include #include namespace DB { FunctionNode::FunctionNode(String function_name_) : IQueryTreeNode(children_size) , function_name(function_name_) { children[parameters_child_index] = std::make_shared(); children[arguments_child_index] = std::make_shared(); } ColumnsWithTypeAndName FunctionNode::getArgumentTypes() const { ColumnsWithTypeAndName argument_types; for (const auto & arg : getArguments().getNodes()) { ColumnWithTypeAndName argument; argument.type = arg->getResultType(); argument_types.push_back(argument); } return argument_types; } void FunctionNode::resolveAsFunction(FunctionBasePtr function_value) { function_name = function_value->getName(); function = std::move(function_value); kind = FunctionKind::ORDINARY; } void FunctionNode::resolveAsAggregateFunction(AggregateFunctionPtr aggregate_function_value) { function_name = aggregate_function_value->getName(); function = std::move(aggregate_function_value); kind = FunctionKind::AGGREGATE; } void FunctionNode::resolveAsWindowFunction(AggregateFunctionPtr window_function_value) { if (!hasWindow()) throw Exception(ErrorCodes::LOGICAL_ERROR, "Trying to resolve FunctionNode without window definition as a window function {}", window_function_value->getName()); resolveAsAggregateFunction(window_function_value); kind = FunctionKind::WINDOW; } void FunctionNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const { buffer << std::string(indent, ' ') << "FUNCTION id: " << format_state.getNodeId(this); if (hasAlias()) buffer << ", alias: " << getAlias(); buffer << ", function_name: " << function_name; std::string function_type = "ordinary"; if (isAggregateFunction()) function_type = "aggregate"; else if (isWindowFunction()) function_type = "window"; buffer << ", function_type: " << function_type; if (function) buffer << ", result_type: " + function->getResultType()->getName(); const auto & parameters = getParameters(); if (!parameters.getNodes().empty()) { buffer << '\n' << std::string(indent + 2, ' ') << "PARAMETERS\n"; parameters.dumpTreeImpl(buffer, format_state, indent + 4); } const auto & arguments = getArguments(); if (!arguments.getNodes().empty()) { buffer << '\n' << std::string(indent + 2, ' ') << "ARGUMENTS\n"; arguments.dumpTreeImpl(buffer, format_state, indent + 4); } if (hasWindow()) { buffer << '\n' << std::string(indent + 2, ' ') << "WINDOW\n"; getWindowNode()->dumpTreeImpl(buffer, format_state, indent + 4); } } bool FunctionNode::isEqualImpl(const IQueryTreeNode & rhs) const { const auto & rhs_typed = assert_cast(rhs); if (function_name != rhs_typed.function_name || isAggregateFunction() != rhs_typed.isAggregateFunction() || isOrdinaryFunction() != rhs_typed.isOrdinaryFunction() || isWindowFunction() != rhs_typed.isWindowFunction()) return false; auto lhs_result_type = getResultType(); auto rhs_result_type = rhs.getResultType(); if (lhs_result_type && rhs_result_type && !lhs_result_type->equals(*rhs_result_type)) return false; else if (lhs_result_type && !rhs_result_type) return false; else if (!lhs_result_type && rhs_result_type) return false; return true; } void FunctionNode::updateTreeHashImpl(HashState & hash_state) const { hash_state.update(function_name.size()); hash_state.update(function_name); hash_state.update(isOrdinaryFunction()); hash_state.update(isAggregateFunction()); hash_state.update(isWindowFunction()); if (auto result_type = getResultType()) { auto result_type_name = result_type->getName(); hash_state.update(result_type_name.size()); hash_state.update(result_type_name); } } QueryTreeNodePtr FunctionNode::cloneImpl() const { auto result_function = std::make_shared(function_name); /** This is valid for clone method to reuse same function pointers * because ordinary functions or aggregate functions must be stateless. */ result_function->function = function; result_function->kind = kind; return result_function; } ASTPtr FunctionNode::toASTImpl() const { auto function_ast = std::make_shared(); function_ast->name = function_name; if (isWindowFunction()) { function_ast->is_window_function = true; function_ast->kind = ASTFunction::Kind::WINDOW_FUNCTION; } const auto & parameters = getParameters(); if (!parameters.getNodes().empty()) { function_ast->children.push_back(parameters.toAST()); function_ast->parameters = function_ast->children.back(); } const auto & arguments = getArguments(); function_ast->children.push_back(arguments.toAST()); function_ast->arguments = function_ast->children.back(); auto window_node = getWindowNode(); if (window_node) { if (auto * identifier_node = window_node->as()) function_ast->window_name = identifier_node->getIdentifier().getFullName(); else function_ast->window_definition = window_node->toAST(); } return function_ast; } }