diff options
Diffstat (limited to 'src/mongo/db')
29 files changed, 596 insertions, 532 deletions
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index f86fbbe8b34..d40ff0f766e 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -129,14 +129,17 @@ public: } // Finish the parsing step by using the LiteParsedQuery to create a CanonicalQuery. - - WhereCallbackReal whereCallback(txn, nss.db()); - auto statusWithCQ = - CanonicalQuery::canonicalize(lpqStatus.getValue().release(), whereCallback); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + std::unique_ptr<CanonicalQuery> cq; + { + CanonicalQuery* rawCq; + WhereCallbackReal whereCallback(txn, nss.db()); + Status canonStatus = + CanonicalQuery::canonicalize(lpqStatus.getValue().release(), &rawCq, whereCallback); + if (!canonStatus.isOK()) { + return canonStatus; + } + cq.reset(rawCq); } - std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); AutoGetCollectionForRead ctx(txn, nss); // The collection may be NULL. If so, getExecutor() should handle it by returning @@ -211,12 +214,16 @@ public: beginQueryOp(txn, nss, cmdObj, ntoreturn, lpq->getSkip()); // 1b) Finish the parsing step by using the LiteParsedQuery to create a CanonicalQuery. - WhereCallbackReal whereCallback(txn, nss.db()); - auto statusWithCQ = CanonicalQuery::canonicalize(lpq.release(), whereCallback); - if (!statusWithCQ.isOK()) { - return appendCommandStatus(result, statusWithCQ.getStatus()); + std::unique_ptr<CanonicalQuery> cq; + { + CanonicalQuery* rawCq; + WhereCallbackReal whereCallback(txn, nss.db()); + Status canonStatus = CanonicalQuery::canonicalize(lpq.release(), &rawCq, whereCallback); + if (!canonStatus.isOK()) { + return appendCommandStatus(result, canonStatus); + } + cq.reset(rawCq); } - std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); // 2) Acquire locks. AutoGetCollectionForRead ctx(txn, nss); diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp index df8fd3bdee4..5be50f433f6 100644 --- a/src/mongo/db/commands/geo_near_cmd.cpp +++ b/src/mongo/db/commands/geo_near_cmd.cpp @@ -181,22 +181,22 @@ public: BSONObj projObj = BSON("$pt" << BSON("$meta" << LiteParsedQuery::metaGeoNearPoint) << "$dis" << BSON("$meta" << LiteParsedQuery::metaGeoNearDistance)); + CanonicalQuery* cq; const WhereCallbackReal whereCallback(txn, nss.db()); - auto statusWithCQ = CanonicalQuery::canonicalize( - nss, rewritten, BSONObj(), projObj, 0, numWanted, BSONObj(), whereCallback); - if (!statusWithCQ.isOK()) { + + if (!CanonicalQuery::canonicalize( + nss, rewritten, BSONObj(), projObj, 0, numWanted, BSONObj(), &cq, whereCallback) + .isOK()) { errmsg = "Can't parse filter / create query"; return false; } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); // Prevent chunks from being cleaned up during yields - this allows us to only check the // version on initial entry into geoNear. RangePreserver preserver(collection); PlanExecutor* rawExec; - if (!getExecutor(txn, collection, cq.release(), PlanExecutor::YIELD_AUTO, &rawExec, 0) - .isOK()) { + if (!getExecutor(txn, collection, cq, PlanExecutor::YIELD_AUTO, &rawExec, 0).isOK()) { errmsg = "can't get query executor"; return false; } diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp index 0b6345ef06a..20783c5b244 100644 --- a/src/mongo/db/commands/index_filter_commands.cpp +++ b/src/mongo/db/commands/index_filter_commands.cpp @@ -268,12 +268,13 @@ Status ClearFilters::clear(OperationContext* txn, // - clear hints for single query shape when a query shape is described in the // command arguments. if (cmdObj.hasField("query")) { - auto statusWithCQ = PlanCacheCommand::canonicalize(txn, ns, cmdObj); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + CanonicalQuery* cqRaw; + Status status = PlanCacheCommand::canonicalize(txn, ns, cmdObj, &cqRaw); + if (!status.isOK()) { + return status; } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + unique_ptr<CanonicalQuery> cq(cqRaw); querySettings->removeAllowedIndices(planCache->computeKey(*cq)); // Remove entry from plan cache @@ -314,10 +315,11 @@ Status ClearFilters::clear(OperationContext* txn, invariant(entry); // Create canonical query. - auto statusWithCQ = CanonicalQuery::canonicalize( - ns, entry->query, entry->sort, entry->projection, whereCallback); - invariant(statusWithCQ.isOK()); - std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cqRaw; + Status result = CanonicalQuery::canonicalize( + ns, entry->query, entry->sort, entry->projection, &cqRaw, whereCallback); + invariant(result.isOK()); + unique_ptr<CanonicalQuery> cq(cqRaw); // Remove plan cache entry. planCache->remove(*cq); @@ -382,11 +384,12 @@ Status SetFilter::set(OperationContext* txn, indexes.push_back(obj.getOwned()); } - auto statusWithCQ = PlanCacheCommand::canonicalize(txn, ns, cmdObj); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + CanonicalQuery* cqRaw; + Status status = PlanCacheCommand::canonicalize(txn, ns, cmdObj, &cqRaw); + if (!status.isOK()) { + return status; } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + unique_ptr<CanonicalQuery> cq(cqRaw); // Add allowed indices to query settings, overriding any previous entries. querySettings->setAllowedIndices(*cq, planCache->computeKey(*cq), indexes); diff --git a/src/mongo/db/commands/index_filter_commands_test.cpp b/src/mongo/db/commands/index_filter_commands_test.cpp index 7da3619d1f7..ba6f6c87e6c 100644 --- a/src/mongo/db/commands/index_filter_commands_test.cpp +++ b/src/mongo/db/commands/index_filter_commands_test.cpp @@ -120,9 +120,9 @@ void addQueryShapeToPlanCache(PlanCache* planCache, BSONObj projectionObj = fromjson(projectionStr); // Create canonical query. - auto statusWithCQ = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projectionObj); - ASSERT_OK(statusWithCQ.getStatus()); - std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cqRaw; + ASSERT_OK(CanonicalQuery::canonicalize(ns, queryObj, sortObj, projectionObj, &cqRaw)); + unique_ptr<CanonicalQuery> cq(cqRaw); QuerySolution qs; qs.cacheData.reset(new SolutionCacheData()); @@ -144,9 +144,9 @@ bool planCacheContains(const PlanCache& planCache, BSONObj projectionObj = fromjson(projectionStr); // Create canonical query. - auto statusWithInputQuery = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projectionObj); - ASSERT_OK(statusWithInputQuery.getStatus()); - unique_ptr<CanonicalQuery> inputQuery = std::move(statusWithInputQuery.getValue()); + CanonicalQuery* cqRaw; + ASSERT_OK(CanonicalQuery::canonicalize(ns, queryObj, sortObj, projectionObj, &cqRaw)); + unique_ptr<CanonicalQuery> cq(cqRaw); // Retrieve cache entries from plan cache. vector<PlanCacheEntry*> entries = planCache.getAllEntries(); @@ -159,12 +159,11 @@ bool planCacheContains(const PlanCache& planCache, // Canonicalizing query shape in cache entry to get cache key. // Alternatively, we could add key to PlanCacheEntry but that would be used in one place // only. - auto statusWithCurrentQuery = - CanonicalQuery::canonicalize(ns, entry->query, entry->sort, entry->projection); - ASSERT_OK(statusWithCurrentQuery.getStatus()); - unique_ptr<CanonicalQuery> currentQuery = std::move(statusWithCurrentQuery.getValue()); + ASSERT_OK( + CanonicalQuery::canonicalize(ns, entry->query, entry->sort, entry->projection, &cqRaw)); + unique_ptr<CanonicalQuery> currentQuery(cqRaw); - if (planCache.computeKey(*currentQuery) == planCache.computeKey(*inputQuery)) { + if (planCache.computeKey(*currentQuery) == planCache.computeKey(*cq)) { found = true; } // Release resources for cache entry after extracting key. diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 8b395343a14..f32ebe3b8d8 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -781,8 +781,8 @@ void State::init() { _scope->invoke(init, 0, 0, 0, true); // js function to run reduce on all keys - // redfunc = _scope->createFunction("for (var key in hashmap) { print('Key is ' + key); list = - // hashmap[key]; ret = reduce(key, list); print('Value is ' + ret); };"); + // redfunc = _scope->createFunction("for (var key in hashmap) { print('Key is ' + key); + // list = hashmap[key]; ret = reduce(key, list); print('Value is ' + ret); };"); _reduceAll = _scope->createFunction( "var map = _mrMap;" "var list, ret;" @@ -1004,10 +1004,10 @@ void State::finalReduce(CurOp* op, ProgressMeterHolder& pm) { const NamespaceString nss(_config.incLong); const WhereCallbackReal whereCallback(_txn, nss.db()); - auto statusWithCQ = - CanonicalQuery::canonicalize(_config.incLong, BSONObj(), sortKey, BSONObj(), whereCallback); - verify(statusWithCQ.isOK()); - std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cqRaw; + verify(CanonicalQuery::canonicalize( + _config.incLong, BSONObj(), sortKey, BSONObj(), &cqRaw, whereCallback).isOK()); + std::unique_ptr<CanonicalQuery> cq(cqRaw); Collection* coll = getCollectionOrUassert(ctx->getDb(), _config.incLong); invariant(coll); @@ -1363,13 +1363,14 @@ public: const WhereCallbackReal whereCallback(txn, nss.db()); - auto statusWithCQ = CanonicalQuery::canonicalize( - config.ns, config.filter, config.sort, BSONObj(), whereCallback); - if (!statusWithCQ.isOK()) { + CanonicalQuery* cqRaw; + if (!CanonicalQuery::canonicalize( + config.ns, config.filter, config.sort, BSONObj(), &cqRaw, whereCallback) + .isOK()) { uasserted(17238, "Can't canonicalize query " + config.filter.toString()); return 0; } - std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + std::unique_ptr<CanonicalQuery> cq(cqRaw); Database* db = scopedAutoDb->getDb(); Collection* coll = state.getCollectionOrUassert(db, config.ns); diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp index 2232632c9a5..1fc0b40493c 100644 --- a/src/mongo/db/commands/plan_cache_commands.cpp +++ b/src/mongo/db/commands/plan_cache_commands.cpp @@ -169,9 +169,10 @@ Status PlanCacheCommand::checkAuthForCommand(ClientBasic* client, } // static -StatusWith<unique_ptr<CanonicalQuery>> PlanCacheCommand::canonicalize(OperationContext* txn, - const string& ns, - const BSONObj& cmdObj) { +Status PlanCacheCommand::canonicalize(OperationContext* txn, + const string& ns, + const BSONObj& cmdObj, + CanonicalQuery** canonicalQueryOut) { // query - required BSONElement queryElt = cmdObj.getField("query"); if (queryElt.eoo()) { @@ -206,15 +207,19 @@ StatusWith<unique_ptr<CanonicalQuery>> PlanCacheCommand::canonicalize(OperationC } // Create canonical query + CanonicalQuery* cqRaw; + const NamespaceString nss(ns); const WhereCallbackReal whereCallback(txn, nss.db()); - auto statusWithCQ = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projObj, whereCallback); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + Status result = + CanonicalQuery::canonicalize(ns, queryObj, sortObj, projObj, &cqRaw, whereCallback); + if (!result.isOK()) { + return result; } - return std::move(statusWithCQ.getValue()); + *canonicalQueryOut = cqRaw; + return Status::OK(); } PlanCacheListQueryShapes::PlanCacheListQueryShapes() @@ -299,12 +304,13 @@ Status PlanCacheClear::clear(OperationContext* txn, // - clear plans for single query shape when a query shape is described in the // command arguments. if (cmdObj.hasField("query")) { - auto statusWithCQ = PlanCacheCommand::canonicalize(txn, ns, cmdObj); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + CanonicalQuery* cqRaw; + Status status = PlanCacheCommand::canonicalize(txn, ns, cmdObj, &cqRaw); + if (!status.isOK()) { + return status; } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + unique_ptr<CanonicalQuery> cq(cqRaw); if (!planCache->contains(*cq)) { // Log if asked to clear non-existent query shape. @@ -368,11 +374,13 @@ Status PlanCacheListPlans::list(OperationContext* txn, const std::string& ns, const BSONObj& cmdObj, BSONObjBuilder* bob) { - auto statusWithCQ = canonicalize(txn, ns, cmdObj); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + CanonicalQuery* cqRaw; + Status status = canonicalize(txn, ns, cmdObj, &cqRaw); + if (!status.isOK()) { + return status; } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + + unique_ptr<CanonicalQuery> cq(cqRaw); if (!planCache.contains(*cq)) { // Return empty plans in results if query shape does not diff --git a/src/mongo/db/commands/plan_cache_commands.h b/src/mongo/db/commands/plan_cache_commands.h index d42773f42e7..3858704dbde 100644 --- a/src/mongo/db/commands/plan_cache_commands.h +++ b/src/mongo/db/commands/plan_cache_commands.h @@ -94,9 +94,10 @@ public: /** * Validatess query shape from command object and returns canonical query. */ - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize(OperationContext* txn, - const std::string& ns, - const BSONObj& cmdObj); + static Status canonicalize(OperationContext* txn, + const std::string& ns, + const BSONObj& cmdObj, + CanonicalQuery** canonicalQueryOut); private: std::string helpText; diff --git a/src/mongo/db/commands/plan_cache_commands_test.cpp b/src/mongo/db/commands/plan_cache_commands_test.cpp index c1216ea197d..8a7eee783d8 100644 --- a/src/mongo/db/commands/plan_cache_commands_test.cpp +++ b/src/mongo/db/commands/plan_cache_commands_test.cpp @@ -125,9 +125,9 @@ TEST(PlanCacheCommandsTest, planCacheListQueryShapesEmpty) { TEST(PlanCacheCommandsTest, planCacheListQueryShapesOneKey) { // Create a canonical query - auto statusWithCQ = CanonicalQuery::canonicalize(ns, fromjson("{a: 1}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cqRaw; + ASSERT_OK(CanonicalQuery::canonicalize(ns, fromjson("{a: 1}"), &cqRaw)); + unique_ptr<CanonicalQuery> cq(cqRaw); // Plan cache with one entry PlanCache planCache; @@ -150,9 +150,9 @@ TEST(PlanCacheCommandsTest, planCacheListQueryShapesOneKey) { TEST(PlanCacheCommandsTest, planCacheClearAllShapes) { // Create a canonical query - auto statusWithCQ = CanonicalQuery::canonicalize(ns, fromjson("{a: 1}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cqRaw; + ASSERT_OK(CanonicalQuery::canonicalize(ns, fromjson("{a: 1}"), &cqRaw)); + unique_ptr<CanonicalQuery> cq(cqRaw); // Plan cache with one entry PlanCache planCache; @@ -178,57 +178,52 @@ TEST(PlanCacheCommandsTest, planCacheClearAllShapes) { TEST(PlanCacheCommandsTest, Canonicalize) { // Invalid parameters PlanCache planCache; + CanonicalQuery* cqRaw; OperationContextNoop txn; // Missing query field - ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{}")).getStatus()); + ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{}"), &cqRaw)); // Query needs to be an object - ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: 1}")).getStatus()); + ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: 1}"), &cqRaw)); // Sort needs to be an object ASSERT_NOT_OK( - PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {}, sort: 1}")).getStatus()); + PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {}, sort: 1}"), &cqRaw)); // Bad query (invalid sort order) - ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {}, sort: {a: 0}}")) - .getStatus()); + ASSERT_NOT_OK( + PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {}, sort: {a: 0}}"), &cqRaw)); // Valid parameters - auto statusWithCQ = PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {a: 1, b: 1}}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> query = std::move(statusWithCQ.getValue()); + ASSERT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {a: 1, b: 1}}"), &cqRaw)); + unique_ptr<CanonicalQuery> query(cqRaw); // Equivalent query should generate same key. - statusWithCQ = PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {b: 1, a: 1}}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> equivQuery = std::move(statusWithCQ.getValue()); + ASSERT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {b: 1, a: 1}}"), &cqRaw)); + unique_ptr<CanonicalQuery> equivQuery(cqRaw); ASSERT_EQUALS(planCache.computeKey(*query), planCache.computeKey(*equivQuery)); // Sort query should generate different key from unsorted query. - statusWithCQ = PlanCacheCommand::canonicalize( - &txn, ns, fromjson("{query: {a: 1, b: 1}, sort: {a: 1, b: 1}}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> sortQuery1 = std::move(statusWithCQ.getValue()); + ASSERT_OK(PlanCacheCommand::canonicalize( + &txn, ns, fromjson("{query: {a: 1, b: 1}, sort: {a: 1, b: 1}}"), &cqRaw)); + unique_ptr<CanonicalQuery> sortQuery1(cqRaw); ASSERT_NOT_EQUALS(planCache.computeKey(*query), planCache.computeKey(*sortQuery1)); // Confirm sort arguments are properly delimited (SERVER-17158) - statusWithCQ = - PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {a: 1, b: 1}, sort: {aab: 1}}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> sortQuery2 = std::move(statusWithCQ.getValue()); + ASSERT_OK(PlanCacheCommand::canonicalize( + &txn, ns, fromjson("{query: {a: 1, b: 1}, sort: {aab: 1}}"), &cqRaw)); + unique_ptr<CanonicalQuery> sortQuery2(cqRaw); ASSERT_NOT_EQUALS(planCache.computeKey(*sortQuery1), planCache.computeKey(*sortQuery2)); // Changing order and/or value of predicates should not change key - statusWithCQ = PlanCacheCommand::canonicalize( - &txn, ns, fromjson("{query: {b: 3, a: 3}, sort: {a: 1, b: 1}}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> sortQuery3 = std::move(statusWithCQ.getValue()); + ASSERT_OK(PlanCacheCommand::canonicalize( + &txn, ns, fromjson("{query: {b: 3, a: 3}, sort: {a: 1, b: 1}}"), &cqRaw)); + unique_ptr<CanonicalQuery> sortQuery3(cqRaw); ASSERT_EQUALS(planCache.computeKey(*sortQuery1), planCache.computeKey(*sortQuery3)); // Projected query should generate different key from unprojected query. - statusWithCQ = PlanCacheCommand::canonicalize( - &txn, ns, fromjson("{query: {a: 1, b: 1}, projection: {_id: 0, a: 1}}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> projectionQuery = std::move(statusWithCQ.getValue()); + ASSERT_OK(PlanCacheCommand::canonicalize( + &txn, ns, fromjson("{query: {a: 1, b: 1}, projection: {_id: 0, a: 1}}"), &cqRaw)); + unique_ptr<CanonicalQuery> projectionQuery(cqRaw); ASSERT_NOT_EQUALS(planCache.computeKey(*query), planCache.computeKey(*projectionQuery)); } @@ -263,12 +258,11 @@ TEST(PlanCacheCommandsTest, planCacheClearUnknownKey) { TEST(PlanCacheCommandsTest, planCacheClearOneKey) { // Create 2 canonical queries. - auto statusWithCQA = CanonicalQuery::canonicalize(ns, fromjson("{a: 1}")); - ASSERT_OK(statusWithCQA.getStatus()); - unique_ptr<CanonicalQuery> cqA = std::move(statusWithCQA.getValue()); - auto statusWithCQB = CanonicalQuery::canonicalize(ns, fromjson("{b: 1}")); - ASSERT_OK(statusWithCQB.getStatus()); - unique_ptr<CanonicalQuery> cqB = std::move(statusWithCQB.getValue()); + CanonicalQuery* cqRaw; + ASSERT_OK(CanonicalQuery::canonicalize(ns, fromjson("{a: 1}"), &cqRaw)); + unique_ptr<CanonicalQuery> cqA(cqRaw); + ASSERT_OK(CanonicalQuery::canonicalize(ns, fromjson("{b: 1}"), &cqRaw)); + unique_ptr<CanonicalQuery> cqB(cqRaw); // Create plan cache with 2 entries. PlanCache planCache; @@ -383,9 +377,9 @@ TEST(PlanCacheCommandsTest, planCacheListPlansUnknownKey) { TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionTrue) { // Create a canonical query - auto statusWithCQ = CanonicalQuery::canonicalize(ns, fromjson("{a: 1}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cqRaw; + ASSERT_OK(CanonicalQuery::canonicalize(ns, fromjson("{a: 1}"), &cqRaw)); + unique_ptr<CanonicalQuery> cq(cqRaw); // Plan cache with one entry PlanCache planCache; @@ -402,9 +396,9 @@ TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionTrue) { TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionFalse) { // Create a canonical query - auto statusWithCQ = CanonicalQuery::canonicalize(ns, fromjson("{a: 1}")); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cqRaw; + ASSERT_OK(CanonicalQuery::canonicalize(ns, fromjson("{a: 1}"), &cqRaw)); + unique_ptr<CanonicalQuery> cq(cqRaw); // Plan cache with one entry PlanCache planCache; diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index ba7e84b6e31..935b4ec41f6 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -587,12 +587,11 @@ public: BSONObj sort = BSON("files_id" << 1 << "n" << 1); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - auto statusWithCQ = CanonicalQuery::canonicalize(ns, query, sort, BSONObj()); - if (!statusWithCQ.isOK()) { + CanonicalQuery* cq; + if (!CanonicalQuery::canonicalize(ns, query, sort, BSONObj(), &cq).isOK()) { uasserted(17240, "Can't canonicalize query " + query.toString()); return 0; } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); // Check shard version at startup. // This will throw before we've done any work if shard version is outdated @@ -603,7 +602,7 @@ public: PlanExecutor* rawExec; if (!getExecutor(txn, coll, - cq.release(), + cq, PlanExecutor::YIELD_MANUAL, &rawExec, QueryPlannerParams::NO_TABLE_SCAN).isOK()) { diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index 0517552c7c2..e5e198d7ff0 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -129,19 +129,18 @@ RecordId Helpers::findOne(OperationContext* txn, if (!collection) return RecordId(); + CanonicalQuery* cq; const WhereCallbackReal whereCallback(txn, collection->ns().db()); - auto statusWithCQ = CanonicalQuery::canonicalize(collection->ns(), query, whereCallback); - massert(17244, "Could not canonicalize " + query.toString(), statusWithCQ.isOK()); - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + massert(17244, + "Could not canonicalize " + query.toString(), + CanonicalQuery::canonicalize(collection->ns(), query, &cq, whereCallback).isOK()); PlanExecutor* rawExec; size_t options = requireIndex ? QueryPlannerParams::NO_TABLE_SCAN : QueryPlannerParams::DEFAULT; - massert( - 17245, - "Could not get executor for query " + query.toString(), - getExecutor(txn, collection, cq.release(), PlanExecutor::YIELD_MANUAL, &rawExec, options) - .isOK()); + massert(17245, + "Could not get executor for query " + query.toString(), + getExecutor(txn, collection, cq, PlanExecutor::YIELD_MANUAL, &rawExec, options).isOK()); unique_ptr<PlanExecutor> exec(rawExec); PlanExecutor::ExecState state; diff --git a/src/mongo/db/exec/sort.cpp b/src/mongo/db/exec/sort.cpp index 7aeef7ee68b..7a98b5113c2 100644 --- a/src/mongo/db/exec/sort.cpp +++ b/src/mongo/db/exec/sort.cpp @@ -226,10 +226,10 @@ void SortStageKeyGenerator::getBoundsForSort(const BSONObj& queryObj, const BSON sortObj, IndexNames::BTREE, true, false, false, "doesnt_matter", NULL, BSONObj()); params.indices.push_back(sortOrder); - auto statusWithQueryForSort = - CanonicalQuery::canonicalize("fake_ns", queryObj, WhereCallbackNoop()); - verify(statusWithQueryForSort.isOK()); - unique_ptr<CanonicalQuery> queryForSort = std::move(statusWithQueryForSort.getValue()); + CanonicalQuery* rawQueryForSort; + verify(CanonicalQuery::canonicalize("fake_ns", queryObj, &rawQueryForSort, WhereCallbackNoop()) + .isOK()); + unique_ptr<CanonicalQuery> queryForSort(rawQueryForSort); vector<QuerySolution*> solns; LOG(5) << "Sort stage: Planning to obtain bounds for sort." << endl; diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp index a5b33be1ba9..62daed09f32 100644 --- a/src/mongo/db/exec/subplan.cpp +++ b/src/mongo/db/exec/subplan.cpp @@ -130,23 +130,27 @@ Status SubplanStage::planSubqueries() { MatchExpression* orChild = orExpr->getChild(i); // Turn the i-th child into its own query. - auto statusWithCQ = CanonicalQuery::canonicalize(*_query, orChild, whereCallback); - if (!statusWithCQ.isOK()) { - mongoutils::str::stream ss; - ss << "Can't canonicalize subchild " << orChild->toString() << " " - << statusWithCQ.getStatus().reason(); - return Status(ErrorCodes::BadValue, ss); - } + { + CanonicalQuery* orChildCQ; + Status childCQStatus = + CanonicalQuery::canonicalize(*_query, orChild, &orChildCQ, whereCallback); + if (!childCQStatus.isOK()) { + mongoutils::str::stream ss; + ss << "Can't canonicalize subchild " << orChild->toString() << " " + << childCQStatus.reason(); + return Status(ErrorCodes::BadValue, ss); + } - branchResult->canonicalQuery = std::move(statusWithCQ.getValue()); + branchResult->canonicalQuery.reset(orChildCQ); + } // Plan the i-th child. We might be able to find a plan for the i-th child in the plan // cache. If there's no cached plan, then we generate and rank plans using the MPS. CachedSolution* rawCS; - if (PlanCache::shouldCacheQuery(*branchResult->canonicalQuery) && + if (PlanCache::shouldCacheQuery(*branchResult->canonicalQuery.get()) && _collection->infoCache() ->getPlanCache() - ->get(*branchResult->canonicalQuery, &rawCS) + ->get(*branchResult->canonicalQuery.get(), &rawCS) .isOK()) { // We have a CachedSolution. Store it for later. LOG(5) << "Subplanner: cached plan found for child " << i << " of " @@ -159,7 +163,7 @@ Status SubplanStage::planSubqueries() { // We don't set NO_TABLE_SCAN because peeking at the cache data will keep us from // considering any plan that's a collscan. - Status status = QueryPlanner::plan(*branchResult->canonicalQuery, + Status status = QueryPlanner::plan(*branchResult->canonicalQuery.get(), _plannerParams, &branchResult->solutions.mutableVector()); diff --git a/src/mongo/db/exec/update.cpp b/src/mongo/db/exec/update.cpp index e37d716d338..7d2a768664f 100644 --- a/src/mongo/db/exec/update.cpp +++ b/src/mongo/db/exec/update.cpp @@ -619,7 +619,7 @@ Status UpdateStage::applyUpdateOpsForInsert(const CanonicalQuery* cq, BSONObj original; if (cq) { - Status status = driver->populateDocumentWithQueryFields(*cq, immutablePaths, *doc); + Status status = driver->populateDocumentWithQueryFields(cq, immutablePaths, *doc); if (!status.isOK()) { return status; } diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp index ddb24fa2faf..46a2a33752d 100644 --- a/src/mongo/db/ops/parsed_delete.cpp +++ b/src/mongo/db/ops/parsed_delete.cpp @@ -69,6 +69,7 @@ Status ParsedDelete::parseRequest() { Status ParsedDelete::parseQueryToCQ() { dassert(!_canonicalQuery.get()); + CanonicalQuery* cqRaw; const WhereCallbackReal whereCallback(_txn, _request->getNamespaceString().db()); // Limit should only used for the findAndModify command when a sort is specified. If a sort @@ -82,24 +83,25 @@ 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().ns(), - _request->getQuery(), - _request->getSort(), - emptyObj, // projection - 0, // skip - limit, - emptyObj, // hint - emptyObj, // min - emptyObj, // max - false, // snapshot - _request->isExplain(), - whereCallback); - - if (statusWithCQ.isOK()) { - _canonicalQuery = std::move(statusWithCQ.getValue()); + Status status = CanonicalQuery::canonicalize(_request->getNamespaceString().ns(), + _request->getQuery(), + _request->getSort(), + emptyObj, // projection + 0, // skip + limit, + emptyObj, // hint + emptyObj, // min + emptyObj, // max + false, // snapshot + _request->isExplain(), + &cqRaw, + whereCallback); + + if (status.isOK()) { + _canonicalQuery.reset(cqRaw); } - return statusWithCQ.getStatus(); + return status; } const DeleteRequest* ParsedDelete::getRequest() const { @@ -121,9 +123,9 @@ bool ParsedDelete::hasParsedQuery() const { return _canonicalQuery.get() != NULL; } -std::unique_ptr<CanonicalQuery> ParsedDelete::releaseParsedQuery() { +CanonicalQuery* ParsedDelete::releaseParsedQuery() { invariant(_canonicalQuery.get() != NULL); - return std::move(_canonicalQuery); + return _canonicalQuery.release(); } } // namespace mongo diff --git a/src/mongo/db/ops/parsed_delete.h b/src/mongo/db/ops/parsed_delete.h index cdf22b4cac7..0745cbb85e8 100644 --- a/src/mongo/db/ops/parsed_delete.h +++ b/src/mongo/db/ops/parsed_delete.h @@ -102,7 +102,7 @@ public: /** * Releases ownership of the canonical query to the caller. */ - std::unique_ptr<CanonicalQuery> releaseParsedQuery(); + CanonicalQuery* releaseParsedQuery(); private: // Transactional context. Not owned by us. diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index 41b010f1d68..80138e0385d 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -73,6 +73,7 @@ Status ParsedUpdate::parseQuery() { Status ParsedUpdate::parseQueryToCQ() { dassert(!_canonicalQuery.get()); + CanonicalQuery* cqRaw; const WhereCallbackReal whereCallback(_txn, _request->getNamespaceString().db()); // Limit should only used for the findAndModify command when a sort is specified. If a sort @@ -86,23 +87,24 @@ 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().ns(), - _request->getQuery(), - _request->getSort(), - emptyObj, // projection - 0, // skip - limit, - emptyObj, // hint - emptyObj, // min - emptyObj, // max - false, // snapshot - _request->isExplain(), - whereCallback); - if (statusWithCQ.isOK()) { - _canonicalQuery = std::move(statusWithCQ.getValue()); + Status status = CanonicalQuery::canonicalize(_request->getNamespaceString().ns(), + _request->getQuery(), + _request->getSort(), + emptyObj, // projection + 0, // skip + limit, + emptyObj, // hint + emptyObj, // min + emptyObj, // max + false, // snapshot + _request->isExplain(), + &cqRaw, + whereCallback); + if (status.isOK()) { + _canonicalQuery.reset(cqRaw); } - return statusWithCQ.getStatus(); + return status; } Status ParsedUpdate::parseUpdate() { @@ -136,9 +138,9 @@ bool ParsedUpdate::hasParsedQuery() const { return _canonicalQuery.get() != NULL; } -std::unique_ptr<CanonicalQuery> ParsedUpdate::releaseParsedQuery() { +CanonicalQuery* ParsedUpdate::releaseParsedQuery() { invariant(_canonicalQuery.get() != NULL); - return std::move(_canonicalQuery); + return _canonicalQuery.release(); } const UpdateRequest* ParsedUpdate::getRequest() const { diff --git a/src/mongo/db/ops/parsed_update.h b/src/mongo/db/ops/parsed_update.h index 3c0cf015c94..8ce08aaabc3 100644 --- a/src/mongo/db/ops/parsed_update.h +++ b/src/mongo/db/ops/parsed_update.h @@ -107,7 +107,7 @@ public: /** * Releases ownership of the canonical query to the caller. */ - std::unique_ptr<CanonicalQuery> releaseParsedQuery(); + CanonicalQuery* releaseParsedQuery(); private: /** diff --git a/src/mongo/db/ops/update_driver.cpp b/src/mongo/db/ops/update_driver.cpp index 9045b691e16..ccd966dbb81 100644 --- a/src/mongo/db/ops/update_driver.cpp +++ b/src/mongo/db/ops/update_driver.cpp @@ -169,19 +169,18 @@ inline Status UpdateDriver::addAndParse(const modifiertable::ModifierType type, Status UpdateDriver::populateDocumentWithQueryFields(const BSONObj& query, const vector<FieldRef*>* immutablePaths, mutablebson::Document& doc) const { + CanonicalQuery* rawCG; // 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 clause does not make sense, hence empty WhereCallback. - auto statusWithCQ = CanonicalQuery::canonicalize("", query, WhereCallbackNoop()); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); - } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); - - return populateDocumentWithQueryFields(*cq, immutablePaths, doc); + Status s = CanonicalQuery::canonicalize("", query, &rawCG, WhereCallbackNoop()); + if (!s.isOK()) + return s; + unique_ptr<CanonicalQuery> cq(rawCG); + return populateDocumentWithQueryFields(rawCG, immutablePaths, doc); } -Status UpdateDriver::populateDocumentWithQueryFields(const CanonicalQuery& query, +Status UpdateDriver::populateDocumentWithQueryFields(const CanonicalQuery* query, const vector<FieldRef*>* immutablePathsPtr, mutablebson::Document& doc) const { EqualityMatches equalities; @@ -201,10 +200,10 @@ Status UpdateDriver::populateDocumentWithQueryFields(const CanonicalQuery& query // Extract only immutable fields from replacement-style status = - pathsupport::extractFullEqualityMatches(*query.root(), pathsToExtract, &equalities); + pathsupport::extractFullEqualityMatches(*query->root(), pathsToExtract, &equalities); } else { // Extract all fields from op-style - status = pathsupport::extractEqualityMatches(*query.root(), &equalities); + status = pathsupport::extractEqualityMatches(*query->root(), &equalities); } if (!status.isOK()) diff --git a/src/mongo/db/ops/update_driver.h b/src/mongo/db/ops/update_driver.h index bb11ee42bb4..00e3e2eb10f 100644 --- a/src/mongo/db/ops/update_driver.h +++ b/src/mongo/db/ops/update_driver.h @@ -71,7 +71,7 @@ public: const std::vector<FieldRef*>* immutablePaths, mutablebson::Document& doc) const; - Status populateDocumentWithQueryFields(const CanonicalQuery& query, + Status populateDocumentWithQueryFields(const CanonicalQuery* query, const std::vector<FieldRef*>* immutablePaths, mutablebson::Document& doc) const; diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index 0a10cfc5f3d..6dbcfe4c812 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -48,7 +48,6 @@ namespace mongo { using boost::intrusive_ptr; using std::shared_ptr; using std::string; -using std::unique_ptr; namespace { class MongodImplementation final : public DocumentSourceNeedsMongod::MongodInterface { @@ -181,17 +180,14 @@ shared_ptr<PlanExecutor> PipelineD::prepareCursorSource( const WhereCallbackReal whereCallback(pExpCtx->opCtx, pExpCtx->ns.db()); if (sortStage) { - auto statusWithCQ = CanonicalQuery::canonicalize( - pExpCtx->ns, queryObj, sortObj, projectionForQuery, whereCallback); + CanonicalQuery* cq; + Status status = CanonicalQuery::canonicalize( + pExpCtx->ns, queryObj, sortObj, projectionForQuery, &cq, whereCallback); PlanExecutor* rawExec; - if (statusWithCQ.isOK() && - getExecutor(txn, - collection, - statusWithCQ.getValue().release(), - PlanExecutor::YIELD_AUTO, - &rawExec, - runnerOptions).isOK()) { + if (status.isOK() && + getExecutor(txn, collection, cq, PlanExecutor::YIELD_AUTO, &rawExec, runnerOptions) + .isOK()) { // success: The PlanExecutor will handle sorting for us using an index. exec.reset(rawExec); sortInRunner = true; @@ -206,14 +202,13 @@ shared_ptr<PlanExecutor> PipelineD::prepareCursorSource( if (!exec.get()) { const BSONObj noSort; - auto statusWithCQ = CanonicalQuery::canonicalize( - pExpCtx->ns, queryObj, noSort, projectionForQuery, whereCallback); - uassertStatusOK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + uassertStatusOK(CanonicalQuery::canonicalize( + pExpCtx->ns, queryObj, noSort, projectionForQuery, &cq, whereCallback)); PlanExecutor* rawExec; - uassertStatusOK(getExecutor( - txn, collection, cq.release(), PlanExecutor::YIELD_AUTO, &rawExec, runnerOptions)); + uassertStatusOK( + getExecutor(txn, collection, cq, PlanExecutor::YIELD_AUTO, &rawExec, runnerOptions)); exec.reset(rawExec); } diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index 701a5fd2545..ac6ba1627d1 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -100,20 +100,20 @@ bool matchExpressionLessThan(const MatchExpression* lhs, const MatchExpression* // // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const std::string& ns, - const BSONObj& query, - const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(const std::string& ns, + const BSONObj& query, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { const BSONObj emptyObj; - return CanonicalQuery::canonicalize(ns, query, emptyObj, emptyObj, 0, 0, whereCallback); + return CanonicalQuery::canonicalize(ns, query, emptyObj, emptyObj, 0, 0, out, whereCallback); } // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const std::string& ns, - const BSONObj& query, - bool explain, - const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(const std::string& ns, + const BSONObj& query, + bool explain, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { const BSONObj emptyObj; return CanonicalQuery::canonicalize(ns, query, @@ -126,54 +126,56 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( emptyObj, // max false, // snapshot explain, + out, whereCallback); } // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const std::string& ns, - const BSONObj& query, - long long skip, - long long limit, - const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(const std::string& ns, + const BSONObj& query, + long long skip, + long long limit, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { const BSONObj emptyObj; - return CanonicalQuery::canonicalize(ns, query, emptyObj, emptyObj, skip, limit, whereCallback); + return CanonicalQuery::canonicalize( + ns, query, emptyObj, emptyObj, skip, limit, out, whereCallback); } // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const std::string& ns, - const BSONObj& query, - const BSONObj& sort, - const BSONObj& proj, - const MatchExpressionParser::WhereCallback& whereCallback) { - return CanonicalQuery::canonicalize(ns, query, sort, proj, 0, 0, whereCallback); +Status CanonicalQuery::canonicalize(const std::string& ns, + const BSONObj& query, + const BSONObj& sort, + const BSONObj& proj, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { + return CanonicalQuery::canonicalize(ns, query, sort, proj, 0, 0, out, whereCallback); } // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const std::string& ns, - const BSONObj& query, - const BSONObj& sort, - const BSONObj& proj, - long long skip, - long long limit, - const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(const std::string& ns, + const BSONObj& query, + const BSONObj& sort, + const BSONObj& proj, + long long skip, + long long limit, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { const BSONObj emptyObj; return CanonicalQuery::canonicalize( - ns, query, sort, proj, skip, limit, emptyObj, whereCallback); + ns, query, sort, proj, skip, limit, emptyObj, out, whereCallback); } // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const std::string& ns, - const BSONObj& query, - const BSONObj& sort, - const BSONObj& proj, - long long skip, - long long limit, - const BSONObj& hint, - const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(const std::string& ns, + const BSONObj& query, + const BSONObj& sort, + const BSONObj& proj, + long long skip, + long long limit, + const BSONObj& hint, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { const BSONObj emptyObj; return CanonicalQuery::canonicalize(ns, query, @@ -186,6 +188,7 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( emptyObj, false, // snapshot false, // explain + out, whereCallback); } @@ -194,20 +197,22 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( // // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const QueryMessage& qm, const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(const QueryMessage& qm, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { // Make LiteParsedQuery. auto lpqStatus = LiteParsedQuery::fromLegacyQueryMessage(qm); if (!lpqStatus.isOK()) { return lpqStatus.getStatus(); } - return CanonicalQuery::canonicalize(lpqStatus.getValue().release(), whereCallback); + return CanonicalQuery::canonicalize(lpqStatus.getValue().release(), out, whereCallback); } // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - LiteParsedQuery* lpq, const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(LiteParsedQuery* lpq, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { std::unique_ptr<LiteParsedQuery> autoLpq(lpq); // Make MatchExpression. @@ -226,14 +231,15 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( if (!initStatus.isOK()) { return initStatus; } - return std::move(cq); + *out = cq.release(); + return Status::OK(); } // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const CanonicalQuery& baseQuery, - MatchExpression* root, - const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(const CanonicalQuery& baseQuery, + MatchExpression* root, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { // Pass empty sort and projection. BSONObj emptyObj; @@ -263,23 +269,24 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( if (!initStatus.isOK()) { return initStatus; } - return std::move(cq); + *out = cq.release(); + return Status::OK(); } // static -StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( - const std::string& ns, - const BSONObj& query, - const BSONObj& sort, - const BSONObj& proj, - long long skip, - long long limit, - const BSONObj& hint, - const BSONObj& minObj, - const BSONObj& maxObj, - bool snapshot, - bool explain, - const MatchExpressionParser::WhereCallback& whereCallback) { +Status CanonicalQuery::canonicalize(const std::string& ns, + const BSONObj& query, + const BSONObj& sort, + const BSONObj& proj, + long long skip, + long long limit, + const BSONObj& hint, + const BSONObj& minObj, + const BSONObj& maxObj, + bool snapshot, + bool explain, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback) { // Pass empty sort and projection. BSONObj emptyObj; @@ -305,7 +312,8 @@ StatusWith<std::unique_ptr<CanonicalQuery>> CanonicalQuery::canonicalize( if (!initStatus.isOK()) { return initStatus; } - return std::move(cq); + *out = cq.release(); + return Status::OK(); } Status CanonicalQuery::init(LiteParsedQuery* lpq, diff --git a/src/mongo/db/query/canonical_query.h b/src/mongo/db/query/canonical_query.h index 56f06a20c9d..58a2c46f3a8 100644 --- a/src/mongo/db/query/canonical_query.h +++ b/src/mongo/db/query/canonical_query.h @@ -41,28 +41,26 @@ namespace mongo { 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. + * Caller owns the pointer in 'out' if any call to canonicalize returns Status::OK(). * * Used for legacy find through the OP_QUERY message. */ - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const QueryMessage& qm, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); + static Status canonicalize(const QueryMessage& qm, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); /** * Takes ownership of 'lpq'. * - * 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. + * Caller owns the pointer in 'out' if any call to canonicalize returns Status::OK(). * * Used for finds using the find command path. */ - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - LiteParsedQuery* lpq, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); + static Status canonicalize(LiteParsedQuery* lpq, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); /** * For testing or for internal clients to use. @@ -75,76 +73,76 @@ public: * * Does not take ownership of 'root'. */ - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const CanonicalQuery& baseQuery, - MatchExpression* root, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); - - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const std::string& ns, - const BSONObj& query, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); - - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const std::string& ns, - const BSONObj& query, - bool explain, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); - - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const std::string& ns, - const BSONObj& query, - long long skip, - long long limit, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); - - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const std::string& ns, - const BSONObj& query, - const BSONObj& sort, - const BSONObj& proj, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); - - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const std::string& ns, - const BSONObj& query, - const BSONObj& sort, - const BSONObj& proj, - long long skip, - long long limit, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); - - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const std::string& ns, - const BSONObj& query, - const BSONObj& sort, - const BSONObj& proj, - long long skip, - long long limit, - const BSONObj& hint, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); - - static StatusWith<std::unique_ptr<CanonicalQuery>> canonicalize( - const std::string& ns, - const BSONObj& query, - const BSONObj& sort, - const BSONObj& proj, - long long skip, - long long limit, - const BSONObj& hint, - const BSONObj& minObj, - const BSONObj& maxObj, - bool snapshot, - bool explain, - const MatchExpressionParser::WhereCallback& whereCallback = - MatchExpressionParser::WhereCallback()); + static Status canonicalize(const CanonicalQuery& baseQuery, + MatchExpression* root, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); + + static Status canonicalize(const std::string& ns, + const BSONObj& query, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); + + static Status canonicalize(const std::string& ns, + const BSONObj& query, + bool explain, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); + + static Status canonicalize(const std::string& ns, + const BSONObj& query, + long long skip, + long long limit, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); + + static Status canonicalize(const std::string& ns, + const BSONObj& query, + const BSONObj& sort, + const BSONObj& proj, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); + + static Status canonicalize(const std::string& ns, + const BSONObj& query, + const BSONObj& sort, + const BSONObj& proj, + long long skip, + long long limit, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); + + static Status canonicalize(const std::string& ns, + const BSONObj& query, + const BSONObj& sort, + const BSONObj& proj, + long long skip, + long long limit, + const BSONObj& hint, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); + + static Status canonicalize(const std::string& ns, + const BSONObj& query, + const BSONObj& sort, + const BSONObj& proj, + long long skip, + long long limit, + const BSONObj& hint, + const BSONObj& minObj, + const BSONObj& maxObj, + bool snapshot, + bool explain, + CanonicalQuery** out, + const MatchExpressionParser::WhereCallback& whereCallback = + MatchExpressionParser::WhereCallback()); /** * Returns true if "query" describes an exact-match query on _id, possibly with diff --git a/src/mongo/db/query/canonical_query_test.cpp b/src/mongo/db/query/canonical_query_test.cpp index 8036dac3adb..d3fb9a55fd4 100644 --- a/src/mongo/db/query/canonical_query_test.cpp +++ b/src/mongo/db/query/canonical_query_test.cpp @@ -35,6 +35,7 @@ namespace mongo { namespace { using std::string; +using std::unique_ptr; using unittest::assertGet; static const char* ns = "somebogusns"; @@ -51,7 +52,6 @@ MatchExpression* parseMatchExpression(const BSONObj& obj) { << ". Reason: " << status.getStatus().toString(); FAIL(ss); } - return status.getValue(); } @@ -62,7 +62,8 @@ MatchExpression* parseMatchExpression(const BSONObj& obj) { */ Status isValid(const std::string& queryStr, const LiteParsedQuery& lpqRaw) { BSONObj queryObj = fromjson(queryStr); - unique_ptr<MatchExpression> me(CanonicalQuery::normalizeTree(parseMatchExpression(queryObj))); + std::unique_ptr<MatchExpression> me( + CanonicalQuery::normalizeTree(parseMatchExpression(queryObj))); return CanonicalQuery::isValid(me.get(), lpqRaw); } @@ -460,22 +461,22 @@ TEST(CanonicalQueryTest, SortTreeNumChildrenComparison) { /** * Utility function to create a CanonicalQuery */ -unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) { +CanonicalQuery* canonicalize(const char* queryStr) { BSONObj queryObj = fromjson(queryStr); - auto statusWithCQ = CanonicalQuery::canonicalize(ns, queryObj); - ASSERT_OK(statusWithCQ.getStatus()); - return std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status result = CanonicalQuery::canonicalize(ns, queryObj, &cq); + ASSERT_OK(result); + return cq; } -std::unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, - const char* sortStr, - const char* projStr) { +CanonicalQuery* canonicalize(const char* queryStr, const char* sortStr, const char* projStr) { BSONObj queryObj = fromjson(queryStr); BSONObj sortObj = fromjson(sortStr); BSONObj projObj = fromjson(projStr); - auto statusWithCQ = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projObj); - ASSERT_OK(statusWithCQ.getStatus()); - return std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status result = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projObj, &cq); + ASSERT_OK(result); + return cq; } // Don't do anything with a double OR. diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index 2283bc66e9f..f170dc8ea04 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -278,9 +278,9 @@ QueryResult::View getMore(OperationContext* txn, // Note that we declare our locks before our ClientCursorPin, in order to ensure that the // pin's destructor is called before the lock destructors (so that the unpin occurs under // the lock). - unique_ptr<AutoGetCollectionForRead> ctx; - unique_ptr<Lock::DBLock> unpinDBLock; - unique_ptr<Lock::CollectionLock> unpinCollLock; + std::unique_ptr<AutoGetCollectionForRead> ctx; + std::unique_ptr<Lock::DBLock> unpinDBLock; + std::unique_ptr<Lock::CollectionLock> unpinCollLock; CursorManager* cursorManager; CursorManager* globalCursorManager = CursorManager::getGlobalCursorManager(); @@ -315,7 +315,7 @@ QueryResult::View getMore(OperationContext* txn, // has a valid RecoveryUnit. As such, we use RAII to accomplish this. // // This must be destroyed before the ClientCursor is destroyed. - unique_ptr<ScopedRecoveryUnitSwapper> ruSwapper; + std::unique_ptr<ScopedRecoveryUnitSwapper> ruSwapper; // These are set in the QueryResult msg we return. int resultFlags = ResultFlag_AwaitCapable; @@ -416,7 +416,7 @@ QueryResult::View getMore(OperationContext* txn, if (PlanExecutor::DEAD == state || PlanExecutor::FAILURE == state) { // Propagate this error to caller. - const unique_ptr<PlanStageStats> stats(exec->getStats()); + const std::unique_ptr<PlanStageStats> stats(exec->getStats()); error() << "getMore executor error, stats: " << Explain::statsToBSON(*stats); uasserted(17406, "getMore executor error: " + WorkingSetCommon::toStatusString(obj)); } @@ -506,14 +506,17 @@ std::string runQuery(OperationContext* txn, beginQueryOp(txn, nss, q.query, q.ntoreturn, q.ntoskip); // Parse the qm into a CanonicalQuery. - - auto statusWithCQ = CanonicalQuery::canonicalize(q, WhereCallbackReal(txn, nss.db())); - if (!statusWithCQ.isOK()) { - uasserted( - 17287, - str::stream() << "Can't canonicalize query: " << statusWithCQ.getStatus().toString()); + std::unique_ptr<CanonicalQuery> cq; + { + CanonicalQuery* cqRaw; + Status canonStatus = + CanonicalQuery::canonicalize(q, &cqRaw, WhereCallbackReal(txn, nss.db())); + if (!canonStatus.isOK()) { + uasserted(17287, + str::stream() << "Can't canonicalize query: " << canonStatus.toString()); + } + cq.reset(cqRaw); } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); invariant(cq.get()); LOG(5) << "Running query:\n" << cq->toString(); @@ -527,7 +530,7 @@ std::string runQuery(OperationContext* txn, ctx.getDb() ? ctx.getDb()->getProfilingLevel() : serverGlobalParams.defaultProfile; // We have a parsed query. Time to get the execution plan for it. - unique_ptr<PlanExecutor> exec; + std::unique_ptr<PlanExecutor> exec; { PlanExecutor* rawExec; Status execStatus = @@ -633,7 +636,7 @@ std::string runQuery(OperationContext* txn, // Caller expects exceptions thrown in certain cases. if (PlanExecutor::FAILURE == state || PlanExecutor::DEAD == state) { - const unique_ptr<PlanStageStats> stats(exec->getStats()); + const std::unique_ptr<PlanStageStats> stats(exec->getStats()); error() << "Plan executor error during find: " << PlanExecutor::statestr(state) << ", stats: " << Explain::statsToBSON(*stats); uasserted(17144, "Executor error: " + WorkingSetCommon::toStatusString(obj)); diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index a098175b112..1472d6693ae 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -467,15 +467,14 @@ Status getExecutor(OperationContext* txn, if (!CanonicalQuery::isSimpleIdQuery(unparsedQuery) || !collection->getIndexCatalog()->findIdIndex(txn)) { const WhereCallbackReal whereCallback(txn, collection->ns().db()); - auto statusWithCQ = - CanonicalQuery::canonicalize(collection->ns(), unparsedQuery, whereCallback); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); - } - std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status status = + CanonicalQuery::canonicalize(collection->ns(), unparsedQuery, &cq, whereCallback); + if (!status.isOK()) + return status; // Takes ownership of 'cq'. - return getExecutor(txn, collection, cq.release(), yieldPolicy, out, plannerOptions); + return getExecutor(txn, collection, cq, yieldPolicy, out, plannerOptions); } LOG(2) << "Using idhack: " << unparsedQuery.toString(); @@ -969,13 +968,13 @@ Status getExecutorGroup(OperationContext* txn, const NamespaceString nss(request.ns); const WhereCallbackReal whereCallback(txn, nss.db()); - - auto statusWithCQ = - CanonicalQuery::canonicalize(request.ns, request.query, request.explain, whereCallback); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + CanonicalQuery* rawCanonicalQuery; + Status canonicalizeStatus = CanonicalQuery::canonicalize( + request.ns, request.query, request.explain, &rawCanonicalQuery, whereCallback); + if (!canonicalizeStatus.isOK()) { + return canonicalizeStatus; } - unique_ptr<CanonicalQuery> canonicalQuery = std::move(statusWithCQ.getValue()); + unique_ptr<CanonicalQuery> canonicalQuery(rawCanonicalQuery); const size_t defaultPlannerOptions = 0; Status status = prepareExecution(txn, @@ -1134,8 +1133,7 @@ std::string getProjectedDottedField(const std::string& field, bool* isIDOut) { std::vector<std::string> prefixStrings(res); prefixStrings.resize(i); // Reset projectedField. Instead of overwriting, joinStringDelim() appends joined - // string - // to the end of projectedField. + // string to the end of projectedField. std::string projectedField; mongo::joinStringDelim(prefixStrings, &projectedField, '.'); return projectedField; @@ -1202,7 +1200,8 @@ Status getExecutorCount(OperationContext* txn, if (!request.getQuery().isEmpty() || !request.getHint().isEmpty()) { // If query or hint is not empty, canonicalize the query before working with collection. typedef MatchExpressionParser::WhereCallback WhereCallback; - auto statusWithCQ = CanonicalQuery::canonicalize( + CanonicalQuery* rawCq = NULL; + Status canonStatus = CanonicalQuery::canonicalize( request.getNs(), request.getQuery(), BSONObj(), // sort @@ -1214,13 +1213,14 @@ Status getExecutorCount(OperationContext* txn, BSONObj(), // max false, // snapshot explain, + &rawCq, collection ? static_cast<const WhereCallback&>(WhereCallbackReal(txn, collection->ns().db())) : static_cast<const WhereCallback&>(WhereCallbackNoop())); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + if (!canonStatus.isOK()) { + return canonStatus; } - cq = std::move(statusWithCQ.getValue()); + cq.reset(rawCq); } if (!collection) { @@ -1348,15 +1348,15 @@ Status 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().ns(), query, whereCallback); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + CanonicalQuery* cq; + Status status = + CanonicalQuery::canonicalize(collection->ns().ns(), query, &cq, whereCallback); + if (!status.isOK()) { + return status; } - std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); // Takes ownership of 'cq'. - return getExecutor(txn, collection, cq.release(), yieldPolicy, out); + return getExecutor(txn, collection, cq, yieldPolicy, out); } // @@ -1369,13 +1369,14 @@ Status 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().ns(), query, BSONObj(), projection, whereCallback); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + CanonicalQuery* cq; + Status status = CanonicalQuery::canonicalize( + collection->ns().ns(), query, BSONObj(), projection, &cq, whereCallback); + if (!status.isOK()) { + return status; } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + unique_ptr<CanonicalQuery> autoCq(cq); // If there's no query, we can just distinct-scan one of the indices. // Not every index in plannerParams.indices may be suitable. Refer to @@ -1402,14 +1403,15 @@ Status getExecutorDistinct(OperationContext* txn, << ", planSummary: " << Explain::getPlanSummary(root); // Takes ownership of its arguments (except for 'collection'). - return PlanExecutor::make(txn, ws, root, soln, cq.release(), collection, yieldPolicy, out); + return PlanExecutor::make( + txn, ws, root, soln, autoCq.release(), collection, yieldPolicy, out); } // See if we can answer the query in a fast-distinct compatible fashion. vector<QuerySolution*> solutions; - Status status = QueryPlanner::plan(*cq, plannerParams, &solutions); + status = QueryPlanner::plan(*cq, plannerParams, &solutions); if (!status.isOK()) { - return getExecutor(txn, collection, cq.release(), yieldPolicy, out); + return getExecutor(txn, collection, autoCq.release(), yieldPolicy, out); } // We look for a solution that has an ixscan we can turn into a distinctixscan @@ -1430,9 +1432,9 @@ Status getExecutorDistinct(OperationContext* txn, LOG(2) << "Using fast distinct: " << cq->toStringShort() << ", planSummary: " << Explain::getPlanSummary(root); - // Takes ownership of 'ws', 'root', 'solutions[i]', and 'cq'. + // Takes ownership of 'ws', 'root', 'solutions[i]', and 'autoCq'. return PlanExecutor::make( - txn, ws, root, solutions[i], cq.release(), collection, yieldPolicy, out); + txn, ws, root, solutions[i], autoCq.release(), collection, yieldPolicy, out); } } @@ -1444,15 +1446,15 @@ Status getExecutorDistinct(OperationContext* txn, } // We drop the projection from the 'cq'. Unfortunately this is not trivial. - statusWithCQ = CanonicalQuery::canonicalize(collection->ns().ns(), query, whereCallback); - if (!statusWithCQ.isOK()) { - return statusWithCQ.getStatus(); + status = CanonicalQuery::canonicalize(collection->ns().ns(), query, &cq, whereCallback); + if (!status.isOK()) { + return status; } - cq = std::move(statusWithCQ.getValue()); + autoCq.reset(cq); - // Takes ownership of 'cq'. - return getExecutor(txn, collection, cq.release(), yieldPolicy, out); + // Takes ownership of 'autoCq'. + return getExecutor(txn, collection, autoCq.release(), yieldPolicy, out); } } // namespace mongo diff --git a/src/mongo/db/query/get_executor_test.cpp b/src/mongo/db/query/get_executor_test.cpp index 0e8740fa089..fdc04609df8 100644 --- a/src/mongo/db/query/get_executor_test.cpp +++ b/src/mongo/db/query/get_executor_test.cpp @@ -48,15 +48,14 @@ static const char* ns = "somebogusns"; /** * Utility functions to create a CanonicalQuery */ -unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, - const char* sortStr, - const char* projStr) { +CanonicalQuery* canonicalize(const char* queryStr, const char* sortStr, const char* projStr) { BSONObj queryObj = fromjson(queryStr); BSONObj sortObj = fromjson(sortStr); BSONObj projObj = fromjson(projStr); - auto statusWithCQ = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projObj); - ASSERT_OK(statusWithCQ.getStatus()); - return std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status result = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projObj, &cq); + ASSERT_OK(result); + return cq; } // diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp index 2bee0f5f10b..da15528d243 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -59,77 +59,90 @@ static const char* ns = "somebogusns"; /** * Utility functions to create a CanonicalQuery */ -unique_ptr<CanonicalQuery> canonicalize(const BSONObj& queryObj) { - auto statusWithCQ = CanonicalQuery::canonicalize(ns, queryObj); - ASSERT_OK(statusWithCQ.getStatus()); - return std::move(statusWithCQ.getValue()); +CanonicalQuery* canonicalize(const BSONObj& queryObj) { + CanonicalQuery* cq; + Status result = CanonicalQuery::canonicalize(ns, queryObj, &cq); + ASSERT_OK(result); + return cq; } -unique_ptr<CanonicalQuery> canonicalize(const char* queryStr) { +CanonicalQuery* canonicalize(const char* queryStr) { BSONObj queryObj = fromjson(queryStr); return canonicalize(queryObj); } -unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, - const char* sortStr, - const char* projStr) { +CanonicalQuery* canonicalize(const char* queryStr, const char* sortStr, const char* projStr) { BSONObj queryObj = fromjson(queryStr); BSONObj sortObj = fromjson(sortStr); BSONObj projObj = fromjson(projStr); - auto statusWithCQ = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projObj); - ASSERT_OK(statusWithCQ.getStatus()); - return std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status result = CanonicalQuery::canonicalize(ns, queryObj, sortObj, projObj, &cq); + ASSERT_OK(result); + return cq; } -unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, - const char* sortStr, - const char* projStr, - long long skip, - long long limit, - const char* hintStr, - const char* minStr, - const char* maxStr) { +CanonicalQuery* canonicalize(const char* queryStr, + const char* sortStr, + const char* projStr, + long long skip, + long long limit, + const char* hintStr, + const char* minStr, + const char* maxStr) { 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(ns, - queryObj, - sortObj, - projObj, - skip, - limit, - hintObj, - minObj, - maxObj, - false, // snapshot - false); // explain - ASSERT_OK(statusWithCQ.getStatus()); - return std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status result = CanonicalQuery::canonicalize(ns, + queryObj, + sortObj, + projObj, + skip, + limit, + hintObj, + minObj, + maxObj, + false, // snapshot + false, // explain + &cq); + ASSERT_OK(result); + return cq; } -unique_ptr<CanonicalQuery> canonicalize(const char* queryStr, - const char* sortStr, - const char* projStr, - long long skip, - long long limit, - const char* hintStr, - const char* minStr, - const char* maxStr, - bool snapshot, - bool explain) { +CanonicalQuery* canonicalize(const char* queryStr, + const char* sortStr, + const char* projStr, + long long skip, + long long limit, + const char* hintStr, + const char* minStr, + const char* maxStr, + bool snapshot, + bool explain) { 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( - ns, queryObj, sortObj, projObj, skip, limit, hintObj, minObj, maxObj, snapshot, explain); - ASSERT_OK(statusWithCQ.getStatus()); - return std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status result = CanonicalQuery::canonicalize(ns, + queryObj, + sortObj, + projObj, + skip, + limit, + hintObj, + minObj, + maxObj, + snapshot, + explain, + &cq); + ASSERT_OK(result); + return cq; } /** @@ -367,7 +380,7 @@ TEST(PlanCacheTest, AddEmptySolutions) { PlanCache planCache; unique_ptr<CanonicalQuery> cq(canonicalize("{a: 1}")); std::vector<QuerySolution*> solns; - unique_ptr<PlanRankingDecision> decision(createDecision(1U)); + std::unique_ptr<PlanRankingDecision> decision(createDecision(1U)); ASSERT_NOT_OK(planCache.add(*cq, solns, decision.get())); } @@ -454,11 +467,14 @@ TEST(PlanCacheTest, NotifyOfWriteOp) { class CachePlanSelectionTest : public mongo::unittest::Test { protected: void setUp() { + cq = NULL; params.options = QueryPlannerParams::INCLUDE_COLLSCAN; addIndex(BSON("_id" << 1)); } void tearDown() { + delete cq; + for (vector<QuerySolution*>::iterator it = solns.begin(); it != solns.end(); ++it) { delete *it; } @@ -540,6 +556,9 @@ protected: const BSONObj& maxObj, bool snapshot) { // Clean up any previous state from a call to runQueryFull + delete cq; + cq = NULL; + for (vector<QuerySolution*>::iterator it = solns.begin(); it != solns.end(); ++it) { delete *it; } @@ -547,19 +566,23 @@ protected: solns.clear(); - auto statusWithCQ = CanonicalQuery::canonicalize(ns, - query, - sort, - proj, - skip, - limit, - hint, - minObj, - maxObj, - snapshot, - false); // explain - ASSERT_OK(statusWithCQ.getStatus()); - Status s = QueryPlanner::plan(*statusWithCQ.getValue(), params, &solns); + Status s = CanonicalQuery::canonicalize(ns, + query, + sort, + proj, + skip, + limit, + hint, + minObj, + maxObj, + snapshot, + false, // explain + &cq); + if (!s.isOK()) { + cq = NULL; + } + ASSERT_OK(s); + s = QueryPlanner::plan(*cq, params, &solns); ASSERT_OK(s); } @@ -628,9 +651,11 @@ protected: const BSONObj& sort, const BSONObj& proj, const QuerySolution& soln) const { - auto statusWithCQ = CanonicalQuery::canonicalize(ns, query, sort, proj); - ASSERT_OK(statusWithCQ.getStatus()); - unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status s = CanonicalQuery::canonicalize(ns, query, sort, proj, &cq); + ASSERT_OK(s); + unique_ptr<CanonicalQuery> scopedCq(cq); + cq = NULL; // Create a CachedSolution the long way.. // QuerySolution -> PlanCacheEntry -> CachedSolution @@ -642,7 +667,7 @@ protected: CachedSolution cachedSoln(ck, entry); QuerySolution* out; - Status s = QueryPlanner::planFromCache(*scopedCq, params, cachedSoln, &out); + s = QueryPlanner::planFromCache(*scopedCq.get(), params, cachedSoln, &out); ASSERT_OK(s); return out; @@ -731,6 +756,7 @@ protected: static const PlanCacheKey ck; BSONObj queryObj; + CanonicalQuery* cq; QueryPlannerParams params; vector<QuerySolution*> solns; }; diff --git a/src/mongo/db/query/query_planner_test.cpp b/src/mongo/db/query/query_planner_test.cpp index 4768eed4312..2c0ca9167a5 100644 --- a/src/mongo/db/query/query_planner_test.cpp +++ b/src/mongo/db/query/query_planner_test.cpp @@ -3761,9 +3761,10 @@ TEST(BadInputTest, CacheDataFromTaggedTree) { // No relevant index matching the index tag. relevantIndices.push_back(IndexEntry(BSON("a" << 1))); - auto statusWithCQ = CanonicalQuery::canonicalize("ns", BSON("a" << 3)); - ASSERT_OK(statusWithCQ.getStatus()); - std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status cqStatus = CanonicalQuery::canonicalize("ns", BSON("a" << 3), &cq); + ASSERT_OK(cqStatus); + std::unique_ptr<CanonicalQuery> scopedCq(cq); scopedCq->root()->setTag(new IndexTag(1)); s = QueryPlanner::cacheDataFromTaggedTree(scopedCq->root(), relevantIndices, &indexTree); @@ -3772,9 +3773,10 @@ TEST(BadInputTest, CacheDataFromTaggedTree) { } TEST(BadInputTest, TagAccordingToCache) { - auto statusWithCQ = CanonicalQuery::canonicalize("ns", BSON("a" << 3)); - ASSERT_OK(statusWithCQ.getStatus()); - std::unique_ptr<CanonicalQuery> scopedCq = std::move(statusWithCQ.getValue()); + CanonicalQuery* cq; + Status cqStatus = CanonicalQuery::canonicalize("ns", BSON("a" << 3), &cq); + ASSERT_OK(cqStatus); + std::unique_ptr<CanonicalQuery> scopedCq(cq); std::unique_ptr<PlanCacheIndexTree> indexTree(new PlanCacheIndexTree()); indexTree->setIndexEntry(IndexEntry(BSON("a" << 1))); @@ -3799,9 +3801,9 @@ TEST(BadInputTest, TagAccordingToCache) { ASSERT_OK(s); // Regenerate canonical query in order to clear tags. - statusWithCQ = CanonicalQuery::canonicalize("ns", BSON("a" << 3)); - ASSERT_OK(statusWithCQ.getStatus()); - scopedCq = std::move(statusWithCQ.getValue()); + cqStatus = CanonicalQuery::canonicalize("ns", BSON("a" << 3), &cq); + ASSERT_OK(cqStatus); + scopedCq.reset(cq); // Mismatched tree topology. PlanCacheIndexTree* child = new PlanCacheIndexTree(); diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp index 496b6e37128..1b876c5296b 100644 --- a/src/mongo/db/query/query_planner_test_fixture.cpp +++ b/src/mongo/db/query/query_planner_test_fixture.cpp @@ -155,20 +155,25 @@ void QueryPlannerTest::runQueryFull(const BSONObj& query, // Clean up any previous state from a call to runQueryFull solns.clear(); - auto statusWithCQ = CanonicalQuery::canonicalize(ns, - query, - sort, - proj, - skip, - limit, - hint, - minObj, - maxObj, - snapshot, - false); // explain - ASSERT_OK(statusWithCQ.getStatus()); - - ASSERT_OK(QueryPlanner::plan(*statusWithCQ.getValue(), params, &solns.mutableVector())); + { + CanonicalQuery* rawCq; + Status s = CanonicalQuery::canonicalize(ns, + query, + sort, + proj, + skip, + limit, + hint, + minObj, + maxObj, + snapshot, + false, // explain + &rawCq); + ASSERT_OK(s); + cq.reset(rawCq); + } + + ASSERT_OK(QueryPlanner::plan(*cq, params, &solns.mutableVector())); } void QueryPlannerTest::runInvalidQuery(const BSONObj& query) { @@ -220,20 +225,25 @@ void QueryPlannerTest::runInvalidQueryFull(const BSONObj& query, bool snapshot) { solns.clear(); - auto statusWithCQ = CanonicalQuery::canonicalize(ns, - query, - sort, - proj, - skip, - limit, - hint, - minObj, - maxObj, - snapshot, - false); // explain - ASSERT_OK(statusWithCQ.getStatus()); - - Status s = QueryPlanner::plan(*statusWithCQ.getValue(), params, &solns.mutableVector()); + { + CanonicalQuery* rawCq; + Status s = CanonicalQuery::canonicalize(ns, + query, + sort, + proj, + skip, + limit, + hint, + minObj, + maxObj, + snapshot, + false, // explain + &rawCq); + ASSERT_OK(s); + cq.reset(rawCq); + } + + Status s = QueryPlanner::plan(*cq, params, &solns.mutableVector()); ASSERT_NOT_OK(s); } @@ -247,11 +257,13 @@ void QueryPlannerTest::runQueryAsCommand(const BSONObj& cmdObj) { std::unique_ptr<LiteParsedQuery> lpq( assertGet(LiteParsedQuery::makeFromFindCommand(nss, cmdObj, isExplain))); + CanonicalQuery* rawCq; WhereCallbackNoop whereCallback; - auto statusWithCQ = CanonicalQuery::canonicalize(lpq.release(), whereCallback); - ASSERT_OK(statusWithCQ.getStatus()); + Status canonStatus = CanonicalQuery::canonicalize(lpq.release(), &rawCq, whereCallback); + ASSERT_OK(canonStatus); + cq.reset(rawCq); - Status s = QueryPlanner::plan(*statusWithCQ.getValue(), params, &solns.mutableVector()); + Status s = QueryPlanner::plan(*cq, params, &solns.mutableVector()); ASSERT_OK(s); } |