Skip to content

Commit ebc2632

Browse files
authored
Add support bitwise aggregate functions (#8768)
* Add support bitwise aggregate functions * Fixed doc * Corrections after review. * Checking the scale of an argument.
1 parent fd9c01c commit ebc2632

File tree

5 files changed

+256
-0
lines changed

5 files changed

+256
-0
lines changed

doc/sql.extensions/README.aggregate_functions.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,39 @@ select department,
2222
from employee_department
2323
group by department
2424
```
25+
26+
## Bitwise aggregates (Firebird 6.0)
27+
28+
The `BIN_AND_AGG`, `BIN_OR_AGG`, and `BIN_XOR_AGG` aggregate functions perform bit operations.
29+
30+
`NULLs` are ignored. It's returned only in the case of none evaluated records having a non-null value.
31+
32+
The input argument must be one of the integer types (`SMALLINT`, `INTEGER`, `BIGINT`, or `INT128`).
33+
The output result is of the same type as the input argument.
34+
35+
Syntax:
36+
37+
```
38+
<bin_add agg> ::= BIN_AND_AGG(<expression>)
39+
40+
<bin_or agg> ::= BIN_OR_AGG(<expression>)
41+
42+
<bin_xor agg> ::= BIN_XOR_AGG([ALL | DISTINCT] <expression>)
43+
```
44+
45+
The `BIN_AND_AGG` and `BIN_OR_AGG` functions do not support the `DISTINCT` keyword, since eliminating duplicates does
46+
not affect the result. However, for `BIN_XOR_AGG`, you can specify `DISTINCT` to exclude duplicates from processing.
47+
48+
Example:
49+
50+
```
51+
SELECT
52+
name,
53+
BIN_AND_AGG(n) AS F_AND,
54+
BIN_OR_AGG(n) AS F_OR,
55+
BIN_XOR_AGG(n) AS F_XOR,
56+
BIN_XOR_AGG(ALL n) AS F_XOR_A,
57+
BIN_XOR_AGG(DISTINCT n) AS F_XOR_D
58+
FROM acl_masks
59+
GROUP BY name
60+
```

src/common/ParserTokens.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,14 @@ PARSER_TOKEN(TOK_BEGIN, "BEGIN", false)
8888
PARSER_TOKEN(TOK_BETWEEN, "BETWEEN", false)
8989
PARSER_TOKEN(TOK_BIGINT, "BIGINT", false)
9090
PARSER_TOKEN(TOK_BIN_AND, "BIN_AND", true)
91+
PARSER_TOKEN(TOK_BIN_AND_AGG, "BIN_AND_AGG", true)
9192
PARSER_TOKEN(TOK_BIN_NOT, "BIN_NOT", true)
9293
PARSER_TOKEN(TOK_BIN_OR, "BIN_OR", true)
94+
PARSER_TOKEN(TOK_BIN_OR_AGG, "BIN_OR_AGG", true)
9395
PARSER_TOKEN(TOK_BIN_SHL, "BIN_SHL", true)
9496
PARSER_TOKEN(TOK_BIN_SHR, "BIN_SHR", true)
9597
PARSER_TOKEN(TOK_BIN_XOR, "BIN_XOR", true)
98+
PARSER_TOKEN(TOK_BIN_XOR_AGG, "BIN_XOR_AGG", true)
9699
PARSER_TOKEN(TOK_BINARY, "BINARY", false)
97100
PARSER_TOKEN(TOK_BIND, "BIND", true)
98101
PARSER_TOKEN(TOK_BIT_LENGTH, "BIT_LENGTH", false)

src/dsql/AggNodes.cpp

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,173 @@ AggNode* MaxMinAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
14671467
type, doDsqlPass(dsqlScratch, arg));
14681468
}
14691469

1470+
//--------------------
1471+
1472+
static AggNode::RegisterFactory1<BinAggNode, BinAggNode::BinType> binAndAggInfo(
1473+
"BIN_AND_AGG", BinAggNode::TYPE_BIN_AND);
1474+
static AggNode::RegisterFactory1<BinAggNode, BinAggNode::BinType> binOrAggInfo(
1475+
"BIN_OR_AGG", BinAggNode::TYPE_BIN_OR);
1476+
static AggNode::RegisterFactory1<BinAggNode, BinAggNode::BinType> binXorAggInfo(
1477+
"BIN_XOR_AGG", BinAggNode::TYPE_BIN_XOR);
1478+
static AggNode::RegisterFactory1<BinAggNode, BinAggNode::BinType> binXorDistinctAggInfo(
1479+
"BIN_XOR_DISTINCT_AGG", BinAggNode::TYPE_BIN_XOR_DISTINCT);
1480+
1481+
BinAggNode::BinAggNode(MemoryPool& pool, BinType aType, ValueExprNode* aArg)
1482+
: AggNode(pool,
1483+
(aType == BinAggNode::TYPE_BIN_AND ? binAndAggInfo :
1484+
aType == BinAggNode::TYPE_BIN_OR ? binOrAggInfo :
1485+
aType == BinAggNode::TYPE_BIN_XOR ? binXorAggInfo : binXorDistinctAggInfo),
1486+
(aType == BinAggNode::TYPE_BIN_XOR_DISTINCT), false, aArg),
1487+
type(aType)
1488+
{
1489+
}
1490+
1491+
void BinAggNode::parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned /*count*/)
1492+
{
1493+
arg = PAR_parse_value(tdbb, csb);
1494+
}
1495+
1496+
void BinAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc)
1497+
{
1498+
DsqlDescMaker::fromNode(dsqlScratch, desc, arg, true);
1499+
1500+
if (desc->isNull())
1501+
return;
1502+
1503+
if (!DTYPE_IS_EXACT(desc->dsc_dtype) || (desc->dsc_scale != 0))
1504+
{
1505+
switch (type)
1506+
{
1507+
case TYPE_BIN_AND:
1508+
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
1509+
Arg::Gds(isc_dsql_agg2_wrongarg) << Arg::Str("BIN_AND_AGG"));
1510+
break;
1511+
1512+
case TYPE_BIN_OR:
1513+
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
1514+
Arg::Gds(isc_dsql_agg2_wrongarg) << Arg::Str("BIN_OR_AGG"));
1515+
break;
1516+
1517+
case TYPE_BIN_XOR:
1518+
case TYPE_BIN_XOR_DISTINCT:
1519+
ERRD_post(Arg::Gds(isc_expression_eval_err) <<
1520+
Arg::Gds(isc_dsql_agg2_wrongarg) << Arg::Str("BIN_XOR_AGG"));
1521+
break;
1522+
1523+
default:
1524+
fb_assert(false);
1525+
break;
1526+
}
1527+
}
1528+
}
1529+
1530+
void BinAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc)
1531+
{
1532+
arg->getDesc(tdbb, csb, desc);
1533+
1534+
if (desc->is128())
1535+
{
1536+
nodFlags |= FLAG_INT128;
1537+
desc->makeInt128(0);
1538+
}
1539+
else
1540+
desc->makeInt64(0);
1541+
}
1542+
1543+
ValueExprNode* BinAggNode::copy(thread_db* tdbb, NodeCopier& copier) const
1544+
{
1545+
BinAggNode* node = FB_NEW_POOL(*tdbb->getDefaultPool()) BinAggNode(*tdbb->getDefaultPool(), type);
1546+
node->arg = copier.copy(tdbb, arg);
1547+
return node;
1548+
}
1549+
1550+
string BinAggNode::internalPrint(NodePrinter& printer) const
1551+
{
1552+
AggNode::internalPrint(printer);
1553+
1554+
NODE_PRINT(printer, type);
1555+
1556+
return "BinAggNode";
1557+
}
1558+
1559+
void BinAggNode::aggInit(thread_db* tdbb, Request* request) const
1560+
{
1561+
AggNode::aggInit(tdbb, request);
1562+
1563+
SINT64 initValue = 0;
1564+
if (type == TYPE_BIN_AND)
1565+
initValue = -1;
1566+
1567+
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
1568+
if (nodFlags & FLAG_INT128)
1569+
{
1570+
Firebird::Int128 i128;
1571+
impure->make_decimal_fixed(i128, 0);
1572+
impure->vlu_misc.vlu_int128 = initValue;
1573+
}
1574+
else
1575+
impure->make_int64(initValue);
1576+
}
1577+
1578+
void BinAggNode::aggPass(thread_db* tdbb, Request* request, dsc* desc) const
1579+
{
1580+
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
1581+
++impure->vlux_count;
1582+
if (nodFlags & FLAG_INT128)
1583+
{
1584+
const auto value = MOV_get_int128(tdbb, desc, 0);
1585+
switch (type)
1586+
{
1587+
case TYPE_BIN_AND:
1588+
impure->vlu_misc.vlu_int128 &= value;
1589+
break;
1590+
1591+
case TYPE_BIN_OR:
1592+
impure->vlu_misc.vlu_int128 |= value;
1593+
break;
1594+
1595+
case TYPE_BIN_XOR:
1596+
case TYPE_BIN_XOR_DISTINCT:
1597+
impure->vlu_misc.vlu_int128 ^= value;
1598+
break;
1599+
}
1600+
}
1601+
else
1602+
{
1603+
const auto value = MOV_get_int64(tdbb, desc, 0);
1604+
switch (type)
1605+
{
1606+
case TYPE_BIN_AND:
1607+
impure->vlu_misc.vlu_int64 &= value;
1608+
break;
1609+
1610+
case TYPE_BIN_OR:
1611+
impure->vlu_misc.vlu_int64 |= value;
1612+
break;
1613+
1614+
case TYPE_BIN_XOR:
1615+
case TYPE_BIN_XOR_DISTINCT:
1616+
impure->vlu_misc.vlu_int64 ^= value;
1617+
break;
1618+
}
1619+
}
1620+
}
1621+
1622+
dsc* BinAggNode::aggExecute(thread_db* tdbb, Request* request) const
1623+
{
1624+
impure_value_ex* impure = request->getImpure<impure_value_ex>(impureOffset);
1625+
1626+
if (!impure->vlux_count)
1627+
return nullptr;
1628+
1629+
return &impure->vlu_desc;
1630+
}
1631+
1632+
AggNode* BinAggNode::dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/
1633+
{
1634+
return FB_NEW_POOL(dsqlScratch->getPool()) BinAggNode(dsqlScratch->getPool(),
1635+
type, doDsqlPass(dsqlScratch, arg));
1636+
}
14701637

14711638
//--------------------
14721639

src/dsql/AggNodes.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,42 @@ class MaxMinAggNode final : public AggNode
219219
const MaxMinType type;
220220
};
221221

222+
class BinAggNode final : public AggNode
223+
{
224+
public:
225+
enum BinType : UCHAR
226+
{
227+
TYPE_BIN_AND,
228+
TYPE_BIN_OR,
229+
TYPE_BIN_XOR,
230+
TYPE_BIN_XOR_DISTINCT
231+
};
232+
233+
explicit BinAggNode(MemoryPool& pool, BinType aType, ValueExprNode* aArg = nullptr);
234+
235+
void parseArgs(thread_db* tdbb, CompilerScratch* csb, unsigned count) override;
236+
237+
unsigned getCapabilities() const override
238+
{
239+
return CAP_RESPECTS_WINDOW_FRAME | CAP_WANTS_AGG_CALLS;
240+
}
241+
242+
Firebird::string internalPrint(NodePrinter& printer) const override;
243+
void make(DsqlCompilerScratch* dsqlScratch, dsc* desc) override;
244+
void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) override;
245+
ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const override;
246+
247+
void aggInit(thread_db* tdbb, Request* request) const override;
248+
void aggPass(thread_db* tdbb, Request* request, dsc* desc) const override;
249+
dsc* aggExecute(thread_db* tdbb, Request* request) const override;
250+
251+
protected:
252+
AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/ override;
253+
254+
public:
255+
const BinType type;
256+
};
257+
222258
class StdDevAggNode final : public AggNode
223259
{
224260
public:

src/dsql/parse.y

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,9 @@ using namespace Firebird;
702702
// tokens added for Firebird 6.0
703703

704704
%token <metaNamePtr> ANY_VALUE
705+
%token <metaNamePtr> BIN_AND_AGG
706+
%token <metaNamePtr> BIN_OR_AGG
707+
%token <metaNamePtr> BIN_XOR_AGG
705708
%token <metaNamePtr> BTRIM
706709
%token <metaNamePtr> CALL
707710
%token <metaNamePtr> CURRENT_SCHEMA
@@ -8584,6 +8587,14 @@ aggregate_function_prefix
85848587
{ $$ = newNode<RegrAggNode>(RegrAggNode::TYPE_REGR_SYY, $3, $5); }
85858588
| ANY_VALUE '(' distinct_noise value ')'
85868589
{ $$ = newNode<AnyValueAggNode>($4); }
8590+
| BIN_AND_AGG '(' value ')'
8591+
{ $$ = newNode<BinAggNode>(BinAggNode::TYPE_BIN_AND, $3); }
8592+
| BIN_OR_AGG '(' value ')'
8593+
{ $$ = newNode<BinAggNode>(BinAggNode::TYPE_BIN_OR, $3); }
8594+
| BIN_XOR_AGG '(' all_noise value ')'
8595+
{ $$ = newNode<BinAggNode>(BinAggNode::TYPE_BIN_XOR, $4); }
8596+
| BIN_XOR_AGG '(' DISTINCT value ')'
8597+
{ $$ = newNode<BinAggNode>(BinAggNode::TYPE_BIN_XOR_DISTINCT, $4); }
85878598
;
85888599

85898600
%type <aggNode> window_function
@@ -9951,6 +9962,9 @@ non_reserved_word
99519962
| UNICODE_VAL
99529963
// added in FB 6.0
99539964
| ANY_VALUE
9965+
| BIN_AND_AGG
9966+
| BIN_OR_AGG
9967+
| BIN_XOR_AGG
99549968
| DOWNTO
99559969
| FORMAT
99569970
| OWNER

0 commit comments

Comments
 (0)