diff options
author | Pawel Terlecki <pawel.terlecki@mongodb.com> | 2019-04-26 05:25:24 -0400 |
---|---|---|
committer | Pawel Terlecki <pawel.terlecki@mongodb.com> | 2019-04-26 14:29:14 -0400 |
commit | 40baef6600a83443b2ae324c97928b000ca09778 (patch) | |
tree | 3f18f22e8c4bb88d503293af632ef0ac79e3762e /src/mongo/db/query | |
parent | 466fd9bf23cb4c694891d77af02b338353d32eb8 (diff) | |
download | mongo-40baef6600a83443b2ae324c97928b000ca09778.tar.gz |
SERVER-40005 Add translation for FindAndModify for FLE
Extended FindAndModifyRequest to validate all fields in parsing and
serialize to BSON with passthru fields.
Diffstat (limited to 'src/mongo/db/query')
-rw-r--r-- | src/mongo/db/query/find_and_modify_request.cpp | 109 | ||||
-rw-r--r-- | src/mongo/db/query/find_and_modify_request.h | 9 | ||||
-rw-r--r-- | src/mongo/db/query/find_and_modify_request_test.cpp | 34 |
3 files changed, 93 insertions, 59 deletions
diff --git a/src/mongo/db/query/find_and_modify_request.cpp b/src/mongo/db/query/find_and_modify_request.cpp index 1ef84b03762..6c46b639177 100644 --- a/src/mongo/db/query/find_and_modify_request.cpp +++ b/src/mongo/db/query/find_and_modify_request.cpp @@ -34,7 +34,9 @@ #include "mongo/base/status_with.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/util/bson_extract.h" +#include "mongo/db/command_generic_argument.h" #include "mongo/db/write_concern.h" +#include "mongo/idl/idl_parser.h" namespace mongo { @@ -52,6 +54,12 @@ const char kUpsertField[] = "upsert"; const char kWriteConcernField[] = "writeConcern"; const std::vector<BSONObj> emptyArrayFilters{}; + +const std::vector<StringData> _knownFields{ + FindAndModifyRequest::kBypassDocumentValidationFieldName, + FindAndModifyRequest::kLegacyCommandName, + FindAndModifyRequest::kCommandName, +}; } // unnamed namespace FindAndModifyRequest::FindAndModifyRequest(NamespaceString fullNs, BSONObj query, BSONObj updateObj) @@ -67,12 +75,12 @@ FindAndModifyRequest FindAndModifyRequest::makeUpdate(NamespaceString fullNs, } FindAndModifyRequest FindAndModifyRequest::makeRemove(NamespaceString fullNs, BSONObj query) { - FindAndModifyRequest request(fullNs, query, BSONObj()); + FindAndModifyRequest request(fullNs, query, {}); request._isRemove = true; return request; } -BSONObj FindAndModifyRequest::toBSON() const { +BSONObj FindAndModifyRequest::toBSON(const BSONObj& commandPassthroughFields) const { BSONObjBuilder builder; builder.append(kCmdName, _ns.coll()); @@ -116,56 +124,77 @@ BSONObj FindAndModifyRequest::toBSON() const { builder.append(kWriteConcernField, _writeConcern->toBSON()); } + IDLParserErrorContext::appendGenericCommandArguments( + commandPassthroughFields, _knownFields, &builder); + return builder.obj(); } StatusWith<FindAndModifyRequest> FindAndModifyRequest::parseFromBSON(NamespaceString fullNs, const BSONObj& cmdObj) { - BSONObj query = cmdObj.getObjectField(kQueryField); - BSONObj fields = cmdObj.getObjectField(kFieldProjectionField); - BSONObj updateObj = cmdObj.getObjectField(kUpdateField); - BSONObj sort = cmdObj.getObjectField(kSortField); - + BSONObj query; + BSONObj fields; + BSONObj updateObj; + BSONObj sort; BSONObj collation; - { - BSONElement collationElt; - Status collationEltStatus = - bsonExtractTypedField(cmdObj, kCollationField, BSONType::Object, &collationElt); - if (!collationEltStatus.isOK() && (collationEltStatus != ErrorCodes::NoSuchKey)) { - return collationEltStatus; - } - if (collationEltStatus.isOK()) { - collation = collationElt.Obj(); - } - } - - std::vector<BSONObj> arrayFilters; + bool shouldReturnNew = false; + bool isUpsert = false; + bool isRemove = false; + bool isUpdate = false; bool arrayFiltersSet = false; - { - BSONElement arrayFiltersElt; - Status arrayFiltersEltStatus = - bsonExtractTypedField(cmdObj, kArrayFiltersField, BSONType::Array, &arrayFiltersElt); - if (!arrayFiltersEltStatus.isOK() && (arrayFiltersEltStatus != ErrorCodes::NoSuchKey)) { - return arrayFiltersEltStatus; - } - if (arrayFiltersEltStatus.isOK()) { - arrayFiltersSet = true; - for (auto arrayFilter : arrayFiltersElt.Obj()) { - if (arrayFilter.type() != BSONType::Object) { - return {ErrorCodes::TypeMismatch, - str::stream() << "Each array filter must be an object, found " - << arrayFilter.type()}; + std::vector<BSONObj> arrayFilters; + + for (auto&& field : cmdObj.getFieldNames<std::set<std::string>>()) { + if (field == kQueryField) { + query = cmdObj.getObjectField(kQueryField); + } else if (field == kSortField) { + sort = cmdObj.getObjectField(kSortField); + } else if (field == kRemoveField) { + isRemove = cmdObj[kRemoveField].trueValue(); + } else if (field == kUpdateField) { + updateObj = cmdObj.getObjectField(kUpdateField); + isUpdate = true; + } else if (field == kNewField) { + shouldReturnNew = cmdObj[kNewField].trueValue(); + } else if (field == kFieldProjectionField) { + fields = cmdObj.getObjectField(kFieldProjectionField); + } else if (field == kUpsertField) { + isUpsert = cmdObj[kUpsertField].trueValue(); + } else if (field == kCollationField) { + BSONElement collationElt; + Status collationEltStatus = + bsonExtractTypedField(cmdObj, kCollationField, BSONType::Object, &collationElt); + if (!collationEltStatus.isOK() && (collationEltStatus != ErrorCodes::NoSuchKey)) { + return collationEltStatus; + } + if (collationEltStatus.isOK()) { + collation = collationElt.Obj(); + } + } else if (field == kArrayFiltersField) { + BSONElement arrayFiltersElt; + Status arrayFiltersEltStatus = bsonExtractTypedField( + cmdObj, kArrayFiltersField, BSONType::Array, &arrayFiltersElt); + if (!arrayFiltersEltStatus.isOK() && (arrayFiltersEltStatus != ErrorCodes::NoSuchKey)) { + return arrayFiltersEltStatus; + } + if (arrayFiltersEltStatus.isOK()) { + arrayFiltersSet = true; + for (auto arrayFilter : arrayFiltersElt.Obj()) { + if (arrayFilter.type() != BSONType::Object) { + return {ErrorCodes::TypeMismatch, + str::stream() << "Each array filter must be an object, found " + << arrayFilter.type()}; + } + arrayFilters.push_back(arrayFilter.Obj()); } - arrayFilters.push_back(arrayFilter.Obj()); } + } else if (!isGenericArgument(field) && + !std::count(_knownFields.begin(), _knownFields.end(), field)) { + return {ErrorCodes::Error(51177), + str::stream() << "BSON field '" << field << "' is an unknown field."}; } } - bool shouldReturnNew = cmdObj[kNewField].trueValue(); - bool isUpsert = cmdObj[kUpsertField].trueValue(); - bool isRemove = cmdObj[kRemoveField].trueValue(); - bool isUpdate = cmdObj.hasField(kUpdateField); - if (!isRemove && !isUpdate) { return {ErrorCodes::FailedToParse, "Either an update or remove=true must be specified"}; } diff --git a/src/mongo/db/query/find_and_modify_request.h b/src/mongo/db/query/find_and_modify_request.h index 71e1ac983d1..f0882a63941 100644 --- a/src/mongo/db/query/find_and_modify_request.h +++ b/src/mongo/db/query/find_and_modify_request.h @@ -50,6 +50,10 @@ class StatusWith; */ class FindAndModifyRequest { public: + static constexpr auto kBypassDocumentValidationFieldName = "bypassDocumentValidation"_sd; + static constexpr auto kLegacyCommandName = "findandmodify"_sd; + static constexpr auto kCommandName = "findAndModify"_sd; + /** * Creates a new instance of an 'update' type findAndModify request. */ @@ -87,9 +91,10 @@ public: /** * Serializes this object into a BSON representation. Fields that are not - * set will not be part of the the serialized object. + * set will not be part of the the serialized object. Passthrough fields + * are appended. */ - BSONObj toBSON() const; + BSONObj toBSON(const BSONObj& commandPassthroughFields) const; const NamespaceString& getNamespaceString() const; BSONObj getQuery() const; diff --git a/src/mongo/db/query/find_and_modify_request_test.cpp b/src/mongo/db/query/find_and_modify_request_test.cpp index 7266cb04a18..a30bdd2e538 100644 --- a/src/mongo/db/query/find_and_modify_request_test.cpp +++ b/src/mongo/db/query/find_and_modify_request_test.cpp @@ -47,7 +47,7 @@ TEST(FindAndModifyRequest, BasicUpdate) { update: { y: 1 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithUpsert) { @@ -63,7 +63,7 @@ TEST(FindAndModifyRequest, UpdateWithUpsert) { upsert: true })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithUpsertFalse) { @@ -79,7 +79,7 @@ TEST(FindAndModifyRequest, UpdateWithUpsertFalse) { upsert: false })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithProjection) { @@ -97,7 +97,7 @@ TEST(FindAndModifyRequest, UpdateWithProjection) { fields: { z: 1 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithNewTrue) { @@ -114,7 +114,7 @@ TEST(FindAndModifyRequest, UpdateWithNewTrue) { new: true })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithNewFalse) { @@ -131,7 +131,7 @@ TEST(FindAndModifyRequest, UpdateWithNewFalse) { new: false })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithSort) { @@ -149,7 +149,7 @@ TEST(FindAndModifyRequest, UpdateWithSort) { sort: { z: -1 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithCollation) { @@ -168,7 +168,7 @@ TEST(FindAndModifyRequest, UpdateWithCollation) { collation: { locale: 'en_US' } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithArrayFilters) { @@ -186,7 +186,7 @@ TEST(FindAndModifyRequest, UpdateWithArrayFilters) { arrayFilters: [ { i: 0 } ] })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithWriteConcern) { @@ -204,7 +204,7 @@ TEST(FindAndModifyRequest, UpdateWithWriteConcern) { writeConcern: { w: 2, fsync: true, wtimeout: 150 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, UpdateWithFullSpec) { @@ -239,7 +239,7 @@ TEST(FindAndModifyRequest, UpdateWithFullSpec) { writeConcern: { w: 2, fsync: true, wtimeout: 150 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, BasicRemove) { @@ -252,7 +252,7 @@ TEST(FindAndModifyRequest, BasicRemove) { remove: true })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, RemoveWithProjection) { @@ -269,7 +269,7 @@ TEST(FindAndModifyRequest, RemoveWithProjection) { fields: { z: 1 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, RemoveWithSort) { @@ -286,7 +286,7 @@ TEST(FindAndModifyRequest, RemoveWithSort) { sort: { z: -1 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, RemoveWithCollation) { @@ -304,7 +304,7 @@ TEST(FindAndModifyRequest, RemoveWithCollation) { collation: { locale: 'en_US' } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, RemoveWithWriteConcern) { @@ -321,7 +321,7 @@ TEST(FindAndModifyRequest, RemoveWithWriteConcern) { writeConcern: { w: 2, fsync: true, wtimeout: 150 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, RemoveWithFullSpec) { @@ -348,7 +348,7 @@ TEST(FindAndModifyRequest, RemoveWithFullSpec) { writeConcern: { w: 2, fsync: true, wtimeout: 150 } })json")); - ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON()); + ASSERT_BSONOBJ_EQ(expectedObj, request.toBSON({})); } TEST(FindAndModifyRequest, ParseWithUpdateOnlyRequiredFields) { |