Skip to content

Commit

Permalink
Feature CORE-3620 - Window function LAST_VALUE.
Browse files Browse the repository at this point in the history
Feature CORE-3621 - Window function NTH_VALUE.
  • Loading branch information
asfernandes committed Oct 25, 2011
1 parent 69d29c3 commit cea1efd
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 0 deletions.
166 changes: 166 additions & 0 deletions src/dsql/WinNodes.cpp
Expand Up @@ -337,6 +337,172 @@ AggNode* FirstValueWinNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) const
//--------------------


static WinFuncNode::Register<LastValueWinNode> lastValueWinInfo("LAST_VALUE");

LastValueWinNode::LastValueWinNode(MemoryPool& pool, dsql_nod* aArg)
: WinFuncNode(pool, lastValueWinInfo, aArg)
{
}

void LastValueWinNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /*count*/)
{
arg = PAR_parse_value(tdbb, csb);
}

void LastValueWinNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
{
MAKE_desc(dsqlScratch, desc, dsqlArg);
desc->setNullable(true);
}

void LastValueWinNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
{
arg->getDesc(tdbb, csb, desc);
}

ValueExprNode* LastValueWinNode::copy(thread_db* tdbb, NodeCopier& copier) const
{
LastValueWinNode* node = FB_NEW(*tdbb->getDefaultPool()) LastValueWinNode(*tdbb->getDefaultPool());
node->arg = copier.copy(tdbb, arg);
return node;
}

void LastValueWinNode::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);
}

void LastValueWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /*desc*/) const
{
}

dsc* LastValueWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/) const
{
return NULL;
}

dsc* LastValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
SINT64 records = impure->vlu_misc.vlu_int64++;

if (!window->move(0))
{
window->move(0); // Come back to our row.
return NULL;
}

dsc* desc = EVL_expr(tdbb, request, arg);
if (!desc || (request->req_flags & req_null))
return NULL;

return desc;
}

AggNode* LastValueWinNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) const
{
return FB_NEW(getPool()) LastValueWinNode(getPool(), PASS1_node(dsqlScratch, dsqlArg));
}


//--------------------


static WinFuncNode::Register<NthValueWinNode> nthValueWinInfo("NTH_VALUE");

NthValueWinNode::NthValueWinNode(MemoryPool& pool, dsql_nod* aArg, dsql_nod* aRow)
: WinFuncNode(pool, nthValueWinInfo, aArg),
dsqlRow(aRow)
{
addChildNode(dsqlRow, row);
}

void NthValueWinNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /*count*/)
{
arg = PAR_parse_value(tdbb, csb);
row = PAR_parse_value(tdbb, csb);
}

void NthValueWinNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
{
MAKE_desc(dsqlScratch, desc, dsqlArg);
desc->setNullable(true);
}

void NthValueWinNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
{
arg->getDesc(tdbb, csb, desc);
}

ValueExprNode* NthValueWinNode::copy(thread_db* tdbb, NodeCopier& copier) const
{
NthValueWinNode* node = FB_NEW(*tdbb->getDefaultPool()) NthValueWinNode(*tdbb->getDefaultPool());
node->arg = copier.copy(tdbb, arg);
node->row = copier.copy(tdbb, row);
return node;
}

void NthValueWinNode::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);
}

void NthValueWinNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /*desc*/) const
{
}

dsc* NthValueWinNode::aggExecute(thread_db* /*tdbb*/, jrd_req* /*request*/) const
{
return NULL;
}

dsc* NthValueWinNode::winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const
{
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);

dsc* desc = EVL_expr(tdbb, request, row);
SINT64 records;

if (!desc || (request->req_flags & req_null) || (records = MOV_get_int64(desc, 0)) <= 0)
{
status_exception::raise(Arg::Gds(isc_sysf_argnmustbe_positive) <<
Arg::Num(2) << Arg::Str(aggInfo.name));
}

if (records > ++impure->vlu_misc.vlu_int64)
return NULL;

records -= impure->vlu_misc.vlu_int64;

if (!window->move(records))
{
window->move(0); // Come back to our row.
return NULL;
}

desc = EVL_expr(tdbb, request, arg);
if (!desc || (request->req_flags & req_null))
return NULL;

return desc;
}

AggNode* NthValueWinNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) const
{
return FB_NEW(getPool()) NthValueWinNode(getPool(),
PASS1_node(dsqlScratch, dsqlArg), PASS1_node(dsqlScratch, dsqlRow));
}


//--------------------


// A direction of -1 is LAG, and 1 is LEAD.
LagLeadWinNode::LagLeadWinNode(MemoryPool& pool, const AggInfo& aAggInfo, int aDirection,
dsql_nod* aArg, dsql_nod* aRows, dsql_nod* aOutExpr)
Expand Down
58 changes: 58 additions & 0 deletions src/dsql/WinNodes.h
Expand Up @@ -122,6 +122,64 @@ class FirstValueWinNode : public WinFuncNode
virtual void parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned count);
};

// LAST_VALUE function.
class LastValueWinNode : public WinFuncNode
{
public:
explicit LastValueWinNode(MemoryPool& pool, dsql_nod* aArg = NULL);

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 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) const;

virtual bool shouldCallWinPass() const
{
return true;
}

virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const;

protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) const;

virtual void parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned count);
};

// NTH_VALUE function.
class NthValueWinNode : public WinFuncNode
{
public:
explicit NthValueWinNode(MemoryPool& pool, dsql_nod* aArg = NULL, dsql_nod* aRow = NULL);

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 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) const;

virtual bool shouldCallWinPass() const
{
return true;
}

virtual dsc* winPass(thread_db* tdbb, jrd_req* request, SlidingWindow* window) const;

protected:
virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) const;

virtual void parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned count);

private:
dsql_nod* dsqlRow;
NestConst<ValueExprNode> row;
};

// LAG/LEAD function.
class LagLeadWinNode : public WinFuncNode
{
Expand Down
4 changes: 4 additions & 0 deletions src/dsql/parse.y
Expand Up @@ -5738,6 +5738,10 @@ window_function
{ $$ = newNode<RowNumberWinNode>(); }
| FIRST_VALUE '(' value ')'
{ $$ = newNode<FirstValueWinNode>($3); }
| LAST_VALUE '(' value ')'
{ $$ = newNode<LastValueWinNode>($3); }
| NTH_VALUE '(' value ',' value ')'
{ $$ = newNode<NthValueWinNode>($3, $5); }
| LAG '(' value ',' value ',' value ')'
{ $$ = newNode<LagWinNode>($3, $5, $7); }
| LAG '(' value ',' value ')'
Expand Down
2 changes: 2 additions & 0 deletions src/yvalve/keywords.cpp
Expand Up @@ -231,6 +231,7 @@ static const TOK tokens[] =
{KEY, "KEY", 1, false},
{LAG, "LAG", 2, false},
{LAST, "LAST", 2, true},
{LAST_VALUE, "LAST_VALUE", 2, false},
{LASTNAME, "LASTNAME", 2, false},
{LEAD, "LEAD", 2, false},
{LEADING, "LEADING", 2, false},
Expand Down Expand Up @@ -272,6 +273,7 @@ static const TOK tokens[] =
{NEXT, "NEXT", 2, true},
{NO, "NO", 1, false},
{NOT, "NOT", 1, false},
{NTH_VALUE, "NTH_VALUE", 2, false},
{NULLIF, "NULLIF", 2, true},
{KW_NULL, "NULL", 1, false},
{NULLS, "NULLS", 2, true},
Expand Down

0 comments on commit cea1efd

Please sign in to comment.