SERVER-104912 core.bson modularity marks (#50551)

GitOrigin-RevId: 84d39d26946778acb03edfa677ff1d25e46d653d
This commit is contained in:
Billy Donahue 2026-05-01 07:55:43 -04:00 committed by MongoDB Bot
parent 932c71f2eb
commit 5f242626e8
18 changed files with 203 additions and 415 deletions

View File

@ -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:

View File

@ -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<Seconds> will parse a number of seconds as a Duration.
*/
template <typename Duration>
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 <typename ToDuration, typename Period>
void serializeDurationToCount(const Duration<Period>& duration,
StringData fieldName,
BSONObjBuilder* builder) {
MONGO_MOD_PUBLIC_FOR_TECHNICAL_REASONS void serializeDurationToCount(
const Duration<Period>& duration, StringData fieldName, BSONObjBuilder* builder) {
builder->append(fieldName, durationCount<ToDuration>(duration));
}

View File

@ -30,6 +30,7 @@
#pragma once
#include "mongo/bson/bsonobj.h"
#include "mongo/util/modules.h"
#include <string>
@ -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 <typename T>
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 <typename T>
class BSONField {
class MONGO_MOD_USE_REPLACEMENT(idl) BSONField {
public:
BSONField(const std::string& name) : _name(name) {}

View File

@ -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 <cstdint>
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.

View File

@ -30,6 +30,7 @@
global:
cpp_namespace: "mongo"
mod_visibility: public
imports:
- "mongo/db/basic_types.idl"

View File

@ -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 {

View File

@ -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 <cstddef>
MONGO_MOD_PUBLIC;
namespace mongo {
namespace bson {

View File

@ -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 {

View File

@ -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",
],

View File

@ -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
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* 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 <absl/container/node_hash_map.h>
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 <typename Condition>
Status bsonCheckOnlyHasFieldsImpl(StringData objectName,
const BSONObj& obj,
const Condition& allowed) {
StringMap<bool> 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 <typename Container>
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 <typename Container>
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

View File

@ -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
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* 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 <algorithm>
#include <iterator>
#include <vector>
namespace mongo {
namespace {
TEST(BsonCheck, CheckNothingLegal) {
ASSERT_OK(bsonCheckOnlyHasFields("", BSONObj(), std::vector<StringData>()));
ASSERT_EQUALS(ErrorCodes::BadValue,
bsonCheckOnlyHasFields("", BSON("a" << 1), std::vector<StringData>()));
}
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

View File

@ -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<bool(long long)> 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<BSONElement> 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,
StatusWith<BSONElement> bsonExtractTypedField(const BSONObj& object,
StringData fieldName,
long long defaultValue,
std::function<bool(long long)> pred,
long long* out) {
return bsonExtractIntegerFieldWithDefaultIf(
object, fieldName, defaultValue, pred, "constraint failed", out);
BSONType type) {
BSONElement out;
if (auto st = bsonExtractTypedField(object, fieldName, type, &out); !st.isOK())
return st;
return out;
}
StatusWith<bool> bsonExtractBooleanField(const BSONObj& object, StringData fieldName) {
bool out;
if (auto st = bsonExtractBooleanField(object, fieldName, &out); !st.isOK())
return st;
return out;
}
StatusWith<long long> bsonExtractIntegerField(const BSONObj& object, StringData fieldName) {
long long out;
if (auto st = bsonExtractIntegerField(object, fieldName, &out); !st.isOK())
return st;
return out;
}
StatusWith<double> bsonExtractDoubleField(const BSONObj& object, StringData fieldName) {
double out;
if (auto st = bsonExtractDoubleField(object, fieldName, &out); !st.isOK())
return st;
return out;
}
StatusWith<std::string> bsonExtractStringField(const BSONObj& object, StringData fieldName) {
std::string out;
if (auto st = bsonExtractStringField(object, fieldName, &out); !st.isOK())
return st;
return out;
}
StatusWith<Timestamp> bsonExtractTimestampField(const BSONObj& object, StringData fieldName) {
Timestamp out;
if (auto st = bsonExtractTimestampField(object, fieldName, &out); !st.isOK())
return st;
return out;
}
StatusWith<OID> bsonExtractOIDField(const BSONObj& object, StringData fieldName) {
OID out;
if (auto st = bsonExtractOIDField(object, fieldName, &out); !st.isOK())
return st;
return out;
}
StatusWith<bool> 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<long long> 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<std::string> 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

View File

@ -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 <functional>
#include <string>
#include <vector>
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<BSONElement> 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<BSONElement> 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<bool> 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<bool> 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<long long> 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<long long> 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<double> 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<std::string> 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<std::string> 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<Timestamp> 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<bool(long long)> pred,
const std::string& predDescription,
long long* out);
Status bsonExtractIntegerFieldWithDefaultIf(const BSONObj& object,
StringData fieldName,
long long defaultValue,
std::function<bool(long long)> pred,
long long* out);
Status bsonExtractOIDField(const BSONObj& object, StringData fieldName, OID* out);
StatusWith<OID> bsonExtractOIDField(const BSONObj& object, StringData fieldName);
} // namespace mongo

View File

@ -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);
}

View File

@ -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

View File

@ -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 <boost/move/utility_core.hpp>
#include <boost/none.hpp>
#include <boost/optional/optional.hpp>
#include <fmt/format.h>
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));

View File

@ -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.

View File

@ -102,9 +102,15 @@ StatusWith<ReplSetMetadata> 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;