Example #1
0
    // static
    void IndexBoundsBuilder::translate(const MatchExpression* expr, int direction,
                                       OrderedIntervalList* oilOut, bool* exactOut) {
        Interval interval;
        bool exact = false;

        if (expr->isLeaf()) {
            if (MatchExpression::EQ == expr->matchType()) {
                const EqualityMatchExpression* node = static_cast<const EqualityMatchExpression*>(expr);
                // We have to copy the data out of the parse tree and stuff it into the index bounds.
                // BSONValue will be useful here.
                BSONObj dataObj = objFromElement(node->getData());

                if (dataObj.couldBeArray()) {
                    // XXX: build better bounds
                    warning() << "building lazy bounds for " << expr->toString() << endl;
                    interval = allValues();
                    exact = false;
                }
                else {
                    verify(dataObj.isOwned());
                    interval = makePointInterval(dataObj);
                    exact = true;
                }
            }
            else if (MatchExpression::LTE == expr->matchType()) {
                const LTEMatchExpression* node = static_cast<const LTEMatchExpression*>(expr);
                BSONObjBuilder bob;
                bob.appendMinKey("");
                bob.append(node->getData());
                BSONObj dataObj = bob.obj();
                verify(dataObj.isOwned());
                interval = makeRangeInterval(dataObj, true, true);
                exact = true;
            }
            else if (MatchExpression::LT == expr->matchType()) {
                const LTMatchExpression* node = static_cast<const LTMatchExpression*>(expr);
                BSONObjBuilder bob;
                bob.appendMinKey("");
                bob.append(node->getData());
                BSONObj dataObj = bob.obj();
                verify(dataObj.isOwned());
                interval = makeRangeInterval(dataObj, true, false);
                exact = true;
            }
            else if (MatchExpression::GT == expr->matchType()) {
                const GTMatchExpression* node = static_cast<const GTMatchExpression*>(expr);
                BSONObjBuilder bob;
                bob.append(node->getData());
                bob.appendMaxKey("");
                BSONObj dataObj = bob.obj();
                verify(dataObj.isOwned());
                interval = makeRangeInterval(dataObj, false, true);
                exact = true;
            }
            else if (MatchExpression::GTE == expr->matchType()) {
                const GTEMatchExpression* node = static_cast<const GTEMatchExpression*>(expr);
                BSONObjBuilder bob;
                bob.append(node->getData());
                bob.appendMaxKey("");
                BSONObj dataObj = bob.obj();
                verify(dataObj.isOwned());
                interval = makeRangeInterval(dataObj, true, true);
                exact = true;
            }
            else {
                // XXX: build better bounds
                warning() << "building lazy bounds for " << expr->toString() << endl;
                interval = allValues();
                exact = false;
            }
        }
        else {
            // XXX: build better bounds
            verify(expr->isArray());
            warning() << "building lazy bounds for " << expr->toString() << endl;
            interval = allValues();
            exact = false;
        }

        if (-1 == direction) {
            reverseInterval(&interval);
        }

        oilOut->intervals.push_back(interval);
        *exactOut = exact;
    }
Example #2
0
Status ProjectionExec::transform(WorkingSetMember* member) const {
    if (_hasReturnKey) {
        BSONObj keyObj;

        if (member->hasComputed(WSM_INDEX_KEY)) {
            const IndexKeyComputedData* key =
                static_cast<const IndexKeyComputedData*>(member->getComputed(WSM_INDEX_KEY));
            keyObj = key->getKey();
        }

        member->obj = Snapshotted<BSONObj>(SnapshotId(), keyObj.getOwned());
        member->keyData.clear();
        member->loc = RecordId();
        member->transitionToOwnedObj();
        return Status::OK();
    }

    BSONObjBuilder bob;
    if (member->hasObj()) {
        MatchDetails matchDetails;

        // If it's a positional projection we need a MatchDetails.
        if (transformRequiresDetails()) {
            matchDetails.requestElemMatchKey();
            verify(NULL != _queryExpression);
            verify(_queryExpression->matchesBSON(member->obj.value(), &matchDetails));
        }

        Status projStatus = transform(member->obj.value(), &bob, &matchDetails);
        if (!projStatus.isOK()) {
            return projStatus;
        }
    } else {
        verify(!requiresDocument());
        // Go field by field.
        if (_includeID) {
            BSONElement elt;
            // Sometimes the _id field doesn't exist...
            if (member->getFieldDotted("_id", &elt) && !elt.eoo()) {
                bob.appendAs(elt, "_id");
            }
        }

        BSONObjIterator it(_source);
        while (it.more()) {
            BSONElement specElt = it.next();
            if (mongoutils::str::equals("_id", specElt.fieldName())) {
                continue;
            }

            BSONElement keyElt;
            // We can project a field that doesn't exist.  We just ignore it.
            if (member->getFieldDotted(specElt.fieldName(), &keyElt) && !keyElt.eoo()) {
                bob.appendAs(keyElt, specElt.fieldName());
            }
        }
    }

    for (MetaMap::const_iterator it = _meta.begin(); it != _meta.end(); ++it) {
        if (META_GEONEAR_DIST == it->second) {
            if (member->hasComputed(WSM_COMPUTED_GEO_DISTANCE)) {
                const GeoDistanceComputedData* dist = static_cast<const GeoDistanceComputedData*>(
                    member->getComputed(WSM_COMPUTED_GEO_DISTANCE));
                bob.append(it->first, dist->getDist());
            } else {
                return Status(ErrorCodes::InternalError,
                              "near loc dist requested but no data available");
            }
        } else if (META_GEONEAR_POINT == it->second) {
            if (member->hasComputed(WSM_GEO_NEAR_POINT)) {
                const GeoNearPointComputedData* point =
                    static_cast<const GeoNearPointComputedData*>(
                        member->getComputed(WSM_GEO_NEAR_POINT));
                BSONObj ptObj = point->getPoint();
                if (ptObj.couldBeArray()) {
                    bob.appendArray(it->first, ptObj);
                } else {
                    bob.append(it->first, ptObj);
                }
            } else {
                return Status(ErrorCodes::InternalError,
                              "near loc proj requested but no data available");
            }
        } else if (META_TEXT_SCORE == it->second) {
            if (member->hasComputed(WSM_COMPUTED_TEXT_SCORE)) {
                const TextScoreComputedData* score = static_cast<const TextScoreComputedData*>(
                    member->getComputed(WSM_COMPUTED_TEXT_SCORE));
                bob.append(it->first, score->getScore());
            } else {
                bob.append(it->first, 0.0);
            }
        } else if (META_RECORDID == it->second) {
            bob.append(it->first, static_cast<long long>(member->loc.repr()));
        }
    }

    BSONObj newObj = bob.obj();
    member->obj = Snapshotted<BSONObj>(SnapshotId(), newObj);
    member->keyData.clear();
    member->loc = RecordId();
    member->transitionToOwnedObj();

    return Status::OK();
}
Example #3
0
Status ProjectionExec::transform(WorkingSetMember* member) const {
    if (_hasReturnKey) {
        BSONObjBuilder builder;

        if (member->hasComputed(WSM_INDEX_KEY)) {
            const IndexKeyComputedData* key =
                static_cast<const IndexKeyComputedData*>(member->getComputed(WSM_INDEX_KEY));
            builder.appendElements(key->getKey());
        }

        // Must be possible to do both returnKey meta-projection and sortKey meta-projection so that
        // mongos can support returnKey.
        for (auto fieldName : _sortKeyMetaFields) {
            auto sortKeyMetaStatus = addSortKeyMetaProj(fieldName, *member, &builder);
            if (!sortKeyMetaStatus.isOK()) {
                return sortKeyMetaStatus;
            }
        }

        member->obj = Snapshotted<BSONObj>(SnapshotId(), builder.obj());
        member->keyData.clear();
        member->recordId = RecordId();
        member->transitionToOwnedObj();
        return Status::OK();
    }

    BSONObjBuilder bob;
    if (member->hasObj()) {
        MatchDetails matchDetails;

        // If it's a positional projection we need a MatchDetails.
        if (transformRequiresDetails()) {
            matchDetails.requestElemMatchKey();
            verify(NULL != _queryExpression);
            verify(_queryExpression->matchesBSON(member->obj.value(), &matchDetails));
        }

        Status projStatus = transform(member->obj.value(), &bob, &matchDetails);
        if (!projStatus.isOK()) {
            return projStatus;
        }
    } else {
        invariant(!_include);
        // Go field by field.
        if (_includeID) {
            BSONElement elt;
            // Sometimes the _id field doesn't exist...
            if (member->getFieldDotted("_id", &elt) && !elt.eoo()) {
                bob.appendAs(elt, "_id");
            }
        }

        mmb::Document projectedDoc;

        for (auto&& specElt : _source) {
            if (mongoutils::str::equals("_id", specElt.fieldName())) {
                continue;
            }

            // $meta sortKey is the only meta-projection which is allowed to operate on index keys
            // rather than the full document.
            auto metaIt = _meta.find(specElt.fieldName());
            if (metaIt != _meta.end()) {
                invariant(metaIt->second == META_SORT_KEY);
                continue;
            }

            // $meta sortKey is also the only element with an Object value in the projection spec
            // that can operate on index keys rather than the full document.
            invariant(BSONType::Object != specElt.type());

            BSONElement keyElt;
            // We can project a field that doesn't exist.  We just ignore it.
            if (member->getFieldDotted(specElt.fieldName(), &keyElt) && !keyElt.eoo()) {
                FieldRef projectedFieldPath{specElt.fieldNameStringData()};
                auto setElementStatus =
                    pathsupport::setElementAtPath(projectedFieldPath, keyElt, &projectedDoc);
                if (!setElementStatus.isOK()) {
                    return setElementStatus;
                }
            }
        }

        bob.appendElements(projectedDoc.getObject());
    }

    for (MetaMap::const_iterator it = _meta.begin(); it != _meta.end(); ++it) {
        if (META_GEONEAR_DIST == it->second) {
            if (member->hasComputed(WSM_COMPUTED_GEO_DISTANCE)) {
                const GeoDistanceComputedData* dist = static_cast<const GeoDistanceComputedData*>(
                    member->getComputed(WSM_COMPUTED_GEO_DISTANCE));
                bob.append(it->first, dist->getDist());
            } else {
                return Status(ErrorCodes::InternalError,
                              "near loc dist requested but no data available");
            }
        } else if (META_GEONEAR_POINT == it->second) {
            if (member->hasComputed(WSM_GEO_NEAR_POINT)) {
                const GeoNearPointComputedData* point =
                    static_cast<const GeoNearPointComputedData*>(
                        member->getComputed(WSM_GEO_NEAR_POINT));
                BSONObj ptObj = point->getPoint();
                if (ptObj.couldBeArray()) {
                    bob.appendArray(it->first, ptObj);
                } else {
                    bob.append(it->first, ptObj);
                }
            } else {
                return Status(ErrorCodes::InternalError,
                              "near loc proj requested but no data available");
            }
        } else if (META_TEXT_SCORE == it->second) {
            if (member->hasComputed(WSM_COMPUTED_TEXT_SCORE)) {
                const TextScoreComputedData* score = static_cast<const TextScoreComputedData*>(
                    member->getComputed(WSM_COMPUTED_TEXT_SCORE));
                bob.append(it->first, score->getScore());
            } else {
                bob.append(it->first, 0.0);
            }
        } else if (META_SORT_KEY == it->second) {
            auto sortKeyMetaStatus = addSortKeyMetaProj(it->first, *member, &bob);
            if (!sortKeyMetaStatus.isOK()) {
                return sortKeyMetaStatus;
            }
        } else if (META_RECORDID == it->second) {
            bob.append(it->first, static_cast<long long>(member->recordId.repr()));
        }
    }

    BSONObj newObj = bob.obj();
    member->obj = Snapshotted<BSONObj>(SnapshotId(), newObj);
    member->keyData.clear();
    member->recordId = RecordId();
    member->transitionToOwnedObj();

    return Status::OK();
}