mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 02:03:04 +01:00
Fix #7018 - Problems with windows frames.
This commit is contained in:
parent
399b154ab0
commit
2cbcbe8fa9
@ -9148,14 +9148,13 @@ WindowClause* WindowClause::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
doDsqlPass(dsqlScratch, extent ? extent : window->extent),
|
||||
exclusion ? exclusion : window->exclusion);
|
||||
|
||||
if (node->order && node->extent && node->extent->unit == FrameExtent::Unit::RANGE &&
|
||||
if (node->extent && node->extent->unit == FrameExtent::Unit::RANGE &&
|
||||
(node->extent->frame1->value || (node->extent->frame2 && node->extent->frame2->value)))
|
||||
{
|
||||
if (node->order->items.getCount() > 1)
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_dsql_window_range_multi_key));
|
||||
}
|
||||
if (!node->order)
|
||||
status_exception::raise(Arg::Gds(isc_dsql_window_range_inv_key_type));
|
||||
else if (node->order->items.getCount() > 1)
|
||||
status_exception::raise(Arg::Gds(isc_dsql_window_range_multi_key));
|
||||
else
|
||||
{
|
||||
OrderNode* key = nodeAs<OrderNode>(node->order->items[0]);
|
||||
@ -9165,10 +9164,7 @@ WindowClause* WindowClause::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
DsqlDescMaker::fromNode(dsqlScratch, &desc, key->value);
|
||||
|
||||
if (!desc.isDateTime() && !desc.isNumeric())
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_dsql_window_range_inv_key_type));
|
||||
}
|
||||
status_exception::raise(Arg::Gds(isc_dsql_window_range_inv_key_type));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -822,7 +822,7 @@ Data source : @4"}, /* eds_statement */
|
||||
{335545115, "Cannot open cursor for non-SELECT statement"}, /* no_cursor */
|
||||
{335545116, "If <window frame bound 1> specifies @1, then <window frame bound 2> shall not specify @2"}, /* dsql_window_incompat_frames */
|
||||
{335545117, "RANGE based window with <expr> {PRECEDING | FOLLOWING} cannot have ORDER BY with more than one value"}, /* dsql_window_range_multi_key */
|
||||
{335545118, "RANGE based window must have an ORDER BY key of numerical, date, time or timestamp types"}, /* dsql_window_range_inv_key_type */
|
||||
{335545118, "RANGE based window with <offset> PRECEDING/FOLLOWING must have a single ORDER BY key of numerical, date, time or timestamp types"}, /* dsql_window_range_inv_key_type */
|
||||
{335545119, "Window RANGE/ROWS PRECEDING/FOLLOWING value must be of a numerical type"}, /* dsql_window_frame_value_inv_type */
|
||||
{335545120, "Invalid PRECEDING or FOLLOWING offset in window function: cannot be negative"}, /* window_frame_value_invalid */
|
||||
{335545121, "Window @1 not found"}, /* dsql_window_not_found */
|
||||
|
@ -790,6 +790,10 @@ namespace Jrd
|
||||
class WindowedStream : public RecordSource
|
||||
{
|
||||
public:
|
||||
using Frame = WindowClause::Frame;
|
||||
using FrameExtent = WindowClause::FrameExtent;
|
||||
using Exclusion = WindowClause::Exclusion;
|
||||
|
||||
class WindowStream : public BaseAggWinStream<WindowStream, BaseBufferedStream>
|
||||
{
|
||||
private:
|
||||
@ -839,8 +843,8 @@ namespace Jrd
|
||||
WindowStream(thread_db* tdbb, CompilerScratch* csb, StreamType stream,
|
||||
const NestValueArray* group, BaseBufferedStream* next,
|
||||
SortNode* order, MapNode* windowMap,
|
||||
WindowClause::FrameExtent* frameExtent,
|
||||
WindowClause::Exclusion exclusion);
|
||||
FrameExtent* frameExtent,
|
||||
Exclusion exclusion);
|
||||
|
||||
public:
|
||||
void open(thread_db* tdbb) const;
|
||||
@ -860,19 +864,19 @@ namespace Jrd
|
||||
|
||||
private:
|
||||
const void getFrameValue(thread_db* tdbb, jrd_req* request,
|
||||
const WindowClause::Frame* frame, impure_value_ex* impureValue) const;
|
||||
const Frame* frame, impure_value_ex* impureValue) const;
|
||||
|
||||
SINT64 locateFrameRange(thread_db* tdbb, jrd_req* request, Impure* impure,
|
||||
const WindowClause::Frame* frame, const dsc* offsetDesc, SINT64 position) const;
|
||||
const Frame* frame, const dsc* offsetDesc, SINT64 position) const;
|
||||
|
||||
private:
|
||||
NestConst<SortNode> m_order;
|
||||
const MapNode* m_windowMap;
|
||||
NestConst<WindowClause::FrameExtent> m_frameExtent;
|
||||
NestConst<FrameExtent> m_frameExtent;
|
||||
Firebird::Array<NestConst<ArithmeticNode> > m_arithNodes;
|
||||
NestValueArray m_aggSources, m_aggTargets;
|
||||
NestValueArray m_winPassSources, m_winPassTargets;
|
||||
WindowClause::Exclusion m_exclusion;
|
||||
Exclusion m_exclusion;
|
||||
UCHAR m_invariantOffsets; // 0x1 | 0x2 bitmask
|
||||
};
|
||||
|
||||
|
@ -191,35 +191,27 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb,
|
||||
|
||||
// Process the unpartioned and unordered map, if existent.
|
||||
|
||||
for (ObjectsArray<WindowSourceNode::Window>::iterator window = windows.begin();
|
||||
window != windows.end();
|
||||
++window)
|
||||
for (auto& window : windows)
|
||||
{
|
||||
// While here, verify not supported functions/clauses.
|
||||
|
||||
if (window->order)
|
||||
if (window.order || window.frameExtent->unit == FrameExtent::Unit::ROWS)
|
||||
{
|
||||
const NestConst<ValueExprNode>* source = window->map->sourceList.begin();
|
||||
|
||||
for (const NestConst<ValueExprNode>* const end = window->map->sourceList.end();
|
||||
source != end;
|
||||
++source)
|
||||
for (const auto& source : window.map->sourceList)
|
||||
{
|
||||
const AggNode* aggNode = nodeAs<AggNode>(*source);
|
||||
|
||||
if (aggNode)
|
||||
if (const auto aggNode = nodeAs<AggNode>(source))
|
||||
{
|
||||
if (aggNode->distinct)
|
||||
{
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_wish_list) <<
|
||||
Arg::Gds(isc_random) << "DISTINCT is not supported in ordered windows");
|
||||
}
|
||||
const char* arg = nullptr;
|
||||
|
||||
if (!(aggNode->getCapabilities() & AggNode::CAP_SUPPORTS_WINDOW_FRAME))
|
||||
if (aggNode->distinct)
|
||||
arg = "DISTINCT";
|
||||
else if (!(aggNode->getCapabilities() & AggNode::CAP_SUPPORTS_WINDOW_FRAME))
|
||||
arg = aggNode->aggInfo.name;
|
||||
|
||||
if (arg)
|
||||
{
|
||||
string msg;
|
||||
msg.printf("%s is not supported in ordered windows", aggNode->aggInfo.name);
|
||||
msg.printf("%s is not supported in windows with ORDER BY or frame by ROWS clauses", arg);
|
||||
|
||||
status_exception::raise(
|
||||
Arg::Gds(isc_wish_list) <<
|
||||
@ -229,15 +221,22 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb,
|
||||
}
|
||||
}
|
||||
|
||||
if (!window->group && !window->order)
|
||||
if (!window.group && !window.order)
|
||||
{
|
||||
fb_assert(!m_joinedStream);
|
||||
if (!m_joinedStream)
|
||||
{
|
||||
m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window.stream,
|
||||
nullptr, FB_NEW_POOL(csb->csb_pool) BufferedStreamWindow(csb, m_next),
|
||||
nullptr, window.map, window.frameExtent, window.exclusion);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window.stream,
|
||||
nullptr, FB_NEW_POOL(csb->csb_pool) BufferedStream(csb, m_joinedStream),
|
||||
nullptr, window.map, window.frameExtent, window.exclusion);
|
||||
}
|
||||
|
||||
m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window->stream,
|
||||
NULL, FB_NEW_POOL(csb->csb_pool) BufferedStreamWindow(csb, m_next),
|
||||
NULL, window->map, NULL, window->exclusion);
|
||||
|
||||
OPT_gen_aggregate_distincts(tdbb, csb, window->map);
|
||||
OPT_gen_aggregate_distincts(tdbb, csb, window.map);
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,14 +247,8 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb,
|
||||
|
||||
StreamList streams;
|
||||
|
||||
for (ObjectsArray<WindowSourceNode::Window>::iterator window = windows.begin();
|
||||
window != windows.end();
|
||||
++window)
|
||||
for (auto& window : windows)
|
||||
{
|
||||
// Refresh the stream list based on the last m_joinedStream.
|
||||
streams.clear();
|
||||
m_joinedStream->findUsedStreams(streams);
|
||||
|
||||
#if 0 //// FIXME: This causes problems, for example with FIRST_VALUE.
|
||||
//// I think it can be fixed with the help of SlidingWindow.
|
||||
|
||||
@ -263,10 +256,10 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb,
|
||||
|
||||
// between !{<n> following || unbounded preceding} and unbounded following
|
||||
if (window->frameExtent &&
|
||||
window->frameExtent->frame2->bound == WindowClause::Frame::Bound::FOLLOWING &&
|
||||
window->frameExtent->frame2->bound == Frame::Bound::FOLLOWING &&
|
||||
!window->frameExtent->frame2->value &&
|
||||
!(window->frameExtent->frame1->bound == WindowClause::Frame::Bound::FOLLOWING ||
|
||||
(window->frameExtent->frame1->bound == WindowClause::Frame::Bound::PRECEDING &&
|
||||
!(window->frameExtent->frame1->bound == Frame::Bound::FOLLOWING ||
|
||||
(window->frameExtent->frame1->bound == Frame::Bound::PRECEDING &&
|
||||
!window->frameExtent->frame1->value)))
|
||||
{
|
||||
if (window->order)
|
||||
@ -286,14 +279,14 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb,
|
||||
}
|
||||
}
|
||||
|
||||
WindowClause::Frame* temp = window->frameExtent->frame1;
|
||||
Frame* temp = window->frameExtent->frame1;
|
||||
window->frameExtent->frame1 = window->frameExtent->frame2;
|
||||
window->frameExtent->frame2 = temp;
|
||||
|
||||
window->frameExtent->frame1->bound = WindowClause::Frame::Bound::PRECEDING;
|
||||
window->frameExtent->frame1->bound = Frame::Bound::PRECEDING;
|
||||
|
||||
if (window->frameExtent->frame2->bound == WindowClause::Frame::Bound::PRECEDING)
|
||||
window->frameExtent->frame2->bound = WindowClause::Frame::Bound::FOLLOWING;
|
||||
if (window->frameExtent->frame2->bound == Frame::Bound::PRECEDING)
|
||||
window->frameExtent->frame2->bound = Frame::Bound::FOLLOWING;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -301,34 +294,38 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb,
|
||||
|
||||
SortNode* windowOrder;
|
||||
|
||||
if (window->group)
|
||||
if (window.group)
|
||||
{
|
||||
windowOrder = FB_NEW_POOL(csb->csb_pool) SortNode(csb->csb_pool);
|
||||
windowOrder->expressions.join(window->group->expressions);
|
||||
windowOrder->direction.join(window->group->direction);
|
||||
windowOrder->nullOrder.join(window->group->nullOrder);
|
||||
windowOrder->expressions.join(window.group->expressions);
|
||||
windowOrder->direction.join(window.group->direction);
|
||||
windowOrder->nullOrder.join(window.group->nullOrder);
|
||||
|
||||
if (window->order)
|
||||
if (window.order)
|
||||
{
|
||||
windowOrder->expressions.join(window->order->expressions);
|
||||
windowOrder->direction.join(window->order->direction);
|
||||
windowOrder->nullOrder.join(window->order->nullOrder);
|
||||
windowOrder->expressions.join(window.order->expressions);
|
||||
windowOrder->direction.join(window.order->direction);
|
||||
windowOrder->nullOrder.join(window.order->nullOrder);
|
||||
}
|
||||
}
|
||||
else
|
||||
windowOrder = window->order;
|
||||
windowOrder = window.order;
|
||||
|
||||
if (windowOrder)
|
||||
{
|
||||
SortedStream* sortedStream = OPT_gen_sort(tdbb, csb, streams, NULL,
|
||||
// Refresh the stream list based on the last m_joinedStream.
|
||||
streams.clear();
|
||||
m_joinedStream->findUsedStreams(streams);
|
||||
|
||||
SortedStream* sortedStream = OPT_gen_sort(tdbb, csb, streams, nullptr,
|
||||
m_joinedStream, windowOrder, false, false);
|
||||
|
||||
m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window->stream,
|
||||
(window->group ? &window->group->expressions : NULL),
|
||||
m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window.stream,
|
||||
(window.group ? &window.group->expressions : nullptr),
|
||||
FB_NEW_POOL(csb->csb_pool) BufferedStream(csb, sortedStream),
|
||||
window->order, window->map, window->frameExtent, window->exclusion);
|
||||
window.order, window.map, window.frameExtent, window.exclusion);
|
||||
|
||||
OPT_gen_aggregate_distincts(tdbb, csb, window->map);
|
||||
OPT_gen_aggregate_distincts(tdbb, csb, window.map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -419,8 +416,8 @@ void WindowedStream::nullRecords(thread_db* tdbb) const
|
||||
WindowedStream::WindowStream::WindowStream(thread_db* tdbb, CompilerScratch* csb, StreamType stream,
|
||||
const NestValueArray* group, BaseBufferedStream* next,
|
||||
SortNode* order, MapNode* windowMap,
|
||||
WindowClause::FrameExtent* frameExtent,
|
||||
WindowClause::Exclusion exclusion)
|
||||
FrameExtent* frameExtent,
|
||||
Exclusion exclusion)
|
||||
: BaseAggWinStream(tdbb, csb, stream, group, NULL, false, next),
|
||||
m_order(order),
|
||||
m_windowMap(windowMap),
|
||||
@ -470,12 +467,12 @@ WindowedStream::WindowStream::WindowStream(thread_db* tdbb, CompilerScratch* csb
|
||||
|
||||
for (unsigned i = 0; i < 2; ++i)
|
||||
{
|
||||
WindowClause::Frame* frame = i == 0 ?
|
||||
Frame* frame = i == 0 ?
|
||||
m_frameExtent->frame1 : m_frameExtent->frame2;
|
||||
|
||||
if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE && frame->value)
|
||||
if (m_frameExtent->unit == FrameExtent::Unit::RANGE && frame->value)
|
||||
{
|
||||
int direction = frame->bound == WindowClause::Frame::Bound::FOLLOWING ? 1 : -1;
|
||||
int direction = frame->bound == Frame::Bound::FOLLOWING ? 1 : -1;
|
||||
|
||||
if (m_order->direction[0] == ORDER_DESC)
|
||||
direction *= -1;
|
||||
@ -605,37 +602,36 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const
|
||||
|
||||
// Find the window start.
|
||||
|
||||
if (m_order && m_frameExtent->frame1->value && !(m_invariantOffsets & 0x1))
|
||||
if (m_frameExtent->frame1->value && !(m_invariantOffsets & 0x1))
|
||||
getFrameValue(tdbb, request, m_frameExtent->frame1, &impure->startOffset);
|
||||
|
||||
if (!m_order)
|
||||
impure->windowBlock.startPosition = impure->partitionBlock.startPosition;
|
||||
// {range | rows} between unbounded preceding and ...
|
||||
else if (m_frameExtent->frame1->bound == WindowClause::Frame::Bound::PRECEDING &&
|
||||
!m_frameExtent->frame1->value)
|
||||
// (no order by) range
|
||||
if ((m_frameExtent->frame1->bound == Frame::Bound::PRECEDING && !m_frameExtent->frame1->value) ||
|
||||
(!m_order && m_frameExtent->unit == FrameExtent::Unit::RANGE))
|
||||
{
|
||||
impure->windowBlock.startPosition = impure->partitionBlock.startPosition;
|
||||
}
|
||||
// rows between current row and ...
|
||||
else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS &&
|
||||
m_frameExtent->frame1->bound == WindowClause::Frame::Bound::CURRENT_ROW)
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::ROWS &&
|
||||
m_frameExtent->frame1->bound == Frame::Bound::CURRENT_ROW)
|
||||
{
|
||||
impure->windowBlock.startPosition = position;
|
||||
}
|
||||
// rows between <n> {preceding | following} and ...
|
||||
else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS &&
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::ROWS &&
|
||||
m_frameExtent->frame1->value)
|
||||
{
|
||||
impure->windowBlock.startPosition = position + impure->startOffset.vlux_count;
|
||||
}
|
||||
// range between current row and ...
|
||||
else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE &&
|
||||
m_frameExtent->frame1->bound == WindowClause::Frame::Bound::CURRENT_ROW)
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::RANGE &&
|
||||
m_frameExtent->frame1->bound == Frame::Bound::CURRENT_ROW)
|
||||
{
|
||||
impure->windowBlock.startPosition = position;
|
||||
}
|
||||
// range between <n> {preceding | following} and ...
|
||||
else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE &&
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::RANGE &&
|
||||
m_frameExtent->frame1->value)
|
||||
{
|
||||
impure->windowBlock.startPosition = locateFrameRange(tdbb, request, impure,
|
||||
@ -649,32 +645,31 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const
|
||||
|
||||
// Find the window end.
|
||||
|
||||
if (m_order && m_frameExtent->frame2->value && !(m_invariantOffsets & 0x2))
|
||||
if (m_frameExtent->frame2->value && !(m_invariantOffsets & 0x2))
|
||||
getFrameValue(tdbb, request, m_frameExtent->frame2, &impure->endOffset);
|
||||
|
||||
if (!m_order)
|
||||
impure->windowBlock.endPosition = impure->partitionBlock.endPosition;
|
||||
// {range | rows} between ... and unbounded following
|
||||
else if (m_frameExtent->frame2->bound == WindowClause::Frame::Bound::FOLLOWING &&
|
||||
!m_frameExtent->frame2->value)
|
||||
// (no order by) range
|
||||
if ((m_frameExtent->frame2->bound == Frame::Bound::FOLLOWING && !m_frameExtent->frame2->value) ||
|
||||
(!m_order && m_frameExtent->unit == FrameExtent::Unit::RANGE))
|
||||
{
|
||||
impure->windowBlock.endPosition = impure->partitionBlock.endPosition;
|
||||
}
|
||||
// rows between ... and current row
|
||||
else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS &&
|
||||
m_frameExtent->frame2->bound == WindowClause::Frame::Bound::CURRENT_ROW)
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::ROWS &&
|
||||
m_frameExtent->frame2->bound == Frame::Bound::CURRENT_ROW)
|
||||
{
|
||||
impure->windowBlock.endPosition = position;
|
||||
}
|
||||
// rows between ... and <n> {preceding | following}
|
||||
else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS &&
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::ROWS &&
|
||||
m_frameExtent->frame2->value)
|
||||
{
|
||||
impure->windowBlock.endPosition = position + impure->endOffset.vlux_count;
|
||||
}
|
||||
// range between ... and current row
|
||||
else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE &&
|
||||
m_frameExtent->frame2->bound == WindowClause::Frame::Bound::CURRENT_ROW)
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::RANGE &&
|
||||
m_frameExtent->frame2->bound == Frame::Bound::CURRENT_ROW)
|
||||
{
|
||||
SINT64 rangePos = position;
|
||||
cacheValues(tdbb, request, &m_order->expressions, impure->orderValues,
|
||||
@ -700,7 +695,7 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const
|
||||
fb_assert(false);
|
||||
}
|
||||
// range between ... and <n> {preceding | following}
|
||||
else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE &&
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::RANGE &&
|
||||
m_frameExtent->frame2->value)
|
||||
{
|
||||
impure->windowBlock.endPosition = locateFrameRange(tdbb, request, impure,
|
||||
@ -712,43 +707,37 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_order)
|
||||
impure->rangePending = MAX(0, impure->windowBlock.endPosition - position);
|
||||
else if (m_order && m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE)
|
||||
if ((m_frameExtent->frame1->bound == Frame::Bound::PRECEDING && !m_frameExtent->frame1->value &&
|
||||
m_frameExtent->frame2->bound == Frame::Bound::FOLLOWING && !m_frameExtent->frame2->value) ||
|
||||
(m_frameExtent->unit == FrameExtent::Unit::RANGE && !m_order))
|
||||
{
|
||||
if (m_frameExtent->frame1->bound == WindowClause::Frame::Bound::PRECEDING &&
|
||||
!m_frameExtent->frame1->value &&
|
||||
m_frameExtent->frame2->bound == WindowClause::Frame::Bound::FOLLOWING &&
|
||||
!m_frameExtent->frame2->value)
|
||||
{
|
||||
impure->rangePending = MAX(0, impure->windowBlock.endPosition - position);
|
||||
}
|
||||
else
|
||||
{
|
||||
SINT64 rangePos = position;
|
||||
cacheValues(tdbb, request, &m_order->expressions, impure->orderValues,
|
||||
DummyAdjustFunctor());
|
||||
|
||||
while (++rangePos <= impure->partitionBlock.endPosition)
|
||||
{
|
||||
if (!m_next->getRecord(tdbb))
|
||||
fb_assert(false);
|
||||
|
||||
if (lookForChange(tdbb, request, &m_order->expressions, m_order,
|
||||
impure->orderValues))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
impure->rangePending = rangePos - position - 1;
|
||||
}
|
||||
|
||||
m_next->locate(tdbb, position);
|
||||
|
||||
if (!m_next->getRecord(tdbb))
|
||||
fb_assert(false);
|
||||
impure->rangePending = MAX(0, impure->windowBlock.endPosition - position);
|
||||
}
|
||||
else if (m_frameExtent->unit == FrameExtent::Unit::RANGE)
|
||||
{
|
||||
SINT64 rangePos = position;
|
||||
cacheValues(tdbb, request, &m_order->expressions, impure->orderValues,
|
||||
DummyAdjustFunctor());
|
||||
|
||||
while (++rangePos <= impure->partitionBlock.endPosition)
|
||||
{
|
||||
if (!m_next->getRecord(tdbb))
|
||||
fb_assert(false);
|
||||
|
||||
if (lookForChange(tdbb, request, &m_order->expressions, m_order,
|
||||
impure->orderValues))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
impure->rangePending = rangePos - position - 1;
|
||||
}
|
||||
|
||||
m_next->locate(tdbb, position);
|
||||
|
||||
if (!m_next->getRecord(tdbb))
|
||||
fb_assert(false);
|
||||
|
||||
//// TODO: There is no need to pass record by record when m_aggSources.isEmpty()
|
||||
|
||||
@ -902,7 +891,7 @@ void WindowedStream::WindowStream::nullRecords(thread_db* tdbb) const
|
||||
}
|
||||
|
||||
const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req* request,
|
||||
const WindowClause::Frame* frame, impure_value_ex* impureValue) const
|
||||
const Frame* frame, impure_value_ex* impureValue) const
|
||||
{
|
||||
dsc* desc = EVL_expr(tdbb, request, frame->value);
|
||||
bool error = false;
|
||||
@ -911,7 +900,7 @@ const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req*
|
||||
error = true;
|
||||
else
|
||||
{
|
||||
if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS)
|
||||
if (m_frameExtent->unit == FrameExtent::Unit::ROWS)
|
||||
{
|
||||
// Purposedly used 32-bit here. So long distance will complicate things for no gain.
|
||||
impureValue->vlux_count = MOV_get_long(tdbb, desc, 0);
|
||||
@ -919,7 +908,7 @@ const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req*
|
||||
if (impureValue->vlux_count < 0)
|
||||
error = true;
|
||||
|
||||
if (frame->bound == WindowClause::Frame::Bound::PRECEDING)
|
||||
if (frame->bound == Frame::Bound::PRECEDING)
|
||||
impureValue->vlux_count = -impureValue->vlux_count;
|
||||
}
|
||||
else if (MOV_compare(tdbb, desc, &zeroDsc) < 0)
|
||||
@ -937,7 +926,7 @@ const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req*
|
||||
}
|
||||
|
||||
SINT64 WindowedStream::WindowStream::locateFrameRange(thread_db* tdbb, jrd_req* request, Impure* impure,
|
||||
const WindowClause::Frame* frame, const dsc* offsetDesc, SINT64 position) const
|
||||
const Frame* frame, const dsc* offsetDesc, SINT64 position) const
|
||||
{
|
||||
if (m_order->expressions.getCount() != 1)
|
||||
{
|
||||
@ -983,7 +972,7 @@ SINT64 WindowedStream::WindowStream::locateFrameRange(thread_db* tdbb, jrd_req*
|
||||
--rangePos;
|
||||
}
|
||||
}
|
||||
else if (frame->bound == WindowClause::Frame::Bound::FOLLOWING)
|
||||
else if (frame->bound == Frame::Bound::FOLLOWING)
|
||||
{
|
||||
const int bound = frame == m_frameExtent->frame1 ? 0 : 1;
|
||||
|
||||
|
@ -905,7 +905,7 @@ Data source : @4', NULL, NULL)
|
||||
('no_cursor', 'DSQL_open', 'dsql.cpp', NULL, 0, 795, NULL, 'Cannot open cursor for non-SELECT statement', NULL, NULL);
|
||||
('dsql_window_incompat_frames', NULL, 'ExprNodes.cpp', NULL, 0, 796, NULL, 'If <window frame bound 1> specifies @1, then <window frame bound 2> shall not specify @2', NULL, NULL);
|
||||
('dsql_window_range_multi_key', NULL, 'ExprNodes.cpp', NULL, 0, 797, NULL, 'RANGE based window with <expr> {PRECEDING | FOLLOWING} cannot have ORDER BY with more than one value', NULL, NULL);
|
||||
('dsql_window_range_inv_key_type', NULL, 'ExprNodes.cpp', NULL, 0, 798, NULL, 'RANGE based window must have an ORDER BY key of numerical, date, time or timestamp types', NULL, NULL);
|
||||
('dsql_window_range_inv_key_type', NULL, 'ExprNodes.cpp', NULL, 0, 798, NULL, 'RANGE based window with <offset> PRECEDING/FOLLOWING must have a single ORDER BY key of numerical, date, time or timestamp types', NULL, NULL);
|
||||
('dsql_window_frame_value_inv_type', NULL, 'ExprNodes.cpp', NULL, 0, 799, NULL, 'Window RANGE/ROWS PRECEDING/FOLLOWING value must be of a numerical type', NULL, NULL);
|
||||
('window_frame_value_invalid', NULL, 'ExprNodes.cpp', NULL, 0, 800, NULL, 'Invalid PRECEDING or FOLLOWING offset in window function: cannot be negative', NULL, NULL);
|
||||
('dsql_window_not_found', NULL, 'ExprNodes.cpp', NULL, 0, 801, NULL, 'Window @1 not found', NULL, NULL);
|
||||
|
Loading…
Reference in New Issue
Block a user