diff --git a/arangod/Aql/AqlFunctionFeature.cpp b/arangod/Aql/AqlFunctionFeature.cpp index 60c836d3e8..0e4c17233e 100644 --- a/arangod/Aql/AqlFunctionFeature.cpp +++ b/arangod/Aql/AqlFunctionFeature.cpp @@ -402,8 +402,7 @@ void AqlFunctionFeature::addDocumentFunctions() { &Functions::Merge}); add({"MERGE_RECURSIVE", "AQL_MERGE_RECURSIVE", ".,.|+", true, true, false, true, true, &Functions::MergeRecursive}); - add({"DOCUMENT", "AQL_DOCUMENT", "h.|.", false, false, true, false, true, - &Functions::Document, NotInCluster}); + add({"DOCUMENT", "AQL_DOCUMENT", "h.|.", false, false, true, false, true, &Functions::Document}); add({"MATCHES", "AQL_MATCHES", ".,.|.", true, true, false, true, true}); add({"UNSET", "AQL_UNSET", ".,.|+", true, true, false, true, true, &Functions::Unset}); diff --git a/arangod/Aql/AstNode.cpp b/arangod/Aql/AstNode.cpp index d69b57844e..4f2ae9b25a 100644 --- a/arangod/Aql/AstNode.cpp +++ b/arangod/Aql/AstNode.cpp @@ -1429,7 +1429,8 @@ bool AstNode::isSimple() const { } if (type == NODE_TYPE_REFERENCE || type == NODE_TYPE_VALUE || - type == NODE_TYPE_VARIABLE || type == NODE_TYPE_NOP) { + type == NODE_TYPE_VARIABLE || type == NODE_TYPE_NOP || + type == NODE_TYPE_QUANTIFIER) { setFlag(DETERMINED_SIMPLE, VALUE_SIMPLE); return true; } @@ -1438,7 +1439,41 @@ bool AstNode::isSimple() const { type == NODE_TYPE_EXPANSION || type == NODE_TYPE_ITERATOR || type == NODE_TYPE_ARRAY_LIMIT || type == NODE_TYPE_CALCULATED_OBJECT_ELEMENT || - type == NODE_TYPE_OPERATOR_TERNARY) { + type == NODE_TYPE_OPERATOR_TERNARY || + type == NODE_TYPE_OPERATOR_NARY_AND || + type == NODE_TYPE_OPERATOR_NARY_OR || + type == NODE_TYPE_OPERATOR_BINARY_PLUS || + type == NODE_TYPE_OPERATOR_BINARY_MINUS || + type == NODE_TYPE_OPERATOR_BINARY_TIMES || + type == NODE_TYPE_OPERATOR_BINARY_DIV || + type == NODE_TYPE_OPERATOR_BINARY_MOD || + type == NODE_TYPE_OPERATOR_BINARY_AND || + type == NODE_TYPE_OPERATOR_BINARY_OR || + type == NODE_TYPE_OPERATOR_BINARY_EQ || + type == NODE_TYPE_OPERATOR_BINARY_NE || + type == NODE_TYPE_OPERATOR_BINARY_LT || + type == NODE_TYPE_OPERATOR_BINARY_LE || + type == NODE_TYPE_OPERATOR_BINARY_GT || + type == NODE_TYPE_OPERATOR_BINARY_GE || + type == NODE_TYPE_OPERATOR_BINARY_IN || + type == NODE_TYPE_OPERATOR_BINARY_NIN || + type == NODE_TYPE_OPERATOR_BINARY_ARRAY_EQ || + type == NODE_TYPE_OPERATOR_BINARY_ARRAY_NE || + type == NODE_TYPE_OPERATOR_BINARY_ARRAY_LT || + type == NODE_TYPE_OPERATOR_BINARY_ARRAY_LE || + type == NODE_TYPE_OPERATOR_BINARY_ARRAY_GT || + type == NODE_TYPE_OPERATOR_BINARY_ARRAY_GE || + type == NODE_TYPE_OPERATOR_BINARY_ARRAY_IN || + type == NODE_TYPE_OPERATOR_BINARY_ARRAY_NIN || + type == NODE_TYPE_RANGE || + type == NODE_TYPE_INDEXED_ACCESS || + type == NODE_TYPE_PASSTHRU || + type == NODE_TYPE_OBJECT_ELEMENT || + type == NODE_TYPE_ATTRIBUTE_ACCESS || + type == NODE_TYPE_BOUND_ATTRIBUTE_ACCESS || + type == NODE_TYPE_OPERATOR_UNARY_NOT || + type == NODE_TYPE_OPERATOR_UNARY_PLUS || + type == NODE_TYPE_OPERATOR_UNARY_MINUS) { size_t const n = numMembers(); for (size_t i = 0; i < n; ++i) { @@ -1454,31 +1489,6 @@ bool AstNode::isSimple() const { return true; } - if (type == NODE_TYPE_OBJECT_ELEMENT || type == NODE_TYPE_ATTRIBUTE_ACCESS || - type == NODE_TYPE_OPERATOR_UNARY_NOT || - type == NODE_TYPE_OPERATOR_UNARY_PLUS || - type == NODE_TYPE_OPERATOR_UNARY_MINUS) { - TRI_ASSERT(numMembers() == 1); - - if (!getMember(0)->isSimple()) { - setFlag(DETERMINED_SIMPLE); - return false; - } - - setFlag(DETERMINED_SIMPLE, VALUE_SIMPLE); - return true; - } - - if (type == NODE_TYPE_BOUND_ATTRIBUTE_ACCESS) { - if (!getMember(0)->isSimple()) { - setFlag(DETERMINED_SIMPLE); - return false; - } - - setFlag(DETERMINED_SIMPLE, VALUE_SIMPLE); - return true; - } - if (type == NODE_TYPE_FCALL) { // some functions have C++ handlers // check if the called function is one of them @@ -1528,63 +1538,6 @@ bool AstNode::isSimple() const { return true; } - if (type == NODE_TYPE_OPERATOR_BINARY_PLUS || - type == NODE_TYPE_OPERATOR_BINARY_MINUS || - type == NODE_TYPE_OPERATOR_BINARY_TIMES || - type == NODE_TYPE_OPERATOR_BINARY_DIV || - type == NODE_TYPE_OPERATOR_BINARY_MOD) { - if (!getMember(0)->isSimple() || !getMember(1)->isSimple()) { - setFlag(DETERMINED_SIMPLE); - return false; - } - setFlag(DETERMINED_SIMPLE, VALUE_SIMPLE); - return true; - } - - if (type == NODE_TYPE_OPERATOR_BINARY_AND || - type == NODE_TYPE_OPERATOR_BINARY_OR || - type == NODE_TYPE_OPERATOR_BINARY_EQ || - type == NODE_TYPE_OPERATOR_BINARY_NE || - type == NODE_TYPE_OPERATOR_BINARY_LT || - type == NODE_TYPE_OPERATOR_BINARY_LE || - type == NODE_TYPE_OPERATOR_BINARY_GT || - type == NODE_TYPE_OPERATOR_BINARY_GE || - type == NODE_TYPE_OPERATOR_BINARY_IN || - type == NODE_TYPE_OPERATOR_BINARY_NIN || - type == NODE_TYPE_OPERATOR_BINARY_ARRAY_EQ || - type == NODE_TYPE_OPERATOR_BINARY_ARRAY_NE || - type == NODE_TYPE_OPERATOR_BINARY_ARRAY_LT || - type == NODE_TYPE_OPERATOR_BINARY_ARRAY_LE || - type == NODE_TYPE_OPERATOR_BINARY_ARRAY_GT || - type == NODE_TYPE_OPERATOR_BINARY_ARRAY_GE || - type == NODE_TYPE_OPERATOR_BINARY_ARRAY_IN || - type == NODE_TYPE_OPERATOR_BINARY_ARRAY_NIN || type == NODE_TYPE_RANGE || - type == NODE_TYPE_INDEXED_ACCESS || type == NODE_TYPE_PASSTHRU) { - // a logical operator is simple if its operands are simple - // a comparison operator is simple if both bounds are simple - // a range is simple if both bounds are simple - if (!getMember(0)->isSimple() || !getMember(1)->isSimple()) { - setFlag(DETERMINED_SIMPLE); - return false; - } - - setFlag(DETERMINED_SIMPLE, VALUE_SIMPLE); - return true; - } - - if (type == NODE_TYPE_OPERATOR_NARY_AND || - type == NODE_TYPE_OPERATOR_NARY_OR) { - // a logical operator is simple if all its operands are simple - for (auto const& it : members) { - if (!it->isSimple()) { - setFlag(DETERMINED_SIMPLE); - return false; - } - } - setFlag(DETERMINED_SIMPLE, VALUE_SIMPLE); - return true; - } - setFlag(DETERMINED_SIMPLE); return false; } diff --git a/js/server/tests/aql/aql-queries-document.js b/js/server/tests/aql/aql-queries-document.js new file mode 100644 index 0000000000..b576190a9a --- /dev/null +++ b/js/server/tests/aql/aql-queries-document.js @@ -0,0 +1,91 @@ +/*jshint globalstrict:false, strict:false, maxlen: 850 */ +/*global assertEqual, AQL_EXECUTE, AQL_EXPLAIN */ + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tests for query language +/// +/// DISCLAIMER +/// +/// Copyright 2010-2012 triagens GmbH, Cologne, Germany +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// +/// Copyright holder is triAGENS GmbH, Cologne, Germany +/// +/// @author Jan Steemann +/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +var jsunity = require("jsunity"); +var internal = require("internal"); +var helper = require("@arangodb/aql-helper"); + +function ahuacatlDocumentsTestSuite () { + var c = null; + const cn = "UnitTestsDocument"; + let execQuery = function (numberOfShards) { + c = internal.db._create("UnitTestsDocument", { numberOfShards }); + + let i; + for (i = 1; i <= 2000; ++i) { + c.insert({ _key: "test" + i, value: i }); + } + + var query = "FOR i IN 1..2000 RETURN DOCUMENT(CONCAT('" + cn + "/test', TO_NUMBER(i)))"; + var nodes = helper.removeClusterNodesFromPlan(AQL_EXPLAIN(query).plan.nodes); + assertEqual("CalculationNode", nodes[nodes.length - 2].type); + assertEqual("simple", nodes[nodes.length - 2].expressionType); + assertEqual("function call", nodes[nodes.length - 2].expression.type); + assertEqual("DOCUMENT", nodes[nodes.length - 2].expression.name); + + var actual = AQL_EXECUTE(query).json.sort(function(l, r) { return l.value - r.value; }); + assertEqual(2000, actual.length); + for (i = 1; i <= 2000; ++i) { + assertEqual(i, actual[i - 1].value); + assertEqual('test' + i, actual[i - 1]._key); + } + }; + + return { + + setUp : function () { + internal.db._drop(cn); + }, + + tearDown : function () { + internal.db._drop(cn); + }, + + testOneShard : function () { + execQuery(1); + }, + + testTwoShards : function () { + execQuery(2); + }, + + testFourShards : function () { + execQuery(4); + } + + }; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief executes the test suite +//////////////////////////////////////////////////////////////////////////////// + +jsunity.run(ahuacatlDocumentsTestSuite); + +return jsunity.done(); +