mirror of https://gitee.com/bigwinds/arangodb
use Ast::ReverseOperator
This commit is contained in:
parent
738636db2d
commit
9c5d150866
|
@ -81,7 +81,7 @@ AstNode const Ast::EmptyStringNode{ "", VALUE_TYPE_STRING };
|
|||
/// @brief inverse comparison operators
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<int, AstNodeType> const Ast::ReverseOperators{
|
||||
std::unordered_map<int, AstNodeType> const Ast::NegatedOperators{
|
||||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_EQ), NODE_TYPE_OPERATOR_BINARY_NE },
|
||||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_NE), NODE_TYPE_OPERATOR_BINARY_EQ },
|
||||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_GT), NODE_TYPE_OPERATOR_BINARY_LE },
|
||||
|
@ -92,6 +92,18 @@ std::unordered_map<int, AstNodeType> const Ast::ReverseOperators{
|
|||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_NIN), NODE_TYPE_OPERATOR_BINARY_IN }
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reverse comparison operators
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unordered_map<int, AstNodeType> const Ast::ReversedOperators{
|
||||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_EQ), NODE_TYPE_OPERATOR_BINARY_EQ },
|
||||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_GT), NODE_TYPE_OPERATOR_BINARY_LT },
|
||||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_GE), NODE_TYPE_OPERATOR_BINARY_LE },
|
||||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_LT), NODE_TYPE_OPERATOR_BINARY_GT },
|
||||
{ static_cast<int>(NODE_TYPE_OPERATOR_BINARY_LE), NODE_TYPE_OPERATOR_BINARY_GE }
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors / destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -1083,6 +1095,19 @@ AstNode* Ast::clone (AstNode const* node) {
|
|||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the reversed operator for a comparison operator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AstNodeType Ast::ReverseOperator (AstNodeType type) {
|
||||
auto it = ReversedOperators.find(static_cast<int>(type));
|
||||
if (it == ReversedOperators.end()) {
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "invalid node type for inversed operator");
|
||||
}
|
||||
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -1222,8 +1247,8 @@ AstNode* Ast::optimizeNotExpression (AstNode* node) {
|
|||
auto lhs = operand->getMember(0);
|
||||
auto rhs = operand->getMember(1);
|
||||
|
||||
auto it = ReverseOperators.find(static_cast<int>(operand->type));
|
||||
TRI_ASSERT(it != ReverseOperators.end());
|
||||
auto it = NegatedOperators.find(static_cast<int>(operand->type));
|
||||
TRI_ASSERT(it != NegatedOperators.end());
|
||||
|
||||
return createNodeBinaryOperator((*it).second, lhs, rhs);
|
||||
}
|
||||
|
|
|
@ -489,6 +489,12 @@ namespace triagens {
|
|||
|
||||
AstNode* clone (AstNode const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the reversed operator for a comparison operator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AstNodeType ReverseOperator (AstNodeType);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -624,11 +630,16 @@ namespace triagens {
|
|||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief inverse comparison operators
|
||||
/// @brief negated comparison operators
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static std::unordered_map<int, AstNodeType> const ReverseOperators;
|
||||
static std::unordered_map<int, AstNodeType> const NegatedOperators;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reverse comparison operators
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static std::unordered_map<int, AstNodeType> const ReversedOperators;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
|
|
|
@ -452,15 +452,15 @@ void Optimizer::setupRules () {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// try to replace simple OR conditions with IN
|
||||
registerRule("replace-OR-with-IN",
|
||||
registerRule("replace-or-with-in",
|
||||
replaceOrWithIn,
|
||||
replaceOrWithIn_pass6,
|
||||
true);
|
||||
|
||||
// try to remove redundant OR
|
||||
registerRule("remove-redundant-OR",
|
||||
removeRedundantOR,
|
||||
removeRedundantOR_pass6,
|
||||
// try to remove redundant OR conditions
|
||||
registerRule("remove-redundant-or",
|
||||
removeRedundantOr,
|
||||
removeRedundantOr_pass6,
|
||||
true);
|
||||
|
||||
// try to find a filter after an enumerate collection and find an index . . .
|
||||
|
@ -474,10 +474,10 @@ void Optimizer::setupRules () {
|
|||
useIndexForSort,
|
||||
useIndexForSort_pass6,
|
||||
true);
|
||||
|
||||
#if 0
|
||||
|
||||
#if 0
|
||||
// try to remove filters which are covered by index ranges
|
||||
// rule seems to work, but tests are still missing
|
||||
// TODO: rule seems to work, but tests are still missing
|
||||
registerRule("remove-filter-covered-by-index",
|
||||
removeFiltersCoveredByIndex,
|
||||
removeFiltersCoveredByIndex_pass6,
|
||||
|
|
|
@ -131,7 +131,7 @@ namespace triagens {
|
|||
replaceOrWithIn_pass6 = 810,
|
||||
|
||||
// remove redundant OR conditions
|
||||
removeRedundantOR_pass6 = 820,
|
||||
removeRedundantOr_pass6 = 820,
|
||||
|
||||
// try to find a filter after an enumerate collection and find an index . . .
|
||||
useIndexRange_pass6 = 830,
|
||||
|
|
|
@ -1477,9 +1477,7 @@ int triagens::aql::useIndexForSort (Optimizer* opt,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// TODO: finish rule and test it
|
||||
|
||||
struct FilterCondition {
|
||||
std::string variableName;
|
||||
std::string attributeName;
|
||||
|
@ -1561,19 +1559,17 @@ struct FilterCondition {
|
|||
lhs = node->getMember(1);
|
||||
rhs = node->getMember(0);
|
||||
|
||||
auto it = Ast::ReverseOperators.find(static_cast<int>(node->type));
|
||||
TRI_ASSERT(it != Ast::ReverseOperators.end());
|
||||
|
||||
op = (*it).second;
|
||||
op = Ast::ReverseOperator(node->type);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
TRI_ASSERT(lhs->type == NODE_TYPE_VALUE);
|
||||
TRI_ASSERT(rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS);
|
||||
|
||||
std::function<void(AstNode const*)> buildName = [&] (AstNode const* node) -> void {
|
||||
std::function<void(AstNode const*, std::string&, std::string&)> buildName =
|
||||
[&] (AstNode const* node, std::string& variableName, std::string& attributeName) -> void {
|
||||
if (node->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
buildName(node->getMember(0));
|
||||
buildName(node->getMember(0), variableName, attributeName);
|
||||
|
||||
if (! attributeName.empty()) {
|
||||
attributeName.push_back('.');
|
||||
|
@ -1588,7 +1584,9 @@ struct FilterCondition {
|
|||
};
|
||||
|
||||
if (attributeName.empty()) {
|
||||
buildName(rhs);
|
||||
TRI_ASSERT(! variableName.empty());
|
||||
|
||||
buildName(rhs, variableName, attributeName);
|
||||
if (op == NODE_TYPE_OPERATOR_BINARY_EQ ||
|
||||
op == NODE_TYPE_OPERATOR_BINARY_NE) {
|
||||
lowInclusive = true;
|
||||
|
@ -1615,10 +1613,19 @@ struct FilterCondition {
|
|||
|
||||
return true;
|
||||
}
|
||||
// else if (attributeName == std::string(buffer.c_str(), buffer.length())) {
|
||||
// same attribute
|
||||
// TODO
|
||||
// }
|
||||
else {
|
||||
// already have collected something, now check if the next condition
|
||||
// is for the same variable / attribute
|
||||
std::string compareVariableName;
|
||||
std::string compareAttributeName;
|
||||
buildName(rhs, compareVariableName, compareAttributeName);
|
||||
|
||||
if (variableName == compareVariableName &&
|
||||
attributeName == compareAttributeName) {
|
||||
// same attribute
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
// fall-through
|
||||
}
|
||||
|
@ -1638,7 +1645,6 @@ struct FilterCondition {
|
|||
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief try to remove filters which are covered by indexes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1657,7 +1663,9 @@ int triagens::aql::removeFiltersCoveredByIndex (Optimizer* opt,
|
|||
// auto outVar = cn->getVariablesSetHere();
|
||||
|
||||
auto setter = plan->getVarSetBy(inVar[0]->id);
|
||||
TRI_ASSERT(setter != nullptr);
|
||||
if (setter == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setter->getType() != EN::CALCULATION) {
|
||||
continue;
|
||||
|
@ -1717,7 +1725,6 @@ int triagens::aql::removeFiltersCoveredByIndex (Optimizer* opt,
|
|||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief helper to compute lots of permutation tuples
|
||||
|
@ -2761,8 +2768,7 @@ int triagens::aql::replaceOrWithIn (Optimizer* opt,
|
|||
LEAVE_BLOCK;
|
||||
}
|
||||
|
||||
struct RemoveRedundantOR {
|
||||
|
||||
struct RemoveRedundantOr {
|
||||
AstNode const* bestValue = nullptr;
|
||||
AstNodeType comparison;
|
||||
bool inclusive;
|
||||
|
@ -2791,19 +2797,22 @@ struct RemoveRedundantOR {
|
|||
(type == NODE_TYPE_OPERATOR_BINARY_GE
|
||||
|| type == NODE_TYPE_OPERATOR_BINARY_GT)) {
|
||||
return -1; //high bound
|
||||
} else if ((comparison == NODE_TYPE_OPERATOR_BINARY_GE
|
||||
}
|
||||
else if ((comparison == NODE_TYPE_OPERATOR_BINARY_GE
|
||||
|| comparison == NODE_TYPE_OPERATOR_BINARY_GT) &&
|
||||
(type == NODE_TYPE_OPERATOR_BINARY_LE
|
||||
|| type == NODE_TYPE_OPERATOR_BINARY_LT)) {
|
||||
return 1; //low bound
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if ((comparison == NODE_TYPE_OPERATOR_BINARY_LE
|
||||
|| comparison == NODE_TYPE_OPERATOR_BINARY_LT) &&
|
||||
(type == NODE_TYPE_OPERATOR_BINARY_LE
|
||||
|| type == NODE_TYPE_OPERATOR_BINARY_LT)) {
|
||||
return -1; //high bound
|
||||
} else if ((comparison == NODE_TYPE_OPERATOR_BINARY_GE
|
||||
}
|
||||
else if ((comparison == NODE_TYPE_OPERATOR_BINARY_GE
|
||||
|| comparison == NODE_TYPE_OPERATOR_BINARY_GT) &&
|
||||
(type == NODE_TYPE_OPERATOR_BINARY_GE
|
||||
|| type == NODE_TYPE_OPERATOR_BINARY_GT)) {
|
||||
|
@ -2823,25 +2832,10 @@ struct RemoveRedundantOR {
|
|||
return (isInclusiveBound(type) ? true : false);
|
||||
}
|
||||
return (cmp * lowhigh == 1);
|
||||
};
|
||||
|
||||
AstNodeType reverseComparison (AstNodeType type) {
|
||||
if (type == NODE_TYPE_OPERATOR_BINARY_LE) {
|
||||
return NODE_TYPE_OPERATOR_BINARY_GE;
|
||||
}
|
||||
else if (type == NODE_TYPE_OPERATOR_BINARY_LT) {
|
||||
return NODE_TYPE_OPERATOR_BINARY_GT;
|
||||
}
|
||||
else if (type == NODE_TYPE_OPERATOR_BINARY_GT) {
|
||||
return NODE_TYPE_OPERATOR_BINARY_LT;
|
||||
}
|
||||
else {
|
||||
return NODE_TYPE_OPERATOR_BINARY_LE;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasRedundantCondition (AstNode const* node) {
|
||||
if(finder.find(node, NODE_TYPE_OPERATOR_BINARY_LT, commonNode, commonName)){
|
||||
if (finder.find(node, NODE_TYPE_OPERATOR_BINARY_LT, commonNode, commonName)) {
|
||||
return hasRedundantConditionWalker(node);
|
||||
}
|
||||
return false;
|
||||
|
@ -2855,10 +2849,10 @@ struct RemoveRedundantOR {
|
|||
hasRedundantConditionWalker(node->getMember(1)));
|
||||
}
|
||||
|
||||
if( type == NODE_TYPE_OPERATOR_BINARY_LE
|
||||
if (type == NODE_TYPE_OPERATOR_BINARY_LE
|
||||
|| type == NODE_TYPE_OPERATOR_BINARY_LT
|
||||
|| type == NODE_TYPE_OPERATOR_BINARY_GE
|
||||
|| type == NODE_TYPE_OPERATOR_BINARY_GT ) {
|
||||
|| type == NODE_TYPE_OPERATOR_BINARY_GT) {
|
||||
|
||||
auto lhs = node->getMember(0);
|
||||
auto rhs = node->getMember(1);
|
||||
|
@ -2867,8 +2861,8 @@ struct RemoveRedundantOR {
|
|||
&& ! hasRedundantConditionWalker(lhs)
|
||||
&& lhs->isConstant()) {
|
||||
|
||||
if (!isComparisonSet) {
|
||||
comparison = reverseComparison(type);
|
||||
if (! isComparisonSet) {
|
||||
comparison = Ast::ReverseOperator(type);
|
||||
bestValue = lhs;
|
||||
isComparisonSet = true;
|
||||
return true;
|
||||
|
@ -2880,7 +2874,7 @@ struct RemoveRedundantOR {
|
|||
}
|
||||
|
||||
if (compareBounds(type, lhs, lowhigh)) {
|
||||
comparison = reverseComparison(type);
|
||||
comparison = Ast::ReverseOperator(type);
|
||||
bestValue = lhs;
|
||||
}
|
||||
return true;
|
||||
|
@ -2888,7 +2882,7 @@ struct RemoveRedundantOR {
|
|||
if (hasRedundantConditionWalker(lhs)
|
||||
&& ! hasRedundantConditionWalker(rhs)
|
||||
&& rhs->isConstant()) {
|
||||
if (!isComparisonSet) {
|
||||
if (! isComparisonSet) {
|
||||
comparison = type;
|
||||
bestValue = rhs;
|
||||
isComparisonSet = true;
|
||||
|
@ -2915,7 +2909,8 @@ struct RemoveRedundantOR {
|
|||
type == NODE_TYPE_INDEXED_ACCESS) {
|
||||
// get a string representation of the node for comparisons
|
||||
return (node->toString() == commonName);
|
||||
} else if (node->isBoolValue()) {
|
||||
}
|
||||
else if (node->isBoolValue()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2923,7 +2918,7 @@ struct RemoveRedundantOR {
|
|||
}
|
||||
};
|
||||
|
||||
int triagens::aql::removeRedundantOR (Optimizer* opt,
|
||||
int triagens::aql::removeRedundantOr (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
Optimizer::Rule const* rule) {
|
||||
ENTER_BLOCK;
|
||||
|
@ -2951,19 +2946,13 @@ int triagens::aql::removeRedundantOR (Optimizer* opt,
|
|||
continue;
|
||||
}
|
||||
|
||||
RemoveRedundantOR remover;
|
||||
if(remover.hasRedundantCondition(cn->expression()->node())){
|
||||
RemoveRedundantOr remover;
|
||||
if (remover.hasRedundantCondition(cn->expression()->node())) {
|
||||
Expression* expr = nullptr;
|
||||
ExecutionNode* newNode = nullptr;
|
||||
auto astNode = remover.createReplacementNode(plan->getAst());
|
||||
|
||||
try {
|
||||
expr = new Expression(plan->getAst(), astNode);
|
||||
}
|
||||
catch (...) {
|
||||
delete astNode;
|
||||
throw;
|
||||
}
|
||||
expr = new Expression(plan->getAst(), astNode);
|
||||
|
||||
try {
|
||||
newNode = new CalculationNode(plan, plan->nextId(), expr, outVar[0]);
|
||||
|
|
|
@ -182,7 +182,7 @@ namespace triagens {
|
|||
|
||||
int replaceOrWithIn (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
int removeRedundantOR (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
int removeRedundantOr (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
} // namespace aql
|
||||
} // namespace triagens
|
||||
|
|
|
@ -38,7 +38,7 @@ var getQueryResults = helper.getQueryResults;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function NewAqlRemoveRedundantORTestSuite () {
|
||||
var ruleName = "remove-redundant-OR";
|
||||
var ruleName = "remove-redundant-or";
|
||||
|
||||
var isRuleUsed = function (query, params) {
|
||||
var result = AQL_EXPLAIN(query, params, { optimizer: { rules: [ "-all", "+" + ruleName ] } });
|
||||
|
|
|
@ -39,7 +39,7 @@ var getQueryResults = helper.getQueryResults;
|
|||
|
||||
function NewAqlReplaceORWithINTestSuite () {
|
||||
var replace;
|
||||
var ruleName = "replace-OR-with-IN";
|
||||
var ruleName = "replace-or-with-in";
|
||||
|
||||
var isRuleUsed = function (query, params) {
|
||||
var result = AQL_EXPLAIN(query, params, { optimizer: { rules: [ "-all", "+" + ruleName ] } });
|
||||
|
|
Loading…
Reference in New Issue