summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/commands/count_cmd.cpp85
-rw-r--r--src/mongo/db/exec/count.cpp14
-rw-r--r--src/mongo/db/exec/count.h28
-rw-r--r--src/mongo/db/query/SConscript2
-rw-r--r--src/mongo/db/query/count_request.cpp131
-rw-r--r--src/mongo/db/query/count_request.h94
-rw-r--r--src/mongo/db/query/count_request_test.cpp133
-rw-r--r--src/mongo/db/query/find_and_modify_request.cpp2
-rw-r--r--src/mongo/db/query/find_and_modify_request.h6
-rw-r--r--src/mongo/db/query/get_executor.cpp25
-rw-r--r--src/mongo/db/query/get_executor.h2
-rw-r--r--src/mongo/db/query/getmore_request.h2
-rw-r--r--src/mongo/dbtests/query_stage_count.cpp38
13 files changed, 416 insertions, 146 deletions
diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp
index 00d5b4ac731..7f4e0bf3a65 100644
--- a/src/mongo/db/commands/count_cmd.cpp
+++ b/src/mongo/db/commands/count_cmd.cpp
@@ -77,14 +77,13 @@ namespace {
ExplainCommon::Verbosity verbosity,
BSONObjBuilder* out) const {
- CountRequest request;
- Status parseStatus = parseRequest(dbname, cmdObj, &request);
- if (!parseStatus.isOK()) {
- return parseStatus;
+ auto request = CountRequest::parseFromBSON(dbname, cmdObj);
+ if (!request.isOK()) {
+ return request.getStatus();
}
// Acquire the db read lock.
- AutoGetCollectionForRead ctx(txn, request.ns);
+ AutoGetCollectionForRead ctx(txn, request.getValue().getNs());
Collection* collection = ctx.getCollection();
// Prevent chunks from being cleaned up during yields - this allows us to only check the
@@ -94,7 +93,7 @@ namespace {
PlanExecutor* rawExec;
Status getExecStatus = getExecutorCount(txn,
collection,
- request,
+ request.getValue(),
true, // explain
PlanExecutor::YIELD_AUTO,
&rawExec);
@@ -114,13 +113,12 @@ namespace {
int, string& errmsg,
BSONObjBuilder& result) {
- CountRequest request;
- Status parseStatus = parseRequest(dbname, cmdObj, &request);
- if (!parseStatus.isOK()) {
- return appendCommandStatus(result, parseStatus);
+ auto request = CountRequest::parseFromBSON(dbname, cmdObj);
+ if (!request.isOK()) {
+ return appendCommandStatus(result, request.getStatus());
}
- AutoGetCollectionForRead ctx(txn, request.ns);
+ AutoGetCollectionForRead ctx(txn, request.getValue().getNs());
Collection* collection = ctx.getCollection();
// Prevent chunks from being cleaned up during yields - this allows us to only check the
@@ -130,7 +128,7 @@ namespace {
PlanExecutor* rawExec;
Status getExecStatus = getExecutorCount(txn,
collection,
- request,
+ request.getValue(),
false, // !explain
PlanExecutor::YIELD_AUTO,
&rawExec);
@@ -160,69 +158,6 @@ namespace {
return true;
}
- /**
- * Parses a count command object, 'cmdObj'.
- *
- * On success, fills in the out-parameter 'request' and returns an OK status.
- *
- * Returns a failure status if 'cmdObj' is not well formed.
- */
- Status parseRequest(const std::string& dbname,
- const BSONObj& cmdObj,
- CountRequest* request) const {
-
- long long skip = 0;
- if (cmdObj["skip"].isNumber()) {
- skip = cmdObj["skip"].numberLong();
- if (skip < 0) {
- return Status(ErrorCodes::BadValue, "skip value is negative in count query");
- }
- }
- else if (cmdObj["skip"].ok()) {
- return Status(ErrorCodes::BadValue, "skip value is not a valid number");
- }
-
- long long limit = 0;
- if (cmdObj["limit"].isNumber()) {
- limit = cmdObj["limit"].numberLong();
- }
- else if (cmdObj["limit"].ok()) {
- return Status(ErrorCodes::BadValue, "limit value is not a valid number");
- }
-
- // For counts, limit and -limit mean the same thing.
- if (limit < 0) {
- limit = -limit;
- }
-
- // We don't validate that "query" is a nested object due to SERVER-15456.
- BSONObj query = cmdObj.getObjectField("query");
-
- BSONObj hintObj;
- if (Object == cmdObj["hint"].type()) {
- hintObj = cmdObj["hint"].Obj();
- }
- else if (String == cmdObj["hint"].type()) {
- const std::string hint = cmdObj.getStringField("hint");
- hintObj = BSON("$hint" << hint);
- }
-
- std::string ns = parseNs(dbname, cmdObj);
-
- if (!nsIsFull(ns)) {
- return Status(ErrorCodes::BadValue, "collection name missing");
- }
-
- // Parsed correctly. Fill out 'request' with the results.
- request->ns = ns;
- request->query = query;
- request->hint = hintObj;
- request->limit = limit;
- request->skip = skip;
-
- return Status::OK();
- }
-
} cmdCount;
} // namespace
diff --git a/src/mongo/db/exec/count.cpp b/src/mongo/db/exec/count.cpp
index 9d747c31aca..7534f7e1e44 100644
--- a/src/mongo/db/exec/count.cpp
+++ b/src/mongo/db/exec/count.cpp
@@ -50,7 +50,7 @@ namespace mongo {
: _txn(txn),
_collection(collection),
_request(request),
- _leftToSkip(request.skip),
+ _leftToSkip(request.getSkip()),
_ws(ws),
_child(child),
_commonStats(kStageType) { }
@@ -62,7 +62,7 @@ namespace mongo {
return true;
}
- if (_request.limit > 0 && _specificStats.nCounted >= _request.limit) {
+ if (_request.getLimit() > 0 && _specificStats.nCounted >= _request.getLimit()) {
return true;
}
@@ -73,14 +73,14 @@ namespace mongo {
invariant(_collection);
long long nCounted = _collection->numRecords(_txn);
- if (0 != _request.skip) {
- nCounted -= _request.skip;
+ if (0 != _request.getSkip()) {
+ nCounted -= _request.getSkip();
if (nCounted < 0) {
nCounted = 0;
}
}
- long long limit = _request.limit;
+ long long limit = _request.getLimit();
if (limit < 0) {
limit = -limit;
}
@@ -90,7 +90,7 @@ namespace mongo {
}
_specificStats.nCounted = nCounted;
- _specificStats.nSkipped = _request.skip;
+ _specificStats.nSkipped = _request.getSkip();
_specificStats.trivialCount = true;
}
@@ -105,7 +105,7 @@ namespace mongo {
// If we don't have a query and we have a non-NULL collection, then we can execute this
// as a trivial count (just ask the collection for how many records it has).
- if (_request.query.isEmpty() && NULL != _collection) {
+ if (_request.getQuery().isEmpty() && NULL != _collection) {
trivialCount();
return PlanStage::IS_EOF;
}
diff --git a/src/mongo/db/exec/count.h b/src/mongo/db/exec/count.h
index ff70f3b2170..05bce99ac66 100644
--- a/src/mongo/db/exec/count.h
+++ b/src/mongo/db/exec/count.h
@@ -30,37 +30,11 @@
#include "mongo/db/exec/plan_stage.h"
+#include "mongo/db/query/count_request.h"
namespace mongo {
/**
- * A description of a request for a count operation. Copyable.
- */
- struct CountRequest {
- // Namespace to operate on (e.g. "foo.bar").
- std::string ns;
-
- // A predicate describing the set of documents to count.
- //
- // NOTE:
- // Parsing the raw BSON to our AST is left for later so that the parse method does not
- // have to look at the catalog. Specifically, creating a CanonicalQuery requires a
- // Collection* due to the WhereCallback, and we'd rather not have the parse method require
- // a Collection*.
- BSONObj query;
-
- // Indicates to the query planner that it should generate a count plan using a
- // particular index.
- BSONObj hint;
-
- // An integer limiting the number of documents to count.
- long long limit;
-
- // An integer indicating to not include the first n documents in the count.
- long long skip;
- };
-
- /**
* Stage used by the count command. This stage sits at the root of a plan tree
* and counts the number of results returned by its child stage.
*
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index 66f00e9696c..bb209a8ae47 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -101,6 +101,7 @@ env.Library(
env.Library(
target='command_request_response',
source=[
+ 'count_request.cpp',
'cursor_responses.cpp',
'find_and_modify_request.cpp',
'getmore_request.cpp',
@@ -115,6 +116,7 @@ env.Library(
env.CppUnitTest(
target='command_request_response_test',
source=[
+ 'count_request_test.cpp',
'find_and_modify_request_test.cpp',
'getmore_request_test.cpp',
],
diff --git a/src/mongo/db/query/count_request.cpp b/src/mongo/db/query/count_request.cpp
new file mode 100644
index 00000000000..a587586590f
--- /dev/null
+++ b/src/mongo/db/query/count_request.cpp
@@ -0,0 +1,131 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 GNU Affero General 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/query/count_request.h"
+
+#include "mongo/db/namespace_string.h"
+#include "mongo/util/mongoutils/str.h"
+
+namespace mongo {
+namespace {
+
+ const char kCmdName[] = "count";
+ const char kQueryField[] = "query";
+ const char kLimitField[] = "limit";
+ const char kSkipField[] = "skip";
+ const char kHintField[] = "hint";
+
+} // namespace
+
+ CountRequest::CountRequest(const std::string& fullNs, BSONObj query)
+ : _fullNs(fullNs),
+ _query(query.getOwned()) {
+ }
+
+ void CountRequest::setHint(BSONObj hint) {
+ _hint = hint.getOwned();
+ }
+
+ BSONObj CountRequest::toBSON() const {
+ BSONObjBuilder builder;
+
+ builder.append(kCmdName, _fullNs);
+ builder.append(kQueryField, _query);
+
+ if (_limit) {
+ builder.append(kLimitField, _limit.get());
+ }
+
+ if (_skip) {
+ builder.append(kSkipField, _skip.get());
+ }
+
+ if (_hint) {
+ builder.append(kHintField, _hint.get());
+ }
+
+ return builder.obj();
+ }
+
+ StatusWith<CountRequest> CountRequest::parseFromBSON(const std::string& dbname,
+ const BSONObj& cmdObj) {
+
+ BSONElement firstElt = cmdObj.firstElement();
+ const std::string coll = (firstElt.type() == BSONType::String) ? firstElt.str() : "";
+
+ const std::string ns = str::stream() << dbname << "." << coll;
+ if (!nsIsFull(ns)) {
+ return Status(ErrorCodes::BadValue, "invalid collection name");
+ }
+
+ // We don't validate that "query" is a nested object due to SERVER-15456.
+ CountRequest request(ns, cmdObj.getObjectField(kQueryField));
+
+ // Limit
+ if (cmdObj[kLimitField].isNumber()) {
+ long long limit = cmdObj[kLimitField].numberLong();
+
+ // For counts, limit and -limit mean the same thing.
+ if (limit < 0) {
+ limit = -limit;
+ }
+
+ request.setLimit(limit);
+ }
+ else if (cmdObj[kLimitField].ok()) {
+ return Status(ErrorCodes::BadValue, "limit value is not a valid number");
+ }
+
+ // Skip
+ if (cmdObj[kSkipField].isNumber()) {
+ long long skip = cmdObj[kSkipField].numberLong();
+ if (skip < 0) {
+ return Status(ErrorCodes::BadValue, "skip value is negative in count query");
+ }
+
+ request.setSkip(skip);
+ }
+ else if (cmdObj[kSkipField].ok()) {
+ return Status(ErrorCodes::BadValue, "skip value is not a valid number");
+ }
+
+ // Hint
+ if (Object == cmdObj[kHintField].type()) {
+ request.setHint(cmdObj[kHintField].Obj());
+ }
+ else if (String == cmdObj[kHintField].type()) {
+ const std::string hint = cmdObj.getStringField(kHintField);
+ request.setHint(BSON("$hint" << hint));
+ }
+
+ return request;
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/query/count_request.h b/src/mongo/db/query/count_request.h
new file mode 100644
index 00000000000..0e9eb25ee30
--- /dev/null
+++ b/src/mongo/db/query/count_request.h
@@ -0,0 +1,94 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 GNU Affero General 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.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+#include <string>
+
+#include "mongo/db/jsobj.h"
+
+namespace mongo {
+
+
+ template<typename T> class StatusWith;
+
+ /**
+ * A description of a request for a count operation. Copyable.
+ */
+ class CountRequest {
+ public:
+
+ /**
+ * Construct an empty request.
+ */
+ CountRequest(const std::string& fullNs, BSONObj query);
+
+ const std::string& getNs() const { return _fullNs; }
+ const BSONObj getQuery() const { return _query; }
+
+ long long getLimit() const { return _limit.value_or(0); }
+ void setLimit(long long limit) { _limit = limit; }
+
+ long long getSkip() const { return _skip.value_or(0); }
+ void setSkip(long long skip) { _skip = skip; }
+
+ const BSONObj getHint() const { return _hint.value_or(BSONObj()); }
+ void setHint(BSONObj hint);
+
+ /**
+ * Constructs a BSON representation of this request, which can be used for sending it in
+ * commands.
+ */
+ BSONObj toBSON() const;
+
+ /**
+ * Construct a CountRequest from the command specification and db name.
+ */
+ static StatusWith<CountRequest> parseFromBSON(const std::string& dbname,
+ const BSONObj& cmdObj);
+
+ private:
+ // Namespace to operate on (e.g. "foo.bar").
+ const std::string _fullNs;
+
+ // A predicate describing the set of documents to count.
+ const BSONObj _query;
+
+ // Optional. An integer limiting the number of documents to count.
+ boost::optional<long long> _limit;
+
+ // Optional. An integer indicating to not include the first n documents in the count.
+ boost::optional<long long> _skip;
+
+ // Optional. Indicates to the query planner that it should generate a count plan using a
+ // particular index.
+ boost::optional<BSONObj> _hint;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/db/query/count_request_test.cpp b/src/mongo/db/query/count_request_test.cpp
new file mode 100644
index 00000000000..4f0546b4180
--- /dev/null
+++ b/src/mongo/db/query/count_request_test.cpp
@@ -0,0 +1,133 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 GNU Affero General 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/bson/json.h"
+#include "mongo/db/query/count_request.h"
+#include "mongo/util/mongoutils/str.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+namespace {
+
+ TEST(CountRequest, ParseDefaults) {
+ const auto countRequestStatus =
+ CountRequest::parseFromBSON("TestDB",
+ BSON("count" << "TestColl" <<
+ "query" << BSON("a" << BSON("$lte" << 10))));
+
+ ASSERT_OK(countRequestStatus.getStatus());
+
+ const CountRequest& countRequest = countRequestStatus.getValue();
+
+ ASSERT_EQUALS(countRequest.getNs(), "TestDB.TestColl");
+ ASSERT_EQUALS(countRequest.getQuery(), fromjson("{ a : { '$lte' : 10 } }"));
+
+ // Defaults
+ ASSERT_EQUALS(countRequest.getLimit(), 0);
+ ASSERT_EQUALS(countRequest.getSkip(), 0);
+ ASSERT(countRequest.getHint().isEmpty());
+ }
+
+ TEST(CountRequest, ParseComplete) {
+ const auto countRequestStatus =
+ CountRequest::parseFromBSON("TestDB",
+ BSON("count" << "TestColl" <<
+ "query" << BSON("a" << BSON("$gte" << 11)) <<
+ "limit" << 100 <<
+ "skip" << 1000 <<
+ "hint" << BSON("b" << 5)));
+
+ ASSERT_OK(countRequestStatus.getStatus());
+
+ const CountRequest& countRequest = countRequestStatus.getValue();
+
+ ASSERT_EQUALS(countRequest.getNs(), "TestDB.TestColl");
+ ASSERT_EQUALS(countRequest.getQuery(), fromjson("{ a : { '$gte' : 11 } }"));
+ ASSERT_EQUALS(countRequest.getLimit(), 100);
+ ASSERT_EQUALS(countRequest.getSkip(), 1000);
+ ASSERT_EQUALS(countRequest.getHint(), fromjson("{ b : 5 }"));
+ }
+
+ TEST(CountRequest, ParseNegativeLimit) {
+ const auto countRequestStatus =
+ CountRequest::parseFromBSON("TestDB",
+ BSON("count" << "TestColl" <<
+ "query" << BSON("a" << BSON("$gte" << 11)) <<
+ "limit" << -100 <<
+ "skip" << 1000 <<
+ "hint" << BSON("b" << 5)));
+
+ ASSERT_OK(countRequestStatus.getStatus());
+
+ const CountRequest& countRequest = countRequestStatus.getValue();
+
+ ASSERT_EQUALS(countRequest.getNs(), "TestDB.TestColl");
+ ASSERT_EQUALS(countRequest.getQuery(), fromjson("{ a : { '$gte' : 11 } }"));
+ ASSERT_EQUALS(countRequest.getLimit(), 100);
+ ASSERT_EQUALS(countRequest.getSkip(), 1000);
+ ASSERT_EQUALS(countRequest.getHint(), fromjson("{ b : 5 }"));
+ }
+
+ TEST(CountRequest, FailParseMissingNS) {
+ const auto countRequestStatus =
+ CountRequest::parseFromBSON("TestDB",
+ BSON("query" << BSON("a" << BSON("$gte" << 11))));
+
+ ASSERT_EQUALS(countRequestStatus.getStatus(), ErrorCodes::BadValue);
+ }
+
+ TEST(CountRequest, FailParseBadSkipValue) {
+ const auto countRequestStatus =
+ CountRequest::parseFromBSON("TestDB",
+ BSON("count" << "TestColl" <<
+ "query" << BSON("a" << BSON("$gte" << 11)) <<
+ "skip" << -1000));
+
+ ASSERT_EQUALS(countRequestStatus.getStatus(), ErrorCodes::BadValue);
+ }
+
+ TEST(CountRequest, ToBSON) {
+ CountRequest countRequest("TestDB.TestColl", BSON("a" << BSON("$gte" << 11)));
+ countRequest.setLimit(100);
+ countRequest.setSkip(1000);
+ countRequest.setHint(BSON("b" << 5));
+
+ BSONObj actualObj = countRequest.toBSON();
+ BSONObj expectedObj(fromjson("{ count : 'TestDB.TestColl',"
+ " query : { a : { '$gte' : 11 } },"
+ " limit : 100,"
+ " skip : 1000,"
+ " hint : { b : 5 } }"));
+
+ ASSERT_EQUALS(actualObj, expectedObj);
+ }
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/db/query/find_and_modify_request.cpp b/src/mongo/db/query/find_and_modify_request.cpp
index 013baeb5079..1b960198d1a 100644
--- a/src/mongo/db/query/find_and_modify_request.cpp
+++ b/src/mongo/db/query/find_and_modify_request.cpp
@@ -49,8 +49,6 @@ namespace {
} // unnamed namespace
- FindAndModifyRequest::FindAndModifyRequest() = default;
-
FindAndModifyRequest::FindAndModifyRequest(NamespaceString fullNs,
BSONObj query,
BSONObj updateObj):
diff --git a/src/mongo/db/query/find_and_modify_request.h b/src/mongo/db/query/find_and_modify_request.h
index 569f1c66aaf..353869abee6 100644
--- a/src/mongo/db/query/find_and_modify_request.h
+++ b/src/mongo/db/query/find_and_modify_request.h
@@ -50,12 +50,6 @@ namespace mongo {
public:
/**
- * Do not use! This constructor is available only because StatusWith requires the
- * type to have one.
- */
- FindAndModifyRequest(); // TODO: SERVER-18007
-
- /**
* Creates a new instance of an 'update' type findAndModify request.
*/
static FindAndModifyRequest makeUpdate(NamespaceString fullNs,
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index 2b7f0980b4b..0f5044273ba 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -1216,6 +1216,7 @@ namespace {
bool explain,
PlanExecutor::YieldPolicy yieldPolicy,
PlanExecutor** execOut) {
+
unique_ptr<WorkingSet> ws(new WorkingSet());
PlanStage* root;
QuerySolution* querySolution;
@@ -1226,24 +1227,29 @@ namespace {
// to create a child for the count stage in this case.
//
// If there is a hint, then we can't use a trival count plan as described above.
- if (collection && request.query.isEmpty() && request.hint.isEmpty()) {
+ if (collection && request.getQuery().isEmpty() && request.getHint().isEmpty()) {
root = new CountStage(txn, collection, request, ws.get(), NULL);
- return PlanExecutor::make(txn, ws.release(), root, request.ns, yieldPolicy, execOut);
+ return PlanExecutor::make(txn,
+ ws.release(),
+ root,
+ request.getNs(),
+ yieldPolicy,
+ execOut);
}
unique_ptr<CanonicalQuery> cq;
- if (!request.query.isEmpty() || !request.hint.isEmpty()) {
+ if (!request.getQuery().isEmpty() || !request.getHint().isEmpty()) {
// If query or hint is not empty, canonicalize the query before working with collection.
typedef MatchExpressionParser::WhereCallback WhereCallback;
CanonicalQuery* rawCq = NULL;
Status canonStatus = CanonicalQuery::canonicalize(
- request.ns,
- request.query,
+ request.getNs(),
+ request.getQuery(),
BSONObj(), // sort
BSONObj(), // projection
0, // skip
0, // limit
- request.hint,
+ request.getHint(),
BSONObj(), // min
BSONObj(), // max
false, // snapshot
@@ -1264,7 +1270,12 @@ namespace {
// reporting machinery always assumes that the root stage for a count operation is
// a CountStage, so in this case we put a CountStage on top of an EOFStage.
root = new CountStage(txn, collection, request, ws.get(), new EOFStage());
- return PlanExecutor::make(txn, ws.release(), root, request.ns, yieldPolicy, execOut);
+ return PlanExecutor::make(txn,
+ ws.release(),
+ root,
+ request.getNs(),
+ yieldPolicy,
+ execOut);
}
invariant(cq.get());
diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h
index 221bef800fc..c92f67a00ca 100644
--- a/src/mongo/db/query/get_executor.h
+++ b/src/mongo/db/query/get_executor.h
@@ -40,7 +40,7 @@
namespace mongo {
class Collection;
- struct CountRequest;
+ class CountRequest;
struct GroupRequest;
diff --git a/src/mongo/db/query/getmore_request.h b/src/mongo/db/query/getmore_request.h
index 197125ecfcf..2d30f96ed75 100644
--- a/src/mongo/db/query/getmore_request.h
+++ b/src/mongo/db/query/getmore_request.h
@@ -45,7 +45,7 @@ namespace mongo {
GetMoreRequest();
/**
- * Construct a GetMoreRequesst from the command specification and db name.
+ * Construct a GetMoreRequest from the command specification and db name.
*/
static StatusWith<GetMoreRequest> parseFromBSON(const std::string& dbname,
const BSONObj& cmdObj);
diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp
index 09f64990bda..3a8ea2dcb8b 100644
--- a/src/mongo/dbtests/query_stage_count.cpp
+++ b/src/mongo/dbtests/query_stage_count.cpp
@@ -148,7 +148,7 @@ namespace QueryStageCount {
unique_ptr<WorkingSet> ws(new WorkingSet);
- StatusWithMatchExpression swme = MatchExpressionParser::parse(request.query);
+ StatusWithMatchExpression swme = MatchExpressionParser::parse(request.getQuery());
unique_ptr<MatchExpression> expression(swme.getValue());
PlanStage* scan;
@@ -164,7 +164,7 @@ namespace QueryStageCount {
ASSERT_FALSE(stats->trivialCount);
ASSERT_EQUALS(stats->nCounted, expected_n);
- ASSERT_EQUALS(stats->nSkipped, request.skip);
+ ASSERT_EQUALS(stats->nSkipped, request.getSkip());
}
// Performs a test using a count stage whereby each unit of work is interjected
@@ -220,16 +220,6 @@ namespace QueryStageCount {
return new CollectionScan(&_txn, params, ws, expr);
}
- CountRequest createCountRequest(const BSONObj& filter, size_t skip=0, size_t limit=0) {
- CountRequest request;
- request.ns = ns();
- request.query = filter;
- request.limit = limit;
- request.skip = skip;
- request.hint = BSONObj();
- return request;
- }
-
static const char* ns() { return "unittest.QueryStageCount"; }
protected:
@@ -244,8 +234,8 @@ namespace QueryStageCount {
class QueryStageCountNoChangeDuringYield : public CountStageTest {
public:
void run() {
- BSONObj filter = BSON("x" << LT << kDocuments/2);
- CountRequest request = createCountRequest(filter);
+ CountRequest request(ns(), BSON("x" << LT << kDocuments / 2));
+
testCount(request, kDocuments/2);
testCount(request, kDocuments/2, true);
}
@@ -254,7 +244,9 @@ namespace QueryStageCount {
class QueryStageCountYieldWithSkip : public CountStageTest {
public:
void run() {
- CountRequest request = createCountRequest(BSON("x" << GTE << 0), 2);
+ CountRequest request(ns(), BSON("x" << GTE << 0));
+ request.setSkip(2);
+
testCount(request, kDocuments-2);
testCount(request, kDocuments-2, true);
}
@@ -263,7 +255,10 @@ namespace QueryStageCount {
class QueryStageCountYieldWithLimit : public CountStageTest {
public:
void run() {
- CountRequest request = createCountRequest(BSON("x" << GTE << 0), 0, 2);
+ CountRequest request(ns(), BSON("x" << GTE << 0));
+ request.setSkip(0);
+ request.setLimit(2);
+
testCount(request, 2);
testCount(request, 2, true);
}
@@ -273,7 +268,8 @@ namespace QueryStageCount {
class QueryStageCountInsertDuringYield : public CountStageTest {
public:
void run() {
- CountRequest request = createCountRequest(BSON("x" << 1));
+ CountRequest request(ns(), BSON("x" << 1));
+
testCount(request, kInterjections+1);
testCount(request, kInterjections+1, true);
}
@@ -289,7 +285,8 @@ namespace QueryStageCount {
void run() {
// expected count would be 99 but we delete the second record
// after doing the first unit of work
- CountRequest request = createCountRequest(BSON("x" << GTE << 1));
+ CountRequest request(ns(), BSON("x" << GTE << 1));
+
testCount(request, kDocuments-2);
testCount(request, kDocuments-2, true);
}
@@ -313,7 +310,8 @@ namespace QueryStageCount {
void run() {
// expected count would be kDocuments-2 but we update the first and second records
// after doing the first unit of work so they wind up getting counted later on
- CountRequest request = createCountRequest(BSON("x" << GTE << 2));
+ CountRequest request(ns(), BSON("x" << GTE << 2));
+
testCount(request, kDocuments);
testCount(request, kDocuments, true);
}
@@ -335,7 +333,7 @@ namespace QueryStageCount {
class QueryStageCountMultiKeyDuringYield : public CountStageTest {
public:
void run() {
- CountRequest request = createCountRequest(BSON("x" << 1));
+ CountRequest request(ns(), BSON("x" << 1));
testCount(request, kDocuments+1, true); // only applies to indexed case
}