diff --git a/arangod/Indexes/PrimaryIndex.cpp b/arangod/Indexes/PrimaryIndex.cpp index 2f5e329d1b..c8f5429511 100644 --- a/arangod/Indexes/PrimaryIndex.cpp +++ b/arangod/Indexes/PrimaryIndex.cpp @@ -93,6 +93,25 @@ TRI_doc_mptr_t* PrimaryIndexIterator::next() { return nullptr; } +void PrimaryIndexIterator::nextBabies(std::vector& buffer, size_t limit) { + size_t atMost = limit; + + buffer.clear(); + + while (_iterator.valid() && atMost > 0) { + auto result = _index->lookup(_trx, _iterator.value()); + _iterator.next(); + + if (result == nullptr) { + return; + } + + buffer.emplace_back(result); + --atMost; + } +} + + void PrimaryIndexIterator::reset() { _iterator.reset(); } TRI_doc_mptr_t* AllIndexIterator::next() { @@ -102,6 +121,23 @@ TRI_doc_mptr_t* AllIndexIterator::next() { return _index->findSequential(_trx, _position, _total); }; +void AllIndexIterator::nextBabies(std::vector& buffer, size_t limit) { + size_t atMost = limit; + + buffer.clear(); + + while (atMost > 0) { + auto result = next(); + + if (result == nullptr) { + return; + } + + buffer.emplace_back(result); + --atMost; + } +} + void AllIndexIterator::reset() { _position.reset(); } TRI_doc_mptr_t* AnyIndexIterator::next() { diff --git a/arangod/Indexes/PrimaryIndex.h b/arangod/Indexes/PrimaryIndex.h index 4a27c622c5..aeed4fba58 100644 --- a/arangod/Indexes/PrimaryIndex.h +++ b/arangod/Indexes/PrimaryIndex.h @@ -56,6 +56,8 @@ class PrimaryIndexIterator final : public IndexIterator { ~PrimaryIndexIterator() {} TRI_doc_mptr_t* next() override; + + void nextBabies(std::vector&, size_t) override; void reset() override; @@ -79,6 +81,8 @@ class AllIndexIterator final : public IndexIterator { ~AllIndexIterator() {} TRI_doc_mptr_t* next() override; + + void nextBabies(std::vector&, size_t) override; void reset() override; diff --git a/js/server/modules/@arangodb/aql-helper.js b/js/server/modules/@arangodb/aql-helper.js index 8239ec160c..fa715a552d 100644 --- a/js/server/modules/@arangodb/aql-helper.js +++ b/js/server/modules/@arangodb/aql-helper.js @@ -255,6 +255,21 @@ function assertQueryWarningAndNull (errorCode, query, bindVars) { assertEqual([ null ], result.json); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief assert a specific warning running a query +//////////////////////////////////////////////////////////////////////////////// + +function assertQueryWarningAndFalse (errorCode, query, bindVars) { + var result = AQL_EXECUTE(query, bindVars), i, found = { }; + + for (i = 0; i < result.warnings.length; ++i) { + found[result.warnings[i].code] = true; + } + + assertTrue(found[errorCode]); + assertEqual([ false ], result.json); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief get a linearized version of an execution plan //////////////////////////////////////////////////////////////////////////////// @@ -477,6 +492,7 @@ exports.getRawQueryResults = getRawQueryResults; exports.getQueryResults = getQueryResults; exports.assertQueryError = assertQueryError; exports.assertQueryWarningAndNull = assertQueryWarningAndNull; +exports.assertQueryWarningAndFalse = assertQueryWarningAndFalse; exports.getLinearizedPlan = getLinearizedPlan; exports.getCompactPlan = getCompactPlan; exports.findExecutionNodes = findExecutionNodes; diff --git a/js/server/tests/aql/aql-functions-string.js b/js/server/tests/aql/aql-functions-string.js index 533734e72b..a8c67c01cd 100644 --- a/js/server/tests/aql/aql-functions-string.js +++ b/js/server/tests/aql/aql-functions-string.js @@ -34,6 +34,7 @@ var jsunity = require("jsunity"); var helper = require("@arangodb/aql-helper"); var getQueryResults = helper.getQueryResults; var assertQueryError = helper.assertQueryError; +var assertQueryWarningAndFalse = helper.assertQueryWarningAndFalse; //////////////////////////////////////////////////////////////////////////////// /// @brief test suite @@ -56,6 +57,135 @@ function ahuacatlStringFunctionsTestSuite () { tearDown : function () { }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test regex function, invalid arguments +//////////////////////////////////////////////////////////////////////////////// + + testRegexInvalid : function () { + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REGEX()"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REGEX(\"test\")"); + assertQueryError(errors.ERROR_QUERY_FUNCTION_ARGUMENT_NUMBER_MISMATCH.code, "RETURN REGEX(\"test\", \"meow\", \"foo\", \"bar\")"); + + assertQueryWarningAndFalse(errors.ERROR_QUERY_INVALID_REGEX.code, "RETURN REGEX(\"test\", \"[\")"); + assertQueryWarningAndFalse(errors.ERROR_QUERY_INVALID_REGEX.code, "RETURN REGEX(\"test\", \"[^\")"); + assertQueryWarningAndFalse(errors.ERROR_QUERY_INVALID_REGEX.code, "RETURN REGEX(\"test\", \"a.(\")"); + assertQueryWarningAndFalse(errors.ERROR_QUERY_INVALID_REGEX.code, "RETURN REGEX(\"test\", \"(a\")"); + assertQueryWarningAndFalse(errors.ERROR_QUERY_INVALID_REGEX.code, "RETURN REGEX(\"test\", \"(a]\")"); + assertQueryWarningAndFalse(errors.ERROR_QUERY_INVALID_REGEX.code, "RETURN REGEX(\"test\", \"**\")"); + assertQueryWarningAndFalse(errors.ERROR_QUERY_INVALID_REGEX.code, "RETURN REGEX(\"test\", \"?\")"); + assertQueryWarningAndFalse(errors.ERROR_QUERY_INVALID_REGEX.code, "RETURN REGEX(\"test\", \"*\")"); + }, + + testRegex : function () { + var values = [ + // whole words + ["the quick brown fox", "the", true], + ["the quick brown fox", "quick", true], + ["the quick brown fox", "quicK", false], + ["the quick brown fox", "quIcK", false], + ["the quick brown fox", "brown", true], + ["the quick brown fox", "fox", true], + ["the quick brown fox", "The", false], + ["the quick brown fox", "THE", false], + ["the quick brown fox", "foxx", false], + ["the quick brown fox", "hasi", false], + + // anchored + ["the quick brown fox", "^the", true], + ["the quick brown fox", "^the$", false], + ["the quick brown fox", "^the quick", true], + ["the quick brown fox", "^the quick brown", true], + ["the quick brown fox", "^the quick brown fo", true], + ["the quick brown fox", "^th", true], + ["the quick brown fox", "^t", true], + ["the quick brown fox", "^the quick$", false], + ["the quick brown fox", "^quick", false], + ["the quick brown fox", "quick$", false], + ["the quick brown fox", "^quick$", false], + ["the quick brown fox", "^brown", false], + ["the quick brown fox", "brown$", false], + ["the quick brown fox", "^brown$", false], + ["the quick brown fox", "fox", true], + ["the quick brown fox", "fox$", true], + ["the quick brown fox", "^fox$", false], + ["the quick brown fox", "The", false], + ["the quick brown fox", "^The", false], + ["the quick brown fox", "THE", false], + ["the quick brown fox", "^THE", false], + ["the quick brown fox", "foxx", false], + ["the quick brown fox", "foxx$", false], + ["the quick brown fox", "the quick brown fox$", true], + ["the quick brown fox", "brown fox$", true], + ["the quick brown fox", "quick brown fox$", true], + ["the quick brown fox", "he quick brown fox$", true], + ["the quick brown fox", "e quick brown fox$", true], + ["the quick brown fox", "quick brown fox$", true], + ["the quick brown fox", "x$", true], + ["the quick brown fox", "^", true], + ["the quick brown fox", "$", true], + ["the quick brown fox", "^.*$", true], + ["the quick brown fox", ".*", true], + ["the quick brown fox", "^.*", true], + ["the quick brown fox", "^.*$", true], + + // partials + ["the quick brown fox", " quick", true], + ["the quick brown fox", " Quick", false], + ["the quick brown fox", "the quick", true], + ["the quick brown fox", "the slow", false], + ["the quick brown fox", "the quick brown", true], + ["the quick brown fox", "the quick browne", false], + ["the quick brown fox", "the quick brownfox", false], + ["the quick brown fox", "the quick brown fox", true], + ["the quick brown fox", "the quick brown foxx", false], + ["the quick brown fox", "quick brown fox", true], + ["the quick brown fox", "a quick brown fox", false], + ["the quick brown fox", "brown fox", true], + ["the quick brown fox", "rown fox", true], + ["the quick brown fox", "rown f", true], + ["the quick brown fox", "e q", true], + ["the quick brown fox", "f z", false], + ["the quick brown fox", "red fo", false], + ["the quick brown fox", "köter", false], + ["the quick brown fox", "ö", false], + ["the quick brown fox", "z", false], + ["the quick brown fox", "z", false], + ["the quick brown fox", " ", true], + ["the quick brown fox", " ", false], + ["the quick brown fox", "", true], + + // wildcards + ["the quick brown fox", "the.*fox", true], + ["the quick brown fox", "^the.*fox$", true], + ["the quick brown fox", "^the.*dog$", false], + ["the quick brown fox", "the (quick|slow) (red|green|brown) (dog|cat|fox)", true], + ["the quick brown fox", "the .*(red|green|brown) (dog|cat|fox)", true], + ["the quick brown fox", "^the .*(red|green|brown) (dog|cat|fox)", true], + ["the quick brown fox", "the (quick|slow) (red|green|brown) (dog|cat)", false], + ["the quick brown fox", "^the (quick|slow) (red|green|brown) (dog|cat)", false], + ["the quick brown fox", "^the .*(red|green|brown) (dog|cat)", false], + ["the quick brown fox", "the .*(red|green|brown) (dog|cat)", false], + ["the quick brown fox", "the (slow|lazy) brown (fox|wolf)", false], + ["the quick brown fox", "the.*brown (fox|wolf)", true], + ["the quick brown fox", "^t.*(fox|wolf)", true], + ["the quick brown fox", "^t.*(fox|wolf)$", true], + ["the quick brown fox", "^t.*(fo|wolf)x$", true], + ["the quick brown fox", "^t.*(fo|wolf)xx", false], + ]; + + values.forEach(function(v) { + var query = "RETURN REGEX(@what, @re)"; + assertEqual(v[2], getQueryResults(query, { what: v[0], re: v[1] })[0], v); + + query = "RETURN NOOPT(REGEX(@what, @re))"; + assertEqual(v[2], getQueryResults(query, { what: v[0], re: v[1] })[0], v); + + query = "RETURN NOOPT(V8(REGEX(@what, @re)))"; + assertEqual(v[2], getQueryResults(query, { what: v[0], re: v[1] })[0], v); + }); + + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test like function, invalid arguments ////////////////////////////////////////////////////////////////////////////////