diff options
author | Charlie Swanson <charlie.swanson@mongodb.com> | 2022-11-10 21:01:57 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-11-10 21:32:17 +0000 |
commit | f32fceffb99d547f978528c17a1a4c0069a3c298 (patch) | |
tree | 6485acdaef650eedb4325721a0dc5da1553c70ad | |
parent | 466f27b8c0b46216c282f7c62d9cfe5d2a876806 (diff) | |
download | mongo-f32fceffb99d547f978528c17a1a4c0069a3c298.tar.gz |
SERVER-68569 Use hinting to update projection_semantics.js
-rw-r--r-- | jstests/core/projection_semantics.js | 104 |
1 files changed, 57 insertions, 47 deletions
diff --git a/jstests/core/projection_semantics.js b/jstests/core/projection_semantics.js index fa22170d351..50fd38d4d45 100644 --- a/jstests/core/projection_semantics.js +++ b/jstests/core/projection_semantics.js @@ -2,8 +2,6 @@ * Tests the behavior of projection for dotted paths, including edge cases where the path only * sometimes exists. * - * TODO SERVER-63947 these tags shouldn't be necessary if we remove the explicit columnstore index - * mention. * @tags: [ * uses_column_store_index, * # We could potentially need to resume an index build in the event of a stepdown, which is not @@ -16,8 +14,11 @@ "use strict"; load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -const columnstoreEnabled = checkSBEEnabled( - db, ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true /* checkAllNodes */); + +if (!checkSBEEnabled(db, ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"])) { + jsTestLog("Skipping test since columnstore Indexes are not enabled"); + return; +} const coll = db.projection_semantics; coll.drop(); @@ -26,8 +27,7 @@ let globalIdCounter = 0; // Tests that when 'projection' is applied to 'input', we get 'expectedOutput'. // Tests that this remains true if indexes are added, or if we use aggregation instead of find. -function testInputOutput( - {input, projection, expectedOutput, interestingIndexes = [], excludeColumnStore = false}) { +function testInputOutput({input, projection, expectedOutput, interestingIndexes = []}) { if (!input.hasOwnProperty("_id")) { input = Object.merge({_id: ++globalIdCounter}, input); } @@ -37,21 +37,15 @@ function testInputOutput( expectedOutput, () => tojson(coll.find({_id: input._id}, projection).limit(1).hint({$natural: 1}).explain())); + for (let indexSpec of interestingIndexes) { assert.commandWorkedOrFailedWithCode(coll.createIndex(indexSpec), ErrorCodes.IndexAlreadyExists); - assert.docEq(coll.find({_id: input._id}, projection).hint(indexSpec).toArray()[0], - expectedOutput); - } - if (columnstoreEnabled && !excludeColumnStore) { - const columnStore = {"$**": "columnstore"}; - assert.commandWorkedOrFailedWithCode(coll.createIndex(columnStore), - ErrorCodes.IndexAlreadyExists); - assert.docEq(coll.find({_id: input._id}, projection).hint(columnStore).toArray()[0], - expectedOutput, - () => tojson(coll.find({_id: input._id}, projection) - .hint(columnStore) - .explain("executionStats"))); + assert.docEq( + coll.find({_id: input._id}, projection).hint(indexSpec).toArray()[0], + expectedOutput, + () => tojson( + coll.find({_id: input._id}, projection).hint(indexSpec).explain("executionStats"))); } assert.docEq( @@ -67,7 +61,7 @@ function testInputOutput( input: input, projection: {a: 1}, expectedOutput: output, - interestingIndexes: [{_id: 1, a: 1}, {a: 1, _id: 1}] + interestingIndexes: [{_id: 1, a: 1}, {a: 1, _id: 1}, {"$**": "columnstore"}] }); // Test some basic "normal" cases. @@ -80,18 +74,19 @@ function testInputOutput( // Test including "a" when "a" is missing/not present. // TODO SERVER-23229 this will return different results if there is a covering index, so here - // but not elsewhere we don't use any "interestingIndexes". + // but not elsewhere we don't use any "interestingIndexes." Column store indexes are excepted + // since their unique storage format means they are unimpacted by SERVER-23229. testInputOutput({ input: {_id: ++globalIdCounter, b: "other", x: "extra"}, projection: {a: 1}, expectedOutput: {_id: globalIdCounter}, - interestingIndexes: [] + interestingIndexes: [{"$**": "columnstore"}] }); testInputOutput({ input: {_id: ++globalIdCounter}, projection: {a: 1}, expectedOutput: {_id: globalIdCounter}, - interestingIndexes: [] + interestingIndexes: [{"$**": "columnstore"}] }); // Test a range of interesting values for "a". We expect everything to be preserved unmodified. @@ -99,7 +94,7 @@ function testInputOutput( input: input, projection: {a: 1}, expectedOutput: input, - interestingIndexes: [{_id: 1, a: 1}, {a: 1, _id: 1}] + interestingIndexes: [{_id: 1, a: 1}, {a: 1, _id: 1}, {"$**": "columnstore"}] }); testIdentityInclusionA({_id: ++globalIdCounter, a: null}); testIdentityInclusionA({_id: ++globalIdCounter, a: undefined}); @@ -124,7 +119,7 @@ function testInputOutput( // Can't use {a: "hashed"} here because it doesn't support array values. // Could use {a: "$**"}, but it can't be hinted without a query predicate so we'll leave // that coverage for elsewhere rather than add complexity to get a valid query predicate. - interestingIndexes: [{a: 1}, {a: -1}] + interestingIndexes: [{a: 1}, {a: -1}, {"$**": "columnstore"}] }); // The "basics" again. @@ -135,18 +130,19 @@ function testInputOutput( // Missing 'a' value again. // TODO SERVER-23229 this will return different results if there is a covering index, so here - // but not elsewhere we don't use any "interestingIndexes". + // but not elsewhere we don't use any "interestingIndexes". Column store indexes are excepted + // since their unique storage format means they are unimpacted by SERVER-23229. testInputOutput({ input: {_id: ++globalIdCounter, b: "other", x: "extra"}, projection: {a: 1, _id: 0}, expectedOutput: {}, - interestingIndexes: [] + interestingIndexes: [{"$**": "columnstore"}] }); testInputOutput({ input: {_id: ++globalIdCounter}, projection: {a: 1, _id: 0}, expectedOutput: {}, - interestingIndexes: [] + interestingIndexes: [{"$**": "columnstore"}] }); // Just a couple of the cases above to confirm the same behavior just without the _id. @@ -165,7 +161,7 @@ function testInputOutput( input: input, projection: {'a.b': 1}, expectedOutput: output, - interestingIndexes: [{_id: 1, 'a.b': 1}, {'a.b': 1, _id: 1}] + interestingIndexes: [{_id: 1, 'a.b': 1}, {'a.b': 1, _id: 1}, {"$**": "columnstore"}] }); // Test some basic "normal" cases. @@ -196,8 +192,15 @@ function testInputOutput( // Interestingly, this bug disappears if the index is multikey ('a' or 'a.b' are arrays), since // we will need to add a fetch to reconstruct the array anyway and will figure out the correct // answer in the process. - const testADotBNoIndexes = (input, output) => testInputOutput( - {input: input, projection: {'a.b': 1}, expectedOutput: output, interestingIndexes: []}); + // + // Column store indexes are excepted since their unique storage format means they are unimpacted + // by SERVER-23229. + const testADotBNoIndexes = (input, output) => testInputOutput({ + input: input, + projection: {'a.b': 1}, + expectedOutput: output, + interestingIndexes: [{"$**": "columnstore"}] + }); testADotBNoIndexes({_id: ++globalIdCounter, b: "other", x: "extra"}, {_id: globalIdCounter}); testADotBNoIndexes({_id: ++globalIdCounter}, {_id: globalIdCounter}); @@ -208,7 +211,7 @@ function testInputOutput( input: input, projection: {'a.b': 1, _id: 0}, expectedOutput: output, - interestingIndexes: [{'a.b': 1}, {'a.b': -1}] + interestingIndexes: [{'a.b': 1}, {'a.b': -1}, {"$**": "columnstore"}] }); // The "basics" again - no _id this time. @@ -266,8 +269,14 @@ function testInputOutput( input: input, projection: {'a.b': 1, 'a.c': 1, _id: 0}, expectedOutput: output, - interestingIndexes: - [{a: 1}, {'a.b': 1}, {'a.c': 1}, {'a.b': 1, 'a.c': 1}, {'a.b': 1, 'a.c': -1}] + interestingIndexes: [ + {a: 1}, + {'a.b': 1}, + {'a.c': 1}, + {'a.b': 1, 'a.c': 1}, + {'a.b': 1, 'a.c': -1}, + {"$**": "columnstore"} + ] }); testIncludeOnlyADotBAndADotC( {_id: ++globalIdCounter, a: {b: "scalar", c: "scalar", d: "extra"}}, @@ -288,12 +297,13 @@ function testInputOutput( // Non-array cases where one or both of the paths don't exist. // // TODO SERVER-23229: This will return different results if there is a covering index, so here - // but not elsewhere we don't use any "interestingIndexes" in test cases. + // but not elsewhere we don't use any "interestingIndexes" in test cases. Column store indexes + // are excepted since their unique storage format means they are unimpacted by SERVER-23229. const testIncludeADotBAndCNoIndexes = (input, output) => testInputOutput({ input: input, projection: {'a.b': 1, 'a.c': 1, _id: 0}, expectedOutput: output, - interestingIndexes: [] + interestingIndexes: [{"$**": "columnstore"}] }); testIncludeADotBAndCNoIndexes({_id: ++globalIdCounter, a: {b: "scalar", d: "extra"}}, @@ -310,7 +320,7 @@ function testInputOutput( input: input, projection: {'a.b.c': 1, _id: 0}, expectedOutput: output, - interestingIndexes: [{'a.b.c': 1}, {'a.b.c': -1}] + interestingIndexes: [{'a.b.c': 1}, {'a.b.c': -1}, {"$**": "columnstore"}] }); // Test some basic "normal" cases. @@ -370,11 +380,14 @@ function testInputOutput( // Interestingly, this bug disappears if the index is multikey ('a.b.c' or any parent is an // array), since we will need to add a fetch to reconstruct the array anyway and will figure out // the correct answer in the process. + // + // Column store indexes are excepted since their unique storage format means they are unimpacted + // by SERVER-23229. const testADotBDotCNoIndexes = (input, output) => testInputOutput({ input: input, projection: {'a.b.c': 1, _id: 0}, expectedOutput: output, - interestingIndexes: [] + interestingIndexes: [{"$**": "columnstore"}] }); testADotBDotCNoIndexes({}, {}); @@ -390,7 +403,7 @@ function testInputOutput( input: input, projection: {'a.b.c': 1, _id: 0}, expectedOutput: output, - interestingIndexes: [{'a.b.c': 1}, {'a.b.c': -1}] + interestingIndexes: [{'a.b.c': 1}, {'a.b.c': -1}, {"$**": "columnstore"}] }); // More cases where 'a.b.c' doesn't exist - but with arrays this time. @@ -628,21 +641,18 @@ function testInputOutput( testInputOutput({ input: {_id: ++globalIdCounter}, projection: {_id: 1}, - expectedOutput: {_id: globalIdCounter} + expectedOutput: {_id: globalIdCounter}, + interestingIndexes: [{_id: 1}, {"$**": "columnstore"}] }); testInputOutput({ input: {_id: ++globalIdCounter}, projection: {_id: 0}, expectedOutput: {}, - // Column store indexes do not support exclusion projections. - excludeColumnStore: true, }); testInputOutput({ input: {_id: ++globalIdCounter, a: 1, b: 1}, projection: {_id: 0}, expectedOutput: {a: 1, b: 1}, - // Column store indexes do not support exclusion projections. - excludeColumnStore: true, }); // Test that you can specify nested paths with dots or as sub-objects and it'll mean the @@ -651,21 +661,21 @@ function testInputOutput( input: {measurements: {temperature: 20, pressure: 0.7, humidity: 0.4, time: new Date()}}, projection: {'measurements.temperature': 1, 'measurements.pressure': 1, _id: 0}, expectedOutput: {measurements: {temperature: 20, pressure: 0.7}}, - interestingIndexes: [{'measurements.temperature': 1, 'measurements.pressure': 1}] + interestingIndexes: + [{'measurements.temperature': 1, 'measurements.pressure': 1}, {"$**": "columnstore"}] }); testInputOutput({ input: {measurements: {temperature: 20, pressure: 0.7, humidity: 0.4, time: new Date()}}, projection: {measurements: {temperature: 1, pressure: 1}, _id: 0}, expectedOutput: {measurements: {temperature: 20, pressure: 0.7}}, - interestingIndexes: [{'measurements.temperature': 1, 'measurements.pressure': 1}] + interestingIndexes: + [{'measurements.temperature': 1, 'measurements.pressure': 1}, {"$**": "columnstore"}] }); // Now with an exclusion projection. testInputOutput({ input: {measurements: {temperature: 20, pressure: 0.7, humidity: 0.4, time: new Date()}}, projection: {measurements: {humidity: 0, time: 0}, _id: 0}, expectedOutput: {measurements: {temperature: 20, pressure: 0.7}}, - // Column store indexes do not support exclusion projections. - excludeColumnStore: true, }); }()); }()); |