summaryrefslogtreecommitdiff
path: root/src/mongo/db/query
diff options
context:
space:
mode:
authorPawel Terlecki <pawel.terlecki@mongodb.com>2019-04-26 05:25:24 -0400
committerPawel Terlecki <pawel.terlecki@mongodb.com>2019-04-26 14:29:14 -0400
commit40baef6600a83443b2ae324c97928b000ca09778 (patch)
tree3f18f22e8c4bb88d503293af632ef0ac79e3762e /src/mongo/db/query
parent466fd9bf23cb4c694891d77af02b338353d32eb8 (diff)
downloadmongo-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.cpp109
-rw-r--r--src/mongo/db/query/find_and_modify_request.h9
-rw-r--r--src/mongo/db/query/find_and_modify_request_test.cpp34
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) {