2021-01-30 01:16:44 +00:00
|
|
|
#include <Interpreters/WindowDescription.h>
|
|
|
|
|
2021-03-18 23:05:43 +00:00
|
|
|
#include <Core/Field.h>
|
2021-07-08 09:24:08 +00:00
|
|
|
#include <Common/FieldVisitorsAccurateComparison.h>
|
2021-06-14 04:13:35 +00:00
|
|
|
#include <Common/FieldVisitorToString.h>
|
2021-01-30 01:16:44 +00:00
|
|
|
#include <IO/Operators.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
|
2021-05-03 22:46:51 +00:00
|
|
|
|
2021-01-30 01:16:44 +00:00
|
|
|
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
|
|
|
|
{
|
2021-09-06 14:24:03 +00:00
|
|
|
buf << type << " BETWEEN ";
|
2021-02-03 12:50:25 +00:00
|
|
|
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
|
|
|
|
{
|
2021-03-18 23:05:43 +00:00
|
|
|
buf << applyVisitor(FieldVisitorToString(), begin_offset);
|
2021-02-03 12:50:25 +00:00
|
|
|
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
|
|
|
|
{
|
2021-03-18 23:05:43 +00:00
|
|
|
buf << applyVisitor(FieldVisitorToString(), end_offset);
|
2021-02-03 12:50:25 +00:00
|
|
|
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-04-06 16:24:56 +00:00
|
|
|
// Check the validity of offsets.
|
2022-07-25 20:53:53 +00:00
|
|
|
if (type == WindowFrame::FrameType::ROWS
|
|
|
|
|| type == WindowFrame::FrameType::GROUPS)
|
2021-04-06 16:24:56 +00:00
|
|
|
{
|
|
|
|
if (begin_type == BoundaryType::Offset
|
|
|
|
&& !((begin_offset.getType() == Field::Types::UInt64
|
|
|
|
|| begin_offset.getType() == Field::Types::Int64)
|
|
|
|
&& begin_offset.get<Int64>() >= 0
|
|
|
|
&& begin_offset.get<Int64>() < INT_MAX))
|
|
|
|
{
|
|
|
|
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
2021-07-08 09:24:37 +00:00
|
|
|
"Frame start offset for '{}' frame must be a nonnegative 32-bit integer, '{}' of type '{}' given",
|
2021-09-06 14:24:03 +00:00
|
|
|
type,
|
2021-04-06 16:24:56 +00:00
|
|
|
applyVisitor(FieldVisitorToString(), begin_offset),
|
2021-09-06 14:24:03 +00:00
|
|
|
begin_offset.getType());
|
2021-04-06 16:24:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (end_type == BoundaryType::Offset
|
|
|
|
&& !((end_offset.getType() == Field::Types::UInt64
|
|
|
|
|| end_offset.getType() == Field::Types::Int64)
|
|
|
|
&& end_offset.get<Int64>() >= 0
|
|
|
|
&& end_offset.get<Int64>() < INT_MAX))
|
|
|
|
{
|
|
|
|
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
2021-07-08 09:24:37 +00:00
|
|
|
"Frame end offset for '{}' frame must be a nonnegative 32-bit integer, '{}' of type '{}' given",
|
2021-09-06 14:24:03 +00:00
|
|
|
type,
|
2021-04-06 16:24:56 +00:00
|
|
|
applyVisitor(FieldVisitorToString(), end_offset),
|
2021-09-06 14:24:03 +00:00
|
|
|
end_offset.getType());
|
2021-04-06 16:24:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check relative positioning of offsets.
|
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-03-18 23:05:43 +00:00
|
|
|
// Frame start offset must be less or equal that the frame end offset.
|
|
|
|
bool begin_less_equal_end;
|
|
|
|
if (begin_preceding && end_preceding)
|
2021-02-04 07:41:09 +00:00
|
|
|
{
|
2021-07-08 09:24:08 +00:00
|
|
|
/// we can't compare Fields using operator<= if fields have different types
|
|
|
|
begin_less_equal_end = applyVisitor(FieldVisitorAccurateLessOrEqual(), end_offset, begin_offset);
|
2021-02-04 07:41:09 +00:00
|
|
|
}
|
2021-03-18 23:05:43 +00:00
|
|
|
else if (begin_preceding && !end_preceding)
|
|
|
|
{
|
|
|
|
begin_less_equal_end = true;
|
|
|
|
}
|
|
|
|
else if (!begin_preceding && end_preceding)
|
|
|
|
{
|
|
|
|
begin_less_equal_end = false;
|
|
|
|
}
|
2021-03-19 00:02:35 +00:00
|
|
|
else /* if (!begin_preceding && !end_preceding) */
|
2021-03-18 23:05:43 +00:00
|
|
|
{
|
2021-07-08 09:24:08 +00:00
|
|
|
begin_less_equal_end = applyVisitor(FieldVisitorAccurateLessOrEqual(), begin_offset, end_offset);
|
2021-03-18 23:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!begin_less_equal_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");
|
|
|
|
}
|
|
|
|
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.
|
2022-07-25 20:53:53 +00:00
|
|
|
if (frame.type == WindowFrame::FrameType::RANGE
|
2021-02-09 15:36:08 +00:00
|
|
|
&& (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
|
|
|
}
|