diff options
author | David Storch <david.storch@mongodb.com> | 2020-04-09 17:24:32 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-04-15 22:31:32 +0000 |
commit | 9ca0c11865bba19999932a57069daed84a4577ca (patch) | |
tree | 29187df784139549f1f03e2f9dd7fdb805b2fe4b /src/mongo/db | |
parent | da349337d17dfa6bf5e92edac92045fab84e1742 (diff) | |
download | mongo-9ca0c11865bba19999932a57069daed84a4577ca.tar.gz |
SERVER-46810 Hex encode collation keys and invalid UTF-8 in dup key error messages
Also changes the error message to include the index's
collation, in order to help users interpret the collation
keys.
Diffstat (limited to 'src/mongo/db')
12 files changed, 167 insertions, 34 deletions
diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp index 49b69bc92d6..938e0261a86 100644 --- a/src/mongo/db/index/index_access_method.cpp +++ b/src/mongo/db/index/index_access_method.cpp @@ -653,7 +653,8 @@ Status AbstractIndexAccessMethod::commitBulk(OperationContext* opCtx, return buildDupKeyErrorStatus(dupKey.getOwned(), _descriptor->parentNS(), _descriptor->indexName(), - _descriptor->keyPattern()); + _descriptor->keyPattern(), + _descriptor->collation()); } } diff --git a/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp b/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp index 68bcb271f96..666bed4ea80 100644 --- a/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp +++ b/src/mongo/db/storage/biggie/biggie_sorted_impl.cpp @@ -195,7 +195,8 @@ SortedDataBuilderInterface::SortedDataBuilderInterface(OperationContext* opCtx, const std::string& identEnd, const NamespaceString& collectionNamespace, const std::string& indexName, - const BSONObj& keyPattern) + const BSONObj& keyPattern, + const BSONObj& collation) : _opCtx(opCtx), _unique(unique), _dupsAllowed(dupsAllowed), @@ -205,6 +206,7 @@ SortedDataBuilderInterface::SortedDataBuilderInterface(OperationContext* opCtx, _collectionNamespace(collectionNamespace), _indexName(indexName), _keyPattern(keyPattern), + _collation(collation), _hasLast(false), _lastKeyToString(""), _lastRID(-1) {} @@ -242,7 +244,8 @@ Status SortedDataBuilderInterface::addKey(const KeyString::Value& keyString) { if (twoKeyCmp == 0 && twoRIDCmp != 0) { if (!_dupsAllowed) { auto key = KeyString::toBson(keyString, _order); - return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern); + return buildDupKeyErrorStatus( + key, _collectionNamespace, _indexName, _keyPattern, _collation); } // Duplicate index entries are allowed on this unique index, so we put the RecordId in the // KeyString until the unique constraint is resolved. @@ -279,7 +282,8 @@ SortedDataBuilderInterface* SortedDataInterface::getBulkBuilder(OperationContext _identEnd, _collectionNamespace, _indexName, - _keyPattern); + _keyPattern, + _collation); } // We append \1 to all idents we get, and therefore the KeyString with ident + \0 will only be @@ -296,6 +300,7 @@ SortedDataInterface::SortedDataInterface(OperationContext* opCtx, _collectionNamespace(desc->getCollection()->ns()), _indexName(desc->indexName()), _keyPattern(desc->keyPattern()), + _collation(desc->collation()), _isUnique(desc->unique()), _isPartial(desc->isPartial()) { // This is the string representation of the KeyString before elements in this ident, which is @@ -355,7 +360,7 @@ Status SortedDataInterface::insert(OperationContext* opCtx, // dups were not allowed. auto key = KeyString::toBson(keyString, _ordering); return buildDupKeyErrorStatus( - key, _collectionNamespace, _indexName, _keyPattern); + key, _collectionNamespace, _indexName, _keyPattern, _collation); } } else { return Status::OK(); @@ -492,7 +497,7 @@ Status SortedDataInterface::dupKeyCheck(OperationContext* opCtx, const KeyString next->keyString.getSize()), key.getSize()) == 0) { return buildDupKeyErrorStatus( - key, _collectionNamespace, _indexName, _keyPattern, _ordering); + key, _collectionNamespace, _indexName, _keyPattern, _collation, _ordering); } return Status::OK(); diff --git a/src/mongo/db/storage/biggie/biggie_sorted_impl.h b/src/mongo/db/storage/biggie/biggie_sorted_impl.h index 559789df44e..96f0229197c 100644 --- a/src/mongo/db/storage/biggie/biggie_sorted_impl.h +++ b/src/mongo/db/storage/biggie/biggie_sorted_impl.h @@ -46,7 +46,8 @@ public: const std::string& identEnd, const NamespaceString& collectionNamespace, const std::string& indexName, - const BSONObj& keyPattern); + const BSONObj& keyPattern, + const BSONObj& collation); void commit(bool mayInterrupt) override; virtual Status addKey(const KeyString::Value& keyString); @@ -63,6 +64,7 @@ private: const NamespaceString _collectionNamespace; const std::string _indexName; const BSONObj _keyPattern; + const BSONObj _collation; // Whether or not we've already added something before. bool _hasLast; // This is the KeyString of the last key added. @@ -195,6 +197,7 @@ private: const NamespaceString _collectionNamespace; const std::string _indexName; const BSONObj _keyPattern; + const BSONObj _collation; // These are the keystring representations of the _prefix and the _identEnd. std::string _KSForIdentStart; std::string _KSForIdentEnd; diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp index 8eb549629e2..f3160e96033 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.cpp @@ -75,7 +75,8 @@ public: bool dupsAllowed, const NamespaceString& collectionNamespace, const std::string& indexName, - const BSONObj& keyPattern) + const BSONObj& keyPattern, + const BSONObj& collation) : _data(data), _currentKeySize(currentKeySize), _ordering(ordering), @@ -83,7 +84,8 @@ public: _comparator(_data->key_comp()), _collectionNamespace(collectionNamespace), _indexName(indexName), - _keyPattern(keyPattern) { + _keyPattern(keyPattern), + _collation(collation) { invariant(_data->empty()); } @@ -100,7 +102,8 @@ public: return Status(ErrorCodes::InternalError, "expected ascending (key, RecordId) order in bulk builder"); } else if (!_dupsAllowed && cmp == 0 && loc != _last->loc) { - return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern); + return buildDupKeyErrorStatus( + key, _collectionNamespace, _indexName, _keyPattern, _collation); } } @@ -133,6 +136,7 @@ private: const NamespaceString _collectionNamespace; const std::string _indexName; const BSONObj _keyPattern; + const BSONObj _collation; }; class EphemeralForTestBtreeImpl : public SortedDataInterface { @@ -142,13 +146,15 @@ public: bool isUnique, const NamespaceString& collectionNamespace, const std::string& indexName, - const BSONObj& keyPattern) + const BSONObj& keyPattern, + const BSONObj& collation) : SortedDataInterface(KeyString::Version::kLatestVersion, ordering), _data(data), _isUnique(isUnique), _collectionNamespace(collectionNamespace), _indexName(indexName), - _keyPattern(keyPattern) { + _keyPattern(keyPattern), + _collation(collation) { _currentKeySize = 0; } @@ -159,7 +165,8 @@ public: dupsAllowed, _collectionNamespace, _indexName, - _keyPattern); + _keyPattern, + _collation); } virtual Status insert(OperationContext* opCtx, @@ -172,7 +179,8 @@ public: // TODO optimization: save the iterator from the dup-check to speed up insert if (!dupsAllowed && keyExists(*_data, key)) - return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern); + return buildDupKeyErrorStatus( + key, _collectionNamespace, _indexName, _keyPattern, _collation); IndexKeyEntry entry(key.getOwned(), loc); if (_data->insert(entry).second) { @@ -240,7 +248,8 @@ public: Status _dupKeyCheck(OperationContext* opCtx, const BSONObj& key) { invariant(!key.hasFieldNames()); if (isDup(*_data, key)) - return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern); + return buildDupKeyErrorStatus( + key, _collectionNamespace, _indexName, _keyPattern, _collation); return Status::OK(); } @@ -618,6 +627,7 @@ private: const NamespaceString _collectionNamespace; const std::string _indexName; const BSONObj _keyPattern; + const BSONObj _collation; }; } // namespace @@ -629,6 +639,7 @@ std::unique_ptr<SortedDataInterface> getEphemeralForTestBtreeImpl( const NamespaceString& collectionNamespace, const std::string& indexName, const BSONObj& keyPattern, + const BSONObj& collation, std::shared_ptr<void>* dataInOut) { invariant(dataInOut); if (!*dataInOut) { @@ -639,7 +650,8 @@ std::unique_ptr<SortedDataInterface> getEphemeralForTestBtreeImpl( isUnique, collectionNamespace, indexName, - keyPattern); + keyPattern, + collation); } } // namespace mongo diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.h b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.h index 60431c1cfa7..fe570288cec 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.h +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl.h @@ -46,6 +46,7 @@ std::unique_ptr<SortedDataInterface> getEphemeralForTestBtreeImpl( const NamespaceString& collectionNamespace, const std::string& indexName, const BSONObj& keyPattern, + const BSONObj& collation, std::shared_ptr<void>* dataInOut); } // namespace mongo diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl_test.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl_test.cpp index bcd0a0ebc32..32895759022 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl_test.cpp +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_btree_impl_test.cpp @@ -57,6 +57,7 @@ public: NamespaceString("test.EphemeralForTest"), "indexName", spec, + BSONObj{}, &_data)); } @@ -66,7 +67,8 @@ public: unique, NamespaceString("test.EphemeralForTest"), "indexName", - BSONObj(), + BSONObj{}, + BSONObj{}, &_data)); } diff --git a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_engine.cpp b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_engine.cpp index 7e0974a8e4f..490635f37f1 100644 --- a/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_engine.cpp +++ b/src/mongo/db/storage/ephemeral_for_test/ephemeral_for_test_engine.cpp @@ -106,6 +106,7 @@ std::unique_ptr<SortedDataInterface> EphemeralForTestEngine::getSortedDataInterf desc->parentNS(), desc->indexName(), desc->keyPattern(), + desc->collation(), &_dataMap[ident]); } diff --git a/src/mongo/db/storage/index_entry_comparison.cpp b/src/mongo/db/storage/index_entry_comparison.cpp index fb817e93a0f..86e0e502290 100644 --- a/src/mongo/db/storage/index_entry_comparison.cpp +++ b/src/mongo/db/storage/index_entry_comparison.cpp @@ -36,6 +36,8 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/storage/duplicate_key_error_info.h" #include "mongo/db/storage/key_string.h" +#include "mongo/util/hex.h" +#include "mongo/util/text.h" namespace mongo { @@ -177,14 +179,29 @@ KeyString::Value IndexEntryComparison::makeKeyStringFromBSONKeyForSeek(const BSO Status buildDupKeyErrorStatus(const BSONObj& key, const NamespaceString& collectionNamespace, const std::string& indexName, - const BSONObj& keyPattern) { + const BSONObj& keyPattern, + const BSONObj& indexCollation) { + const bool hasCollation = !indexCollation.isEmpty(); + StringBuilder sb; sb << "E11000 duplicate key error"; sb << " collection: " << collectionNamespace; sb << " index: " << indexName; + if (hasCollation) { + sb << " collation: " << indexCollation; + } sb << " dup key: "; - BSONObjBuilder builder; + // For the purpose of producing a useful error message, generate a representation of the key + // with field names hydrated and with invalid UTF-8 hex-encoded. + BSONObjBuilder builderForErrmsg; + + // Used to build a version of the key after hydrating with field names but without hex encoding + // invalid UTF-8. This key is attached to the extra error info and consumed by callers who may + // wish to retry on duplicate key errors. The field names are rehydrated so that we don't return + // BSON with duplicate key names to clients. + BSONObjBuilder builderForErrorExtraInfo; + // key is a document with forms like: '{ : 123}', '{ : {num: 123} }', '{ : 123, : "str" }' BSONObjIterator keyValueIt(key); // keyPattern is a document with only one level. e.g. '{a : 1, b : -1}', '{a.b : 1}' @@ -197,23 +214,45 @@ Status buildDupKeyErrorStatus(const BSONObj& key, if (keyNameElem.eoo()) break; - builder.appendAs(keyValueElem, keyNameElem.fieldName()); + builderForErrorExtraInfo.appendAs(keyValueElem, keyNameElem.fieldName()); + + // If the duplicate key value contains a string, then it's possible that the string contains + // binary data which is not valid UTF-8. This is true for all indexes with a collation, + // since the index stores collation keys rather than raw user strings. But it's also + // possible that the application has stored binary data inside a string, which the system + // has never rejected. + // + // If the string in the key is invalid UTF-8, then we hex encode it before adding it to the + // error message so that the driver can assume valid UTF-8 when reading the reply. + const bool shouldHexEncode = keyValueElem.type() == BSONType::String && + (hasCollation || !isValidUTF8(keyValueElem.valueStringData())); + + if (shouldHexEncode) { + auto stringToEncode = keyValueElem.valueStringData(); + builderForErrmsg.append( + keyNameElem.fieldName(), + str::stream() << "0x" + << toHexLower(stringToEncode.rawData(), stringToEncode.size())); + } else { + builderForErrmsg.appendAs(keyValueElem, keyNameElem.fieldName()); + } } - auto keyValueWithName = builder.obj(); - sb << keyValueWithName; - return Status(DuplicateKeyErrorInfo(keyPattern, keyValueWithName), sb.str()); + sb << builderForErrmsg.obj(); + + return Status(DuplicateKeyErrorInfo(keyPattern, builderForErrorExtraInfo.obj()), sb.str()); } Status buildDupKeyErrorStatus(const KeyString::Value& keyString, const NamespaceString& collectionNamespace, const std::string& indexName, const BSONObj& keyPattern, + const BSONObj& indexCollation, const Ordering& ordering) { const BSONObj key = KeyString::toBson( keyString.getBuffer(), keyString.getSize(), ordering, keyString.getTypeBits()); - return buildDupKeyErrorStatus(key, collectionNamespace, indexName, keyPattern); + return buildDupKeyErrorStatus(key, collectionNamespace, indexName, keyPattern, indexCollation); } } // namespace mongo diff --git a/src/mongo/db/storage/index_entry_comparison.h b/src/mongo/db/storage/index_entry_comparison.h index 802e5d4e489..ad4bbbc8aa6 100644 --- a/src/mongo/db/storage/index_entry_comparison.h +++ b/src/mongo/db/storage/index_entry_comparison.h @@ -258,7 +258,8 @@ private: Status buildDupKeyErrorStatus(const BSONObj& key, const NamespaceString& collectionNamespace, const std::string& indexName, - const BSONObj& keyPattern); + const BSONObj& keyPattern, + const BSONObj& indexCollation); /** * Returns the formatted error status about the duplicate KeyString. @@ -267,6 +268,7 @@ Status buildDupKeyErrorStatus(const KeyString::Value& keyString, const NamespaceString& collectionNamespace, const std::string& indexName, const BSONObj& keyPattern, + const BSONObj& indexCollation, const Ordering& ordering); } // namespace mongo diff --git a/src/mongo/db/storage/index_entry_comparison_test.cpp b/src/mongo/db/storage/index_entry_comparison_test.cpp index 0cfd6b830fc..5ef646b36e0 100644 --- a/src/mongo/db/storage/index_entry_comparison_test.cpp +++ b/src/mongo/db/storage/index_entry_comparison_test.cpp @@ -32,6 +32,7 @@ #include "mongo/db/storage/duplicate_key_error_info.h" #include "mongo/db/storage/index_entry_comparison.h" #include "mongo/unittest/unittest.h" +#include "mongo/util/hex.h" namespace mongo { @@ -42,7 +43,7 @@ TEST(IndexEntryComparison, BuildDupKeyErrorStatusProducesExpectedErrorObject) { auto keyValue = BSON("" << 10 << "" << "abc"); - auto dupKeyStatus = buildDupKeyErrorStatus(keyValue, collNss, indexName, keyPattern); + auto dupKeyStatus = buildDupKeyErrorStatus(keyValue, collNss, indexName, keyPattern, BSONObj{}); ASSERT_NOT_OK(dupKeyStatus); ASSERT_EQUALS(dupKeyStatus.code(), ErrorCodes::DuplicateKey); @@ -61,4 +62,59 @@ TEST(IndexEntryComparison, BuildDupKeyErrorStatusProducesExpectedErrorObject) { BSON("keyPattern" << keyPattern << "keyValue" << keyValueWithFieldName)); } +TEST(IndexEntryComparison, BuildDupKeyErrorMessageIncludesCollationAndHexEncodedCollationKey) { + StringData mockCollationKey("bar"); + + NamespaceString collNss("test.foo"); + std::string indexName("a_1"); + auto keyPattern = BSON("a" << 1); + auto keyValue = BSON("" << mockCollationKey); + auto collation = BSON("locale" + << "en_US"); + + auto dupKeyStatus = buildDupKeyErrorStatus(keyValue, collNss, indexName, keyPattern, collation); + ASSERT_NOT_OK(dupKeyStatus); + ASSERT_EQUALS(dupKeyStatus.code(), ErrorCodes::DuplicateKey); + + ASSERT(dupKeyStatus.reason().find("collation:") != std::string::npos); + + // Verify that the collation key is hex encoded in the error message. + std::string expectedHexEncoding = + "0x" + toHexLower(mockCollationKey.rawData(), mockCollationKey.size()); + ASSERT(dupKeyStatus.reason().find(expectedHexEncoding) != std::string::npos); + + // But no hex encoding should have taken place inside the key attached to the extra error info. + auto extraInfo = dupKeyStatus.extraInfo<DuplicateKeyErrorInfo>(); + ASSERT(extraInfo); + ASSERT_BSONOBJ_EQ(extraInfo->getKeyPattern(), keyPattern); + ASSERT_BSONOBJ_EQ(extraInfo->getDuplicatedKeyValue(), BSON("a" << mockCollationKey)); +} + +TEST(IndexEntryComparison, BuildDupKeyErrorMessageHexEncodesInvalidUTF8ForIndexWithoutCollation) { + NamespaceString collNss("test.foo"); + std::string indexName("a_1"); + auto keyPattern = BSON("a" << 1); + + // The byte sequence c0 16 is invalid UTF-8 since this is an overlong encoding of the letter + // "a", which should be represented as simply 0x16. The byte 0xc0 is always illegal in UTF-8 + // since it would only ever be used for an overload two-byte encoding of an ASCII character. + auto keyValue = BSON("" + << "\xc0\x16"); + auto dupKeyStatus = buildDupKeyErrorStatus(keyValue, collNss, indexName, keyPattern, BSONObj{}); + ASSERT_NOT_OK(dupKeyStatus); + ASSERT_EQUALS(dupKeyStatus.code(), ErrorCodes::DuplicateKey); + + // We expect to find a hex-encoded version of the illegal UTF-8 byte sequence inside the error + // string. + ASSERT(dupKeyStatus.reason().find("0xc016") != std::string::npos); + + // In the extra error info, we expect that no hex encoding has taken place. + auto extraInfo = dupKeyStatus.extraInfo<DuplicateKeyErrorInfo>(); + ASSERT(extraInfo); + ASSERT_BSONOBJ_EQ(extraInfo->getKeyPattern(), keyPattern); + ASSERT_BSONOBJ_EQ(extraInfo->getDuplicatedKeyValue(), + BSON("a" + << "\xc0\x16")); +} + } // namespace mongo diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp index 137fb2cb52d..6339021a1b5 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.cpp @@ -245,6 +245,7 @@ WiredTigerIndex::WiredTigerIndex(OperationContext* ctx, _collectionNamespace(desc->parentNS()), _indexName(desc->indexName()), _keyPattern(desc->keyPattern()), + _collation(desc->collation()), _prefix(prefix), _isIdIndex(desc->isIdIndex()) {} @@ -380,7 +381,7 @@ Status WiredTigerIndex::dupKeyCheck(OperationContext* opCtx, const KeyString::Va if (isDup(opCtx, c, key)) return buildDupKeyErrorStatus( - key, _collectionNamespace, _indexName, _keyPattern, _ordering); + key, _collectionNamespace, _indexName, _keyPattern, _collation, _ordering); return Status::OK(); } @@ -699,8 +700,11 @@ private: if (cmp == 0) { // Duplicate found! auto newKey = KeyString::toBson(newKeyString, _idx->_ordering); - return buildDupKeyErrorStatus( - newKey, _idx->collectionNamespace(), _idx->indexName(), _idx->keyPattern()); + return buildDupKeyErrorStatus(newKey, + _idx->collectionNamespace(), + _idx->indexName(), + _idx->keyPattern(), + _idx->_collation); } else { /* * _previousKeyString.isEmpty() is only true on the first call to addKey(). @@ -744,8 +748,11 @@ private: // Dup found! if (!_dupsAllowed) { auto newKey = KeyString::toBson(newKeyString, _idx->_ordering); - return buildDupKeyErrorStatus( - newKey, _idx->collectionNamespace(), _idx->indexName(), _idx->keyPattern()); + return buildDupKeyErrorStatus(newKey, + _idx->collectionNamespace(), + _idx->indexName(), + _idx->keyPattern(), + _idx->_collation); } // If we get here, we are in the weird mode where dups are allowed on a unique @@ -1526,7 +1533,8 @@ Status WiredTigerIndexUnique::_insertTimestampUnsafe(OperationContext* opCtx, if (!dupsAllowed) { auto key = KeyString::toBson(keyString, _ordering); - return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern); + return buildDupKeyErrorStatus( + key, _collectionNamespace, _indexName, _keyPattern, _collation); } if (!insertedId) { @@ -1572,7 +1580,8 @@ Status WiredTigerIndexUnique::_insertTimestampSafe(OperationContext* opCtx, if (ret == WT_DUPLICATE_KEY) { auto key = KeyString::toBson( keyString.getBuffer(), sizeWithoutRecordId, _ordering, keyString.getTypeBits()); - return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern); + return buildDupKeyErrorStatus( + key, _collectionNamespace, _indexName, _keyPattern, _collation); } invariantWTOK(ret); @@ -1587,7 +1596,8 @@ Status WiredTigerIndexUnique::_insertTimestampSafe(OperationContext* opCtx, if (_keyExists(opCtx, c, keyString.getBuffer(), sizeWithoutRecordId)) { auto key = KeyString::toBson( keyString.getBuffer(), sizeWithoutRecordId, _ordering, keyString.getTypeBits()); - return buildDupKeyErrorStatus(key, _collectionNamespace, _indexName, _keyPattern); + return buildDupKeyErrorStatus( + key, _collectionNamespace, _indexName, _keyPattern, _collation); } } diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_index.h b/src/mongo/db/storage/wiredtiger/wiredtiger_index.h index 5fefad39b92..dddf3dc054c 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_index.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_index.h @@ -183,6 +183,7 @@ protected: const NamespaceString _collectionNamespace; const std::string _indexName; const BSONObj _keyPattern; + const BSONObj _collation; KVPrefix _prefix; bool _isIdIndex; }; |