mirror of https://gitee.com/bigwinds/arangodb
Expression:
- add function isSimpleAccessReference() to check whether it is a coll.attr.attr - add function getAccessNRef() to retrieve pair("attr.attr", "coll"), SortIndex optimizer: - use the new functionality to get better readable code. rename indexes -> indices
This commit is contained in:
parent
18d308af0f
commit
5e75ec8bb5
|
@ -408,10 +408,10 @@ void EnumerateCollectionNode::toJsonHelper (triagens::basics::Json& nodes,
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get vector of indexes with fields <attrs>
|
/// @brief get vector of indices with fields <attrs>
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::vector<TRI_index_t*> EnumerateCollectionNode::getIndexesUnordered (vector<std::string> attrs) const {
|
std::vector<TRI_index_t*> EnumerateCollectionNode::getIndicesUnordered (vector<std::string> attrs) const {
|
||||||
std::vector<TRI_index_t*> out;
|
std::vector<TRI_index_t*> out;
|
||||||
TRI_document_collection_t* document = _collection->documentCollection();
|
TRI_document_collection_t* document = _collection->documentCollection();
|
||||||
size_t const n = document->_allIndexes._length;
|
size_t const n = document->_allIndexes._length;
|
||||||
|
@ -499,7 +499,7 @@ EnumerateCollectionNode::CompareIndex (TRI_index_t* idx,
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<EnumerateCollectionNode::IndexMatch> EnumerateCollectionNode::getIndexesOrdered (IndexMatchVec &attrs) const {
|
std::vector<EnumerateCollectionNode::IndexMatch> EnumerateCollectionNode::getIndicesOrdered (IndexMatchVec &attrs) const {
|
||||||
|
|
||||||
std::vector<IndexMatch> out;
|
std::vector<IndexMatch> out;
|
||||||
TRI_document_collection_t* document = _collection->documentCollection();
|
TRI_document_collection_t* document = _collection->documentCollection();
|
||||||
|
@ -842,7 +842,7 @@ public:
|
||||||
: _foundCalcNodes(0),
|
: _foundCalcNodes(0),
|
||||||
_elms(me->getElements())
|
_elms(me->getElements())
|
||||||
{
|
{
|
||||||
_myVars.reserve(_elms.size());
|
_myVars.resize(_elms.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool before (ExecutionNode* en) {
|
bool before (ExecutionNode* en) {
|
||||||
|
|
|
@ -654,10 +654,10 @@ namespace triagens {
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief get vector of indexes that has any match in its fields with <attrs>
|
/// @brief get vector of indices that has any match in its fields with <attrs>
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::vector<TRI_index_t*> getIndexesUnordered (vector<std::string> attrs) const;
|
std::vector<TRI_index_t*> getIndicesUnordered (vector<std::string> attrs) const;
|
||||||
|
|
||||||
enum MatchType {
|
enum MatchType {
|
||||||
FULL_MATCH,
|
FULL_MATCH,
|
||||||
|
@ -689,7 +689,7 @@ namespace triagens {
|
||||||
/// the specified indexes.
|
/// the specified indexes.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::vector<IndexMatch> getIndexesOrdered (IndexMatchVec &attrs) const;
|
std::vector<IndexMatch> getIndicesOrdered (IndexMatchVec &attrs) const;
|
||||||
|
|
||||||
TRI_vocbase_t* vocbase () const {
|
TRI_vocbase_t* vocbase () const {
|
||||||
return _vocbase;
|
return _vocbase;
|
||||||
|
|
|
@ -334,6 +334,65 @@ AqlValue Expression::executeSimpleExpression (AstNode const* node,
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "unhandled type in simple expression");
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "unhandled type in simple expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Expression::isSimpleAccessReference() const {
|
||||||
|
if (!isSimple()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto expNode = _node;
|
||||||
|
|
||||||
|
if (expNode->type != triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (expNode->type == triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||||
|
expNode = expNode->getMember (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (expNode->type == triagens::aql::NODE_TYPE_REFERENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, std::string> Expression::getAccessNRef() const {
|
||||||
|
if (!isSimple()) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||||
|
"getAccessNRef works only on simple expressions!");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto expNode = _node;
|
||||||
|
std::vector<std::string> attributeVector;
|
||||||
|
|
||||||
|
if (expNode->type != triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||||
|
"getAccessNRef works only on simple expressions!");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (expNode->type == triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||||
|
attributeVector.push_back(expNode->getStringValue());
|
||||||
|
expNode = expNode->getMember (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string attributeVectorStr = "";
|
||||||
|
for (auto oneAttr = attributeVector.rbegin();
|
||||||
|
oneAttr != attributeVector.rend();
|
||||||
|
++oneAttr) {
|
||||||
|
if (attributeVectorStr.size() > 0)
|
||||||
|
attributeVectorStr += std::string(".");
|
||||||
|
attributeVectorStr += *oneAttr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expNode->type != triagens::aql::NODE_TYPE_REFERENCE) {
|
||||||
|
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||||
|
"getAccessNRef works only on simple expressions!");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto var = static_cast<Variable*>(expNode->getData());
|
||||||
|
|
||||||
|
return std::make_pair(attributeVectorStr, var->name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- END-OF-FILE
|
// --SECTION-- END-OF-FILE
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -146,10 +146,23 @@ namespace triagens {
|
||||||
/// @brief check whether this is a simple expression.
|
/// @brief check whether this is a simple expression.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
bool isSimple () {
|
bool isSimple () const {
|
||||||
return _type == SIMPLE;
|
return _type == SIMPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief check whether this is a simple access to a Reference.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool isSimpleAccessReference () const;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief this gives you ("variable.access", "Reference")
|
||||||
|
/// call isSimpleAccessReference in advance to enshure no exceptions.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::pair<std::string, std::string> getAccessNRef() const;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private functions
|
// --SECTION-- private functions
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -374,7 +374,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::vector<TRI_index_t*> idxs = node->getIndexesUnordered(attrs);
|
std::vector<TRI_index_t*> idxs = node->getIndicesUnordered(attrs);
|
||||||
// make one new plan for every index in <idxs> that replaces the
|
// make one new plan for every index in <idxs> that replaces the
|
||||||
// enumerate collection node with a RangeIndexNode . . .
|
// enumerate collection node with a RangeIndexNode . . .
|
||||||
for (auto idx: idxs) {
|
for (auto idx: idxs) {
|
||||||
|
@ -543,6 +543,8 @@ int triagens::aql::useIndexRange (Optimizer* opt,
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
||||||
|
using EN = triagens::aql::ExecutionNode;
|
||||||
|
|
||||||
SortNode *_sortNode;
|
SortNode *_sortNode;
|
||||||
RangesInfo* _ranges;
|
RangesInfo* _ranges;
|
||||||
ExecutionPlan* _plan;
|
ExecutionPlan* _plan;
|
||||||
|
@ -569,186 +571,106 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
||||||
_idsToRemove.push_back(Node->id());
|
_idsToRemove.push_back(Node->id());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool before (ExecutionNode* en) {
|
void RemoveSortNode (ExecutionPlan *newPlan) {
|
||||||
std::cout << "type:" << en->getTypeString() << "\n";
|
for (auto idToRemove = _idsToRemove.begin();
|
||||||
size_t n = _vars.size();
|
idToRemove != _idsToRemove.end();
|
||||||
auto outvar = en->getVariablesSetHere();
|
++idToRemove) {
|
||||||
/*
|
newPlan->unlinkNode(newPlan->getNodeById(*idToRemove));
|
||||||
if ((_executionNodesFound < n) &&
|
|
||||||
en->getType() == triagens::aql::ExecutionNode::CALCULATION) {
|
|
||||||
|
|
||||||
// Look up whether this is one of the calculation nodes we reference.
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
if (_vars[i]->id == outvar[0]->id) {
|
|
||||||
_myVars[i] = static_cast<triagens::aql::CalculationNode*>(en);
|
|
||||||
_executionNodesFound++;
|
|
||||||
_idsToRemove.push_back (en->id());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_executionNodesFound == n) {
|
|
||||||
// ok we got all, study them.
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_executionNodesFound == n) {*/
|
|
||||||
if (en->getType() == triagens::aql::ExecutionNode::FILTER) {
|
|
||||||
/// skip. we don't care.
|
|
||||||
/// TODO: check whether to ABORT here?
|
|
||||||
}
|
|
||||||
if (en->getType() == triagens::aql::ExecutionNode::SORT) {
|
|
||||||
return true; // pulling two sorts together is done elsewhere.
|
|
||||||
}
|
|
||||||
if (en->getType() == triagens::aql::ExecutionNode::LIMIT) {
|
|
||||||
return true; // LIMIT is criterion to stop
|
|
||||||
}
|
|
||||||
if (en->getType() == triagens::aql::ExecutionNode::INDEX_RANGE) {
|
|
||||||
// TODO: we should also match INDEX_RANGE later on.
|
|
||||||
// todo: this may only be done if there is a full index match.
|
|
||||||
}
|
|
||||||
else if (en->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION) {
|
|
||||||
/*
|
|
||||||
std::cout << "blub\n";
|
|
||||||
auto JsonPlan = _plan->toJson(TRI_UNKNOWN_MEM_ZONE, false);
|
|
||||||
auto JsonString = JsonPlan.toString();
|
|
||||||
std::cout <<"Old Plan: \n" << JsonString << "\n";
|
|
||||||
*/
|
|
||||||
size_t nVarsIndexable = 0;
|
|
||||||
std::vector<std::vector<RangeInfo*>> rangeInfo;
|
|
||||||
std::vector<std::string> attributeVector;
|
|
||||||
EnumerateCollectionNode::IndexMatchVec attrs;
|
|
||||||
std::string collectionName;
|
|
||||||
|
|
||||||
auto node = static_cast<EnumerateCollectionNode*>(en);
|
|
||||||
auto var = node->getVariablesSetHere()[0]; // should only be 1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
auto blarg = _sortNode->getExpressions();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
auto sortElements = _sortNode->getElements();
|
|
||||||
|
|
||||||
for (size_t n = 0; n < sortElements.size(); n++) {
|
|
||||||
// we should have already made shure this works above.
|
|
||||||
TRI_ASSERT(sortElements[n].first->id == _myVars[n]->outVariable()->id);
|
|
||||||
bool ASC = sortElements[n].second; /// TODO what to do with this?
|
|
||||||
|
|
||||||
auto exp = _myVars[n]->expression();
|
|
||||||
|
|
||||||
if (!exp->isSimple()) {
|
|
||||||
break; // nott simple? stop evaluation.
|
|
||||||
}
|
|
||||||
|
|
||||||
auto expNode = exp->node();
|
|
||||||
|
|
||||||
if (expNode->type != triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
|
||||||
break; // we only support attribute accesses.
|
|
||||||
}
|
|
||||||
|
|
||||||
// digg through nested Attributes:
|
|
||||||
while (expNode->type == triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
|
||||||
attributeVector.push_back(expNode->getStringValue());
|
|
||||||
expNode = expNode->getMember (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// And concatenate the attributes again in reverse order:
|
|
||||||
std::string attributeVectorStr = "";
|
|
||||||
for (auto oneAttr = attributeVector.rbegin();
|
|
||||||
oneAttr != attributeVector.rend();
|
|
||||||
++oneAttr) {
|
|
||||||
if (attributeVectorStr.size() > 0)
|
|
||||||
attributeVectorStr += std::string(".");
|
|
||||||
attributeVectorStr += *oneAttr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we now should have a Collection Reference:
|
|
||||||
if (expNode->type != triagens::aql::NODE_TYPE_REFERENCE) {
|
|
||||||
break; // some other operation - can't work with this.
|
|
||||||
}
|
|
||||||
|
|
||||||
auto subVar = static_cast<Variable*>(expNode->getData());
|
|
||||||
if (subVar->name != var->name) {
|
|
||||||
// No, the requested collection is not a reference to this.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
expNode = exp->node();
|
|
||||||
|
|
||||||
attrs.push_back(std::make_pair(attributeVectorStr, ASC));
|
|
||||||
collectionName = expNode->getStringValue();
|
|
||||||
|
|
||||||
rangeInfo.push_back(std::vector<RangeInfo*>());
|
|
||||||
rangeInfo.at(nVarsIndexable).push_back(new RangeInfo(var->name, /// todo: asc/desc
|
|
||||||
attributeVectorStr,
|
|
||||||
///(ASC)? a:b,
|
|
||||||
///(ASC)? b:a,
|
|
||||||
|
|
||||||
nullptr, nullptr));
|
|
||||||
nVarsIndexable++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nVarsIndexable == 0) {
|
|
||||||
return true; // we didn't find anything replaceable by this index
|
|
||||||
}
|
|
||||||
|
|
||||||
auto indexes = node->getIndexesOrdered(attrs);
|
|
||||||
|
|
||||||
if (indexes.size() == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// make one new plan for every index in <idxs> that replaces the
|
|
||||||
// enumerate collection node with a RangeIndexNode . . .
|
|
||||||
for (auto idx: indexes) {
|
|
||||||
|
|
||||||
//can only use the index if it is a skip list or (a hash and we
|
|
||||||
//are checking equality)
|
|
||||||
std::cout << "FOUND INDEX!\n";
|
|
||||||
|
|
||||||
auto newPlan = _plan->clone();
|
|
||||||
ExecutionNode* newNode = nullptr;
|
|
||||||
try{
|
|
||||||
newNode = new IndexRangeNode( newPlan->nextId(),
|
|
||||||
node->vocbase(),
|
|
||||||
node->collection(),
|
|
||||||
node->outVariable(),
|
|
||||||
idx.index,/// TODO: estimate cost on match quality
|
|
||||||
rangeInfo);
|
|
||||||
newPlan->registerNode(newNode);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
if (newNode != nullptr) {
|
|
||||||
delete newNode;
|
|
||||||
}
|
|
||||||
delete newPlan;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
newPlan->replaceNode(newPlan->getNodeById(node->id()), newNode);
|
|
||||||
|
|
||||||
auto JsonPlan = newPlan->toJson(TRI_UNKNOWN_MEM_ZONE, false);
|
|
||||||
auto JsonString = JsonPlan.toString();
|
|
||||||
std::cout <<"New Plan: \n" << JsonString << "\n";
|
|
||||||
|
|
||||||
if (idx.fullmatch) { // if the index replaces the sort, remove it.
|
|
||||||
for (auto idToRemove = _idsToRemove.begin();
|
|
||||||
idToRemove != _idsToRemove.end();
|
|
||||||
++idToRemove) {
|
|
||||||
newPlan->unlinkNode(newPlan->getNodeById(*idToRemove));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JsonPlan = newPlan->toJson(TRI_UNKNOWN_MEM_ZONE, false);
|
|
||||||
JsonString = JsonPlan.toString();
|
|
||||||
std::cout <<"removed foo \n" << JsonString << "\n";
|
|
||||||
|
|
||||||
_out.push_back(newPlan);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleEnumerateCollectionNode(EnumerateCollectionNode* node)
|
||||||
|
{
|
||||||
|
auto collectionName = node->getVariablesSetHere()[0]->name;
|
||||||
|
auto sortParams = _sortNode->getCalcNodePairs();
|
||||||
|
|
||||||
|
EnumerateCollectionNode::IndexMatchVec attrs;
|
||||||
|
std::vector<std::vector<RangeInfo*>> rangeInfo;
|
||||||
|
size_t nVarsIndexable = 0;
|
||||||
|
|
||||||
|
for (size_t n = 0; n < sortParams.size(); n++) {
|
||||||
|
bool ASC = sortParams[n].second;
|
||||||
|
auto oneSortExpression = sortParams[n].first->expression();
|
||||||
|
_idsToRemove.push_back(sortParams[n].first->id());
|
||||||
|
|
||||||
|
if (!oneSortExpression->isSimpleAccessReference()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto simpleExpression = oneSortExpression->getAccessNRef();
|
||||||
|
|
||||||
|
if (simpleExpression.second != collectionName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs.push_back(std::make_pair(simpleExpression.first, ASC));
|
||||||
|
|
||||||
|
rangeInfo.push_back(std::vector<RangeInfo*>());
|
||||||
|
|
||||||
|
rangeInfo.at(nVarsIndexable).push_back(new RangeInfo(collectionName,
|
||||||
|
simpleExpression.first,
|
||||||
|
nullptr, nullptr));
|
||||||
|
nVarsIndexable++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nVarsIndexable == 0) {
|
||||||
|
return; // we didn't find anything replaceable by indice
|
||||||
|
}
|
||||||
|
|
||||||
|
auto indices = node->getIndicesOrdered(attrs);
|
||||||
|
|
||||||
|
// make one new plan for each index that replaces this
|
||||||
|
// EnumerateCollectionNode with an IndexRangeNode
|
||||||
|
for (auto idx: indices) {
|
||||||
|
//can only use the index if it is a skip list or (a hash and we
|
||||||
|
//are checking equality)
|
||||||
|
auto newPlan = _plan->clone();
|
||||||
|
ExecutionNode* newNode = nullptr;
|
||||||
|
try {
|
||||||
|
newNode = new IndexRangeNode( newPlan->nextId(),
|
||||||
|
node->vocbase(),
|
||||||
|
node->collection(),
|
||||||
|
node->outVariable(),
|
||||||
|
idx.index,/// TODO: estimate cost on match quality
|
||||||
|
rangeInfo);
|
||||||
|
newPlan->registerNode(newNode);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
if (newNode != nullptr) {
|
||||||
|
delete newNode;
|
||||||
|
}
|
||||||
|
delete newPlan;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
newPlan->replaceNode(newPlan->getNodeById(node->id()), newNode);
|
||||||
|
|
||||||
|
if (idx.fullmatch) { // if the index superseedes the sort, remove it.
|
||||||
|
RemoveSortNode(newPlan);
|
||||||
|
}
|
||||||
|
_out.push_back(newPlan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool before (ExecutionNode* en) {
|
||||||
|
std::cout << "type:" << en->getTypeString() << "\n";
|
||||||
|
switch (en->getType()) {
|
||||||
|
default: // skip. we don't care.
|
||||||
|
case EN::FILTER: // skip. we don't care.
|
||||||
|
return false; /// TODO: check whether to ABORT here?
|
||||||
|
case EN::SORT: // pulling two sorts together is done elsewhere.
|
||||||
|
return en != _sortNode;
|
||||||
|
case EN::LIMIT: // LIMIT is criterion to stop
|
||||||
|
return true;
|
||||||
|
case EN::INDEX_RANGE:
|
||||||
|
// TODO: we should also match INDEX_RANGE later on.
|
||||||
|
// todo: this may only be done if there is a full index match.
|
||||||
|
return true;
|
||||||
|
case EN::ENUMERATE_COLLECTION:
|
||||||
|
handleEnumerateCollectionNode(static_cast<EnumerateCollectionNode*>(en));
|
||||||
|
return true; // no matching index found.
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue