Exemple #1
0
// static
MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) {
    // root->isLogical() is true now.  We care about AND, OR, and NOT. NOR currently scares us.
    if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) {
        // We could have AND of AND of AND.  Make sure we clean up our children before merging
        // them.
        // UNITTEST 11738048
        for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
            (*root->getChildVector())[i] = normalizeTree(root->getChild(i));
        }

        // If any of our children are of the same logical operator that we are, we remove the
        // child's children and append them to ourselves after we examine all children.
        std::vector<MatchExpression*> absorbedChildren;

        for (size_t i = 0; i < root->numChildren();) {
            MatchExpression* child = root->getChild(i);
            if (child->matchType() == root->matchType()) {
                // AND of an AND or OR of an OR.  Absorb child's children into ourself.
                for (size_t j = 0; j < child->numChildren(); ++j) {
                    absorbedChildren.push_back(child->getChild(j));
                }
                // TODO(opt): this is possibly n^2-ish
                root->getChildVector()->erase(root->getChildVector()->begin() + i);
                child->getChildVector()->clear();
                // Note that this only works because we cleared the child's children
                delete child;
                // Don't increment 'i' as the current child 'i' used to be child 'i+1'
            } else {
                ++i;
            }
        }

        root->getChildVector()->insert(
            root->getChildVector()->end(), absorbedChildren.begin(), absorbedChildren.end());

        // AND of 1 thing is the thing, OR of 1 thing is the thing.
        if (1 == root->numChildren()) {
            MatchExpression* ret = root->getChild(0);
            root->getChildVector()->clear();
            delete root;
            return ret;
        }
    } else if (MatchExpression::NOT == root->matchType()) {
        // Normalize the rest of the tree hanging off this NOT node.
        NotMatchExpression* nme = static_cast<NotMatchExpression*>(root);
        MatchExpression* child = nme->releaseChild();
        // normalizeTree(...) takes ownership of 'child', and then
        // transfers ownership of its return value to 'nme'.
        nme->resetChild(normalizeTree(child));
    } else if (MatchExpression::ELEM_MATCH_VALUE == root->matchType()) {
        // Just normalize our children.
        for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
            (*root->getChildVector())[i] = normalizeTree(root->getChild(i));
        }
    }

    return root;
}
Exemple #2
0
    Status CanonicalQuery::init(LiteParsedQuery* lpq,
                                const MatchExpressionParser::WhereCallback& whereCallback,
                                MatchExpression* root) {
        _pq.reset(lpq);

        // Normalize, sort and validate tree.
        root = normalizeTree(root);

        sortTree(root);
        _root.reset(root);
        Status validStatus = isValid(root, *_pq);
        if (!validStatus.isOK()) {
            return validStatus;
        }

        // Validate the projection if there is one.
        if (!_pq->getProj().isEmpty()) {
            ParsedProjection* pp;
            Status projStatus = 
                ParsedProjection::make(_pq->getProj(), _root.get(), &pp, whereCallback);
            if (!projStatus.isOK()) {
                return projStatus;
            }
            _proj.reset(pp);
        }

        return Status::OK();
    }
Status CanonicalQuery::init(LiteParsedQuery* lpq) {
    _pq.reset(lpq);

    // Build a parse tree from the BSONObj in the parsed query.
    StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter());
    if (!swme.isOK()) {
        return swme.getStatus();
    }

    MatchExpression* root = swme.getValue();
    root = normalizeTree(root);
    Status validStatus = isValid(root);
    if (!validStatus.isOK()) {
        return validStatus;
    }

    _root.reset(root);

    // Validate the projection if there is one.
    if (!_pq->getProj().isEmpty()) {
        ParsedProjection* pp;
        Status projStatus = ParsedProjection::make(_pq->getProj(), root, &pp);
        if (!projStatus.isOK()) {
            return projStatus;
        }
        _proj.reset(pp);
    }

    return Status::OK();
}
Exemple #4
0
Status CanonicalQuery::init(LiteParsedQuery* lpq,
                            const ExtensionsCallback& extensionsCallback,
                            MatchExpression* root) {
    _pq.reset(lpq);

    _hasNoopExtensions = extensionsCallback.hasNoopExtensions();
    _isIsolated = LiteParsedQuery::isQueryIsolated(lpq->getFilter());

    // Normalize, sort and validate tree.
    root = normalizeTree(root);

    sortTree(root);
    _root.reset(root);
    Status validStatus = isValid(root, *_pq);
    if (!validStatus.isOK()) {
        return validStatus;
    }

    // Validate the projection if there is one.
    if (!_pq->getProj().isEmpty()) {
        ParsedProjection* pp;
        Status projStatus =
            ParsedProjection::make(_pq->getProj(), _root.get(), &pp, extensionsCallback);
        if (!projStatus.isOK()) {
            return projStatus;
        }
        _proj.reset(pp);
    }

    if (_proj && _proj->wantSortKey() && _pq->getSort().isEmpty()) {
        return Status(ErrorCodes::BadValue, "cannot use sortKey $meta projection without a sort");
    }

    return Status::OK();
}
    Status CanonicalQuery::init(LiteParsedQuery* lpq) {
        _pq.reset(lpq);

        // Build a parse tree from the BSONObj in the parsed query.
        StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter());
        if (!swme.isOK()) { return swme.getStatus(); }

        MatchExpression* root = swme.getValue();
        root = normalizeTree(root);
        Status validStatus = isValid(root);
        if (!validStatus.isOK()) {
            return validStatus;
        }

        _root.reset(root);

        if (!_pq->getProj().isEmpty()) {
            LiteProjection* liteProj = NULL;
            Status liteProjStatus = LiteProjection::make(_pq->getFilter(), _pq->getProj(), &liteProj);
            if (!liteProjStatus.isOK()) {
                return liteProjStatus;
            }
            _liteProj.reset(liteProj);
        }

        return Status::OK();
    }
    // static
    MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) {
        // root->isLogical() is true now.  We care about AND and OR.  Negations currently scare us.
        if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) {
            // We could have AND of AND of AND.  Make sure we clean up our children before merging
            // them.
            // UNITTEST 11738048
            for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
                (*root->getChildVector())[i] = normalizeTree(root->getChild(i));
            }

            // If any of our children are of the same logical operator that we are, we remove the
            // child's children and append them to ourselves after we examine all children.
            vector<MatchExpression*> absorbedChildren;

            for (size_t i = 0; i < root->numChildren();) {
                MatchExpression* child = root->getChild(i);
                if (child->matchType() == root->matchType()) {
                    // AND of an AND or OR of an OR.  Absorb child's children into ourself.
                    for (size_t j = 0; j < child->numChildren(); ++j) {
                        absorbedChildren.push_back(child->getChild(j));
                    }
                    // TODO(opt): this is possibly n^2-ish
                    root->getChildVector()->erase(root->getChildVector()->begin() + i);
                    child->getChildVector()->clear();
                    // Note that this only works because we cleared the child's children
                    delete child;
                    // Don't increment 'i' as the current child 'i' used to be child 'i+1'
                }
                else {
                    ++i;
                }
            }

            root->getChildVector()->insert(root->getChildVector()->end(),
                                           absorbedChildren.begin(),
                                           absorbedChildren.end());

            // AND of 1 thing is the thing, OR of 1 thing is the thing.
            if (1 == root->numChildren()) {
                MatchExpression* ret = root->getChild(0);
                root->getChildVector()->clear();
                delete root;
                return ret;
            }
        }

        return root;
    }
Exemple #7
0
    // static
    // XXX TODO: This does not belong here at all.
    MatchExpression* CanonicalQuery::logicalRewrite(MatchExpression* tree) {
        // Only thing we do is pull an OR up at the root.
        if (MatchExpression::AND != tree->matchType()) {
            return tree;
        }

        // We want to bail out ASAP if we have nothing to do here.
        size_t numOrs = 0;
        for (size_t i = 0; i < tree->numChildren(); ++i) {
            if (MatchExpression::OR == tree->getChild(i)->matchType()) {
                ++numOrs;
            }
        }

        // Only do this for one OR right now.
        if (1 != numOrs) {
            return tree;
        }

        // Detach the OR from the root.
        invariant(NULL != tree->getChildVector());
        std::vector<MatchExpression*>& rootChildren = *tree->getChildVector();
        MatchExpression* orChild = NULL;
        for (size_t i = 0; i < rootChildren.size(); ++i) {
            if (MatchExpression::OR == rootChildren[i]->matchType()) {
                orChild = rootChildren[i];
                rootChildren.erase(rootChildren.begin() + i);
                break;
            }
        }

        // AND the existing root with each or child.
        invariant(NULL != orChild);
        invariant(NULL != orChild->getChildVector());
        std::vector<MatchExpression*>& orChildren = *orChild->getChildVector();
        for (size_t i = 0; i < orChildren.size(); ++i) {
            AndMatchExpression* ama = new AndMatchExpression();
            ama->add(orChildren[i]);
            ama->add(tree->shallowClone());
            orChildren[i] = ama;
        }
        delete tree;

        // Clean up any consequences from this tomfoolery.
        return normalizeTree(orChild);
    }
//void AssociationTree::solve(std::vector<std::pair<unsigned int, unsigned int> > & _pairs, std::vector<unsigned int> &  _unassoc)
void AssociationTree::solve(std::vector<std::pair<unsigned int, unsigned int> > & _pairs, std::vector<bool> & _associated_mask)
{
    std::list<AssociationNode*>::iterator best_node;
    bool rootReached = false;
    AssociationNode *anPtr;
    
    //grows tree exploring all likely hypothesis
    growTree();
    
    //computes tree probs
    computeTree();
    
    //normalizes tree probs
    normalizeTree();

    //if terminus_node_list_ is empty exit withou pairing
    if ( terminus_node_list_.empty() ) return;
    
    //choose best node based on best tree probability
    chooseBestTerminus(best_node);
    
    //resize _associated_mask and resets it to false
    _associated_mask.resize(nd_,false);

    //set pairs
    anPtr = *best_node; //init pointer
    int ii=0;
    while( ! anPtr->isRoot() ) //set pairs
    {
//         if ( anPtr->getTargetIndex() == nt_) //detection with void target -> unassociated detection
//         {
//             _unassoc.push_back(anPtr->getDetectionIndex());
//         }
//         else
//         {
//             _pairs.push_back( std::pair<unsigned int, unsigned int>(anPtr->getDetectionIndex(), anPtr->getTargetIndex()) );
//         }
        if ( anPtr->getTargetIndex() < nt_ ) //association pair
        {
            _associated_mask.at(anPtr->getDetectionIndex()) = true; 
            _pairs.push_back( std::pair<unsigned int, unsigned int>(anPtr->getDetectionIndex(), anPtr->getTargetIndex()) );
        }
        anPtr = anPtr->upNodePtr();
    }        
}
Exemple #9
0
    Status CanonicalQuery::init(LiteParsedQuery* lpq) {
        _pq.reset(lpq);

        // Build a parse tree from the BSONObj in the parsed query.
        StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter());
        if (!swme.isOK()) { return swme.getStatus(); }

        MatchExpression* root = swme.getValue();
        normalizeTree(root);
        _root.reset(root);

        if (!_pq->getProj().isEmpty()) {
            ParsedProjection* proj;
            Status projStatus = ProjectionParser::parseFindSyntax(_pq->getProj(), &proj);
            if (!projStatus.isOK()) {
                return projStatus;
            }
            _proj.reset(proj);
        }

        return Status::OK();
    }
Exemple #10
0
Status CanonicalQuery::init(std::unique_ptr<QueryRequest> qr,
                            const ExtensionsCallback& extensionsCallback,
                            MatchExpression* root,
                            std::unique_ptr<CollatorInterface> collator) {
    _qr = std::move(qr);
    _collator = std::move(collator);

    _hasNoopExtensions = extensionsCallback.hasNoopExtensions();
    _isIsolated = QueryRequest::isQueryIsolated(_qr->getFilter());

    // Normalize, sort and validate tree.
    root = normalizeTree(root);

    sortTree(root);
    _root.reset(root);
    Status validStatus = isValid(root, *_qr);
    if (!validStatus.isOK()) {
        return validStatus;
    }

    // Validate the projection if there is one.
    if (!_qr->getProj().isEmpty()) {
        ParsedProjection* pp;
        Status projStatus =
            ParsedProjection::make(_qr->getProj(), _root.get(), &pp, extensionsCallback);
        if (!projStatus.isOK()) {
            return projStatus;
        }
        _proj.reset(pp);
    }

    if (_proj && _proj->wantSortKey() && _qr->getSort().isEmpty()) {
        return Status(ErrorCodes::BadValue, "cannot use sortKey $meta projection without a sort");
    }

    return Status::OK();
}
Exemple #11
0
 Status CanonicalQuery::normalize(MatchExpression* root) {
     _root.reset(normalizeTree(root));
     sortTree(_root.get());
     return isValid(_root.get());
 }
Exemple #12
0
// static
MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) {
    if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) {
        // We could have AND of AND of AND.  Make sure we clean up our children before merging them.
        for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
            (*root->getChildVector())[i] = normalizeTree(root->getChild(i));
        }

        // If any of our children are of the same logical operator that we are, we remove the
        // child's children and append them to ourselves after we examine all children.
        std::vector<MatchExpression*> absorbedChildren;

        for (size_t i = 0; i < root->numChildren();) {
            MatchExpression* child = root->getChild(i);
            if (child->matchType() == root->matchType()) {
                // AND of an AND or OR of an OR.  Absorb child's children into ourself.
                for (size_t j = 0; j < child->numChildren(); ++j) {
                    absorbedChildren.push_back(child->getChild(j));
                }
                // TODO(opt): this is possibly n^2-ish
                root->getChildVector()->erase(root->getChildVector()->begin() + i);
                child->getChildVector()->clear();
                // Note that this only works because we cleared the child's children
                delete child;
                // Don't increment 'i' as the current child 'i' used to be child 'i+1'
            } else {
                ++i;
            }
        }

        root->getChildVector()->insert(
            root->getChildVector()->end(), absorbedChildren.begin(), absorbedChildren.end());

        // AND of 1 thing is the thing, OR of 1 thing is the thing.
        if (1 == root->numChildren()) {
            MatchExpression* ret = root->getChild(0);
            root->getChildVector()->clear();
            delete root;
            return ret;
        }
    } else if (MatchExpression::NOR == root->matchType()) {
        // First clean up children.
        for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
            (*root->getChildVector())[i] = normalizeTree(root->getChild(i));
        }

        // NOR of one thing is NOT of the thing.
        if (1 == root->numChildren()) {
            // Detach the child and assume ownership.
            std::unique_ptr<MatchExpression> child(root->getChild(0));
            root->getChildVector()->clear();

            // Delete the root when this goes out of scope.
            std::unique_ptr<NorMatchExpression> ownedRoot(static_cast<NorMatchExpression*>(root));

            // Make a NOT to be the new root and transfer ownership of the child to it.
            auto newRoot = stdx::make_unique<NotMatchExpression>();
            newRoot->init(child.release()).transitional_ignore();

            return newRoot.release();
        }
    } else if (MatchExpression::NOT == root->matchType()) {
        // Normalize the rest of the tree hanging off this NOT node.
        NotMatchExpression* nme = static_cast<NotMatchExpression*>(root);
        MatchExpression* child = nme->releaseChild();
        // normalizeTree(...) takes ownership of 'child', and then
        // transfers ownership of its return value to 'nme'.
        nme->resetChild(normalizeTree(child));
    } else if (MatchExpression::ELEM_MATCH_OBJECT == root->matchType()) {
        // Normalize the rest of the tree hanging off this ELEM_MATCH_OBJECT node.
        ElemMatchObjectMatchExpression* emome = static_cast<ElemMatchObjectMatchExpression*>(root);
        auto child = emome->releaseChild();
        // normalizeTree(...) takes ownership of 'child', and then
        // transfers ownership of its return value to 'emome'.
        emome->resetChild(std::unique_ptr<MatchExpression>(normalizeTree(child.release())));
    } else if (MatchExpression::ELEM_MATCH_VALUE == root->matchType()) {
        // Just normalize our children.
        for (size_t i = 0; i < root->getChildVector()->size(); ++i) {
            (*root->getChildVector())[i] = normalizeTree(root->getChild(i));
        }
    } else if (MatchExpression::MATCH_IN == root->matchType()) {
        std::unique_ptr<InMatchExpression> in(static_cast<InMatchExpression*>(root));

        // IN of 1 regex is the regex.
        if (in->getRegexes().size() == 1 && in->getEqualities().empty()) {
            RegexMatchExpression* childRe = in->getRegexes().begin()->get();
            invariant(!childRe->getTag());

            // Create a new RegexMatchExpression, because 'childRe' does not have a path.
            auto re = stdx::make_unique<RegexMatchExpression>();
            re->init(in->path(), childRe->getString(), childRe->getFlags()).transitional_ignore();
            if (in->getTag()) {
                re->setTag(in->getTag()->clone());
            }
            return normalizeTree(re.release());
        }

        // IN of 1 equality is the equality.
        if (in->getEqualities().size() == 1 && in->getRegexes().empty()) {
            auto eq = stdx::make_unique<EqualityMatchExpression>();
            eq->init(in->path(), *(in->getEqualities().begin())).transitional_ignore();
            eq->setCollator(in->getCollator());
            if (in->getTag()) {
                eq->setTag(in->getTag()->clone());
            }
            return eq.release();
        }

        return in.release();
    }

    return root;
}