diff options
author | Bernard Gorman <bernard.gorman@mongodb.com> | 2019-11-14 21:59:35 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-11-14 21:59:35 +0000 |
commit | 23e55cb3d041236f399f7095df31cd3e3da491cc (patch) | |
tree | 25bc309af51bc66dbd46922b0cf7560b3351478a /src/mongo/db/ops | |
parent | cdc44d95e169da75093f25c324aa9670e72743e8 (diff) | |
download | mongo-23e55cb3d041236f399f7095df31cd3e3da491cc.tar.gz |
SERVER-43860 Always upsert exact source document for pipeline-insert $merge
Diffstat (limited to 'src/mongo/db/ops')
-rw-r--r-- | src/mongo/db/ops/parsed_update.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/ops/update_request.h | 39 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops.idl | 5 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops_exec.cpp | 1 |
4 files changed, 44 insertions, 18 deletions
diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index 073ea2d4865..6c68a621d82 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -32,6 +32,7 @@ #include "mongo/db/ops/parsed_update.h" #include "mongo/db/ops/update_request.h" +#include "mongo/db/ops/write_ops_gen.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/collation/collator_factory_interface.h" #include "mongo/db/query/query_planner_common.h" @@ -53,6 +54,22 @@ Status ParsedUpdate::parseRequest() { // of a document during a multi-update. invariant(!(_request->shouldReturnAnyDocs() && _request->isMulti())); + // It is invalid to specify 'upsertSupplied:true' for a non-upsert operation, or if no upsert + // document was supplied with the request. + if (_request->shouldUpsertSuppliedDocument()) { + uassert(ErrorCodes::FailedToParse, + str::stream() << "cannot specify '" + << write_ops::UpdateOpEntry::kUpsertSuppliedFieldName + << ": true' for a non-upsert operation", + _request->isUpsert()); + const auto& constants = _request->getUpdateConstants(); + uassert(ErrorCodes::FailedToParse, + str::stream() << "the parameter '" + << write_ops::UpdateOpEntry::kUpsertSuppliedFieldName + << "' is set to 'true', but no document was supplied", + constants && (*constants)["new"_sd].type() == BSONType::Object); + } + // It is invalid to request that a ProjectionStage be applied to the UpdateStage if the // UpdateStage would not return any document. invariant(_request->getProj().isEmpty() || _request->shouldReturnAnyDocs()); diff --git a/src/mongo/db/ops/update_request.h b/src/mongo/db/ops/update_request.h index f946302c6b9..5fa0a561b7e 100644 --- a/src/mongo/db/ops/update_request.h +++ b/src/mongo/db/ops/update_request.h @@ -56,16 +56,7 @@ public: RETURN_NEW }; - inline UpdateRequest(const NamespaceString& nsString) - : _nsString(nsString), - _god(false), - _upsert(false), - _multi(false), - _fromMigration(false), - _fromOplogApplication(false), - _isExplain(false), - _returnDocs(ReturnDocOption::RETURN_NONE), - _yieldPolicy(PlanExecutor::NO_YIELD) {} + inline UpdateRequest(const NamespaceString& nsString) : _nsString(nsString) {} const NamespaceString& getNamespaceString() const { return _nsString; @@ -154,6 +145,14 @@ public: return _upsert; } + inline void setUpsertSuppliedDocument(bool value = true) { + _upsertSuppliedDocument = value; + } + + bool shouldUpsertSuppliedDocument() const { + return _upsertSuppliedDocument; + } + inline void setMulti(bool value = true) { _multi = value; } @@ -306,22 +305,26 @@ private: // God bypasses _id checking and index generation. It is only used on behalf of system // updates, never user updates. - bool _god; + bool _god = false; // True if this should insert if no matching document is found. - bool _upsert; + bool _upsert = false; + + // True if this upsert operation should insert the document supplied as 'c.new' if the query + // does not match any documents. + bool _upsertSuppliedDocument = false; // True if this update is allowed to affect more than one document. - bool _multi; + bool _multi = false; // True if this update is on behalf of a chunk migration. - bool _fromMigration; + bool _fromMigration = false; // True if this update was triggered by the application of an oplog entry. - bool _fromOplogApplication; + bool _fromOplogApplication = false; // Whether or not we are requesting an explained update. Explained updates are read-only. - bool _isExplain; + bool _isExplain = false; // Specifies which version of the documents to return, if any. // @@ -335,10 +338,10 @@ private: // // This allows findAndModify to execute an update and retrieve the resulting document // without another query before or after the update. - ReturnDocOption _returnDocs; + ReturnDocOption _returnDocs = ReturnDocOption::RETURN_NONE; // Whether or not the update should yield. Defaults to NO_YIELD. - PlanExecutor::YieldPolicy _yieldPolicy; + PlanExecutor::YieldPolicy _yieldPolicy = PlanExecutor::NO_YIELD; }; } // namespace mongo diff --git a/src/mongo/db/ops/write_ops.idl b/src/mongo/db/ops/write_ops.idl index 9409aa73041..42f86b1f481 100644 --- a/src/mongo/db/ops/write_ops.idl +++ b/src/mongo/db/ops/write_ops.idl @@ -127,6 +127,11 @@ structs: operation inserts only a single document." type: bool default: false + upsertSupplied: + description: "Only applicable when upsert is true. If set, and if no documents match + the query, the update subsystem will insert the document supplied as + 'c.new' rather than generating a new document from the update spec." + type: optionalBool collation: description: "Specifies the collation to use for the operation." type: object diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index 38da11a7d0e..3b1c09b6a62 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -724,6 +724,7 @@ static SingleWriteResult performSingleUpdateOpWithDupKeyRetry(OperationContext* request.setArrayFilters(write_ops::arrayFiltersOf(op)); request.setMulti(op.getMulti()); request.setUpsert(op.getUpsert()); + request.setUpsertSuppliedDocument(op.getUpsertSupplied()); request.setHint(op.getHint()); request.setYieldPolicy(opCtx->inMultiDocumentTransaction() ? PlanExecutor::INTERRUPT_ONLY |