diff options
Diffstat (limited to 'src/mongo/db/update')
| -rw-r--r-- | src/mongo/db/update/addtoset_node.cpp | 5 | ||||
| -rw-r--r-- | src/mongo/db/update/addtoset_node_test.cpp | 17 | ||||
| -rw-r--r-- | src/mongo/db/update/document_diff_calculator_test.cpp | 11 | ||||
| -rw-r--r-- | src/mongo/db/update/document_diff_serialization.cpp | 4 | ||||
| -rw-r--r-- | src/mongo/db/update/object_replace_executor.cpp | 17 | ||||
| -rw-r--r-- | src/mongo/db/update/object_replace_executor.h | 9 | ||||
| -rw-r--r-- | src/mongo/db/update/pipeline_executor.cpp | 4 | ||||
| -rw-r--r-- | src/mongo/db/update/pipeline_executor.h | 7 | ||||
| -rw-r--r-- | src/mongo/db/update/pipeline_executor_test.cpp | 40 | ||||
| -rw-r--r-- | src/mongo/db/update/storage_validation.cpp | 33 | ||||
| -rw-r--r-- | src/mongo/db/update/update_driver.cpp | 9 | ||||
| -rw-r--r-- | src/mongo/db/update/update_driver.h | 9 | ||||
| -rw-r--r-- | src/mongo/db/update/update_driver_test.cpp | 9 | ||||
| -rw-r--r-- | src/mongo/db/update/update_executor.h | 4 |
14 files changed, 37 insertions, 141 deletions
diff --git a/src/mongo/db/update/addtoset_node.cpp b/src/mongo/db/update/addtoset_node.cpp index 824f6943c8e..f7b821815d1 100644 --- a/src/mongo/db/update/addtoset_node.cpp +++ b/src/mongo/db/update/addtoset_node.cpp @@ -85,10 +85,7 @@ Status AddToSetNode::init(BSONElement modExpr, str::stream() << "Found unexpected fields after $each in $addToSet: " << modExpr.Obj()); } - - // We call 'ArrayVerifyIndexes' to uassert in the event that 'firstElement' is a - // BSONArray with invalid indexes. - _elements = firstElement.ArrayVerifyIndexes(); + _elements = firstElement.Array(); } } diff --git a/src/mongo/db/update/addtoset_node_test.cpp b/src/mongo/db/update/addtoset_node_test.cpp index f590c7140dc..d2b7f90be65 100644 --- a/src/mongo/db/update/addtoset_node_test.cpp +++ b/src/mongo/db/update/addtoset_node_test.cpp @@ -99,23 +99,6 @@ TEST(AddToSetNodeTest, InitSucceedsWithArray) { ASSERT_OK(node.init(update["$addToSet"]["a"], expCtx)); } -TEST(AddToSetNodeTest, InitFailsWhenArgumentIsInvalidBSONArray) { - // Create our invalid array by creating a BSONObj with non contiguous array indexes that is then - // passed to the BSONArray ctor. - BSONObj updateArrAsObj = BSON("0" - << "foo" - << "2" - << "bar"); - BSONArray updateArr(updateArrAsObj); - - auto update = BSON("$addToSet" << BSON("fieldName" << BSON("$each" << updateArr))); - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - AddToSetNode node; - - ASSERT_THROWS(node.init(update["$addToSet"]["fieldName"], expCtx), - ExceptionFor<ErrorCodes::BadValue>); -} - TEST(AddToSetNodeTest, InitSucceedsWithScaler) { auto update = fromjson("{$addToSet: {a: 1}}"); boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); diff --git a/src/mongo/db/update/document_diff_calculator_test.cpp b/src/mongo/db/update/document_diff_calculator_test.cpp index 5c83ac027c8..55a05051021 100644 --- a/src/mongo/db/update/document_diff_calculator_test.cpp +++ b/src/mongo/db/update/document_diff_calculator_test.cpp @@ -32,7 +32,6 @@ #include <functional> #include "mongo/bson/bson_depth.h" -#include "mongo/bson/bson_validate.h" #include "mongo/bson/json.h" #include "mongo/db/update/document_diff_calculator.h" #include "mongo/unittest/unittest.h" @@ -296,7 +295,7 @@ TEST(DocumentDiffCalculatorTest, DeeplyNestObjectGenerateDiff) { preBob.append("largeField", largeValue); buildDeepObj(&preBob, "subObj", 0, maxDepth, functionToApply); auto preObj = preBob.done(); - ASSERT(validateBSON(preObj).isOK()); + ASSERT(preObj.valid()); BSONObjBuilder postBob; postBob.append("largeField", largeValue); @@ -313,7 +312,7 @@ TEST(DocumentDiffCalculatorTest, DeeplyNestObjectGenerateDiff) { // Deleting the deepest field should give the post object. diffOutput = doc_diff::computeDiff(preObj, postBob2.done(), 0, nullptr); ASSERT(diffOutput); - ASSERT_OK(validateBSON(diffOutput->diff)); + ASSERT(diffOutput->diff.valid()); BSONObjBuilder expectedOutputBuilder; buildDeepObj(&expectedOutputBuilder, @@ -342,17 +341,17 @@ TEST(DocumentDiffCalculatorTest, DeepestObjectSubDiff) { value = 1; buildDeepObj(&bob1, "subObj", 0, BSONDepth::getMaxDepthForUserStorage(), functionToApply); auto preObj = bob1.done(); - ASSERT_OK(validateBSON(preObj)); + ASSERT(preObj.valid()); BSONObjBuilder postBob; value = 2; buildDeepObj(&postBob, "subObj", 0, BSONDepth::getMaxDepthForUserStorage(), functionToApply); auto postObj = postBob.done(); - ASSERT_OK(validateBSON(postObj)); + ASSERT(postObj.valid()); auto diffOutput = doc_diff::computeDiff(preObj, postObj, 0, nullptr); ASSERT(diffOutput); - ASSERT_OK(validateBSON(diffOutput->diff)); + ASSERT(diffOutput->diff.valid()); BSONObjBuilder expectedOutputBuilder; buildDeepObj(&expectedOutputBuilder, diff --git a/src/mongo/db/update/document_diff_serialization.cpp b/src/mongo/db/update/document_diff_serialization.cpp index db3d4520e49..0f5533e1d06 100644 --- a/src/mongo/db/update/document_diff_serialization.cpp +++ b/src/mongo/db/update/document_diff_serialization.cpp @@ -80,9 +80,7 @@ Node* DocumentSubDiffNode::addChild(StringData fieldName, std::unique_ptr<Node> sizeTracker.addEntry(fieldName.size(), nodePtr); auto result = children.insert({fieldName.toString(), std::move(node)}); - uassert(7693400, - str::stream() << "Document already has a field named '" << fieldName << "'", - result.second); + invariant(result.second); StringData storedFieldName = result.first->first; switch (nodePtr->type()) { case (NodeType::kArray): diff --git a/src/mongo/db/update/object_replace_executor.cpp b/src/mongo/db/update/object_replace_executor.cpp index 205b270a8ca..e2d9262e001 100644 --- a/src/mongo/db/update/object_replace_executor.cpp +++ b/src/mongo/db/update/object_replace_executor.cpp @@ -45,24 +45,19 @@ namespace { constexpr StringData kIdFieldName = "_id"_sd; } // namespace -ObjectReplaceExecutor::ObjectReplaceExecutor(BSONObj replacement, bool bypassEmptyTsReplacement) - : _replacementDoc(replacement.getOwned()), - _containsId(false), - _bypassEmptyTsReplacement(bypassEmptyTsReplacement) { - // Check for the existence of the "_id" field, and if approrpriate replace all zero-valued - // timestamps with the current time. +ObjectReplaceExecutor::ObjectReplaceExecutor(BSONObj replacement) + : _replacementDoc(replacement.getOwned()), _containsId(false) { + + // Replace all zero-valued timestamps with the current time and check for the existence of _id. for (auto&& elem : _replacementDoc) { + // Do not change the _id field. if (elem.fieldNameStringData() == kIdFieldName) { _containsId = true; continue; } - // For updates that originated from the oplog, we're required to apply the update - // exactly as it was recorded (even if it contains zero-valued timestamps). Therefore, - // we should only replace zero-valued timestamps with the current time when - // '_bypassEmptyTsReplacement' is false. - if (!_bypassEmptyTsReplacement && elem.type() == BSONType::bsonTimestamp) { + if (elem.type() == BSONType::bsonTimestamp) { auto timestampView = DataView(const_cast<char*>(elem.value())); // We don't need to do an endian-safe read here, because 0 is 0 either way. diff --git a/src/mongo/db/update/object_replace_executor.h b/src/mongo/db/update/object_replace_executor.h index 3f4c787e588..f9c70bde919 100644 --- a/src/mongo/db/update/object_replace_executor.h +++ b/src/mongo/db/update/object_replace_executor.h @@ -65,11 +65,10 @@ public: bool allowTopLevelDollarPrefixedFields = false); /** - * Initializes the node with the document to replace with. If 'bypassEmptyTsReplacement' is - * false, any zero-valued timestamps (except for the _id) will be replaced with the current - * time. + * Initializes the node with the document to replace with. Any zero-valued timestamps (except + * for the _id) are updated to the current time. */ - explicit ObjectReplaceExecutor(BSONObj replacement, bool bypassEmptyTsReplacement = false); + explicit ObjectReplaceExecutor(BSONObj replacement); /** * Replaces the document that 'applyParams.element' belongs to with 'val'. If 'val' does not @@ -96,8 +95,6 @@ private: // True if '_replacementDoc' contains an _id. bool _containsId; - - bool _bypassEmptyTsReplacement = false; }; } // namespace mongo diff --git a/src/mongo/db/update/pipeline_executor.cpp b/src/mongo/db/update/pipeline_executor.cpp index 7d99b3aecb3..710803d6b04 100644 --- a/src/mongo/db/update/pipeline_executor.cpp +++ b/src/mongo/db/update/pipeline_executor.cpp @@ -87,10 +87,6 @@ PipelineExecutor::PipelineExecutor(const boost::intrusive_ptr<ExpressionContext> invariant(stageConstraints.requiredPosition == StageConstraints::PositionRequirement::kNone); invariant(!stageConstraints.isIndependentOfAnyCollection); - - if (stageConstraints.checkExistenceForDiffInsertOperations) { - _checkExistenceForDiffInsertOperations = true; - } } _pipeline->addInitialSource(DocumentSourceQueue::create(expCtx)); diff --git a/src/mongo/db/update/pipeline_executor.h b/src/mongo/db/update/pipeline_executor.h index 7569005de7d..e0b16b851c2 100644 --- a/src/mongo/db/update/pipeline_executor.h +++ b/src/mongo/db/update/pipeline_executor.h @@ -64,14 +64,7 @@ public: Value serialize() const final; - bool getCheckExistenceForDiffInsertOperations() const override final { - return _checkExistenceForDiffInsertOperations; - } - private: - // Sets to true if the pipeline contains '$_internalApplyOplogUpdate'. - bool _checkExistenceForDiffInsertOperations = false; - boost::intrusive_ptr<ExpressionContext> _expCtx; std::unique_ptr<Pipeline, PipelineDeleter> _pipeline; }; diff --git a/src/mongo/db/update/pipeline_executor_test.cpp b/src/mongo/db/update/pipeline_executor_test.cpp index d237dd4f78e..c650e06749d 100644 --- a/src/mongo/db/update/pipeline_executor_test.cpp +++ b/src/mongo/db/update/pipeline_executor_test.cpp @@ -719,45 +719,5 @@ TEST_F(PipelineExecutorV2ModeTest, TestIndexesAffectedWithArraysAfterIndexPath) } } -/** - * Verifies the fix for SERVER-76934 in the case where the original document has a duplicate field. - */ -TEST_F(PipelineExecutorV2ModeTest, TestIndexesAffectedWithArraysAfterIndexPath1) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - BSONObj preImage( - fromjson("{f1: {paddingField: 'largeValueString'}, k: {c: 1, c: 2, paddingField: " - "'largeValueString'}}")); - - auto doc = mutablebson::Document(preImage); - const std::vector<BSONObj> pipeline{ - fromjson("{$replaceWith: {$literal: {f1: {paddingField: 'largeValueString'}, k: {c: 4, " - "paddingField: 'largeValueString'}} }}")}; - PipelineExecutor exec(expCtx, pipeline); - ASSERT_THROWS_CODE_AND_WHAT(exec.applyUpdate(getApplyParams(doc.root())), - AssertionException, - 7693400, - "Document already has a field named 'c'"); -} - -/** - * Verifies the fix for SERVER-76934 in the case where the pipeline tries to add a duplicate field. - */ -TEST_F(PipelineExecutorV2ModeTest, TestIndexesAffectedWithArraysAfterIndexPath2) { - boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - BSONObj preImage( - fromjson("{f1: {paddingField: 'largeValueString'}, k: {c: 1, paddingField: " - "'largeValueString'}}")); - - auto doc = mutablebson::Document(preImage); - const std::vector<BSONObj> pipeline{ - fromjson("{$replaceWith: {$literal: {f1: {paddingField: 'largeValueString'}, k: {c: 4, c: " - "5, paddingField: 'largeValueString'}} }}")}; - PipelineExecutor exec(expCtx, pipeline); - ASSERT_THROWS_CODE_AND_WHAT(exec.applyUpdate(getApplyParams(doc.root())), - AssertionException, - 7693400, - "Document already has a field named 'c'"); -} - } // namespace } // namespace mongo diff --git a/src/mongo/db/update/storage_validation.cpp b/src/mongo/db/update/storage_validation.cpp index 69967c14aef..d94c645a588 100644 --- a/src/mongo/db/update/storage_validation.cpp +++ b/src/mongo/db/update/storage_validation.cpp @@ -160,30 +160,19 @@ void scanDocument(const mutablebson::Document& doc, auto currElem = doc.root().leftChild(); while (currElem.ok()) { if (currElem.getFieldName() == idFieldName && shouldValidate) { - if (currElem.getType() == BSONType::Object) { - // We need to recursively validate the _id field while ensuring we disallow - // top-level $-prefix fields in the _id object. - scanDocument(currElem, - true /* deep */, - 0 /* recursionLevel - forces _id fields to be treated as top-level. */, - false /* Top-level _id fields cannot be $-prefixed. */, - shouldValidate, - containsDotsAndDollarsField); - } else { - uassertStatusOK(storageValidIdField(currElem.getValue())); - } - } else { - // Validate this child element. - const auto deep = true; - const uint32_t recursionLevel = 1; - scanDocument(currElem, - deep, - recursionLevel, - allowTopLevelDollarPrefixes, - shouldValidate, - containsDotsAndDollarsField); + uassertStatusOK(storageValidIdField(currElem.getValue())); } + // Validate this child element. + const auto deep = true; + const uint32_t recursionLevel = 1; + scanDocument(currElem, + deep, + recursionLevel, + allowTopLevelDollarPrefixes, + shouldValidate, + containsDotsAndDollarsField); + currElem = currElem.rightSibling(); } } diff --git a/src/mongo/db/update/update_driver.cpp b/src/mongo/db/update/update_driver.cpp index 9839487da9d..5ce9dc8aa84 100644 --- a/src/mongo/db/update/update_driver.cpp +++ b/src/mongo/db/update/update_driver.cpp @@ -159,14 +159,7 @@ void UpdateDriver::parse( "multi update is not supported for replacement-style update", !multi); - // For updates that originated from the oplog, we're required to apply the update - // exactly as it was recorded (even if it contains zero-valued timestamps). Therefore, - // we should only replace zero-valued timestamps with the current time when both - // '_bypassEmptyTsReplacement' and '_fromOplogApplication' are false. - const bool bypassEmptyTsReplacement = _bypassEmptyTsReplacement || _fromOplogApplication; - - _updateExecutor = std::make_unique<ObjectReplaceExecutor>(updateMod.getUpdateReplacement(), - bypassEmptyTsReplacement); + _updateExecutor = std::make_unique<ObjectReplaceExecutor>(updateMod.getUpdateReplacement()); // Register the fact that this driver will only do full object replacements. _updateType = UpdateType::kReplacement; diff --git a/src/mongo/db/update/update_driver.h b/src/mongo/db/update/update_driver.h index 9949f43787c..94d1f73c8d4 100644 --- a/src/mongo/db/update/update_driver.h +++ b/src/mongo/db/update/update_driver.h @@ -195,13 +195,6 @@ public: _containsDotsAndDollarsField = containsDotsAndDollarsField; } - bool bypassEmptyTsReplacement() const { - return _bypassEmptyTsReplacement; - } - void setBypassEmptyTsReplacement(bool bypassEmptyTsReplacement) { - _bypassEmptyTsReplacement = bypassEmptyTsReplacement; - } - /** * Serialize the update expression to Value. Output of this method is expected to, when parsed, * produce a logically equivalent update expression. @@ -245,8 +238,6 @@ private: // True if this update comes from an oplog application. bool _fromOplogApplication = false; - bool _bypassEmptyTsReplacement = false; - // True if this update is guaranteed not to contain dots or dollars fields and should skip the // check. bool _skipDotsDollarsCheck = false; diff --git a/src/mongo/db/update/update_driver_test.cpp b/src/mongo/db/update/update_driver_test.cpp index 86f6ae492bf..2d03e4b7886 100644 --- a/src/mongo/db/update/update_driver_test.cpp +++ b/src/mongo/db/update/update_driver_test.cpp @@ -46,6 +46,15 @@ #include "mongo/db/update_index_data.h" #include "mongo/unittest/unittest.h" +#define ASSERT_DOES_NOT_THROW(EXPRESSION) \ + try { \ + EXPRESSION; \ + } catch (const AssertionException& e) { \ + ::mongo::str::stream err; \ + err << "Threw an exception incorrectly: " << e.toString(); \ + ::mongo::unittest::TestAssertionFailure(__FILE__, __LINE__, err).stream(); \ + } + namespace mongo { namespace { diff --git a/src/mongo/db/update/update_executor.h b/src/mongo/db/update/update_executor.h index a5f964e76ac..539f044432b 100644 --- a/src/mongo/db/update/update_executor.h +++ b/src/mongo/db/update/update_executor.h @@ -136,10 +136,6 @@ public: virtual void setCollator(const CollatorInterface* collator){}; - virtual bool getCheckExistenceForDiffInsertOperations() const { - return false; - } - /** * Applies the update to 'applyParams.element'. Returns an ApplyResult specifying whether the * operation was a no-op and whether indexes are affected. |
