diff --git a/modules_poc/modules.yaml b/modules_poc/modules.yaml index 699a8434203..29eb573d8db 100644 --- a/modules_poc/modules.yaml +++ b/modules_poc/modules.yaml @@ -63,6 +63,8 @@ core: - src/mongo/db/stats/counter_ops.h core.bson: + meta: + fully_marked: true files: - src/mongo/bson/ # Unsure about the next one but putting here for now: diff --git a/src/mongo/bson/bson_duration.h b/src/mongo/bson/bson_duration.h index 053aa0c2614..271b3c88e1c 100644 --- a/src/mongo/bson/bson_duration.h +++ b/src/mongo/bson/bson_duration.h @@ -33,6 +33,7 @@ #include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/util/duration.h" +#include "mongo/util/modules.h" namespace mongo { @@ -42,7 +43,7 @@ namespace mongo { * e.g. parseDurationFromCount will parse a number of seconds as a Duration. */ template -Duration parseDurationFromCount(const BSONElement& elem) { +MONGO_MOD_PUBLIC_FOR_TECHNICAL_REASONS Duration parseDurationFromCount(const BSONElement& elem) { uassert(ErrorCodes::BadValue, str::stream() << "Duration value must be numeric, got: " << typeName(elem.type()), elem.isNumber()); @@ -55,9 +56,8 @@ Duration parseDurationFromCount(const BSONElement& elem) { * Serializes a Duration to a BSON int32/int64 for the specified units. */ template -void serializeDurationToCount(const Duration& duration, - StringData fieldName, - BSONObjBuilder* builder) { +MONGO_MOD_PUBLIC_FOR_TECHNICAL_REASONS void serializeDurationToCount( + const Duration& duration, StringData fieldName, BSONObjBuilder* builder) { builder->append(fieldName, durationCount(duration)); } diff --git a/src/mongo/bson/bson_field.h b/src/mongo/bson/bson_field.h index efd0c45f7a5..03518a96154 100644 --- a/src/mongo/bson/bson_field.h +++ b/src/mongo/bson/bson_field.h @@ -30,6 +30,7 @@ #pragma once #include "mongo/bson/bsonobj.h" +#include "mongo/util/modules.h" #include @@ -71,10 +72,12 @@ namespace mongo { * * // Use BSONField::operator()() to retrieve the name of the field: * BSONObj obj = BSON(MyCollFields::draining() << 1); + * + * Deprecated: IDL should now be preferred for imposing structure onto BSON. */ template -class BSONFieldValue { +class MONGO_MOD_USE_REPLACEMENT(idl) BSONFieldValue { public: BSONFieldValue(const std::string& name, const T& t) : _name(name), _t(t) {} @@ -91,7 +94,7 @@ private: }; template -class BSONField { +class MONGO_MOD_USE_REPLACEMENT(idl) BSONField { public: BSONField(const std::string& name) : _name(name) {} diff --git a/src/mongo/bson/bson_validate.h b/src/mongo/bson/bson_validate.h index a05f2f57645..0087e0c72cf 100644 --- a/src/mongo/bson/bson_validate.h +++ b/src/mongo/bson/bson_validate.h @@ -33,9 +33,12 @@ #include "mongo/bson/bson_validate_gen.h" #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsontypes.h" +#include "mongo/util/modules.h" #include +MONGO_MOD_PUBLIC; + namespace mongo { enum ValidationVersion { @@ -47,7 +50,7 @@ enum ValidationVersion { // When adding new versions of BSON validation, update both this and the range and the // default for the server parameter in src/mongo/bson/bson_validate.idl -static constexpr ValidationVersion currentValidationVersion = V2_Column; +constexpr inline ValidationVersion currentValidationVersion = V2_Column; /** * Checks that the buf holds a BSON object as defined in http://bsonspec.org/spec.html. diff --git a/src/mongo/bson/bson_validate.idl b/src/mongo/bson/bson_validate.idl index 13606f31974..3d474e307ed 100644 --- a/src/mongo/bson/bson_validate.idl +++ b/src/mongo/bson/bson_validate.idl @@ -30,6 +30,7 @@ global: cpp_namespace: "mongo" + mod_visibility: public imports: - "mongo/db/basic_types.idl" diff --git a/src/mongo/bson/bsonobj_comparator.h b/src/mongo/bson/bsonobj_comparator.h index 783e35d6448..9cacaa29ac1 100644 --- a/src/mongo/bson/bsonobj_comparator.h +++ b/src/mongo/bson/bsonobj_comparator.h @@ -31,6 +31,9 @@ #include "mongo/base/string_data_comparator.h" #include "mongo/bson/bsonobj_comparator_interface.h" +#include "mongo/util/modules.h" + +MONGO_MOD_PUBLIC; namespace mongo { diff --git a/src/mongo/bson/dotted_path/dotted_path_support.h b/src/mongo/bson/dotted_path/dotted_path_support.h index 18198bd7a40..02cdce6979f 100644 --- a/src/mongo/bson/dotted_path/dotted_path_support.h +++ b/src/mongo/bson/dotted_path/dotted_path_support.h @@ -33,9 +33,12 @@ #include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonelement_comparator_interface.h" #include "mongo/bson/bsonobj.h" +#include "mongo/util/modules.h" #include +MONGO_MOD_PUBLIC; + namespace mongo { namespace bson { diff --git a/src/mongo/bson/unordered_fields_bsonobj_comparator.h b/src/mongo/bson/unordered_fields_bsonobj_comparator.h index 6bd8996ac6b..3742be9f6a6 100644 --- a/src/mongo/bson/unordered_fields_bsonobj_comparator.h +++ b/src/mongo/bson/unordered_fields_bsonobj_comparator.h @@ -31,6 +31,9 @@ #include "mongo/base/string_data_comparator.h" #include "mongo/bson/bsonobj_comparator_interface.h" +#include "mongo/util/modules.h" + +MONGO_MOD_PUBLIC; namespace mongo { diff --git a/src/mongo/bson/util/BUILD.bazel b/src/mongo/bson/util/BUILD.bazel index b47d0ce8c19..bdb14223a75 100644 --- a/src/mongo/bson/util/BUILD.bazel +++ b/src/mongo/bson/util/BUILD.bazel @@ -22,7 +22,6 @@ mongo_cc_library( mongo_cc_unit_test( name = "bson_util_test", srcs = [ - "bson_check_test.cpp", "bson_extract_test.cpp", "builder_test.cpp", ], diff --git a/src/mongo/bson/util/bson_check.h b/src/mongo/bson/util/bson_check.h deleted file mode 100644 index 15ead0956fc..00000000000 --- a/src/mongo/bson/util/bson_check.h +++ /dev/null @@ -1,120 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/base/error_codes.h" -#include "mongo/base/status.h" -#include "mongo/base/string_data.h" -#include "mongo/bson/bsonelement.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/bson/bsontypes.h" -#include "mongo/db/commands.h" -#include "mongo/idl/command_generic_argument.h" -#include "mongo/util/assert_util.h" -#include "mongo/util/str.h" -#include "mongo/util/string_map.h" - -#include - -namespace mongo { - -/** - * Confirms that obj only contains field names where allowed(name) returns true, - * and that no field name occurs multiple times. - * - * On failure, returns BadValue and a message naming the unexpected field or error code 51000 with - * a message naming a repeated field. "objectName" is included in the message, for reporting - * purposes. - */ -template -Status bsonCheckOnlyHasFieldsImpl(StringData objectName, - const BSONObj& obj, - const Condition& allowed) { - StringMap seenFields; - for (auto&& e : obj) { - const auto name = e.fieldNameStringData(); - - if (!allowed(name)) { - return Status(ErrorCodes::BadValue, - str::stream() - << "Unexpected field " << e.fieldName() << " in " << objectName); - } - - bool& seenBefore = seenFields[name]; - if (!seenBefore) { - seenBefore = true; - } else { - return Status(ErrorCodes::Error(51000), - str::stream() - << "Field " << name << " appears multiple times in " << objectName); - } - } - return Status::OK(); -} - -/** - * Like above but only allows fields from the passed-in container. - */ -template -Status bsonCheckOnlyHasFields(StringData objectName, - const BSONObj& obj, - const Container& allowedFields) { - return bsonCheckOnlyHasFieldsImpl(objectName, obj, [&](StringData name) { - return std::find(std::begin(allowedFields), std::end(allowedFields), name) != - std::end(allowedFields); - }); -} - -/** - * Like above but only allows fields from the passed-in container or are generic command arguments. - */ -template -Status bsonCheckOnlyHasFieldsForCommand(StringData objectName, - const BSONObj& obj, - const Container& allowedFields) { - return bsonCheckOnlyHasFieldsImpl(objectName, obj, [&](StringData name) { - return isGenericArgument(name) || - (std::find(std::begin(allowedFields), std::end(allowedFields), name) != - std::end(allowedFields)); - }); -} - -/** - * Throws a uassert if the type of the elem does not match that provided in expectedType - */ -inline void checkBSONType(BSONType expectedType, const BSONElement& elem) { - uassert(elem.type() == BSONType::eoo ? ErrorCodes::NoSuchKey : ErrorCodes::TypeMismatch, - str::stream() << "Wrong type for '" << elem.fieldNameStringData() << "'. Expected a " - << typeName(expectedType) << ", got a " << typeName(elem.type()) << '.', - elem.type() == expectedType); -} - - -} // namespace mongo diff --git a/src/mongo/bson/util/bson_check_test.cpp b/src/mongo/bson/util/bson_check_test.cpp deleted file mode 100644 index e183235c0f5..00000000000 --- a/src/mongo/bson/util/bson_check_test.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/bson/util/bson_check.h" - -#include "mongo/bson/bsonmisc.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/unittest/unittest.h" - -#include -#include -#include - -namespace mongo { -namespace { - -TEST(BsonCheck, CheckNothingLegal) { - ASSERT_OK(bsonCheckOnlyHasFields("", BSONObj(), std::vector())); - ASSERT_EQUALS(ErrorCodes::BadValue, - bsonCheckOnlyHasFields("", BSON("a" << 1), std::vector())); -} - -const char* const legals[] = {"aField", "anotherField", "thirdField"}; - -TEST(BsonCheck, CheckHasOnlyOnEmptyObject) { - ASSERT_OK(bsonCheckOnlyHasFields("", BSONObj(), legals)); -} - -TEST(BsonCheck, CheckHasOnlyLegalFields) { - ASSERT_OK(bsonCheckOnlyHasFields("", - BSON("aField" << "value" - << "thirdField" << 1 << "anotherField" << 2), - legals)); - ASSERT_OK(bsonCheckOnlyHasFields("", - BSON("aField" << "value" - << "thirdField" << 1), - legals)); - - ASSERT_EQUALS(ErrorCodes::BadValue, - bsonCheckOnlyHasFields("", - BSON("aField" << "value" - << "illegal" << 4 << "thirdField" << 1), - legals)); -} - -TEST(BsonCheck, CheckNoDuplicates) { - ASSERT_EQUALS(51000, - bsonCheckOnlyHasFields( - "", BSON("aField" << 1 << "anotherField" << 2 << "aField" << 3), legals) - .code()); -} - -} // namespace -} // namespace mongo diff --git a/src/mongo/bson/util/bson_extract.cpp b/src/mongo/bson/util/bson_extract.cpp index 76705a343b1..70b716cc9cd 100644 --- a/src/mongo/bson/util/bson_extract.cpp +++ b/src/mongo/bson/util/bson_extract.cpp @@ -188,21 +188,6 @@ Status bsonExtractOIDField(const BSONObj& object, StringData fieldName, OID* out return status; } -Status bsonExtractOIDFieldWithDefault(const BSONObj& object, - StringData fieldName, - const OID& defaultValue, - OID* out) { - BSONElement element; - Status status = bsonExtractTypedFieldImpl(object, fieldName, BSONType::oid, &element, true); - if (status == ErrorCodes::NoSuchKey) { - *out = defaultValue; - return Status::OK(); - } - if (status.isOK()) - *out = element.OID(); - return status; -} - Status bsonExtractStringFieldWithDefault(const BSONObj& object, StringData fieldName, StringData defaultValue, @@ -226,18 +211,6 @@ Status bsonExtractDoubleField(const BSONObj& object, StringData fieldName, doubl return bsonExtractDoubleFieldImpl(object, fieldName, out, false); } -Status bsonExtractDoubleFieldWithDefault(const BSONObj& object, - StringData fieldName, - double defaultValue, - double* out) { - Status status = bsonExtractDoubleFieldImpl(object, fieldName, out, true); - if (status == ErrorCodes::NoSuchKey) { - *out = defaultValue; - return Status::OK(); - } - return status; -} - Status bsonExtractIntegerFieldWithDefault(const BSONObj& object, StringData fieldName, long long defaultValue, @@ -250,31 +223,95 @@ Status bsonExtractIntegerFieldWithDefault(const BSONObj& object, return status; } -Status bsonExtractIntegerFieldWithDefaultIf(const BSONObj& object, - StringData fieldName, - long long defaultValue, - std::function pred, - const std::string& predDescription, - long long* out) { - Status status = bsonExtractIntegerFieldWithDefault(object, fieldName, defaultValue, out); - if (!status.isOK()) { - return status; - } - if (!pred(*out)) { - return Status(ErrorCodes::BadValue, - str::stream() << "Invalid value in field \"" << fieldName << "\": " << *out - << ": " << predDescription); - } - return status; +//////////////////////////////////////////////////////////// +// StatusWith variants of the above. + +StatusWith bsonExtractField(const BSONObj& object, StringData fieldName) { + BSONElement out; + if (auto st = bsonExtractField(object, fieldName, &out); !st.isOK()) + return st; + return out; } -Status bsonExtractIntegerFieldWithDefaultIf(const BSONObj& object, - StringData fieldName, - long long defaultValue, - std::function pred, - long long* out) { - return bsonExtractIntegerFieldWithDefaultIf( - object, fieldName, defaultValue, pred, "constraint failed", out); +StatusWith bsonExtractTypedField(const BSONObj& object, + StringData fieldName, + BSONType type) { + BSONElement out; + if (auto st = bsonExtractTypedField(object, fieldName, type, &out); !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractBooleanField(const BSONObj& object, StringData fieldName) { + bool out; + if (auto st = bsonExtractBooleanField(object, fieldName, &out); !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractIntegerField(const BSONObj& object, StringData fieldName) { + long long out; + if (auto st = bsonExtractIntegerField(object, fieldName, &out); !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractDoubleField(const BSONObj& object, StringData fieldName) { + double out; + if (auto st = bsonExtractDoubleField(object, fieldName, &out); !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractStringField(const BSONObj& object, StringData fieldName) { + std::string out; + if (auto st = bsonExtractStringField(object, fieldName, &out); !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractTimestampField(const BSONObj& object, StringData fieldName) { + Timestamp out; + if (auto st = bsonExtractTimestampField(object, fieldName, &out); !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractOIDField(const BSONObj& object, StringData fieldName) { + OID out; + if (auto st = bsonExtractOIDField(object, fieldName, &out); !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractBooleanFieldWithDefault(const BSONObj& object, + StringData fieldName, + bool defaultValue) { + bool out; + if (auto st = bsonExtractBooleanFieldWithDefault(object, fieldName, defaultValue, &out); + !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractIntegerFieldWithDefault(const BSONObj& object, + StringData fieldName, + long long defaultValue) { + long long out; + if (auto st = bsonExtractIntegerFieldWithDefault(object, fieldName, defaultValue, &out); + !st.isOK()) + return st; + return out; +} + +StatusWith bsonExtractStringFieldWithDefault(const BSONObj& object, + StringData fieldName, + StringData defaultValue) { + std::string out; + if (auto st = bsonExtractStringFieldWithDefault(object, fieldName, defaultValue, &out); + !st.isOK()) + return st; + return out; } } // namespace mongo diff --git a/src/mongo/bson/util/bson_extract.h b/src/mongo/bson/util/bson_extract.h index 2bedb38b59b..b275e940fce 100644 --- a/src/mongo/bson/util/bson_extract.h +++ b/src/mongo/bson/util/bson_extract.h @@ -30,20 +30,22 @@ #pragma once #include "mongo/base/status.h" +#include "mongo/base/status_with.h" #include "mongo/base/string_data.h" +#include "mongo/bson/bsonelement.h" +#include "mongo/bson/bsonobj.h" #include "mongo/bson/bsontypes.h" +#include "mongo/bson/oid.h" +#include "mongo/bson/timestamp.h" +#include "mongo/util/modules.h" #include #include #include +MONGO_MOD_PUBLIC; + namespace mongo { - -class BSONObj; -class BSONElement; -class OID; -class Timestamp; - /** * Finds an element named "fieldName" in "object". * @@ -51,6 +53,7 @@ class Timestamp; * ErrorCodes::NoSuchKey if there are no matches. */ Status bsonExtractField(const BSONObj& object, StringData fieldName, BSONElement* outElement); +StatusWith bsonExtractField(const BSONObj& object, StringData fieldName); /** * Finds an element named "fieldName" in "object". @@ -64,6 +67,9 @@ Status bsonExtractTypedField(const BSONObj& object, StringData fieldName, BSONType type, BSONElement* outElement); +StatusWith bsonExtractTypedField(const BSONObj& object, + StringData fieldName, + BSONType type); /** * Finds a bool-like element named "fieldName" in "object". @@ -74,6 +80,23 @@ Status bsonExtractTypedField(const BSONObj& object, * than Status::OK(), the resulting value of "*out" is undefined. */ Status bsonExtractBooleanField(const BSONObj& object, StringData fieldName, bool* out); +StatusWith bsonExtractBooleanField(const BSONObj& object, StringData fieldName); + +/** + * If a field named "fieldName" is present, and is either a number or boolean type, stores the + * truth value of the field into "*out". If no field named "fieldName" is present, sets "*out" + * to "defaultValue". In these cases, returns Status::OK(). + * + * If "fieldName" is present more than once, behavior is undefined. If the found field is not a + * boolean or number, returns ErrorCodes::TypeMismatch. + */ +Status bsonExtractBooleanFieldWithDefault(const BSONObj& object, + StringData fieldName, + bool defaultValue, + bool* out); +StatusWith bsonExtractBooleanFieldWithDefault(const BSONObj& object, + StringData fieldName, + bool defaultValue); /** * Finds an element named "fieldName" in "object" that represents an integral value. @@ -86,6 +109,23 @@ Status bsonExtractBooleanField(const BSONObj& object, StringData fieldName, bool * undefined. */ Status bsonExtractIntegerField(const BSONObj& object, StringData fieldName, long long* out); +StatusWith bsonExtractIntegerField(const BSONObj& object, StringData fieldName); + +/** + * If a field named "fieldName" is present and is a value of numeric type with an exact 64-bit + * integer representation, returns that representation in *out and returns Status::OK(). If + * there is no field named "fieldName", stores defaultValue into *out and returns Status::OK(). + * If the field is found, but has non-numeric type, returns ErrorCodes::TypeMismatch. If the + * value has numeric type, but cannot be represented as a 64-bit integer, returns + * ErrorCodes::BadValue. + */ +Status bsonExtractIntegerFieldWithDefault(const BSONObj& object, + StringData fieldName, + long long defaultValue, + long long* out); +StatusWith bsonExtractIntegerFieldWithDefault(const BSONObj& object, + StringData fieldName, + long long defaultValue); /** * Finds an element named "fieldName" in "object" that represents a double-precision floating point @@ -98,6 +138,7 @@ Status bsonExtractIntegerField(const BSONObj& object, StringData fieldName, long * For return values other than Status::OK(), the resulting value of "*out" is undefined. */ Status bsonExtractDoubleField(const BSONObj& object, StringData fieldName, double* out); +StatusWith bsonExtractDoubleField(const BSONObj& object, StringData fieldName); /** * Finds a string-typed element named "fieldName" in "object" and stores its value in "out". @@ -108,75 +149,9 @@ Status bsonExtractDoubleField(const BSONObj& object, StringData fieldName, doubl * Status::OK(), the resulting value of "*out" is undefined. */ Status bsonExtractStringField(const BSONObj& object, StringData fieldName, std::string* out); +StatusWith bsonExtractStringField(const BSONObj& object, StringData fieldName); /** - * Finds an Timestamp-typed element named "fieldName" in "object" and stores its value in "out". - * - * Returns Status::OK() and sets *out to the found element's Timestamp value on success. Returns - * ErrorCodes::NoSuchKey if there are no matches for "fieldName", and ErrorCodes::TypeMismatch - * if the type of the matching element is not Timestamp. For return values other than - * Status::OK(), the resulting value of "*out" is undefined. - */ -Status bsonExtractTimestampField(const BSONObj& object, StringData fieldName, Timestamp* out); - -/** - * Finds an OID-typed element named "fieldName" in "object" and stores its value in "out". - * - * Returns Status::OK() and sets *out to the found element's OID value on success. Returns - * ErrorCodes::NoSuchKey if there are no matches for "fieldName", and ErrorCodes::TypeMismatch - * if the type of the matching element is not OID. For return values other than Status::OK(), - * the resulting value of "*out" is undefined. - */ -Status bsonExtractOIDField(const BSONObj& object, StringData fieldName, OID* out); - -/** - * Finds a bool-like element named "fieldName" in "object". - * - * If a field named "fieldName" is present, and is either a number or boolean type, stores the - * truth value of the field into "*out". If no field named "fieldName" is present, sets "*out" - * to "defaultValue". In these cases, returns Status::OK(). - * - * If "fieldName" is present more than once, behavior is undefined. If the found field is not a - * boolean or number, returns ErrorCodes::TypeMismatch. - */ -Status bsonExtractBooleanFieldWithDefault(const BSONObj& object, - StringData fieldName, - bool defaultValue, - bool* out); - -/** - * Finds an element named "fieldName" in "object" that represents an integral value. - * - * If a field named "fieldName" is present and is a value of numeric type with an exact 64-bit - * integer representation, returns that representation in *out and returns Status::OK(). If - * there is no field named "fieldName", stores defaultValue into *out and returns Status::OK(). - * If the field is found, but has non-numeric type, returns ErrorCodes::TypeMismatch. If the - * value has numeric type, but cannot be represented as a 64-bit integer, returns - * ErrorCodes::BadValue. - */ -Status bsonExtractIntegerFieldWithDefault(const BSONObj& object, - StringData fieldName, - long long defaultValue, - long long* out); - -/** - * Finds a double-precision floating point element named "fieldName" in "object". - * - * If a field named "fieldName" is present, and is a double, stores the value of the field into - * "*out". If no field named fieldName is present, sets "*out" to "defaultValue". In these cases, - * returns Status::OK(). - * - * If "fieldName" is present more than once, behavior is undefined. If the found field is not a - * double, returns ErrorCodes::TypeMismatch. - */ -Status bsonExtractDoubleFieldWithDefault(const BSONObj& object, - StringData fieldName, - double defaultValue, - double* out); - -/** - * Finds a std::string element named "fieldName" in "object". - * * If a field named "fieldName" is present, and is a string, stores the value of the field into * "*out". If no field named fieldName is present, sets "*out" to "defaultValue". In these * cases, returns Status::OK(). @@ -188,42 +163,29 @@ Status bsonExtractStringFieldWithDefault(const BSONObj& object, StringData fieldName, StringData defaultValue, std::string* out); +StatusWith bsonExtractStringFieldWithDefault(const BSONObj& object, + StringData fieldName, + StringData defaultValue); /** - * Finds an OID-typed element named "fieldName" in "object" and stores its value in *out. + * Finds an Timestamp-typed element named "fieldName" in "object" and stores its value in "out". * - * Returns Status::OK() and sets *out to the found element's OID value on success. If no field - * named "fieldName" is present, *out is set to "defaultValue" and Status::OK() is returned. - * Returns ErrorCodes::TypeMismatch if the type of the matching element is not OID. For return - * values other than Status::OK(), the resulting value of *out is undefined. + * Returns Status::OK() and sets *out to the found element's Timestamp value on success. Returns + * ErrorCodes::NoSuchKey if there are no matches for "fieldName", and ErrorCodes::TypeMismatch + * if the type of the matching element is not Timestamp. For return values other than + * Status::OK(), the resulting value of "*out" is undefined. */ -Status bsonExtractOIDFieldWithDefault(const BSONObj& object, - StringData fieldName, - const OID& defaultValue, - OID* out); +Status bsonExtractTimestampField(const BSONObj& object, StringData fieldName, Timestamp* out); +StatusWith bsonExtractTimestampField(const BSONObj& object, StringData fieldName); /** - * Finds an element named "fieldName" in "object" that represents an integral value for which - * 'pred' is true. + * Finds an OID-typed element named "fieldName" in "object" and stores its value in "out". * - * If a field named "fieldName" is present and is a value of numeric type with an exact 64-bit - * integer representation, returns that representation in *out and returns Status::OK(). - * If there is no field named "fieldName", stores defaultValue into *out and returns Status::OK(). - * If the field is found, but has non-numeric type, returns ErrorCodes::TypeMismatch. - * If the value has numeric type, but cannot be represented as a 64-bit integer, returns BadValue. - * If the parsed value (or default) fails the predicate, returns ErrorCodes::BadValue. + * Returns Status::OK() and sets *out to the found element's OID value on success. Returns + * ErrorCodes::NoSuchKey if there are no matches for "fieldName", and ErrorCodes::TypeMismatch + * if the type of the matching element is not OID. For return values other than Status::OK(), + * the resulting value of "*out" is undefined. */ -Status bsonExtractIntegerFieldWithDefaultIf(const BSONObj& object, - StringData fieldName, - long long defaultValue, - std::function pred, - const std::string& predDescription, - long long* out); - -Status bsonExtractIntegerFieldWithDefaultIf(const BSONObj& object, - StringData fieldName, - long long defaultValue, - std::function pred, - long long* out); - +Status bsonExtractOIDField(const BSONObj& object, StringData fieldName, OID* out); +StatusWith bsonExtractOIDField(const BSONObj& object, StringData fieldName); } // namespace mongo diff --git a/src/mongo/bson/util/bson_extract_test.cpp b/src/mongo/bson/util/bson_extract_test.cpp index 897282feca2..7acccb7deed 100644 --- a/src/mongo/bson/util/bson_extract_test.cpp +++ b/src/mongo/bson/util/bson_extract_test.cpp @@ -147,48 +147,4 @@ TEST(ExtractBSON, ExtractIntegerField) { ASSERT_EQUALS(-(1LL << 55), v); ASSERT_OK(bsonExtractIntegerField(BSON("a" << 5178), "a", &v)); ASSERT_EQUALS(5178, v); - auto pred = [](long long x) { - return x > 0; - }; - ASSERT_OK(bsonExtractIntegerFieldWithDefaultIf(BSON("a" << 1), "a", -1LL, pred, &v)); - ASSERT_OK(bsonExtractIntegerFieldWithDefaultIf(BSON("a" << 1), "b", 1LL, pred, &v)); - auto msg = "'a' has to be greater than zero"; - auto status = bsonExtractIntegerFieldWithDefaultIf(BSON("a" << -1), "a", 1LL, pred, msg, &v); - ASSERT_EQUALS(ErrorCodes::BadValue, status); - ASSERT_STRING_CONTAINS(status.reason(), msg); - ASSERT_EQUALS(ErrorCodes::BadValue, - bsonExtractIntegerFieldWithDefaultIf(BSON("a" << 1), "b", -1LL, pred, &v)); -} - -TEST(ExtractBSON, ExtractDoubleFieldWithDefault) { - double d; - ASSERT_EQUALS(ErrorCodes::NoSuchKey, bsonExtractDoubleField(BSON("a" << 1), "b", &d)); - ASSERT_OK(bsonExtractDoubleFieldWithDefault(BSON("a" << 1), "b", 1.2, &d)); - ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractDoubleField(BSON("a" << false), "a", &d)); - ASSERT_OK(bsonExtractDoubleField(BSON("a" << 5178.0), "a", &d)); - ASSERT_EQUALS(5178.0, d); - ASSERT_OK(bsonExtractDoubleField(BSON("a" << 5178), "a", &d)); - ASSERT_EQUALS(5178, d); - ASSERT_OK(bsonExtractDoubleField(BSON("a" << 5178), "a", &d)); - ASSERT_EQUALS(5178.0, d); - ASSERT_OK(bsonExtractDoubleField(BSON("a" << 5178.0), "a", &d)); - ASSERT_EQUALS(5178, d); - ASSERT_OK(bsonExtractDoubleFieldWithDefault(BSON("a" << 1.0), "b", 1, &d)); - ASSERT_EQUALS(1.0, d); - ASSERT_OK(bsonExtractDoubleFieldWithDefault(BSON("a" << 2.0), "a", 1, &d)); - ASSERT_EQUALS(2.0, d); -} - -TEST(ExtractBSON, ExtractOIDFieldWithDefault) { - OID r; - OID def = OID(); - ASSERT_EQUALS(ErrorCodes::NoSuchKey, bsonExtractOIDField(BSON("a" << 1), "b", &r)); - ASSERT_OK(bsonExtractOIDFieldWithDefault(BSON("a" << 2), "b", def, &r)); - ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractOIDField(BSON("a" << false), "a", &r)); - ASSERT_OK(bsonExtractOIDField(BSON("a" << def), "a", &r)); - ASSERT_EQUALS(def, r); - ASSERT_OK(bsonExtractOIDFieldWithDefault(BSON("a" << 3.0), "b", def, &r)); - ASSERT_EQUALS(def, r); - ASSERT_OK(bsonExtractOIDFieldWithDefault(BSON("a" << def), "a", OID(), &r)); - ASSERT_EQUALS(def, r); } diff --git a/src/mongo/db/commands/apply_ops_cmd.cpp b/src/mongo/db/commands/apply_ops_cmd.cpp index 41647afec1d..4eef3de0953 100644 --- a/src/mongo/db/commands/apply_ops_cmd.cpp +++ b/src/mongo/db/commands/apply_ops_cmd.cpp @@ -35,7 +35,6 @@ #include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/bsontypes.h" -#include "mongo/bson/util/bson_check.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/db/auth/authorization_session.h" // IWYU pragma: keep #include "mongo/db/commands.h" @@ -80,7 +79,7 @@ bool checkCOperationType(const BSONObj& opObj, const StringData opName) { } } return false; -}; +} /** * Returns kNeedsSuperuser, if the provided applyOps command contains an empty applyOps command or diff --git a/src/mongo/db/commands/oplog_application_checks.cpp b/src/mongo/db/commands/oplog_application_checks.cpp index 585012243db..af3bedc6f44 100644 --- a/src/mongo/db/commands/oplog_application_checks.cpp +++ b/src/mongo/db/commands/oplog_application_checks.cpp @@ -31,7 +31,6 @@ #include "mongo/base/error_codes.h" #include "mongo/base/string_data.h" #include "mongo/bson/bsontypes.h" -#include "mongo/bson/util/bson_check.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_checks.h" @@ -63,8 +62,19 @@ #include #include #include +#include namespace mongo { + +void checkBSONType(BSONType type, const BSONElement& elem) { + uassert(elem.type() == BSONType::eoo ? ErrorCodes::NoSuchKey : ErrorCodes::TypeMismatch, + fmt::format("Wrong type for {:?}. Expected a {}, got a {}.", + elem.fieldNameStringData(), + typeName(type), + typeName(elem.type())), + elem.type() == type); +} + UUID OplogApplicationChecks::getUUIDFromOplogEntry(const BSONObj& oplogEntry) { BSONElement uiElem = oplogEntry["ui"]; return uassertStatusOK(UUID::parse(uiElem)); diff --git a/src/mongo/db/commands/oplog_application_checks.h b/src/mongo/db/commands/oplog_application_checks.h index cf1e66f316f..b185f9cc8c8 100644 --- a/src/mongo/db/commands/oplog_application_checks.h +++ b/src/mongo/db/commands/oplog_application_checks.h @@ -31,14 +31,15 @@ #include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonobj.h" #include "mongo/db/auth/authorization_session.h" +#include "mongo/db/database_name.h" +#include "mongo/db/operation_context.h" #include "mongo/util/modules.h" #include "mongo/util/uuid.h" namespace mongo { -class BSONElement; -class BSONObj; -class DatabaseName; -class OperationContext; + +/** `uassert` that `elem` type matches the specified `type`. */ +void checkBSONType(BSONType type, const BSONElement& elem); // OplogApplicationValidity represents special conditions relevant to authorization for // oplog application. diff --git a/src/mongo/rpc/metadata/repl_set_metadata.cpp b/src/mongo/rpc/metadata/repl_set_metadata.cpp index 4cefedf510c..a6239f5ceac 100644 --- a/src/mongo/rpc/metadata/repl_set_metadata.cpp +++ b/src/mongo/rpc/metadata/repl_set_metadata.cpp @@ -102,9 +102,15 @@ StatusWith ReplSetMetadata::readFromMetadata(const BSONObj& met return status; OID id; - status = bsonExtractOIDFieldWithDefault(replMetadataObj, kReplicaSetIdFieldName, OID(), &id); - if (!status.isOK()) - return status; + if (BSONElement e = replMetadataObj.getField(kReplicaSetIdFieldName); !e.eoo()) { + if (e.type() != BSONType::oid) + return Status(ErrorCodes::TypeMismatch, + fmt::format("{:?} had the wrong type. Expected {}, found {}", + kReplicaSetIdFieldName, + BSONType::oid, + typeName(e.type()))); + id = e.OID(); + } // We provide a default because these fields will be removed in SERVER-27668. long long primaryIndex;