From 9034b668f90feb5a0f1ac9fd2a8714ecbe4cd057 Mon Sep 17 00:00:00 2001 From: Arun Banala Date: Wed, 30 Oct 2019 15:49:38 +0000 Subject: SERVER-44050 Arrays are not correctly rejected during key generation for 'hashed' indexes (cherry picked from commit 888f7e6fc10ccb999be203b8cbad4dbe19d0a5d2) --- jstests/core/hashindex1.js | 10 ++++++++++ src/mongo/db/index/expression_keys_private.cpp | 20 ++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/jstests/core/hashindex1.js b/jstests/core/hashindex1.js index 93986ecfd5e..09a1e1f7b47 100644 --- a/jstests/core/hashindex1.js +++ b/jstests/core/hashindex1.js @@ -87,3 +87,13 @@ var total = t.find().hint({"_id": 1}).toArray().length; var totala = t.find().hint(goodspec).toArray().length; assert.eq(total, totala, "non-sparse index has wrong total"); assert.lt(totalb, totala, "sparse index should have smaller total"); + +// Test that having arrays along the path of the index is not allowed. +assert.commandWorked(t.createIndex({"field1.field2.0.field4": "hashed"})); +assert.writeErrorWithCode(t.insert({field1: []}), 16766); +assert.writeErrorWithCode(t.insert({field1: {field2: []}}), 16766); +assert.writeErrorWithCode(t.insert({field1: {field2: {0: []}}}), 16766); +assert.writeErrorWithCode(t.insert({field1: [{field2: {0: []}}]}), 16766); +assert.writeErrorWithCode(t.insert({field1: {field2: {0: {field4: []}}}}), 16766); +assert.writeOK(t.insert({field1: {field2: {0: {otherField: []}}}})); +assert.writeOK(t.insert({field1: {field2: {0: {field4: 1}}}})); diff --git a/src/mongo/db/index/expression_keys_private.cpp b/src/mongo/db/index/expression_keys_private.cpp index 9fe3365f393..0a4cd2e42ed 100644 --- a/src/mongo/db/index/expression_keys_private.cpp +++ b/src/mongo/db/index/expression_keys_private.cpp @@ -361,7 +361,18 @@ void ExpressionKeysPrivate::getHashKeys(const BSONObj& obj, const CollatorInterface* collator, BSONObjSet* keys) { const char* cstr = hashedField.c_str(); - BSONElement fieldVal = dps::extractElementAtPath(obj, cstr); + BSONElement fieldVal = dps::extractElementAtPathOrArrayAlongPath(obj, cstr); + + // If we hit an array while traversing the path, 'cstr' will point to the path component + // immediately following the array, or the null termination byte if the final field in the path + // was an array. + uassert( + 16766, + str::stream() + << "Error: hashed indexes do not currently support array values. Found array at path: " + << hashedField.substr( + 0, hashedField.size() - StringData(cstr).size() - !StringData(cstr).empty()), + fieldVal.type() != BSONType::Array); // Convert strings to comparison keys. BSONObj fieldValObj; @@ -370,13 +381,6 @@ void ExpressionKeysPrivate::getHashKeys(const BSONObj& obj, CollationIndexKey::collationAwareIndexKeyAppend(fieldVal, collator, &bob); fieldValObj = bob.obj(); fieldVal = fieldValObj.firstElement(); - } - - uassert(16766, - "Error: hashed indexes do not currently support array values", - fieldVal.type() != Array); - - if (!fieldVal.eoo()) { BSONObj key = BSON("" << makeSingleHashKey(fieldVal, seed, hashVersion)); keys->insert(key); } else if (!isSparse) { -- cgit v1.2.1