ClickHouse/src/Interpreters/WindowDescription.cpp

165 lines
4.4 KiB
C++
Raw Normal View History

2021-01-30 01:16:44 +00:00
#include <Interpreters/WindowDescription.h>
#include <IO/Operators.h>
#include <Parsers/ASTFunction.h>
namespace DB
{
2021-02-03 13:33:50 +00:00
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
}
2021-01-30 01:16:44 +00:00
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();
}
2021-02-03 12:50:25 +00:00
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)
{
2021-02-09 11:56:11 +00:00
buf << "UNBOUNDED";
buf << " "
<< (begin_preceding ? "PRECEDING" : "FOLLOWING");
2021-02-03 12:50:25 +00:00
}
else
{
buf << abs(begin_offset);
buf << " "
2021-02-05 09:13:19 +00:00
<< (begin_preceding ? "PRECEDING" : "FOLLOWING");
2021-02-03 12:50:25 +00:00
}
buf << " AND ";
if (end_type == BoundaryType::Current)
{
buf << "CURRENT ROW";
}
else if (end_type == BoundaryType::Unbounded)
{
2021-02-09 11:56:11 +00:00
buf << "UNBOUNDED";
buf << " "
<< (end_preceding ? "PRECEDING" : "FOLLOWING");
2021-02-03 12:50:25 +00:00
}
else
{
buf << abs(end_offset);
buf << " "
2021-02-05 09:13:19 +00:00
<< (end_preceding ? "PRECEDING" : "FOLLOWING");
2021-02-03 12:50:25 +00:00
}
}
void WindowFrame::checkValid() const
{
2021-02-05 09:13:19 +00:00
// 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));
2021-02-03 12:50:25 +00:00
if (begin_type == BoundaryType::Unbounded
|| end_type == BoundaryType::Unbounded)
{
return;
}
if (begin_type == BoundaryType::Current
&& end_type == BoundaryType::Offset
2021-02-05 09:13:19 +00:00
&& !end_preceding)
2021-02-03 12:50:25 +00:00
{
return;
}
if (end_type == BoundaryType::Current
&& begin_type == BoundaryType::Offset
2021-02-05 09:13:19 +00:00
&& begin_preceding)
2021-02-03 12:50:25 +00:00
{
return;
}
2021-02-03 14:55:40 +00:00
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;
}
2021-02-04 07:41:09 +00:00
if (end_type == BoundaryType::Offset
&& begin_type == BoundaryType::Offset)
{
2021-02-09 15:36:08 +00:00
// Frame starting with following rows can't have preceding rows.
2021-02-05 09:13:19 +00:00
if (!(end_preceding && !begin_preceding))
2021-02-04 07:41:09 +00:00
{
2021-02-09 15:36:08 +00:00
// Frame start offset must be less or equal that the frame end offset.
const bool begin_before_end
= begin_offset * (begin_preceding ? -1 : 1)
<= end_offset * (end_preceding ? -1 : 1);
if (!begin_before_end)
{
throw Exception(ErrorCodes::BAD_ARGUMENTS,
"Frame start offset {} {} does not precede the frame end offset {} {}",
begin_offset, begin_preceding ? "PRECEDING" : "FOLLOWING",
end_offset, end_preceding ? "PRECEDING" : "FOLLOWING");
}
2021-02-09 11:56:11 +00:00
return;
2021-02-04 07:41:09 +00:00
}
}
2021-02-03 12:50:25 +00:00
throw Exception(ErrorCodes::BAD_ARGUMENTS,
"Window frame '{}' is invalid",
toString());
}
2021-02-09 15:36:08 +00:00
void WindowDescription::checkValid() const
{
frame.checkValid();
// RANGE OFFSET requires exactly one ORDER BY column.
if (frame.type == WindowFrame::FrameType::Range
&& (frame.begin_type == WindowFrame::BoundaryType::Offset
|| frame.end_type == WindowFrame::BoundaryType::Offset)
&& order_by.size() != 1)
{
throw Exception(ErrorCodes::BAD_ARGUMENTS,
"The RANGE OFFSET window frame requires exactly one ORDER BY column, {} given",
order_by.size());
}
}
2021-01-30 01:16:44 +00:00
}