diff options
-rw-r--r-- | buildscripts/resmokeconfig/suites/replica_sets_multi_stmt_txn_jscore_passthrough.yml | 3 | ||||
-rw-r--r-- | jstests/core/geo_near_tailable.js | 25 | ||||
-rw-r--r-- | src/mongo/db/query/canonical_query.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner.cpp | 2 |
4 files changed, 35 insertions, 1 deletions
diff --git a/buildscripts/resmokeconfig/suites/replica_sets_multi_stmt_txn_jscore_passthrough.yml b/buildscripts/resmokeconfig/suites/replica_sets_multi_stmt_txn_jscore_passthrough.yml index 7a3f0037aa4..5d66eb6200d 100644 --- a/buildscripts/resmokeconfig/suites/replica_sets_multi_stmt_txn_jscore_passthrough.yml +++ b/buildscripts/resmokeconfig/suites/replica_sets_multi_stmt_txn_jscore_passthrough.yml @@ -274,6 +274,9 @@ selector: - jstests/core/cursora.js - jstests/core/bench_test1.js + # It is illegal to open a tailable cursor in a transaction + - jstests/core/geo_near_tailable.js + exclude_with_any_tags: # "Cowardly refusing to override read concern of command: ..." - assumes_read_concern_unchanged diff --git a/jstests/core/geo_near_tailable.js b/jstests/core/geo_near_tailable.js new file mode 100644 index 00000000000..fd7b077f110 --- /dev/null +++ b/jstests/core/geo_near_tailable.js @@ -0,0 +1,25 @@ +// @tags: [requires_capped] +// +// Tests that combine $geoNear and tailable cursors. +// +(function() { + "use strict"; + + let cmdRes; + const collName = 'geo_near_tailable'; + const cappedCollName = 'geo_near_tailable_capped'; + + // Avoid using the drop() shell helper here in order to avoid "implicit collection recreation" + // which can happen when this test runs in certain passthroughs. For details, see + // "jstests/libs/override_methods/implicitly_shard_accessed_collections.js". + db.runCommand({drop: collName}); + db.runCommand({drop: cappedCollName}); + assert.commandWorked(db.createCollection(collName)); + assert.commandWorked(db.createCollection(cappedCollName, {capped: true, size: 10000})); + + // Error when tailable option is used with NEAR. + cmdRes = db.runCommand({find: collName, filter: {a: {$geoNear: [1, 2]}}, tailable: true}); + assert.commandFailedWithCode(cmdRes, ErrorCodes.BadValue); + cmdRes = db.runCommand({find: cappedCollName, filter: {a: {$geoNear: [1, 2]}}, tailable: true}); + assert.commandFailedWithCode(cmdRes, ErrorCodes.BadValue); +})(); diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp index 6d2337d92ef..3d15afafe6c 100644 --- a/src/mongo/db/query/canonical_query.cpp +++ b/src/mongo/db/query/canonical_query.cpp @@ -404,6 +404,12 @@ Status CanonicalQuery::isValid(MatchExpression* root, const QueryRequest& parsed return Status(ErrorCodes::BadValue, "text and tailable cursor not allowed in same query"); } + // NEAR and tailable are incompatible. + if (numGeoNear > 0 && parsed.isTailable()) { + return Status(ErrorCodes::BadValue, + "Tailable cursors and geo $near cannot be used together"); + } + // $natural sort order must agree with hint. if (sortNaturalElt) { if (!hintObj.isEmpty() && !hintNaturalElt) { diff --git a/src/mongo/db/query/query_planner.cpp b/src/mongo/db/query/query_planner.cpp index d91e92a6449..9236c52d206 100644 --- a/src/mongo/db/query/query_planner.cpp +++ b/src/mongo/db/query/query_planner.cpp @@ -544,7 +544,7 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan( // If the query requests a tailable cursor, the only solution is a collscan + filter with // tailable set on the collscan. if (isTailable) { - if (!QueryPlannerCommon::hasNode(query.root(), MatchExpression::GEO_NEAR) && canTableScan) { + if (canTableScan) { auto soln = buildCollscanSoln(query, isTailable, params); if (soln) { out.push_back(std::move(soln)); |