mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 14:03:03 +01:00
SQL 2023 ANY_VALUE aggregate function. (#7617)
This commit is contained in:
parent
fa9c6d4d3c
commit
986e96fac8
24
doc/sql.extensions/README.aggregate_functions.md
Normal file
24
doc/sql.extensions/README.aggregate_functions.md
Normal 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
|
||||
```
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
;
|
||||
|
||||
%%
|
||||
|
Loading…
Reference in New Issue
Block a user