diff options
author | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-04-02 21:36:01 -0400 |
---|---|---|
committer | Gregory Wlodarek <gregory.wlodarek@mongodb.com> | 2019-04-02 21:38:45 -0400 |
commit | 24aa7dc8f39e133da8a3e405863e5dbbd980f68d (patch) | |
tree | 2f6036aad918f29be82fe2e6831e2453fe679446 /src/mongo/db/commands | |
parent | 573495bbf17851758e7fcf76c85a3d66d6b53342 (diff) | |
download | mongo-24aa7dc8f39e133da8a3e405863e5dbbd980f68d.tar.gz |
SERVER-39231 'create' command should reject incorrect types for known options
Diffstat (limited to 'src/mongo/db/commands')
-rw-r--r-- | src/mongo/db/commands/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/commands/create.idl | 117 | ||||
-rw-r--r-- | src/mongo/db/commands/dbcommands.cpp | 83 |
3 files changed, 173 insertions, 28 deletions
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index c1faa282b74..b3c753cf933 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -259,6 +259,7 @@ env.Library( "sleep_command.cpp", "validate.cpp", "write_commands/write_commands.cpp", + env.Idlc('create.idl')[0], env.Idlc('enable_coordinator_for_create_indexes_command.idl')[0], ], LIBDEPS_PRIVATE=[ diff --git a/src/mongo/db/commands/create.idl b/src/mongo/db/commands/create.idl new file mode 100644 index 00000000000..685b56f483a --- /dev/null +++ b/src/mongo/db/commands/create.idl @@ -0,0 +1,117 @@ +# Copyright (C) 2019-present MongoDB, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the Server Side Public License, version 1, +# as published by MongoDB, Inc. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Server Side Public License for more details. +# +# You should have received a copy of the Server Side Public License +# along with this program. If not, see +# <http://www.mongodb.com/licensing/server-side-public-license>. +# +# As a special exception, the copyright holders give permission to link the +# code of portions of this program with the OpenSSL library under certain +# conditions as described in each individual source file and distribute +# linked combinations including the program with the OpenSSL library. You +# must comply with the Server Side Public License in all respects for +# all of the code used other than as permitted herein. If you modify file(s) +# with this exception, you may extend this exception to your version of the +# file(s), but you are not obligated to do so. If you do not wish to do so, +# delete this exception statement from your version. If you delete this +# exception statement from all source files in the program, then also delete +# it in the license file. +# + +global: + cpp_namespace: "mongo" + +imports: + - "mongo/idl/basic_types.idl" + +commands: + create: + description: "Parser for the 'create' Command" + namespace: concatenate_with_db + cpp_name: CreateCommand + strict: true + fields: + capped: + description: "Specify true to create a capped collection. If you specify true, you + must also set a maximum size in the 'size' field." + type: safeBool + default: false + autoIndexId: + description: "Specify false to disable the automatic creation of an index on the + _id field." + type: safeBool + optional: true + idIndex: + description: "Specify the default _id index specification." + type: object + optional: true + size: + description: "Specify a maximum size in bytes for the capped collection." + type: safeInt64 + optional: true + max: + description: "The maximum number of documents allowed in the capped collection. The + 'size' limit takes precedence over this limit." + type: safeInt64 + optional: true + storageEngine: + description: "Specify a configuration to the storage engine on a per-collection + basis when creating a collection." + type: object + optional: true + validator: + description: "Specify validation rules or expressions for the collection." + type: object + optional: true + validationLevel: + description: "Determines how strictly to apply the validation rules to existing + documents during an update. + Can be one of following values: 'off', 'strict' or 'moderate'." + type: string + default: '"strict"' + validationAction: + description: "Determines whether to error on invalid documents or just warn about + the violations but allow invalid documents to be inserted. + Can be either 'warn' or 'error'." + type: string + default: '"error"' + indexOptionDefaults: + description: "Allows users to specify a default configuration for indexes when + creating a collection." + type: object + optional: true + viewOn: + description: "The name of the source collection or view from which to create the + view." + type: string + optional: true + pipeline: + description: "An array that consists of the aggregation pipeline. Creates the view + by applying the specified pipeline to the 'viewOn' collection or + view." + type: array<object> + optional: true + collation: + description: "Specifies the default collation for the collection or the view." + type: object + optional: true + writeConcern: + description: "A document that expresses the write concern for the operation." + type: object + optional: true + temp: + description: "DEPRECATED" + type: safeBool + optional: true + flags: + description: "DEPRECATED" + type: int + optional: true diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index 7378c1fae2c..1be49d127e4 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -55,6 +55,7 @@ #include "mongo/db/catalog_raii.h" #include "mongo/db/clientcursor.h" #include "mongo/db/commands.h" +#include "mongo/db/commands/create_gen.h" #include "mongo/db/commands/profile_common.h" #include "mongo/db/commands/profile_gen.h" #include "mongo/db/commands/server_status.h" @@ -259,22 +260,41 @@ public: class CmdCreate : public BasicCommand { public: CmdCreate() : BasicCommand("create") {} + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } + virtual bool adminOnly() const { return false; } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { return true; } std::string help() const override { - return "create a collection explicitly\n" - "{ create: <ns>[, capped: <bool>, size: <collSizeInBytes>, max: <nDocs>] }"; + return str::stream() + << "explicitly creates a collection or view\n" + << "{\n" + << " create: <string: collection or view name> [,\n" + << " capped: <bool: capped collection>,\n" + << " autoIndexId: <bool: automatic creation of _id index>,\n" + << " idIndex: <document: _id index specification>,\n" + << " size: <int: size in bytes of the capped collection>,\n" + << " max: <int: max number of documents in the capped collection>,\n" + << " storageEngine: <document: storage engine configuration>,\n" + << " validator: <document: validation rules>,\n" + << " validationLevel: <string: validation level>,\n" + << " validationAction: <string: validation action>,\n" + << " indexOptionDefaults: <document: default configuration for indexes>,\n" + << " viewOn: <string: name of source collection or view>,\n" + << " pipeline: <array<object>: aggregation pipeline stage>,\n" + << " collation: <document: default collation for the collection or view>,\n" + << " writeConcern: <document: write concern expression for the operation>]\n" + << "}"; } + virtual Status checkAuthForCommand(Client* client, const std::string& dbname, const BSONObj& cmdObj) const { @@ -286,34 +306,44 @@ public: const string& dbname, const BSONObj& cmdObj, BSONObjBuilder& result) { - const NamespaceString ns(CommandHelpers::parseNsCollectionRequired(dbname, cmdObj)); + IDLParserErrorContext ctx("create"); + CreateCommand cmd = CreateCommand::parse(ctx, cmdObj); - if (cmdObj.hasField("autoIndexId")) { + const NamespaceString ns = cmd.getNamespace(); + + if (cmd.getAutoIndexId()) { const char* deprecationWarning = "the autoIndexId option is deprecated and will be removed in a future release"; warning() << deprecationWarning; result.append("note", deprecationWarning); } + // Ensure that the 'size' field is present if 'capped' is set to true. + if (cmd.getCapped()) { + uassert(ErrorCodes::InvalidOptions, + str::stream() << "the 'size' field is required when 'capped' is true", + cmd.getSize()); + } + + // If the 'size' or 'max' fields are present, then 'capped' must be set to true. + if (cmd.getSize() || cmd.getMax()) { + uassert(ErrorCodes::InvalidOptions, + str::stream() << "the 'capped' field needs to be true when either the 'size'" + << " or 'max' fields are present", + cmd.getCapped()); + } + // Validate _id index spec and fill in missing fields. - if (auto idIndexElem = cmdObj["idIndex"]) { - if (cmdObj["viewOn"]) { - uasserted(ErrorCodes::InvalidOptions, - str::stream() << "'idIndex' is not allowed with 'viewOn': " - << idIndexElem); - } - if (cmdObj["autoIndexId"]) { - uasserted(ErrorCodes::InvalidOptions, - str::stream() << "'idIndex' is not allowed with 'autoIndexId': " - << idIndexElem); - } + if (cmd.getIdIndex()) { + auto idIndexSpec = *cmd.getIdIndex(); - if (idIndexElem.type() != BSONType::Object) { - uasserted(ErrorCodes::TypeMismatch, - str::stream() << "'idIndex' has to be a document: " << idIndexElem); - } + uassert(ErrorCodes::InvalidOptions, + str::stream() << "'idIndex' is not allowed with 'viewOn': " << idIndexSpec, + !cmd.getViewOn()); - auto idIndexSpec = idIndexElem.Obj(); + uassert(ErrorCodes::InvalidOptions, + str::stream() << "'idIndex' is not allowed with 'autoIndexId': " << idIndexSpec, + !cmd.getAutoIndexId()); // Perform index spec validation. idIndexSpec = uassertStatusOK(index_key_validate::validateIndexSpec( @@ -322,19 +352,16 @@ public: // Validate or fill in _id index collation. std::unique_ptr<CollatorInterface> defaultCollator; - if (auto collationElem = cmdObj["collation"]) { - if (collationElem.type() != BSONType::Object) { - uasserted(ErrorCodes::TypeMismatch, - str::stream() << "'collation' has to be a document: " - << collationElem); - } + if (cmd.getCollation()) { auto collatorStatus = CollatorFactoryInterface::get(opCtx->getServiceContext()) - ->makeFromBSON(collationElem.Obj()); + ->makeFromBSON(*cmd.getCollation()); uassertStatusOK(collatorStatus.getStatus()); defaultCollator = std::move(collatorStatus.getValue()); } + idIndexSpec = uassertStatusOK(index_key_validate::validateIndexSpecCollation( opCtx, idIndexSpec, defaultCollator.get())); + std::unique_ptr<CollatorInterface> idIndexCollator; if (auto collationElem = idIndexSpec["collation"]) { auto collatorStatus = CollatorFactoryInterface::get(opCtx->getServiceContext()) |