138 lines
6.4 KiB
JavaScript
138 lines
6.4 KiB
JavaScript
// Tests for the $in/sort/limit optimization combined with inequality bounds. SERVER-5777
|
|
|
|
t = db.jstests_sortm;
|
|
t.drop();
|
|
|
|
/** Assert that the 'a' and 'b' fields of the documents match. */
|
|
function assertMatch( expectedMatch, match ) {
|
|
assert.eq( expectedMatch.a, match.a );
|
|
assert.eq( expectedMatch.b, match.b );
|
|
}
|
|
|
|
/** Assert an expected document or array of documents matches the 'matches' array. */
|
|
function assertMatches( expectedMatches, matches ) {
|
|
if ( expectedMatches.length == null ) {
|
|
assertMatch( expectedMatches, matches[ 0 ] );
|
|
}
|
|
for( i = 0; i < expectedMatches.length; ++i ) {
|
|
assertMatch( expectedMatches[ i ], matches[ i ] );
|
|
}
|
|
}
|
|
|
|
/** Generate a cursor using global parameters. */
|
|
function find( query ) {
|
|
return t.find( query ).sort( _sort ).limit( _limit ).hint( _hint );
|
|
}
|
|
|
|
/** Check the expected matches and nscanned values for a query. */
|
|
function checkMatchesAndNscanned( expectedMatch, expectedNscanned, query ) {
|
|
result = find( query ).toArray();
|
|
assertMatches( expectedMatch, result );
|
|
explain = find( query ).explain();
|
|
assert.eq( expectedNscanned, explain.nscanned );
|
|
assert.eq( expectedMatch.length || 1, explain.n );
|
|
assert( explain.scanAndOrder );
|
|
}
|
|
|
|
/** Reset data, index, and _sort and _hint globals. */
|
|
function reset( sort, index ) {
|
|
t.drop();
|
|
t.save( { a:1, b:1 } );
|
|
t.save( { a:1, b:2 } );
|
|
t.save( { a:1, b:3 } );
|
|
t.save( { a:2, b:0 } );
|
|
t.save( { a:2, b:3 } );
|
|
t.save( { a:2, b:5 } );
|
|
t.ensureIndex( index );
|
|
_sort = sort;
|
|
_hint = index;
|
|
}
|
|
|
|
function checkForwardDirection( sort, index ) {
|
|
reset( sort, index );
|
|
|
|
_limit = -1;
|
|
|
|
// Lower bound checks.
|
|
checkMatchesAndNscanned( { a:2, b:0 }, 3 /* = 2 docs + 1 interval skip */,
|
|
{ a:{ $in:[ 1, 2 ] }, b:{ $gte:0 } } );
|
|
checkMatchesAndNscanned( { a:1, b:1 }, 4 /* = 2 docs + 2 interval skips */,
|
|
{ a:{ $in:[ 1, 2 ] }, b:{ $gt:0 } } );
|
|
checkMatchesAndNscanned( { a:1, b:1 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $gte:1 } } );
|
|
checkMatchesAndNscanned( { a:1, b:2 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $gt:1 } } );
|
|
checkMatchesAndNscanned( { a:1, b:2 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $gte:2 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $gt:2 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $gte:3 } } );
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $gt:3 } } );
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $gte:4 } } );
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 2 /* = 1 doc + 1 interval skip */,
|
|
{ a:{ $in:[ 1, 2 ] }, b:{ $gt:4 } } );
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $gte:5 } } );
|
|
|
|
// Upper bound checks.
|
|
checkMatchesAndNscanned( { a:2, b:0 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $lte:0 } } );
|
|
checkMatchesAndNscanned( { a:2, b:0 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $lt:1 } } );
|
|
checkMatchesAndNscanned( { a:2, b:0 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $lte:1 } } );
|
|
checkMatchesAndNscanned( { a:2, b:0 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $lt:3 } } );
|
|
|
|
// Lower and upper bounds checks.
|
|
checkMatchesAndNscanned( { a:2, b:0 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $gte:0, $lte:0 } } );
|
|
checkMatchesAndNscanned( { a:2, b:0 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $gte:0, $lt:1 } } );
|
|
checkMatchesAndNscanned( { a:2, b:0 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $gte:0, $lte:1 } } );
|
|
checkMatchesAndNscanned( { a:1, b:1 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $gt:0, $lte:1 } } );
|
|
checkMatchesAndNscanned( { a:1, b:2 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $gte:2, $lt:3 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $gte:2.5, $lte:3 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $gt:2.5, $lte:3 } } );
|
|
|
|
// Limit is -2.
|
|
_limit = -2;
|
|
checkMatchesAndNscanned( [ { a:2, b:0 }, { a:1, b:1 } ], 5,
|
|
{ a:{ $in:[ 1, 2 ] }, b:{ $gte:0 } } );
|
|
checkMatchesAndNscanned( [ { a:1, b:2 }, { a:1, b:3 } ], 5,
|
|
{ a:{ $in:[ 1, 2 ] }, b:{ $gt:1 } } );
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $gt:4 } } );
|
|
|
|
// With an additional document between the $in values.
|
|
t.save( { a:1.5, b:3 } );
|
|
checkMatchesAndNscanned( [ { a:2, b:0 }, { a:1, b:1 } ], 6,
|
|
{ a:{ $in:[ 1, 2 ] }, b:{ $gte:0 } } );
|
|
}
|
|
|
|
// Basic test with an index suffix order.
|
|
checkForwardDirection( { b:1 }, { a:1, b:1 } );
|
|
// With an additonal index field.
|
|
checkForwardDirection( { b:1 }, { a:1, b:1, c:1 } );
|
|
// With an additonal reverse direction index field.
|
|
checkForwardDirection( { b:1 }, { a:1, b:1, c:-1 } );
|
|
// With an additonal ordered index field.
|
|
checkForwardDirection( { b:1, c:1 }, { a:1, b:1, c:1 } );
|
|
// With an additonal reverse direction ordered index field.
|
|
checkForwardDirection( { b:1, c:-1 }, { a:1, b:1, c:-1 } );
|
|
|
|
function checkReverseDirection( sort, index ) {
|
|
reset( sort, index );
|
|
_limit = -1;
|
|
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $gte:0 } } );
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $gte:5 } } );
|
|
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $lte:5 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $lt:5 } } );
|
|
checkMatchesAndNscanned( { a:1, b:2 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $lt:3 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $lt:3.1 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $lt:3.5 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $lte:3 } } );
|
|
|
|
checkMatchesAndNscanned( { a:2, b:5 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $lte:5, $gte:5 } } );
|
|
checkMatchesAndNscanned( { a:1, b:1 }, 2, { a:{ $in:[ 1, 2 ] }, b:{ $lt:2, $gte:1 } } );
|
|
checkMatchesAndNscanned( { a:1, b:2 }, 3, { a:{ $in:[ 1, 2 ] }, b:{ $lt:3, $gt:1 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $lt:3.5, $gte:3 } } );
|
|
checkMatchesAndNscanned( { a:1, b:3 }, 4, { a:{ $in:[ 1, 2 ] }, b:{ $lte:3, $gt:0 } } );
|
|
}
|
|
|
|
// With a descending order index.
|
|
checkReverseDirection( { b:-1 }, { a:1, b:-1 } );
|
|
checkReverseDirection( { b:-1 }, { a:1, b:-1, c:1 } );
|
|
checkReverseDirection( { b:-1 }, { a:1, b:-1, c:-1 } );
|
|
checkReverseDirection( { b:-1, c:1 }, { a:1, b:-1, c:1 } );
|
|
checkReverseDirection( { b:-1, c:-1 }, { a:1, b:-1, c:-1 } );
|