9
9
* Test covering behavior for queries over a multikey index.
10
10
*/
11
11
// For making assertions about explain output.
12
- import { getPlanStage , getWinningPlan , isIxscan , planHasStage } from "jstests/libs/analyze_plan.js" ;
12
+ import {
13
+ getOptimizer ,
14
+ getPlanStage ,
15
+ getWinningPlan ,
16
+ isCollscan ,
17
+ isIxscan ,
18
+ isIxscanMultikey ,
19
+ planHasStage
20
+ } from "jstests/libs/analyze_plan.js" ;
13
21
14
22
let coll = db . covered_multikey ;
15
23
coll . drop ( ) ;
@@ -21,7 +29,18 @@ assert.eq(1, coll.find({a: 1, b: 2}, {_id: 0, a: 1}).itcount());
21
29
assert . eq ( { a : 1 } , coll . findOne ( { a : 1 , b : 2 } , { _id : 0 , a : 1 } ) ) ;
22
30
let explainRes = coll . explain ( "queryPlanner" ) . find ( { a : 1 , b : 2 } , { _id : 0 , a : 1 } ) . finish ( ) ;
23
31
let winningPlan = getWinningPlan ( explainRes . queryPlanner ) ;
24
- assert ( isIxscan ( db , winningPlan ) ) ;
32
+ switch ( getOptimizer ( explainRes ) ) {
33
+ case "classic" : {
34
+ assert ( isIxscan ( db , winningPlan ) ) ;
35
+ break ;
36
+ }
37
+ case "CQF" : {
38
+ // TODO SERVER-77719: Ensure that the decision for using the scan lines up with CQF
39
+ // optimizer. M2: allow only collscans, M4: check bonsai behavior for index scan.
40
+ assert ( isCollscan ( db , winningPlan ) ) ;
41
+ break
42
+ }
43
+ }
25
44
assert ( ! planHasStage ( db , winningPlan , "FETCH" ) ) ;
26
45
27
46
coll . drop ( ) ;
@@ -47,10 +66,20 @@ assert.commandWorked(coll.createIndex({a: 1}));
47
66
assert . eq ( { a : [ ] } , coll . findOne ( { a : [ ] } , { _id : 0 , a : 1 } ) ) ;
48
67
explainRes = coll . explain ( "queryPlanner" ) . find ( { a : [ ] } , { _id : 0 , a : 1 } ) . finish ( ) ;
49
68
winningPlan = getWinningPlan ( explainRes . queryPlanner ) ;
50
- assert ( planHasStage ( db , winningPlan , "IXSCAN" ) ) ;
51
- assert ( planHasStage ( db , winningPlan , "FETCH" ) ) ;
52
- let ixscanStage = getPlanStage ( winningPlan , "IXSCAN" ) ;
53
- assert . eq ( true , ixscanStage . isMultiKey ) ;
69
+ switch ( getOptimizer ( explainRes ) ) {
70
+ case "classic" : {
71
+ assert ( isIxscan ( db , winningPlan ) ) ;
72
+ assert ( planHasStage ( db , winningPlan , "FETCH" ) ) ;
73
+ assert ( isIxscanMultikey ( winningPlan ) ) ;
74
+ break ;
75
+ }
76
+ case "CQF" : {
77
+ // TODO SERVER-77719: Ensure that the decision for using the scan lines up with CQF
78
+ // optimizer. M2: allow only collscans, M4: check bonsai behavior for index scan.
79
+ assert ( isCollscan ( db , winningPlan ) ) ;
80
+ break
81
+ }
82
+ }
54
83
55
84
// Verify that a query cannot be covered over a path which is multikey due to a single-element
56
85
// array.
@@ -60,10 +89,20 @@ assert.commandWorked(coll.createIndex({a: 1}));
60
89
assert . eq ( { a : [ 2 ] } , coll . findOne ( { a : 2 } , { _id : 0 , a : 1 } ) ) ;
61
90
explainRes = coll . explain ( "queryPlanner" ) . find ( { a : 2 } , { _id : 0 , a : 1 } ) . finish ( ) ;
62
91
winningPlan = getWinningPlan ( explainRes . queryPlanner ) ;
63
- assert ( planHasStage ( db , winningPlan , "IXSCAN" ) ) ;
64
- assert ( planHasStage ( db , winningPlan , "FETCH" ) ) ;
65
- ixscanStage = getPlanStage ( winningPlan , "IXSCAN" ) ;
66
- assert . eq ( true , ixscanStage . isMultiKey ) ;
92
+ switch ( getOptimizer ( explainRes ) ) {
93
+ case "classic" : {
94
+ assert ( isIxscan ( db , winningPlan ) ) ;
95
+ assert ( planHasStage ( db , winningPlan , "FETCH" ) ) ;
96
+ assert ( isIxscanMultikey ( winningPlan ) ) ;
97
+ break ;
98
+ }
99
+ case "CQF" : {
100
+ // TODO SERVER-77719: Ensure that the decision for using the scan lines up with CQF
101
+ // optimizer. M2: allow only collscans, M4: check bonsai behavior for index scan.
102
+ assert ( isCollscan ( db , winningPlan ) ) ;
103
+ break ;
104
+ }
105
+ }
67
106
68
107
// Verify that a query cannot be covered over a path which is multikey due to a single-element
69
108
// array, where the path is made multikey by an update rather than an insert.
@@ -74,43 +113,82 @@ assert.commandWorked(coll.update({}, {$set: {a: [2]}}));
74
113
assert . eq ( { a : [ 2 ] } , coll . findOne ( { a : 2 } , { _id : 0 , a : 1 } ) ) ;
75
114
explainRes = coll . explain ( "queryPlanner" ) . find ( { a : 2 } , { _id : 0 , a : 1 } ) . finish ( ) ;
76
115
winningPlan = getWinningPlan ( explainRes . queryPlanner ) ;
77
- assert ( planHasStage ( db , winningPlan , "IXSCAN" ) ) ;
78
- assert ( planHasStage ( db , winningPlan , "FETCH" ) ) ;
79
- ixscanStage = getPlanStage ( winningPlan , "IXSCAN" ) ;
80
- assert . eq ( true , ixscanStage . isMultiKey ) ;
116
+ switch ( getOptimizer ( explainRes ) ) {
117
+ case "classic" : {
118
+ assert ( isIxscan ( db , winningPlan ) ) ;
119
+ assert ( planHasStage ( db , winningPlan , "FETCH" ) ) ;
120
+ assert ( isIxscanMultikey ( winningPlan ) ) ;
121
+ break ;
122
+ }
123
+ case "CQF" : {
124
+ // TODO SERVER-77719: Ensure that the decision for using the scan lines up with CQF
125
+ // optimizer. M2: allow only collscans, M4: check bonsai behavior for index scan.
126
+ assert ( isCollscan ( db , winningPlan ) ) ;
127
+ break ;
128
+ }
129
+ }
81
130
82
131
// Verify that a trailing empty array makes a 2dsphere index multikey.
83
132
assert ( coll . drop ( ) ) ;
84
133
assert . commandWorked ( coll . createIndex ( { "a.b" : 1 , c : "2dsphere" } ) ) ;
85
134
assert . commandWorked ( coll . insert ( { a : { b : 1 } , c : { type : "Point" , coordinates : [ 0 , 0 ] } } ) ) ;
86
135
explainRes = coll . explain ( ) . find ( ) . hint ( { "a.b" : 1 , c : "2dsphere" } ) . finish ( ) ;
87
136
winningPlan = getWinningPlan ( explainRes . queryPlanner ) ;
88
- ixscanStage = getPlanStage ( winningPlan , "IXSCAN" ) ;
137
+ let optimizer = getOptimizer ( explainRes ) ;
138
+ let stages = { "classic" : "IXSCAN" , "CQF" : "IndexScan" } ;
139
+ let ixscanStage = getPlanStage ( winningPlan , stages [ optimizer ] ) ;
89
140
assert . neq ( null , ixscanStage ) ;
90
141
assert . eq ( false , ixscanStage . isMultiKey ) ;
91
142
assert . commandWorked ( coll . insert ( { a : { b : [ ] } , c : { type : "Point" , coordinates : [ 0 , 0 ] } } ) ) ;
92
143
explainRes = coll . explain ( ) . find ( ) . hint ( { "a.b" : 1 , c : "2dsphere" } ) . finish ( ) ;
93
144
winningPlan = getWinningPlan ( explainRes . queryPlanner ) ;
94
- ixscanStage = getPlanStage ( winningPlan , "IXSCAN" ) ;
95
- assert . neq ( null , ixscanStage ) ;
96
- assert . eq ( true , ixscanStage . isMultiKey ) ;
145
+ switch ( getOptimizer ( explainRes ) ) {
146
+ case "classic" : {
147
+ assert ( isIxscan ( db , winningPlan ) ) ;
148
+ assert ( isIxscanMultikey ( winningPlan ) ) ;
149
+ break ;
150
+ }
151
+ case "CQF" : {
152
+ // TODO SERVER-77719: Ensure that the decision for using the scan lines up with CQF
153
+ // optimizer. M2: allow only collscans, M4: check bonsai behavior for index scan.
154
+ break ;
155
+ }
156
+ }
97
157
98
158
// Verify that a mid-path empty array makes a 2dsphere index multikey.
99
159
assert ( coll . drop ( ) ) ;
100
160
assert . commandWorked ( coll . createIndex ( { "a.b" : 1 , c : "2dsphere" } ) ) ;
101
161
assert . commandWorked ( coll . insert ( { a : [ ] , c : { type : "Point" , coordinates : [ 0 , 0 ] } } ) ) ;
102
162
explainRes = coll . explain ( ) . find ( ) . hint ( { "a.b" : 1 , c : "2dsphere" } ) . finish ( ) ;
103
163
winningPlan = getWinningPlan ( explainRes . queryPlanner ) ;
104
- ixscanStage = getPlanStage ( winningPlan , "IXSCAN" ) ;
105
- assert . neq ( null , ixscanStage ) ;
106
- assert . eq ( true , ixscanStage . isMultiKey ) ;
164
+ switch ( getOptimizer ( explainRes ) ) {
165
+ case "classic" : {
166
+ assert ( isIxscan ( db , winningPlan ) ) ;
167
+ assert ( isIxscanMultikey ( winningPlan ) ) ;
168
+ break ;
169
+ }
170
+ case "CQF" : {
171
+ // TODO SERVER-77719: Ensure that the decision for using the scan lines up with CQF
172
+ // optimizer. M2: allow only collscans, M4: check bonsai behavior for index scan.
173
+ break ;
174
+ }
175
+ }
107
176
108
177
// Verify that a single-element array makes a 2dsphere index multikey.
109
178
assert ( coll . drop ( ) ) ;
110
179
assert . commandWorked ( coll . createIndex ( { "a.b" : 1 , c : "2dsphere" } ) ) ;
111
180
assert . commandWorked ( coll . insert ( { a : { b : [ 3 ] } , c : { type : "Point" , coordinates : [ 0 , 0 ] } } ) ) ;
112
181
explainRes = coll . explain ( ) . find ( ) . hint ( { "a.b" : 1 , c : "2dsphere" } ) . finish ( ) ;
113
182
winningPlan = getWinningPlan ( explainRes . queryPlanner ) ;
114
- ixscanStage = getPlanStage ( winningPlan , "IXSCAN" ) ;
115
- assert . neq ( null , ixscanStage ) ;
116
- assert . eq ( true , ixscanStage . isMultiKey ) ;
183
+ switch ( getOptimizer ( explainRes ) ) {
184
+ case "classic" : {
185
+ assert ( isIxscan ( db , winningPlan ) ) ;
186
+ assert ( isIxscanMultikey ( winningPlan ) ) ;
187
+ break ;
188
+ }
189
+ case "CQF" : {
190
+ // TODO SERVER-77719: Ensure that the decision for using the scan lines up with CQF
191
+ // optimizer. M2: allow only collscans, M4: check bonsai behavior for index scan.
192
+ break ;
193
+ }
194
+ }
0 commit comments