8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 17:23:03 +01:00

Merge branch 'new_window_functions' of git://github.com/nakagami/firebird into new-window-functions

This commit is contained in:
Adriano dos Santos Fernandes 2016-06-29 12:26:45 -03:00
commit 26895605f4
8 changed files with 439 additions and 53 deletions

View File

@ -144,6 +144,9 @@ Syntax:
<ranking window function> ::=
DENSE_RANK() |
RANK() |
PERCENT_RANK() |
CUME_DIST() |
NTILE(<expr>) |
ROW_NUMBER()
The rank functions compute the ordinal rank of a row within the window partition. In this category
@ -158,6 +161,9 @@ select
salary,
dense_rank() over (order by salary),
rank() over (order by salary),
percent_rank() over (order by salary),
cume_dist() over (order by salary),
ntile(3) over (order by salary),
row_number() over (order by salary),
sum(1) over (order by salary)
from employee
@ -165,18 +171,21 @@ select
And the result set:
id salary dense_rank rank row_number sum
-- ------ ---------- ---- ---------- ---
3 8.00 1 1 1 1
4 9.00 2 2 2 2
1 10.00 3 3 3 4
5 10.00 3 3 4 4
2 12.00 4 5 5 5
id salary dense_rank rank percent_rank cume_dist ntile row_number sum
-- ------ ---------- ---- ------------------ -------------------- ------ ---------- ---
3 8.00 1 1 0.000000000000000 0.2000000000000000 1 1 1
4 9.00 2 2 0.2500000000000000 0.4000000000000000 1 2 2
1 10.00 3 3 0.5000000000000000 0.8000000000000000 2 3 4
5 10.00 3 3 0.5000000000000000 0.8000000000000000 2 4 4
2 12.00 4 5 1.000000000000000 1.000000000000000 3 5 5
The difference between DENSE_RANK and RANK is that there is a gap related to duplicate rows (in
relation to the window ordering) only in RANK. DENSE_RANK continues assigning sequential numbers
after the duplicate salary. On the other hand, ROW_NUMBER always assigns sequential numbers, even
when there is duplicate values.
PERCENT_RANK is a ratio of RANK to group count.
CUME_DIST is cumulative distribution of a value in a group.
NTILE distributes the rows into a specified number of groups.
4.2 Navigational functions
--------------------------

View File

@ -430,7 +430,7 @@ void AggNode::aggFinish(thread_db* /*tdbb*/, jrd_req* request) const
}
}
dsc* AggNode::execute(thread_db* tdbb, jrd_req* request) const
dsc* AggNode::execute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -469,7 +469,14 @@ dsc* AggNode::execute(thread_db* tdbb, jrd_req* request) const
}
}
return aggExecute(tdbb, request);
return aggExecute(tdbb, request, win_row_count);
}
dsc* AggNode::execute(thread_db* tdbb, jrd_req* request) const
{
fb_assert(false);
return NULL;
}
@ -664,7 +671,7 @@ void AvgAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* desc) const
ArithmeticNode::add2(desc, impure, this, blr_add);
}
dsc* AvgAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const
dsc* AvgAggNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -815,7 +822,7 @@ void ListAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const
impure->vlu_blob->BLB_put_data(tdbb, temp, len);
}
dsc* ListAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const
dsc* ListAggNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -928,7 +935,7 @@ void CountAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* /*desc*/)
++impure->vlu_misc.vlu_int64;
}
dsc* CountAggNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request) const
dsc* CountAggNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -1172,7 +1179,7 @@ void SumAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* desc) const
ArithmeticNode::add2(desc, impure, this, blr_add);
}
dsc* SumAggNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request) const
dsc* SumAggNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -1269,7 +1276,7 @@ void MaxMinAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const
EVL_make_value(tdbb, desc, impure);
}
dsc* MaxMinAggNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request) const
dsc* MaxMinAggNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -1382,7 +1389,7 @@ void StdDevAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const
impure2->x2 += d * d;
}
dsc* StdDevAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const
dsc* StdDevAggNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
StdDevImpure* impure2 = request->getImpure<StdDevImpure>(impure2Offset);
@ -1548,7 +1555,7 @@ void CorrAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /*desc
fb_assert(false);
}
dsc* CorrAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const
dsc* CorrAggNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
CorrImpure* impure2 = request->getImpure<CorrImpure>(impure2Offset);
@ -1740,7 +1747,7 @@ void RegrAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /*desc
fb_assert(false);
}
dsc* RegrAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const
dsc* RegrAggNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
RegrImpure* impure2 = request->getImpure<RegrImpure>(impure2Offset);
@ -1904,7 +1911,7 @@ void RegrCountAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /
fb_assert(false);
}
dsc* RegrCountAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const
dsc* RegrCountAggNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);

View File

@ -45,7 +45,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -79,7 +79,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -103,7 +103,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -123,7 +123,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -149,7 +149,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -186,7 +186,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -227,7 +227,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual bool aggPass(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -274,7 +274,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual bool aggPass(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -303,7 +303,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual bool aggPass(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;

View File

@ -973,7 +973,7 @@ public:
{
}
virtual dsc* winPass(thread_db* /*tdbb*/, jrd_req* /*request*/, SlidingWindow* /*window*/) const
virtual dsc* winPass(thread_db* /*tdbb*/, jrd_req* /*request*/, SlidingWindow* /*window*/, FB_UINT64 /*win_rou_count*/) const
{
return NULL;
}
@ -982,9 +982,10 @@ public:
virtual void aggFinish(thread_db* tdbb, jrd_req* request) const;
virtual bool aggPass(thread_db* tdbb, jrd_req* request) const;
virtual dsc* execute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* execute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const = 0;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const = 0;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const = 0;
virtual AggNode* dsqlPass(DsqlCompilerScratch* dsqlScratch);

View File

@ -94,7 +94,7 @@ void DenseRankWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /
{
}
dsc* DenseRankWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request) const
dsc* DenseRankWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -178,7 +178,7 @@ void RankWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* /*desc*/)
++impure->vlux_count;
}
dsc* RankWinNode::aggExecute(thread_db* tdbb, jrd_req* request) const
dsc* RankWinNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -203,6 +203,171 @@ AggNode* RankWinNode::dsqlCopy(DsqlCompilerScratch* /*dsqlScratch*/) /*const*/
//--------------------
static WinFuncNode::RegisterFactory0<PercentRankWinNode> percentRankWinInfo("PERCENT_RANK");
PercentRankWinNode::PercentRankWinNode(MemoryPool& pool)
: WinFuncNode(pool, percentRankWinInfo),
tempImpure(0)
{
fb_assert(dsqlChildNodes.getCount() == 1 && jrdChildNodes.getCount() == 1);
dsqlChildNodes.clear();
jrdChildNodes.clear();
}
string PercentRankWinNode::internalPrint(NodePrinter& printer) const
{
WinFuncNode::internalPrint(printer);
NODE_PRINT(printer, tempImpure);
return "PercentRankWinNode";
}
void PercentRankWinNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
{
desc->makeDouble();
}
void PercentRankWinNode::getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* desc)
{
desc->makeDouble();
}
ValueExprNode* PercentRankWinNode::copy(thread_db* tdbb, NodeCopier& /*copier*/) const
{
return FB_NEW_POOL(*tdbb->getDefaultPool()) PercentRankWinNode(*tdbb->getDefaultPool());
}
AggNode* PercentRankWinNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
AggNode::pass2(tdbb, csb);
tempImpure = CMP_impure(csb, sizeof(impure_value_ex));
return this;
}
void PercentRankWinNode::aggInit(thread_db* tdbb, jrd_req* request) const
{
AggNode::aggInit(tdbb, request);
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
impure->make_int64(1, 0);
impure->vlux_count = 0;
}
void PercentRankWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* /*desc*/) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
++impure->vlux_count;
}
dsc* PercentRankWinNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
dsc temp;
double d = (double)(impure->vlu_misc.vlu_int64 -1) / (double)(win_row_count -1);
temp.makeDouble(&d);
impure_value_ex* impureTemp = request->getImpure<impure_value_ex>(tempImpure);
EVL_make_value(tdbb, &temp, impureTemp);
impure->vlu_misc.vlu_int64 += impure->vlux_count;
impure->vlux_count = 0;
return &impureTemp->vlu_desc;
}
AggNode* PercentRankWinNode::dsqlCopy(DsqlCompilerScratch* /*dsqlScratch*/) /*const*/
{
return FB_NEW_POOL(getPool()) PercentRankWinNode(getPool());
}
//--------------------
static WinFuncNode::RegisterFactory0<CumeDistWinNode> cumeDistWinInfo("CUME_DIST");
CumeDistWinNode::CumeDistWinNode(MemoryPool& pool)
: WinFuncNode(pool, cumeDistWinInfo),
tempImpure(0)
{
fb_assert(dsqlChildNodes.getCount() == 1 && jrdChildNodes.getCount() == 1);
dsqlChildNodes.clear();
jrdChildNodes.clear();
}
string CumeDistWinNode::internalPrint(NodePrinter& printer) const
{
WinFuncNode::internalPrint(printer);
NODE_PRINT(printer, tempImpure);
return "CumeDistWinNode";
}
void CumeDistWinNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
{
desc->makeDouble();
}
void CumeDistWinNode::getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* desc)
{
desc->makeDouble();
}
ValueExprNode* CumeDistWinNode::copy(thread_db* tdbb, NodeCopier& /*copier*/) const
{
return FB_NEW_POOL(*tdbb->getDefaultPool()) CumeDistWinNode(*tdbb->getDefaultPool());
}
AggNode* CumeDistWinNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
AggNode::pass2(tdbb, csb);
tempImpure = CMP_impure(csb, sizeof(impure_value_ex));
return this;
}
void CumeDistWinNode::aggInit(thread_db* tdbb, jrd_req* request) const
{
AggNode::aggInit(tdbb, request);
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
impure->make_int64(1, 0);
impure->vlux_count = 0;
}
void CumeDistWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* /*desc*/) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
++impure->vlux_count;
}
dsc* CumeDistWinNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
dsc temp;
impure->vlu_misc.vlu_int64 += impure->vlux_count;
impure->vlux_count = 0;
double d = (double)(impure->vlu_misc.vlu_int64 -1) / (double)(win_row_count);
temp.makeDouble(&d);
impure_value_ex* impureTemp = request->getImpure<impure_value_ex>(tempImpure);
EVL_make_value(tdbb, &temp, impureTemp);
return &impureTemp->vlu_desc;
}
AggNode* CumeDistWinNode::dsqlCopy(DsqlCompilerScratch* /*dsqlScratch*/) /*const*/
{
return FB_NEW_POOL(getPool()) CumeDistWinNode(getPool());
}
//--------------------
static WinFuncNode::RegisterFactory0<RowNumberWinNode> rowNumberWinInfo("ROW_NUMBER");
RowNumberWinNode::RowNumberWinNode(MemoryPool& pool)
@ -252,13 +417,13 @@ void RowNumberWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /
{
}
dsc* RowNumberWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request) const
dsc* RowNumberWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* request, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
return &impure->vlu_desc;
}
dsc* RowNumberWinNode::winPass(thread_db* /*tdbb*/, jrd_req* request, SlidingWindow* /*window*/) const
dsc* RowNumberWinNode::winPass(thread_db* /*tdbb*/, jrd_req* request, SlidingWindow* /*window*/, FB_UINT64 /*win_row_count*/) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
++impure->vlu_misc.vlu_int64;
@ -325,12 +490,12 @@ void FirstValueWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc*
{
}
dsc* FirstValueWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/) const
dsc* FirstValueWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/, FB_UINT64 win_row_count) const
{
return NULL;
}
dsc* FirstValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const
dsc* FirstValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_row_count*/) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
SINT64 records = impure->vlu_misc.vlu_int64++;
@ -402,12 +567,12 @@ void LastValueWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /
{
}
dsc* LastValueWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/) const
dsc* LastValueWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/, FB_UINT64 win_row_count) const
{
return NULL;
}
dsc* LastValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const
dsc* LastValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_row_count*/) const
{
if (!window->move(0))
return NULL;
@ -492,12 +657,12 @@ void NthValueWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /*
{
}
dsc* NthValueWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/) const
dsc* NthValueWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/, FB_UINT64 win_row_count) const
{
return NULL;
}
dsc* NthValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const
dsc* NthValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_row_count*/) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
@ -602,12 +767,12 @@ void LagLeadWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /*d
{
}
dsc* LagLeadWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/) const
dsc* LagLeadWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/, FB_UINT64 win_row_count) const
{
return NULL;
}
dsc* LagLeadWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const
dsc* LagLeadWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_row_count*/) const
{
window->move(0); // Come back to our row because rows may reference columns.
@ -699,4 +864,117 @@ AggNode* LeadWinNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
}
//--------------------
static WinFuncNode::RegisterFactory0<NTileWinNode> nTileWinInfo("NTILE");
NTileWinNode::NTileWinNode(MemoryPool& pool, ValueExprNode* aArg)
: WinFuncNode(pool, nTileWinInfo, aArg),
tempImpure(0)
{
fb_assert(dsqlChildNodes.getCount() == 1 && jrdChildNodes.getCount() == 1);
dsqlChildNodes.clear();
jrdChildNodes.clear();
addChildNode(arg, arg);
}
void NTileWinNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /*count*/)
{
arg = PAR_parse_value(tdbb, csb);
}
string NTileWinNode::internalPrint(NodePrinter& printer) const
{
WinFuncNode::internalPrint(printer);
NODE_PRINT(printer, tempImpure);
return "NTileWinNode";
}
void NTileWinNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
{
if (dsqlScratch->clientDialect == 1)
desc->makeDouble();
else
desc->makeInt64(0);
}
void NTileWinNode::getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* desc)
{
desc->makeInt64(0);
}
ValueExprNode* NTileWinNode::copy(thread_db* tdbb, NodeCopier& copier) const
{
NTileWinNode* node = FB_NEW_POOL(*tdbb->getDefaultPool()) NTileWinNode(*tdbb->getDefaultPool());
node->arg = copier.copy(tdbb, arg);
return node;
}
AggNode* NTileWinNode::pass2(thread_db* tdbb, CompilerScratch* csb)
{
AggNode::pass2(tdbb, csb);
tempImpure = CMP_impure(csb, sizeof(impure_value_ex));
return this;
}
void NTileWinNode::aggInit(thread_db* tdbb, jrd_req* request) const
{
AggNode::aggInit(tdbb, request);
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
impure->make_int64(0, 0);
impure->vlux_count = 0;
}
void NTileWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* request, dsc* /*desc*/) const
{
}
dsc* NTileWinNode::aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 /*win_row_count*/) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
return &impure->vlu_desc;
}
dsc* NTileWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 win_row_count) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
window->move(0); // Come back to our row because row may reference columns.
dsc* desc = EVL_expr(tdbb, request, arg);
if (!desc || (request->req_flags & req_null))
status_exception::raise(Arg::Gds(isc_sysf_argnmustbe_positive) <<
Arg::Num(1) << Arg::Str(aggInfo.name));
SINT64 buckets = MOV_get_int64(desc, 0);
if (buckets <= 0)
{
status_exception::raise(Arg::Gds(isc_sysf_argnmustbe_positive) <<
Arg::Num(1) << Arg::Str(aggInfo.name));
}
SINT64 n = impure->vlux_count;
SINT64 top_boundary = win_row_count / buckets + 1;
SINT64 bottom_boundary = win_row_count / buckets;
SINT64 num_top_boundary = win_row_count % buckets;
if (n < top_boundary * num_top_boundary)
impure->vlu_misc.vlu_int64 = (n / top_boundary) + 1;
else
impure->vlu_misc.vlu_int64 = num_top_boundary + (n - num_top_boundary * top_boundary) / bottom_boundary + 1;
++impure->vlux_count;
return &impure->vlu_desc;
}
AggNode* NTileWinNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
{
return FB_NEW_POOL(getPool()) NTileWinNode(getPool(), doDsqlPass(dsqlScratch, arg));
}
} // namespace Jrd

View File

@ -43,7 +43,7 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -63,7 +63,53 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
private:
USHORT tempImpure;
};
// PERCENT_RANK function.
class PercentRankWinNode : public WinFuncNode
{
public:
explicit PercentRankWinNode(MemoryPool& pool);
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual AggNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void aggInit(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
private:
USHORT tempImpure;
};
// CUME_DIST function.
class CumeDistWinNode : public WinFuncNode
{
public:
explicit CumeDistWinNode(MemoryPool& pool);
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual AggNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void aggInit(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -85,14 +131,14 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
virtual void aggSetup(bool& wantWinPass) const
{
wantWinPass = true;
}
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const;
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_rou_count*/) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -111,14 +157,14 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
virtual void aggSetup(bool& wantWinPass) const
{
wantWinPass = true;
}
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const;
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_rou_count*/) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -139,14 +185,14 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
virtual void aggSetup(bool& wantWinPass) const
{
wantWinPass = true;
}
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const;
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_rou_count*/) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -175,14 +221,14 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
virtual void aggSetup(bool& wantWinPass) const
{
wantWinPass = true;
}
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const;
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_rou_count*/) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
@ -207,14 +253,14 @@ public:
virtual void aggInit(thread_db* tdbb, jrd_req* request, AggType aggType) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
virtual void aggSetup(bool& wantWinPass) const
{
wantWinPass = true;
}
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const;
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_rou_count*/) const;
protected:
virtual void parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned count);
@ -263,6 +309,36 @@ protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
};
// NTILE function.
class NTileWinNode : public WinFuncNode
{
public:
explicit NTileWinNode(MemoryPool& pool, ValueExprNode* aArg = NULL);
virtual Firebird::string internalPrint(NodePrinter& printer) const;
virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc);
virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc);
virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const;
virtual AggNode* pass2(thread_db* tdbb, CompilerScratch* csb);
virtual void aggInit(thread_db* tdbb, jrd_req* request) const;
virtual void aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const;
virtual dsc* aggExecute(thread_db* tdbb, jrd_req* request, FB_UINT64 win_row_count) const;
virtual bool shouldCallWinPass() const
{
return true;
}
virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window, FB_UINT64 /*win_rou_count*/) const;
protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/;
virtual void parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned count);
private:
USHORT tempImpure;
};
} // namespace

View File

@ -591,6 +591,9 @@ using namespace Firebird;
// tokens added for Firebird 4.0
%token <metaNamePtr> CUME_DIST
%token <metaNamePtr> NTILE
%token <metaNamePtr> PERCENT_RANK
%token <metaNamePtr> PRIVILEGE
%token <metaNamePtr> RDB_ROLE_IN_USE
%token <metaNamePtr> RDB_SYSTEM_PRIVILEGE
@ -7000,6 +7003,10 @@ window_function
{ $$ = newNode<DenseRankWinNode>(); }
| RANK '(' ')'
{ $$ = newNode<RankWinNode>(); }
| PERCENT_RANK '(' ')'
{ $$ = newNode<PercentRankWinNode>(); }
| CUME_DIST '(' ')'
{ $$ = newNode<CumeDistWinNode>(); }
| ROW_NUMBER '(' ')'
{ $$ = newNode<RowNumberWinNode>(); }
| FIRST_VALUE '(' value ')'
@ -7020,6 +7027,8 @@ window_function
{ $$ = newNode<LeadWinNode>($3, $5, newNode<NullNode>()); }
| LEAD '(' value ')'
{ $$ = newNode<LeadWinNode>($3, MAKE_const_slong(1), newNode<NullNode>()); }
| NTILE '(' u_numeric_constant ')'
{ $$ = newNode<NTileWinNode>($3); }
;
%type <valueExprNode> nth_from
@ -7835,7 +7844,10 @@ non_reserved_word
| LAST_VALUE
| LAG
| LEAD
| NTILE
| RANK
| PERCENT_RANK
| CUME_DIST
| ROW_NUMBER
| USAGE
| LINGER

View File

@ -139,6 +139,7 @@ static const TOK tokens[] =
{CREATE, "CREATE", false},
{CROSS, "CROSS", false},
{CSTRING, "CSTRING", false},
{CUME_DIST, "CUME_DIST", false},
{CURRENT, "CURRENT", false},
{CURRENT_CONNECTION, "CURRENT_CONNECTION", false},
{CURRENT_DATE, "CURRENT_DATE", false},
@ -280,6 +281,7 @@ static const TOK tokens[] =
{NO, "NO", false},
{NOT, "NOT", false},
{NTH_VALUE, "NTH_VALUE", false},
{NTILE, "NTILE", false},
{NULLIF, "NULLIF", true},
{KW_NULL, "NULL", false},
{NULLS, "NULLS", true},
@ -307,6 +309,7 @@ static const TOK tokens[] =
{PARAMETER, "PARAMETER", false},
{PARTITION, "PARTITION", false},
{PASSWORD, "PASSWORD", false},
{PERCENT_RANK, "PERCENT_RANK", false},
{PI, "PI", false},
{PLACING, "PLACING", false},
{PLAN, "PLAN", false},