mirror of https://gitee.com/bigwinds/arangodb
139 lines
4.3 KiB
C++
139 lines
4.3 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2019 ArangoDB 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 ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Yuriy Popov
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Aql/Ast.h"
|
|
#include "Aql/LateMaterializedOptimizerRulesCommon.h"
|
|
|
|
using namespace arangodb::aql;
|
|
|
|
namespace {
|
|
|
|
// traverse the AST, using previsitor
|
|
void traverseReadOnly(AstNode* node, AstNode* parentNode, size_t childNumber,
|
|
std::function<bool(AstNode const*, AstNode*, size_t)> const& preVisitor) {
|
|
if (node == nullptr) {
|
|
return;
|
|
}
|
|
|
|
if (!preVisitor(node, parentNode, childNumber)) {
|
|
return;
|
|
}
|
|
|
|
size_t const n = node->numMembers();
|
|
|
|
for (size_t i = 0; i < n; ++i) {
|
|
auto member = node->getMemberUnchecked(i);
|
|
|
|
if (member != nullptr) {
|
|
traverseReadOnly(member, node, i, preVisitor);
|
|
}
|
|
}
|
|
}
|
|
|
|
// traversal state
|
|
template<typename T>
|
|
struct TraversalState {
|
|
Variable const* variable;
|
|
latematerialized::NodeWithAttrs<T>& nodeAttrs;
|
|
bool optimize;
|
|
bool wasAccess;
|
|
};
|
|
}
|
|
|
|
// determines attributes referenced in an expression for the specified out variable
|
|
template<typename T>
|
|
bool latematerialized::getReferencedAttributes(AstNode* node,
|
|
Variable const* variable,
|
|
NodeWithAttrs<T>& nodeAttrs) {
|
|
TraversalState<T> state{variable, nodeAttrs, true, false};
|
|
|
|
auto preVisitor = [&state](AstNode const* node,
|
|
AstNode* parentNode, size_t childNumber) {
|
|
if (node == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
switch (node->type) {
|
|
case NODE_TYPE_ATTRIBUTE_ACCESS:
|
|
if (!state.wasAccess) {
|
|
T afData;
|
|
afData.parentNode = parentNode;
|
|
afData.childNumber = childNumber;
|
|
state.nodeAttrs.attrs.emplace_back(
|
|
typename NodeWithAttrs<T>::AttributeAndField{std::vector<arangodb::basics::AttributeName>{
|
|
{std::string(node->getStringValue(), node->getStringLength()), false}}, std::move(afData)});
|
|
state.wasAccess = true;
|
|
} else {
|
|
state.nodeAttrs.attrs.back().attr.emplace_back(std::string(node->getStringValue(), node->getStringLength()), false);
|
|
}
|
|
return true;
|
|
case NODE_TYPE_REFERENCE: {
|
|
// reference to a variable
|
|
auto v = static_cast<Variable const*>(node->getData());
|
|
if (v == state.variable) {
|
|
if (!state.wasAccess) {
|
|
// we haven't seen an attribute access directly before
|
|
state.optimize = false;
|
|
|
|
return false;
|
|
}
|
|
std::reverse(state.nodeAttrs.attrs.back().attr.begin(), state.nodeAttrs.attrs.back().attr.end());
|
|
} else if (state.wasAccess) {
|
|
state.nodeAttrs.attrs.pop_back();
|
|
}
|
|
// finish an attribute path
|
|
state.wasAccess = false;
|
|
return true;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (state.wasAccess) {
|
|
// not appropriate node type
|
|
state.wasAccess = false;
|
|
state.optimize = false;
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
traverseReadOnly(node, nullptr, 0, preVisitor);
|
|
|
|
return state.optimize;
|
|
}
|
|
|
|
template struct latematerialized::NodeWithAttrs<latematerialized::AstAndFieldData>;
|
|
template struct latematerialized::NodeWithAttrs<latematerialized::AstAndColumnFieldData>;
|
|
|
|
template bool latematerialized::getReferencedAttributes(
|
|
AstNode* node,
|
|
Variable const* variable,
|
|
NodeWithAttrs<latematerialized::AstAndFieldData>& nodeAttrs);
|
|
|
|
template bool latematerialized::getReferencedAttributes(
|
|
AstNode* node,
|
|
Variable const* variable,
|
|
NodeWithAttrs<latematerialized::AstAndColumnFieldData>& nodeAttrs);
|