summaryrefslogtreecommitdiff
path: root/src/mongo/db
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/db
parentf49018bca41048d8a4f729ccc0489ea6be073a20 (diff)
downloadmongo-f7a46a118288ba0ce45c7664777ea0e89c2eb845.tar.gz
SERVER-23610 CanonicalQuery should own a CollatorInterface
Diffstat (limited to 'src/mongo/db')
-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
42 files changed, 460 insertions, 175 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;