summaryrefslogtreecommitdiff
path: root/jstests/noPassthroughWithMongod/plan_cache_not_in_regex.js
blob: 4406843eb8396827b3e04aa388d1ba09f56e3aa2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
 * Tests that a $not-$in-$regex query, which cannot be supported by an index, cannot incorrectly
 * hijack the cached plan for an earlier $not-$in query.
 */
(function() {
"use strict";

load('jstests/libs/analyze_plan.js');  // For isCollScan and getPlanCacheKeyFromShape.

const coll = db.plan_cache_not_in_regex;
coll.drop();

// Helper function which obtains the cached plan, if any, for a given query shape.
function getPlanForCacheEntry(query, proj, sort) {
    const keyHash = getPlanCacheKeyFromShape(
        {query: query, projection: proj, sort: sort, collection: coll, db: db});

    const cursor = coll.aggregate([{$planCacheStats: {}}, {$match: {planCacheKey: keyHash}}]);
    const entryStats = cursor.toArray();
    assert.eq(entryStats.length, 1, `Expected one cached plan, found: ${tojson(entryStats)}`);
    return entryStats.shift();
}

// Insert a document containing a field 'a', and create two indexes that can support queries on
// this field. This is to ensure that the plan we choose will be cached, since if only a single
// index is available, the solution will not be cached.
assert.commandWorked(coll.insert({a: "foo"}));
assert.commandWorked(coll.createIndex({a: 1}));
assert.commandWorked(coll.createIndex({a: 1, b: 1}));

// Repeat the test for query, query with projection, and query with projection and sort.
for (let [proj, sort] of [[{}, {}], [{_id: 0, a: 1}, {}], [{_id: 0, a: 1}, {a: 1}]]) {
    // Perform a plain $not-$in query on 'a' and confirm that the plan is cached.
    const queryShape = {a: {$not: {$in: [32, 33]}}};
    assert.eq(1, coll.find(queryShape, proj).sort(sort).itcount());
    let cacheEntry = getPlanForCacheEntry(queryShape, proj, sort);
    assert(cacheEntry);

    // If the cached plan is inactive, perform the same query to activate it.
    if (cacheEntry.isActive === false) {
        assert.eq(1, coll.find(queryShape, proj).sort(sort).itcount());
        cacheEntry = getPlanForCacheEntry(queryShape, proj, sort);
        assert(cacheEntry);
        assert(cacheEntry.isActive);
    }

    // Now perform a $not-$in-$regex query, confirm that it obtains the correct results, and
    // that it used a COLLSCAN rather than planning from the cache.
    const explainOutput =
        assert.commandWorked(coll.find({a: {$not: {$in: [34, /bar/]}}}).explain("executionStats"));
    assert(isCollscan(coll.getDB(), getWinningPlan(explainOutput.queryPlanner)));
    assert.eq(1, explainOutput.executionStats.nReturned);

    // Flush the plan cache before the next iteration.
    coll.getPlanCache().clear();
}
})();