mirror of https://gitee.com/bigwinds/arangodb
added all node types to FilterToEnumCollFinder.
This commit is contained in:
parent
b00521b881
commit
b6f9f11e5e
|
@ -1051,7 +1051,8 @@ void IndexRangeBlock::readSkiplistIndex () {
|
||||||
// this creates the infinite range (i.e. >= null)
|
// this creates the infinite range (i.e. >= null)
|
||||||
Json hass(Json::List);
|
Json hass(Json::List);
|
||||||
hass.add(Json(Json::Null));
|
hass.add(Json(Json::Null));
|
||||||
skiplistOperator = TRI_CreateIndexOperator(TRI_GE_INDEX_OPERATOR, nullptr, nullptr, hass.steal(), shaper, nullptr, 1, nullptr);
|
skiplistOperator = TRI_CreateIndexOperator(TRI_GE_INDEX_OPERATOR, nullptr,
|
||||||
|
nullptr, hass.steal(), shaper, nullptr, 1, nullptr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
skiplistOperator = TRI_CreateIndexOperator(TRI_EQ_INDEX_OPERATOR, nullptr,
|
skiplistOperator = TRI_CreateIndexOperator(TRI_EQ_INDEX_OPERATOR, nullptr,
|
||||||
|
|
|
@ -398,123 +398,152 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
||||||
bool before (ExecutionNode* en) {
|
bool before (ExecutionNode* en) {
|
||||||
_canThrow = (_canThrow || en->canThrow()); // can any node walked over throw?
|
_canThrow = (_canThrow || en->canThrow()); // can any node walked over throw?
|
||||||
|
|
||||||
if (en->getType() == triagens::aql::ExecutionNode::FILTER) {
|
switch (en->getType()) {
|
||||||
std::vector<Variable const*> inVar = en->getVariablesUsedHere();
|
case EN::ENUMERATE_LIST:
|
||||||
TRI_ASSERT(inVar.size() == 1);
|
break;
|
||||||
_varIds.insert(inVar[0]->id);
|
case EN::CALCULATION: {
|
||||||
}
|
auto outvar = en->getVariablesSetHere();
|
||||||
else if (en->getType() == triagens::aql::ExecutionNode::CALCULATION) {
|
TRI_ASSERT(outvar.size() == 1);
|
||||||
auto outvar = en->getVariablesSetHere();
|
if (_varIds.find(outvar[0]->id) != _varIds.end()) {
|
||||||
TRI_ASSERT(outvar.size() == 1);
|
auto node = static_cast<CalculationNode*>(en);
|
||||||
if (_varIds.find(outvar[0]->id) != _varIds.end()) {
|
std::string attr;
|
||||||
auto node = static_cast<CalculationNode*>(en);
|
std::string enumCollVar;
|
||||||
std::string attr;
|
buildRangeInfo(node->expression()->node(), enumCollVar, attr);
|
||||||
std::string enumCollVar;
|
|
||||||
buildRangeInfo(node->expression()->node(), enumCollVar, attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (en->getType() == triagens::aql::ExecutionNode::ENUMERATE_COLLECTION) {
|
|
||||||
auto node = static_cast<EnumerateCollectionNode*>(en);
|
|
||||||
auto var = node->getVariablesSetHere()[0]; // should only be 1
|
|
||||||
auto map = _ranges->find(var->name); // check if we have any ranges with this var
|
|
||||||
|
|
||||||
if (map != nullptr) {
|
|
||||||
// check the first components of <map> against indexes of <node> . . .
|
|
||||||
std::unordered_set<std::string> attrs;
|
|
||||||
|
|
||||||
bool valid = true; // are all the range infos valid
|
|
||||||
bool equality = true; // are all the range infos equalities
|
|
||||||
|
|
||||||
for(auto x: *map) {
|
|
||||||
valid &= x.second._valid;
|
|
||||||
if (!valid) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
equality &= x.second.is1ValueRangeInfo();
|
|
||||||
attrs.insert(x.first);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EN::SUBQUERY:
|
||||||
|
break;
|
||||||
|
case EN::FILTER:{
|
||||||
|
std::vector<Variable const*> inVar = en->getVariablesUsedHere();
|
||||||
|
TRI_ASSERT(inVar.size() == 1);
|
||||||
|
_varIds.insert(inVar[0]->id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EN::INTERSECTION:
|
||||||
|
case EN::SINGLETON:
|
||||||
|
case EN::AGGREGATE:
|
||||||
|
case EN::LOOKUP_JOIN:
|
||||||
|
case EN::MERGE_JOIN:
|
||||||
|
case EN::LOOKUP_INDEX_UNIQUE:
|
||||||
|
case EN::LOOKUP_INDEX_RANGE:
|
||||||
|
case EN::LOOKUP_FULL_COLLECTION:
|
||||||
|
case EN::CONCATENATION:
|
||||||
|
case EN::MERGE:
|
||||||
|
case EN::REMOTE:
|
||||||
|
case EN::INSERT:
|
||||||
|
case EN::REMOVE:
|
||||||
|
case EN::REPLACE:
|
||||||
|
case EN::UPDATE:
|
||||||
|
case EN::RETURN:
|
||||||
|
case EN::NORESULTS:
|
||||||
|
case EN::ILLEGAL:
|
||||||
|
break;
|
||||||
|
case EN::LIMIT:
|
||||||
|
// if we meet a limit node between a filter and an enumerate collection,
|
||||||
|
// we abort . . .
|
||||||
|
return true;
|
||||||
|
case EN::SORT:
|
||||||
|
case EN::INDEX_RANGE:
|
||||||
|
break;
|
||||||
|
case EN::ENUMERATE_COLLECTION:{
|
||||||
|
auto node = static_cast<EnumerateCollectionNode*>(en);
|
||||||
|
auto var = node->getVariablesSetHere()[0]; // should only be 1
|
||||||
|
auto map = _ranges->find(var->name); // check if we have any ranges with this var
|
||||||
|
|
||||||
|
if (map != nullptr) {
|
||||||
|
// check the first components of <map> against indexes of <node> . . .
|
||||||
|
std::unordered_set<std::string> attrs;
|
||||||
|
|
||||||
|
bool valid = true; // are all the range infos valid
|
||||||
|
bool equality = true; // are all the range infos equalities
|
||||||
|
|
||||||
if (! _canThrow) {
|
for(auto x: *map) {
|
||||||
if (! valid) { // ranges are not valid . . .
|
valid &= x.second._valid;
|
||||||
|
if (!valid) {
|
||||||
auto newPlan = _plan->clone();
|
break;
|
||||||
try {
|
|
||||||
auto parents = newPlan->getNodeById(node->id())->getParents();
|
|
||||||
for (auto x: parents) {
|
|
||||||
auto noRes = new NoResultsNode(newPlan->nextId());
|
|
||||||
newPlan->registerNode(noRes);
|
|
||||||
newPlan->insertDependency(x, noRes);
|
|
||||||
_opt->addPlan(newPlan, _level, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
delete newPlan;
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
|
equality &= x.second.is1ValueRangeInfo();
|
||||||
|
attrs.insert(x.first);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
std::vector<TRI_index_t*> idxs;
|
|
||||||
std::vector<size_t> prefixes;
|
|
||||||
// {idxs.at(i)->_fields[0]..idxs.at(i)->_fields[prefixes.at(i)]}
|
|
||||||
// is a subset of <attrs>
|
|
||||||
|
|
||||||
node->getIndexesForIndexRangeNode(attrs, idxs, prefixes);
|
if (! _canThrow) {
|
||||||
|
if (! valid) { // ranges are not valid . . .
|
||||||
// make one new plan for every index in <idxs> that replaces the
|
|
||||||
// enumerate collection node with a RangeIndexNode . . .
|
|
||||||
|
|
||||||
for (size_t i = 0; i < idxs.size(); i++) {
|
|
||||||
std::vector<std::vector<RangeInfo>> rangeInfo;
|
|
||||||
rangeInfo.push_back(std::vector<RangeInfo>());
|
|
||||||
|
|
||||||
// ranges must be valid and all comparisons == if hash index or ==
|
auto newPlan = _plan->clone();
|
||||||
// followed by a single <, >, >=, or <= if a skip index in the
|
try {
|
||||||
// order of the fields of the index.
|
auto parents = newPlan->getNodeById(node->id())->getParents();
|
||||||
auto idx = idxs.at(i);
|
for (auto x: parents) {
|
||||||
if (idx->_type == TRI_IDX_TYPE_HASH_INDEX && equality) {
|
auto noRes = new NoResultsNode(newPlan->nextId());
|
||||||
for (size_t j = 0; j < idx->_fields._length; j++) {
|
newPlan->registerNode(noRes);
|
||||||
auto range = map->find(std::string(idx->_fields._buffer[j]));
|
newPlan->insertDependency(x, noRes);
|
||||||
rangeInfo.at(0).push_back(range->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) {
|
|
||||||
size_t j = 0;
|
|
||||||
auto range = map->find(std::string(idx->_fields._buffer[0]));
|
|
||||||
rangeInfo.at(0).push_back(range->second);
|
|
||||||
equality = range->second.is1ValueRangeInfo();
|
|
||||||
while (++j < prefixes.at(i) && equality){
|
|
||||||
range = map->find(std::string(idx->_fields._buffer[j]));
|
|
||||||
rangeInfo.at(0).push_back(range->second);
|
|
||||||
equality = equality && range->second.is1ValueRangeInfo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rangeInfo.at(0).size() != 0) {
|
|
||||||
auto newPlan = _plan->clone();
|
|
||||||
try {
|
|
||||||
ExecutionNode* newNode = new IndexRangeNode(newPlan->nextId(), node->vocbase(),
|
|
||||||
node->collection(), node->outVariable(), idx, rangeInfo);
|
|
||||||
newPlan->registerNode(newNode);
|
|
||||||
newPlan->replaceNode(newPlan->getNodeById(node->id()), newNode);
|
|
||||||
_opt->addPlan(newPlan, _level, true);
|
_opt->addPlan(newPlan, _level, true);
|
||||||
}
|
}
|
||||||
catch (...) {
|
}
|
||||||
delete newPlan;
|
catch (...) {
|
||||||
throw;
|
delete newPlan;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::vector<TRI_index_t*> idxs;
|
||||||
|
std::vector<size_t> prefixes;
|
||||||
|
// {idxs.at(i)->_fields[0]..idxs.at(i)->_fields[prefixes.at(i)]}
|
||||||
|
// is a subset of <attrs>
|
||||||
|
|
||||||
|
node->getIndexesForIndexRangeNode(attrs, idxs, prefixes);
|
||||||
|
|
||||||
|
// make one new plan for every index in <idxs> that replaces the
|
||||||
|
// enumerate collection node with a RangeIndexNode . . .
|
||||||
|
|
||||||
|
for (size_t i = 0; i < idxs.size(); i++) {
|
||||||
|
std::vector<std::vector<RangeInfo>> rangeInfo;
|
||||||
|
rangeInfo.push_back(std::vector<RangeInfo>());
|
||||||
|
|
||||||
|
// ranges must be valid and all comparisons == if hash index or ==
|
||||||
|
// followed by a single <, >, >=, or <= if a skip index in the
|
||||||
|
// order of the fields of the index.
|
||||||
|
auto idx = idxs.at(i);
|
||||||
|
if (idx->_type == TRI_IDX_TYPE_HASH_INDEX && equality) {
|
||||||
|
for (size_t j = 0; j < idx->_fields._length; j++) {
|
||||||
|
auto range = map->find(std::string(idx->_fields._buffer[j]));
|
||||||
|
rangeInfo.at(0).push_back(range->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx->_type == TRI_IDX_TYPE_SKIPLIST_INDEX) {
|
||||||
|
size_t j = 0;
|
||||||
|
auto range = map->find(std::string(idx->_fields._buffer[0]));
|
||||||
|
rangeInfo.at(0).push_back(range->second);
|
||||||
|
equality = range->second.is1ValueRangeInfo();
|
||||||
|
while (++j < prefixes.at(i) && equality){
|
||||||
|
range = map->find(std::string(idx->_fields._buffer[j]));
|
||||||
|
rangeInfo.at(0).push_back(range->second);
|
||||||
|
equality = equality && range->second.is1ValueRangeInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rangeInfo.at(0).size() != 0) {
|
||||||
|
auto newPlan = _plan->clone();
|
||||||
|
try {
|
||||||
|
ExecutionNode* newNode = new IndexRangeNode(newPlan->nextId(), node->vocbase(),
|
||||||
|
node->collection(), node->outVariable(), idx, rangeInfo);
|
||||||
|
newPlan->registerNode(newNode);
|
||||||
|
newPlan->replaceNode(newPlan->getNodeById(node->id()), newNode);
|
||||||
|
_opt->addPlan(newPlan, _level, true);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
delete newPlan;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (en->getType() == triagens::aql::ExecutionNode::LIMIT) {
|
|
||||||
// if we meet a limit node between a filter and an enumerate collection,
|
|
||||||
// we abort . . .
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue