Ejemplo n.º 1
0
void BSONElementIterator::ArrayIterationState::reset(const FieldRef& ref, int start) {
    restOfPath = ref.dottedField(start).toString();
    hasMore = restOfPath.size() > 0;
    if (hasMore) {
        nextPieceOfPath = ref.getPart(start);
        nextPieceOfPathIsNumber = isAllDigits(nextPieceOfPath);
    } else {
        nextPieceOfPathIsNumber = false;
    }
}
Ejemplo n.º 2
0
/**
 * Helper function to check if path conflicts are all prefixes.
 */
static Status checkPathIsPrefixOf(const FieldRef& path, const FieldRefSet& conflictPaths) {
    for (FieldRefSet::const_iterator it = conflictPaths.begin(); it != conflictPaths.end(); ++it) {
        const FieldRef* conflictingPath = *it;
        // Conflicts are always prefixes (or equal to) the path, or vice versa
        if (path.numParts() > conflictingPath->numParts()) {
            string errMsg = stream() << "field at '" << conflictingPath->dottedField()
                                     << "' must be exactly specified, field at sub-path '"
                                     << path.dottedField() << "'found";
            return Status(ErrorCodes::NotExactValueField, errMsg);
        }
    }

    return Status::OK();
}
Ejemplo n.º 3
0
Status isUpdatable(const FieldRef& field) {
    const size_t numParts = field.numParts();

    if (numParts == 0) {
        return Status(ErrorCodes::EmptyFieldName, "An empty update path is not valid.");
    }

    for (size_t i = 0; i != numParts; ++i) {
        const StringData part = field.getPart(i);

        if (part.empty()) {
            return Status(ErrorCodes::EmptyFieldName,
                          mongolutils::str::stream()
                              << "The update path '" << field.dottedField()
                              << "' contains an empty field name, which is not allowed.");
        }
    }

    return Status::OK();
}
Ejemplo n.º 4
0
    bool TypeMatchExpression::_matches( const StringData& path,
                                        const MatchableDocument* doc,
                                        MatchDetails* details ) const {

        FieldRef fieldRef;
        fieldRef.parse( path );

        bool traversedArray = false;
        size_t idxPath = 0;
        BSONElement e = doc->getFieldDottedOrArray( fieldRef, &idxPath, &traversedArray );

        string rest = fieldRef.dottedField( idxPath + 1 );

        if ( e.type() != Array ) {
            return matchesSingleElement( e );
        }

        BSONObjIterator i( e.Obj() );
        while ( i.more() ) {
            BSONElement x = i.next();
            bool found = false;
            if ( rest.size() == 0 ) {
                found = matchesSingleElement( x );
            }
            else if ( x.isABSONObj() ) {
                BSONMatchableDocument doc( x.Obj() );
                found = _matches( rest, &doc, details );
            }

            if ( found ) {
                if ( details && details->needRecord() ) {
                    // this block doesn't have to be inside the _allHaveToMatch handler
                    // but this matches the old semantics
                    details->setElemMatchKey( x.fieldName() );
                }
                return true;
            }
        }

        return false;
    }
Ejemplo n.º 5
0
/**
 * Helper function to check if the current equality match paths conflict with a new path.
 */
static Status checkEqualityConflicts(const EqualityMatches& equalities, const FieldRef& path) {
    int parentPathPart = -1;
    const BSONElement& parentEl = findParentEqualityElement(equalities, path, &parentPathPart);

    if (parentEl.eoo())
        return Status::OK();

    string errMsg = "cannot infer query fields to set, ";

    StringData pathStr = path.dottedField();
    StringData prefixStr = path.dottedSubstring(0, parentPathPart);
    StringData suffixStr = path.dottedSubstring(parentPathPart, path.numParts());

    if (suffixStr.size() != 0)
        errMsg += stream() << "both paths '" << pathStr << "' and '" << prefixStr
                           << "' are matched";
    else
        errMsg += stream() << "path '" << pathStr << "' is matched twice";

    return Status(ErrorCodes::NotSingleValueField, errMsg);
}
Ejemplo n.º 6
0
Status findLongestPrefix(const FieldRef& prefix,
                         mutablebson::Element root,
                         size_t* idxFound,
                         mutablebson::Element* elemFound) {
    // If root is empty or the prefix is so, there's no point in looking for a prefix.
    const size_t prefixSize = prefix.numParts();
    if (!root.hasChildren() || prefixSize == 0) {
        return Status(ErrorCodes::NonExistentPath, "either the document or the path are empty");
    }

    // Loop through prefix's parts. At each iteration, check that the part ('curr') exists
    // in 'root' and that the type of the previous part ('prev') allows for children.
    mutablebson::Element curr = root;
    mutablebson::Element prev = root;
    size_t i = 0;
    size_t numericPart = 0;
    bool viable = true;
    for (; i < prefixSize; i++) {
        // If prefix wants to reach 'curr' by applying a non-numeric index to an array
        // 'prev', or if 'curr' wants to traverse a leaf 'prev', then we'd be in a
        // non-viable path (see definition on the header file).
        StringData prefixPart = prefix.getPart(i);
        prev = curr;
        switch (curr.getType()) {
            case Object:
                curr = prev[prefixPart];
                break;

            case Array:
                if (!isNumeric(prefixPart, &numericPart)) {
                    viable = false;
                } else {
                    curr = prev[numericPart];
                }
                break;

            default:
                viable = false;
        }

        // If we couldn't find the next field part of the prefix in the document or if the
        // field part we're in constitutes a non-viable path, we can stop looking.
        if (!curr.ok() || !viable) {
            break;
        }
    }

    // We broke out of the loop because one of four things happened. (a) 'prefix' and
    // 'root' have nothing in common, (b) 'prefix' is not viable in 'root', (c) not all the
    // parts in 'prefix' exist in 'root', or (d) all parts do. In each case, we need to
    // figure out what index and Element pointer to return.
    if (i == 0) {
        return Status(ErrorCodes::NonExistentPath, "cannot find path in the document");
    } else if (!viable) {
        *idxFound = i - 1;
        *elemFound = prev;
        return Status(ErrorCodes::PathNotViable,
                      mongolutils::str::stream() << "cannot use the part (" << prefix.getPart(i - 1)
                                                << " of " << prefix.dottedField()
                                                << ") to traverse the element ({" << curr.toString()
                                                << "})");
    } else if (curr.ok()) {
        *idxFound = i - 1;
        *elemFound = curr;
        return Status::OK();
    } else {
        *idxFound = i - 1;
        *elemFound = prev;
        return Status::OK();
    }
}
Ejemplo n.º 7
0
bool LeafMatchExpression::_matches( const FieldRef& fieldRef,
                                    const MatchableDocument* doc,
                                    MatchDetails* details ) const {

    bool traversedArray = false;
    size_t idxPath = 0;
    BSONElement e = doc->getFieldDottedOrArray( fieldRef, &idxPath, &traversedArray );

    if ( e.type() != Array || traversedArray ) {
        return matchesSingleElement( e );
    }

    string rest = fieldRef.dottedField( idxPath + 1 );
    StringData next;
    bool nextIsNumber = false;
    if ( rest.size() > 0 ) {
        next = fieldRef.getPart( idxPath + 1 );
        nextIsNumber = isAllDigits( next );
    }

    BSONObjIterator i( e.Obj() );
    while ( i.more() ) {
        BSONElement x = i.next();

        bool found = false;
        if ( rest.size() == 0 ) {
            found = matchesSingleElement( x );
        }
        else if ( x.type() == Object ) {
            FieldRef myFieldRef;
            myFieldRef.parse( rest );
            BSONMatchableDocument myDoc( x.Obj() );
            found = _matches( myFieldRef, &myDoc, NULL );
        }


        if ( !found && nextIsNumber && next == x.fieldName() ) {
            string reallyNext = fieldRef.dottedField( idxPath + 2 );
            if ( reallyNext.size() == 0 ) {
                found = matchesSingleElement( x );
            }
            else if ( x.isABSONObj() ) {
                // TODO: this is slow
                FieldRef myFieldRef;
                myFieldRef.parse( "x." + reallyNext );
                BSONObjBuilder b;
                b.appendAs( x, "x" );
                BSONObj temp = b.obj();
                BSONMatchableDocument myDoc( temp );
                found = _matches( myFieldRef, &myDoc, NULL );
            }
        }

        if ( found ) {
            if ( !_allHaveToMatch ) {
                if ( details && details->needRecord() ) {
                    // this block doesn't have to be inside the _allHaveToMatch handler
                    // but this matches the old semantics
                    details->setElemMatchKey( x.fieldName() );
                }
                return true;
            }
        }
        else if ( _allHaveToMatch ) {
            return false;
        }
    }

    if ( rest.size() > 0 ) {
        // we're supposed to have gone further down
        return false;
    }

    return matchesSingleElement( e );
}