diff options
author | Adityavardhan Agrawal <adi.agrawal@mongodb.com> | 2023-05-11 13:54:16 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-05-11 14:34:01 +0000 |
commit | bb7468fd0c2f7f2e3bdd4561d2c906f9ebb007ab (patch) | |
tree | e722d195cdbf05cd41131c869555d9548b2e10b5 | |
parent | dc864de3212e83b2d2a7553b6d9a975c523305e6 (diff) | |
download | mongo-bb7468fd0c2f7f2e3bdd4561d2c906f9ebb007ab.tar.gz |
SERVER-76944: Correctly return bool in the prepSubNodes function in plan_enumerator.cpp
-rw-r--r-- | jstests/noPassthrough/no_query_plan_unindexed_child_with_text.js | 54 | ||||
-rw-r--r-- | src/mongo/db/query/plan_enumerator.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/query/plan_enumerator.h | 3 |
3 files changed, 62 insertions, 4 deletions
diff --git a/jstests/noPassthrough/no_query_plan_unindexed_child_with_text.js b/jstests/noPassthrough/no_query_plan_unindexed_child_with_text.js new file mode 100644 index 00000000000..4e298a3a9a0 --- /dev/null +++ b/jstests/noPassthrough/no_query_plan_unindexed_child_with_text.js @@ -0,0 +1,54 @@ +/** + * Tests that query planning fails when an $or has a text child along with an unindexed child. + * + * @tags: [ + * requires_fcv_71, + * ] + */ +(function() { +"use strict"; + +const conn = MongoRunner.runMongod(); +assert.neq(null, conn, "mongod was unable to start up"); + +const db = conn.getDB("test"); +const coll = db.getCollection(jsTestName()); +coll.drop(); + +assert.commandWorked(coll.insert({x: 1})); + +assert.commandWorked(coll.createIndex({"$**": "text"})); + +assert.commandWorked(coll.createIndex({"indexed": 1})); + +const pipeline = [ + { + $match: { + $and: [{ + $and: [ + {"indexed": {$eq: 1}}, + { + $or: [ + {$text: {$search: "abcd"}}, + {"unindexed": {$eq: 1}}, + ] + }, + ] + }] + } + }, +]; + +assert.throwsWithCode(function() { + coll.aggregate(pipeline); +}, ErrorCodes.NoQueryExecutionPlans); + +assert.commandWorked( + db.adminCommand({configureFailPoint: "disableMatchExpressionOptimization", mode: "alwaysOn"})); + +assert.throwsWithCode(function() { + coll.aggregate(pipeline); +}, ErrorCodes.NoQueryExecutionPlans); + +MongoRunner.stopMongod(conn); +})(); diff --git a/src/mongo/db/query/plan_enumerator.cpp b/src/mongo/db/query/plan_enumerator.cpp index 4db9ca8b693..ac79474cbb8 100644 --- a/src/mongo/db/query/plan_enumerator.cpp +++ b/src/mongo/db/query/plan_enumerator.cpp @@ -1331,7 +1331,6 @@ void PlanEnumerator::getIndexedPreds(MatchExpression* node, } bool PlanEnumerator::prepSubNodes(MatchExpression* node, - PrepMemoContext context, vector<MemoID>* subnodesOut, vector<MemoID>* mandatorySubnodes) { @@ -1366,9 +1365,13 @@ bool PlanEnumerator::prepSubNodes(MatchExpression* node, childContext.elemMatchExpr = child; childContext.outsidePreds = context.outsidePreds; markTraversedThroughElemMatchObj(&childContext); - prepSubNodes(child, childContext, subnodesOut, mandatorySubnodes); + if (!prepSubNodes(child, childContext, subnodesOut, mandatorySubnodes)) { + return false; + } } else if (MatchExpression::AND == child->matchType()) { - prepSubNodes(child, context, subnodesOut, mandatorySubnodes); + if (!prepSubNodes(child, context, subnodesOut, mandatorySubnodes)) { + return false; + } } } return true; diff --git a/src/mongo/db/query/plan_enumerator.h b/src/mongo/db/query/plan_enumerator.h index 9eabd5b09b9..db7206a608e 100644 --- a/src/mongo/db/query/plan_enumerator.h +++ b/src/mongo/db/query/plan_enumerator.h @@ -338,7 +338,8 @@ private: * Recursively traverse 'node', with OR nodes as the base case. The OR nodes are not * explored--instead we call prepMemo() on the OR subnode, and add its assignment to the output. * Subnodes are "mandatory" if they *must* use an index (TEXT and GEO). - * Returns a boolean indicating whether all mandatory subnodes can be indexed. + * Returns a boolean indicating whether all mandatory subnodes can be indexed and returns false + * to stop enumerating alternatives for an indexed OR. */ bool prepSubNodes(MatchExpression* node, PrepMemoContext context, |