summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorTess Avitabile <tess.avitabile@mongodb.com>2016-04-28 16:36:11 -0400
committerTess Avitabile <tess.avitabile@mongodb.com>2016-05-05 10:29:06 -0400
commitf7a46a118288ba0ce45c7664777ea0e89c2eb845 (patch)
treed9ba6c6981072ce4b836617ebb1889ac17e4fcc2 /src/mongo
parentf49018bca41048d8a4f729ccc0489ea6be073a20 (diff)
downloadmongo-f7a46a118288ba0ce45c7664777ea0e89c2eb845.tar.gz
SERVER-23610 CanonicalQuery should own a CollatorInterface
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_local.cpp15
-rw-r--r--src/mongo/db/auth/authz_manager_external_state_mock.cpp2
-rw-r--r--src/mongo/db/auth/role_graph.h5
-rw-r--r--src/mongo/db/auth/role_graph_update.cpp10
-rw-r--r--src/mongo/db/commands/SConscript2
-rw-r--r--src/mongo/db/commands/find_cmd.cpp4
-rw-r--r--src/mongo/db/commands/geo_near_cmd.cpp2
-rw-r--r--src/mongo/db/commands/index_filter_commands.cpp2
-rw-r--r--src/mongo/db/commands/index_filter_commands_test.cpp35
-rw-r--r--src/mongo/db/commands/mr.cpp8
-rw-r--r--src/mongo/db/commands/mr.h2
-rw-r--r--src/mongo/db/commands/plan_cache_commands.cpp2
-rw-r--r--src/mongo/db/commands/plan_cache_commands_test.cpp36
-rw-r--r--src/mongo/db/dbcommands.cpp3
-rw-r--r--src/mongo/db/dbhelpers.cpp3
-rw-r--r--src/mongo/db/exec/sort_key_generator.cpp14
-rw-r--r--src/mongo/db/exec/sort_key_generator.h7
-rw-r--r--src/mongo/db/exec/subplan.cpp3
-rw-r--r--src/mongo/db/ops/SConscript1
-rw-r--r--src/mongo/db/ops/parsed_delete.cpp3
-rw-r--r--src/mongo/db/ops/parsed_update.cpp3
-rw-r--r--src/mongo/db/ops/update_driver.cpp5
-rw-r--r--src/mongo/db/ops/update_driver.h5
-rw-r--r--src/mongo/db/ops/update_driver_test.cpp76
-rw-r--r--src/mongo/db/pipeline/pipeline_d.cpp2
-rw-r--r--src/mongo/db/query/SConscript18
-rw-r--r--src/mongo/db/query/canonical_query.cpp32
-rw-r--r--src/mongo/db/query/canonical_query.h27
-rw-r--r--src/mongo/db/query/canonical_query_test.cpp33
-rw-r--r--src/mongo/db/query/collation/collator_factory_mock.cpp14
-rw-r--r--src/mongo/db/query/collation/collator_factory_mock_decoration.cpp50
-rw-r--r--src/mongo/db/query/collation/collator_factory_mock_test.cpp17
-rw-r--r--src/mongo/db/query/find.cpp2
-rw-r--r--src/mongo/db/query/get_executor.cpp12
-rw-r--r--src/mongo/db/query/get_executor_test.cpp6
-rw-r--r--src/mongo/db/query/plan_cache_test.cpp36
-rw-r--r--src/mongo/db/query/query_planner_test.cpp18
-rw-r--r--src/mongo/db/query/query_planner_test_fixture.cpp14
-rw-r--r--src/mongo/db/query/query_planner_test_fixture.h5
-rw-r--r--src/mongo/db/query/query_test_service_context.cpp47
-rw-r--r--src/mongo/db/query/query_test_service_context.h52
-rw-r--r--src/mongo/db/ttl.cpp2
-rw-r--r--src/mongo/dbtests/SConscript1
-rw-r--r--src/mongo/dbtests/documentsourcetests.cpp3
-rw-r--r--src/mongo/dbtests/executor_registry.cpp4
-rw-r--r--src/mongo/dbtests/oplogstarttests.cpp2
-rw-r--r--src/mongo/dbtests/plan_ranking.cpp48
-rw-r--r--src/mongo/dbtests/query_plan_executor.cpp8
-rw-r--r--src/mongo/dbtests/query_stage_cached_plan.cpp8
-rw-r--r--src/mongo/dbtests/query_stage_delete.cpp2
-rw-r--r--src/mongo/dbtests/query_stage_multiplan.cpp15
-rw-r--r--src/mongo/dbtests/query_stage_subplan.cpp20
-rw-r--r--src/mongo/dbtests/query_stage_update.cpp2
-rw-r--r--src/mongo/dbtests/sort_key_generator_test.cpp11
-rw-r--r--src/mongo/s/SConscript2
-rw-r--r--src/mongo/s/chunk_manager.cpp2
-rw-r--r--src/mongo/s/chunk_manager_targeter.cpp13
-rw-r--r--src/mongo/s/chunk_manager_targeter_test.cpp7
-rw-r--r--src/mongo/s/commands/cluster_find_and_modify_cmd.cpp10
-rw-r--r--src/mongo/s/commands/cluster_find_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_move_chunk_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_pipeline_cmd.cpp2
-rw-r--r--src/mongo/s/commands/cluster_split_cmd.cpp3
-rw-r--r--src/mongo/s/commands/strategy.cpp2
-rw-r--r--src/mongo/s/shard_key_pattern.cpp7
-rw-r--r--src/mongo/s/shard_key_pattern.h4
-rw-r--r--src/mongo/s/shard_key_pattern_test.cpp6
67 files changed, 582 insertions, 241 deletions
diff --git a/src/mongo/db/auth/authz_manager_external_state_local.cpp b/src/mongo/db/auth/authz_manager_external_state_local.cpp
index 7525464f6bb..5d76027fc22 100644
--- a/src/mongo/db/auth/authz_manager_external_state_local.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp
@@ -370,14 +370,16 @@ Status AuthzManagerExternalStateLocal::_initializeRoleGraph(OperationContext* tx
class AuthzManagerExternalStateLocal::AuthzManagerLogOpHandler : public RecoveryUnit::Change {
public:
- // None of the parameters below (except externalState) need to live longer than
- // the instantiations of this class
- AuthzManagerLogOpHandler(AuthzManagerExternalStateLocal* externalState,
+ // None of the parameters below (except txn and externalState) need to live longer than the
+ // instantiations of this class
+ AuthzManagerLogOpHandler(OperationContext* txn,
+ AuthzManagerExternalStateLocal* externalState,
const char* op,
const char* ns,
const BSONObj& o,
const BSONObj* o2)
- : _externalState(externalState),
+ : _txn(txn),
+ _externalState(externalState),
_op(op),
_ns(ns),
_o(o.getOwned()),
@@ -388,7 +390,7 @@ public:
virtual void commit() {
stdx::lock_guard<stdx::mutex> lk(_externalState->_roleGraphMutex);
Status status = _externalState->_roleGraph.handleLogOp(
- _op.c_str(), NamespaceString(_ns.c_str()), _o, _isO2Set ? &_o2 : NULL);
+ _txn, _op.c_str(), NamespaceString(_ns.c_str()), _o, _isO2Set ? &_o2 : NULL);
if (status == ErrorCodes::OplogOperationUnsupported) {
_externalState->_roleGraph = RoleGraph();
@@ -419,6 +421,7 @@ public:
virtual void rollback() {}
private:
+ OperationContext* _txn;
AuthzManagerExternalStateLocal* _externalState;
const std::string _op;
const std::string _ns;
@@ -432,7 +435,7 @@ void AuthzManagerExternalStateLocal::logOp(
OperationContext* txn, const char* op, const char* ns, const BSONObj& o, const BSONObj* o2) {
if (ns == AuthorizationManager::rolesCollectionNamespace.ns() ||
ns == AuthorizationManager::adminCommandNamespace.ns()) {
- txn->recoveryUnit()->registerChange(new AuthzManagerLogOpHandler(this, op, ns, o, o2));
+ txn->recoveryUnit()->registerChange(new AuthzManagerLogOpHandler(txn, this, op, ns, o, o2));
}
}
diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
index 47f65d888c4..6bab48f91e9 100644
--- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp
+++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp
@@ -204,7 +204,7 @@ Status AuthzManagerExternalStateMock::updateOne(OperationContext* txn,
if (query.hasField("_id")) {
document.root().appendElement(query["_id"]);
}
- status = driver.populateDocumentWithQueryFields(query, NULL, document);
+ status = driver.populateDocumentWithQueryFields(txn, query, NULL, document);
if (!status.isOK()) {
return status;
}
diff --git a/src/mongo/db/auth/role_graph.h b/src/mongo/db/auth/role_graph.h
index 50a0c47a857..42512312b64 100644
--- a/src/mongo/db/auth/role_graph.h
+++ b/src/mongo/db/auth/role_graph.h
@@ -41,6 +41,8 @@
namespace mongo {
+class OperationContext;
+
/**
* A graph of role and privilege relationships.
*
@@ -240,7 +242,8 @@ public:
* operation is not supported, and other codes (typically BadValue) if the oplog operation
* is ill-described.
*/
- Status handleLogOp(const char* op,
+ Status handleLogOp(OperationContext* txn,
+ const char* op,
const NamespaceString& ns,
const BSONObj& o,
const BSONObj* o2);
diff --git a/src/mongo/db/auth/role_graph_update.cpp b/src/mongo/db/auth/role_graph_update.cpp
index 62df4a33a4b..6d44385b8f8 100644
--- a/src/mongo/db/auth/role_graph_update.cpp
+++ b/src/mongo/db/auth/role_graph_update.cpp
@@ -160,7 +160,8 @@ Status handleOplogInsert(RoleGraph* roleGraph, const BSONObj& insertedObj) {
*
* Treats all updates as upserts.
*/
-Status handleOplogUpdate(RoleGraph* roleGraph,
+Status handleOplogUpdate(OperationContext* txn,
+ RoleGraph* roleGraph,
const BSONObj& updatePattern,
const BSONObj& queryPattern) {
RoleName roleToUpdate;
@@ -178,7 +179,7 @@ Status handleOplogUpdate(RoleGraph* roleGraph,
status = AuthorizationManager::getBSONForRole(roleGraph, roleToUpdate, roleDocument.root());
if (status == ErrorCodes::RoleNotFound) {
// The query pattern will only contain _id, no other immutable fields are present
- status = driver.populateDocumentWithQueryFields(queryPattern, NULL, roleDocument);
+ status = driver.populateDocumentWithQueryFields(txn, queryPattern, NULL, roleDocument);
}
if (!status.isOK())
return status;
@@ -273,7 +274,8 @@ Status RoleGraph::addRoleFromDocument(const BSONObj& doc) {
return status;
}
-Status RoleGraph::handleLogOp(const char* op,
+Status RoleGraph::handleLogOp(OperationContext* txn,
+ const char* op,
const NamespaceString& ns,
const BSONObj& o,
const BSONObj* o2) {
@@ -307,7 +309,7 @@ Status RoleGraph::handleLogOp(const char* op,
return Status(ErrorCodes::InternalError,
"Missing query pattern in update oplog entry.");
}
- return handleOplogUpdate(this, o, *o2);
+ return handleOplogUpdate(txn, this, o, *o2);
case 'd':
return handleOplogDelete(this, o);
case 'n':
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript
index 74935b95a60..54dbbc405fa 100644
--- a/src/mongo/db/commands/SConscript
+++ b/src/mongo/db/commands/SConscript
@@ -98,6 +98,7 @@ env.CppUnitTest(
"index_filter_commands_test.cpp",
],
LIBDEPS=[
+ "$BUILD_DIR/mongo/db/query/query_test_service_context",
"$BUILD_DIR/mongo/db/serveronly",
"$BUILD_DIR/mongo/util/ntservice_mock",
],
@@ -122,6 +123,7 @@ env.CppUnitTest(
"plan_cache_commands_test.cpp",
],
LIBDEPS=[
+ "$BUILD_DIR/mongo/db/query/query_test_service_context",
"$BUILD_DIR/mongo/db/serveronly",
"$BUILD_DIR/mongo/util/ntservice_mock",
],
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index 8741623dd8c..13ba25eb033 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -147,7 +147,7 @@ public:
ExtensionsCallbackReal extensionsCallback(txn, &nss);
auto statusWithCQ =
- CanonicalQuery::canonicalize(lpqStatus.getValue().release(), extensionsCallback);
+ CanonicalQuery::canonicalize(txn, lpqStatus.getValue().release(), extensionsCallback);
if (!statusWithCQ.isOK()) {
return statusWithCQ.getStatus();
}
@@ -232,7 +232,7 @@ public:
// Finish the parsing step by using the LiteParsedQuery to create a CanonicalQuery.
ExtensionsCallbackReal extensionsCallback(txn, &nss);
- auto statusWithCQ = CanonicalQuery::canonicalize(lpq.release(), extensionsCallback);
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn, lpq.release(), extensionsCallback);
if (!statusWithCQ.isOK()) {
return appendCommandStatus(result, statusWithCQ.getStatus());
}
diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp
index aaef5f68171..392c0f58993 100644
--- a/src/mongo/db/commands/geo_near_cmd.cpp
+++ b/src/mongo/db/commands/geo_near_cmd.cpp
@@ -209,7 +209,7 @@ public:
const ExtensionsCallbackReal extensionsCallback(txn, &nss);
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, rewritten, BSONObj(), projObj, 0, numWanted, BSONObj(), extensionsCallback);
+ txn, nss, rewritten, BSONObj(), projObj, 0, numWanted, BSONObj(), extensionsCallback);
if (!statusWithCQ.isOK()) {
errmsg = "Can't parse filter / create query";
return false;
diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp
index 287e7e5950f..961e34e4ccd 100644
--- a/src/mongo/db/commands/index_filter_commands.cpp
+++ b/src/mongo/db/commands/index_filter_commands.cpp
@@ -323,7 +323,7 @@ Status ClearFilters::clear(OperationContext* txn,
// Create canonical query.
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, entry->query, entry->sort, entry->projection, extensionsCallback);
+ txn, nss, entry->query, entry->sort, entry->projection, extensionsCallback);
invariant(statusWithCQ.isOK());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/db/commands/index_filter_commands_test.cpp b/src/mongo/db/commands/index_filter_commands_test.cpp
index 463f1bb117e..7015d32ec56 100644
--- a/src/mongo/db/commands/index_filter_commands_test.cpp
+++ b/src/mongo/db/commands/index_filter_commands_test.cpp
@@ -38,6 +38,7 @@
#include "mongo/db/operation_context_noop.h"
#include "mongo/db/query/plan_ranker.h"
#include "mongo/db/query/query_solution.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/unittest/unittest.h"
using namespace mongo;
@@ -112,7 +113,8 @@ PlanRankingDecision* createDecision(size_t numPlans) {
/**
* Injects an entry into plan cache for query shape.
*/
-void addQueryShapeToPlanCache(PlanCache* planCache,
+void addQueryShapeToPlanCache(OperationContext* txn,
+ PlanCache* planCache,
const char* queryStr,
const char* sortStr,
const char* projectionStr) {
@@ -122,7 +124,7 @@ void addQueryShapeToPlanCache(PlanCache* planCache,
// Create canonical query.
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, queryObj, sortObj, projectionObj, ExtensionsCallbackDisallowExtensions());
+ txn, nss, queryObj, sortObj, projectionObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -141,13 +143,16 @@ bool planCacheContains(const PlanCache& planCache,
const char* queryStr,
const char* sortStr,
const char* projectionStr) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
BSONObj queryObj = fromjson(queryStr);
BSONObj sortObj = fromjson(sortStr);
BSONObj projectionObj = fromjson(projectionStr);
// Create canonical query.
auto statusWithInputQuery = CanonicalQuery::canonicalize(
- nss, queryObj, sortObj, projectionObj, ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, queryObj, sortObj, projectionObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithInputQuery.getStatus());
unique_ptr<CanonicalQuery> inputQuery = std::move(statusWithInputQuery.getValue());
@@ -163,7 +168,8 @@ bool planCacheContains(const PlanCache& planCache,
// Alternatively, we could add key to PlanCacheEntry but that would be used in one place
// only.
auto statusWithCurrentQuery =
- CanonicalQuery::canonicalize(nss,
+ CanonicalQuery::canonicalize(txn.get(),
+ nss,
entry->query,
entry->sort,
entry->projection,
@@ -296,13 +302,14 @@ TEST(IndexFilterCommandsTest, SetFilterInvalidParameter) {
TEST(IndexFilterCommandsTest, SetAndClearFilters) {
QuerySettings querySettings;
PlanCache planCache;
- OperationContextNoop txn;
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
// Inject query shape into plan cache.
- addQueryShapeToPlanCache(&planCache, "{a: 1, b: 1}", "{a: -1}", "{_id: 0, a: 1}");
+ addQueryShapeToPlanCache(txn.get(), &planCache, "{a: 1, b: 1}", "{a: -1}", "{_id: 0, a: 1}");
ASSERT_TRUE(planCacheContains(planCache, "{a: 1, b: 1}", "{a: -1}", "{_id: 0, a: 1}"));
- ASSERT_OK(SetFilter::set(&txn,
+ ASSERT_OK(SetFilter::set(txn.get(),
&querySettings,
&planCache,
nss.ns(),
@@ -322,7 +329,7 @@ TEST(IndexFilterCommandsTest, SetAndClearFilters) {
// Replacing the hint for the same query shape ({a: 1, b: 1} and {b: 2, a: 3}
// share same shape) should not change the query settings size.
- ASSERT_OK(SetFilter::set(&txn,
+ ASSERT_OK(SetFilter::set(txn.get(),
&querySettings,
&planCache,
nss.ns(),
@@ -333,7 +340,7 @@ TEST(IndexFilterCommandsTest, SetAndClearFilters) {
ASSERT_EQUALS(filters.size(), 1U);
// Add hint for different query shape.
- ASSERT_OK(SetFilter::set(&txn,
+ ASSERT_OK(SetFilter::set(txn.get(),
&querySettings,
&planCache,
nss.ns(),
@@ -342,7 +349,7 @@ TEST(IndexFilterCommandsTest, SetAndClearFilters) {
ASSERT_EQUALS(filters.size(), 2U);
// Add hint for 3rd query shape. This is to prepare for ClearHint tests.
- ASSERT_OK(SetFilter::set(&txn,
+ ASSERT_OK(SetFilter::set(txn.get(),
&querySettings,
&planCache,
nss.ns(),
@@ -351,12 +358,12 @@ TEST(IndexFilterCommandsTest, SetAndClearFilters) {
ASSERT_EQUALS(filters.size(), 3U);
// Add 2 entries to plan cache and check plan cache after clearing one/all filters.
- addQueryShapeToPlanCache(&planCache, "{a: 1}", "{}", "{}");
- addQueryShapeToPlanCache(&planCache, "{b: 1}", "{}", "{}");
+ addQueryShapeToPlanCache(txn.get(), &planCache, "{a: 1}", "{}", "{}");
+ addQueryShapeToPlanCache(txn.get(), &planCache, "{b: 1}", "{}", "{}");
// Clear single hint.
ASSERT_OK(ClearFilters::clear(
- &txn, &querySettings, &planCache, nss.ns(), fromjson("{query: {a: 1}}")));
+ txn.get(), &querySettings, &planCache, nss.ns(), fromjson("{query: {a: 1}}")));
filters = getFilters(querySettings);
ASSERT_EQUALS(filters.size(), 2U);
@@ -365,7 +372,7 @@ TEST(IndexFilterCommandsTest, SetAndClearFilters) {
ASSERT_TRUE(planCacheContains(planCache, "{b: 1}", "{}", "{}"));
// Clear all filters
- ASSERT_OK(ClearFilters::clear(&txn, &querySettings, &planCache, nss.ns(), fromjson("{}")));
+ ASSERT_OK(ClearFilters::clear(txn.get(), &querySettings, &planCache, nss.ns(), fromjson("{}")));
filters = getFilters(querySettings);
ASSERT_TRUE(filters.empty());
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index e8c1651aa8a..3f0b2643af8 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -983,7 +983,7 @@ BSONObj _nativeToTemp(const BSONObj& args, void* data) {
* After calling this method, the temp collection will be completed.
* If inline, the results will be in the in memory map
*/
-void State::finalReduce(CurOp* curOp, ProgressMeterHolder& pm) {
+void State::finalReduce(OperationContext* txn, CurOp* curOp, ProgressMeterHolder& pm) {
if (_jsMode) {
// apply the reduce within JS
if (_onDisk) {
@@ -1061,7 +1061,7 @@ void State::finalReduce(CurOp* curOp, ProgressMeterHolder& pm) {
const ExtensionsCallbackReal extensionsCallback(_txn, &nss);
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, BSONObj(), sortKey, BSONObj(), extensionsCallback);
+ CanonicalQuery::canonicalize(txn, nss, BSONObj(), sortKey, BSONObj(), extensionsCallback);
verify(statusWithCQ.isOK());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -1430,7 +1430,7 @@ public:
const ExtensionsCallbackReal extensionsCallback(txn, &nss);
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, config.filter, config.sort, BSONObj(), extensionsCallback);
+ txn, nss, config.filter, config.sort, BSONObj(), extensionsCallback);
if (!statusWithCQ.isOK()) {
uasserted(17238, "Can't canonicalize query " + config.filter.toString());
return 0;
@@ -1572,7 +1572,7 @@ public:
// if not inline: dump the in memory map to inc collection, all data is on disk
state.dumpToInc();
// final reduce
- state.finalReduce(curOp, pm);
+ state.finalReduce(txn, curOp, pm);
reduceTime += rt.micros();
countsBuilder.appendNumber("reduce", state.numReduces());
timingBuilder.appendNumber("reduceTime", reduceTime / 1000);
diff --git a/src/mongo/db/commands/mr.h b/src/mongo/db/commands/mr.h
index 3237e6f7238..0fdec1129a9 100644
--- a/src/mongo/db/commands/mr.h
+++ b/src/mongo/db/commands/mr.h
@@ -306,7 +306,7 @@ public:
void finalReduce(BSONList& values);
- void finalReduce(CurOp* op, ProgressMeterHolder& pm);
+ void finalReduce(OperationContext* txn, CurOp* op, ProgressMeterHolder& pm);
// ------- cleanup/data positioning ----------
diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp
index b7c408f3b3c..f48c16dc268 100644
--- a/src/mongo/db/commands/plan_cache_commands.cpp
+++ b/src/mongo/db/commands/plan_cache_commands.cpp
@@ -212,7 +212,7 @@ StatusWith<unique_ptr<CanonicalQuery>> PlanCacheCommand::canonicalize(OperationC
const ExtensionsCallbackReal extensionsCallback(txn, &nss);
auto statusWithCQ = CanonicalQuery::canonicalize(
- std::move(nss), queryObj, sortObj, projObj, extensionsCallback);
+ txn, std::move(nss), queryObj, sortObj, projObj, extensionsCallback);
if (!statusWithCQ.isOK()) {
return statusWithCQ.getStatus();
}
diff --git a/src/mongo/db/commands/plan_cache_commands_test.cpp b/src/mongo/db/commands/plan_cache_commands_test.cpp
index 7234588fd37..ab811c7cf92 100644
--- a/src/mongo/db/commands/plan_cache_commands_test.cpp
+++ b/src/mongo/db/commands/plan_cache_commands_test.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/operation_context_noop.h"
#include "mongo/db/query/plan_ranker.h"
#include "mongo/db/query/query_solution.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/mongoutils/str.h"
@@ -125,9 +126,12 @@ TEST(PlanCacheCommandsTest, planCacheListQueryShapesEmpty) {
}
TEST(PlanCacheCommandsTest, planCacheListQueryShapesOneKey) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
// Create a canonical query
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -151,16 +155,18 @@ TEST(PlanCacheCommandsTest, planCacheListQueryShapesOneKey) {
*/
TEST(PlanCacheCommandsTest, planCacheClearAllShapes) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
// Create a canonical query
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
// Plan cache with one entry
PlanCache planCache;
QuerySolution qs;
- OperationContextNoop txn;
qs.cacheData.reset(createSolutionCacheData());
std::vector<QuerySolution*> solns;
@@ -169,7 +175,7 @@ TEST(PlanCacheCommandsTest, planCacheClearAllShapes) {
ASSERT_EQUALS(getShapes(planCache).size(), 1U);
// Clear cache and confirm number of keys afterwards.
- ASSERT_OK(PlanCacheClear::clear(&txn, &planCache, nss.ns(), BSONObj()));
+ ASSERT_OK(PlanCacheClear::clear(txn.get(), &planCache, nss.ns(), BSONObj()));
ASSERT_EQUALS(getShapes(planCache).size(), 0U);
}
@@ -268,13 +274,16 @@ TEST(PlanCacheCommandsTest, planCacheClearUnknownKey) {
}
TEST(PlanCacheCommandsTest, planCacheClearOneKey) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
// Create 2 canonical queries.
auto statusWithCQA = CanonicalQuery::canonicalize(
- nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQA.getStatus());
unique_ptr<CanonicalQuery> cqA = std::move(statusWithCQA.getValue());
auto statusWithCQB = CanonicalQuery::canonicalize(
- nss, fromjson("{b: 1}"), ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, fromjson("{b: 1}"), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQB.getStatus());
unique_ptr<CanonicalQuery> cqB = std::move(statusWithCQB.getValue());
@@ -299,10 +308,9 @@ TEST(PlanCacheCommandsTest, planCacheClearOneKey) {
// Drop {b: 1} from cache. Make sure {a: 1} is still in cache afterwards.
BSONObjBuilder bob;
- OperationContextNoop txn;
- ASSERT_OK(
- PlanCacheClear::clear(&txn, &planCache, nss.ns(), BSON("query" << cqB->getQueryObj())));
+ ASSERT_OK(PlanCacheClear::clear(
+ txn.get(), &planCache, nss.ns(), BSON("query" << cqB->getQueryObj())));
vector<BSONObj> shapesAfter = getShapes(planCache);
ASSERT_EQUALS(shapesAfter.size(), 1U);
ASSERT_EQUALS(shapesAfter[0], shapeA);
@@ -392,9 +400,12 @@ TEST(PlanCacheCommandsTest, planCacheListPlansUnknownKey) {
}
TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionTrue) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
// Create a canonical query
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -412,9 +423,12 @@ TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionTrue) {
}
TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionFalse) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
// Create a canonical query
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, fromjson("{a: 1}"), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index a23025034f0..b1fbd59940c 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -631,7 +631,8 @@ public:
MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
auto statusWithCQ =
- CanonicalQuery::canonicalize(NamespaceString(ns),
+ CanonicalQuery::canonicalize(txn,
+ NamespaceString(ns),
query,
sort,
BSONObj(),
diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp
index 623a06b9098..54157d737fe 100644
--- a/src/mongo/db/dbhelpers.cpp
+++ b/src/mongo/db/dbhelpers.cpp
@@ -134,7 +134,8 @@ RecordId Helpers::findOne(OperationContext* txn,
const ExtensionsCallbackReal extensionsCallback(txn, &collection->ns());
- auto statusWithCQ = CanonicalQuery::canonicalize(collection->ns(), query, extensionsCallback);
+ auto statusWithCQ =
+ CanonicalQuery::canonicalize(txn, collection->ns(), query, extensionsCallback);
massert(17244, "Could not canonicalize " + query.toString(), statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/db/exec/sort_key_generator.cpp b/src/mongo/db/exec/sort_key_generator.cpp
index 7ffa4fe3f52..0625e1553fc 100644
--- a/src/mongo/db/exec/sort_key_generator.cpp
+++ b/src/mongo/db/exec/sort_key_generator.cpp
@@ -50,7 +50,9 @@ namespace mongo {
// SortKeyGenerator
//
-SortKeyGenerator::SortKeyGenerator(const BSONObj& sortSpec, const BSONObj& queryObj) {
+SortKeyGenerator::SortKeyGenerator(OperationContext* txn,
+ const BSONObj& sortSpec,
+ const BSONObj& queryObj) {
_hasBounds = false;
_sortHasMeta = false;
_rawSortSpec = sortSpec;
@@ -100,7 +102,7 @@ SortKeyGenerator::SortKeyGenerator(const BSONObj& sortSpec, const BSONObj& query
_keyGen.reset(new BtreeKeyGeneratorV1(fieldNames, fixed, false /* not sparse */, nullptr));
// The bounds checker only works on the Btree part of the sort key.
- getBoundsForSort(queryObj, _btreeObj);
+ getBoundsForSort(txn, queryObj, _btreeObj);
if (_hasBounds) {
_boundsChecker.reset(new IndexBoundsChecker(&_bounds, _btreeObj, 1 /* == order */));
@@ -220,7 +222,9 @@ StatusWith<BSONObj> SortKeyGenerator::getSortKeyFromObject(const WorkingSetMembe
return *keys.begin();
}
-void SortKeyGenerator::getBoundsForSort(const BSONObj& queryObj, const BSONObj& sortObj) {
+void SortKeyGenerator::getBoundsForSort(OperationContext* txn,
+ const BSONObj& queryObj,
+ const BSONObj& sortObj) {
QueryPlannerParams params;
params.options = QueryPlannerParams::NO_TABLE_SCAN;
@@ -230,7 +234,7 @@ void SortKeyGenerator::getBoundsForSort(const BSONObj& queryObj, const BSONObj&
params.indices.push_back(sortOrder);
auto statusWithQueryForSort = CanonicalQuery::canonicalize(
- NamespaceString("fake.ns"), queryObj, ExtensionsCallbackNoop());
+ txn, NamespaceString("fake.ns"), queryObj, ExtensionsCallbackNoop());
verify(statusWithQueryForSort.isOK());
std::unique_ptr<CanonicalQuery> queryForSort = std::move(statusWithQueryForSort.getValue());
@@ -287,7 +291,7 @@ bool SortKeyGeneratorStage::isEOF() {
PlanStage::StageState SortKeyGeneratorStage::doWork(WorkingSetID* out) {
if (!_sortKeyGen) {
- _sortKeyGen = stdx::make_unique<SortKeyGenerator>(_sortSpec, _query);
+ _sortKeyGen = stdx::make_unique<SortKeyGenerator>(getOpCtx(), _sortSpec, _query);
return PlanStage::NEED_TIME;
}
diff --git a/src/mongo/db/exec/sort_key_generator.h b/src/mongo/db/exec/sort_key_generator.h
index ea035c5db5e..b63b56b0c4d 100644
--- a/src/mongo/db/exec/sort_key_generator.h
+++ b/src/mongo/db/exec/sort_key_generator.h
@@ -52,8 +52,11 @@ public:
* 'queryObj' is the BSONObj in the .find(...) clause. For multikey arrays we have to
* ensure that the value we select to sort by is within bounds generated by
* executing 'queryObj' using the virtual index with key pattern 'sortSpec'.
+ *
+ * 'txn' must point to a valid OperationContext, but 'txn' does not need to outlive the
+ * constructed SortKeyGenerator.
*/
- SortKeyGenerator(const BSONObj& sortSpec, const BSONObj& queryObj);
+ SortKeyGenerator(OperationContext* txn, const BSONObj& sortSpec, const BSONObj& queryObj);
/**
* Returns the key used to sort 'member'. If the member is in LOC_AND_IDX state, it must not
@@ -76,7 +79,7 @@ private:
*
* Populates _hasBounds and _bounds.
*/
- void getBoundsForSort(const BSONObj& queryObj, const BSONObj& sortObj);
+ void getBoundsForSort(OperationContext* txn, const BSONObj& queryObj, const BSONObj& sortObj);
// The raw object in .sort()
BSONObj _rawSortSpec;
diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp
index 320e3d58502..b694a4cc902 100644
--- a/src/mongo/db/exec/subplan.cpp
+++ b/src/mongo/db/exec/subplan.cpp
@@ -186,7 +186,8 @@ Status SubplanStage::planSubqueries() {
MatchExpression* orChild = _orExpression->getChild(i);
// Turn the i-th child into its own query.
- auto statusWithCQ = CanonicalQuery::canonicalize(*_query, orChild, extensionsCallback);
+ auto statusWithCQ =
+ CanonicalQuery::canonicalize(getOpCtx(), *_query, orChild, extensionsCallback);
if (!statusWithCQ.isOK()) {
mongoutils::str::stream ss;
ss << "Can't canonicalize subchild " << orChild->toString() << " "
diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript
index a6ac8dff253..e91110656a4 100644
--- a/src/mongo/db/ops/SConscript
+++ b/src/mongo/db/ops/SConscript
@@ -231,6 +231,7 @@ env.CppUnitTest(
LIBDEPS=[
'$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils',
'$BUILD_DIR/mongo/db/query/query_planner',
+ '$BUILD_DIR/mongo/db/query/query_test_service_context',
'update_driver',
],
)
diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp
index 5b488412827..80cc3b44d8b 100644
--- a/src/mongo/db/ops/parsed_delete.cpp
+++ b/src/mongo/db/ops/parsed_delete.cpp
@@ -83,7 +83,8 @@ Status ParsedDelete::parseQueryToCQ() {
// The projection needs to be applied after the delete operation, so we specify an empty
// BSONObj as the projection during canonicalization.
const BSONObj emptyObj;
- auto statusWithCQ = CanonicalQuery::canonicalize(_request->getNamespaceString(),
+ auto statusWithCQ = CanonicalQuery::canonicalize(_txn,
+ _request->getNamespaceString(),
_request->getQuery(),
_request->getSort(),
emptyObj, // projection
diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp
index ce4dc8d79ce..1de16adeff5 100644
--- a/src/mongo/db/ops/parsed_update.cpp
+++ b/src/mongo/db/ops/parsed_update.cpp
@@ -88,7 +88,8 @@ Status ParsedUpdate::parseQueryToCQ() {
// The projection needs to be applied after the update operation, so we specify an empty
// BSONObj as the projection during canonicalization.
const BSONObj emptyObj;
- auto statusWithCQ = CanonicalQuery::canonicalize(_request->getNamespaceString(),
+ auto statusWithCQ = CanonicalQuery::canonicalize(_txn,
+ _request->getNamespaceString(),
_request->getQuery(),
_request->getSort(),
emptyObj, // projection
diff --git a/src/mongo/db/ops/update_driver.cpp b/src/mongo/db/ops/update_driver.cpp
index d3b5f32c16a..885759df77b 100644
--- a/src/mongo/db/ops/update_driver.cpp
+++ b/src/mongo/db/ops/update_driver.cpp
@@ -167,14 +167,15 @@ inline Status UpdateDriver::addAndParse(const modifiertable::ModifierType type,
return Status::OK();
}
-Status UpdateDriver::populateDocumentWithQueryFields(const BSONObj& query,
+Status UpdateDriver::populateDocumentWithQueryFields(OperationContext* txn,
+ const BSONObj& query,
const vector<FieldRef*>* immutablePaths,
mutablebson::Document& doc) const {
// We canonicalize the query to collapse $and/$or, and the first arg (ns) is not needed. Also,
// because this is for the upsert case, where we insert a new document if one was not found, the
// $where/$text clauses do not make sense, hence empty ExtensionsCallback.
auto statusWithCQ =
- CanonicalQuery::canonicalize(NamespaceString(""), query, ExtensionsCallbackNoop());
+ CanonicalQuery::canonicalize(txn, NamespaceString(""), query, ExtensionsCallbackNoop());
if (!statusWithCQ.isOK()) {
return statusWithCQ.getStatus();
}
diff --git a/src/mongo/db/ops/update_driver.h b/src/mongo/db/ops/update_driver.h
index bb11ee42bb4..dd1c940586e 100644
--- a/src/mongo/db/ops/update_driver.h
+++ b/src/mongo/db/ops/update_driver.h
@@ -43,6 +43,8 @@
namespace mongo {
+class OperationContext;
+
class UpdateDriver {
public:
struct Options;
@@ -67,7 +69,8 @@ public:
* Returns Status::OK() if the document can be used. If there are any error or
* conflicts along the way then those errors will be returned.
*/
- Status populateDocumentWithQueryFields(const BSONObj& query,
+ Status populateDocumentWithQueryFields(OperationContext* txn,
+ const BSONObj& query,
const std::vector<FieldRef*>* immutablePaths,
mutablebson::Document& doc) const;
diff --git a/src/mongo/db/ops/update_driver_test.cpp b/src/mongo/db/ops/update_driver_test.cpp
index 1a778b231a9..a2347b1048f 100644
--- a/src/mongo/db/ops/update_driver_test.cpp
+++ b/src/mongo/db/ops/update_driver_test.cpp
@@ -37,6 +37,7 @@
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
#include "mongo/db/field_ref.h"
#include "mongo/db/json.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/db/update_index_data.h"
#include "mongo/unittest/unittest.h"
@@ -47,11 +48,14 @@ using mongo::BSONElement;
using mongo::BSONObjIterator;
using mongo::FieldRef;
using mongo::fromjson;
-using mongo::OwnedPointerVector;
-using mongo::UpdateIndexData;
using mongo::mutablebson::Document;
+using mongo::OperationContext;
+using mongo::OwnedPointerVector;
+using mongo::QueryTestServiceContext;
+using mongo::ServiceContext;
using mongo::StringData;
using mongo::UpdateDriver;
+using mongo::UpdateIndexData;
using mongoutils::str::stream;
TEST(Parse, Normal) {
@@ -139,6 +143,7 @@ public:
_driverRepl(new UpdateDriver(UpdateDriver::Options())) {
_driverOps->parse(fromjson("{$set:{'_':1}}"));
_driverRepl->parse(fromjson("{}"));
+ _opCtx = _serviceContext.makeOperationContext();
}
Document& doc() {
@@ -153,7 +158,13 @@ public:
return *_driverRepl;
}
+ OperationContext* txn() {
+ return _opCtx.get();
+ }
+
private:
+ QueryTestServiceContext _serviceContext;
+ ServiceContext::UniqueOperationContext _opCtx;
std::unique_ptr<UpdateDriver> _driverOps;
std::unique_ptr<UpdateDriver> _driverRepl;
Document _doc;
@@ -218,139 +229,139 @@ static void assertSameFields(const BSONObj& docA, const BSONObj& docB) {
TEST_F(CreateFromQuery, BasicOp) {
BSONObj query = fromjson("{a:1,b:2}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(query, doc().getObject());
}
TEST_F(CreateFromQuery, BasicOpEq) {
BSONObj query = fromjson("{a:{$eq:1}}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{a:1}"), doc().getObject());
}
TEST_F(CreateFromQuery, BasicOpWithId) {
BSONObj query = fromjson("{_id:1,a:1,b:2}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(query, doc().getObject());
}
TEST_F(CreateFromQuery, BasicRepl) {
BSONObj query = fromjson("{a:1,b:2}");
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{}"), doc().getObject());
}
TEST_F(CreateFromQuery, BasicReplWithId) {
BSONObj query = fromjson("{_id:1,a:1,b:2}");
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{_id:1}"), doc().getObject());
}
TEST_F(CreateFromQuery, BasicReplWithIdEq) {
BSONObj query = fromjson("{_id:{$eq:1},a:1,b:2}");
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{_id:1}"), doc().getObject());
}
TEST_F(CreateFromQuery, NoRootIdOp) {
BSONObj query = fromjson("{'_id.a':1,'_id.b':2}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{_id:{a:1,b:2}}"), doc().getObject());
}
TEST_F(CreateFromQuery, NoRootIdRepl) {
BSONObj query = fromjson("{'_id.a':1,'_id.b':2}");
- ASSERT_NOT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_NOT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
}
TEST_F(CreateFromQuery, NestedSharedRootOp) {
BSONObj query = fromjson("{'a.c':1,'a.b':{$eq:2}}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{a:{c:1,b:2}}"), doc().getObject());
}
TEST_F(CreateFromQuery, OrQueryOp) {
BSONObj query = fromjson("{$or:[{a:1}]}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{a:1}"), doc().getObject());
}
TEST_F(CreateFromQuery, OrQueryIdRepl) {
BSONObj query = fromjson("{$or:[{_id:1}]}");
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{_id:1}"), doc().getObject());
}
TEST_F(CreateFromQuery, OrQueryNoExtractOps) {
BSONObj query = fromjson("{$or:[{a:1}, {b:2}]}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(BSONObj(), doc().getObject());
}
TEST_F(CreateFromQuery, OrQueryNoExtractIdRepl) {
BSONObj query = fromjson("{$or:[{_id:1}, {_id:2}]}");
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(BSONObj(), doc().getObject());
}
TEST_F(CreateFromQuery, AndQueryOp) {
BSONObj query = fromjson("{$and:[{'a.c':1},{'a.b':{$eq:2}}]}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{a:{c:1,b:2}}"), doc().getObject());
}
TEST_F(CreateFromQuery, AndQueryIdRepl) {
BSONObj query = fromjson("{$and:[{_id:1},{a:{$eq:2}}]}");
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{_id:1}"), doc().getObject());
}
TEST_F(CreateFromQuery, AllArrayOp) {
BSONObj query = fromjson("{a:{$all:[1]}}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{a:1}"), doc().getObject());
}
TEST_F(CreateFromQuery, AllArrayIdRepl) {
BSONObj query = fromjson("{_id:{$all:[1]}, b:2}");
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(fromjson("{_id:1}"), doc().getObject());
}
TEST_F(CreateFromQuery, ConflictFieldsFailOp) {
BSONObj query = fromjson("{a:1,'a.b':1}");
- ASSERT_NOT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_NOT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
}
TEST_F(CreateFromQuery, ConflictFieldsFailSameValueOp) {
BSONObj query = fromjson("{a:{b:1},'a.b':1}");
- ASSERT_NOT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_NOT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
}
TEST_F(CreateFromQuery, ConflictWithIdRepl) {
BSONObj query = fromjson("{_id:1,'_id.a':1}");
- ASSERT_NOT_OK(driverRepl().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_NOT_OK(driverRepl().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
}
TEST_F(CreateFromQuery, ConflictAndQueryOp) {
BSONObj query = fromjson("{$and:[{a:{b:1}},{'a.b':{$eq:1}}]}");
- ASSERT_NOT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_NOT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
}
TEST_F(CreateFromQuery, ConflictAllMultipleValsOp) {
BSONObj query = fromjson("{a:{$all:[1, 2]}}");
- ASSERT_NOT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_NOT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
}
TEST_F(CreateFromQuery, NoConflictOrQueryOp) {
BSONObj query = fromjson("{$or:[{a:{b:1}},{'a.b':{$eq:1}}]}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(BSONObj(), doc().getObject());
}
TEST_F(CreateFromQuery, ImmutableFieldsOp) {
BSONObj query = fromjson("{$or:[{a:{b:1}},{'a.b':{$eq:1}}]}");
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, NULL, doc()));
+ ASSERT_OK(driverOps().populateDocumentWithQueryFields(txn(), query, NULL, doc()));
assertSameFields(BSONObj(), doc().getObject());
}
@@ -358,7 +369,8 @@ TEST_F(CreateFromQuery, ShardKeyRepl) {
BSONObj query = fromjson("{a:{$eq:1}}, b:2}");
OwnedPointerVector<FieldRef> immutablePaths;
immutablePaths.push_back(new FieldRef("a"));
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, &immutablePaths.vector(), doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(
+ txn(), query, &immutablePaths.vector(), doc()));
assertSameFields(fromjson("{a:1}"), doc().getObject());
}
@@ -367,7 +379,8 @@ TEST_F(CreateFromQuery, NestedShardKeyRepl) {
OwnedPointerVector<FieldRef> immutablePaths;
immutablePaths.push_back(new FieldRef("a"));
immutablePaths.push_back(new FieldRef("b.c"));
- ASSERT_OK(driverRepl().populateDocumentWithQueryFields(query, &immutablePaths.vector(), doc()));
+ ASSERT_OK(driverRepl().populateDocumentWithQueryFields(
+ txn(), query, &immutablePaths.vector(), doc()));
assertSameFields(fromjson("{a:1,b:{c:2}}"), doc().getObject());
}
@@ -376,7 +389,8 @@ TEST_F(CreateFromQuery, NestedShardKeyOp) {
OwnedPointerVector<FieldRef> immutablePaths;
immutablePaths.push_back(new FieldRef("a"));
immutablePaths.push_back(new FieldRef("b.c"));
- ASSERT_OK(driverOps().populateDocumentWithQueryFields(query, &immutablePaths.vector(), doc()));
+ ASSERT_OK(
+ driverOps().populateDocumentWithQueryFields(txn(), query, &immutablePaths.vector(), doc()));
assertSameFields(fromjson("{a:1,b:{c:2},d:3}"), doc().getObject());
}
@@ -385,8 +399,8 @@ TEST_F(CreateFromQuery, NotFullShardKeyRepl) {
OwnedPointerVector<FieldRef> immutablePaths;
immutablePaths.push_back(new FieldRef("a"));
immutablePaths.push_back(new FieldRef("b"));
- ASSERT_NOT_OK(
- driverRepl().populateDocumentWithQueryFields(query, &immutablePaths.vector(), doc()));
+ ASSERT_NOT_OK(driverRepl().populateDocumentWithQueryFields(
+ txn(), query, &immutablePaths.vector(), doc()));
}
} // unnamed namespace
diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp
index 874c7f5f070..e254603af3b 100644
--- a/src/mongo/db/pipeline/pipeline_d.cpp
+++ b/src/mongo/db/pipeline/pipeline_d.cpp
@@ -209,7 +209,7 @@ StatusWith<std::unique_ptr<PlanExecutor>> attemptToGetExecutor(
const ExtensionsCallbackReal extensionsCallback(pExpCtx->opCtx, &pExpCtx->ns);
auto cq = CanonicalQuery::canonicalize(
- pExpCtx->ns, queryObj, sortObj, projectionObj, extensionsCallback);
+ txn, pExpCtx->ns, queryObj, sortObj, projectionObj, extensionsCallback);
if (!cq.isOK()) {
// Return an error instead of uasserting, since there are cases where the combination of
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index 80afbbf0893..1818879820e 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -44,6 +44,7 @@ env.Library(
env.Library(
target='query',
source=[
+ "collation/collator_factory_mock_decoration.cpp",
"explain.cpp",
"get_executor.cpp",
"find.cpp",
@@ -54,8 +55,6 @@ env.Library(
"stage_builder.cpp",
],
LIBDEPS=[
- "collation/collator_factory_interface",
- # TODO SERVER-22371: Replace collator_factory_mock with collator_factory_icu.
"collation/collator_factory_mock",
"internal_plans",
"query_common",
@@ -93,6 +92,7 @@ env.CppUnitTest(
],
LIBDEPS=[
"query",
+ "query_test_service_context",
"$BUILD_DIR/mongo/db/serveronly",
"$BUILD_DIR/mongo/dbtests/mocklib",
"$BUILD_DIR/mongo/util/ntservice_mock",
@@ -185,12 +185,24 @@ env.Library(
)
env.Library(
+ target="query_test_service_context",
+ source=[
+ "query_test_service_context.cpp",
+ ],
+ LIBDEPS=[
+ "collation/collator_factory_mock",
+ "$BUILD_DIR/mongo/db/service_context",
+ ],
+)
+
+env.Library(
target="query_planner_test_fixture",
source=[
"query_planner_test_fixture.cpp",
],
LIBDEPS=[
"query_planner_test_lib",
+ "query_test_service_context",
"$BUILD_DIR/mongo/unittest/unittest",
],
)
@@ -213,6 +225,7 @@ env.CppUnitTest(
LIBDEPS=[
"collation/collator_interface_mock",
"query_planner",
+ "query_test_service_context",
],
)
@@ -283,6 +296,7 @@ env.CppUnitTest(
],
LIBDEPS=[
"query_planner_test_fixture",
+ "query_test_service_context",
],
)
diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp
index 5cc41126c79..7fe801443f2 100644
--- a/src/mongo/db/query/canonical_query.cpp
+++ b/src/mongo/db/query/canonical_query.cpp
@@ -102,20 +102,25 @@ bool matchExpressionLessThan(const MatchExpression* lhs, const MatchExpression*
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
- NamespaceString nss, const BSONObj& query, const ExtensionsCallback& extensionsCallback) {
+ OperationContext* txn,
+ NamespaceString nss,
+ const BSONObj& query,
+ const ExtensionsCallback& extensionsCallback) {
const BSONObj emptyObj;
return CanonicalQuery::canonicalize(
- std::move(nss), query, emptyObj, emptyObj, 0, 0, extensionsCallback);
+ txn, std::move(nss), query, emptyObj, emptyObj, 0, 0, extensionsCallback);
}
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
bool explain,
const ExtensionsCallback& extensionsCallback) {
const BSONObj emptyObj;
- return CanonicalQuery::canonicalize(std::move(nss),
+ return CanonicalQuery::canonicalize(txn,
+ std::move(nss),
query,
emptyObj, // sort
emptyObj, // projection
@@ -131,6 +136,7 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
long long skip,
@@ -138,22 +144,24 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
const ExtensionsCallback& extensionsCallback) {
const BSONObj emptyObj;
return CanonicalQuery::canonicalize(
- std::move(nss), query, emptyObj, emptyObj, skip, limit, extensionsCallback);
+ txn, std::move(nss), query, emptyObj, emptyObj, skip, limit, extensionsCallback);
}
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
const BSONObj& sort,
const BSONObj& proj,
const ExtensionsCallback& extensionsCallback) {
return CanonicalQuery::canonicalize(
- std::move(nss), query, sort, proj, 0, 0, extensionsCallback);
+ txn, std::move(nss), query, sort, proj, 0, 0, extensionsCallback);
}
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
const BSONObj& sort,
@@ -163,11 +171,12 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
const ExtensionsCallback& extensionsCallback) {
const BSONObj emptyObj;
return CanonicalQuery::canonicalize(
- std::move(nss), query, sort, proj, skip, limit, emptyObj, extensionsCallback);
+ txn, std::move(nss), query, sort, proj, skip, limit, emptyObj, extensionsCallback);
}
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
const BSONObj& sort,
@@ -177,7 +186,8 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
const BSONObj& hint,
const ExtensionsCallback& extensionsCallback) {
const BSONObj emptyObj;
- return CanonicalQuery::canonicalize(std::move(nss),
+ return CanonicalQuery::canonicalize(txn,
+ std::move(nss),
query,
sort,
proj,
@@ -197,19 +207,19 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
- const QueryMessage& qm, const ExtensionsCallback& extensionsCallback) {
+ OperationContext* txn, const QueryMessage& qm, const ExtensionsCallback& extensionsCallback) {
// Make LiteParsedQuery.
auto lpqStatus = LiteParsedQuery::fromLegacyQueryMessage(qm);
if (!lpqStatus.isOK()) {
return lpqStatus.getStatus();
}
- return CanonicalQuery::canonicalize(lpqStatus.getValue().release(), extensionsCallback);
+ return CanonicalQuery::canonicalize(txn, lpqStatus.getValue().release(), extensionsCallback);
}
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
- LiteParsedQuery* lpq, const ExtensionsCallback& extensionsCallback) {
+ OperationContext* txn, LiteParsedQuery* lpq, const ExtensionsCallback& extensionsCallback) {
std::unique_ptr<LiteParsedQuery> autoLpq(lpq);
// Make MatchExpression.
@@ -234,6 +244,7 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
+ OperationContext* txn,
const CanonicalQuery& baseQuery,
MatchExpression* root,
const ExtensionsCallback& extensionsCallback) {
@@ -269,6 +280,7 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
// static
StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
const BSONObj& sort,
diff --git a/src/mongo/db/query/canonical_query.h b/src/mongo/db/query/canonical_query.h
index 65741b8f204..e6288ff9d1a 100644
--- a/src/mongo/db/query/canonical_query.h
+++ b/src/mongo/db/query/canonical_query.h
@@ -38,16 +38,23 @@
namespace mongo {
+class OperationContext;
+
class CanonicalQuery {
public:
/**
* If parsing succeeds, returns a std::unique_ptr<CanonicalQuery> representing the parsed
* query (which will never be NULL). If parsing fails, returns an error Status.
*
+ * 'txn' must point to a valid OperationContext, but 'txn' does not need to outlive the returned
+ * CanonicalQuery.
+ *
* Used for legacy find through the OP_QUERY message.
*/
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
- const QueryMessage& qm, const ExtensionsCallback& extensionsCallback);
+ OperationContext* txn,
+ const QueryMessage& qm,
+ const ExtensionsCallback& extensionsCallback);
/**
* Takes ownership of 'lpq'.
@@ -55,9 +62,13 @@ public:
* If parsing succeeds, returns a std::unique_ptr<CanonicalQuery> representing the parsed
* query (which will never be NULL). If parsing fails, returns an error Status.
*
+ * 'txn' must point to a valid OperationContext, but 'txn' does not need to outlive the returned
+ * CanonicalQuery.
+ *
* Used for finds using the find command path.
*/
- static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(LiteParsedQuery* lpq,
+ static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(OperationContext* txn,
+ LiteParsedQuery* lpq,
const ExtensionsCallback&);
/**
@@ -72,20 +83,26 @@ public:
* Does not take ownership of 'root'.
*/
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
+ OperationContext* txn,
const CanonicalQuery& baseQuery,
MatchExpression* root,
const ExtensionsCallback& extensionsCallback);
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
- NamespaceString nss, const BSONObj& query, const ExtensionsCallback& extensionsCallback);
+ OperationContext* txn,
+ NamespaceString nss,
+ const BSONObj& query,
+ const ExtensionsCallback& extensionsCallback);
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
bool explain,
const ExtensionsCallback& extensionsCallback);
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
long long skip,
@@ -93,6 +110,7 @@ public:
const ExtensionsCallback& extensionsCallback);
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
const BSONObj& sort,
@@ -100,6 +118,7 @@ public:
const ExtensionsCallback& extensionsCallback);
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
const BSONObj& sort,
@@ -109,6 +128,7 @@ public:
const ExtensionsCallback& extensionsCallback);
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
const BSONObj& sort,
@@ -119,6 +139,7 @@ public:
const ExtensionsCallback& extensionsCallback);
static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(
+ OperationContext* txn,
NamespaceString nss,
const BSONObj& query,
const BSONObj& sort,
diff --git a/src/mongo/db/query/canonical_query_test.cpp b/src/mongo/db/query/canonical_query_test.cpp
index 05c95409f7e..11fada4de05 100644
--- a/src/mongo/db/query/canonical_query_test.cpp
+++ b/src/mongo/db/query/canonical_query_test.cpp
@@ -35,6 +35,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
#include "mongo/db/query/index_tag.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -428,13 +429,16 @@ TEST(CanonicalQueryTest, IsValidTextAndSnapshot) {
}
TEST(CanonicalQueryTest, IsValidSortKeyMetaProjection) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
// Passing a sortKey meta-projection without a sort is an error.
{
const bool isExplain = false;
auto lpq = assertGet(LiteParsedQuery::makeFromFindCommand(
nss, fromjson("{find: 'testcoll', projection: {foo: {$meta: 'sortKey'}}}"), isExplain));
- auto cq =
- CanonicalQuery::canonicalize(lpq.release(), ExtensionsCallbackDisallowExtensions());
+ auto cq = CanonicalQuery::canonicalize(
+ txn.get(), lpq.release(), ExtensionsCallbackDisallowExtensions());
ASSERT_NOT_OK(cq.getStatus());
}
@@ -445,8 +449,8 @@ TEST(CanonicalQueryTest, IsValidSortKeyMetaProjection) {
nss,
fromjson("{find: 'testcoll', projection: {foo: {$meta: 'sortKey'}}, sort: {bar: 1}}"),
isExplain));
- auto cq =
- CanonicalQuery::canonicalize(lpq.release(), ExtensionsCallbackDisallowExtensions());
+ auto cq = CanonicalQuery::canonicalize(
+ txn.get(), lpq.release(), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(cq.getStatus());
}
}
@@ -538,9 +542,12 @@ TEST(CanonicalQueryTest, SortTreeNumChildrenComparison) {
* Utility function to create a CanonicalQuery
*/
unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
BSONObj queryObj = fromjson(queryStr);
- auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, queryObj, ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ txn.get(), nss, queryObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
@@ -548,11 +555,14 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) {
std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
const char* sortStr,
const char* projStr) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
BSONObj queryObj = fromjson(queryStr);
BSONObj sortObj = fromjson(sortStr);
BSONObj projObj = fromjson(projStr);
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, queryObj, sortObj, projObj, ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, queryObj, sortObj, projObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
@@ -653,16 +663,19 @@ TEST(CanonicalQueryTest, NormalizeWithInPreservesCollator) {
}
TEST(CanonicalQueryTest, CanonicalizeFromBaseQuery) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
const bool isExplain = true;
const std::string cmdStr =
"{find:'bogusns', filter:{$or:[{a:1,b:1},{a:1,c:1}]}, projection:{a:1}, sort:{b:1}}";
auto lpq = assertGet(LiteParsedQuery::makeFromFindCommand(nss, fromjson(cmdStr), isExplain));
- auto baseCq = assertGet(
- CanonicalQuery::canonicalize(lpq.release(), ExtensionsCallbackDisallowExtensions()));
+ auto baseCq = assertGet(CanonicalQuery::canonicalize(
+ txn.get(), lpq.release(), ExtensionsCallbackDisallowExtensions()));
MatchExpression* firstClauseExpr = baseCq->root()->getChild(0);
auto childCq = assertGet(CanonicalQuery::canonicalize(
- *baseCq, firstClauseExpr, ExtensionsCallbackDisallowExtensions()));
+ txn.get(), *baseCq, firstClauseExpr, ExtensionsCallbackDisallowExtensions()));
// Descriptive test. The childCq's filter should be the relevant $or clause, rather than the
// entire query predicate.
diff --git a/src/mongo/db/query/collation/collator_factory_mock.cpp b/src/mongo/db/query/collation/collator_factory_mock.cpp
index 0233cbcf262..e1d1f8f7d2d 100644
--- a/src/mongo/db/query/collation/collator_factory_mock.cpp
+++ b/src/mongo/db/query/collation/collator_factory_mock.cpp
@@ -31,24 +31,12 @@
#include "mongo/db/query/collation/collator_factory_mock.h"
#include "mongo/base/init.h"
+#include "mongo/bson/bsonobj.h"
#include "mongo/db/query/collation/collator_interface_mock.h"
-#include "mongo/db/service_context.h"
#include "mongo/stdx/memory.h"
namespace mongo {
-namespace {
-
-// TODO SERVER-22371: We should decorate with a CollatorFactoryICU instead.
-MONGO_INITIALIZER_WITH_PREREQUISITES(CreateCollatorFactory,
- ("SetGlobalEnvironment"))(InitializerContext* context) {
- CollatorFactoryInterface::set(getGlobalServiceContext(),
- stdx::make_unique<CollatorFactoryMock>());
- return Status::OK();
-}
-
-} // namespace
-
StatusWith<std::unique_ptr<CollatorInterface>> CollatorFactoryMock::makeFromBSON(
const BSONObj& spec) {
auto collator =
diff --git a/src/mongo/db/query/collation/collator_factory_mock_decoration.cpp b/src/mongo/db/query/collation/collator_factory_mock_decoration.cpp
new file mode 100644
index 00000000000..3c8ef8d7cba
--- /dev/null
+++ b/src/mongo/db/query/collation/collator_factory_mock_decoration.cpp
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2016 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/base/init.h"
+#include "mongo/db/query/collation/collator_factory_mock.h"
+#include "mongo/db/service_context.h"
+#include "mongo/stdx/memory.h"
+
+namespace mongo {
+
+namespace {
+
+// TODO SERVER-22371: We should decorate with a CollatorFactoryICU instead.
+MONGO_INITIALIZER_WITH_PREREQUISITES(CreateCollatorFactory,
+ ("SetGlobalEnvironment"))(InitializerContext* context) {
+ CollatorFactoryInterface::set(getGlobalServiceContext(),
+ stdx::make_unique<CollatorFactoryMock>());
+ return Status::OK();
+}
+
+} // namespace
+
+} // namespace mongo
diff --git a/src/mongo/db/query/collation/collator_factory_mock_test.cpp b/src/mongo/db/query/collation/collator_factory_mock_test.cpp
index f97a6360185..461909bda15 100644
--- a/src/mongo/db/query/collation/collator_factory_mock_test.cpp
+++ b/src/mongo/db/query/collation/collator_factory_mock_test.cpp
@@ -28,23 +28,14 @@
#include "mongo/platform/basic.h"
-#include "mongo/base/init.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/db/query/collation/collator_factory_mock.h"
-#include "mongo/db/service_context_noop.h"
-#include "mongo/stdx/memory.h"
#include "mongo/unittest/unittest.h"
namespace {
using namespace mongo;
-// Stub to avoid including the server environment library.
-MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) {
- setGlobalServiceContext(stdx::make_unique<ServiceContextNoop>());
- return Status::OK();
-}
-
TEST(CollatorFactoryMockTest, CollatorFactoryMockConstructsReverseStringCollator) {
CollatorFactoryMock factory;
auto collator = factory.makeFromBSON(BSONObj());
@@ -52,12 +43,4 @@ TEST(CollatorFactoryMockTest, CollatorFactoryMockConstructsReverseStringCollator
ASSERT_GT(collator.getValue()->compare("abc", "cba"), 0);
}
-// TODO SERVER-22371: Remove this test. We will decorate with a CollatorFactoryICU instead.
-TEST(CollatorFactoryMockTest, ServiceContextDecoratedWithCollatorFactoryMock) {
- auto factory = CollatorFactoryInterface::get(getGlobalServiceContext());
- auto collator = factory->makeFromBSON(BSONObj());
- ASSERT_OK(collator.getStatus());
- ASSERT_GT(collator.getValue()->compare("abc", "cba"), 0);
-}
-
} // namespace
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp
index ca5ec06a5b6..bd58ccf4a2d 100644
--- a/src/mongo/db/query/find.cpp
+++ b/src/mongo/db/query/find.cpp
@@ -499,7 +499,7 @@ std::string runQuery(OperationContext* txn,
// Parse the qm into a CanonicalQuery.
- auto statusWithCQ = CanonicalQuery::canonicalize(q, ExtensionsCallbackReal(txn, &nss));
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn, q, ExtensionsCallbackReal(txn, &nss));
if (!statusWithCQ.isOK()) {
uasserted(
17287,
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index cf5fa10d047..33e6f533fb3 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -937,7 +937,7 @@ StatusWith<unique_ptr<PlanExecutor>> getExecutorGroup(OperationContext* txn,
const ExtensionsCallbackReal extensionsCallback(txn, &nss);
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, request.query, request.explain, extensionsCallback);
+ CanonicalQuery::canonicalize(txn, nss, request.query, request.explain, extensionsCallback);
if (!statusWithCQ.isOK()) {
return statusWithCQ.getStatus();
}
@@ -1155,6 +1155,7 @@ StatusWith<unique_ptr<PlanExecutor>> getExecutorCount(OperationContext* txn,
unique_ptr<WorkingSet> ws = make_unique<WorkingSet>();
auto cq = CanonicalQuery::canonicalize(
+ txn,
request.getNs(),
request.getQuery(),
BSONObj(), // sort
@@ -1330,8 +1331,8 @@ StatusWith<unique_ptr<PlanExecutor>> getExecutorDistinct(OperationContext* txn,
// If there are no suitable indices for the distinct hack bail out now into regular planning
// with no projection.
if (plannerParams.indices.empty()) {
- auto statusWithCQ =
- CanonicalQuery::canonicalize(collection->ns(), query, isExplain, extensionsCallback);
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ txn, collection->ns(), query, isExplain, extensionsCallback);
if (!statusWithCQ.isOK()) {
return statusWithCQ.getStatus();
}
@@ -1349,7 +1350,8 @@ StatusWith<unique_ptr<PlanExecutor>> getExecutorDistinct(OperationContext* txn,
BSONObj projection = getDistinctProjection(field);
// Apply a projection of the key. Empty BSONObj() is for the sort.
- auto statusWithCQ = CanonicalQuery::canonicalize(collection->ns(),
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn,
+ collection->ns(),
query,
BSONObj(), // sort
projection,
@@ -1447,7 +1449,7 @@ StatusWith<unique_ptr<PlanExecutor>> getExecutorDistinct(OperationContext* txn,
// We drop the projection from the 'cq'. Unfortunately this is not trivial.
statusWithCQ =
- CanonicalQuery::canonicalize(collection->ns(), query, isExplain, extensionsCallback);
+ CanonicalQuery::canonicalize(txn, collection->ns(), query, isExplain, extensionsCallback);
if (!statusWithCQ.isOK()) {
return statusWithCQ.getStatus();
}
diff --git a/src/mongo/db/query/get_executor_test.cpp b/src/mongo/db/query/get_executor_test.cpp
index 29c73f6c8b2..630eb00ca40 100644
--- a/src/mongo/db/query/get_executor_test.cpp
+++ b/src/mongo/db/query/get_executor_test.cpp
@@ -35,6 +35,7 @@
#include "mongo/db/json.h"
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
#include "mongo/db/query/query_settings.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/mongoutils/str.h"
@@ -52,11 +53,14 @@ static const NamespaceString nss("test.collection");
unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
const char* sortStr,
const char* projStr) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
BSONObj queryObj = fromjson(queryStr);
BSONObj sortObj = fromjson(sortStr);
BSONObj projObj = fromjson(projStr);
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, queryObj, sortObj, projObj, ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, queryObj, sortObj, projObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp
index 61e803af8af..2b146d9c83a 100644
--- a/src/mongo/db/query/plan_cache_test.cpp
+++ b/src/mongo/db/query/plan_cache_test.cpp
@@ -44,6 +44,7 @@
#include "mongo/db/query/query_planner.h"
#include "mongo/db/query/query_planner_test_lib.h"
#include "mongo/db/query/query_solution.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/scopeguard.h"
@@ -62,8 +63,11 @@ static const NamespaceString nss("test.collection");
* Utility functions to create a CanonicalQuery
*/
unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj) {
- auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, queryObj, ExtensionsCallbackDisallowExtensions());
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ txn.get(), nss, queryObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
@@ -76,11 +80,14 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) {
unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
const char* sortStr,
const char* projStr) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
BSONObj queryObj = fromjson(queryStr);
BSONObj sortObj = fromjson(sortStr);
BSONObj projObj = fromjson(projStr);
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, queryObj, sortObj, projObj, ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, queryObj, sortObj, projObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
@@ -93,13 +100,17 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
const char* hintStr,
const char* minStr,
const char* maxStr) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
BSONObj queryObj = fromjson(queryStr);
BSONObj sortObj = fromjson(sortStr);
BSONObj projObj = fromjson(projStr);
BSONObj hintObj = fromjson(hintStr);
BSONObj minObj = fromjson(minStr);
BSONObj maxObj = fromjson(maxStr);
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn.get(),
+ nss,
queryObj,
sortObj,
projObj,
@@ -125,13 +136,17 @@ unique_ptr<CanonicalQuery> canonicalize(const char* queryStr,
const char* maxStr,
bool snapshot,
bool explain) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
BSONObj queryObj = fromjson(queryStr);
BSONObj sortObj = fromjson(sortStr);
BSONObj projObj = fromjson(projStr);
BSONObj hintObj = fromjson(hintStr);
BSONObj minObj = fromjson(minStr);
BSONObj maxObj = fromjson(maxStr);
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn.get(),
+ nss,
queryObj,
sortObj,
projObj,
@@ -516,6 +531,9 @@ protected:
const BSONObj& minObj,
const BSONObj& maxObj,
bool snapshot) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
// Clean up any previous state from a call to runQueryFull
for (vector<QuerySolution*>::iterator it = solns.begin(); it != solns.end(); ++it) {
delete *it;
@@ -523,7 +541,8 @@ protected:
solns.clear();
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn.get(),
+ nss,
query,
sort,
proj,
@@ -605,8 +624,11 @@ protected:
const BSONObj& sort,
const BSONObj& proj,
const QuerySolution& soln) const {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, query, sort, proj, ExtensionsCallbackDisallowExtensions());
+ txn.get(), nss, query, sort, proj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/db/query/query_planner_test.cpp b/src/mongo/db/query/query_planner_test.cpp
index ea5dcf3f4b1..77898adad35 100644
--- a/src/mongo/db/query/query_planner_test.cpp
+++ b/src/mongo/db/query/query_planner_test.cpp
@@ -4138,7 +4138,7 @@ TEST_F(QueryPlannerTest, KeyPatternOverflowsInt) {
// Test bad input to query planner helpers.
//
-TEST(BadInputTest, CacheDataFromTaggedTree) {
+TEST_F(QueryPlannerTest, CacheDataFromTaggedTreeFailsOnBadInput) {
PlanCacheIndexTree* indexTree;
// Null match expression.
@@ -4150,8 +4150,10 @@ TEST(BadInputTest, CacheDataFromTaggedTree) {
// No relevant index matching the index tag.
relevantIndices.push_back(IndexEntry(BSON("a" << 1)));
- auto statusWithCQ = CanonicalQuery::canonicalize(
- NamespaceString("test.collection"), BSON("a" << 3), ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ NamespaceString("test.collection"),
+ BSON("a" << 3),
+ ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue());
scopedCq->root()->setTag(new IndexTag(1));
@@ -4161,11 +4163,11 @@ TEST(BadInputTest, CacheDataFromTaggedTree) {
ASSERT(NULL == indexTree);
}
-TEST(BadInputTest, TagAccordingToCache) {
+TEST_F(QueryPlannerTest, TagAccordingToCacheFailsOnBadInput) {
const NamespaceString nss("test.collection");
- auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, BSON("a" << 3), ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ txn(), nss, BSON("a" << 3), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue());
@@ -4192,8 +4194,8 @@ TEST(BadInputTest, TagAccordingToCache) {
ASSERT_OK(s);
// Regenerate canonical query in order to clear tags.
- statusWithCQ =
- CanonicalQuery::canonicalize(nss, BSON("a" << 3), ExtensionsCallbackDisallowExtensions());
+ statusWithCQ = CanonicalQuery::canonicalize(
+ txn(), nss, BSON("a" << 3), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
scopedCq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp
index 0e336528b45..5f89d1ee35c 100644
--- a/src/mongo/db/query/query_planner_test_fixture.cpp
+++ b/src/mongo/db/query/query_planner_test_fixture.cpp
@@ -50,11 +50,16 @@ using unittest::assertGet;
const NamespaceString QueryPlannerTest::nss("test.collection");
void QueryPlannerTest::setUp() {
+ opCtx = serviceContext.makeOperationContext();
internalQueryPlannerEnableHashIntersection = true;
params.options = QueryPlannerParams::INCLUDE_COLLSCAN;
addIndex(BSON("_id" << 1));
}
+OperationContext* QueryPlannerTest::txn() {
+ return opCtx.get();
+}
+
void QueryPlannerTest::addIndex(BSONObj keyPattern, bool multikey) {
params.indices.push_back(IndexEntry(keyPattern,
multikey,
@@ -199,7 +204,8 @@ void QueryPlannerTest::runQueryFull(const BSONObj& query,
solns.clear();
cq.reset();
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
query,
sort,
proj,
@@ -267,7 +273,8 @@ void QueryPlannerTest::runInvalidQueryFull(const BSONObj& query,
solns.clear();
cq.reset();
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
query,
sort,
proj,
@@ -296,7 +303,8 @@ void QueryPlannerTest::runQueryAsCommand(const BSONObj& cmdObj) {
std::unique_ptr<LiteParsedQuery> lpq(
assertGet(LiteParsedQuery::makeFromFindCommand(nss, cmdObj, isExplain)));
- auto statusWithCQ = CanonicalQuery::canonicalize(lpq.release(), ExtensionsCallbackNoop());
+ auto statusWithCQ =
+ CanonicalQuery::canonicalize(txn(), lpq.release(), ExtensionsCallbackNoop());
ASSERT_OK(statusWithCQ.getStatus());
cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/db/query/query_planner_test_fixture.h b/src/mongo/db/query/query_planner_test_fixture.h
index 0a2bfcc8b1a..98f4916ff6f 100644
--- a/src/mongo/db/query/query_planner_test_fixture.h
+++ b/src/mongo/db/query/query_planner_test_fixture.h
@@ -39,6 +39,7 @@
#include "mongo/db/json.h"
#include "mongo/db/query/collation/collator_interface.h"
#include "mongo/db/query/query_solution.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -47,6 +48,8 @@ class QueryPlannerTest : public mongo::unittest::Test {
protected:
void setUp();
+ OperationContext* txn();
+
//
// Build up test.
//
@@ -197,6 +200,8 @@ protected:
static const NamespaceString nss;
+ QueryTestServiceContext serviceContext;
+ ServiceContext::UniqueOperationContext opCtx;
BSONObj queryObj;
std::unique_ptr<CanonicalQuery> cq;
QueryPlannerParams params;
diff --git a/src/mongo/db/query/query_test_service_context.cpp b/src/mongo/db/query/query_test_service_context.cpp
new file mode 100644
index 00000000000..e2682fe44d4
--- /dev/null
+++ b/src/mongo/db/query/query_test_service_context.cpp
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) 2016 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/query_test_service_context.h"
+
+#include "mongo/db/query/collation/collator_factory_mock.h"
+#include "mongo/stdx/memory.h"
+
+namespace mongo {
+
+QueryTestServiceContext::QueryTestServiceContext() {
+ CollatorFactoryInterface::set(&_serviceContext, stdx::make_unique<CollatorFactoryMock>());
+ _uniqueClient = _serviceContext.makeClient("QueryTest");
+}
+
+ServiceContext::UniqueOperationContext QueryTestServiceContext::makeOperationContext() {
+ return _uniqueClient->makeOperationContext();
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/query/query_test_service_context.h b/src/mongo/db/query/query_test_service_context.h
new file mode 100644
index 00000000000..7466116d354
--- /dev/null
+++ b/src/mongo/db/query/query_test_service_context.h
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2016 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 "mongo/db/client.h"
+#include "mongo/db/service_context_noop.h"
+
+namespace mongo {
+
+/**
+ * QueryTestServiceContext is a helper class for tests that require only a single Client under a
+ * single ServiceContext for their execution context. The owned ServiceContext is decorated with a
+ * CollatorFactoryMock.
+ */
+class QueryTestServiceContext {
+public:
+ QueryTestServiceContext();
+
+ ServiceContext::UniqueOperationContext makeOperationContext();
+
+private:
+ ServiceContextNoop _serviceContext;
+ ServiceContext::UniqueClient _uniqueClient;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp
index 108c86d4e0f..35020609c56 100644
--- a/src/mongo/db/ttl.cpp
+++ b/src/mongo/db/ttl.cpp
@@ -289,7 +289,7 @@ private:
BSONObj query =
BSON(keyFieldName << BSON("$gte" << kDawnOfTime << "$lte" << expirationTime));
auto canonicalQuery =
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions());
+ CanonicalQuery::canonicalize(txn, nss, query, ExtensionsCallbackDisallowExtensions());
invariantOK(canonicalQuery.getStatus());
DeleteStageParams params;
diff --git a/src/mongo/dbtests/SConscript b/src/mongo/dbtests/SConscript
index 7f5a55f45ed..9bc684be8b6 100644
--- a/src/mongo/dbtests/SConscript
+++ b/src/mongo/dbtests/SConscript
@@ -111,6 +111,7 @@ dbtest = env.Program(
"$BUILD_DIR/mongo/db/auth/authmocks",
"$BUILD_DIR/mongo/db/query/collation/collator_interface_mock",
"$BUILD_DIR/mongo/db/query/query",
+ "$BUILD_DIR/mongo/db/query/query_test_service_context",
"$BUILD_DIR/mongo/db/storage/paths",
"$BUILD_DIR/mongo/db/repl/repl_coordinator_global",
"$BUILD_DIR/mongo/db/repl/replmocks",
diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp
index d391b31a20e..3c87cce2aea 100644
--- a/src/mongo/dbtests/documentsourcetests.cpp
+++ b/src/mongo/dbtests/documentsourcetests.cpp
@@ -97,7 +97,8 @@ protected:
OldClientWriteContext ctx(&_opCtx, nss.ns());
auto cq =
- uassertStatusOK(CanonicalQuery::canonicalize(nss,
+ uassertStatusOK(CanonicalQuery::canonicalize(&_opCtx,
+ nss,
/*query=*/BSONObj(),
/*sort=*/BSONObj(),
/*proj=*/BSONObj(),
diff --git a/src/mongo/dbtests/executor_registry.cpp b/src/mongo/dbtests/executor_registry.cpp
index 564ddcc7da6..e3719dff6bf 100644
--- a/src/mongo/dbtests/executor_registry.cpp
+++ b/src/mongo/dbtests/executor_registry.cpp
@@ -77,8 +77,8 @@ public:
unique_ptr<CollectionScan> scan(new CollectionScan(&_opCtx, params, ws.get(), NULL));
// Create a plan executor to hold it
- auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, BSONObj(), ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ &_opCtx, nss, BSONObj(), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/dbtests/oplogstarttests.cpp b/src/mongo/dbtests/oplogstarttests.cpp
index b1bfad6b010..72496dcdc46 100644
--- a/src/mongo/dbtests/oplogstarttests.cpp
+++ b/src/mongo/dbtests/oplogstarttests.cpp
@@ -76,7 +76,7 @@ protected:
void setupFromQuery(const BSONObj& query) {
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions());
+ CanonicalQuery::canonicalize(&_txn, nss, query, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
_cq = std::move(statusWithCQ.getValue());
_oplogws.reset(new WorkingSet());
diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp
index a9dc89e1144..c3c506bfd2e 100644
--- a/src/mongo/dbtests/plan_ranking.cpp
+++ b/src/mongo/dbtests/plan_ranking.cpp
@@ -151,6 +151,10 @@ public:
return _mps->hasBackupPlan();
}
+ OperationContext* txn() {
+ return &_txn;
+ }
+
protected:
// A large number, which must be larger than the number of times
// candidate plans are worked by the multi plan runner. Used for
@@ -197,7 +201,7 @@ public:
// Run the query {a:4, b:1}.
{
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, BSON("a" << 100 << "b" << 1), ExtensionsCallbackDisallowExtensions());
+ txn(), nss, BSON("a" << 100 << "b" << 1), ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
cq = std::move(statusWithCQ.getValue());
ASSERT(cq.get());
@@ -215,7 +219,7 @@ public:
// And run the same query again.
{
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, BSON("a" << 100 << "b" << 1), ExtensionsCallbackDisallowExtensions());
+ txn(), nss, BSON("a" << 100 << "b" << 1), ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
cq = std::move(statusWithCQ.getValue());
}
@@ -248,8 +252,10 @@ public:
addIndex(BSON("b" << 1));
// Run the query {a:1, b:{$gt:1}.
- auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, BSON("a" << 1 << "b" << BSON("$gt" << 1)), ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
+ BSON("a" << 1 << "b" << BSON("$gt" << 1)),
+ ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(NULL != cq.get());
@@ -287,7 +293,8 @@ public:
addIndex(BSON("a" << 1 << "b" << 1));
// Query for a==27 with projection that wants 'a' and 'b'. BSONObj() is for sort.
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
BSON("a" << 27),
BSONObj(),
BSON("_id" << 0 << "a" << 1 << "b" << 1),
@@ -324,8 +331,8 @@ public:
// There is no data that matches this query but we don't know that until EOF.
BSONObj queryObj = BSON("a" << 1 << "b" << 1 << "c" << 99);
- auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, queryObj, ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ txn(), nss, queryObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(NULL != cq.get());
@@ -361,7 +368,8 @@ public:
// There is no data that matches this query ({a:2}). Both scans will hit EOF before
// returning any data.
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
BSON("a" << 2),
BSONObj(),
BSON("_id" << 0 << "a" << 1 << "b" << 1),
@@ -397,7 +405,7 @@ public:
// Run the query {a:N+1, b:1}. (No such document.)
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, BSON("a" << N + 1 << "b" << 1), ExtensionsCallbackDisallowExtensions());
+ txn(), nss, BSON("a" << N + 1 << "b" << 1), ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(NULL != cq.get());
@@ -432,7 +440,8 @@ public:
// Run the query {a:N+1, b:1}. (No such document.)
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss,
+ CanonicalQuery::canonicalize(txn(),
+ nss,
BSON("a" << BSON("$gte" << N + 1) << "b" << 1),
ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
@@ -465,7 +474,7 @@ public:
BSONObj sortObj = BSON("c" << 1);
BSONObj projObj = BSONObj();
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, queryObj, sortObj, projObj, ExtensionsCallbackDisallowExtensions());
+ txn(), nss, queryObj, sortObj, projObj, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -493,7 +502,7 @@ public:
// Look for A Space Odyssey.
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, BSON("foo" << 2001), ExtensionsCallbackDisallowExtensions());
+ txn(), nss, BSON("foo" << 2001), ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(NULL != cq.get());
@@ -524,7 +533,8 @@ public:
addIndex(BSON("d" << 1 << "e" << 1));
// Query: find({a: 1}).sort({d: 1})
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
BSON("a" << 1),
BSON("d" << 1), // sort
BSONObj(), // projection
@@ -563,8 +573,10 @@ public:
// Solutions using either 'a' or 'b' will take a long time to start producing
// results. However, an index scan on 'b' will start producing results sooner
// than an index scan on 'a'.
- auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, fromjson("{a: 1, b: 1, c: {$gte: 5000}}"), ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
+ fromjson("{a: 1, b: 1, c: {$gte: 5000}}"),
+ ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(NULL != cq.get());
@@ -594,8 +606,10 @@ public:
addIndex(BSON("b" << 1 << "c" << 1));
addIndex(BSON("a" << 1));
- auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, fromjson("{a: 9, b: {$ne: 10}, c: 9}"), ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
+ fromjson("{a: 9, b: {$ne: 10}, c: 9}"),
+ ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
ASSERT(NULL != cq.get());
diff --git a/src/mongo/dbtests/query_plan_executor.cpp b/src/mongo/dbtests/query_plan_executor.cpp
index ffc2557cda4..714d57a4ea6 100644
--- a/src/mongo/dbtests/query_plan_executor.cpp
+++ b/src/mongo/dbtests/query_plan_executor.cpp
@@ -102,8 +102,8 @@ public:
unique_ptr<WorkingSet> ws(new WorkingSet());
// Canonicalize the query.
- auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, filterObj, ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ &_txn, nss, filterObj, ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
verify(NULL != cq.get());
@@ -147,8 +147,8 @@ public:
IndexScan* ix = new IndexScan(&_txn, ixparams, ws.get(), NULL);
unique_ptr<PlanStage> root(new FetchStage(&_txn, ws.get(), ix, NULL, coll));
- auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, BSONObj(), ExtensionsCallbackDisallowExtensions());
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ &_txn, nss, BSONObj(), ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
verify(NULL != cq.get());
diff --git a/src/mongo/dbtests/query_stage_cached_plan.cpp b/src/mongo/dbtests/query_stage_cached_plan.cpp
index 32550bc2172..5b61c8fa181 100644
--- a/src/mongo/dbtests/query_stage_cached_plan.cpp
+++ b/src/mongo/dbtests/query_stage_cached_plan.cpp
@@ -100,6 +100,10 @@ public:
wuow.commit();
}
+ OperationContext* txn() {
+ return &_txn;
+ }
+
protected:
const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext();
OperationContext& _txn = *_txnPtr;
@@ -119,7 +123,7 @@ public:
// Query can be answered by either index on "a" or index on "b".
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, fromjson("{a: {$gte: 8}, b: 1}"), ExtensionsCallbackDisallowExtensions());
+ txn(), nss, fromjson("{a: {$gte: 8}, b: 1}"), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
const std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -184,7 +188,7 @@ public:
// Query can be answered by either index on "a" or index on "b".
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, fromjson("{a: {$gte: 8}, b: 1}"), ExtensionsCallbackDisallowExtensions());
+ txn(), nss, fromjson("{a: {$gte: 8}, b: 1}"), ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
const std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/dbtests/query_stage_delete.cpp b/src/mongo/dbtests/query_stage_delete.cpp
index 4c3e2b873aa..73b39d0b273 100644
--- a/src/mongo/dbtests/query_stage_delete.cpp
+++ b/src/mongo/dbtests/query_stage_delete.cpp
@@ -105,7 +105,7 @@ public:
unique_ptr<CanonicalQuery> canonicalize(const BSONObj& query) {
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions());
+ CanonicalQuery::canonicalize(&_txn, nss, query, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
diff --git a/src/mongo/dbtests/query_stage_multiplan.cpp b/src/mongo/dbtests/query_stage_multiplan.cpp
index 8d16a859578..03e36ee41cf 100644
--- a/src/mongo/dbtests/query_stage_multiplan.cpp
+++ b/src/mongo/dbtests/query_stage_multiplan.cpp
@@ -107,6 +107,10 @@ public:
_client.remove(nss.ns(), obj);
}
+ OperationContext* txn() {
+ return &_txn;
+ }
+
protected:
const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext();
OperationContext& _txn = *_txnPtr;
@@ -163,7 +167,7 @@ public:
// Hand the plans off to the MPS.
auto statusWithCQ = CanonicalQuery::canonicalize(
- nss, BSON("foo" << 7), ExtensionsCallbackDisallowExtensions());
+ txn(), nss, BSON("foo" << 7), ExtensionsCallbackDisallowExtensions());
verify(statusWithCQ.isOK());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
verify(NULL != cq.get());
@@ -218,7 +222,8 @@ public:
Collection* collection = ctx.getCollection();
// Query for both 'a' and 'b' and sort on 'b'.
- auto statusWithCQ = CanonicalQuery::canonicalize(nss,
+ auto statusWithCQ = CanonicalQuery::canonicalize(txn(),
+ nss,
BSON("a" << 1 << "b" << 1), // query
BSON("b" << 1), // sort
BSONObj(), // proj
@@ -325,7 +330,7 @@ public:
AutoGetCollectionForRead ctx(&_txn, nss.ns());
auto cq = uassertStatusOK(CanonicalQuery::canonicalize(
- nss, BSON("x" << 1), ExtensionsCallbackDisallowExtensions()));
+ txn(), nss, BSON("x" << 1), ExtensionsCallbackDisallowExtensions()));
unique_ptr<MultiPlanStage> mps =
make_unique<MultiPlanStage>(&_txn, ctx.getCollection(), cq.get());
@@ -399,8 +404,8 @@ public:
// Create the executor (Matching all documents).
auto queryObj = BSON("foo" << BSON("$gte" << 0));
- auto cq = uassertStatusOK(
- CanonicalQuery::canonicalize(nss, queryObj, ExtensionsCallbackDisallowExtensions()));
+ auto cq = uassertStatusOK(CanonicalQuery::canonicalize(
+ txn(), nss, queryObj, ExtensionsCallbackDisallowExtensions()));
auto exec =
uassertStatusOK(getExecutor(&_txn, coll, std::move(cq), PlanExecutor::YIELD_MANUAL));
diff --git a/src/mongo/dbtests/query_stage_subplan.cpp b/src/mongo/dbtests/query_stage_subplan.cpp
index 490069c7cae..0a5a0b1a01d 100644
--- a/src/mongo/dbtests/query_stage_subplan.cpp
+++ b/src/mongo/dbtests/query_stage_subplan.cpp
@@ -67,6 +67,10 @@ public:
_client.insert(nss.ns(), doc);
}
+ OperationContext* txn() {
+ return &_txn;
+ }
+
protected:
/**
* Parses the json string 'findCmd', specifying a find command, to a CanonicalQuery.
@@ -79,7 +83,7 @@ protected:
unittest::assertGet(LiteParsedQuery::makeFromFindCommand(nss, cmdObj, isExplain));
auto cq = unittest::assertGet(
- CanonicalQuery::canonicalize(lpq.release(), ExtensionsCallbackNoop()));
+ CanonicalQuery::canonicalize(txn(), lpq.release(), ExtensionsCallbackNoop()));
return cq;
}
@@ -111,7 +115,7 @@ public:
"{a: {$geoWithin: {$centerSphere: [[1,1],10]}}}]}");
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions());
+ CanonicalQuery::canonicalize(txn(), nss, query, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -155,7 +159,7 @@ public:
Collection* collection = ctx.getCollection();
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions());
+ CanonicalQuery::canonicalize(txn(), nss, query, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -211,7 +215,7 @@ public:
Collection* collection = ctx.getCollection();
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions());
+ CanonicalQuery::canonicalize(txn(), nss, query, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -268,7 +272,7 @@ public:
Collection* collection = ctx.getCollection();
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions());
+ CanonicalQuery::canonicalize(txn(), nss, query, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
@@ -521,8 +525,8 @@ public:
insert(BSON("_id" << 3 << "a" << 1 << "c" << 3));
insert(BSON("_id" << 4 << "a" << 1 << "c" << 4));
- auto cq = unittest::assertGet(
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions()));
+ auto cq = unittest::assertGet(CanonicalQuery::canonicalize(
+ txn(), nss, query, ExtensionsCallbackDisallowExtensions()));
Collection* collection = ctx.getCollection();
@@ -582,7 +586,7 @@ public:
BSONObj sort = BSON("d" << 1);
BSONObj projection;
auto cq = unittest::assertGet(CanonicalQuery::canonicalize(
- nss, query, sort, projection, ExtensionsCallbackDisallowExtensions()));
+ txn(), nss, query, sort, projection, ExtensionsCallbackDisallowExtensions()));
Collection* collection = ctx.getCollection();
diff --git a/src/mongo/dbtests/query_stage_update.cpp b/src/mongo/dbtests/query_stage_update.cpp
index a81e6f78e92..b05d88fa996 100644
--- a/src/mongo/dbtests/query_stage_update.cpp
+++ b/src/mongo/dbtests/query_stage_update.cpp
@@ -89,7 +89,7 @@ public:
unique_ptr<CanonicalQuery> canonicalize(const BSONObj& query) {
auto statusWithCQ =
- CanonicalQuery::canonicalize(nss, query, ExtensionsCallbackDisallowExtensions());
+ CanonicalQuery::canonicalize(&_txn, nss, query, ExtensionsCallbackDisallowExtensions());
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
diff --git a/src/mongo/dbtests/sort_key_generator_test.cpp b/src/mongo/dbtests/sort_key_generator_test.cpp
index 5d6622f0f2b..5a8faa6d2b2 100644
--- a/src/mongo/dbtests/sort_key_generator_test.cpp
+++ b/src/mongo/dbtests/sort_key_generator_test.cpp
@@ -31,6 +31,7 @@
#include "mongo/db/exec/sort_key_generator.h"
#include "mongo/db/json.h"
#include "mongo/stdx/memory.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -46,12 +47,15 @@ namespace {
* Returns the BSON representation of the sort key, to be checked against the expected sort key.
*/
BSONObj extractSortKey(const char* sortSpec, const char* doc) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
WorkingSetMember wsm;
wsm.obj = Snapshotted<BSONObj>(SnapshotId(), fromjson(doc));
wsm.transitionToOwnedObj();
BSONObj sortKey;
- auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(fromjson(sortSpec), BSONObj());
+ auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(txn.get(), fromjson(sortSpec), BSONObj());
ASSERT_OK(sortKeyGen->getSortKey(wsm, &sortKey));
return sortKey;
@@ -67,6 +71,9 @@ BSONObj extractSortKey(const char* sortSpec, const char* doc) {
* Returns the BSON representation of the sort key, to be checked against the expected sort key.
*/
BSONObj extractSortKeyCovered(const char* sortSpec, const IndexKeyDatum& ikd) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
WorkingSet ws;
WorkingSetID wsid = ws.allocate();
WorkingSetMember* wsm = ws.get(wsid);
@@ -74,7 +81,7 @@ BSONObj extractSortKeyCovered(const char* sortSpec, const IndexKeyDatum& ikd) {
ws.transitionToRecordIdAndIdx(wsid);
BSONObj sortKey;
- auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(fromjson(sortSpec), BSONObj());
+ auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(txn.get(), fromjson(sortSpec), BSONObj());
ASSERT_OK(sortKeyGen->getSortKey(*wsm, &sortKey));
return sortKey;
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 91e6098d15a..cb7dfb3d0ff 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -149,6 +149,7 @@ env.CppUnitTest(
'coreshard',
'mongoscore',
'$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ '$BUILD_DIR/mongo/db/query/query_test_service_context',
'$BUILD_DIR/mongo/db/service_context_noop_init',
]
)
@@ -251,6 +252,7 @@ env.CppUnitTest(
'mongoscore',
'sharding_test_fixture',
'$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init',
+ "$BUILD_DIR/mongo/db/query/query_test_service_context",
'$BUILD_DIR/mongo/db/service_context_noop_init',
]
)
diff --git a/src/mongo/s/chunk_manager.cpp b/src/mongo/s/chunk_manager.cpp
index cb2e0055e31..328045ce868 100644
--- a/src/mongo/s/chunk_manager.cpp
+++ b/src/mongo/s/chunk_manager.cpp
@@ -490,7 +490,7 @@ void ChunkManager::getShardIdsForQuery(OperationContext* txn,
const BSONObj& query,
set<ShardId>* shardIds) const {
auto statusWithCQ =
- CanonicalQuery::canonicalize(NamespaceString(_ns), query, ExtensionsCallbackNoop());
+ CanonicalQuery::canonicalize(txn, NamespaceString(_ns), query, ExtensionsCallbackNoop());
uassertStatusOK(statusWithCQ.getStatus());
unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
diff --git a/src/mongo/s/chunk_manager_targeter.cpp b/src/mongo/s/chunk_manager_targeter.cpp
index 90d1ac9c86f..717692e324b 100644
--- a/src/mongo/s/chunk_manager_targeter.cpp
+++ b/src/mongo/s/chunk_manager_targeter.cpp
@@ -110,8 +110,8 @@ UpdateType getUpdateExprType(const BSONObj& updateExpr) {
* { _id : { $lt : 30 } } => false
* { foo : <anything> } => false
*/
-bool isExactIdQuery(const BSONObj& query) {
- StatusWith<BSONObj> status = virtualIdShardKey.extractShardKeyFromQuery(query);
+bool isExactIdQuery(OperationContext* txn, const BSONObj& query) {
+ StatusWith<BSONObj> status = virtualIdShardKey.extractShardKeyFromQuery(txn, query);
if (!status.isOK()) {
return false;
}
@@ -372,7 +372,7 @@ Status ChunkManagerTargeter::targetUpdate(OperationContext* txn,
if (updateType == UpdateType_OpStyle) {
// Target using the query
StatusWith<BSONObj> status =
- _manager->getShardKeyPattern().extractShardKeyFromQuery(query);
+ _manager->getShardKeyPattern().extractShardKeyFromQuery(txn, query);
// Bad query
if (!status.isOK())
@@ -404,7 +404,8 @@ Status ChunkManagerTargeter::targetUpdate(OperationContext* txn,
}
// Validate that single (non-multi) sharded updates are targeted by shard key or _id
- if (!updateDoc.getMulti() && shardKey.isEmpty() && !isExactIdQuery(updateDoc.getQuery())) {
+ if (!updateDoc.getMulti() && shardKey.isEmpty() &&
+ !isExactIdQuery(txn, updateDoc.getQuery())) {
return Status(ErrorCodes::ShardKeyNotFound,
stream() << "update " << updateDoc.toBSON()
<< " does not contain _id or shard key for pattern "
@@ -441,7 +442,7 @@ Status ChunkManagerTargeter::targetDelete(OperationContext* txn,
// Get the shard key
StatusWith<BSONObj> status =
- _manager->getShardKeyPattern().extractShardKeyFromQuery(deleteDoc.getQuery());
+ _manager->getShardKeyPattern().extractShardKeyFromQuery(txn, deleteDoc.getQuery());
// Bad query
if (!status.isOK())
@@ -451,7 +452,7 @@ Status ChunkManagerTargeter::targetDelete(OperationContext* txn,
// Validate that single (limit-1) sharded deletes are targeted by shard key or _id
if (deleteDoc.getLimit() == 1 && shardKey.isEmpty() &&
- !isExactIdQuery(deleteDoc.getQuery())) {
+ !isExactIdQuery(txn, deleteDoc.getQuery())) {
return Status(ErrorCodes::ShardKeyNotFound,
stream() << "delete " << deleteDoc.toBSON()
<< " does not contain _id or shard key for pattern "
diff --git a/src/mongo/s/chunk_manager_targeter_test.cpp b/src/mongo/s/chunk_manager_targeter_test.cpp
index b811edf87e1..91759528efd 100644
--- a/src/mongo/s/chunk_manager_targeter_test.cpp
+++ b/src/mongo/s/chunk_manager_targeter_test.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/matcher/extensions_callback_noop.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/query/canonical_query.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/s/chunk_manager.h"
#include "mongo/s/shard_key_pattern.h"
#include "mongo/unittest/unittest.h"
@@ -55,9 +56,13 @@ using std::make_pair;
// Utility function to create a CanonicalQuery
unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) {
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
BSONObj queryObj = fromjson(queryStr);
const NamespaceString nss("test.foo");
- auto statusWithCQ = CanonicalQuery::canonicalize(nss, queryObj, ExtensionsCallbackNoop());
+ auto statusWithCQ =
+ CanonicalQuery::canonicalize(txn.get(), nss, queryObj, ExtensionsCallbackNoop());
ASSERT_OK(statusWithCQ.getStatus());
return std::move(statusWithCQ.getValue());
}
diff --git a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp
index 086375cbd5d..6f24f34540d 100644
--- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp
+++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp
@@ -102,7 +102,7 @@ public:
const BSONObj query = cmdObj.getObjectField("query");
- StatusWith<BSONObj> status = _getShardKey(chunkMgr, query);
+ StatusWith<BSONObj> status = _getShardKey(txn, chunkMgr, query);
if (!status.isOK()) {
return status.getStatus();
}
@@ -164,7 +164,7 @@ public:
const BSONObj query = cmdObj.getObjectField("query");
- StatusWith<BSONObj> status = _getShardKey(chunkMgr, query);
+ StatusWith<BSONObj> status = _getShardKey(txn, chunkMgr, query);
if (!status.isOK()) {
// Bad query
return appendCommandStatus(result, status.getStatus());
@@ -194,10 +194,12 @@ private:
return chunkMgr;
}
- StatusWith<BSONObj> _getShardKey(shared_ptr<ChunkManager> chunkMgr,
+ StatusWith<BSONObj> _getShardKey(OperationContext* txn,
+ shared_ptr<ChunkManager> chunkMgr,
const BSONObj& query) const {
// Verify that the query has an equality predicate using the shard key
- StatusWith<BSONObj> status = chunkMgr->getShardKeyPattern().extractShardKeyFromQuery(query);
+ StatusWith<BSONObj> status =
+ chunkMgr->getShardKeyPattern().extractShardKeyFromQuery(txn, query);
if (!status.isOK()) {
return status;
diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp
index ef9d44860a8..4337f17555c 100644
--- a/src/mongo/s/commands/cluster_find_cmd.cpp
+++ b/src/mongo/s/commands/cluster_find_cmd.cpp
@@ -144,7 +144,8 @@ public:
return appendCommandStatus(result, lpq.getStatus());
}
- auto cq = CanonicalQuery::canonicalize(lpq.getValue().release(), ExtensionsCallbackNoop());
+ auto cq =
+ CanonicalQuery::canonicalize(txn, lpq.getValue().release(), ExtensionsCallbackNoop());
if (!cq.isOK()) {
return appendCommandStatus(result, cq.getStatus());
}
diff --git a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
index 8a5a22f8024..ae156c39753 100644
--- a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
+++ b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp
@@ -165,7 +165,8 @@ public:
shared_ptr<Chunk> chunk;
if (!find.isEmpty()) {
- StatusWith<BSONObj> status = info->getShardKeyPattern().extractShardKeyFromQuery(find);
+ StatusWith<BSONObj> status =
+ info->getShardKeyPattern().extractShardKeyFromQuery(txn, find);
// Bad query
if (!status.isOK())
diff --git a/src/mongo/s/commands/cluster_pipeline_cmd.cpp b/src/mongo/s/commands/cluster_pipeline_cmd.cpp
index 18126daa236..064019156de 100644
--- a/src/mongo/s/commands/cluster_pipeline_cmd.cpp
+++ b/src/mongo/s/commands/cluster_pipeline_cmd.cpp
@@ -144,7 +144,7 @@ public:
BSONObj firstMatchQuery = pipeline->getInitialQuery();
ChunkManagerPtr chunkMgr = conf->getChunkManager(txn, fullns);
BSONObj shardKeyMatches = uassertStatusOK(
- chunkMgr->getShardKeyPattern().extractShardKeyFromQuery(firstMatchQuery));
+ chunkMgr->getShardKeyPattern().extractShardKeyFromQuery(txn, firstMatchQuery));
// Don't need to split pipeline if the first $match is an exact match on shard key, unless
// there is a stage that needs to be run on the primary shard.
diff --git a/src/mongo/s/commands/cluster_split_cmd.cpp b/src/mongo/s/commands/cluster_split_cmd.cpp
index 9ad61445a0f..11df2bbe8ab 100644
--- a/src/mongo/s/commands/cluster_split_cmd.cpp
+++ b/src/mongo/s/commands/cluster_split_cmd.cpp
@@ -181,7 +181,8 @@ public:
shared_ptr<Chunk> chunk;
if (!find.isEmpty()) {
- StatusWith<BSONObj> status = info->getShardKeyPattern().extractShardKeyFromQuery(find);
+ StatusWith<BSONObj> status =
+ info->getShardKeyPattern().extractShardKeyFromQuery(txn, find);
// Bad query
if (!status.isOK()) {
diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp
index bcece3548c0..f2a670ab4ce 100644
--- a/src/mongo/s/commands/strategy.cpp
+++ b/src/mongo/s/commands/strategy.cpp
@@ -155,7 +155,7 @@ void Strategy::queryOp(OperationContext* txn, Request& request) {
uassertStatusOK(readPrefExtractStatus);
}
- auto canonicalQuery = CanonicalQuery::canonicalize(q, ExtensionsCallbackNoop());
+ auto canonicalQuery = CanonicalQuery::canonicalize(txn, q, ExtensionsCallbackNoop());
uassertStatusOK(canonicalQuery.getStatus());
// If the $explain flag was set, we must run the operation on the shards as an explain command
diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp
index d78d64ca0aa..861fee0643e 100644
--- a/src/mongo/s/shard_key_pattern.cpp
+++ b/src/mongo/s/shard_key_pattern.cpp
@@ -262,12 +262,13 @@ static BSONElement findEqualityElement(const EqualityMatches& equalities, const
return extractKeyElementFromMatchable(matchable, suffixStr);
}
-StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(const BSONObj& basicQuery) const {
+StatusWith<BSONObj> ShardKeyPattern::extractShardKeyFromQuery(OperationContext* txn,
+ const BSONObj& basicQuery) const {
if (!isValid())
return StatusWith<BSONObj>(BSONObj());
- auto statusWithCQ =
- CanonicalQuery::canonicalize(NamespaceString(""), basicQuery, ExtensionsCallbackNoop());
+ auto statusWithCQ = CanonicalQuery::canonicalize(
+ txn, NamespaceString(""), basicQuery, ExtensionsCallbackNoop());
if (!statusWithCQ.isOK()) {
return StatusWith<BSONObj>(statusWithCQ.getStatus());
}
diff --git a/src/mongo/s/shard_key_pattern.h b/src/mongo/s/shard_key_pattern.h
index 33c8f9d025d..1a8cfe91cd5 100644
--- a/src/mongo/s/shard_key_pattern.h
+++ b/src/mongo/s/shard_key_pattern.h
@@ -40,6 +40,7 @@ namespace mongo {
class CanonicalQuery;
class FieldRef;
+class OperationContext;
/**
* Helper struct when generating flattened bounds below
@@ -163,7 +164,8 @@ public:
* { a : { b : { $eq : "hi" } } } --> returns {} because the query language treats this as
* a : { $eq : { b : ... } }
*/
- StatusWith<BSONObj> extractShardKeyFromQuery(const BSONObj& basicQuery) const;
+ StatusWith<BSONObj> extractShardKeyFromQuery(OperationContext* txn,
+ const BSONObj& basicQuery) const;
StatusWith<BSONObj> extractShardKeyFromQuery(const CanonicalQuery& query) const;
/**
diff --git a/src/mongo/s/shard_key_pattern_test.cpp b/src/mongo/s/shard_key_pattern_test.cpp
index 57cb7bca521..bb54fc289b5 100644
--- a/src/mongo/s/shard_key_pattern_test.cpp
+++ b/src/mongo/s/shard_key_pattern_test.cpp
@@ -29,6 +29,7 @@
#include "mongo/db/hasher.h"
#include "mongo/db/json.h"
+#include "mongo/db/query/query_test_service_context.h"
#include "mongo/unittest/unittest.h"
namespace {
@@ -249,7 +250,10 @@ TEST(ShardKeyPattern, ExtractDocShardKeyHashed) {
}
static BSONObj queryKey(const ShardKeyPattern& pattern, const BSONObj& query) {
- StatusWith<BSONObj> status = pattern.extractShardKeyFromQuery(query);
+ QueryTestServiceContext serviceContext;
+ auto txn = serviceContext.makeOperationContext();
+
+ StatusWith<BSONObj> status = pattern.extractShardKeyFromQuery(txn.get(), query);
if (!status.isOK())
return BSONObj();
return status.getValue();