55
55
56
56
#include < v8.h>
57
57
58
+ #include < limits>
59
+
58
60
using namespace arangodb ;
59
61
using namespace arangodb ::aql;
60
62
using VelocyPackHelper = arangodb::basics::VelocyPackHelper;
@@ -1465,21 +1467,36 @@ AqlValue Expression::executeSimpleExpressionExpansion(ExpressionContext& ctx,
1465
1467
}
1466
1468
}
1467
1469
1468
- // FILTER
1469
- AstNode const * filterNode = node->getMember (2 );
1470
+ // quantifier and FILTER
1471
+ AstNode const * quantifierAndFilterNode = node->getMember (2 );
1472
+
1473
+ AstNode const * quantifierNode = nullptr ;
1474
+ AstNode const * filterNode = nullptr ;
1470
1475
1471
- if (filterNode->type == NODE_TYPE_NOP) {
1476
+ if (quantifierAndFilterNode == nullptr ||
1477
+ quantifierAndFilterNode->type == NODE_TYPE_NOP) {
1472
1478
filterNode = nullptr ;
1473
- } else if (filterNode->isConstant ()) {
1474
- if (filterNode->isTrue ()) {
1475
- // filter expression is always true
1476
- filterNode = nullptr ;
1477
- } else {
1478
- // filter expression is always false
1479
- if (isBoolean) {
1480
- return AqlValue (AqlValueHintBool (false ));
1479
+ } else {
1480
+ TRI_ASSERT (quantifierAndFilterNode->type == NODE_TYPE_ARRAY_FILTER);
1481
+ TRI_ASSERT (quantifierAndFilterNode->numMembers () == 2 );
1482
+
1483
+ quantifierNode = quantifierAndFilterNode->getMember (0 );
1484
+ TRI_ASSERT (quantifierNode != nullptr );
1485
+ TRI_ASSERT (quantifierNode->type == NODE_TYPE_NOP ||
1486
+ quantifierNode->isIntValue () ||
1487
+ quantifierNode->type == NODE_TYPE_QUANTIFIER ||
1488
+ quantifierNode->type == NODE_TYPE_RANGE);
1489
+
1490
+ filterNode = quantifierAndFilterNode->getMember (1 );
1491
+
1492
+ if (!isBoolean && filterNode->isConstant ()) {
1493
+ if (filterNode->isTrue ()) {
1494
+ // filter expression is always true
1495
+ filterNode = nullptr ;
1496
+ } else {
1497
+ // filter expression is always false
1498
+ return AqlValue (AqlValueHintEmptyArray ());
1481
1499
}
1482
- return AqlValue (AqlValueHintEmptyArray ());
1483
1500
}
1484
1501
}
1485
1502
@@ -1592,6 +1609,45 @@ AqlValue Expression::executeSimpleExpressionExpansion(ExpressionContext& ctx,
1592
1609
}
1593
1610
1594
1611
size_t const n = value.length ();
1612
+
1613
+ // relevant only in case isBoolean = true
1614
+ size_t minRequiredItems = 0 ;
1615
+ size_t maxRequiredItems = 0 ;
1616
+ size_t takenItems = 0 ;
1617
+
1618
+ if (quantifierNode == nullptr || quantifierNode->type == NODE_TYPE_NOP) {
1619
+ // no quantifier. assume we need at least 1 item
1620
+ minRequiredItems = 1 ;
1621
+ maxRequiredItems = std::numeric_limits<decltype (maxRequiredItems)>::max ();
1622
+ } else {
1623
+ // note: quantifierNode can be a NODE_TYPE_QUANTIFIER (ALL|ANY|NONE),
1624
+ // a number (e.g. 3), or a range (e.g. 1..5)
1625
+ if (quantifierNode->type == NODE_TYPE_QUANTIFIER) {
1626
+ // ALL|ANY|NONE
1627
+ std::tie (minRequiredItems, maxRequiredItems) =
1628
+ Quantifier::requiredMatches (n, quantifierNode);
1629
+ } else if (quantifierNode->type == NODE_TYPE_RANGE) {
1630
+ // range
1631
+ TRI_ASSERT (quantifierNode->numMembers () == 2 );
1632
+ TRI_ASSERT (quantifierNode->getMember (0 )->isIntValue ());
1633
+
1634
+ minRequiredItems =
1635
+ static_cast <size_t >(quantifierNode->getMember (0 )->getIntValue ());
1636
+ TRI_ASSERT (quantifierNode->getMember (1 )->isIntValue ());
1637
+ maxRequiredItems =
1638
+ static_cast <size_t >(quantifierNode->getMember (1 )->getIntValue ());
1639
+ } else if (quantifierNode->isIntValue ()) {
1640
+ // exact value
1641
+ minRequiredItems = maxRequiredItems =
1642
+ static_cast <size_t >(quantifierNode->getIntValue ());
1643
+ } else {
1644
+ // quantifier type was already validated before.
1645
+ TRI_ASSERT (false );
1646
+ }
1647
+ }
1648
+
1649
+ TRI_ASSERT (minRequiredItems <= maxRequiredItems);
1650
+
1595
1651
for (size_t i = 0 ; i < n; ++i) {
1596
1652
bool localMustDestroy;
1597
1653
AqlValue item = value.at (i, localMustDestroy, false );
@@ -1623,16 +1679,16 @@ AqlValue Expression::executeSimpleExpressionExpansion(ExpressionContext& ctx,
1623
1679
}
1624
1680
1625
1681
if (takeItem) {
1626
- if (isBoolean) {
1627
- return AqlValue (AqlValueHintBool (true ));
1628
- }
1682
+ ++takenItems;
1629
1683
1630
- AqlValue sub = executeSimpleExpression (ctx, projectionNode,
1631
- localMustDestroy, false );
1632
- sub.toVelocyPack (&vopts, builder, /* resolveExternals*/ false ,
1633
- /* allowUnindexed*/ false );
1634
- if (localMustDestroy) {
1635
- sub.destroy ();
1684
+ if (!isBoolean) {
1685
+ AqlValue sub = executeSimpleExpression (ctx, projectionNode,
1686
+ localMustDestroy, false );
1687
+ sub.toVelocyPack (&vopts, builder, /* resolveExternals*/ false ,
1688
+ /* allowUnindexed*/ false );
1689
+ if (localMustDestroy) {
1690
+ sub.destroy ();
1691
+ }
1636
1692
}
1637
1693
}
1638
1694
ctx.clearVariable (variable);
@@ -1652,7 +1708,8 @@ AqlValue Expression::executeSimpleExpressionExpansion(ExpressionContext& ctx,
1652
1708
}
1653
1709
1654
1710
if (isBoolean) {
1655
- return AqlValue (AqlValueHintBool (false ));
1711
+ return AqlValue (AqlValueHintBool (takenItems >= minRequiredItems &&
1712
+ takenItems <= maxRequiredItems));
1656
1713
}
1657
1714
1658
1715
builder.close ();
0 commit comments