mirror of https://gitee.com/bigwinds/arangodb
do not simplify non-deterministic conditions (#7926)
This commit is contained in:
parent
79257310c0
commit
e42befdc52
|
@ -421,7 +421,8 @@ void AqlFunctionFeature::addMiscFunctions() {
|
|||
add({"VERSION", "", Function::makeFlags(FF::Deterministic), &Functions::Version}); // deterministic, not cacheable. only on
|
||||
// coordinator
|
||||
add({"FAIL", "|.", Function::makeFlags(FF::CanRunOnDBServer), &Functions::Fail}); // not deterministic and not cacheable
|
||||
add({"NOOPT", ".", Function::makeFlags(FF::CanRunOnDBServer), &Functions::Passthru}); // prevents all optimizations!
|
||||
add({"NOOPT", ".", Function::makeFlags(FF::CanRunOnDBServer, FF::NoEval), &Functions::Passthru}); // prevents all optimizations!
|
||||
add({"NOEVAL", ".", Function::makeFlags(FF::Deterministic, FF::CanRunOnDBServer, FF::NoEval), &Functions::Passthru}); // prevents all optimizations!
|
||||
add({"SLEEP", ".", Function::makeFlags(FF::CanRunOnDBServer), &Functions::Sleep}); // not deterministic and not cacheable
|
||||
add({"COLLECTIONS", "", Function::makeFlags(), &Functions::Collections}); // not deterministic and not cacheable
|
||||
add({"CURRENT_USER", "", Function::makeFlags(FF::Deterministic),
|
||||
|
@ -439,6 +440,8 @@ void AqlFunctionFeature::addMiscFunctions() {
|
|||
// NEAR, WITHIN, WITHIN_RECTANGLE and FULLTEXT are replaced by the AQL
|
||||
// optimizer with collection-based subqueries they are all not marked as
|
||||
// non-deterministic and non-cacheable here as they refer to documents
|
||||
// note further that all of these function call will be replaced by equivalent
|
||||
// subqueries by the optimizer
|
||||
add({"NEAR", ".h,.,.|.,.", Function::makeFlags(), &Functions::NotImplemented});
|
||||
add({"WITHIN", ".h,.,.,.|.", Function::makeFlags(), &Functions::NotImplemented});
|
||||
add({"WITHIN_RECTANGLE", "h.,.,.,.,.", Function::makeFlags(), &Functions::NotImplemented});
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "Aql/Graphs.h"
|
||||
#include "Aql/Query.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "Basics/SmallVector.h"
|
||||
#include "Basics/StringRef.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "Basics/tri-strings.h"
|
||||
|
@ -98,7 +99,7 @@ LogicalDataSource::Category const* injectDataSourceInQuery(
|
|||
// name has changed by the lookup, so we need to reserve the collection
|
||||
// name on the heap and update our StringRef
|
||||
char* p = query.registerString(dataSourceName.data(), dataSourceName.size());
|
||||
nameRef = StringRef(p, dataSourceName.size());
|
||||
nameRef = arangodb::StringRef(p, dataSourceName.size());
|
||||
}
|
||||
|
||||
// add views to the collection list
|
||||
|
@ -664,7 +665,7 @@ AstNode* Ast::createNodeDataSource(arangodb::CollectionNameResolver const& resol
|
|||
char const* name, size_t nameLength,
|
||||
AccessMode::Type accessType,
|
||||
bool validateName, bool failIfDoesNotExist) {
|
||||
StringRef nameRef(name, nameLength);
|
||||
arangodb::StringRef nameRef(name, nameLength);
|
||||
|
||||
// will throw if validation fails
|
||||
validateDataSourceName(nameRef, validateName);
|
||||
|
@ -691,7 +692,7 @@ AstNode* Ast::createNodeDataSource(arangodb::CollectionNameResolver const& resol
|
|||
AstNode* Ast::createNodeCollection(arangodb::CollectionNameResolver const& resolver,
|
||||
char const* name, size_t nameLength,
|
||||
AccessMode::Type accessType) {
|
||||
StringRef nameRef(name, nameLength);
|
||||
arangodb::StringRef nameRef(name, nameLength);
|
||||
|
||||
// will throw if validation fails
|
||||
validateDataSourceName(nameRef, true);
|
||||
|
@ -1158,7 +1159,7 @@ AstNode* Ast::createNodeWithCollections(AstNode const* collections,
|
|||
if (c->isStringValue()) {
|
||||
std::string const name = c->getString();
|
||||
// this call may update nameRef
|
||||
StringRef nameRef(name);
|
||||
arangodb::StringRef nameRef(name);
|
||||
LogicalDataSource::Category const* category =
|
||||
injectDataSourceInQuery(*_query, resolver, AccessMode::Type::READ, false, nameRef);
|
||||
if (category == LogicalCollection::category()) {
|
||||
|
@ -1174,7 +1175,7 @@ AstNode* Ast::createNodeWithCollections(AstNode const* collections,
|
|||
auto names = coll->realNames();
|
||||
|
||||
for (auto const& n : names) {
|
||||
StringRef shardsNameRef(n);
|
||||
arangodb::StringRef shardsNameRef(n);
|
||||
LogicalDataSource::Category const* shardsCategory =
|
||||
injectDataSourceInQuery(*_query, resolver, AccessMode::Type::READ,
|
||||
false, shardsNameRef);
|
||||
|
@ -1206,7 +1207,7 @@ AstNode* Ast::createNodeCollectionList(AstNode const* edgeCollections,
|
|||
auto ci = ClusterInfo::instance();
|
||||
auto ss = ServerState::instance();
|
||||
auto doTheAdd = [&](std::string const& name) {
|
||||
StringRef nameRef(name);
|
||||
arangodb::StringRef nameRef(name);
|
||||
LogicalDataSource::Category const* category =
|
||||
injectDataSourceInQuery(*_query, resolver, AccessMode::Type::READ, false, nameRef);
|
||||
if (category == LogicalCollection::category()) {
|
||||
|
@ -1216,7 +1217,7 @@ AstNode* Ast::createNodeCollectionList(AstNode const* edgeCollections,
|
|||
auto const& names = c->realNames();
|
||||
|
||||
for (auto const& n : names) {
|
||||
StringRef shardsNameRef(n);
|
||||
arangodb::StringRef shardsNameRef(n);
|
||||
LogicalDataSource::Category const* shardsCategory =
|
||||
injectDataSourceInQuery(*_query, resolver, AccessMode::Type::READ,
|
||||
false, shardsNameRef);
|
||||
|
@ -1570,7 +1571,7 @@ void Ast::injectBindParameters(BindParameters& parameters,
|
|||
auto const& c = it.first;
|
||||
|
||||
if (c->type == NODE_TYPE_PARAMETER_DATASOURCE &&
|
||||
paramRef == StringRef(c->getStringValue(), c->getStringLength())) {
|
||||
paramRef == arangodb::StringRef(c->getStringValue(), c->getStringLength())) {
|
||||
isWriteCollection = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1588,7 +1589,7 @@ void Ast::injectBindParameters(BindParameters& parameters,
|
|||
auto& c = _writeCollections[i].first;
|
||||
|
||||
if (c->type == NODE_TYPE_PARAMETER_DATASOURCE &&
|
||||
paramRef == StringRef(c->getStringValue(), c->getStringLength())) {
|
||||
paramRef == arangodb::StringRef(c->getStringValue(), c->getStringLength())) {
|
||||
c = node;
|
||||
// no break here. replace all occurrences
|
||||
}
|
||||
|
@ -1692,7 +1693,7 @@ AstNode* Ast::replaceAttributeAccess(AstNode* node, Variable const* variable,
|
|||
return node;
|
||||
}
|
||||
|
||||
std::vector<StringRef> attributePath;
|
||||
std::vector<arangodb::StringRef> attributePath;
|
||||
|
||||
auto visitor = [&](AstNode* node) -> AstNode* {
|
||||
if (node == nullptr) {
|
||||
|
@ -1828,7 +1829,7 @@ void Ast::validateAndOptimize() {
|
|||
auto func = static_cast<Function*>(node->getData());
|
||||
TRI_ASSERT(func != nullptr);
|
||||
|
||||
if (func->name == "NOOPT") {
|
||||
if (func->hasFlag(Function::Flags::NoEval)) {
|
||||
// NOOPT will turn all function optimizations off
|
||||
++(ctx->stopOptimizationRequests);
|
||||
}
|
||||
|
@ -1901,7 +1902,7 @@ void Ast::validateAndOptimize() {
|
|||
auto func = static_cast<Function*>(node->getData());
|
||||
TRI_ASSERT(func != nullptr);
|
||||
|
||||
if (func->name == "NOOPT") {
|
||||
if (func->hasFlag(Function::Flags::NoEval)) {
|
||||
// NOOPT will turn all function optimizations off
|
||||
--ctx->stopOptimizationRequests;
|
||||
}
|
||||
|
@ -3307,7 +3308,7 @@ AstNode* Ast::optimizeIndexedAccess(AstNode* node) {
|
|||
// found a string value (e.g. a['foo']). now turn this into
|
||||
// an attribute access (e.g. a.foo) in order to make the node qualify
|
||||
// for being turned into an index range later
|
||||
StringRef indexValue(index->getStringValue(), index->getStringLength());
|
||||
arangodb::StringRef indexValue(index->getStringValue(), index->getStringLength());
|
||||
|
||||
if (!indexValue.empty() && (indexValue[0] < '0' || indexValue[0] > '9')) {
|
||||
// we have to be careful with numeric values here...
|
||||
|
@ -3535,10 +3536,11 @@ AstNode const* Ast::resolveConstAttributeAccess(AstNode const* node) {
|
|||
TRI_ASSERT(node != nullptr);
|
||||
TRI_ASSERT(node->type == NODE_TYPE_ATTRIBUTE_ACCESS);
|
||||
|
||||
std::vector<std::string> attributeNames;
|
||||
SmallVector<arangodb::StringRef>::allocator_type::arena_type a;
|
||||
SmallVector<arangodb::StringRef> attributeNames{a};
|
||||
|
||||
while (node->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
attributeNames.emplace_back(node->getString());
|
||||
attributeNames.push_back(node->getStringRef());
|
||||
node = node->getMember(0);
|
||||
}
|
||||
|
||||
|
@ -3553,15 +3555,15 @@ AstNode const* Ast::resolveConstAttributeAccess(AstNode const* node) {
|
|||
|
||||
if (node->type == NODE_TYPE_OBJECT) {
|
||||
TRI_ASSERT(which > 0);
|
||||
std::string const& attributeName = attributeNames[which - 1];
|
||||
arangodb::StringRef const& attributeName = attributeNames[which - 1];
|
||||
--which;
|
||||
|
||||
size_t const n = node->numMembers();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto member = node->getMember(i);
|
||||
auto member = node->getMemberUnchecked(i);
|
||||
|
||||
if (member->type == NODE_TYPE_OBJECT_ELEMENT &&
|
||||
StringRef(member->getStringValue(), member->getStringLength()) == attributeName) {
|
||||
arangodb::StringRef(member->getStringValue(), member->getStringLength()) == attributeName) {
|
||||
// found the attribute
|
||||
node = member->getMember(0);
|
||||
if (which == 0) {
|
||||
|
@ -3720,7 +3722,7 @@ AstNode* Ast::createNode(AstNodeType type) {
|
|||
|
||||
/// @brief validate the name of the given datasource
|
||||
/// in case validation fails, will throw an exception
|
||||
void Ast::validateDataSourceName(StringRef const& name, bool validateStrict) {
|
||||
void Ast::validateDataSourceName(arangodb::StringRef const& name, bool validateStrict) {
|
||||
// common validation
|
||||
if (name.empty() ||
|
||||
(validateStrict &&
|
||||
|
@ -3734,7 +3736,7 @@ void Ast::validateDataSourceName(StringRef const& name, bool validateStrict) {
|
|||
|
||||
/// @brief create an AST collection node
|
||||
/// private function, does no validation
|
||||
AstNode* Ast::createNodeCollectionNoValidation(StringRef const& name,
|
||||
AstNode* Ast::createNodeCollectionNoValidation(arangodb::StringRef const& name,
|
||||
AccessMode::Type accessType) {
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
auto ci = ClusterInfo::instance();
|
||||
|
|
|
@ -768,6 +768,17 @@ std::string AstNode::getString() const {
|
|||
return std::string(getStringValue(), getStringLength());
|
||||
}
|
||||
|
||||
/// @brief return the string value of a node, as a StringRef
|
||||
arangodb::StringRef AstNode::getStringRef() const noexcept {
|
||||
TRI_ASSERT(type == NODE_TYPE_VALUE || type == NODE_TYPE_OBJECT_ELEMENT ||
|
||||
type == NODE_TYPE_ATTRIBUTE_ACCESS || type == NODE_TYPE_PARAMETER ||
|
||||
type == NODE_TYPE_PARAMETER_DATASOURCE || type == NODE_TYPE_COLLECTION ||
|
||||
type == NODE_TYPE_VIEW || type == NODE_TYPE_BOUND_ATTRIBUTE_ACCESS ||
|
||||
type == NODE_TYPE_FCALL_USER);
|
||||
TRI_ASSERT(value.type == VALUE_TYPE_STRING);
|
||||
return arangodb::StringRef(getStringValue(), getStringLength());
|
||||
}
|
||||
|
||||
/// @brief test if all members of a node are equality comparisons
|
||||
bool AstNode::isOnlyEqualityMatch() const {
|
||||
if (type != NODE_TYPE_OPERATOR_BINARY_AND && type != NODE_TYPE_OPERATOR_NARY_AND) {
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "Basics/AttributeNameParser.h"
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "Basics/StringRef.h"
|
||||
|
||||
#include <velocypack/Slice.h>
|
||||
|
||||
|
@ -254,6 +255,9 @@ struct AstNode {
|
|||
/// @brief return the string value of a node, as an std::string
|
||||
std::string getString() const;
|
||||
|
||||
/// @brief return the string value of a node, as a StringRef
|
||||
arangodb::StringRef getStringRef() const noexcept;
|
||||
|
||||
/// @brief test if all members of a node are equality comparisons
|
||||
bool isOnlyEqualityMatch() const;
|
||||
|
||||
|
|
|
@ -49,7 +49,11 @@ struct Function {
|
|||
Cacheable = 2,
|
||||
|
||||
/// @brief whether or not the function may be executed on DB servers
|
||||
CanRunOnDBServer = 4
|
||||
CanRunOnDBServer = 4,
|
||||
|
||||
/// @brief exclude the function from being evaluated during AST optimizations
|
||||
/// evaluation of function will only happen at query runtime
|
||||
NoEval = 8
|
||||
};
|
||||
|
||||
/// @brief helper for building flags
|
||||
|
|
|
@ -838,9 +838,8 @@ void arangodb::aql::sortInValuesRule(Optimizer* opt, std::unique_ptr<ExecutionPl
|
|||
AstNode const* testNode = originalNode;
|
||||
|
||||
if (originalNode->type == NODE_TYPE_FCALL &&
|
||||
static_cast<Function const*>(originalNode->getData())->name ==
|
||||
"NOOPT") {
|
||||
// bypass NOOPT(...)
|
||||
static_cast<Function const*>(originalNode->getData())->hasFlag(Function::Flags::NoEval)) {
|
||||
// bypass NOOPT(...) for testing
|
||||
TRI_ASSERT(originalNode->numMembers() == 1);
|
||||
auto args = originalNode->getMember(0);
|
||||
|
||||
|
@ -2189,9 +2188,12 @@ void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
|
|||
return;
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
auto p = plan.get();
|
||||
|
||||
auto visitor = [p](AstNode* node) {
|
||||
auto visitor = [p, &modified](AstNode* node) {
|
||||
AstNode* original = node;
|
||||
|
||||
again:
|
||||
if (node->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
auto const* accessed = node->getMemberUnchecked(0);
|
||||
|
@ -2225,7 +2227,13 @@ void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
|
|||
if (member->type == NODE_TYPE_OBJECT_ELEMENT &&
|
||||
StringRef(member->getStringValue(), member->getStringLength()) == attributeName) {
|
||||
// found the attribute!
|
||||
node = member->getMember(0);
|
||||
AstNode* next = member->getMember(0);
|
||||
if (!next->isDeterministic()) {
|
||||
// do not descend into non-deterministic nodes
|
||||
return node;
|
||||
}
|
||||
// descend further
|
||||
node = next;
|
||||
// now try optimizing the simplified condition
|
||||
// time for a goto...!
|
||||
goto again;
|
||||
|
@ -2237,6 +2245,7 @@ void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
|
|||
|
||||
// attribute not found
|
||||
if (!isDynamic) {
|
||||
modified = true;
|
||||
return Ast::createNodeValueNull();
|
||||
}
|
||||
}
|
||||
|
@ -2292,7 +2301,13 @@ void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
|
|||
if (member->type == NODE_TYPE_OBJECT_ELEMENT &&
|
||||
StringRef(member->getStringValue(), member->getStringLength()) == attributeName) {
|
||||
// found the attribute!
|
||||
node = member->getMember(0);
|
||||
AstNode* next = member->getMember(0);
|
||||
if (!next->isDeterministic()) {
|
||||
// do not descend into non-deterministic nodes
|
||||
return node;
|
||||
}
|
||||
// descend further
|
||||
node = next;
|
||||
// now try optimizing the simplified condition
|
||||
// time for a goto...!
|
||||
goto again;
|
||||
|
@ -2304,6 +2319,7 @@ void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
|
|||
|
||||
// attribute not found
|
||||
if (!isDynamic) {
|
||||
modified = true;
|
||||
return Ast::createNodeValueNull();
|
||||
}
|
||||
} else if (accessed->type == NODE_TYPE_ARRAY) {
|
||||
|
@ -2317,6 +2333,7 @@ void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
|
|||
valid);
|
||||
if (!valid) {
|
||||
// invalid index
|
||||
modified = true;
|
||||
return Ast::createNodeValueNull();
|
||||
}
|
||||
} else {
|
||||
|
@ -2330,21 +2347,31 @@ void arangodb::aql::simplifyConditionsRule(Optimizer* opt,
|
|||
position = n + position;
|
||||
}
|
||||
if (position >= 0 && position < n) {
|
||||
node = accessed->getMember(static_cast<size_t>(position));
|
||||
AstNode* next = accessed->getMember(static_cast<size_t>(position));
|
||||
if (!next->isDeterministic()) {
|
||||
// do not descend into non-deterministic nodes
|
||||
return node;
|
||||
}
|
||||
// descend further
|
||||
node = next;
|
||||
// now try optimizing the simplified condition
|
||||
// time for a goto...!
|
||||
goto again;
|
||||
}
|
||||
|
||||
// index out of bounds
|
||||
modified = true;
|
||||
return Ast::createNodeValueNull();
|
||||
}
|
||||
}
|
||||
|
||||
if (node != original) {
|
||||
// we come out with a different, so we changed something...
|
||||
modified = true;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
bool modified = false;
|
||||
for (auto const& n : nodes) {
|
||||
auto nn = ExecutionNode::castTo<CalculationNode*>(n);
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
#include "GeneralServer/IoTask.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace arangodb {
|
||||
class ConnectionStatistics;
|
||||
|
||||
|
|
|
@ -21,14 +21,12 @@
|
|||
/// @author Jan Steemann
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_BASICS_AUTO_VECTOR_H
|
||||
#define ARANGODB_BASICS_AUTO_VECTOR_H 1
|
||||
#ifndef ARANGODB_BASICS_SMALL_VECTOR_H
|
||||
#define ARANGODB_BASICS_SMALL_VECTOR_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/short_alloc.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace arangodb {
|
||||
|
||||
template <class T, std::size_t BufSize = 64>
|
||||
|
|
|
@ -45,31 +45,31 @@ function optimizerRuleTestSuite () {
|
|||
|
||||
testRuleDisabled : function () {
|
||||
let queries = [
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[0]",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[3]",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[4]",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[10]",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-1]",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-2]",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-3]",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-4]",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data['0']",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data['3']",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data['4']",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data['fffff']",
|
||||
"LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data['-2']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['a']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['d']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['d']['x']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['z']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['0']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['1']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['2']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['999']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data.a",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data.d",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data.d.x",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data.z",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[0]",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[3]",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[4]",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[10]",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-1]",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-2]",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-3]",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-4]",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data['0']",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data['3']",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data['4']",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data['fffff']",
|
||||
"LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data['-2']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['a']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['d']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['d']['x']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['z']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['0']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['1']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['2']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['999']",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data.a",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data.d",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data.d.x",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data.z",
|
||||
];
|
||||
|
||||
queries.forEach(function(query) {
|
||||
|
@ -95,6 +95,8 @@ function optimizerRuleTestSuite () {
|
|||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: 4 } } RETURN data[NOOPT('999')]",
|
||||
"LET data = { a: 1, b: 2, c: 3, [NOOPT('foo')] : 4 } RETURN data.z",
|
||||
"LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', [NOOPT('foo')] : 4 } } RETURN data.d.z",
|
||||
"LET data = { a: RAND() } RETURN data.a",
|
||||
"LET data = { a: RAND(), b: RAND() } RETURN [data.a, data.b]",
|
||||
];
|
||||
|
||||
queries.forEach(function(query) {
|
||||
|
@ -105,41 +107,41 @@ function optimizerRuleTestSuite () {
|
|||
|
||||
testResults : function () {
|
||||
let queries = [
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[0]", 1 ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[3]", 4 ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[4]", null ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[10]", null ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-1]", 4 ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-2]", 3 ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-3]", 2 ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-4]", 1 ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data[-5]", null ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data['0']", 1 ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data['3']", 4 ],
|
||||
[ "LET data = [ 1, 2, 3, NOOPT(4) ] RETURN data['4']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['a']", 1 ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['d']", { x: 'x', y: 'y', foo: 4 } ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['d']['x']", 'x' ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['z']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['0']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['1']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['2']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data['999']", null ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOOPT(4) } } RETURN data['1']", 1 ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOOPT(4) } } RETURN data[1]", 1 ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOOPT(4) } } RETURN data['99']", 3 ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOOPT(4) } } RETURN data[99]", 3 ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOOPT(4) } } RETURN data['d']['2']", 'y' ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOOPT(4) } } RETURN data.d.`2`", 'y' ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOOPT(4) } } RETURN data.`d`.`2`", 'y' ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOOPT(4) } } RETURN data.d['2']", 'y' ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data.a", 1 ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data.d", { x: 'x', y: 'y', foo: 4 } ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data.d.x", 'x' ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOOPT(4) } } RETURN data.z", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', [NOOPT('foo')] : 4 } } RETURN data.z", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', [NOOPT('foo')] : 4 } } RETURN data.b", 2 ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', [NOOPT('foo')] : 4 } } RETURN data.d.y", 'y' ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[0]", 1 ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[3]", 4 ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[4]", null ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[10]", null ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-1]", 4 ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-2]", 3 ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-3]", 2 ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-4]", 1 ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data[-5]", null ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data['0']", 1 ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data['3']", 4 ],
|
||||
[ "LET data = [ 1, 2, 3, NOEVAL(4) ] RETURN data['4']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['a']", 1 ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['d']", { x: 'x', y: 'y', foo: 4 } ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['d']['x']", 'x' ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['z']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['0']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['1']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['2']", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data['999']", null ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOEVAL(4) } } RETURN data['1']", 1 ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOEVAL(4) } } RETURN data[1]", 1 ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOEVAL(4) } } RETURN data['99']", 3 ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOEVAL(4) } } RETURN data[99]", 3 ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOEVAL(4) } } RETURN data['d']['2']", 'y' ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOEVAL(4) } } RETURN data.d.`2`", 'y' ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOEVAL(4) } } RETURN data.`d`.`2`", 'y' ],
|
||||
[ "LET data = { '1': 1, '2': 2, '99': 3, d: { '1': 'x', '2': 'y', '3': NOEVAL(4) } } RETURN data.d['2']", 'y' ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data.a", 1 ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data.d", { x: 'x', y: 'y', foo: 4 } ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data.d.x", 'x' ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', foo: NOEVAL(4) } } RETURN data.z", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', [NOEVAL('foo')] : 4 } } RETURN data.z", null ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', [NOEVAL('foo')] : 4 } } RETURN data.b", 2 ],
|
||||
[ "LET data = { a: 1, b: 2, c: 3, d: { x: 'x', y: 'y', [NOEVAL('foo')] : 4 } } RETURN data.d.y", 'y' ],
|
||||
];
|
||||
|
||||
queries.forEach(function(query) {
|
||||
|
|
Loading…
Reference in New Issue