diff --git a/arangod/Aql/Executor.cpp b/arangod/Aql/Executor.cpp index bbdd0caeeb..b66138cd89 100644 --- a/arangod/Aql/Executor.cpp +++ b/arangod/Aql/Executor.cpp @@ -68,14 +68,14 @@ std::unordered_map(NODE_TYPE_OPERATOR_BINARY_AND), "LOGICAL_AND"}, {static_cast(NODE_TYPE_OPERATOR_BINARY_OR), "LOGICAL_OR"}, {static_cast(NODE_TYPE_OPERATOR_TERNARY), "TERNARY_OPERATOR"}, - {static_cast(NODE_TYPE_OPERATOR_BINARY_EQ), "RELATIONAL_ARRAY_EQUAL"}, - {static_cast(NODE_TYPE_OPERATOR_BINARY_NE), "RELATIONAL_ARRAY_UNEQUAL"}, - {static_cast(NODE_TYPE_OPERATOR_BINARY_GT), "RELATIONAL_ARRAY_GREATER"}, - {static_cast(NODE_TYPE_OPERATOR_BINARY_GE), "RELATIONAL_ARRAY_GREATEREQUAL"}, - {static_cast(NODE_TYPE_OPERATOR_BINARY_LT), "RELATIONAL_ARRAY_LESS"}, - {static_cast(NODE_TYPE_OPERATOR_BINARY_LE), "RELATIONAL_ARRAY_LESSEQUAL"}, - {static_cast(NODE_TYPE_OPERATOR_BINARY_IN), "RELATIONAL_ARRAY_IN"}, - {static_cast(NODE_TYPE_OPERATOR_BINARY_NIN), "RELATIONAL_ARRAY_NOT_IN"}}; + {static_cast(NODE_TYPE_OPERATOR_BINARY_ARRAY_EQ), "RELATIONAL_ARRAY_EQUAL"}, + {static_cast(NODE_TYPE_OPERATOR_BINARY_ARRAY_NE), "RELATIONAL_ARRAY_UNEQUAL"}, + {static_cast(NODE_TYPE_OPERATOR_BINARY_ARRAY_GT), "RELATIONAL_ARRAY_GREATER"}, + {static_cast(NODE_TYPE_OPERATOR_BINARY_ARRAY_GE), "RELATIONAL_ARRAY_GREATEREQUAL"}, + {static_cast(NODE_TYPE_OPERATOR_BINARY_ARRAY_LT), "RELATIONAL_ARRAY_LESS"}, + {static_cast(NODE_TYPE_OPERATOR_BINARY_ARRAY_LE), "RELATIONAL_ARRAY_LESSEQUAL"}, + {static_cast(NODE_TYPE_OPERATOR_BINARY_ARRAY_IN), "RELATIONAL_ARRAY_IN"}, + {static_cast(NODE_TYPE_OPERATOR_BINARY_ARRAY_NIN), "RELATIONAL_ARRAY_NOT_IN"}}; //////////////////////////////////////////////////////////////////////////////// /// @brief user-accessible functions @@ -1103,9 +1103,10 @@ void Executor::generateCodeBinaryArrayOperator(AstNode const* node) { generateCodeNode(node->getMember(1)); AstNode const* quantifier = node->getMember(2); + if (quantifier->type == NODE_TYPE_QUANTIFIER) { _buffer->appendChar(','); - _buffer->appendInteger(node->getIntValue()); + _buffer->appendInteger(quantifier->getIntValue(true)); } _buffer->appendChar(')'); diff --git a/arangod/Aql/Expression.cpp b/arangod/Aql/Expression.cpp index 7c96db58bf..304ddda02a 100644 --- a/arangod/Aql/Expression.cpp +++ b/arangod/Aql/Expression.cpp @@ -1102,7 +1102,7 @@ AqlValue Expression::executeSimpleExpressionArrayComparison( std::pair requiredMatches = Quantifier::RequiredMatches(n, node->getMember(2)); TRI_ASSERT(requiredMatches.first <= requiredMatches.second); - + // for equality and non-equality we can use a binary comparison bool const compareUtf8 = (node->type != NODE_TYPE_OPERATOR_BINARY_ARRAY_EQ && node->type != NODE_TYPE_OPERATOR_BINARY_ARRAY_NE); @@ -1111,7 +1111,7 @@ AqlValue Expression::executeSimpleExpressionArrayComparison( size_t matches = 0; size_t numLeft = n; - for (size_t i = 0; i < n; ++i, --numLeft) { + for (size_t i = 0; i < n; ++i) { auto leftItem = left.extractArrayMember(trx, leftCollection, static_cast(i), false); AqlValue leftItemValue(&leftItem); bool result; @@ -1156,6 +1156,8 @@ AqlValue Expression::executeSimpleExpressionArrayComparison( TRI_ASSERT(false); } } + + --numLeft; if (result) { ++matches; diff --git a/arangod/Aql/Quantifier.cpp b/arangod/Aql/Quantifier.cpp index e3dade41d1..7771c7218d 100644 --- a/arangod/Aql/Quantifier.cpp +++ b/arangod/Aql/Quantifier.cpp @@ -87,6 +87,7 @@ std::pair Quantifier::RequiredMatches(size_t inputSize, AstNode } // won't be reached + TRI_ASSERT(false); return std::make_pair(SIZE_MAX, SIZE_MAX); } diff --git a/js/apps/system/_admin/aardvark/APP/frontend/js/modules/common/@arangodb/aql/explainer.js b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/common/@arangodb/aql/explainer.js index b4eb7ac92d..c9b1703617 100644 --- a/js/apps/system/_admin/aardvark/APP/frontend/js/modules/common/@arangodb/aql/explainer.js +++ b/js/apps/system/_admin/aardvark/APP/frontend/js/modules/common/@arangodb/aql/explainer.js @@ -447,13 +447,13 @@ function processQuery (query, explain) { var lhs = buildExpression(node.subNodes[0]); var rhs = buildExpression(node.subNodes[1]); if (node.subNodes.length === 3) { - // array operator node... prepend "all" | "any" | "none" + // array operator node... prepend "all" | "any" | "none" to node type name = node.subNodes[2].quantifier + " " + name; } if (node.sorted) { return lhs + " " + name + " " + annotation("/* sorted */") + " " + rhs; } - return lhs + " " + name + " " + rhs;; + return lhs + " " + name + " " + rhs; }; isConst = isConst && ([ "value", "object", "object element", "array" ].indexOf(node.type) !== -1); diff --git a/js/common/modules/@arangodb/aql/explainer.js b/js/common/modules/@arangodb/aql/explainer.js index 72c88f2d6e..76d5b90440 100644 --- a/js/common/modules/@arangodb/aql/explainer.js +++ b/js/common/modules/@arangodb/aql/explainer.js @@ -446,13 +446,13 @@ function processQuery (query, explain) { var lhs = buildExpression(node.subNodes[0]); var rhs = buildExpression(node.subNodes[1]); if (node.subNodes.length === 3) { - // array operator node... prepend "all" | "any" | "none" + // array operator node... prepend "all" | "any" | "none" to node type name = node.subNodes[2].quantifier + " " + name; } if (node.sorted) { return lhs + " " + name + " " + annotation("/* sorted */") + " " + rhs; } - return lhs + " " + name + " " + rhs;; + return lhs + " " + name + " " + rhs; }; isConst = isConst && ([ "value", "object", "object element", "array" ].indexOf(node.type) !== -1); diff --git a/js/server/modules/@arangodb/aql.js b/js/server/modules/@arangodb/aql.js index d6984065de..15b63e5047 100644 --- a/js/server/modules/@arangodb/aql.js +++ b/js/server/modules/@arangodb/aql.js @@ -1458,27 +1458,55 @@ function LOGICAL_NOT (lhs) { /// @brief perform equality check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_FUNC (lhs, rhs, all, func) { +function RELATIONAL_ARRAY_FUNC (lhs, rhs, quantifier, func) { 'use strict'; if (TYPEWEIGHT(lhs) !== TYPEWEIGHT_ARRAY) { return false; } - var n = lhs.length; + var n = lhs.length, min, max; + if (quantifier === 1) { + // NONE + min = max = 0; + } + else if (quantifier === 2) { + // ALL + min = max = n; + } + else if (quantifier === 3) { + // ANY + min = (n === 0 ? 0 : 1); + max = n; + } + + var left = n, matches = 0; for (var i = 0; i < n; ++i) { var result = func(lhs[i], rhs); - if (all && !result) { - return false; + --left; + + if (result) { + ++matches; + if (matches > max) { + // too many matches + return false; + } + if (matches >= min && matches + left <= max) { + // enough matches + return true; + } } - if (!all && result) { - return true; + else { + if (matches + left < min) { + // too few matches + return false; + } } } + return true; } - //////////////////////////////////////////////////////////////////////////////// /// @brief perform equality check /// @@ -1925,80 +1953,80 @@ function RELATIONAL_NOT_IN (lhs, rhs) { /// @brief perform equality check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_EQUAL (lhs, rhs, all) { +function RELATIONAL_ARRAY_EQUAL (lhs, rhs, quantifier) { 'use strict'; - return RELATIONAL_ARRAY_FUNC(lhs, rhs, all, RELATIONAL_EQUAL); + return RELATIONAL_ARRAY_FUNC(lhs, rhs, quantifier, RELATIONAL_EQUAL); } //////////////////////////////////////////////////////////////////////////////// /// @brief perform unequality check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_UNEQUAL (lhs, rhs, all) { +function RELATIONAL_ARRAY_UNEQUAL (lhs, rhs, quantifier) { 'use strict'; - return RELATIONAL_ARRAY_FUNC(lhs, rhs, all, RELATIONAL_UNEQUAL); + return RELATIONAL_ARRAY_FUNC(lhs, rhs, quantifier, RELATIONAL_UNEQUAL); } //////////////////////////////////////////////////////////////////////////////// /// @brief perform greater check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_GREATER (lhs, rhs, all) { +function RELATIONAL_ARRAY_GREATER (lhs, rhs, quantifier) { 'use strict'; - return RELATIONAL_ARRAY_FUNC(lhs, rhs, all, RELATIONAL_GREATER); + return RELATIONAL_ARRAY_FUNC(lhs, rhs, quantifier, RELATIONAL_GREATER); } //////////////////////////////////////////////////////////////////////////////// /// @brief perform greater equal check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_GREATEREQUAL (lhs, rhs, all) { +function RELATIONAL_ARRAY_GREATEREQUAL (lhs, rhs, quantifier) { 'use strict'; - return RELATIONAL_ARRAY_FUNC(lhs, rhs, all, RELATIONAL_GREATEREQUAL); + return RELATIONAL_ARRAY_FUNC(lhs, rhs, quantifier, RELATIONAL_GREATEREQUAL); } //////////////////////////////////////////////////////////////////////////////// /// @brief perform less check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_LESS (lhs, rhs, all) { +function RELATIONAL_ARRAY_LESS (lhs, rhs, quantifier) { 'use strict'; - return RELATIONAL_ARRAY_FUNC(lhs, rhs, all, RELATIONAL_LESS); + return RELATIONAL_ARRAY_FUNC(lhs, rhs, quantifier, RELATIONAL_LESS); } //////////////////////////////////////////////////////////////////////////////// /// @brief perform less equal check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_LESSEQUAL (lhs, rhs, all) { +function RELATIONAL_ARRAY_LESSEQUAL (lhs, rhs, quantifier) { 'use strict'; - return RELATIONAL_ARRAY_FUNC(lhs, rhs, all, RELATIONAL_LESSEQUAL); + return RELATIONAL_ARRAY_FUNC(lhs, rhs, quantifier, RELATIONAL_LESSEQUAL); } //////////////////////////////////////////////////////////////////////////////// /// @brief perform in check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_IN (lhs, rhs, all) { +function RELATIONAL_ARRAY_IN (lhs, rhs, quantifier) { 'use strict'; - return RELATIONAL_ARRAY_FUNC(lhs, rhs, all, RELATIONAL_IN); + return RELATIONAL_ARRAY_FUNC(lhs, rhs, quantifier, RELATIONAL_IN); } //////////////////////////////////////////////////////////////////////////////// /// @brief perform in check for arrays //////////////////////////////////////////////////////////////////////////////// -function RELATIONAL_ARRAY_NOT_IN (lhs, rhs, all) { +function RELATIONAL_ARRAY_NOT_IN (lhs, rhs, quantifier) { 'use strict'; - return RELATIONAL_ARRAY_FUNC(lhs, rhs, all, RELATIONAL_NOT_IN); + return RELATIONAL_ARRAY_FUNC(lhs, rhs, quantifier, RELATIONAL_NOT_IN); } ////////////////////////////////////////////////////////////////////////////////