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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
/**
* Tests passing hint to the delete command:
* - A bad argument to the hint option should raise an error.
* - The hint option should support both the name of the index, and the object spec of the
* index.
*
* @tags: [
* assumes_unsharded_collection,
* requires_non_retryable_writes,
* ]
*/
(function() {
"use strict";
load("jstests/libs/analyze_plan.js");
function assertCommandUsesIndex(command, expectedHintKeyPattern) {
const out = assert.commandWorked(coll.runCommand({explain: command}));
const planStage = getPlanStage(out, "IXSCAN");
assert.neq(null, planStage);
assert.eq(planStage.keyPattern, expectedHintKeyPattern, tojson(planStage));
}
const coll = db.jstests_delete_hint;
function normalIndexTest() {
// Hint using a key pattern.
coll.drop();
assert.commandWorked(coll.insert({x: 1, y: 1}));
assert.commandWorked(coll.createIndex({x: 1}));
assert.commandWorked(coll.createIndex({y: -1}));
// Hint using index key pattern.
let deleteCmd = {delete: coll.getName(), deletes: [{q: {x: 1}, limit: 1, hint: {x: 1}}]};
assertCommandUsesIndex(deleteCmd, {x: 1});
// Hint using an index name.
deleteCmd = {delete: coll.getName(), deletes: [{q: {x: 1}, limit: 1, hint: 'y_-1'}]};
assertCommandUsesIndex(deleteCmd, {y: -1});
// Passing a hint should not use the idhack fast-path.
deleteCmd = {delete: coll.getName(), deletes: [{q: {_id: 1}, limit: 1, hint: 'y_-1'}]};
assertCommandUsesIndex(deleteCmd, {y: -1});
}
function sparseIndexTest() {
// Create a sparse index with 2 documents.
coll.drop();
assert.commandWorked(coll.insert([{x: 1}, {x: 1}, {x: 1, s: 0}, {x: 1, s: 0}]));
assert.commandWorked(coll.createIndex({x: 1}));
assert.commandWorked(coll.createIndex({s: 1}, {sparse: true}));
// Hint should be respected, even on incomplete indexes.
let deleteCmd = {delete: coll.getName(), deletes: [{q: {_id: 1}, limit: 1, hint: {s: 1}}]};
assertCommandUsesIndex(deleteCmd, {s: 1});
// Delete hinting a sparse index deletes only the document in the sparse index.
deleteCmd = {delete: coll.getName(), deletes: [{q: {}, limit: 0, hint: {s: 1}}]};
let res = assert.commandWorked(coll.runCommand(deleteCmd));
assert.eq(2, res.n);
}
function shellHelpersTest() {
coll.drop();
assert.commandWorked(coll.insert([{x: 1}, {x: 1, s: 0}, {x: 1, s: 0}]));
assert.commandWorked(coll.createIndex({x: 1}));
assert.commandWorked(coll.createIndex({s: 1}, {sparse: true}));
// Test shell helpers using a hinted sparse index should only delete documents that exist in
// the sparse index.
let res = coll.deleteOne({x: 1}, {hint: {s: 1}});
assert.eq(res.deletedCount, 1);
// Test bulk writes.
let bulk = coll.initializeUnorderedBulkOp();
bulk.find({x: 1}).hint({s: 1}).remove();
res = bulk.execute();
assert.eq(res.nRemoved, 2);
bulk = coll.initializeUnorderedBulkOp();
bulk.find({x: 2}).hint({s: 1}).removeOne();
res = bulk.execute();
assert.eq(res.nRemoved, 0);
assert.commandWorked(coll.insert([{x: 0}, {x: 1, s: 0}, {x: 1, s: 0}, {x: 1, s: 0}]));
res = coll.bulkWrite([{deleteOne: {filter: {x: 1}, hint: {s: 1}}}]);
assert.eq(res.deletedCount, 1);
res = coll.bulkWrite([{
deleteMany: {
filter: {x: 1},
hint: {s: 1},
}
}]);
assert.eq(res.deletedCount, 2);
}
function failedHintTest() {
coll.drop();
assert.commandWorked(coll.insert({x: 1}));
assert.commandWorked(coll.createIndex({x: 1}));
// Command should fail with incorrectly formatted hints.
let deleteCmd = {delete: coll.getName(), deletes: [{q: {_id: 1}, limit: 1, hint: 1}]};
assert.commandFailedWithCode(coll.runCommand(deleteCmd), ErrorCodes.FailedToParse);
deleteCmd = {delete: coll.getName(), deletes: [{q: {_id: 1}, limit: 1, hint: true}]};
assert.commandFailedWithCode(coll.runCommand(deleteCmd), ErrorCodes.FailedToParse);
// Command should fail with hints to non-existent indexes.
deleteCmd = {delete: coll.getName(), deletes: [{q: {_id: 1}, limit: 1, hint: {badHint: 1}}]};
assert.commandFailedWithCode(coll.runCommand(deleteCmd), ErrorCodes.BadValue);
}
normalIndexTest();
sparseIndexTest();
shellHelpersTest();
failedHintTest();
})();
|