diff options
Diffstat (limited to 'jstests/aggregation/bugs/skip_limit_overflow.js')
-rw-r--r-- | jstests/aggregation/bugs/skip_limit_overflow.js | 100 |
1 files changed, 64 insertions, 36 deletions
diff --git a/jstests/aggregation/bugs/skip_limit_overflow.js b/jstests/aggregation/bugs/skip_limit_overflow.js index 597518d069b..0b1fa027a48 100644 --- a/jstests/aggregation/bugs/skip_limit_overflow.js +++ b/jstests/aggregation/bugs/skip_limit_overflow.js @@ -19,10 +19,6 @@ assert.commandWorked(db.runCommand({create: coll.getName()})); function testPipeline(pipeline, expectedResult, optimizedAwayStages) { const explainOutput = coll.explain().aggregate(pipeline); - assert(explainOutput.hasOwnProperty("stages"), - "Expected pipeline " + tojsononeline(pipeline) + - " to use an aggregation framework in the explain output: " + tojson(explainOutput)); - if (optimizedAwayStages) { optimizedAwayStages.forEach( (stage) => @@ -31,17 +27,21 @@ function testPipeline(pipeline, expectedResult, optimizedAwayStages) { stage + " stage in the explain output: " + tojson(explainOutput))); } - for (let path in expectedResult) { - const subPaths = path.split("."); - const stageName = subPaths[0]; + for (const stageName in expectedResult) { + const path = expectedResult[stageName].path; + const expectedValue = expectedResult[stageName].expectedValue; + const stages = getAggPlanStages(explainOutput, stageName); assert(stages !== null, "Expected pipeline " + tojsononeline(pipeline) + " to include a " + stageName + " stage in the explain output: " + tojson(explainOutput)); - assert(stages.length == expectedResult[path].length, - "Expected pipeline " + tojsononeline(pipeline) + " to include " + - expectedResult[path].length + stageName + - " stages in the explain output: " + tojson(explainOutput)); + assert.eq(stages.length, + expectedValue.length, + "Expected pipeline " + tojsononeline(pipeline) + " to include " + + expectedValue.length + " " + stageName + + " stages in the explain output: " + tojson(explainOutput)); + + const subPaths = path.split("."); assert.eq( stages.reduce( (res, stage) => { @@ -49,7 +49,7 @@ function testPipeline(pipeline, expectedResult, optimizedAwayStages) { return res; }, []), - expectedResult[path], + expectedValue, "Stage: " + stageName + ", path: " + path + ", explain: " + tojson(explainOutput)); } @@ -60,35 +60,46 @@ function testPipeline(pipeline, expectedResult, optimizedAwayStages) { // Case where overflow of limit + skip prevents limit stage from being absorbed. Values // are specified as integrals > MAX_LONG. Note that we cannot specify this huge value as // a NumberLong, as we get a number conversion error (even if it's passed as a string). -testPipeline([{$sort: {x: -1}}, {$skip: 18446744073709552000}, {$limit: 6}], - {"$limit": [NumberLong(6)], "$skip": [NumberLong("9223372036854775807")]}); -testPipeline([{$sort: {x: -1}}, {$skip: 6}, {$limit: 18446744073709552000}], - {"$limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(6)]}); +testPipeline([{$sort: {x: -1}}, {$skip: 18446744073709552000}, {$limit: 6}], { + $limit: {path: "$limit", expectedValue: [NumberLong(6)]}, + $skip: {path: "$skip", expectedValue: [NumberLong("9223372036854775807")]} +}); +testPipeline([{$sort: {x: -1}}, {$skip: 6}, {$limit: 18446744073709552000}], { + $limit: {path: "$limit", expectedValue: [NumberLong("9223372036854775807")]}, + $skip: {path: "$skip", expectedValue: [NumberLong(6)]} +}); // Case where overflow of limit + skip prevents limit stage from being absorbed. One of the // values == MAX_LONG, another one is 1. -testPipeline([{$sort: {x: -1}}, {$skip: NumberLong("9223372036854775807")}, {$limit: 1}], - {"$limit": [NumberLong(1)], "$skip": [NumberLong("9223372036854775807")]}); -testPipeline([{$sort: {x: -1}}, {$skip: 1}, {$limit: NumberLong("9223372036854775807")}], - {"$limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(1)]}); +testPipeline([{$sort: {x: -1}}, {$skip: NumberLong("9223372036854775807")}, {$limit: 1}], { + $limit: {path: "$limit", expectedValue: [NumberLong(1)]}, + $skip: {path: "$skip", expectedValue: [NumberLong("9223372036854775807")]} +}); +testPipeline([{$sort: {x: -1}}, {$skip: 1}, {$limit: NumberLong("9223372036854775807")}], { + $limit: {path: "$limit", expectedValue: [NumberLong("9223372036854775807")]}, + $skip: {path: "$skip", expectedValue: [NumberLong(1)]} +}); // Case where limit + skip do not overflow. Limit == MAX_LONG and skip is 0. Should be able to // absorb the limit and skip stages. // Note that we cannot specify limit == 0, so we expect an error in this case. testPipeline([{$sort: {x: -1}}, {$skip: 0}, {$limit: NumberLong("9223372036854775807")}], - {"$sort.limit": [NumberLong("9223372036854775807")]}, + {SORT: {path: "limitAmount", expectedValue: [NumberLong("9223372036854775807")]}}, ["$skip", "$limit"]); // Case where limit + skip do not overflow. One value is MAX_LONG - 1 and another one is 1. // Should be able to absorb the limit stage. testPipeline([{$sort: {x: -1}}, {$skip: NumberLong("9223372036854775806")}, {$limit: 1}], { - "$sort.limit": [NumberLong("9223372036854775807")], - "$skip": [NumberLong("9223372036854775806")] + SORT: {path: "limitAmount", expectedValue: [NumberLong("9223372036854775807")]}, + $skip: {path: "$skip", expectedValue: [NumberLong("9223372036854775806")]} }, ["$limit"]); testPipeline([{$sort: {x: -1}}, {$skip: 1}, {$limit: NumberLong("9223372036854775806")}], - {"$sort.limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(1)]}, + { + SORT: {path: "limitAmount", expectedValue: [NumberLong("9223372036854775807")]}, + $skip: {path: "$skip", expectedValue: [NumberLong(1)]} + }, ["$limit"]); // Case where the first $limit can be pushed down, but the second overflows and thus remains in @@ -101,10 +112,13 @@ testPipeline( {$skip: 10}, {$limit: 1} ], - {"$sort.limit": [NumberLong("9223372036854775807")], "$limit": [NumberLong(1)]}); + { + SORT: {path: "limitAmount", expectedValue: [NumberLong("9223372036854775807")]}, + $limit: {path: "$limit", expectedValue: [NumberLong(1)]} + }); -// Case with multiple $limit and $skip stages where the second $limit ends up being the smallest. -// There is no overflow in this case. +// Case with multiple $limit and $skip stages where the second $limit ends up being the +// smallest. There is no overflow in this case. testPipeline( [ {$sort: {x: -1}}, @@ -114,37 +128,51 @@ testPipeline( {$limit: 1} ], { - "$sort.limit": [NumberLong("9223372036854775804")], - "$skip": [NumberLong("9223372036854775803")] + SORT: {path: "limitAmount", expectedValue: [NumberLong("9223372036854775804")]}, + $skip: {path: "$skip", expectedValue: [NumberLong("9223372036854775803")]} }); // Case where limit + skip do not overflow. Both values are < MAX_LONG. testPipeline([{$sort: {x: -1}}, {$skip: 674761616283}, {$limit: 35361718}], - {"$sort.limit": [NumberLong(674796978001)], "$skip": [NumberLong(674761616283)]}, + { + SORT: {path: "limitAmount", expectedValue: [NumberLong(674796978001)]}, + $skip: {path: "$skip", expectedValue: [NumberLong(674761616283)]} + }, ["$limit"]); testPipeline([{$sort: {x: -1}}, {$skip: 35361718}, {$limit: 674761616283}], - {"$sort.limit": [NumberLong(674796978001)], "$skip": [NumberLong(35361718)]}, + { + SORT: {path: "limitAmount", expectedValue: [NumberLong(674796978001)]}, + $skip: {path: "$skip", expectedValue: [NumberLong(35361718)]} + }, ["$limit"]); // Case where where overflow of limit + skip + skip prevents limit stage from being absorbed. // One skip == MAX_LONG - 1, another one is 1. Should merge two skip stages into one. testPipeline( [{$sort: {x: -1}}, {$skip: 1}, {$skip: NumberLong("9223372036854775806")}, {$limit: 1}], - {"$limit": [NumberLong(1)], "$skip": [NumberLong("9223372036854775807")]}); + { + $limit: {path: "$limit", expectedValue: [NumberLong(1)]}, + $skip: {path: "$skip", expectedValue: [NumberLong("9223372036854775807")]} + }, + ["$sort"]); // Case where where overflow of limit + skip + skip prevents limit stage from being absorbed. // One skip == MAX_LONG, another one is 1. Should not absorb or merge any stages. testPipeline( [{$sort: {x: -1}}, {$skip: 1}, {$skip: NumberLong("9223372036854775807")}, {$limit: 1}], - {"$limit": [NumberLong(1)], "$skip": [NumberLong(1), NumberLong("9223372036854775807")]}); + { + $limit: {path: "$limit", expectedValue: [NumberLong(1)]}, + $skip: {path: "$skip", expectedValue: [NumberLong(1), NumberLong("9223372036854775807")]} + }, + ["$sort"]); // Case where sample size is > MAX_LONG. testPipeline([{$sample: {size: 18446744073709552000}}], - {"$sample.size": [NumberLong("9223372036854775807")]}); + {$sample: {path: "$sample.size", expectedValue: [NumberLong("9223372036854775807")]}}); // Case where sample size is == MAX_LONG. testPipeline([{$sample: {size: NumberLong("9223372036854775807")}}], - {"$sample.size": [NumberLong("9223372036854775807")]}); + {$sample: {path: "$sample.size", expectedValue: [NumberLong("9223372036854775807")]}}); // Case where sample size is == MAX_LONG - 1. testPipeline([{$sample: {size: NumberLong("9223372036854775806")}}], - {"$sample.size": [NumberLong("9223372036854775806")]}); + {$sample: {path: "$sample.size", expectedValue: [NumberLong("9223372036854775806")]}}); })(); |