diff --git a/CHANGELOG b/CHANGELOG index 0ccc4eaf56..dba72ef9bc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ v3.4.6 (2016-05-21) ------------------- +* fixed "collection not found" exception during setup of 3-way smart join queries in the + cluster + * fixed an edge case of handling `null` values in the AQL function `MIN` for input sequences that started with a `null` value. In this case, `null` was always returned as the minimum value even though other non-null values may have followed, and `MIN` was supposed diff --git a/arangod/Aql/EngineInfoContainerDBServer.cpp b/arangod/Aql/EngineInfoContainerDBServer.cpp index 935cd0fa37..b00715dfe1 100644 --- a/arangod/Aql/EngineInfoContainerDBServer.cpp +++ b/arangod/Aql/EngineInfoContainerDBServer.cpp @@ -266,6 +266,22 @@ void EngineInfoContainerDBServer::EngineInfo::serializeSnippet( infoBuilder.add(VPackValue(arangodb::basics::StringUtils::itoa(_idOfRemoteNode) + ":" + id)); TRI_ASSERT(!_nodes.empty()); + + // build up a map of prototypes, e.g. c1 => c2, c2 => c3, c3 => c4, + // so we can determine a common prototype ancestor in case we have 3- or 4-way joins + std::unordered_map prototypes; + for (auto enIt = _nodes.rbegin(), end = _nodes.rend(); enIt != end; ++enIt) { + auto const nodeType = (*enIt)->getType(); + if (nodeType == ExecutionNode::INDEX || nodeType == ExecutionNode::ENUMERATE_COLLECTION) { + auto x = dynamic_cast(*enIt); + auto const* prototype = x->prototypeCollection(); + if (prototype == nullptr) { + continue; + } + prototypes[x->collection()] = prototype; + } + } + // copy the relevant fragment of the plan for each shard // Note that in these parts of the query there are no SubqueryNodes, // since they are all on the coordinator! @@ -292,6 +308,15 @@ void EngineInfoContainerDBServer::EngineInfo::serializeSnippet( if (nodeType == ExecutionNode::INDEX || nodeType == ExecutionNode::ENUMERATE_COLLECTION) { auto x = dynamic_cast(clone); auto const* prototype = x->prototypeCollection(); + // find prototypes of prototypes + while (prototype != nullptr) { + auto it = prototypes.find(prototype); + if (it == prototypes.end()) { + break; + } + prototype = (*it).second; + } + if (prototype != nullptr) { auto s1 = prototype->shardIds(); auto s2 = x->collection()->shardIds();