summaryrefslogtreecommitdiff
path: root/jstests/core/index_filter_collation.js
blob: d6fa0daaa734f941a301317a25e3df929db40a26 (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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/**
 * Test that index filters are applied with the correct collation.
 * @tags: [
 *   # This test attempts to perform queries with plan cache filters set up. The former operation
 *   # may be routed to a secondary in the replica set, whereas the latter must be routed to the
 *   # primary.
 *   assumes_read_preference_unchanged,
 *   does_not_support_stepdowns,
 *   # Needs to create a collection with a collation.
 *   assumes_no_implicit_collection_creation_after_drop
 * ]
 */
(function() {
"use strict";

load("jstests/libs/analyze_plan.js");  // For getPlanStages.

const collName = "index_filter_collation";
const coll = db[collName];

const caseInsensitive = {
    locale: "fr",
    strength: 2
};
coll.drop();
assert.commandWorked(db.createCollection(collName, {collation: caseInsensitive}));

function checkIndexFilterSet(explain, shouldBeSet) {
    if (explain.queryPlanner.winningPlan.shards) {
        for (let shard of explain.queryPlanner.winningPlan.shards) {
            assert.eq(shard.indexFilterSet, shouldBeSet);
        }
    } else {
        assert.eq(explain.queryPlanner.indexFilterSet, shouldBeSet);
    }
}

// Now create an index filter on a query with no collation specified.
assert.commandWorked(coll.createIndexes([{x: 1}, {x: 1, y: 1}]));
assert.commandWorked(
    db.runCommand({planCacheSetFilter: collName, query: {"x": 3}, indexes: [{x: 1, y: 1}]}));

const listFilters = assert.commandWorked(db.runCommand({planCacheListFilters: collName}));
assert.eq(listFilters.filters.length, 1);
assert.eq(listFilters.filters[0].query, {x: 3});
assert.eq(listFilters.filters[0].indexes, [{x: 1, y: 1}]);

// Create an index filter on a query with the default collation specified.
assert.commandWorked(db.runCommand({
    planCacheSetFilter: collName,
    query: {"x": 3},
    collation: caseInsensitive,
    indexes: [{x: 1}]
}));

// Although these two queries would run with the same collation, they have different "shapes"
// so we expect there to be two index filters present.
let res = assert.commandWorked(db.runCommand({planCacheListFilters: collName}));
assert.eq(res.filters.length, 2);

// One of the filters should only be applied to queries with the "fr" collation
// and use the {x: 1} index.
assert(res.filters.some((filter) => filter.hasOwnProperty("collation") &&
                            filter.collation.locale === "fr" &&
                            friendlyEqual(filter.indexes, [{x: 1}])));

// The other should not have any collation, and allow the index {x: 1, y: 1}.
assert(res.filters.some((filter) => !filter.hasOwnProperty("collation") &&
                            friendlyEqual(filter.indexes, [{x: 1, y: 1}])));

function assertIsIxScanOnIndex(winningPlan, keyPattern) {
    const ixScans = getPlanStages(winningPlan, "IXSCAN");
    assert.gt(ixScans.length, 0);
    assert.eq(ixScans[0].keyPattern, keyPattern);
}

// Run the queries and be sure the correct indexes are used.
let explain = coll.find({x: 3}).explain();
checkIndexFilterSet(explain, true);
assertIsIxScanOnIndex(explain.queryPlanner.winningPlan, {x: 1, y: 1});

// Run the queries and be sure the correct indexes are used.
explain = coll.find({x: 3}).collation(caseInsensitive).explain();
checkIndexFilterSet(explain, true);
assertIsIxScanOnIndex(explain.queryPlanner.winningPlan, {x: 1});
})();