mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql-jmmh-conditions' of github.com:arangodb/arangodb into aql-jmmh-conditions
This commit is contained in:
commit
dd93460318
|
@ -668,7 +668,7 @@ TRI_json_t* AstNode::computeJson () const {
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief sort the members of a (list) node
|
/// @brief sort the members of an (array) node
|
||||||
/// this will also set the VALUE_SORTED flag for the node
|
/// this will also set the VALUE_SORTED flag for the node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -270,7 +270,7 @@ namespace triagens {
|
||||||
TRI_json_t* computeJson () const;
|
TRI_json_t* computeJson () const;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief sort the members of a (list) node
|
/// @brief sort the members of an (array) node
|
||||||
/// this will also set the FLAG_SORTED flag for the node
|
/// this will also set the FLAG_SORTED flag for the node
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// TODO: sort IN values
|
||||||
|
|
||||||
#include "Condition.h"
|
#include "Condition.h"
|
||||||
#include "Aql/Ast.h"
|
#include "Aql/Ast.h"
|
||||||
#include "Aql/AstNode.h"
|
#include "Aql/AstNode.h"
|
||||||
|
@ -38,8 +40,6 @@
|
||||||
#include "Basics/json.h"
|
#include "Basics/json.h"
|
||||||
#include "Basics/JsonHelper.h"
|
#include "Basics/JsonHelper.h"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace triagens::aql;
|
using namespace triagens::aql;
|
||||||
using CompareResult = ConditionPartCompareResult;
|
using CompareResult = ConditionPartCompareResult;
|
||||||
|
|
||||||
|
@ -527,6 +527,9 @@ std::pair<bool, bool> Condition::findIndexForAndNode (size_t position,
|
||||||
}
|
}
|
||||||
|
|
||||||
_root->changeMember(position, bestIndex->specializeCondition(node, reference));
|
_root->changeMember(position, bestIndex->specializeCondition(node, reference));
|
||||||
|
#if 0
|
||||||
|
_isSorted = sortOrs();
|
||||||
|
#endif
|
||||||
|
|
||||||
usedIndexes.emplace_back(bestIndex);
|
usedIndexes.emplace_back(bestIndex);
|
||||||
|
|
||||||
|
@ -549,8 +552,6 @@ void Condition::normalize (ExecutionPlan* plan) {
|
||||||
|
|
||||||
optimize(plan);
|
optimize(plan);
|
||||||
|
|
||||||
fixOrs(plan);
|
|
||||||
|
|
||||||
#ifdef TRI_ENABLE_MAINTAINER_MODE
|
#ifdef TRI_ENABLE_MAINTAINER_MODE
|
||||||
if (_root != nullptr) {
|
if (_root != nullptr) {
|
||||||
// _root->dump(0);
|
// _root->dump(0);
|
||||||
|
@ -559,16 +560,176 @@ void Condition::normalize (ExecutionPlan* plan) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Condition::fixOrs (ExecutionPlan* plan) {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
if (_root == nullptr) {
|
/// @brief removes condition parts from another
|
||||||
return;
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
AstNode const* Condition::removeIndexCondition (Variable const* variable,
|
||||||
|
AstNode const* other) {
|
||||||
|
if (_root == nullptr || other == nullptr) {
|
||||||
|
return _root;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(_root != nullptr);
|
||||||
|
TRI_ASSERT(_root->type == NODE_TYPE_OPERATOR_NARY_OR);
|
||||||
|
|
||||||
|
TRI_ASSERT(other != nullptr);
|
||||||
|
TRI_ASSERT(other->type == NODE_TYPE_OPERATOR_NARY_OR);
|
||||||
|
|
||||||
|
if (other->numMembers() != 1 && _root->numMembers() != 1) {
|
||||||
|
return _root;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto andNode = _root->getMemberUnchecked(0);
|
||||||
|
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
|
size_t const n = andNode->numMembers();
|
||||||
|
|
||||||
|
std::unordered_set<size_t> toRemove;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
auto operand = andNode->getMemberUnchecked(i);
|
||||||
|
|
||||||
|
if (operand->isComparisonOperator()) {
|
||||||
|
auto lhs = operand->getMember(0);
|
||||||
|
auto rhs = operand->getMember(1);
|
||||||
|
|
||||||
|
if (lhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||||
|
std::pair<Variable const*, std::vector<triagens::basics::AttributeName>> result;
|
||||||
|
|
||||||
|
if (lhs->isAttributeAccessForVariable(result) &&
|
||||||
|
rhs->isConstant()) {
|
||||||
|
if (result.first != variable) {
|
||||||
|
// attribute access for different variable
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionPart current(variable, result.second, operand, ATTRIBUTE_LEFT, nullptr);
|
||||||
|
|
||||||
|
if (canRemove(current, other)) {
|
||||||
|
toRemove.emplace(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
||||||
|
rhs->type == NODE_TYPE_EXPANSION) {
|
||||||
|
std::pair<Variable const*, std::vector<triagens::basics::AttributeName>> result;
|
||||||
|
|
||||||
|
if (rhs->isAttributeAccessForVariable(result) &&
|
||||||
|
lhs->isConstant()) {
|
||||||
|
if (result.first != variable) {
|
||||||
|
// attribute access for different variable
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConditionPart current(variable, result.second, operand, ATTRIBUTE_RIGHT, nullptr);
|
||||||
|
|
||||||
|
if (canRemove(current, other)) {
|
||||||
|
toRemove.emplace(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toRemove.empty()) {
|
||||||
|
return _root;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a new AST condition
|
||||||
|
AstNode* newNode = nullptr;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
if (toRemove.find(i) == toRemove.end()) {
|
||||||
|
auto what = andNode->getMemberUnchecked(i);
|
||||||
|
|
||||||
|
if (newNode == nullptr) {
|
||||||
|
// the only node so far
|
||||||
|
newNode = what;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// AND-combine with existing node
|
||||||
|
newNode = _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_AND, newNode, what);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief remove (now) invalid variables from the condition
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool Condition::removeInvalidVariables (std::unordered_set<Variable const*> const& validVars) {
|
||||||
|
if (_root == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRI_ASSERT(_root != nullptr);
|
||||||
|
TRI_ASSERT(_root->type == NODE_TYPE_OPERATOR_NARY_OR);
|
||||||
|
|
||||||
|
bool isEmpty = false;
|
||||||
|
|
||||||
|
// handle sub nodes of top-level OR node
|
||||||
|
size_t const n = _root->numMembers();
|
||||||
|
std::unordered_set<Variable const*> varsUsed;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
auto andNode = _root->getMemberUnchecked(i);
|
||||||
|
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
|
|
||||||
|
size_t nAnd = andNode->numMembers();
|
||||||
|
for (size_t j = 0; j < nAnd; /* no hoisting */) {
|
||||||
|
// check which variables are used in each AND
|
||||||
|
varsUsed.clear();
|
||||||
|
Ast::getReferencedVariables(andNode, varsUsed);
|
||||||
|
|
||||||
|
bool invalid = false;
|
||||||
|
for (auto& it : varsUsed) {
|
||||||
|
if (validVars.find(it) == validVars.end()) {
|
||||||
|
// found an invalid variable here...
|
||||||
|
invalid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalid) {
|
||||||
|
andNode->removeMemberUnchecked(j);
|
||||||
|
// repeat with some member index
|
||||||
|
TRI_ASSERT(nAnd > 0);
|
||||||
|
--nAnd;
|
||||||
|
if (nAnd == 0) {
|
||||||
|
isEmpty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- private methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief sort ORs for the same attribute so they are in ascending value
|
||||||
|
/// order. this will only work if the condition is for a single attribute
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool Condition::sortOrs () {
|
||||||
|
if (_root == nullptr) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
size_t const n = _root->numMembers();
|
size_t const n = _root->numMembers();
|
||||||
|
|
||||||
if (n < 2) {
|
if (n < 2) {
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ConditionPart> parts;
|
std::vector<ConditionPart> parts;
|
||||||
|
@ -583,13 +744,13 @@ return;
|
||||||
|
|
||||||
if (nAnd != 1) {
|
if (nAnd != 1) {
|
||||||
// we can't handle this one
|
// we can't handle this one
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operand = sub->getMemberUnchecked(0);
|
auto operand = sub->getMemberUnchecked(0);
|
||||||
|
|
||||||
if (! operand->isComparisonOperator()) {
|
if (! operand->isComparisonOperator()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lhs = operand->getMember(0);
|
auto lhs = operand->getMember(0);
|
||||||
|
@ -617,7 +778,6 @@ return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
TRI_ASSERT(parts.size() == _root->numMembers());
|
TRI_ASSERT(parts.size() == _root->numMembers());
|
||||||
|
|
||||||
// now sort all conditions by variable name, attribute name, attribute value
|
// now sort all conditions by variable name, attribute name, attribute value
|
||||||
|
@ -637,63 +797,67 @@ return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare attribute values next
|
// compare attribute values next
|
||||||
res = CompareAstNodes(lhs.valueNode, rhs.valueNode, false);
|
auto ll = lhs.lowerBound();
|
||||||
|
auto lr = rhs.lowerBound();
|
||||||
|
|
||||||
|
if (ll == nullptr && lr != nullptr) {
|
||||||
|
// left lower bound is not set but right
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ll != nullptr && lr == nullptr) {
|
||||||
|
// left lower bound is set but not right
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ll != nullptr && lr != nullptr) {
|
||||||
|
// both lower bounds are set
|
||||||
|
res = CompareAstNodes(ll, lr, false);
|
||||||
|
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
return res < 0;
|
return res < 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lhs.isLowerInclusive() && ! rhs.isLowerInclusive()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (rhs.isLowerInclusive() && ! lhs.isLowerInclusive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// all things equal
|
// all things equal
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct CompValue {
|
auto l = 0;
|
||||||
AstNode const* lowerValue = nullptr;
|
for (size_t r = 1; r < n; ++r) {
|
||||||
AstNode const* upperValue = nullptr;
|
auto& l = parts[l].data;
|
||||||
bool lowerIncluded = false;
|
auto& r = parts[r].data;
|
||||||
bool upperIncluded = false;
|
|
||||||
bool empty = true;
|
|
||||||
|
|
||||||
CompValue (AstNodeType opType, AstNode const* valueNode) {
|
if (l.higher > r.higher ||
|
||||||
if (opType == NODE_TYPE_OPERATOR_BINARY_LE || opType == NODE_TYPE_OPERATOR_BINARY_LT || opType == NODE_TYPE_OPERATOR_BINARY_EQ) {
|
(l.higher == r.higher && (l.inclusive || ! r.inclusive)) {
|
||||||
upperValue = valueNode;
|
// r is contained in l => remove r (i.e. do nothing)
|
||||||
|
r.data = nullptr;
|
||||||
}
|
}
|
||||||
if (opType == NODE_TYPE_OPERATOR_BINARY_GE || opType == NODE_TYPE_OPERATOR_BINARY_GT || opType == NODE_TYPE_OPERATOR_BINARY_EQ) {
|
else if (r.lower < l.higher || (r.lower == l.higher && (r.inclusive || l.inclusive))) {
|
||||||
lowerValue = valueNode;
|
// r extends l => fuse l.lower & r.higher
|
||||||
}
|
|
||||||
lowerIncluded = (opType == NODE_TYPE_OPERATOR_BINARY_GE || opType == NODE_TYPE_OPERATOR_BINARY_EQ);
|
|
||||||
upperIncluded = (opType == NODE_TYPE_OPERATOR_BINARY_LE || opType == NODE_TYPE_OPERATOR_BINARY_EQ);
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CompValue lastValue;
|
r.data = nullptr;
|
||||||
*/
|
newOrNode->getMember(newor
|
||||||
// now finally sort the members of the AND-node
|
|
||||||
for (size_t i = 1; i < parts.size(); ++i) {
|
|
||||||
// Results are -1, 0, 1, move to 0, 1, 2 for the lookup:
|
|
||||||
auto& other = parts[i - 1];
|
|
||||||
auto& current = parts[i];
|
|
||||||
|
|
||||||
ConditionPartCompareResult res = ConditionPart::ResultsTable
|
|
||||||
[CompareAstNodes(current.valueNode, other.valueNode, false) + 1]
|
|
||||||
[current.whichCompareOperation()]
|
|
||||||
[other.whichCompareOperation()];
|
|
||||||
|
|
||||||
std::cout << "CURRENT: " << current.valueNode << ", OTHER: " << other.valueNode << ", RES: " << (int) res << "\n";
|
|
||||||
if (res == CompareResult::IMPOSSIBLE) {
|
|
||||||
// means disjoint ranges here
|
|
||||||
std::cout << "DISJOINT\n";
|
|
||||||
}
|
}
|
||||||
else if (res == CompareResult::OTHER_CONTAINED_IN_SELF) {
|
else {
|
||||||
std::cout << "KEEPING OTHER\n";
|
// disjoint ranges. simply add the node
|
||||||
|
newOrNode->addMember(r);
|
||||||
}
|
}
|
||||||
else if (res == CompareResult::DISJOINT) {
|
}
|
||||||
std::cout << "KEEPING OTHER\n";
|
*/
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
_root->changeMember(i, static_cast<AstNode*>(parts[i].data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// _root->changeMember(i, static_cast<AstNode*>(parts[i].data));
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -766,7 +930,6 @@ restartThisOrItem:
|
||||||
andNode->changeMember(p++, it);
|
andNode->changeMember(p++, it);
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimization is only necessary if an AND node has multiple members
|
// optimization is only necessary if an AND node has multiple members
|
||||||
|
@ -928,174 +1091,16 @@ restartThisOrItem:
|
||||||
} // foreach sub-and-node
|
} // foreach sub-and-node
|
||||||
|
|
||||||
fastForwardToNextOrItem:
|
fastForwardToNextOrItem:
|
||||||
if (retry) {
|
if (! retry) {
|
||||||
|
// root nodes hasn't changed. go to next sub-node!
|
||||||
|
++r;
|
||||||
|
}
|
||||||
// number of root sub-nodes has probably changed.
|
// number of root sub-nodes has probably changed.
|
||||||
// now recalculate the number and don't modify r!
|
// now recalculate the number and don't modify r!
|
||||||
n = _root->numMembers();
|
n = _root->numMembers();
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// root nodes hasn't changed. go to next sub-node!
|
|
||||||
++r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief removes condition parts from another
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
AstNode const* Condition::removeIndexCondition (Variable const* variable,
|
|
||||||
AstNode const* other) {
|
|
||||||
if (_root == nullptr || other == nullptr) {
|
|
||||||
return _root;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_ASSERT(_root != nullptr);
|
|
||||||
TRI_ASSERT(_root->type == NODE_TYPE_OPERATOR_NARY_OR);
|
|
||||||
|
|
||||||
TRI_ASSERT(other != nullptr);
|
|
||||||
TRI_ASSERT(other->type == NODE_TYPE_OPERATOR_NARY_OR);
|
|
||||||
|
|
||||||
if (other->numMembers() != 1 && _root->numMembers() != 1) {
|
|
||||||
return _root;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto andNode = _root->getMemberUnchecked(0);
|
|
||||||
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
|
||||||
size_t const n = andNode->numMembers();
|
|
||||||
|
|
||||||
std::unordered_set<size_t> toRemove;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
auto operand = andNode->getMemberUnchecked(i);
|
|
||||||
|
|
||||||
if (operand->isComparisonOperator()) {
|
|
||||||
auto lhs = operand->getMember(0);
|
|
||||||
auto rhs = operand->getMember(1);
|
|
||||||
|
|
||||||
if (lhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
|
||||||
std::pair<Variable const*, std::vector<triagens::basics::AttributeName>> result;
|
|
||||||
|
|
||||||
if (lhs->isAttributeAccessForVariable(result) &&
|
|
||||||
rhs->isConstant()) {
|
|
||||||
if (result.first != variable) {
|
|
||||||
// attribute access for different variable
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionPart current(variable, result.second, operand, ATTRIBUTE_LEFT, nullptr);
|
|
||||||
|
|
||||||
if (canRemove(current, other)) {
|
|
||||||
toRemove.emplace(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
|
||||||
rhs->type == NODE_TYPE_EXPANSION) {
|
|
||||||
std::pair<Variable const*, std::vector<triagens::basics::AttributeName>> result;
|
|
||||||
|
|
||||||
if (rhs->isAttributeAccessForVariable(result) &&
|
|
||||||
lhs->isConstant()) {
|
|
||||||
if (result.first != variable) {
|
|
||||||
// attribute access for different variable
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionPart current(variable, result.second, operand, ATTRIBUTE_RIGHT, nullptr);
|
|
||||||
|
|
||||||
if (canRemove(current, other)) {
|
|
||||||
toRemove.emplace(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toRemove.empty()) {
|
|
||||||
return _root;
|
|
||||||
}
|
|
||||||
|
|
||||||
// build a new AST condition
|
|
||||||
AstNode* newNode = nullptr;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
if (toRemove.find(i) == toRemove.end()) {
|
|
||||||
auto what = andNode->getMemberUnchecked(i);
|
|
||||||
|
|
||||||
if (newNode == nullptr) {
|
|
||||||
// the only node so far
|
|
||||||
newNode = what;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// AND-combine with existing node
|
|
||||||
newNode = _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_AND, newNode, what);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief remove (now) invalid variables from the condition
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool Condition::removeInvalidVariables (std::unordered_set<Variable const*> const& validVars) {
|
|
||||||
if (_root == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRI_ASSERT(_root != nullptr);
|
|
||||||
TRI_ASSERT(_root->type == NODE_TYPE_OPERATOR_NARY_OR);
|
|
||||||
|
|
||||||
bool isEmpty = false;
|
|
||||||
|
|
||||||
// handle sub nodes of top-level OR node
|
|
||||||
size_t const n = _root->numMembers();
|
|
||||||
std::unordered_set<Variable const*> varsUsed;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
auto andNode = _root->getMemberUnchecked(i);
|
|
||||||
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
|
||||||
|
|
||||||
size_t nAnd = andNode->numMembers();
|
|
||||||
for (size_t j = 0; j < nAnd; /* no hoisting */) {
|
|
||||||
// check which variables are used in each AND
|
|
||||||
varsUsed.clear();
|
|
||||||
Ast::getReferencedVariables(andNode, varsUsed);
|
|
||||||
|
|
||||||
bool invalid = false;
|
|
||||||
for (auto& it : varsUsed) {
|
|
||||||
if (validVars.find(it) == validVars.end()) {
|
|
||||||
// found an invalid variable here...
|
|
||||||
invalid = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
andNode->removeMemberUnchecked(j);
|
|
||||||
// repeat with some member index
|
|
||||||
TRI_ASSERT(nAnd > 0);
|
|
||||||
--nAnd;
|
|
||||||
if (nAnd == 0) {
|
|
||||||
isEmpty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return isEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// --SECTION-- private methods
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief registers an attribute access for a particular (collection) variable
|
/// @brief registers an attribute access for a particular (collection) variable
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -109,6 +109,56 @@ namespace triagens {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief returns the lower bound
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline AstNode const* lowerBound () const {
|
||||||
|
if (operatorType == NODE_TYPE_OPERATOR_BINARY_GT ||
|
||||||
|
operatorType == NODE_TYPE_OPERATOR_BINARY_GE ||
|
||||||
|
operatorType == NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||||
|
return valueNode;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief returns if the lower bound is inclusive
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool isLowerInclusive () const {
|
||||||
|
if (operatorType == NODE_TYPE_OPERATOR_BINARY_GE ||
|
||||||
|
operatorType == NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief returns the upper bound
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline AstNode const* upperBound () const {
|
||||||
|
if (operatorType == NODE_TYPE_OPERATOR_BINARY_LT ||
|
||||||
|
operatorType == NODE_TYPE_OPERATOR_BINARY_LE ||
|
||||||
|
operatorType == NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||||
|
return valueNode;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief returns if the upper bound is inclusive
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool isUpperInclusive () const {
|
||||||
|
if (operatorType == NODE_TYPE_OPERATOR_BINARY_LE ||
|
||||||
|
operatorType == NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief true if the condition is completely covered by the other condition
|
/// @brief true if the condition is completely covered by the other condition
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -188,6 +238,15 @@ namespace triagens {
|
||||||
return (_root->numMembers() == 0);
|
return (_root->numMembers() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not the condition results will be sorted (this is only
|
||||||
|
/// relevant if the condition consists of multiple ORs)
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline bool isSorted () const {
|
||||||
|
return _isSorted;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief return the condition as a Json object
|
/// @brief return the condition as a Json object
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -226,14 +285,6 @@ namespace triagens {
|
||||||
|
|
||||||
void normalize (ExecutionPlan*);
|
void normalize (ExecutionPlan*);
|
||||||
|
|
||||||
void fixOrs (ExecutionPlan*);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
/// @brief optimize the condition expression tree
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void optimize (ExecutionPlan*);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief removes condition parts from another
|
/// @brief removes condition parts from another
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -263,6 +314,19 @@ namespace triagens {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief sort ORs for the same attribute so they are in ascending value
|
||||||
|
/// order. this will only work if the condition is for a single attribute
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool sortOrs ();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief optimize the condition expression tree
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void optimize (ExecutionPlan*);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief registers an attribute access for a particular (collection) variable
|
/// @brief registers an attribute access for a particular (collection) variable
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -365,6 +429,12 @@ namespace triagens {
|
||||||
|
|
||||||
bool _isNormalized;
|
bool _isNormalized;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief whether or not the condition will return a sorted result
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool _isSorted;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1871,16 +1871,41 @@ struct SortToIndexNode final : public WalkerWorker<ExecutionNode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const& indexes = indexNode->getIndexes();
|
auto const& indexes = indexNode->getIndexes();
|
||||||
|
|
||||||
if (indexes.size() != 1) {
|
if (indexes.size() != 1) {
|
||||||
// can only use this index node if it uses exactly one index
|
// can only use this index node if it uses exactly one index or multiple indexes on exactly the same attributes
|
||||||
|
auto cond = indexNode->condition();
|
||||||
|
|
||||||
|
if (! cond->isSorted()) {
|
||||||
|
// index conditions do not guarantee sortedness
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<triagens::basics::AttributeName>> seen;
|
||||||
|
|
||||||
|
for (auto& index : indexes) {
|
||||||
|
if (index->sparse) {
|
||||||
|
// cannot use a sparse index for sorting
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! seen.empty() && triagens::basics::AttributeName::isIdentical(index->fields, seen)) {
|
||||||
|
// different attributes
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// all indexes use the same attributes and index conditions guarantee sorted output
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we get here, we either have one index or multiple indexes on the same attributes
|
||||||
auto index = indexes[0];
|
auto index = indexes[0];
|
||||||
|
|
||||||
if (! index->isSorted()) {
|
if (! index->isSorted()) {
|
||||||
// can only use a sorted index
|
// can only use a sorted index
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index->sparse) {
|
if (index->sparse) {
|
||||||
// cannot use a sparse index for sorting
|
// cannot use a sparse index for sorting
|
||||||
return true;
|
return true;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -52,6 +52,25 @@ bool triagens::basics::AttributeName::isIdentical (std::vector<AttributeName> co
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief compare two attribute name vectors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool triagens::basics::AttributeName::isIdentical (std::vector<std::vector<AttributeName>> const& lhs,
|
||||||
|
std::vector<std::vector<AttributeName>> const& rhs) {
|
||||||
|
if (lhs.size() != rhs.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lhs.size(); ++i) {
|
||||||
|
if (! isIdentical(lhs[i], rhs[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void triagens::basics::TRI_ParseAttributeString (std::string const& input,
|
void triagens::basics::TRI_ParseAttributeString (std::string const& input,
|
||||||
std::vector<AttributeName>& result) {
|
std::vector<AttributeName>& result) {
|
||||||
size_t parsedUntil = 0;
|
size_t parsedUntil = 0;
|
||||||
|
|
|
@ -78,6 +78,13 @@ namespace triagens {
|
||||||
|
|
||||||
static bool isIdentical (std::vector<AttributeName> const&,
|
static bool isIdentical (std::vector<AttributeName> const&,
|
||||||
std::vector<AttributeName> const&);
|
std::vector<AttributeName> const&);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief compare two attribute name vectors
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static bool isIdentical (std::vector<std::vector<AttributeName>> const&,
|
||||||
|
std::vector<std::vector<AttributeName>> const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue