diff --git a/arangod/Aql/TraversalConditionFinder.cpp b/arangod/Aql/TraversalConditionFinder.cpp index b7af940fc1..48f7e3c7db 100644 --- a/arangod/Aql/TraversalConditionFinder.cpp +++ b/arangod/Aql/TraversalConditionFinder.cpp @@ -34,26 +34,38 @@ using namespace triagens::aql; using EN = triagens::aql::ExecutionNode; -bool checkPathVariableAccessFeasible(CalculationNode const* cn, TraversalNode * tn, Variable const* var, bool &conditionIsImpossible) { +bool checkPathVariableAccessFeasible(CalculationNode const* cn, + TraversalNode * tn, + Variable const* var, + bool &conditionIsImpossible, + Ast* ast) { auto node = cn->expression()->node(); std::vector currentPath; std::vector> paths; + std::vector> clonePath; node->findVariableAccess(currentPath, paths, var); for (auto onePath : paths) { size_t len = onePath.size(); + bool isEdgeAccess = false; + bool isVertexAccess = false; + bool isAsterisc = false; + size_t attrAccessTo = 0; - if ((onePath[len - 2]->type == NODE_TYPE_ATTRIBUTE_ACCESS) && - strcmp(onePath[len - 2]->getStringValue(), "edges") && - strcmp(onePath[len - 2]->getStringValue(), "vertices")) { + if (onePath[len - 2]->type == NODE_TYPE_ATTRIBUTE_ACCESS) { + isEdgeAccess = strcmp(onePath[len - 2]->getStringValue(), "edges") == 0; + isVertexAccess = strcmp(onePath[len - 2]->getStringValue(), "vertices") == 0; - /* We can't catch all cases in which this error would occur, so we don't throw here. - std::string message("TRAVERSAL: path only knows 'edges' and 'vertices', not "); - message += onePath[len - 2]->getStringValue(); - THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE, message); - */ - return false; + if (!isEdgeAccess && ! isVertexAccess) { + + /* We can't catch all cases in which this error would occur, so we don't throw here. + std::string message("TRAVERSAL: path only knows 'edges' and 'vertices', not "); + message += onePath[len - 2]->getStringValue(); + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE, message); + */ + return false; + } } // we now need to check for p.edges[n] whether n is >= 0 @@ -65,21 +77,83 @@ bool checkPathVariableAccessFeasible(CalculationNode const* cn, TraversalNode * return false; } conditionIsImpossible = !tn->isInRange(indexAccessNode->value.value._int); + attrAccessTo = indexAccessNode->value.value._int; } else if ((onePath[len - 3]->type == NODE_TYPE_ITERATOR) && (onePath[len - 4]->type == NODE_TYPE_EXPANSION)){ // we now need to check for p.edges[*] which becomes a fancy structure - + isAsterisc = true; } else { return false; } // OR? don't know howto continue. + AstNode const * compareNode = nullptr; + AstNode const * accessNodeBranch = nullptr; for (auto oneNode : onePath) { if (oneNode->type == NODE_TYPE_OPERATOR_BINARY_OR) { return false; } + if (compareNode != nullptr && accessNodeBranch == nullptr) { + accessNodeBranch = oneNode; + } + + if (oneNode->type == NODE_TYPE_OPERATOR_BINARY_EQ) { + compareNode = oneNode; + } + } + + if (compareNode != NULL) { + AstNode const * pathAccessNode; + AstNode const * filterByNode; + + if (compareNode->getMember(0) == accessNodeBranch) { + pathAccessNode = accessNodeBranch; + filterByNode = compareNode->getMember(1); + } + else { + pathAccessNode = accessNodeBranch; + filterByNode = compareNode->getMember(0); + } + + if (accessNodeBranch->isSimple() && filterByNode->type == NODE_TYPE_VALUE) { + AstNode *newNode = accessNodeBranch->clone(ast); + + // since we just copied one path, we should only find one. + newNode->findVariableAccess(currentPath, clonePath, var); + newNode->dump(20); + if (isAsterisc) { + + } + else { + auto len = clonePath[0].size(); + /// todo len < 4 + AstNode* firstRefNode = (AstNode*) clonePath[0][len - 4]; + TRI_ASSERT(firstRefNode->type == NODE_TYPE_ATTRIBUTE_ACCESS); + auto varRefNode = new AstNode(NODE_TYPE_REFERENCE); + ast->query()->addNode(varRefNode); + varRefNode->setData(isEdgeAccess ? tn->edgeOutVariable(): tn->vertexOutVariable()); + firstRefNode->changeMember(0, varRefNode); + tn->storeSimpleExpression(isAsterisc, + isEdgeAccess, + attrAccessTo, + NODE_TYPE_OPERATOR_BINARY_EQ, + newNode, + filterByNode); + + printf("\n xxxxx: %s\n", newNode->toString().c_str()); + printf("\n yyyy: %s\n", accessNodeBranch->toString().c_str()); + printf("\n yyyy: %s\n", filterByNode->toString().c_str()); + } + + } +printf("\na: %s\n", compareNode->toString().c_str()); +printf("\na: %s\n", accessNodeBranch->toString().c_str()); + + triagens::basics::Json j(TRI_UNKNOWN_MEM_ZONE, accessNodeBranch->toJson(TRI_UNKNOWN_MEM_ZONE, true)); + printf("sanotuh %s\n", j.toString().c_str()); + } } @@ -189,7 +263,7 @@ bool TraversalConditionFinder::before (ExecutionNode* en) { int variableType = node->checkIsOutVariable(conditionVar->id); if (variableType >= 0) { if ((variableType == 2) && - checkPathVariableAccessFeasible(cn, node, conditionVar, conditionIsImpossible)) + checkPathVariableAccessFeasible(cn, node, conditionVar, conditionIsImpossible, _plan->getAst())) { condition->andCombine(it.second->expression()->node()); foundCondition = true; diff --git a/arangod/Aql/TraversalNode.cpp b/arangod/Aql/TraversalNode.cpp index fa993ccc7a..8fcc6b2080 100644 --- a/arangod/Aql/TraversalNode.cpp +++ b/arangod/Aql/TraversalNode.cpp @@ -32,6 +32,19 @@ using namespace std; using namespace triagens::basics; using namespace triagens::aql; +void TraversalNode::simpleTravererExpression::toJson(triagens::basics::Json& json, + TRI_memory_zone_t* zone) const +{ + json("isAsteriscAccess", triagens::basics::Json(isAsteriscAccess)) + ("isEdgeAccess", triagens::basics::Json(isEdgeAccess)) + ("indexAccess", triagens::basics::Json((int32_t)indexAccess)) + ("comparisonType", triagens::basics::Json("==")) /// TODO more comparison types? + ("varAccess", varAccess->toJson(zone, true)) + ("compareTo", compareTo->toJson(zone, true)); + + +} + TraversalNode::TraversalNode (ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase, @@ -185,13 +198,13 @@ TraversalNode::TraversalNode (ExecutionPlan* plan, } int TraversalNode::checkIsOutVariable(size_t variableId) { - if (_vertexOutVariable->id == variableId) { + if (_vertexOutVariable != nullptr && _vertexOutVariable->id == variableId) { return 0; } - if (_edgeOutVariable->id == variableId) { + if (_edgeOutVariable != nullptr && _edgeOutVariable->id == variableId) { return 1; } - if (_pathOutVariable->id == variableId) { + if (_pathOutVariable != nullptr && _pathOutVariable->id == variableId) { return 2; } return -1; @@ -304,6 +317,16 @@ void TraversalNode::toJsonHelper (triagens::basics::Json& nodes, json("pathOutVariable", pathOutVariable()->toJson()); } + if (expressions.size() > 0) { + triagens::basics::Json expressionArray = triagens::basics::Json(triagens::basics::Json::Array, + expressions.size()); + for (auto x : expressions) { + triagens::basics::Json exp(zone, triagens::basics::Json::Object); + x.toJson(exp, zone); + expressionArray(exp); + } + json("simpleExpressions", expressionArray); + } // And add it: nodes(json); } @@ -380,10 +403,10 @@ void TraversalNode::setCondition(triagens::aql::Condition* condition){ Ast::getReferencedVariables(condition->root(), varsUsedByCondition); for (auto oneVar : varsUsedByCondition) { - if ((oneVar->id != _vertexOutVariable->id) && - (oneVar->id != _edgeOutVariable->id) && - (oneVar->id != _pathOutVariable->id) && - (oneVar->id != _inVariable->id)) { + if ((_vertexOutVariable != nullptr && oneVar->id != _vertexOutVariable->id) && + (_edgeOutVariable != nullptr && oneVar->id != _edgeOutVariable->id) && + (_pathOutVariable != nullptr && oneVar->id != _pathOutVariable->id) && + (_inVariable != nullptr && oneVar->id != _inVariable->id)) { _conditionVariables.push_back(oneVar); } @@ -392,6 +415,22 @@ void TraversalNode::setCondition(triagens::aql::Condition* condition){ _condition = condition; } +void TraversalNode::storeSimpleExpression(bool isAsteriscAccess, + bool isEdgeAccess, + size_t indexAccess, + AstNodeType comparisonType, + AstNode const* varAccess, + AstNode const* compareTo) { + + simpleTravererExpression e { + isAsteriscAccess, + isEdgeAccess, + indexAccess, + comparisonType, + varAccess, + compareTo}; + expressions.emplace_back(e); +} // Local Variables: diff --git a/arangod/Aql/TraversalNode.h b/arangod/Aql/TraversalNode.h index 25e49a9e07..a4e331b228 100644 --- a/arangod/Aql/TraversalNode.h +++ b/arangod/Aql/TraversalNode.h @@ -49,6 +49,18 @@ namespace triagens { friend class ExecutionBlock; friend class TraversalCollectionBlock; + struct simpleTravererExpression { + bool isAsteriscAccess; + bool isEdgeAccess; + size_t indexAccess; + AstNodeType comparisonType; + AstNode const* varAccess; + AstNode const* compareTo; + + void toJson(triagens::basics::Json& json, + TRI_memory_zone_t* zone) const; + }; + //////////////////////////////////////////////////////////////////////////////// /// @brief constructor with a vocbase and a collection name //////////////////////////////////////////////////////////////////////////////// @@ -325,6 +337,17 @@ namespace triagens { return _maxDepth >= _minDepth; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief Remember a simple comparator filter +//////////////////////////////////////////////////////////////////////////////// + + void storeSimpleExpression(bool isAsteriscAccess, + bool isEdgeAccess, + size_t indexAccess, + AstNodeType comparisonType, + AstNode const* varAccess, + AstNode const* compareTo); + // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- @@ -421,6 +444,12 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// std::vector _conditionVariables; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief store a simple comparator filter +//////////////////////////////////////////////////////////////////////////////// + + std::vector expressions; }; } // namespace triagens::aql