diff options
-rw-r--r-- | jstests/core/explain_uuid.js | 56 | ||||
-rw-r--r-- | src/mongo/db/commands.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/commands/count_cmd.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 2 | ||||
-rw-r--r-- | src/mongo/idl/idl_parser.cpp | 6 |
5 files changed, 70 insertions, 2 deletions
diff --git a/jstests/core/explain_uuid.js b/jstests/core/explain_uuid.js new file mode 100644 index 00000000000..a7de30a1ef2 --- /dev/null +++ b/jstests/core/explain_uuid.js @@ -0,0 +1,56 @@ +/** + * Test that running explain() providing a collection UUID rather than collection name will fail + * cleanly. + */ +(function() { + "use strict"; + + // Use our own database so that we're guaranteed the only collection is this one. + const explainDB = db.getSiblingDB("explain_uuid_db"); + + assert.commandWorked(explainDB.dropDatabase()); + + const coll = explainDB.explain_uuid; + assert.writeOK(coll.insert({a: 1})); + + const collInfos = explainDB.getCollectionInfos({name: coll.getName()}); + assert.eq(collInfos.length, 1, collInfos); + const uuid = collInfos[0].info.uuid; + + // Run a find explain looking up by UUID. + assert.commandFailedWithCode(explainDB.runCommand({explain: {find: uuid}}), + ErrorCodes.InvalidNamespace); + + // Do similar for other commands. + assert.commandFailedWithCode(explainDB.runCommand({explain: {aggregate: uuid, cursor: {}}}), + ErrorCodes.TypeMismatch); + + assert.commandFailedWithCode(explainDB.runCommand({explain: {count: uuid}}), + ErrorCodes.InvalidNamespace); + + assert.commandFailedWithCode(explainDB.runCommand({explain: {distinct: uuid, key: "x"}}), + ErrorCodes.InvalidNamespace); + + // When auth is enabled, running findAndModify with an invalid namespace will produce a special + // error during the auth check, rather than the generic 'InvalidNamespace' error. + const expectedCode = TestData.auth ? 17137 : ErrorCodes.InvalidNamespace; + assert.commandFailedWithCode( + explainDB.runCommand({explain: {findAndModify: uuid, query: {a: 1}, remove: true}}), + expectedCode); + + assert.commandFailedWithCode( + explainDB.runCommand({explain: {delete: uuid, deletes: [{q: {}, limit: 1}]}}), + ErrorCodes.BadValue); + + assert.commandFailedWithCode(explainDB.runCommand({ + explain: { + update: uuid, + updates: [{ + q: {a: 1}, + u: {$set: {b: 1}}, + }] + } + }), + ErrorCodes.BadValue); + +})(); diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index 4ff86edc586..f7aa71e9184 100644 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -126,6 +126,12 @@ NamespaceString Command::parseNsCollectionRequired(const string& dbname, const B // Accepts both BSON String and Symbol for collection name per SERVER-16260 // TODO(kangas) remove Symbol support in MongoDB 3.0 after Ruby driver audit BSONElement first = cmdObj.firstElement(); + const bool isUUID = (first.canonicalType() == canonicalizeBSONType(mongo::BinData) && + first.binDataType() == BinDataType::newUUID); + uassert(ErrorCodes::InvalidNamespace, + str::stream() << "Collection name must be provided. UUID is not valid in this " + << "context", + !isUUID); uassert(ErrorCodes::InvalidNamespace, str::stream() << "collection name has invalid type " << typeName(first.type()), first.canonicalType() == canonicalizeBSONType(mongo::String)); diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp index f8af43deaf4..2a306facb7a 100644 --- a/src/mongo/db/commands/count_cmd.cpp +++ b/src/mongo/db/commands/count_cmd.cpp @@ -118,7 +118,7 @@ public: BSONObjBuilder* out) const { const bool isExplain = true; Lock::DBLock dbLock(opCtx, dbname, MODE_IS); - auto nss = parseNsOrUUID(opCtx, dbname, cmdObj); + auto nss = parseNsCollectionRequired(dbname, cmdObj); auto request = CountRequest::parseFromBSON(nss, cmdObj, isExplain); if (!request.isOK()) { return request.getStatus(); diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index c50f5a93e80..c913dde609e 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -133,7 +133,7 @@ public: const BSONObj& cmdObj, ExplainOptions::Verbosity verbosity, BSONObjBuilder* out) const override { - const NamespaceString nss(parseNs(dbname, cmdObj)); + const NamespaceString nss(parseNsCollectionRequired(dbname, cmdObj)); if (!nss.isValid()) { return {ErrorCodes::InvalidNamespace, str::stream() << "Invalid collection name: " << nss.ns()}; diff --git a/src/mongo/idl/idl_parser.cpp b/src/mongo/idl/idl_parser.cpp index 9d4c139c9dc..fbcd93b5e4f 100644 --- a/src/mongo/idl/idl_parser.cpp +++ b/src/mongo/idl/idl_parser.cpp @@ -227,6 +227,12 @@ void IDLParserErrorContext::throwBadEnumValue(StringData enumValue) const { NamespaceString IDLParserErrorContext::parseNSCollectionRequired(StringData dbName, const BSONElement& element) { + const bool isUUID = (element.canonicalType() == canonicalizeBSONType(mongo::BinData) && + element.binDataType() == BinDataType::newUUID); + uassert(ErrorCodes::BadValue, + str::stream() << "Collection name must be provided. UUID is not valid in this " + << "context", + !isUUID); uassert(ErrorCodes::BadValue, str::stream() << "collection name has invalid type " << typeName(element.type()), element.canonicalType() == canonicalizeBSONType(mongo::String)); |