#include #include #include namespace DB { namespace ErrorCodes { extern const int BAD_ARGUMENTS; } std::string WindowFunctionDescription::dump() const { WriteBufferFromOwnString ss; ss << "window function '" << column_name << "\n"; ss << "function node " << function_node->dumpTree() << "\n"; ss << "aggregate function '" << aggregate_function->getName() << "'\n"; if (!function_parameters.empty()) { ss << "parameters " << toString(function_parameters) << "\n"; } return ss.str(); } std::string WindowDescription::dump() const { WriteBufferFromOwnString ss; ss << "window '" << window_name << "'\n"; ss << "partition_by " << dumpSortDescription(partition_by) << "\n"; ss << "order_by " << dumpSortDescription(order_by) << "\n"; ss << "full_sort_description " << dumpSortDescription(full_sort_description) << "\n"; return ss.str(); } std::string WindowFrame::toString() const { WriteBufferFromOwnString buf; toString(buf); return buf.str(); } void WindowFrame::toString(WriteBuffer & buf) const { buf << toString(type) << " BETWEEN "; if (begin_type == BoundaryType::Current) { buf << "CURRENT ROW"; } else if (begin_type == BoundaryType::Unbounded) { buf << "UNBOUNDED"; buf << " " << (begin_preceding ? "PRECEDING" : "FOLLOWING"); } else { buf << abs(begin_offset); buf << " " << (begin_preceding ? "PRECEDING" : "FOLLOWING"); } buf << " AND "; if (end_type == BoundaryType::Current) { buf << "CURRENT ROW"; } else if (end_type == BoundaryType::Unbounded) { buf << "UNBOUNDED"; buf << " " << (end_preceding ? "PRECEDING" : "FOLLOWING"); } else { buf << abs(end_offset); buf << " " << (end_preceding ? "PRECEDING" : "FOLLOWING"); } } void WindowFrame::checkValid() const { // UNBOUNDED PRECEDING end and UNBOUNDED FOLLOWING start should have been // forbidden at the parsing level. assert(!(begin_type == BoundaryType::Unbounded && !begin_preceding)); assert(!(end_type == BoundaryType::Unbounded && end_preceding)); if (begin_type == BoundaryType::Unbounded || end_type == BoundaryType::Unbounded) { return; } if (begin_type == BoundaryType::Current && end_type == BoundaryType::Offset && !end_preceding) { return; } if (end_type == BoundaryType::Current && begin_type == BoundaryType::Offset && begin_preceding) { return; } if (end_type == BoundaryType::Current && begin_type == BoundaryType::Current) { // BETWEEN CURRENT ROW AND CURRENT ROW makes some sense for RANGE or // GROUP frames, and is technically valid for ROWS frame. return; } if (end_type == BoundaryType::Offset && begin_type == BoundaryType::Offset) { if (!(end_preceding && !begin_preceding)) { // Should probably check here that starting offset is less than // ending offset, but with regard to ORDER BY direction for RANGE // frames. return; } } throw Exception(ErrorCodes::BAD_ARGUMENTS, "Window frame '{}' is invalid", toString()); } }