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

SQL 2023 ANY_VALUE aggregate function. (#7617)

This commit is contained in:
Adriano dos Santos Fernandes 2023-09-18 07:51:41 -03:00 committed by GitHub
parent fa9c6d4d3c
commit 986e96fac8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 146 additions and 0 deletions

View File

@ -0,0 +1,24 @@
# Aggregate Functions
## ANY_VALUE (Firebird 6.0)
`ANY_VALUE` is a non-deterministic aggregate function that returns its expression for an arbitrary
record from the grouped rows.
`NULLs` are ignored. It's returned only in the case of none evaluated records having a non-null value.
Syntax:
```
<any value> ::= ANY_VALUE(<expression>)
```
Example:
```
select department,
any_value(employee) employee
from employee_department
group by department
```

View File

@ -62,6 +62,7 @@ PARSER_TOKEN(TOK_AFTER, "AFTER", true)
PARSER_TOKEN(TOK_ALL, "ALL", false)
PARSER_TOKEN(TOK_ALTER, "ALTER", false)
PARSER_TOKEN(TOK_ALWAYS, "ALWAYS", true)
PARSER_TOKEN(TOK_ANY_VALUE, "ANY_VALUE", true)
PARSER_TOKEN(TOK_AND, "AND", false)
PARSER_TOKEN(TOK_ANY, "ANY", false)
PARSER_TOKEN(TOK_AS, "AS", false)

View File

@ -491,6 +491,92 @@ dsc* AggNode::execute(thread_db* tdbb, Request* request) const
//--------------------
static AggNode::RegisterFactory0<AnyValueAggNode> anyValueAggInfo("ANY_VALUE");
AnyValueAggNode::AnyValueAggNode(MemoryPool& pool, ValueExprNode* aArg)
: AggNode(pool, anyValueAggInfo, false, false, aArg)
{
}
DmlNode* AnyValueAggNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR /*blrOp*/)
{
const auto node = FB_NEW_POOL(pool) AnyValueAggNode(pool);
node->arg = PAR_parse_value(tdbb, csb);
return node;
}
void AnyValueAggNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /*count*/)
{
arg = PAR_parse_value(tdbb, csb);
}
void AnyValueAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
{
DsqlDescMaker::fromNode(dsqlScratch, desc, arg, true);
}
void AnyValueAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
{
arg->getDesc(tdbb, csb, desc);
}
ValueExprNode* AnyValueAggNode::copy(thread_db* tdbb, NodeCopier& copier) const
{
const auto node = FB_NEW_POOL(*tdbb->getDefaultPool()) AnyValueAggNode(*tdbb->getDefaultPool());
node->nodScale = nodScale;
node->arg = copier.copy(tdbb, arg);
return node;
}
string AnyValueAggNode::internalPrint(NodePrinter& printer) const
{
AggNode::internalPrint(printer);
return "AnyValueAggNode";
}
void AnyValueAggNode::aggInit(thread_db* tdbb, Request* request) const
{
AggNode::aggInit(tdbb, request);
const auto impure = request->getImpure<impure_value_ex>(impureOffset);
impure->vlu_desc.dsc_dtype = 0;
}
void AnyValueAggNode::aggPass(thread_db* tdbb, Request* request, dsc* desc) const
{
const auto impure = request->getImpure<impure_value_ex>(impureOffset);
if (!impure->vlu_desc.dsc_dtype)
{
const auto argValue = EVL_expr(tdbb, request, arg);
if (!(request->req_flags & req_null))
EVL_make_value(tdbb, argValue, impure);
}
}
dsc* AnyValueAggNode::aggExecute(thread_db* /*tdbb*/, Request* request) const
{
const auto impure = request->getImpure<impure_value_ex>(impureOffset);
if (impure->vlu_desc.dsc_dtype)
return &impure->vlu_desc;
return nullptr;
}
AggNode* AnyValueAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
{
return FB_NEW_POOL(dsqlScratch->getPool()) AnyValueAggNode(dsqlScratch->getPool(),
doDsqlPass(dsqlScratch, arg));
}
//--------------------
static AggNode::Register<AvgAggNode> avgAggInfo("AVG", blr_agg_average, blr_agg_average_distinct);
AvgAggNode::AvgAggNode(MemoryPool& pool, bool aDistinct, bool aDialect1, ValueExprNode* aArg)

View File

@ -30,6 +30,33 @@
namespace Jrd {
class AnyValueAggNode final : public AggNode
{
public:
explicit AnyValueAggNode(MemoryPool& pool, ValueExprNode* aArg = nullptr);
static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp);
unsigned getCapabilities() const override
{
return CAP_RESPECTS_WINDOW_FRAME | CAP_WANTS_AGG_CALLS;
}
void parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned count) override;
Firebird::string internalPrint(NodePrinter& printer) const override;
void make(DsqlCompilerScratch* dsqlScratch, dsc* desc) override;
void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) override;
ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const override;
void aggInit(thread_db* tdbb, Request* request) const override;
void aggPass(thread_db* tdbb, Request* request, dsc* desc) const override;
dsc* aggExecute(thread_db* tdbb, Request* request) const override;
protected:
AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/ override;
};
class AvgAggNode final : public AggNode
{
public:

View File

@ -696,6 +696,10 @@ using namespace Firebird;
%token <metaNamePtr> UNICODE_CHAR
%token <metaNamePtr> UNICODE_VAL
// tokens added for Firebird 6.0
%token <metaNamePtr> ANY_VALUE
// precedence declarations for expression evaluation
%left OR
@ -8029,6 +8033,8 @@ aggregate_function_prefix
{ $$ = newNode<RegrAggNode>(RegrAggNode::TYPE_REGR_SXY, $3, $5); }
| REGR_SYY '(' value ',' value ')'
{ $$ = newNode<RegrAggNode>(RegrAggNode::TYPE_REGR_SYY, $3, $5); }
| ANY_VALUE '(' distinct_noise value ')'
{ $$ = newNode<AnyValueAggNode>($4); }
;
%type <aggNode> window_function
@ -9225,6 +9231,8 @@ non_reserved_word
| TIMEZONE_NAME
| UNICODE_CHAR
| UNICODE_VAL
// added in FB 6.0
| ANY_VALUE
;
%%