summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/write_commands
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2017-06-07 13:56:30 +0300
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2017-07-06 18:05:57 -0400
commite09a21c0d849878792e647d2326d6fde865ac458 (patch)
treeb3cd6c002db115e73fa8151609467a4ec7ce3d0d /src/mongo/db/commands/write_commands
parent1447d3db59804752e6c2882a6a8a4a14d7ae71ad (diff)
downloadmongo-e09a21c0d849878792e647d2326d6fde865ac458.tar.gz
SERVER-28752 Use IDL for write commands parsing
Diffstat (limited to 'src/mongo/db/commands/write_commands')
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp73
-rw-r--r--src/mongo/db/commands/write_commands/write_commands_common.cpp79
-rw-r--r--src/mongo/db/commands/write_commands/write_commands_common.h5
3 files changed, 105 insertions, 52 deletions
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index b9e92e13947..dcab92230d2 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -41,8 +41,8 @@
#include "mongo/db/ops/parsed_delete.h"
#include "mongo/db/ops/parsed_update.h"
#include "mongo/db/ops/update_lifecycle_impl.h"
+#include "mongo/db/ops/write_ops.h"
#include "mongo/db/ops/write_ops_exec.h"
-#include "mongo/db/ops/write_ops_parsers.h"
#include "mongo/db/query/explain.h"
#include "mongo/db/query/get_executor.h"
#include "mongo/db/repl/repl_client_info.h"
@@ -53,10 +53,6 @@
#include "mongo/s/stale_exception.h"
namespace mongo {
-
-using std::string;
-using std::stringstream;
-
namespace {
void redactTooLongLog(mutablebson::Document* cmdObj, StringData fieldName) {
@@ -225,8 +221,6 @@ public:
BSONObjBuilder& result) = 0;
};
-} // namespace
-
class CmdInsert final : public WriteCommand {
public:
CmdInsert() : WriteCommand("insert") {}
@@ -235,7 +229,7 @@ public:
redactTooLongLog(cmdObj, "documents");
}
- void help(stringstream& help) const final {
+ void help(std::stringstream& help) const final {
help << "insert documents";
}
@@ -251,12 +245,12 @@ public:
void runImpl(OperationContext* opCtx,
const OpMsgRequest& request,
BSONObjBuilder& result) final {
- const auto batch = parseInsertCommand(request);
+ const auto batch = InsertOp::parse(request);
const auto reply = performInserts(opCtx, batch);
serializeReply(opCtx,
ReplyStyle::kNotUpdate,
- batch.continueOnError,
- batch.documents.size(),
+ !batch.getWriteCommandBase().getOrdered(),
+ batch.getDocuments().size(),
reply,
&result);
}
@@ -270,7 +264,7 @@ public:
redactTooLongLog(cmdObj, "updates");
}
- void help(stringstream& help) const final {
+ void help(std::stringstream& help) const final {
help << "update documents";
}
@@ -286,12 +280,12 @@ public:
void runImpl(OperationContext* opCtx,
const OpMsgRequest& request,
BSONObjBuilder& result) final {
- const auto batch = parseUpdateCommand(request);
+ const auto batch = UpdateOp::parse(request);
const auto reply = performUpdates(opCtx, batch);
serializeReply(opCtx,
ReplyStyle::kUpdate,
- batch.continueOnError,
- batch.updates.size(),
+ !batch.getWriteCommandBase().getOrdered(),
+ batch.getUpdates().size(),
reply,
&result);
}
@@ -301,21 +295,21 @@ public:
const BSONObj& cmdObj,
ExplainOptions::Verbosity verbosity,
BSONObjBuilder* out) const final {
- auto request = OpMsgRequest::fromDBAndBody(dbname, cmdObj);
- const auto batch = parseUpdateCommand(request);
+ const auto opMsgRequest(OpMsgRequest::fromDBAndBody(dbname, cmdObj));
+ const auto batch = UpdateOp::parse(opMsgRequest);
uassert(ErrorCodes::InvalidLength,
"explained write batches must be of size 1",
- batch.updates.size() == 1);
+ batch.getUpdates().size() == 1);
- UpdateLifecycleImpl updateLifecycle(batch.ns);
- UpdateRequest updateRequest(batch.ns);
+ UpdateLifecycleImpl updateLifecycle(batch.getNamespace());
+ UpdateRequest updateRequest(batch.getNamespace());
updateRequest.setLifecycle(&updateLifecycle);
- updateRequest.setQuery(batch.updates[0].query);
- updateRequest.setCollation(batch.updates[0].collation);
- updateRequest.setUpdates(batch.updates[0].update);
- updateRequest.setArrayFilters(batch.updates[0].arrayFilters);
- updateRequest.setMulti(batch.updates[0].multi);
- updateRequest.setUpsert(batch.updates[0].upsert);
+ updateRequest.setQuery(batch.getUpdates()[0].getQ());
+ updateRequest.setUpdates(batch.getUpdates()[0].getU());
+ updateRequest.setCollation(write_ops::collationOf(batch.getUpdates()[0]));
+ updateRequest.setArrayFilters(write_ops::arrayFiltersOf(batch.getUpdates()[0]));
+ updateRequest.setMulti(batch.getUpdates()[0].getMulti());
+ updateRequest.setUpsert(batch.getUpdates()[0].getUpsert());
updateRequest.setYieldPolicy(PlanExecutor::YIELD_AUTO);
updateRequest.setExplain();
@@ -324,7 +318,7 @@ public:
// Explains of write commands are read-only, but we take write locks so that timing
// info is more accurate.
- AutoGetCollection collection(opCtx, batch.ns, MODE_IX);
+ AutoGetCollection collection(opCtx, batch.getNamespace(), MODE_IX);
auto exec = uassertStatusOK(getExecutorUpdate(
opCtx, &CurOp::get(opCtx)->debug(), collection.getCollection(), &parsedUpdate));
@@ -341,7 +335,7 @@ public:
redactTooLongLog(cmdObj, "deletes");
}
- void help(stringstream& help) const final {
+ void help(std::stringstream& help) const final {
help << "delete documents";
}
@@ -357,12 +351,12 @@ public:
void runImpl(OperationContext* opCtx,
const OpMsgRequest& request,
BSONObjBuilder& result) final {
- const auto batch = parseDeleteCommand(request);
+ const auto batch = DeleteOp::parse(request);
const auto reply = performDeletes(opCtx, batch);
serializeReply(opCtx,
ReplyStyle::kNotUpdate,
- batch.continueOnError,
- batch.deletes.size(),
+ !batch.getWriteCommandBase().getOrdered(),
+ batch.getDeletes().size(),
reply,
&result);
}
@@ -372,16 +366,16 @@ public:
const BSONObj& cmdObj,
ExplainOptions::Verbosity verbosity,
BSONObjBuilder* out) const final {
- auto request = OpMsgRequest::fromDBAndBody(dbname, cmdObj);
- const auto batch = parseDeleteCommand(request);
+ const auto opMsgRequest(OpMsgRequest::fromDBAndBody(dbname, cmdObj));
+ const auto batch = DeleteOp::parse(opMsgRequest);
uassert(ErrorCodes::InvalidLength,
"explained write batches must be of size 1",
- batch.deletes.size() == 1);
+ batch.getDeletes().size() == 1);
- DeleteRequest deleteRequest(batch.ns);
- deleteRequest.setQuery(batch.deletes[0].query);
- deleteRequest.setCollation(batch.deletes[0].collation);
- deleteRequest.setMulti(batch.deletes[0].multi);
+ DeleteRequest deleteRequest(batch.getNamespace());
+ deleteRequest.setQuery(batch.getDeletes()[0].getQ());
+ deleteRequest.setCollation(write_ops::collationOf(batch.getDeletes()[0]));
+ deleteRequest.setMulti(batch.getDeletes()[0].getMulti());
deleteRequest.setYieldPolicy(PlanExecutor::YIELD_AUTO);
deleteRequest.setExplain();
@@ -390,7 +384,7 @@ public:
// Explains of write commands are read-only, but we take write locks so that timing
// info is more accurate.
- AutoGetCollection collection(opCtx, batch.ns, MODE_IX);
+ AutoGetCollection collection(opCtx, batch.getNamespace(), MODE_IX);
// Explain the plan tree.
auto exec = uassertStatusOK(getExecutorDelete(
@@ -400,4 +394,5 @@ public:
}
} cmdDelete;
+} // namespace
} // namespace mongo
diff --git a/src/mongo/db/commands/write_commands/write_commands_common.cpp b/src/mongo/db/commands/write_commands/write_commands_common.cpp
index aa208a1d3c7..9a5eb5d6cd8 100644
--- a/src/mongo/db/commands/write_commands/write_commands_common.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands_common.cpp
@@ -37,19 +37,76 @@
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/catalog/document_validation.h"
+#include "mongo/db/ops/write_ops.h"
#include "mongo/util/assert_util.h"
namespace mongo {
namespace auth {
+namespace {
-using std::string;
-using std::vector;
+using write_ops::Insert;
+using write_ops::Update;
+using write_ops::UpdateOpEntry;
+
+/**
+ * Helper to determine whether or not there are any upserts in the batch
+ */
+bool containsUpserts(const BSONObj& writeCmdObj) {
+ BSONElement updatesEl = writeCmdObj[Update::kUpdatesFieldName];
+ if (updatesEl.type() != Array) {
+ return false;
+ }
+
+ for (const auto& updateEl : updatesEl.Array()) {
+ if (!updateEl.isABSONObj())
+ continue;
+
+ if (updateEl.Obj()[UpdateOpEntry::kUpsertFieldName].trueValue())
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Helper to extract the namespace being indexed from a raw BSON write command.
+ *
+ * TODO: Remove when we have parsing hooked before authorization.
+ */
+StatusWith<NamespaceString> getIndexedNss(const BSONObj& writeCmdObj) {
+ BSONElement documentsEl = writeCmdObj[Insert::kDocumentsFieldName];
+ if (documentsEl.type() != Array) {
+ return {ErrorCodes::FailedToParse, "index write batch is invalid"};
+ }
+
+ BSONObjIterator it(documentsEl.Obj());
+ if (!it.more()) {
+ return {ErrorCodes::FailedToParse, "index write batch is empty"};
+ }
+
+ BSONElement indexDescEl = it.next();
+
+ const std::string nsToIndex = indexDescEl["ns"].str();
+ if (nsToIndex.empty()) {
+ return {ErrorCodes::FailedToParse,
+ "index write batch contains an invalid index descriptor"};
+ }
+
+ if (it.more()) {
+ return {ErrorCodes::FailedToParse,
+ "index write batches may only contain a single index descriptor"};
+ }
+
+ return {NamespaceString(std::move(nsToIndex))};
+}
+
+} // namespace
Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
BatchedCommandRequest::BatchType cmdType,
const NamespaceString& cmdNSS,
const BSONObj& cmdObj) {
- vector<Privilege> privileges;
+ std::vector<Privilege> privileges;
ActionSet actionsOnCommandNSS;
if (shouldBypassDocumentValidationForCommand(cmdObj)) {
@@ -61,12 +118,12 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
actionsOnCommandNSS.addAction(ActionType::insert);
} else {
// Special-case indexes until we have a command
- string nsToIndex, errMsg;
- if (!BatchedCommandRequest::getIndexedNS(cmdObj, &nsToIndex, &errMsg)) {
- return Status(ErrorCodes::FailedToParse, errMsg);
+ const auto swNssToIndex = getIndexedNss(cmdObj);
+ if (!swNssToIndex.isOK()) {
+ return swNssToIndex.getStatus();
}
- NamespaceString nssToIndex(nsToIndex);
+ const auto& nssToIndex = swNssToIndex.getValue();
privileges.push_back(
Privilege(ResourcePattern::forExactNamespace(nssToIndex), ActionType::createIndex));
}
@@ -74,7 +131,7 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
actionsOnCommandNSS.addAction(ActionType::update);
// Upsert also requires insert privs
- if (BatchedCommandRequest::containsUpserts(cmdObj)) {
+ if (containsUpserts(cmdObj)) {
actionsOnCommandNSS.addAction(ActionType::insert);
}
} else {
@@ -82,7 +139,6 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
actionsOnCommandNSS.addAction(ActionType::remove);
}
-
if (!actionsOnCommandNSS.empty()) {
privileges.emplace_back(ResourcePattern::forExactNamespace(cmdNSS), actionsOnCommandNSS);
}
@@ -92,5 +148,6 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
return Status(ErrorCodes::Unauthorized, "unauthorized");
}
-}
-}
+
+} // namespace auth
+} // namespace mongo
diff --git a/src/mongo/db/commands/write_commands/write_commands_common.h b/src/mongo/db/commands/write_commands/write_commands_common.h
index 53ba02aad05..8f8206d3c70 100644
--- a/src/mongo/db/commands/write_commands/write_commands_common.h
+++ b/src/mongo/db/commands/write_commands/write_commands_common.h
@@ -44,5 +44,6 @@ Status checkAuthForWriteCommand(AuthorizationSession* authzSession,
BatchedCommandRequest::BatchType cmdType,
const NamespaceString& cmdNSS,
const BSONObj& cmdObj);
-}
-}
+
+} // namespace auth
+} // namespace mongo