Beispiel #1
0
    TEST(BitAnd, 32and32) {
        const SafeNum val1(static_cast<int>(0xE0F1U));
        const SafeNum val2(static_cast<int>(0xDF01U));
        const SafeNum expected(static_cast<int>(0xC001U));
        const SafeNum result = val1 & val2;
        ASSERT_EQUALS(mongo::NumberInt, result.type());

        ASSERT_TRUE(expected.isIdentical(result));
    }

    TEST(BitAnd, 64and64) {
        const SafeNum val1(static_cast<long long>(0xE0F1E0F1E0F1ULL));
        const SafeNum val2(static_cast<long long>(0xDF01DF01DF01ULL));
        const SafeNum expected(static_cast<long long>(0xC001C001C001ULL));
        const SafeNum result = val1 & val2;
        ASSERT_EQUALS(mongo::NumberLong, result.type());
        ASSERT_TRUE(expected.isIdentical(result));
    }

    TEST(BitAnd, MixedSize) {
        const SafeNum val_small(static_cast<int>(0xE0F1U));
        const SafeNum val_big(static_cast<long long>(0xDF01U));
        const SafeNum expected(static_cast<long long>(0xC001U));
        const SafeNum result_s_b = val_small & val_big;
        const SafeNum result_b_s = val_big & val_small;

        ASSERT_EQUALS(mongo::NumberLong, result_s_b.type());
        ASSERT_TRUE(expected.isIdentical(result_s_b));

        ASSERT_EQUALS(mongo::NumberLong, result_b_s.type());
        ASSERT_TRUE(expected.isIdentical(result_b_s));
    Status ModifierInc::prepare(mutablebson::Element root,
                                const StringData& matchedField,
                                ExecInfo* execInfo) {

        _preparedState.reset(new PreparedState(root.getDocument()));

        // If we have a $-positional field, it is time to bind it to an actual field part.
        if (_posDollar) {
            if (matchedField.empty()) {
                return Status(ErrorCodes::BadValue, "matched field not provided");
            }
            _preparedState->boundDollar = matchedField.toString();
            _fieldRef.setPart(_posDollar, _preparedState->boundDollar);
        }

        // Locate the field name in 'root'. Note that we may not have all the parts in the path
        // in the doc -- which is fine. Our goal now is merely to reason about whether this mod
        // apply is a noOp or whether is can be in place. The remaining path, if missing, will
        // be created during the apply.
        Status status = pathsupport::findLongestPrefix(_fieldRef,
                                                       root,
                                                       &_preparedState->idxFound,
                                                       &_preparedState->elemFound);

        // FindLongestPrefix may say the path does not exist at all, which is fine here, or
        // that the path was not viable or otherwise wrong, in which case, the mod cannot
        // proceed.
        if (status.code() == ErrorCodes::NonExistentPath) {
            _preparedState->elemFound = root.getDocument().end();
        }
        else if (!status.isOK()) {
            return status;
        }

        // We register interest in the field name. The driver needs this info to sort out if
        // there is any conflict among mods.
        execInfo->fieldRef[0] = &_fieldRef;

        // Capture the value we are going to write. At this point, there may not be a value
        // against which to operate, so the result will be simply _val.
        _preparedState->newValue = _val;

        //
        // in-place and no-op logic
        //
        // If the field path is not fully present, then this mod cannot be in place, nor is a
        // noOp.
        if (!_preparedState->elemFound.ok() ||
            _preparedState->idxFound < static_cast<int32_t>(_fieldRef.numParts() - 1)) {
            return Status::OK();
        }

        // If the value being $inc'ed is the same as the one already in the doc, than this is a
        // noOp.
        if (!_preparedState->elemFound.isNumeric())
            return Status(ErrorCodes::BadValue,
                          "invalid attempt to increment a non-numeric field");

        const SafeNum currentValue = _preparedState->elemFound.getValueSafeNum();

        // Update newValue w.r.t to the current value of the found element.
        _preparedState->newValue += currentValue;

        // If the result of the addition is invalid, we must return an error.
        if (!_preparedState->newValue.isValid())
            return Status(ErrorCodes::BadValue,
                          "Failed to increment current value");

        // If the values are identical (same type, same value), then this is a no-op, and
        // therefore in-place as well.
        if (_preparedState->newValue.isIdentical(currentValue)) {
            _preparedState->noOp = execInfo->noOp = true;
            _preparedState->inPlace = execInfo->inPlace = true;
            return Status::OK();
        }

        // If the types are the same, this can be done in place.
        //
        // TODO: Potentially, cases where $inc results in a mixed type of the same size could
        // be in-place as well, but we don't currently handle them.
        if (_preparedState->newValue.type() == currentValue.type()) {
            _preparedState->inPlace = execInfo->inPlace = true;
        }

        return Status::OK();
    }