diff options
author | Militsa Sotirova <militsa.sotirova@mongodb.com> | 2022-09-29 12:58:50 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-09-29 14:04:48 +0000 |
commit | 0b24ce9b359574b8f695fce8b4d9b80fdcaa4a10 (patch) | |
tree | 5d6ceb3b8f3776a02dabc4f027a410a19688c3d1 | |
parent | 44d7b27d4ba081d27e4ae4826ecda9ef05323cb5 (diff) | |
download | mongo-0b24ce9b359574b8f695fce8b4d9b80fdcaa4a10.tar.gz |
SERVER-66928 convert ABT pipeline tests to golden testing
9 files changed, 4001 insertions, 2681 deletions
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript index be13b5fc366..8c65edab339 100644 --- a/src/mongo/db/pipeline/SConscript +++ b/src/mongo/db/pipeline/SConscript @@ -490,7 +490,8 @@ env.Library( env.CppUnitTest( target='db_pipeline_test', source=[ - 'abt/abt_pipeline_test.cpp', + 'abt/abt_optimization_test.cpp', + 'abt/abt_translation_test.cpp', 'accumulator_js_test.cpp' if get_option('js-engine') != 'none' else [], 'accumulator_test.cpp', 'aggregation_request_test.cpp', diff --git a/src/mongo/db/pipeline/abt/abt_optimization_test.cpp b/src/mongo/db/pipeline/abt/abt_optimization_test.cpp new file mode 100644 index 00000000000..2d74409e4ee --- /dev/null +++ b/src/mongo/db/pipeline/abt/abt_optimization_test.cpp @@ -0,0 +1,361 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + + +#include "mongo/db/pipeline/abt/utils.h" +#include "mongo/db/query/optimizer/cascades/cost_derivation.h" +#include "mongo/db/query/optimizer/explain.h" +#include "mongo/db/query/optimizer/opt_phase_manager.h" +#include "mongo/db/query/optimizer/utils/unit_test_utils.h" +#include "mongo/unittest/golden_test.h" + +namespace mongo::optimizer { + +unittest::GoldenTestConfig goldenTestConfigABTOptimization{"src/mongo/db/test_output/pipeline/abt"}; + +TEST(ABTTranslate, OptimizePipelineTests) { + unittest::GoldenTestContext gctx(&goldenTestConfigABTOptimization); + + testABTTranslationAndOptimization( + gctx, + "optimized $match with $or: pipeline is able to use a SargableNode with a disjunction of " + "point intervals.", + "[{$match: {$or: [{a: 1}, {a: 2}, {a: 3}]}}]", + "collection", + {OptPhase::MemoSubstitutionPhase}, + {{{"collection", + ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}); + + // TODO SERVER-67819 Support indexing for eqMember op type + testABTTranslationAndOptimization( + gctx, + "optimized $match with $in and a list of equalities becomes a comparison to an EqMember " + "list.", + "[{$match: {a: {$in: [1, 2, 3]}}}]", + "collection", + {OptPhase::MemoSubstitutionPhase}, + {{{"collection", + ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized $project inclusion then $match: observe the Filter can be reordered " + "against the Eval node", + "[{$project: {a: 1, b: 1}}, {$match: {a: 2}}]", + "collection", + {OptPhase::ConstEvalPre, + OptPhase::PathFuse, + OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}); + + testABTTranslationAndOptimization(gctx, + "optimized $match basic", + "[{$match: {a: 1, b: 2}}]", + "collection", + {OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}); + + testABTTranslationAndOptimization( + gctx, + "optimized $expr filter: make sure we have a single array constant for (1, 2, 'str', ...)", + "[{$project: {a: {$filter: {input: [1, 2, 'str', {a: 2.0, b:'s'}, 3, 4], as: 'num', cond: " + "{$and: [{$gte: ['$$num', 2]}, {$lte: ['$$num', 3]}]}}}}}]", + "collection", + {OptPhase::ConstEvalPre}); + + testABTTranslationAndOptimization( + gctx, + "optimized $group local global", + "[{$group: {_id: '$a', c: {$sum: '$b'}}}]", + "collection", + {OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", ScanDefinition{{}, {}, {DistributionType::UnknownPartitioning}}}}, + 5 /*numberOfPartitions*/}); + + testABTTranslationAndOptimization(gctx, + "optimized $unwind then $sort", + "[{$unwind: '$x'}, {$sort: {'x': 1}}]", + "collection", + OptPhaseManager::getAllRewritesSet()); + + testABTTranslationAndOptimization( + gctx, + "optimized $match with index", + "[{$match: {'a': 10}}]", + "collection", + {OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized $match index covered", + "[{$project: {_id: 0, a: 1}}, {$match: {'a': 10}}]", + "collection", + {OptPhase::ConstEvalPre, + OptPhase::PathFuse, + OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{ + {}, + {{"index1", + IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}}}, + false /*multiKey*/}}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized $match index covered, match then project", + "[{$match: {'a': 10}}, {$project: {_id: 0, a: 1}}]", + "collection", + {OptPhase::ConstEvalPre, + OptPhase::PathFuse, + OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{ + {}, + {{"index1", + IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}}}, + false /*multiKey*/}}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized $match index covered, match on two indexed keys then project", + "[{$match: {'a': 10, 'b': 20}}, {$project: {_id: 0, a: 1}}]", + "collection", + {OptPhase::ConstEvalPre, + OptPhase::PathFuse, + OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{ + {}, + {{"index1", + IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}, + {makeNonMultikeyIndexPath("b"), CollationOp::Ascending}}}, + false /*multiKey*/}}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized $match index covered, match on three indexed keys then project", + "[{$match: {'a': 10, 'b': 20, 'c': 30}}, {$project: {_id: 0, a: 1, b: 1, c: 1}}]", + "collection", + {OptPhase::ConstEvalPre, + OptPhase::PathFuse, + OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{ + {}, + {{"index1", + IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}, + {makeNonMultikeyIndexPath("b"), CollationOp::Ascending}, + {makeNonMultikeyIndexPath("c"), CollationOp::Ascending}}}, + false /*multiKey*/}}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized $match index covered, inclusion project then match on three indexed keys", + "[{$project: {_id: 0, a: 1, b: 1, c: 1}}, {$match: {'a': 10, 'b': 20, 'c': 30}}]", + "collection", + {OptPhase::ConstEvalPre, + OptPhase::PathFuse, + OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{ + {}, + {{"index1", + IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}, + {makeNonMultikeyIndexPath("b"), CollationOp::Ascending}, + {makeNonMultikeyIndexPath("c"), CollationOp::Ascending}}}, + false /*multiKey*/}}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized $match sort index", + "[{$match: {'a': 10}}, {$sort: {'a': 1}}]", + "collection", + {OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized range index", + "[{$match: {'a': {$gt: 70, $lt: 90}}}]", + "collection", + {OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}, + {}, + true); + + testABTTranslationAndOptimization( + gctx, + "optimized index on two keys", + "[{$match: {'a': 2, 'b': 2}}]", + "collection", + {OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"collection", + ScanDefinition{{}, + {{"index1", + IndexDefinition{{{makeIndexPath("a"), CollationOp::Ascending}, + {makeIndexPath("b"), CollationOp::Ascending}}, + true /*multiKey*/}}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized index on one key", + "[{$match: {'a': 2, 'b': 2}}]", + "collection", + {OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase, + OptPhase::ConstEvalPost}, + {{{"collection", + ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized $group eval no inline: verify that \"b\" is not inlined in the group " + "expression, but is coming from the physical scan", + "[{$group: {_id: null, a: {$first: '$b'}}}]", + "collection", + OptPhaseManager::getAllRewritesSet()); + + std::string scanDefA = "collA"; + std::string scanDefB = "collB"; + Metadata metadata{{{scanDefA, {}}, {scanDefB, {}}}}; + testABTTranslationAndOptimization(gctx, + "optimized union", + "[{$unionWith: 'collB'}, {$match: {_id: 1}}]", + scanDefA, + {OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + metadata, + {}, + false, + {{NamespaceString("a." + scanDefB), {}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized common expression elimination", + "[{$project: {foo: {$add: ['$b', 1]}, bar: {$add: ['$b', 1]}}}]", + "test", + {OptPhase::ConstEvalPre}, + {{{"test", {{}, {}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized group by dependency: demonstrate that \"c\" is set to the array size " + "(not the array itself coming from the group)", + "[{$group: {_id: {}, b: {$addToSet: '$a'}}}, {$project: " + "{_id: 0, b: {$size: '$b'}}}, {$project: {_id: 0, c: '$b'}}]", + "test", + {OptPhase::ConstEvalPre, + OptPhase::PathFuse, + OptPhase::MemoSubstitutionPhase, + OptPhase::MemoExplorationPhase, + OptPhase::MemoImplementationPhase}, + {{{"test", {{}, {}}}}}); + + testABTTranslationAndOptimization( + gctx, + "optimized double $elemMatch", + "[{$match: {a: {$elemMatch: {$gte: 5, $lte: 6}}, b: {$elemMatch: {$gte: 1, $lte: 3}}}}]", + "test", + {OptPhase::MemoSubstitutionPhase}, + {{{"test", {{}, {}}}}}, + defaultConvertPathToInterval); +} + +TEST(ABTTranslate, PartialIndex) { + unittest::GoldenTestContext gctx(&goldenTestConfigABTOptimization); + + PrefixId prefixId; + std::string scanDefName = "collection"; + ProjectionName scanProjName = prefixId.getNextId("scan"); + + // By default the constant is translated as "int32". + auto conversionResult = convertExprToPartialSchemaReq( + make<EvalFilter>( + make<PathGet>("b", + make<PathTraverse>(make<PathCompare>(Operations::Eq, Constant::int32(2)), + PathTraverse::kSingleLevel)), + make<Variable>(scanProjName)), + true /*isFilterContext*/, + {} /*pathToInterval*/); + ASSERT_TRUE(conversionResult.has_value()); + ASSERT_FALSE(conversionResult->_retainPredicate); + Metadata metadata = { + {{scanDefName, + ScanDefinition{{}, + {{"index1", + IndexDefinition{{{makeIndexPath("a"), CollationOp::Ascending}}, + true /*multiKey*/, + {DistributionType::Centralized}, + std::move(conversionResult->_reqMap)}}}}}}}; + + testABTTranslationAndOptimization( + gctx, + "optimized partial index: the expression matches the pipeline", + "[{$match: {'a': 3, 'b': 2}}]", + scanDefName, + OptPhaseManager::getAllRewritesSet(), + metadata); + + testABTTranslationAndOptimization( + gctx, + "optimized partial index negative: the expression does not match the pipeline", + "[{$match: {'a': 3, 'b': 3}}]", + scanDefName, + OptPhaseManager::getAllRewritesSet(), + metadata); +} +} // namespace mongo::optimizer diff --git a/src/mongo/db/pipeline/abt/abt_pipeline_test.cpp b/src/mongo/db/pipeline/abt/abt_pipeline_test.cpp deleted file mode 100644 index 4c7c82e9910..00000000000 --- a/src/mongo/db/pipeline/abt/abt_pipeline_test.cpp +++ /dev/null @@ -1,2680 +0,0 @@ -/** - * Copyright (C) 2022-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include <boost/intrusive_ptr.hpp> - -#include "mongo/db/pipeline/abt/utils.h" -#include "mongo/db/query/optimizer/cascades/cost_derivation.h" -#include "mongo/db/query/optimizer/explain.h" -#include "mongo/db/query/optimizer/opt_phase_manager.h" -#include "mongo/db/query/optimizer/utils/unit_test_utils.h" -#include "mongo/unittest/unittest.h" - -namespace mongo { -namespace { - -using namespace optimizer; - -TEST(ABTTranslate, MatchWithInEmptyList) { - // A $match with $in and an empty equalities list should not match any documents. - ABT emptyListIn = translatePipeline("[{$match: {a: {$in: []}}}]"); - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathConstant []\n" - "| Const [false]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - emptyListIn); -} - -TEST(ABTTranslate, MatchWithInSingletonList) { - // A $match with $in and singleton equalities list should simplify to single equality. - ABT singletonListIn = translatePipeline("[{$match: {a: {$in: [1]}}}]"); - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [1]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - singletonListIn); -} - -TEST(ABTTranslate, MatchWithInList) { - // A $match with $in and a list of equalities becomes a comparison to an EqMember list. - ABT listIn = translatePipeline("[{$match: {a: {$in: [1, 2, 3]}}}]"); - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [EqMember]\n" - "| Const [[1, 2, 3]]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - listIn); -} - -TEST(ABTTranslate, MatchWithInDuplicateElementsRemoved) { - // A $match with $in and a list of equalities has the duplicates removed from the list. - ABT listIn = translatePipeline("[{$match: {a: {$in: ['abc', 'def', 'ghi', 'def']}}}]"); - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [EqMember]\n" - "| Const [[\"abc\", \"def\", \"ghi\"]]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - listIn); -} - -TEST(ABTTranslate, EmptyElemMatch) { - ABT emptyElemMatch = translatePipeline("[{$match: {'a': {$elemMatch: {}}}}]"); - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathComposeM []\n" - "| | PathArr []\n" - "| PathTraverse [1]\n" - "| PathComposeM []\n" - "| | PathComposeA []\n" - "| | | PathArr []\n" - "| | PathObj []\n" - "| PathConstant []\n" - "| Const [true]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - emptyElemMatch); -} - -TEST(ABTTranslate, MatchWithElemMatchAndIn) { - ABT elemMatchIn = translatePipeline("[{$match: {'a.b': {$elemMatch: {$in: [1, 2, 3]}}}}]"); - - // The PathGet and PathTraverse operators interact correctly when $in is under $elemMatch. - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathGet [b]\n" - "| PathComposeM []\n" - "| | PathArr []\n" - "| PathTraverse [1]\n" - "| PathCompare [EqMember]\n" - "| Const [[1, 2, 3]]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - elemMatchIn); -} - -TEST(ABTTranslate, MatchWithOrConvertedToIn) { - ABT orTranslated = translatePipeline("[{$match: {$or: [{a: 1}, {a: 2}, {a: 3}]}}]"); - ABT inTranslated = translatePipeline("[{$match: {a: {$in: [1, 2, 3]}}}]"); - - PrefixId prefixId; - std::string scanDefName = "collection"; - Metadata metadata = { - {{scanDefName, - ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}; - OptPhaseManager phaseManager( - {OptPhase::MemoSubstitutionPhase}, prefixId, metadata, DebugInfo::kDefaultForTests); - - phaseManager.optimize(orTranslated); - phaseManager.optimize(inTranslated); - - // Both pipelines are able to use a SargableNode with a disjunction of point intervals. - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Sargable [Complete]\n" - "| | | | | requirementsMap: \n" - "| | | | | refProjection: scan_0, path: 'PathGet [a] PathTraverse [1] " - "PathIdentity []', intervals: {{{[Const [3], Const [3]]}} U {{[Const [1], Const [1]]}} U " - "{{[Const [2], Const [2]]}}}\n" - "| | | | candidateIndexes: \n" - "| | | | candidateId: 1, index1, {}, {0}, {{{[Const [3], Const [3]]}} U " - "{{[Const [1], Const [1]]}} U {{[Const [2], Const [2]]}}}\n" - "| | | scanParams: \n" - "| | | {'a': evalTemp_0}\n" - "| | | residualReqs: \n" - "| | | refProjection: evalTemp_0, path: 'PathTraverse [1] PathIdentity " - "[]', intervals: {{{[Const [3], Const [3]]}} U {{[Const [1], Const [1]]}} U {{[Const [2], " - "Const [2]]}}}, entryIndex: 0\n" - "| | BindBlock:\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - orTranslated); - // TODO SERVER-67819 Support indexing for eqMember op type - // ASSERT(orTranslated == inTranslated); -} - -TEST(ABTTranslate, SortLimitSkip) { - ABT translated = translatePipeline( - "[{$limit: 5}, " - "{$skip: 3}, " - "{$sort: {a: 1, b: -1}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Collation []\n" - "| | collation: \n" - "| | sort_0: Ascending\n" - "| | sort_1: Descending\n" - "| RefBlock: \n" - "| Variable [sort_0]\n" - "| Variable [sort_1]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [sort_1]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [sort_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathIdentity []\n" - "LimitSkip []\n" - "| limitSkip:\n" - "| limit: (none)\n" - "| skip: 3\n" - "LimitSkip []\n" - "| limitSkip:\n" - "| limit: 5\n" - "| skip: 0\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ProjectRetain) { - PrefixId prefixId; - std::string scanDefName = "collection"; - Metadata metadata = {{{scanDefName, ScanDefinition{{}, {}}}}}; - ABT translated = translatePipeline( - metadata, "[{$project: {a: 1, b: 1}}, {$match: {a: 2}}]", scanDefName, prefixId); - - OptPhaseManager phaseManager({OptPhase::ConstEvalPre, - OptPhase::PathFuse, - OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - // Observe the Filter can be reordered against the Eval node. - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [b]\n" - "| | PathConstant []\n" - "| | Variable [fieldProj_2]\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathConstant []\n" - "| | Variable [fieldProj_1]\n" - "| PathField [_id]\n" - "| PathConstant []\n" - "| Variable [fieldProj_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [fieldProj_1]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "PhysicalScan [{'_id': fieldProj_0, 'a': fieldProj_1, 'b': fieldProj_2}, collection]\n" - " BindBlock:\n" - " [fieldProj_0]\n" - " Source []\n" - " [fieldProj_1]\n" - " Source []\n" - " [fieldProj_2]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, ProjectRetain1) { - ABT translated = translatePipeline("[{$project: {a1: 1, a2: 1, a3: 1, a4: 1, a5: 1, a6: 1}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathKeep [_id, a1, a2, a3, a4, a5, a6]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, AddFields) { - // Since '$z' is a single element, it will be considered a renamed path. - ABT translated = translatePipeline("[{$addFields: {a: '$z'}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathDefault []\n" - "| | Const [{}]\n" - "| PathField [a]\n" - "| PathConstant []\n" - "| Variable [projRenamedPath_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projRenamedPath_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [z]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ProjectRenames) { - // Since '$c' is a single element, it will be considered a renamed path. - ABT translated = translatePipeline("[{$project: {'a.b': '$c'}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathTraverse [inf]\n" - "| | PathComposeM []\n" - "| | | PathDefault []\n" - "| | | Const [{}]\n" - "| | PathComposeM []\n" - "| | | PathField [b]\n" - "| | | PathConstant []\n" - "| | | Variable [projRenamedPath_0]\n" - "| | PathKeep [b]\n" - "| PathKeep [_id, a]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projRenamedPath_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [c]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ProjectPaths) { - ABT translated = translatePipeline("[{$project: {'a.b.c': '$x.y.z'}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathTraverse [inf]\n" - "| | PathComposeM []\n" - "| | | PathField [b]\n" - "| | | PathTraverse [inf]\n" - "| | | PathComposeM []\n" - "| | | | PathDefault []\n" - "| | | | Const [{}]\n" - "| | | PathComposeM []\n" - "| | | | PathField [c]\n" - "| | | | PathConstant []\n" - "| | | | Variable [projGetPath_0]\n" - "| | | PathKeep [c]\n" - "| | PathKeep [b]\n" - "| PathKeep [_id, a]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projGetPath_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [x]\n" - "| PathTraverse [inf]\n" - "| PathGet [y]\n" - "| PathTraverse [inf]\n" - "| PathGet [z]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ProjectPaths1) { - ABT translated = translatePipeline("[{$project: {'a.b':1, 'a.c':1, 'b':1}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathTraverse [inf]\n" - "| | PathComposeM []\n" - "| | | PathKeep [b, c]\n" - "| | PathObj []\n" - "| PathKeep [_id, a, b]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ProjectInclusion) { - ABT translated = translatePipeline("[{$project: {a: {$add: ['$c.d', 2]}, b: 1}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathDefault []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathConstant []\n" - "| | Variable [projGetPath_0]\n" - "| PathKeep [_id, a, b]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projGetPath_0]\n" - "| BinaryOp [Add]\n" - "| | Const [2]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [c]\n" - "| PathTraverse [inf]\n" - "| PathGet [d]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ProjectExclusion) { - ABT translated = translatePipeline("[{$project: {a: 0, b: 0}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathDrop [a, b]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ProjectReplaceRoot) { - ABT translated = translatePipeline("[{$replaceRoot: {newRoot: '$a'}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | newRoot_0\n" - "| RefBlock: \n" - "| Variable [newRoot_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [newRoot_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, MatchBasic) { - PrefixId prefixId; - std::string scanDefName = "collection"; - - ABT translated = translatePipeline("[{$match: {a: 1, b: 2}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [1]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [b]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); - - OptPhaseManager phaseManager({OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - {{{scanDefName, ScanDefinition{{}, {}}}}}, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [evalTemp_3]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [evalTemp_2]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [1]\n" - "PhysicalScan [{'<root>': scan_0, 'a': evalTemp_2, 'b': evalTemp_3}, collection]\n" - " BindBlock:\n" - " [evalTemp_2]\n" - " Source []\n" - " [evalTemp_3]\n" - " Source []\n" - " [scan_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, MatchPath1) { - ABT translated = translatePipeline("[{$match: {$expr: {$eq: ['$a', 1]}}}]"); - - // Demonstrate simple path is converted to EvalFilter. - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathCompare [Eq]\n" - "| Const [1]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, MatchPath2) { - ABT translated = translatePipeline("[{$match: {$expr: {$eq: ['$a.b', 1]}}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathConstant []\n" - "| BinaryOp [Eq]\n" - "| | Const [1]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [inf]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ElemMatchPath) { - ABT translated = translatePipeline( - "[{$project: {a: {$literal: [1, 2, 3, 4]}}}, {$match: {a: {$elemMatch: {$gte: 2, $lte: " - "3}}}}]"); - - // Observe type bracketing in the filter. - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [combinedProjection_0]\n" - "| PathGet [a]\n" - "| PathComposeM []\n" - "| | PathArr []\n" - "| PathTraverse [1]\n" - "| PathComposeM []\n" - "| | PathComposeM []\n" - "| | | PathCompare [Lt]\n" - "| | | Const [\"\"]\n" - "| | PathCompare [Gte]\n" - "| | Const [2]\n" - "| PathComposeM []\n" - "| | PathCompare [Gte]\n" - "| | Const [nan]\n" - "| PathCompare [Lte]\n" - "| Const [3]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathDefault []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathConstant []\n" - "| | Variable [projGetPath_0]\n" - "| PathKeep [_id, a]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projGetPath_0]\n" - "| Const [[1, 2, 3, 4]]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, MatchProject) { - ABT translated = translatePipeline( - "[{$project: {s: {$add: ['$a', '$b']}, c: 1}}, " - "{$match: {$or: [{c: 2}, {s: {$gte: 10}}]}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [combinedProjection_0]\n" - "| PathComposeA []\n" - "| | PathGet [c]\n" - "| | PathTraverse [1]\n" - "| | PathCompare [Eq]\n" - "| | Const [2]\n" - "| PathGet [s]\n" - "| PathTraverse [1]\n" - "| PathComposeM []\n" - "| | PathCompare [Lt]\n" - "| | Const [\"\"]\n" - "| PathCompare [Gte]\n" - "| Const [10]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathDefault []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [s]\n" - "| | PathConstant []\n" - "| | Variable [projGetPath_0]\n" - "| PathKeep [_id, c, s]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projGetPath_0]\n" - "| BinaryOp [Add]\n" - "| | EvalPath []\n" - "| | | Variable [scan_0]\n" - "| | PathGet [b]\n" - "| | PathIdentity []\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ProjectComplex) { - ABT translated = translatePipeline("[{$project: {'a1.b.c':1, 'a.b.c.d.e':'str'}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathField [a1]\n" - "| | PathTraverse [inf]\n" - "| | PathComposeM []\n" - "| | | PathField [b]\n" - "| | | PathTraverse [inf]\n" - "| | | PathComposeM []\n" - "| | | | PathKeep [c]\n" - "| | | PathObj []\n" - "| | PathComposeM []\n" - "| | | PathKeep [b]\n" - "| | PathObj []\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathTraverse [inf]\n" - "| | PathComposeM []\n" - "| | | PathField [b]\n" - "| | | PathTraverse [inf]\n" - "| | | PathComposeM []\n" - "| | | | PathField [c]\n" - "| | | | PathTraverse [inf]\n" - "| | | | PathComposeM []\n" - "| | | | | PathField [d]\n" - "| | | | | PathTraverse [inf]\n" - "| | | | | PathComposeM []\n" - "| | | | | | PathDefault []\n" - "| | | | | | Const [{}]\n" - "| | | | | PathComposeM []\n" - "| | | | | | PathField [e]\n" - "| | | | | | PathConstant []\n" - "| | | | | | Variable [projGetPath_0]\n" - "| | | | | PathKeep [e]\n" - "| | | | PathKeep [d]\n" - "| | | PathKeep [c]\n" - "| | PathKeep [b]\n" - "| PathKeep [_id, a, a1]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projGetPath_0]\n" - "| Const [\"str\"]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, ExprFilter) { - ABT translated = translatePipeline( - "[{$project: {a: {$filter: {input: [1, 2, 'str', {a: 2.0, b:'s'}, 3, 4], as: 'num', cond: " - "{$and: [{$gte: ['$$num', 2]}, {$lte: ['$$num', 3]}]}}}}}]"); - - PrefixId prefixId; - std::string scanDefName = "collection"; - OptPhaseManager phaseManager({OptPhase::ConstEvalPre}, - prefixId, - {{{scanDefName, ScanDefinition{{}, {}}}}}, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - // Make sure we have a single array constant for (1, 2, 'str', ...). - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathDefault []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathConstant []\n" - "| | EvalPath []\n" - "| | | Const [[1, 2, \"str\", {\"a\" : 2, \"b\" : \"s\"}, 3, 4]]\n" - "| | PathTraverse [inf]\n" - "| | PathLambda []\n" - "| | LambdaAbstraction [projGetPath_0_var_1]\n" - "| | If []\n" - "| | | | Const [Nothing]\n" - "| | | Variable [projGetPath_0_var_1]\n" - "| | BinaryOp [And]\n" - "| | | BinaryOp [Gte]\n" - "| | | | Const [2]\n" - "| | | Variable [projGetPath_0_var_1]\n" - "| | BinaryOp [Lte]\n" - "| | | Const [3]\n" - "| | Variable [projGetPath_0_var_1]\n" - "| PathKeep [_id, a]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, GroupBasic) { - ABT translated = - translatePipeline("[{$group: {_id: '$a.b', s: {$sum: {$multiply: ['$b', '$c']}}}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | agg_project_0\n" - "| RefBlock: \n" - "| Variable [agg_project_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [agg_project_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [s]\n" - "| | PathConstant []\n" - "| | Variable [s_agg_0]\n" - "| PathField [_id]\n" - "| PathConstant []\n" - "| Variable [groupByProj_0]\n" - "GroupBy []\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [groupByProj_0]\n" - "| aggregations: \n" - "| [s_agg_0]\n" - "| FunctionCall [$sum]\n" - "| Variable [groupByInputProj_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByInputProj_0]\n" - "| BinaryOp [Mult]\n" - "| | EvalPath []\n" - "| | | Variable [scan_0]\n" - "| | PathGet [c]\n" - "| | PathIdentity []\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [inf]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, GroupLocalGlobal) { - ABT translated = translatePipeline("[{$group: {_id: '$a', c: {$sum: '$b'}}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | agg_project_0\n" - "| RefBlock: \n" - "| Variable [agg_project_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [agg_project_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [c]\n" - "| | PathConstant []\n" - "| | Variable [c_agg_0]\n" - "| PathField [_id]\n" - "| PathConstant []\n" - "| Variable [groupByProj_0]\n" - "GroupBy []\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [groupByProj_0]\n" - "| aggregations: \n" - "| [c_agg_0]\n" - "| FunctionCall [$sum]\n" - "| Variable [groupByInputProj_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByInputProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); - - PrefixId prefixId; - std::string scanDefName = "collection"; - OptPhaseManager phaseManager( - {OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - {{{scanDefName, ScanDefinition{{}, {}, {DistributionType::UnknownPartitioning}}}}, - 5 /*numberOfPartitions*/}, - DebugInfo::kDefaultForTests); - - ABT optimized = std::move(translated); - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | agg_project_0\n" - "| RefBlock: \n" - "| Variable [agg_project_0]\n" - "Exchange []\n" - "| | distribution: \n" - "| | type: Centralized\n" - "| RefBlock: \n" - "Evaluation []\n" - "| BindBlock:\n" - "| [agg_project_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [c]\n" - "| | PathConstant []\n" - "| | Variable [c_agg_0]\n" - "| PathField [_id]\n" - "| PathConstant []\n" - "| Variable [groupByProj_0]\n" - "GroupBy [Global]\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [groupByProj_0]\n" - "| aggregations: \n" - "| [c_agg_0]\n" - "| FunctionCall [$sum]\n" - "| Variable [preagg_0]\n" - "Exchange []\n" - "| | distribution: \n" - "| | type: HashPartitioning\n" - "| | projections: \n" - "| | groupByProj_0\n" - "| RefBlock: \n" - "| Variable [groupByProj_0]\n" - "GroupBy [Local]\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [groupByProj_0]\n" - "| aggregations: \n" - "| [preagg_0]\n" - "| FunctionCall [$sum]\n" - "| Variable [groupByInputProj_0]\n" - "PhysicalScan [{'a': groupByProj_0, 'b': groupByInputProj_0}, collection, parallel]\n" - " BindBlock:\n" - " [groupByInputProj_0]\n" - " Source []\n" - " [groupByProj_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, UnwindBasic) { - ABT translated = translatePipeline("[{$unwind: {path: '$a.b.c'}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | embedProj_0\n" - "| RefBlock: \n" - "| Variable [embedProj_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [embedProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathField [a]\n" - "| PathTraverse [inf]\n" - "| PathField [b]\n" - "| PathTraverse [inf]\n" - "| PathField [c]\n" - "| PathConstant []\n" - "| Variable [unwoundProj_0]\n" - "Unwind []\n" - "| BindBlock:\n" - "| [unwoundPid_0]\n" - "| Source []\n" - "| [unwoundProj_0]\n" - "| Source []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [unwoundProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathGet [b]\n" - "| PathGet [c]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, UnwindComplex) { - ABT translated = translatePipeline( - "[{$unwind: {path: '$a.b.c', includeArrayIndex: 'p1.pid', preserveNullAndEmptyArrays: " - "true}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | embedPidProj_0\n" - "| RefBlock: \n" - "| Variable [embedPidProj_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [embedPidProj_0]\n" - "| EvalPath []\n" - "| | Variable [embedProj_0]\n" - "| PathField [p1]\n" - "| PathField [pid]\n" - "| PathConstant []\n" - "| If []\n" - "| | | Const [null]\n" - "| | Variable [unwoundPid_0]\n" - "| BinaryOp [Gte]\n" - "| | Const [0]\n" - "| Variable [unwoundPid_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [embedProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathField [a]\n" - "| PathTraverse [inf]\n" - "| PathField [b]\n" - "| PathTraverse [inf]\n" - "| PathField [c]\n" - "| PathLambda []\n" - "| LambdaAbstraction [unwoundLambdaVarName_0]\n" - "| If []\n" - "| | | Variable [unwoundLambdaVarName_0]\n" - "| | Variable [unwoundProj_0]\n" - "| BinaryOp [Gte]\n" - "| | Const [0]\n" - "| Variable [unwoundPid_0]\n" - "Unwind [retainNonArrays]\n" - "| BindBlock:\n" - "| [unwoundPid_0]\n" - "| Source []\n" - "| [unwoundProj_0]\n" - "| Source []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [unwoundProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathGet [b]\n" - "| PathGet [c]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, UnwindAndGroup) { - ABT translated = translatePipeline( - "[{$unwind:{path: '$a.b', preserveNullAndEmptyArrays: true}}, " - "{$group:{_id: '$a.b'}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | agg_project_0\n" - "| RefBlock: \n" - "| Variable [agg_project_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [agg_project_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathField [_id]\n" - "| PathConstant []\n" - "| Variable [groupByProj_0]\n" - "GroupBy []\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [groupByProj_0]\n" - "| aggregations: \n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByProj_0]\n" - "| EvalPath []\n" - "| | Variable [embedProj_0]\n" - "| PathGet [a]\n" - "| PathTraverse [inf]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [embedProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathField [a]\n" - "| PathTraverse [inf]\n" - "| PathField [b]\n" - "| PathLambda []\n" - "| LambdaAbstraction [unwoundLambdaVarName_0]\n" - "| If []\n" - "| | | Variable [unwoundLambdaVarName_0]\n" - "| | Variable [unwoundProj_0]\n" - "| BinaryOp [Gte]\n" - "| | Const [0]\n" - "| Variable [unwoundPid_0]\n" - "Unwind [retainNonArrays]\n" - "| BindBlock:\n" - "| [unwoundPid_0]\n" - "| Source []\n" - "| [unwoundProj_0]\n" - "| Source []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [unwoundProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, UnwindSort) { - ABT translated = translatePipeline("[{$unwind: '$x'}, {$sort: {'x': 1}}]"); - - PrefixId prefixId; - std::string scanDefName = "collection"; - OptPhaseManager phaseManager(OptPhaseManager::getAllRewritesSet(), - prefixId, - {{{scanDefName, ScanDefinition{{}, {}}}}}, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | embedProj_0\n" - "| RefBlock: \n" - "| Variable [embedProj_0]\n" - "Collation []\n" - "| | collation: \n" - "| | sort_0: Ascending\n" - "| RefBlock: \n" - "| Variable [sort_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [sort_0]\n" - "| Variable [unwoundProj_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [embedProj_0]\n" - "| If []\n" - "| | | Variable [scan_0]\n" - "| | FunctionCall [setField]\n" - "| | | | Variable [unwoundProj_0]\n" - "| | | Const [\"x\"]\n" - "| | Variable [scan_0]\n" - "| BinaryOp [Or]\n" - "| | FunctionCall [isObject]\n" - "| | Variable [scan_0]\n" - "| FunctionCall [exists]\n" - "| Variable [unwoundProj_0]\n" - "Unwind []\n" - "| BindBlock:\n" - "| [unwoundPid_0]\n" - "| Source []\n" - "| [unwoundProj_0]\n" - "| Source []\n" - "PhysicalScan [{'<root>': scan_0, 'x': unwoundProj_0}, collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n" - " [unwoundProj_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, MatchIndex) { - PrefixId prefixId; - std::string scanDefName = "collection"; - - Metadata metadata = { - {{scanDefName, - ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}; - ABT translated = translatePipeline(metadata, "[{$match: {'a': 10}}]", scanDefName, prefixId); - - OptPhaseManager phaseManager({OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [10]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); - - ABT optimized = std::move(translated); - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "BinaryJoin [joinType: Inner, {rid_0}]\n" - "| | Const [true]\n" - "| LimitSkip []\n" - "| | limitSkip:\n" - "| | limit: 1\n" - "| | skip: 0\n" - "| Seek [ridProjection: rid_0, {'<root>': scan_0}, collection]\n" - "| | BindBlock:\n" - "| | [scan_0]\n" - "| | Source []\n" - "| RefBlock: \n" - "| Variable [rid_0]\n" - "IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: " - "{[Const [10], Const [10]]}]\n" - " BindBlock:\n" - " [rid_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, MatchIndexCovered) { - PrefixId prefixId; - std::string scanDefName = "collection"; - - Metadata metadata = { - {{scanDefName, - ScanDefinition{ - {}, - {{"index1", - IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}}}, - false /*multiKey*/}}}}}}}; - ABT translated = translatePipeline( - metadata, "[{$project: {_id: 0, a: 1}}, {$match: {'a': 10}}]", scanDefName, prefixId); - - OptPhaseManager phaseManager({OptPhase::ConstEvalPre, - OptPhase::PathFuse, - OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = std::move(translated); - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathField [a]\n" - "| PathConstant []\n" - "| Variable [fieldProj_0]\n" - "IndexScan [{'<indexKey> 0': fieldProj_0}, scanDefName: collection, indexDefName: index1, " - "interval: {[Const [10], Const [10]]}]\n" - " BindBlock:\n" - " [fieldProj_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, MatchIndexCovered1) { - PrefixId prefixId; - std::string scanDefName = "collection"; - - Metadata metadata = { - {{scanDefName, - ScanDefinition{ - {}, - {{"index1", - IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}}}, - false /*multiKey*/}}}}}}}; - ABT translated = translatePipeline( - metadata, "[{$match: {'a': 10}}, {$project: {_id: 0, a: 1}}]", scanDefName, prefixId); - - OptPhaseManager phaseManager({OptPhase::ConstEvalPre, - OptPhase::PathFuse, - OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = std::move(translated); - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathField [a]\n" - "| PathConstant []\n" - "| Variable [fieldProj_0]\n" - "IndexScan [{'<indexKey> 0': fieldProj_0}, scanDefName: collection, indexDefName: index1, " - "interval: {[Const [10], Const [10]]}]\n" - " BindBlock:\n" - " [fieldProj_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, MatchIndexCovered2) { - PrefixId prefixId; - std::string scanDefName = "collection"; - - Metadata metadata = { - {{scanDefName, - ScanDefinition{ - {}, - {{"index1", - IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}, - {makeNonMultikeyIndexPath("b"), CollationOp::Ascending}}}, - false /*multiKey*/}}}}}}}; - ABT translated = translatePipeline(metadata, - "[{$match: {'a': 10, 'b': 20}}, {$project: {_id: 0, a: 1}}]", - scanDefName, - prefixId); - - OptPhaseManager phaseManager({OptPhase::ConstEvalPre, - OptPhase::PathFuse, - OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = std::move(translated); - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathField [a]\n" - "| PathConstant []\n" - "| Variable [fieldProj_0]\n" - "IndexScan [{'<indexKey> 0': fieldProj_0}, scanDefName: collection, indexDefName: index1, " - "interval: {[Const [10], Const [10]], [Const [20], Const [20]]}]\n" - " BindBlock:\n" - " [fieldProj_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, MatchIndexCovered3) { - PrefixId prefixId; - std::string scanDefName = "collection"; - - Metadata metadata = { - {{scanDefName, - ScanDefinition{ - {}, - {{"index1", - IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}, - {makeNonMultikeyIndexPath("b"), CollationOp::Ascending}, - {makeNonMultikeyIndexPath("c"), CollationOp::Ascending}}}, - false /*multiKey*/}}}}}}}; - ABT translated = translatePipeline( - metadata, - "[{$match: {'a': 10, 'b': 20, 'c': 30}}, {$project: {_id: 0, a: 1, b: 1, c: 1}}]", - scanDefName, - prefixId); - - OptPhaseManager phaseManager({OptPhase::ConstEvalPre, - OptPhase::PathFuse, - OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = std::move(translated); - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [c]\n" - "| | PathConstant []\n" - "| | Variable [fieldProj_2]\n" - "| PathComposeM []\n" - "| | PathField [b]\n" - "| | PathConstant []\n" - "| | Variable [fieldProj_1]\n" - "| PathField [a]\n" - "| PathConstant []\n" - "| Variable [fieldProj_0]\n" - "IndexScan [{'<indexKey> 0': fieldProj_0, '<indexKey> 1': fieldProj_1, '<indexKey> 2': " - "fieldProj_2}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], " - "Const [10]], [Const [20], Const [20]], [Const [30], Const [30]]}]\n" - " BindBlock:\n" - " [fieldProj_0]\n" - " Source []\n" - " [fieldProj_1]\n" - " Source []\n" - " [fieldProj_2]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, MatchIndexCovered4) { - PrefixId prefixId; - std::string scanDefName = "collection"; - - Metadata metadata = { - {{scanDefName, - ScanDefinition{ - {}, - {{"index1", - IndexDefinition{{{{makeNonMultikeyIndexPath("a"), CollationOp::Ascending}, - {makeNonMultikeyIndexPath("b"), CollationOp::Ascending}, - {makeNonMultikeyIndexPath("c"), CollationOp::Ascending}}}, - false /*multiKey*/}}}}}}}; - ABT translated = translatePipeline( - metadata, - "[{$project: {_id: 0, a: 1, b: 1, c: 1}}, {$match: {'a': 10, 'b': 20, 'c': 30}}]", - scanDefName, - prefixId); - - OptPhaseManager phaseManager({OptPhase::ConstEvalPre, - OptPhase::PathFuse, - OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = std::move(translated); - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [c]\n" - "| | PathConstant []\n" - "| | Variable [fieldProj_2]\n" - "| PathComposeM []\n" - "| | PathField [b]\n" - "| | PathConstant []\n" - "| | Variable [fieldProj_1]\n" - "| PathField [a]\n" - "| PathConstant []\n" - "| Variable [fieldProj_0]\n" - "IndexScan [{'<indexKey> 0': fieldProj_0, '<indexKey> 1': fieldProj_1, '<indexKey> 2': " - "fieldProj_2}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], " - "Const [10]], [Const [20], Const [20]], [Const [30], Const [30]]}]\n" - " BindBlock:\n" - " [fieldProj_0]\n" - " Source []\n" - " [fieldProj_1]\n" - " Source []\n" - " [fieldProj_2]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, MatchSortIndex) { - PrefixId prefixId; - std::string scanDefName = "collection"; - - Metadata metadata = { - {{scanDefName, - ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}; - ABT translated = translatePipeline( - metadata, "[{$match: {'a': 10}}, {$sort: {'a': 1}}]", scanDefName, prefixId); - - OptPhaseManager phaseManager({OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Collation []\n" - "| | collation: \n" - "| | sort_0: Ascending\n" - "| RefBlock: \n" - "| Variable [sort_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [sort_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathIdentity []\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [10]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); - - ABT optimized = std::move(translated); - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Collation []\n" - "| | collation: \n" - "| | sort_0: Ascending\n" - "| RefBlock: \n" - "| Variable [sort_0]\n" - "BinaryJoin [joinType: Inner, {rid_0}]\n" - "| | Const [true]\n" - "| LimitSkip []\n" - "| | limitSkip:\n" - "| | limit: 1\n" - "| | skip: 0\n" - "| Seek [ridProjection: rid_0, {'<root>': scan_0, 'a': sort_0}, collection]\n" - "| | BindBlock:\n" - "| | [scan_0]\n" - "| | Source []\n" - "| | [sort_0]\n" - "| | Source []\n" - "| RefBlock: \n" - "| Variable [rid_0]\n" - "IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: " - "{[Const [10], Const [10]]}]\n" - " BindBlock:\n" - " [rid_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, RangeIndex) { - PrefixId prefixId; - std::string scanDefName = "collection"; - Metadata metadata = { - {{scanDefName, - ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}; - ABT translated = - translatePipeline(metadata, "[{$match: {'a': {$gt: 70, $lt: 90}}}]", scanDefName, prefixId); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathComposeM []\n" - "| | PathCompare [Lt]\n" - "| | Const [\"\"]\n" - "| PathCompare [Gt]\n" - "| Const [70]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathComposeM []\n" - "| | PathCompare [Gte]\n" - "| | Const [nan]\n" - "| PathCompare [Lt]\n" - "| Const [90]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); - - OptPhaseManager phaseManager({OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = std::move(translated); - phaseManager.getHints()._disableScan = true; - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "BinaryJoin [joinType: Inner, {rid_0}]\n" - "| | Const [true]\n" - "| LimitSkip []\n" - "| | limitSkip:\n" - "| | limit: 1\n" - "| | skip: 0\n" - "| Seek [ridProjection: rid_0, {'<root>': scan_0}, collection]\n" - "| | BindBlock:\n" - "| | [scan_0]\n" - "| | Source []\n" - "| RefBlock: \n" - "| Variable [rid_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | FunctionCall [getArraySize]\n" - "| | Variable [sides_0]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "GroupBy []\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [rid_0]\n" - "| aggregations: \n" - "| [sides_0]\n" - "| FunctionCall [$addToSet]\n" - "| Variable [sideId_0]\n" - "Union []\n" - "| | BindBlock:\n" - "| | [rid_0]\n" - "| | Source []\n" - "| | [sideId_0]\n" - "| | Source []\n" - "| Evaluation []\n" - "| | BindBlock:\n" - "| | [sideId_0]\n" - "| | Const [1]\n" - "| IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: " - "{(Const [70], Const [\"\"])}]\n" - "| BindBlock:\n" - "| [rid_0]\n" - "| Source []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [sideId_0]\n" - "| Const [0]\n" - "IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: " - "{[Const [nan], Const [90])}]\n" - " BindBlock:\n" - " [rid_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, Index1) { - { - PrefixId prefixId; - std::string scanDefName = "collection"; - Metadata metadata = { - {{scanDefName, - ScanDefinition{{}, - {{"index1", - IndexDefinition{{{makeIndexPath("a"), CollationOp::Ascending}, - {makeIndexPath("b"), CollationOp::Ascending}}, - true /*multiKey*/}}}}}}}; - - ABT translated = - translatePipeline(metadata, "[{$match: {'a': 2, 'b': 2}}]", scanDefName, prefixId); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [b]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); - - OptPhaseManager phaseManager({OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "BinaryJoin [joinType: Inner, {rid_0}]\n" - "| | Const [true]\n" - "| LimitSkip []\n" - "| | limitSkip:\n" - "| | limit: 1\n" - "| | skip: 0\n" - "| Seek [ridProjection: rid_0, {'<root>': scan_0}, collection]\n" - "| | BindBlock:\n" - "| | [scan_0]\n" - "| | Source []\n" - "| RefBlock: \n" - "| Variable [rid_0]\n" - "IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: " - "{[Const [2], Const [2]], [Const [2], Const [2]]}]\n" - " BindBlock:\n" - " [rid_0]\n" - " Source []\n", - optimized); - } - - { - PrefixId prefixId; - std::string scanDefName = "collection"; - Metadata metadata = { - {{scanDefName, - ScanDefinition{{}, {{"index1", makeIndexDefinition("a", CollationOp::Ascending)}}}}}}; - - ABT translated = - translatePipeline(metadata, "[{$match: {'a': 2, 'b': 2}}]", scanDefName, prefixId); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [b]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); - - // Demonstrate we can use an index over only one field. - OptPhaseManager phaseManager({OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase, - OptPhase::ConstEvalPost}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "BinaryJoin [joinType: Inner, {rid_0}]\n" - "| | Const [true]\n" - "| Filter []\n" - "| | EvalFilter []\n" - "| | | Variable [evalTemp_4]\n" - "| | PathTraverse [1]\n" - "| | PathCompare [Eq]\n" - "| | Const [2]\n" - "| LimitSkip []\n" - "| | limitSkip:\n" - "| | limit: 1\n" - "| | skip: 0\n" - "| Seek [ridProjection: rid_0, {'<root>': scan_0, 'b': evalTemp_4}, collection]\n" - "| | BindBlock:\n" - "| | [evalTemp_4]\n" - "| | Source []\n" - "| | [scan_0]\n" - "| | Source []\n" - "| RefBlock: \n" - "| Variable [rid_0]\n" - "IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: " - "{[Const [2], Const [2]]}]\n" - " BindBlock:\n" - " [rid_0]\n" - " Source []\n", - optimized); - } -} - -TEST(ABTTranslate, GroupMultiKey) { - ABT translated = translatePipeline( - "[{$group: {_id: {'isin': '$isin', 'year': '$year'}, 'count': {$sum: 1}, 'open': {$first: " - "'$$ROOT'}}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | agg_project_0\n" - "| RefBlock: \n" - "| Variable [agg_project_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [agg_project_0]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [open]\n" - "| | PathConstant []\n" - "| | Variable [open_agg_0]\n" - "| PathComposeM []\n" - "| | PathField [count]\n" - "| | PathConstant []\n" - "| | Variable [count_agg_0]\n" - "| PathField [_id]\n" - "| PathComposeM []\n" - "| | PathField [year]\n" - "| | PathConstant []\n" - "| | Variable [groupByProj_1]\n" - "| PathField [isin]\n" - "| PathConstant []\n" - "| Variable [groupByProj_0]\n" - "GroupBy []\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [groupByProj_0]\n" - "| | Variable [groupByProj_1]\n" - "| aggregations: \n" - "| [count_agg_0]\n" - "| FunctionCall [$sum]\n" - "| Const [1]\n" - "| [open_agg_0]\n" - "| FunctionCall [$first]\n" - "| Variable [scan_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByProj_1]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [year]\n" - "| PathIdentity []\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByProj_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [isin]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, GroupEvalNoInline) { - ABT translated = translatePipeline("[{$group: {_id: null, a: {$first: '$b'}}}]"); - - PrefixId prefixId; - std::string scanDefName = "collection"; - OptPhaseManager phaseManager(OptPhaseManager::getAllRewritesSet(), - prefixId, - {{{scanDefName, ScanDefinition{{}, {}}}}}, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - // Verify that "b" is not inlined in the group expression, but is coming from the physical scan. - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | agg_project_0\n" - "| RefBlock: \n" - "| Variable [agg_project_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [agg_project_0]\n" - "| Let [inputField_1]\n" - "| | If []\n" - "| | | | Variable [inputField_1]\n" - "| | | FunctionCall [setField]\n" - "| | | | | Variable [a_agg_0]\n" - "| | | | Const [\"a\"]\n" - "| | | Variable [inputField_1]\n" - "| | BinaryOp [Or]\n" - "| | | FunctionCall [isObject]\n" - "| | | Variable [inputField_1]\n" - "| | FunctionCall [exists]\n" - "| | Variable [a_agg_0]\n" - "| If []\n" - "| | | Const [{}]\n" - "| | FunctionCall [setField]\n" - "| | | | Variable [groupByProj_0]\n" - "| | | Const [\"_id\"]\n" - "| | Const [{}]\n" - "| BinaryOp [Or]\n" - "| | FunctionCall [isObject]\n" - "| | Const [{}]\n" - "| FunctionCall [exists]\n" - "| Variable [groupByProj_0]\n" - "GroupBy []\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [groupByProj_0]\n" - "| aggregations: \n" - "| [a_agg_0]\n" - "| FunctionCall [$first]\n" - "| Variable [groupByInputProj_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByProj_0]\n" - "| Const [null]\n" - "PhysicalScan [{'b': groupByInputProj_0}, collection]\n" - " BindBlock:\n" - " [groupByInputProj_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, ArrayExpr) { - ABT translated = translatePipeline("[{$project: {a: ['$b', '$c']}}]"); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathDefault []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [a]\n" - "| | PathConstant []\n" - "| | Variable [projGetPath_0]\n" - "| PathKeep [_id, a]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projGetPath_0]\n" - "| FunctionCall [newArray]\n" - "| | EvalPath []\n" - "| | | Variable [scan_0]\n" - "| | PathGet [c]\n" - "| | PathIdentity []\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Scan [collection]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, Union) { - PrefixId prefixId; - std::string scanDefA = "collA"; - std::string scanDefB = "collB"; - - Metadata metadata{{{scanDefA, {}}, {scanDefB, {}}}}; - ABT translated = translatePipeline(metadata, - "[{$unionWith: 'collB'}, {$match: {_id: 1}}]", - prefixId.getNextId("scan"), - scanDefA, - prefixId, - {{NamespaceString("a." + scanDefB), {}}}); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [_id]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [1]\n" - "Union []\n" - "| | BindBlock:\n" - "| | [scan_0]\n" - "| | Source []\n" - "| Evaluation []\n" - "| | BindBlock:\n" - "| | [scan_0]\n" - "| | EvalPath []\n" - "| | | Variable [scan_1]\n" - "| | PathIdentity []\n" - "| Scan [collB]\n" - "| BindBlock:\n" - "| [scan_1]\n" - "| Source []\n" - "Scan [collA]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); - - OptPhaseManager phaseManager( - {OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - {{{scanDefA, ScanDefinition{{}, {}}}, {scanDefB, ScanDefinition{{}, {}}}}}, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - // Note that the optimized ABT will show the filter push-down. - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Union []\n" - "| | BindBlock:\n" - "| | [scan_0]\n" - "| | Source []\n" - "| Filter []\n" - "| | EvalFilter []\n" - "| | | Variable [scan_0]\n" - "| | PathGet [_id]\n" - "| | PathTraverse [1]\n" - "| | PathCompare [Eq]\n" - "| | Const [1]\n" - "| Evaluation []\n" - "| | BindBlock:\n" - "| | [scan_0]\n" - "| | EvalPath []\n" - "| | | Variable [scan_1]\n" - "| | PathIdentity []\n" - "| PhysicalScan [{'<root>': scan_1}, collB]\n" - "| BindBlock:\n" - "| [scan_1]\n" - "| Source []\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [evalTemp_0]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [1]\n" - "PhysicalScan [{'<root>': scan_0, '_id': evalTemp_0}, collA]\n" - " BindBlock:\n" - " [evalTemp_0]\n" - " Source []\n" - " [scan_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, PartialIndex) { - PrefixId prefixId; - std::string scanDefName = "collection"; - ProjectionName scanProjName = prefixId.getNextId("scan"); - - // The expression matches the pipeline. - // By default the constant is translated as "int32". - auto conversionResult = convertExprToPartialSchemaReq( - make<EvalFilter>( - make<PathGet>("b", - make<PathTraverse>(make<PathCompare>(Operations::Eq, Constant::int32(2)), - PathTraverse::kSingleLevel)), - make<Variable>(scanProjName)), - true /*isFilterContext*/, - {} /*pathToInterval*/); - ASSERT_TRUE(conversionResult.has_value()); - ASSERT_FALSE(conversionResult->_retainPredicate); - - Metadata metadata = { - {{scanDefName, - ScanDefinition{{}, - {{"index1", - IndexDefinition{{{makeIndexPath("a"), CollationOp::Ascending}}, - true /*multiKey*/, - {DistributionType::Centralized}, - std::move(conversionResult->_reqMap)}}}}}}}; - - ABT translated = translatePipeline( - metadata, "[{$match: {'a': 3, 'b': 2}}]", scanProjName, scanDefName, prefixId); - - OptPhaseManager phaseManager( - OptPhaseManager::getAllRewritesSet(), prefixId, metadata, DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "BinaryJoin [joinType: Inner, {rid_0}]\n" - "| | Const [true]\n" - "| Filter []\n" - "| | FunctionCall [traverseF]\n" - "| | | | Const [false]\n" - "| | | LambdaAbstraction [valCmp_0]\n" - "| | | BinaryOp [Eq]\n" - "| | | | Const [2]\n" - "| | | Variable [valCmp_0]\n" - "| | Variable [evalTemp_4]\n" - "| LimitSkip []\n" - "| | limitSkip:\n" - "| | limit: 1\n" - "| | skip: 0\n" - "| Seek [ridProjection: rid_0, {'<root>': scan_0, 'b': evalTemp_4}, collection]\n" - "| | BindBlock:\n" - "| | [evalTemp_4]\n" - "| | Source []\n" - "| | [scan_0]\n" - "| | Source []\n" - "| RefBlock: \n" - "| Variable [rid_0]\n" - "IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: " - "{[Const [3], Const [3]]}]\n" - " BindBlock:\n" - " [rid_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, PartialIndexNegative) { - PrefixId prefixId; - std::string scanDefName = "collection"; - ProjectionName scanProjName = prefixId.getNextId("scan"); - - // The expression does not match the pipeline. - auto conversionResult = convertExprToPartialSchemaReq( - make<EvalFilter>( - make<PathGet>("b", - make<PathTraverse>(make<PathCompare>(Operations::Eq, Constant::int32(2)), - PathTraverse::kSingleLevel)), - make<Variable>(scanProjName)), - true /*isFilterContext*/, - {} /*pathToInterval*/); - ASSERT_TRUE(conversionResult.has_value()); - ASSERT_FALSE(conversionResult->_retainPredicate); - - Metadata metadata = { - {{scanDefName, - ScanDefinition{{}, - {{"index1", - IndexDefinition{{{makeIndexPath("a"), CollationOp::Ascending}}, - true /*multiKey*/, - {DistributionType::Centralized}, - std::move(conversionResult->_reqMap)}}}}}}}; - - ABT translated = translatePipeline( - metadata, "[{$match: {'a': 3, 'b': 3}}]", scanProjName, scanDefName, prefixId); - - OptPhaseManager phaseManager( - OptPhaseManager::getAllRewritesSet(), prefixId, metadata, DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| FunctionCall [traverseF]\n" - "| | | Const [false]\n" - "| | LambdaAbstraction [valCmp_1]\n" - "| | BinaryOp [Eq]\n" - "| | | Const [3]\n" - "| | Variable [valCmp_1]\n" - "| Variable [evalTemp_3]\n" - "Filter []\n" - "| FunctionCall [traverseF]\n" - "| | | Const [false]\n" - "| | LambdaAbstraction [valCmp_0]\n" - "| | BinaryOp [Eq]\n" - "| | | Const [3]\n" - "| | Variable [valCmp_0]\n" - "| Variable [evalTemp_2]\n" - "PhysicalScan [{'<root>': scan_0, 'a': evalTemp_2, 'b': evalTemp_3}, collection]\n" - " BindBlock:\n" - " [evalTemp_2]\n" - " Source []\n" - " [evalTemp_3]\n" - " Source []\n" - " [scan_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, CommonExpressionElimination) { - PrefixId prefixId; - Metadata metadata = {{{"test", {{}, {}}}}}; - - auto rootNode = - translatePipeline(metadata, - "[{$project: {foo: {$add: ['$b', 1]}, bar: {$add: ['$b', 1]}}}]", - "test", - prefixId); - - OptPhaseManager phaseManager( - {OptPhase::ConstEvalPre}, prefixId, metadata, DebugInfo::kDefaultForTests); - - phaseManager.optimize(rootNode); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_0\n" - "| RefBlock: \n" - "| Variable [combinedProjection_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_0]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathComposeM []\n" - "| | PathDefault []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [foo]\n" - "| | PathConstant []\n" - "| | Variable [projGetPath_0]\n" - "| PathComposeM []\n" - "| | PathField [bar]\n" - "| | PathConstant []\n" - "| | Variable [projGetPath_0]\n" - "| PathKeep [_id, bar, foo]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [projGetPath_0]\n" - "| BinaryOp [Add]\n" - "| | Const [1]\n" - "| EvalPath []\n" - "| | Variable [scan_0]\n" - "| PathGet [b]\n" - "| PathIdentity []\n" - "Scan [test]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - rootNode); -} - -TEST(ABTTranslate, GroupByDependency) { - PrefixId prefixId; - Metadata metadata = {{{"test", {{}, {}}}}}; - - ABT translated = - translatePipeline(metadata, - "[{$group: {_id: {}, b: {$addToSet: '$a'}}}, {$project: " - "{_id: 0, b: {$size: '$b'}}}, {$project: {_id: 0, c: '$b'}}]", - "test", - prefixId); - - OptPhaseManager phaseManager({OptPhase::ConstEvalPre, - OptPhase::PathFuse, - OptPhase::MemoSubstitutionPhase, - OptPhase::MemoExplorationPhase, - OptPhase::MemoImplementationPhase}, - prefixId, - metadata, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - // Demonstrate that "c" is set to the array size (not the array itself coming from the group). - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | combinedProjection_1\n" - "| RefBlock: \n" - "| Variable [combinedProjection_1]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [combinedProjection_1]\n" - "| EvalPath []\n" - "| | Const [{}]\n" - "| PathComposeM []\n" - "| | PathField [c]\n" - "| | PathConstant []\n" - "| | FunctionCall [getArraySize]\n" - "| | Variable [b_agg_0]\n" - "| PathKeep []\n" - "GroupBy []\n" - "| | groupings: \n" - "| | RefBlock: \n" - "| | Variable [groupByProj_0]\n" - "| aggregations: \n" - "| [b_agg_0]\n" - "| FunctionCall [$addToSet]\n" - "| Variable [groupByInputProj_0]\n" - "Evaluation []\n" - "| BindBlock:\n" - "| [groupByProj_0]\n" - "| Const [{}]\n" - "PhysicalScan [{'a': groupByInputProj_0}, test]\n" - " BindBlock:\n" - " [groupByInputProj_0]\n" - " Source []\n", - optimized); -} - -TEST(ABTTranslate, NotEquals) { - PrefixId prefixId; - Metadata metadata = {{{"test", {{}, {}}}}}; - - ABT translated = translatePipeline(metadata, "[{$match: {'a': {$ne: 2}}}]", "test", prefixId); - - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Filter []\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathConstant []\n" - "| UnaryOp [Not]\n" - "| EvalFilter []\n" - "| | Variable [scan_0]\n" - "| PathGet [a]\n" - "| PathTraverse [1]\n" - "| PathCompare [Eq]\n" - "| Const [2]\n" - "Scan [test]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - translated); -} - -TEST(ABTTranslate, DoubleElemMatch) { - PrefixId prefixId; - Metadata metadata = {{{"test", {{}, {}}}}}; - - ABT translated = translatePipeline( - metadata, - "[{$match: {a: {$elemMatch: {$gte: 5, $lte: 6}}, b: {$elemMatch: {$gte: 1, $lte: 3}}}}]", - "test", - prefixId); - - OptPhaseManager phaseManager({OptPhase::MemoSubstitutionPhase}, - prefixId, - false /*requireRID*/, - metadata, - std::make_unique<HeuristicCE>(), - std::make_unique<DefaultCosting>(), - defaultConvertPathToInterval, - DebugInfo::kDefaultForTests); - - ABT optimized = translated; - phaseManager.optimize(optimized); - - // Demonstrate we get a single Sargable node which encodes both predicates. - ASSERT_EXPLAIN_V2( - "Root []\n" - "| | projections: \n" - "| | scan_0\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Sargable [Complete]\n" - "| | | | | requirementsMap: \n" - "| | | | | refProjection: scan_0, path: 'PathGet [a] PathIdentity []', " - "intervals: {{{[Const [[]], Const [BinData(0, )])}}}\n" - "| | | | | refProjection: scan_0, path: 'PathGet [a] PathTraverse [1] " - "PathIdentity []', intervals: {{{[Const [5], Const [6]]}}}\n" - "| | | | | refProjection: scan_0, path: 'PathGet [b] PathIdentity []', " - "intervals: {{{[Const [[]], Const [BinData(0, )])}}}\n" - "| | | | | refProjection: scan_0, path: 'PathGet [b] PathTraverse [1] " - "PathIdentity []', intervals: {{{[Const [1], Const [3]]}}}\n" - "| | | | candidateIndexes: \n" - "| | | scanParams: \n" - "| | | {'a': evalTemp_7, 'b': evalTemp_8}\n" - "| | | residualReqs: \n" - "| | | refProjection: evalTemp_7, path: 'PathIdentity []', intervals: " - "{{{[Const [[]], Const [BinData(0, )])}}}, entryIndex: 0\n" - "| | | refProjection: evalTemp_7, path: 'PathTraverse [1] PathIdentity " - "[]', intervals: {{{[Const [5], Const [6]]}}}, entryIndex: 1\n" - "| | | refProjection: evalTemp_8, path: 'PathIdentity []', intervals: " - "{{{[Const [[]], Const [BinData(0, )])}}}, entryIndex: 2\n" - "| | | refProjection: evalTemp_8, path: 'PathTraverse [1] PathIdentity " - "[]', intervals: {{{[Const [1], Const [3]]}}}, entryIndex: 3\n" - "| | BindBlock:\n" - "| RefBlock: \n" - "| Variable [scan_0]\n" - "Scan [test]\n" - " BindBlock:\n" - " [scan_0]\n" - " Source []\n", - optimized); -} - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/pipeline/abt/abt_translation_test.cpp b/src/mongo/db/pipeline/abt/abt_translation_test.cpp new file mode 100644 index 00000000000..c64479e1354 --- /dev/null +++ b/src/mongo/db/pipeline/abt/abt_translation_test.cpp @@ -0,0 +1,174 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/db/pipeline/abt/utils.h" +#include "mongo/db/query/optimizer/explain.h" +#include "mongo/db/query/optimizer/utils/unit_test_utils.h" +#include "mongo/unittest/golden_test.h" + +namespace mongo::optimizer { + +unittest::GoldenTestConfig goldenTestConfigABTTranslation{"src/mongo/db/test_output/pipeline/abt"}; + +TEST(ABTTranslate, BasicTests) { + unittest::GoldenTestContext gctx(&goldenTestConfigABTTranslation); + + testABTTranslationAndOptimization( + gctx, "$match with $in, empty list", "[{$match: {a: {$in: []}}}]"); + + testABTTranslationAndOptimization( + gctx, "match with $in, singleton list", "[{$match: {a: {$in: [1]}}}]"); + + testABTTranslationAndOptimization( + gctx, + "$match with $in and a list of equalities becomes a comparison to an EqMember list.", + "[{$match: {a: {$in: [1, 2, 3]}}}]"); + + testABTTranslationAndOptimization(gctx, + "match with $in over an array, duplicated equalities removed", + "[{$match: {a: {$in: ['abc', 'def', 'ghi', 'def']}}}]"); + + + testABTTranslationAndOptimization( + gctx, "$match with empty $elemMatch", "[{$match: {'a': {$elemMatch: {}}}}]"); + + testABTTranslationAndOptimization( + gctx, + "ensure the PathGet and PathTraverse operators interact correctly when $in is " + "under $elemMatch", + "[{$match: {'a.b': {$elemMatch: {$in: [1, 2, 3]}}}}]"); + + testABTTranslationAndOptimization( + gctx, "sort limit skip", "[{$limit: 5}, {$skip: 3}, {$sort: {a: 1, b: -1}}]"); + + testABTTranslationAndOptimization( + gctx, "inclusion project", "[{$project: {a1: 1, a2: 1, a3: 1, a4: 1, a5: 1, a6: 1}}]"); + + testABTTranslationAndOptimization( + gctx, + "project rename through addFields: since '$z' is a single element, it will be " + "considered a renamed path", + "[{$addFields: {a: '$z'}}]"); + + testABTTranslationAndOptimization( + gctx, + "project rename: since '$c' is a single element, it will be considered a renamed path", + "[{$project: {'a.b': '$c'}}]"); + + testABTTranslationAndOptimization( + gctx, "project rename dotted paths", "[{$project: {'a.b.c': '$x.y.z'}}]"); + + testABTTranslationAndOptimization( + gctx, "inclusion project dotted paths", "[{$project: {'a.b':1, 'a.c':1, 'b':1}}]"); + + testABTTranslationAndOptimization(gctx, + "inclusion project with computed field", + "[{$project: {a: {$add: ['$c.d', 2]}, b: 1}}]"); + + testABTTranslationAndOptimization(gctx, "exclusion project", "[{$project: {a: 0, b: 0}}]"); + + testABTTranslationAndOptimization(gctx, "replaceRoot", "[{$replaceRoot: {newRoot: '$a'}}]"); + + testABTTranslationAndOptimization(gctx, "$match basic", "[{$match: {a: 1, b: 2}}]"); + + testABTTranslationAndOptimization( + gctx, "$match with $expr $eq", "[{$match: {$expr: {$eq: ['$a', 1]}}}]"); + + testABTTranslationAndOptimization( + gctx, "$match with $expr $eq with dotted path", "[{$match: {$expr: {$eq: ['$a.b', 1]}}}]"); + + testABTTranslationAndOptimization( + gctx, + "$match with value $elemMatch: observe type bracketing in the filter.", + "[{$project: {a: {$literal: [1, 2, 3, 4]}}}, {$match: {a: {$elemMatch: {$gte: 2, $lte: " + "3}}}}]"); + + testABTTranslationAndOptimization( + gctx, + "$project then $match", + "[{$project: {s: {$add: ['$a', '$b']}, c: 1}}, {$match: {$or: [{c: 2}, {s: {$gte: " + "10}}]}}]"); + + testABTTranslationAndOptimization( + gctx, "$project with deeply nested path", "[{$project: {'a1.b.c':1, 'a.b.c.d.e':'str'}}]"); + + testABTTranslationAndOptimization( + gctx, "basic $group", "[{$group: {_id: '$a.b', s: {$sum: {$multiply: ['$b', '$c']}}}}]"); + + testABTTranslationAndOptimization( + gctx, "$group local global", "[{$group: {_id: '$a', c: {$sum: '$b'}}}]"); + + testABTTranslationAndOptimization(gctx, "basic $unwind", "[{$unwind: {path: '$a.b.c'}}]"); + + testABTTranslationAndOptimization( + gctx, + "complex $unwind", + "[{$unwind: {path: '$a.b.c', includeArrayIndex: 'p1.pid', preserveNullAndEmptyArrays: " + "true}}]"); + + testABTTranslationAndOptimization( + gctx, + "$unwind with $group", + "[{$unwind:{path: '$a.b', preserveNullAndEmptyArrays: true}}, {$group:{_id: '$a.b'}}]"); + + testABTTranslationAndOptimization(gctx, "$match with index", "[{$match: {'a': 10}}]"); + + testABTTranslationAndOptimization( + gctx, "$match sort index", "[{$match: {'a': 10}}, {$sort: {'a': 1}}]"); + + testABTTranslationAndOptimization( + gctx, "$match with range", "[{$match: {'a': {$gt: 70, $lt: 90}}}]"); + + testABTTranslationAndOptimization(gctx, "index on two keys", "[{$match: {'a': 2, 'b': 2}}]"); + + testABTTranslationAndOptimization( + gctx, + "$group with complex _id", + "[{$group: {_id: {'isin': '$isin', 'year': '$year'}, 'count': {$sum: 1}, 'open': {$first: " + "'$$ROOT'}}}]"); + + testABTTranslationAndOptimization( + gctx, "$project with computed array", "[{$project: {a: ['$b', '$c']}}]"); + + std::string scanDefA = "collA"; + std::string scanDefB = "collB"; + Metadata metadataUnion{{{scanDefA, {}}, {scanDefB, {}}}}; + testABTTranslationAndOptimization(gctx, + "union", + "[{$unionWith: 'collB'}, {$match: {_id: 1}}]", + scanDefA, + {}, + metadataUnion, + {}, + false, + {{NamespaceString("a." + scanDefB), {}}}); + + testABTTranslationAndOptimization(gctx, "$match with $ne", "[{$match: {'a': {$ne: 2}}}]"); +} +} // namespace mongo::optimizer diff --git a/src/mongo/db/query/optimizer/utils/unit_test_utils.cpp b/src/mongo/db/query/optimizer/utils/unit_test_utils.cpp index 1bd82ce80f5..c060535acf6 100644 --- a/src/mongo/db/query/optimizer/utils/unit_test_utils.cpp +++ b/src/mongo/db/query/optimizer/utils/unit_test_utils.cpp @@ -156,4 +156,177 @@ ABT translatePipeline(const std::string& pipelineStr, std::string scanDefName) { return translatePipeline(metadata, pipelineStr, std::move(scanDefName), prefixId); } +void serializeOptPhases(std::ostream& stream, opt::unordered_set<OptPhase> phaseSet) { + // The order of phases in the golden file must be the same every time the test is run. + std::set<std::string> orderedPhases; + for (const auto& phase : phaseSet) { + orderedPhases.insert(OptPhaseEnum::toString[static_cast<int>(phase)]); + } + + stream << "optimization phases: " << std::endl; + for (const auto& phase : orderedPhases) { + stream << "\t" << phase << std::endl; + } +} + +void explainPreserveIndentation(std::ostream& stream, std::string baseTabs, std::string explain) { + std::string currLine = ""; + for (char ch : explain) { + if (ch == '\n') { + stream << baseTabs << currLine << std::endl; + currLine = ""; + } else { + currLine += ch; + } + } + stream << std::endl; +} + +void serializeDistributionAndPaths(std::ostream& stream, + DistributionAndPaths distributionAndPaths, + std::string baseTabs) { + stream << baseTabs << "distribution and paths: " << std::endl; + stream << baseTabs << "\tdistribution type: " + << DistributionTypeEnum::toString[static_cast<int>(distributionAndPaths._type)] + << std::endl; + stream << baseTabs << "\tdistribution paths: " << std::endl; + for (const ABT& abt : distributionAndPaths._paths) { + explainPreserveIndentation(stream, baseTabs + "\t\t", ExplainGenerator::explainV2(abt)); + } +} + +void serializeMetadata(std::ostream& stream, Metadata metadata) { + stream << "metadata: " << std::endl; + + stream << "\tnumber of partitions: " << metadata._numberOfPartitions << std::endl; + + // The ScanDefinitions are stored in an unordered map, and the order of the ScanDefinitions in + // the golden file must be the same every time the test is run. + std::map<std::string, ScanDefinition> orderedScanDefs; + for (auto element : metadata._scanDefs) { + orderedScanDefs.insert(element); + } + + stream << "\tscan definitions: " << std::endl; + for (const auto& element : orderedScanDefs) { + stream << "\t\t" << element.first << ": " << std::endl; + + ScanDefinition scanDef = element.second; + + stream << "\t\t\toptions: " << std::endl; + for (const auto& optionElem : scanDef.getOptionsMap()) { + stream << "\t\t\t\t" << optionElem.first << ": " << optionElem.second << std::endl; + } + + serializeDistributionAndPaths(stream, scanDef.getDistributionAndPaths(), "\t\t\t"); + + stream << "\t\t\tindexes: " << std::endl; + for (const auto& indexElem : scanDef.getIndexDefs()) { + stream << "\t\t\t\t" << indexElem.first << ": " << std::endl; + + IndexDefinition indexDef = indexElem.second; + + stream << "\t\t\t\t\tcollation spec: " << std::endl; + for (const auto& indexCollationEntry : indexDef.getCollationSpec()) { + stream << "\t\t\t\t\t\tABT path: " << std::endl; + explainPreserveIndentation(stream, + "\t\t\t\t\t\t\t", + ExplainGenerator::explainV2(indexCollationEntry._path)); + + stream << "\t\t\t\t\t\tcollation op: " + << CollationOpEnum::toString[static_cast<int>(indexCollationEntry._op)] + << std::endl; + } + + stream << "\t\t\t\t\tversion: " << indexDef.getVersion() << std::endl; + stream << "\t\t\t\t\tordering bits: " << indexDef.getOrdering() << std::endl; + stream << "\t\t\t\t\tis multi-key: " << indexDef.isMultiKey() << std::endl; + + serializeDistributionAndPaths(stream, indexDef.getDistributionAndPaths(), "\t\t\t\t\t"); + + std::string serializedReqMap = + ExplainGenerator::explainPartialSchemaReqMap(indexDef.getPartialReqMap()); + explainPreserveIndentation(stream, "\t\t\t\t\t", serializedReqMap); + } + + stream << "\t\t\tnon multi-key index paths: " << std::endl; + for (const auto& indexPath : scanDef.getNonMultiKeyPathSet()) { + explainPreserveIndentation(stream, "\t\t\t\t", ExplainGenerator::explainV2(indexPath)); + } + + stream << "\t\t\tcollection exists: " << scanDef.exists() << std::endl; + stream << "\t\t\tCE type: " << scanDef.getCE() << std::endl; + } +} + +ABT translatetoABT(const std::string& pipelineStr, + std::string scanDefName, + Metadata metadata, + const std::vector<ExpressionContext::ResolvedNamespace>& involvedNss) { + PrefixId prefixId; + return translatePipeline( + metadata, pipelineStr, prefixId.getNextId("scan"), scanDefName, prefixId, involvedNss); +} + +ABT optimizeABT(ABT abt, + opt::unordered_set<OptPhase> phaseSet, + Metadata metadata, + PathToIntervalFn pathToInterval, + bool phaseManagerDisableScan) { + PrefixId prefixId; + + OptPhaseManager phaseManager(phaseSet, + prefixId, + false, + metadata, + std::make_unique<HeuristicCE>(), + std::make_unique<DefaultCosting>(), + pathToInterval, + DebugInfo::kDefaultForTests); + if (phaseManagerDisableScan) { + phaseManager.getHints()._disableScan = true; + } + + ABT optimized = abt; + phaseManager.optimize(optimized); + return optimized; +} + +void testABTTranslationAndOptimization( + unittest::GoldenTestContext& gctx, + const std::string& variationName, + const std::string& pipelineStr, + std::string scanDefName, + opt::unordered_set<OptPhase> phaseSet, + Metadata metadata, + PathToIntervalFn pathToInterval, + bool phaseManagerDisableScan, + const std::vector<ExpressionContext::ResolvedNamespace>& involvedNss) { + auto& stream = gctx.outStream(); + bool optimizePipeline = !phaseSet.empty(); + + stream << "==== VARIATION: " << variationName << " ====" << std::endl; + stream << "-- INPUTS:" << std::endl; + stream << "pipeline: " << pipelineStr << std::endl; + + serializeMetadata(stream, metadata); + if (optimizePipeline) { + serializeOptPhases(stream, phaseSet); + } + + stream << std::endl << "-- OUTPUT:" << std::endl; + + ABT translated = translatetoABT(pipelineStr, scanDefName, metadata, involvedNss); + + if (optimizePipeline) { + ABT optimized = + optimizeABT(translated, phaseSet, metadata, pathToInterval, phaseManagerDisableScan); + stream << ExplainGenerator::explainV2(optimized) << std::endl; + } else { + stream << ExplainGenerator::explainV2(translated) << std::endl; + } + + stream << std::endl; +} + } // namespace mongo::optimizer diff --git a/src/mongo/db/query/optimizer/utils/unit_test_utils.h b/src/mongo/db/query/optimizer/utils/unit_test_utils.h index f25df1a11b0..1183c3e7859 100644 --- a/src/mongo/db/query/optimizer/utils/unit_test_utils.h +++ b/src/mongo/db/query/optimizer/utils/unit_test_utils.h @@ -33,9 +33,12 @@ #include "mongo/db/operation_context_noop.h" #include "mongo/db/pipeline/expression_context_for_test.h" #include "mongo/db/pipeline/pipeline.h" +#include "mongo/db/query/optimizer/cascades/cost_derivation.h" #include "mongo/db/query/optimizer/defs.h" #include "mongo/db/query/optimizer/metadata.h" +#include "mongo/db/query/optimizer/opt_phase_manager.h" #include "mongo/db/query/optimizer/utils/utils.h" +#include "mongo/unittest/golden_test.h" namespace mongo::optimizer { @@ -107,4 +110,20 @@ ABT translatePipeline(Metadata& metadata, ABT translatePipeline(const std::string& pipelineStr, std::string scanDefName = "collection"); +/** + * This function translates the given pipeline string to an ABT and (if optimization phases are + * provided) optimizes the ABT using the parameters specified. It then writes the output to a file + * that will be compared to the golden testing file for the test file. + **/ +void testABTTranslationAndOptimization( + unittest::GoldenTestContext& gctx, + const std::string& variationName, + const std::string& pipelineStr, + std::string scanDefName = "collection", + opt::unordered_set<OptPhase> phaseSet = {}, + Metadata metadata = {{{"collection", ScanDefinition{{}, {}}}}}, + PathToIntervalFn pathToInterval = {}, + bool phaseManagerDisableScan = false, + const std::vector<ExpressionContext::ResolvedNamespace>& involvedNss = {}); + } // namespace mongo::optimizer diff --git a/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/basic_tests.txt b/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/basic_tests.txt new file mode 100644 index 00000000000..b13052e048a --- /dev/null +++ b/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/basic_tests.txt @@ -0,0 +1,1686 @@ +==== VARIATION: $match with $in, empty list ==== +-- INPUTS: +pipeline: [{$match: {a: {$in: []}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathConstant [] +| Const [false] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: match with $in, singleton list ==== +-- INPUTS: +pipeline: [{$match: {a: {$in: [1]}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [Eq] +| Const [1] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match with $in and a list of equalities becomes a comparison to an EqMember list. ==== +-- INPUTS: +pipeline: [{$match: {a: {$in: [1, 2, 3]}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [EqMember] +| Const [[1, 2, 3]] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: match with $in over an array, duplicated equalities removed ==== +-- INPUTS: +pipeline: [{$match: {a: {$in: ['abc', 'def', 'ghi', 'def']}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [EqMember] +| Const [["abc", "def", "ghi"]] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match with empty $elemMatch ==== +-- INPUTS: +pipeline: [{$match: {'a': {$elemMatch: {}}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathComposeM [] +| | PathArr [] +| PathTraverse [1] +| PathComposeM [] +| | PathComposeA [] +| | | PathArr [] +| | PathObj [] +| PathConstant [] +| Const [true] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: ensure the PathGet and PathTraverse operators interact correctly when $in is under $elemMatch ==== +-- INPUTS: +pipeline: [{$match: {'a.b': {$elemMatch: {$in: [1, 2, 3]}}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathGet [b] +| PathComposeM [] +| | PathArr [] +| PathTraverse [1] +| PathCompare [EqMember] +| Const [[1, 2, 3]] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: sort limit skip ==== +-- INPUTS: +pipeline: [{$limit: 5}, {$skip: 3}, {$sort: {a: 1, b: -1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Collation [] +| | collation: +| | sort_0: Ascending +| | sort_1: Descending +| RefBlock: +| Variable [sort_0] +| Variable [sort_1] +Evaluation [] +| BindBlock: +| [sort_1] +| EvalPath [] +| | Variable [scan_0] +| PathGet [b] +| PathIdentity [] +Evaluation [] +| BindBlock: +| [sort_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathIdentity [] +LimitSkip [] +| limitSkip: +| limit: (none) +| skip: 3 +LimitSkip [] +| limitSkip: +| limit: 5 +| skip: 0 +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: inclusion project ==== +-- INPUTS: +pipeline: [{$project: {a1: 1, a2: 1, a3: 1, a4: 1, a5: 1, a6: 1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathKeep [_id, a1, a2, a3, a4, a5, a6] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: project rename through addFields: since '$z' is a single element, it will be considered a renamed path ==== +-- INPUTS: +pipeline: [{$addFields: {a: '$z'}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathDefault [] +| | Const [{}] +| PathField [a] +| PathConstant [] +| Variable [projRenamedPath_0] +Evaluation [] +| BindBlock: +| [projRenamedPath_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [z] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: project rename: since '$c' is a single element, it will be considered a renamed path ==== +-- INPUTS: +pipeline: [{$project: {'a.b': '$c'}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathField [a] +| | PathTraverse [inf] +| | PathComposeM [] +| | | PathDefault [] +| | | Const [{}] +| | PathComposeM [] +| | | PathField [b] +| | | PathConstant [] +| | | Variable [projRenamedPath_0] +| | PathKeep [b] +| PathKeep [_id, a] +Evaluation [] +| BindBlock: +| [projRenamedPath_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [c] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: project rename dotted paths ==== +-- INPUTS: +pipeline: [{$project: {'a.b.c': '$x.y.z'}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathField [a] +| | PathTraverse [inf] +| | PathComposeM [] +| | | PathField [b] +| | | PathTraverse [inf] +| | | PathComposeM [] +| | | | PathDefault [] +| | | | Const [{}] +| | | PathComposeM [] +| | | | PathField [c] +| | | | PathConstant [] +| | | | Variable [projGetPath_0] +| | | PathKeep [c] +| | PathKeep [b] +| PathKeep [_id, a] +Evaluation [] +| BindBlock: +| [projGetPath_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [x] +| PathTraverse [inf] +| PathGet [y] +| PathTraverse [inf] +| PathGet [z] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: inclusion project dotted paths ==== +-- INPUTS: +pipeline: [{$project: {'a.b':1, 'a.c':1, 'b':1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathField [a] +| | PathTraverse [inf] +| | PathComposeM [] +| | | PathKeep [b, c] +| | PathObj [] +| PathKeep [_id, a, b] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: inclusion project with computed field ==== +-- INPUTS: +pipeline: [{$project: {a: {$add: ['$c.d', 2]}, b: 1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathDefault [] +| | Const [{}] +| PathComposeM [] +| | PathField [a] +| | PathConstant [] +| | Variable [projGetPath_0] +| PathKeep [_id, a, b] +Evaluation [] +| BindBlock: +| [projGetPath_0] +| BinaryOp [Add] +| | Const [2] +| EvalPath [] +| | Variable [scan_0] +| PathGet [c] +| PathTraverse [inf] +| PathGet [d] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: exclusion project ==== +-- INPUTS: +pipeline: [{$project: {a: 0, b: 0}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathDrop [a, b] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: replaceRoot ==== +-- INPUTS: +pipeline: [{$replaceRoot: {newRoot: '$a'}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | newRoot_0 +| RefBlock: +| Variable [newRoot_0] +Evaluation [] +| BindBlock: +| [newRoot_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match basic ==== +-- INPUTS: +pipeline: [{$match: {a: 1, b: 2}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [Eq] +| Const [1] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [b] +| PathTraverse [1] +| PathCompare [Eq] +| Const [2] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match with $expr $eq ==== +-- INPUTS: +pipeline: [{$match: {$expr: {$eq: ['$a', 1]}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathCompare [Eq] +| Const [1] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match with $expr $eq with dotted path ==== +-- INPUTS: +pipeline: [{$match: {$expr: {$eq: ['$a.b', 1]}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathConstant [] +| BinaryOp [Eq] +| | Const [1] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [inf] +| PathGet [b] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match with value $elemMatch: observe type bracketing in the filter. ==== +-- INPUTS: +pipeline: [{$project: {a: {$literal: [1, 2, 3, 4]}}}, {$match: {a: {$elemMatch: {$gte: 2, $lte: 3}}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Filter [] +| EvalFilter [] +| | Variable [combinedProjection_0] +| PathGet [a] +| PathComposeM [] +| | PathArr [] +| PathTraverse [1] +| PathComposeM [] +| | PathComposeM [] +| | | PathCompare [Lt] +| | | Const [""] +| | PathCompare [Gte] +| | Const [2] +| PathComposeM [] +| | PathCompare [Gte] +| | Const [nan] +| PathCompare [Lte] +| Const [3] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathDefault [] +| | Const [{}] +| PathComposeM [] +| | PathField [a] +| | PathConstant [] +| | Variable [projGetPath_0] +| PathKeep [_id, a] +Evaluation [] +| BindBlock: +| [projGetPath_0] +| Const [[1, 2, 3, 4]] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $project then $match ==== +-- INPUTS: +pipeline: [{$project: {s: {$add: ['$a', '$b']}, c: 1}}, {$match: {$or: [{c: 2}, {s: {$gte: 10}}]}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Filter [] +| EvalFilter [] +| | Variable [combinedProjection_0] +| PathComposeA [] +| | PathGet [c] +| | PathTraverse [1] +| | PathCompare [Eq] +| | Const [2] +| PathGet [s] +| PathTraverse [1] +| PathComposeM [] +| | PathCompare [Lt] +| | Const [""] +| PathCompare [Gte] +| Const [10] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathDefault [] +| | Const [{}] +| PathComposeM [] +| | PathField [s] +| | PathConstant [] +| | Variable [projGetPath_0] +| PathKeep [_id, c, s] +Evaluation [] +| BindBlock: +| [projGetPath_0] +| BinaryOp [Add] +| | EvalPath [] +| | | Variable [scan_0] +| | PathGet [b] +| | PathIdentity [] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $project with deeply nested path ==== +-- INPUTS: +pipeline: [{$project: {'a1.b.c':1, 'a.b.c.d.e':'str'}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathField [a1] +| | PathTraverse [inf] +| | PathComposeM [] +| | | PathField [b] +| | | PathTraverse [inf] +| | | PathComposeM [] +| | | | PathKeep [c] +| | | PathObj [] +| | PathComposeM [] +| | | PathKeep [b] +| | PathObj [] +| PathComposeM [] +| | PathField [a] +| | PathTraverse [inf] +| | PathComposeM [] +| | | PathField [b] +| | | PathTraverse [inf] +| | | PathComposeM [] +| | | | PathField [c] +| | | | PathTraverse [inf] +| | | | PathComposeM [] +| | | | | PathField [d] +| | | | | PathTraverse [inf] +| | | | | PathComposeM [] +| | | | | | PathDefault [] +| | | | | | Const [{}] +| | | | | PathComposeM [] +| | | | | | PathField [e] +| | | | | | PathConstant [] +| | | | | | Variable [projGetPath_0] +| | | | | PathKeep [e] +| | | | PathKeep [d] +| | | PathKeep [c] +| | PathKeep [b] +| PathKeep [_id, a, a1] +Evaluation [] +| BindBlock: +| [projGetPath_0] +| Const ["str"] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: basic $group ==== +-- INPUTS: +pipeline: [{$group: {_id: '$a.b', s: {$sum: {$multiply: ['$b', '$c']}}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | agg_project_0 +| RefBlock: +| Variable [agg_project_0] +Evaluation [] +| BindBlock: +| [agg_project_0] +| EvalPath [] +| | Const [{}] +| PathComposeM [] +| | PathField [s] +| | PathConstant [] +| | Variable [s_agg_0] +| PathField [_id] +| PathConstant [] +| Variable [groupByProj_0] +GroupBy [] +| | groupings: +| | RefBlock: +| | Variable [groupByProj_0] +| aggregations: +| [s_agg_0] +| FunctionCall [$sum] +| Variable [groupByInputProj_0] +Evaluation [] +| BindBlock: +| [groupByInputProj_0] +| BinaryOp [Mult] +| | EvalPath [] +| | | Variable [scan_0] +| | PathGet [c] +| | PathIdentity [] +| EvalPath [] +| | Variable [scan_0] +| PathGet [b] +| PathIdentity [] +Evaluation [] +| BindBlock: +| [groupByProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [inf] +| PathGet [b] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $group local global ==== +-- INPUTS: +pipeline: [{$group: {_id: '$a', c: {$sum: '$b'}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | agg_project_0 +| RefBlock: +| Variable [agg_project_0] +Evaluation [] +| BindBlock: +| [agg_project_0] +| EvalPath [] +| | Const [{}] +| PathComposeM [] +| | PathField [c] +| | PathConstant [] +| | Variable [c_agg_0] +| PathField [_id] +| PathConstant [] +| Variable [groupByProj_0] +GroupBy [] +| | groupings: +| | RefBlock: +| | Variable [groupByProj_0] +| aggregations: +| [c_agg_0] +| FunctionCall [$sum] +| Variable [groupByInputProj_0] +Evaluation [] +| BindBlock: +| [groupByInputProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [b] +| PathIdentity [] +Evaluation [] +| BindBlock: +| [groupByProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: basic $unwind ==== +-- INPUTS: +pipeline: [{$unwind: {path: '$a.b.c'}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | embedProj_0 +| RefBlock: +| Variable [embedProj_0] +Evaluation [] +| BindBlock: +| [embedProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathField [a] +| PathTraverse [inf] +| PathField [b] +| PathTraverse [inf] +| PathField [c] +| PathConstant [] +| Variable [unwoundProj_0] +Unwind [] +| BindBlock: +| [unwoundPid_0] +| Source [] +| [unwoundProj_0] +| Source [] +Evaluation [] +| BindBlock: +| [unwoundProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathGet [b] +| PathGet [c] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: complex $unwind ==== +-- INPUTS: +pipeline: [{$unwind: {path: '$a.b.c', includeArrayIndex: 'p1.pid', preserveNullAndEmptyArrays: true}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | embedPidProj_0 +| RefBlock: +| Variable [embedPidProj_0] +Evaluation [] +| BindBlock: +| [embedPidProj_0] +| EvalPath [] +| | Variable [embedProj_0] +| PathField [p1] +| PathField [pid] +| PathConstant [] +| If [] +| | | Const [null] +| | Variable [unwoundPid_0] +| BinaryOp [Gte] +| | Const [0] +| Variable [unwoundPid_0] +Evaluation [] +| BindBlock: +| [embedProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathField [a] +| PathTraverse [inf] +| PathField [b] +| PathTraverse [inf] +| PathField [c] +| PathLambda [] +| LambdaAbstraction [unwoundLambdaVarName_0] +| If [] +| | | Variable [unwoundLambdaVarName_0] +| | Variable [unwoundProj_0] +| BinaryOp [Gte] +| | Const [0] +| Variable [unwoundPid_0] +Unwind [retainNonArrays] +| BindBlock: +| [unwoundPid_0] +| Source [] +| [unwoundProj_0] +| Source [] +Evaluation [] +| BindBlock: +| [unwoundProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathGet [b] +| PathGet [c] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $unwind with $group ==== +-- INPUTS: +pipeline: [{$unwind:{path: '$a.b', preserveNullAndEmptyArrays: true}}, {$group:{_id: '$a.b'}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | agg_project_0 +| RefBlock: +| Variable [agg_project_0] +Evaluation [] +| BindBlock: +| [agg_project_0] +| EvalPath [] +| | Const [{}] +| PathField [_id] +| PathConstant [] +| Variable [groupByProj_0] +GroupBy [] +| | groupings: +| | RefBlock: +| | Variable [groupByProj_0] +| aggregations: +Evaluation [] +| BindBlock: +| [groupByProj_0] +| EvalPath [] +| | Variable [embedProj_0] +| PathGet [a] +| PathTraverse [inf] +| PathGet [b] +| PathIdentity [] +Evaluation [] +| BindBlock: +| [embedProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathField [a] +| PathTraverse [inf] +| PathField [b] +| PathLambda [] +| LambdaAbstraction [unwoundLambdaVarName_0] +| If [] +| | | Variable [unwoundLambdaVarName_0] +| | Variable [unwoundProj_0] +| BinaryOp [Gte] +| | Const [0] +| Variable [unwoundPid_0] +Unwind [retainNonArrays] +| BindBlock: +| [unwoundPid_0] +| Source [] +| [unwoundProj_0] +| Source [] +Evaluation [] +| BindBlock: +| [unwoundProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathGet [b] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match with index ==== +-- INPUTS: +pipeline: [{$match: {'a': 10}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [Eq] +| Const [10] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match sort index ==== +-- INPUTS: +pipeline: [{$match: {'a': 10}}, {$sort: {'a': 1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Collation [] +| | collation: +| | sort_0: Ascending +| RefBlock: +| Variable [sort_0] +Evaluation [] +| BindBlock: +| [sort_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [a] +| PathIdentity [] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [Eq] +| Const [10] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match with range ==== +-- INPUTS: +pipeline: [{$match: {'a': {$gt: 70, $lt: 90}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathComposeM [] +| | PathCompare [Lt] +| | Const [""] +| PathCompare [Gt] +| Const [70] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathComposeM [] +| | PathCompare [Gte] +| | Const [nan] +| PathCompare [Lt] +| Const [90] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: index on two keys ==== +-- INPUTS: +pipeline: [{$match: {'a': 2, 'b': 2}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [Eq] +| Const [2] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [b] +| PathTraverse [1] +| PathCompare [Eq] +| Const [2] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $group with complex _id ==== +-- INPUTS: +pipeline: [{$group: {_id: {'isin': '$isin', 'year': '$year'}, 'count': {$sum: 1}, 'open': {$first: '$$ROOT'}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | agg_project_0 +| RefBlock: +| Variable [agg_project_0] +Evaluation [] +| BindBlock: +| [agg_project_0] +| EvalPath [] +| | Const [{}] +| PathComposeM [] +| | PathField [open] +| | PathConstant [] +| | Variable [open_agg_0] +| PathComposeM [] +| | PathField [count] +| | PathConstant [] +| | Variable [count_agg_0] +| PathField [_id] +| PathComposeM [] +| | PathField [year] +| | PathConstant [] +| | Variable [groupByProj_1] +| PathField [isin] +| PathConstant [] +| Variable [groupByProj_0] +GroupBy [] +| | groupings: +| | RefBlock: +| | Variable [groupByProj_0] +| | Variable [groupByProj_1] +| aggregations: +| [count_agg_0] +| FunctionCall [$sum] +| Const [1] +| [open_agg_0] +| FunctionCall [$first] +| Variable [scan_0] +Evaluation [] +| BindBlock: +| [groupByProj_1] +| EvalPath [] +| | Variable [scan_0] +| PathGet [year] +| PathIdentity [] +Evaluation [] +| BindBlock: +| [groupByProj_0] +| EvalPath [] +| | Variable [scan_0] +| PathGet [isin] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $project with computed array ==== +-- INPUTS: +pipeline: [{$project: {a: ['$b', '$c']}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathDefault [] +| | Const [{}] +| PathComposeM [] +| | PathField [a] +| | PathConstant [] +| | Variable [projGetPath_0] +| PathKeep [_id, a] +Evaluation [] +| BindBlock: +| [projGetPath_0] +| FunctionCall [newArray] +| | EvalPath [] +| | | Variable [scan_0] +| | PathGet [c] +| | PathIdentity [] +| EvalPath [] +| | Variable [scan_0] +| PathGet [b] +| PathIdentity [] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: union ==== +-- INPUTS: +pipeline: [{$unionWith: 'collB'}, {$match: {_id: 1}}] +metadata: + number of partitions: 1 + scan definitions: + collA: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + collB: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [_id] +| PathTraverse [1] +| PathCompare [Eq] +| Const [1] +Union [] +| | BindBlock: +| | [scan_0] +| | Source [] +| Evaluation [] +| | BindBlock: +| | [scan_0] +| | EvalPath [] +| | | Variable [scan_1] +| | PathIdentity [] +| Scan [collB] +| BindBlock: +| [scan_1] +| Source [] +Scan [collA] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: $match with $ne ==== +-- INPUTS: +pipeline: [{$match: {'a': {$ne: 2}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathConstant [] +| UnaryOp [Not] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [Eq] +| Const [2] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + diff --git a/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/optimize_pipeline_tests.txt b/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/optimize_pipeline_tests.txt new file mode 100644 index 00000000000..9f03e9a01af --- /dev/null +++ b/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/optimize_pipeline_tests.txt @@ -0,0 +1,1438 @@ +==== VARIATION: optimized $match with $or: pipeline is able to use a SargableNode with a disjunction of point intervals. ==== +-- INPUTS: +pipeline: [{$match: {$or: [{a: 1}, {a: 2}, {a: 3}]}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Sargable [Complete] +| | | | | requirementsMap: +| | | | | refProjection: scan_0, path: 'PathGet [a] PathTraverse [1] PathIdentity []', intervals: {{{[Const [3], Const [3]]}} U {{[Const [1], Const [1]]}} U {{[Const [2], Const [2]]}}} +| | | | candidateIndexes: +| | | | candidateId: 1, index1, {}, {0}, {{{[Const [3], Const [3]]}} U {{[Const [1], Const [1]]}} U {{[Const [2], Const [2]]}}} +| | | scanParams: +| | | {'a': evalTemp_0} +| | | residualReqs: +| | | refProjection: evalTemp_0, path: 'PathTraverse [1] PathIdentity []', intervals: {{{[Const [3], Const [3]]}} U {{[Const [1], Const [1]]}} U {{[Const [2], Const [2]]}}}, entryIndex: 0 +| | BindBlock: +| RefBlock: +| Variable [scan_0] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: optimized $match with $in and a list of equalities becomes a comparison to an EqMember list. ==== +-- INPUTS: +pipeline: [{$match: {a: {$in: [1, 2, 3]}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [scan_0] +| PathGet [a] +| PathTraverse [1] +| PathCompare [EqMember] +| Const [[1, 2, 3]] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: optimized $project inclusion then $match: observe the Filter can be reordered against the Eval node ==== +-- INPUTS: +pipeline: [{$project: {a: 1, b: 1}}, {$match: {a: 2}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Const [{}] +| PathComposeM [] +| | PathField [b] +| | PathConstant [] +| | Variable [fieldProj_2] +| PathComposeM [] +| | PathField [a] +| | PathConstant [] +| | Variable [fieldProj_1] +| PathField [_id] +| PathConstant [] +| Variable [fieldProj_0] +Filter [] +| EvalFilter [] +| | Variable [fieldProj_1] +| PathTraverse [1] +| PathCompare [Eq] +| Const [2] +PhysicalScan [{'_id': fieldProj_0, 'a': fieldProj_1, 'b': fieldProj_2}, collection] + BindBlock: + [fieldProj_0] + Source [] + [fieldProj_1] + Source [] + [fieldProj_2] + Source [] + + +==== VARIATION: optimized $match basic ==== +-- INPUTS: +pipeline: [{$match: {a: 1, b: 2}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| EvalFilter [] +| | Variable [evalTemp_3] +| PathTraverse [1] +| PathCompare [Eq] +| Const [2] +Filter [] +| EvalFilter [] +| | Variable [evalTemp_2] +| PathTraverse [1] +| PathCompare [Eq] +| Const [1] +PhysicalScan [{'<root>': scan_0, 'a': evalTemp_2, 'b': evalTemp_3}, collection] + BindBlock: + [evalTemp_2] + Source [] + [evalTemp_3] + Source [] + [scan_0] + Source [] + + +==== VARIATION: optimized $expr filter: make sure we have a single array constant for (1, 2, 'str', ...) ==== +-- INPUTS: +pipeline: [{$project: {a: {$filter: {input: [1, 2, 'str', {a: 2.0, b:'s'}, 3, 4], as: 'num', cond: {$and: [{$gte: ['$$num', 2]}, {$lte: ['$$num', 3]}]}}}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathDefault [] +| | Const [{}] +| PathComposeM [] +| | PathField [a] +| | PathConstant [] +| | EvalPath [] +| | | Const [[1, 2, "str", {"a" : 2, "b" : "s"}, 3, 4]] +| | PathTraverse [inf] +| | PathLambda [] +| | LambdaAbstraction [projGetPath_0_var_1] +| | If [] +| | | | Const [Nothing] +| | | Variable [projGetPath_0_var_1] +| | BinaryOp [And] +| | | BinaryOp [Gte] +| | | | Const [2] +| | | Variable [projGetPath_0_var_1] +| | BinaryOp [Lte] +| | | Const [3] +| | Variable [projGetPath_0_var_1] +| PathKeep [_id, a] +Scan [collection] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: optimized $group local global ==== +-- INPUTS: +pipeline: [{$group: {_id: '$a', c: {$sum: '$b'}}}] +metadata: + number of partitions: 5 + scan definitions: + collection: + options: + distribution and paths: + distribution type: UnknownPartitioning + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | agg_project_0 +| RefBlock: +| Variable [agg_project_0] +Exchange [] +| | distribution: +| | type: Centralized +| RefBlock: +Evaluation [] +| BindBlock: +| [agg_project_0] +| EvalPath [] +| | Const [{}] +| PathComposeM [] +| | PathField [c] +| | PathConstant [] +| | Variable [c_agg_0] +| PathField [_id] +| PathConstant [] +| Variable [groupByProj_0] +GroupBy [Global] +| | groupings: +| | RefBlock: +| | Variable [groupByProj_0] +| aggregations: +| [c_agg_0] +| FunctionCall [$sum] +| Variable [preagg_0] +Exchange [] +| | distribution: +| | type: HashPartitioning +| | projections: +| | groupByProj_0 +| RefBlock: +| Variable [groupByProj_0] +GroupBy [Local] +| | groupings: +| | RefBlock: +| | Variable [groupByProj_0] +| aggregations: +| [preagg_0] +| FunctionCall [$sum] +| Variable [groupByInputProj_0] +PhysicalScan [{'a': groupByProj_0, 'b': groupByInputProj_0}, collection, parallel] + BindBlock: + [groupByInputProj_0] + Source [] + [groupByProj_0] + Source [] + + +==== VARIATION: optimized $unwind then $sort ==== +-- INPUTS: +pipeline: [{$unwind: '$x'}, {$sort: {'x': 1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPost + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + PathLower + +-- OUTPUT: +Root [] +| | projections: +| | embedProj_0 +| RefBlock: +| Variable [embedProj_0] +Collation [] +| | collation: +| | sort_0: Ascending +| RefBlock: +| Variable [sort_0] +Evaluation [] +| BindBlock: +| [sort_0] +| Variable [unwoundProj_0] +Evaluation [] +| BindBlock: +| [embedProj_0] +| If [] +| | | Variable [scan_0] +| | FunctionCall [setField] +| | | | Variable [unwoundProj_0] +| | | Const ["x"] +| | Variable [scan_0] +| BinaryOp [Or] +| | FunctionCall [isObject] +| | Variable [scan_0] +| FunctionCall [exists] +| Variable [unwoundProj_0] +Unwind [] +| BindBlock: +| [unwoundPid_0] +| Source [] +| [unwoundProj_0] +| Source [] +PhysicalScan [{'<root>': scan_0, 'x': unwoundProj_0}, collection] + BindBlock: + [scan_0] + Source [] + [unwoundProj_0] + Source [] + + +==== VARIATION: optimized $match with index ==== +-- INPUTS: +pipeline: [{$match: {'a': 10}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +BinaryJoin [joinType: Inner, {rid_0}] +| | Const [true] +| LimitSkip [] +| | limitSkip: +| | limit: 1 +| | skip: 0 +| Seek [ridProjection: rid_0, {'<root>': scan_0}, collection] +| | BindBlock: +| | [scan_0] +| | Source [] +| RefBlock: +| Variable [rid_0] +IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], Const [10]]}] + BindBlock: + [rid_0] + Source [] + + +==== VARIATION: optimized $match index covered ==== +-- INPUTS: +pipeline: [{$project: {_id: 0, a: 1}}, {$match: {'a': 10}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 0 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + PathGet [a] + PathIdentity [] + + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Const [{}] +| PathField [a] +| PathConstant [] +| Variable [fieldProj_0] +IndexScan [{'<indexKey> 0': fieldProj_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], Const [10]]}] + BindBlock: + [fieldProj_0] + Source [] + + +==== VARIATION: optimized $match index covered, match then project ==== +-- INPUTS: +pipeline: [{$match: {'a': 10}}, {$project: {_id: 0, a: 1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 0 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + PathGet [a] + PathIdentity [] + + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Const [{}] +| PathField [a] +| PathConstant [] +| Variable [fieldProj_0] +IndexScan [{'<indexKey> 0': fieldProj_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], Const [10]]}] + BindBlock: + [fieldProj_0] + Source [] + + +==== VARIATION: optimized $match index covered, match on two indexed keys then project ==== +-- INPUTS: +pipeline: [{$match: {'a': 10, 'b': 20}}, {$project: {_id: 0, a: 1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathIdentity [] + + collation op: Ascending + ABT path: + PathGet [b] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 0 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + PathGet [a] + PathIdentity [] + + PathGet [b] + PathIdentity [] + + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Const [{}] +| PathField [a] +| PathConstant [] +| Variable [fieldProj_0] +IndexScan [{'<indexKey> 0': fieldProj_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], Const [10]], [Const [20], Const [20]]}] + BindBlock: + [fieldProj_0] + Source [] + + +==== VARIATION: optimized $match index covered, match on three indexed keys then project ==== +-- INPUTS: +pipeline: [{$match: {'a': 10, 'b': 20, 'c': 30}}, {$project: {_id: 0, a: 1, b: 1, c: 1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathIdentity [] + + collation op: Ascending + ABT path: + PathGet [b] + PathIdentity [] + + collation op: Ascending + ABT path: + PathGet [c] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 0 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + PathGet [a] + PathIdentity [] + + PathGet [b] + PathIdentity [] + + PathGet [c] + PathIdentity [] + + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Const [{}] +| PathComposeM [] +| | PathField [c] +| | PathConstant [] +| | Variable [fieldProj_2] +| PathComposeM [] +| | PathField [b] +| | PathConstant [] +| | Variable [fieldProj_1] +| PathField [a] +| PathConstant [] +| Variable [fieldProj_0] +IndexScan [{'<indexKey> 0': fieldProj_0, '<indexKey> 1': fieldProj_1, '<indexKey> 2': fieldProj_2}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], Const [10]], [Const [20], Const [20]], [Const [30], Const [30]]}] + BindBlock: + [fieldProj_0] + Source [] + [fieldProj_1] + Source [] + [fieldProj_2] + Source [] + + +==== VARIATION: optimized $match index covered, inclusion project then match on three indexed keys ==== +-- INPUTS: +pipeline: [{$project: {_id: 0, a: 1, b: 1, c: 1}}, {$match: {'a': 10, 'b': 20, 'c': 30}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathIdentity [] + + collation op: Ascending + ABT path: + PathGet [b] + PathIdentity [] + + collation op: Ascending + ABT path: + PathGet [c] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 0 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + PathGet [a] + PathIdentity [] + + PathGet [b] + PathIdentity [] + + PathGet [c] + PathIdentity [] + + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Const [{}] +| PathComposeM [] +| | PathField [c] +| | PathConstant [] +| | Variable [fieldProj_2] +| PathComposeM [] +| | PathField [b] +| | PathConstant [] +| | Variable [fieldProj_1] +| PathField [a] +| PathConstant [] +| Variable [fieldProj_0] +IndexScan [{'<indexKey> 0': fieldProj_0, '<indexKey> 1': fieldProj_1, '<indexKey> 2': fieldProj_2}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], Const [10]], [Const [20], Const [20]], [Const [30], Const [30]]}] + BindBlock: + [fieldProj_0] + Source [] + [fieldProj_1] + Source [] + [fieldProj_2] + Source [] + + +==== VARIATION: optimized $match sort index ==== +-- INPUTS: +pipeline: [{$match: {'a': 10}}, {$sort: {'a': 1}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Collation [] +| | collation: +| | sort_0: Ascending +| RefBlock: +| Variable [sort_0] +BinaryJoin [joinType: Inner, {rid_0}] +| | Const [true] +| LimitSkip [] +| | limitSkip: +| | limit: 1 +| | skip: 0 +| Seek [ridProjection: rid_0, {'<root>': scan_0, 'a': sort_0}, collection] +| | BindBlock: +| | [scan_0] +| | Source [] +| | [sort_0] +| | Source [] +| RefBlock: +| Variable [rid_0] +IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [10], Const [10]]}] + BindBlock: + [rid_0] + Source [] + + +==== VARIATION: optimized range index ==== +-- INPUTS: +pipeline: [{$match: {'a': {$gt: 70, $lt: 90}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +BinaryJoin [joinType: Inner, {rid_0}] +| | Const [true] +| LimitSkip [] +| | limitSkip: +| | limit: 1 +| | skip: 0 +| Seek [ridProjection: rid_0, {'<root>': scan_0}, collection] +| | BindBlock: +| | [scan_0] +| | Source [] +| RefBlock: +| Variable [rid_0] +Filter [] +| EvalFilter [] +| | FunctionCall [getArraySize] +| | Variable [sides_0] +| PathCompare [Eq] +| Const [2] +GroupBy [] +| | groupings: +| | RefBlock: +| | Variable [rid_0] +| aggregations: +| [sides_0] +| FunctionCall [$addToSet] +| Variable [sideId_0] +Union [] +| | BindBlock: +| | [rid_0] +| | Source [] +| | [sideId_0] +| | Source [] +| Evaluation [] +| | BindBlock: +| | [sideId_0] +| | Const [1] +| IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: {(Const [70], Const [""])}] +| BindBlock: +| [rid_0] +| Source [] +Evaluation [] +| BindBlock: +| [sideId_0] +| Const [0] +IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [nan], Const [90])}] + BindBlock: + [rid_0] + Source [] + + +==== VARIATION: optimized index on two keys ==== +-- INPUTS: +pipeline: [{$match: {'a': 2, 'b': 2}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + ABT path: + PathGet [b] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +BinaryJoin [joinType: Inner, {rid_0}] +| | Const [true] +| LimitSkip [] +| | limitSkip: +| | limit: 1 +| | skip: 0 +| Seek [ridProjection: rid_0, {'<root>': scan_0}, collection] +| | BindBlock: +| | [scan_0] +| | Source [] +| RefBlock: +| Variable [rid_0] +IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [2], Const [2]], [Const [2], Const [2]]}] + BindBlock: + [rid_0] + Source [] + + +==== VARIATION: optimized index on one key ==== +-- INPUTS: +pipeline: [{$match: {'a': 2, 'b': 2}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPost + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +BinaryJoin [joinType: Inner, {rid_0}] +| | Const [true] +| Filter [] +| | EvalFilter [] +| | | Variable [evalTemp_4] +| | PathTraverse [1] +| | PathCompare [Eq] +| | Const [2] +| LimitSkip [] +| | limitSkip: +| | limit: 1 +| | skip: 0 +| Seek [ridProjection: rid_0, {'<root>': scan_0, 'b': evalTemp_4}, collection] +| | BindBlock: +| | [evalTemp_4] +| | Source [] +| | [scan_0] +| | Source [] +| RefBlock: +| Variable [rid_0] +IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [2], Const [2]]}] + BindBlock: + [rid_0] + Source [] + + +==== VARIATION: optimized $group eval no inline: verify that "b" is not inlined in the group expression, but is coming from the physical scan ==== +-- INPUTS: +pipeline: [{$group: {_id: null, a: {$first: '$b'}}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPost + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + PathLower + +-- OUTPUT: +Root [] +| | projections: +| | agg_project_0 +| RefBlock: +| Variable [agg_project_0] +Evaluation [] +| BindBlock: +| [agg_project_0] +| Let [inputField_1] +| | If [] +| | | | Variable [inputField_1] +| | | FunctionCall [setField] +| | | | | Variable [a_agg_0] +| | | | Const ["a"] +| | | Variable [inputField_1] +| | BinaryOp [Or] +| | | FunctionCall [isObject] +| | | Variable [inputField_1] +| | FunctionCall [exists] +| | Variable [a_agg_0] +| If [] +| | | Const [{}] +| | FunctionCall [setField] +| | | | Variable [groupByProj_0] +| | | Const ["_id"] +| | Const [{}] +| BinaryOp [Or] +| | FunctionCall [isObject] +| | Const [{}] +| FunctionCall [exists] +| Variable [groupByProj_0] +GroupBy [] +| | groupings: +| | RefBlock: +| | Variable [groupByProj_0] +| aggregations: +| [a_agg_0] +| FunctionCall [$first] +| Variable [groupByInputProj_0] +Evaluation [] +| BindBlock: +| [groupByProj_0] +| Const [null] +PhysicalScan [{'b': groupByInputProj_0}, collection] + BindBlock: + [groupByInputProj_0] + Source [] + + +==== VARIATION: optimized union ==== +-- INPUTS: +pipeline: [{$unionWith: 'collB'}, {$match: {_id: 1}}] +metadata: + number of partitions: 1 + scan definitions: + collA: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 + collB: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Union [] +| | BindBlock: +| | [scan_0] +| | Source [] +| Filter [] +| | EvalFilter [] +| | | Variable [scan_0] +| | PathGet [_id] +| | PathTraverse [1] +| | PathCompare [Eq] +| | Const [1] +| Evaluation [] +| | BindBlock: +| | [scan_0] +| | EvalPath [] +| | | Variable [scan_1] +| | PathIdentity [] +| PhysicalScan [{'<root>': scan_1}, collB] +| BindBlock: +| [scan_1] +| Source [] +Filter [] +| EvalFilter [] +| | Variable [evalTemp_0] +| PathTraverse [1] +| PathCompare [Eq] +| Const [1] +PhysicalScan [{'<root>': scan_0, '_id': evalTemp_0}, collA] + BindBlock: + [evalTemp_0] + Source [] + [scan_0] + Source [] + + +==== VARIATION: optimized common expression elimination ==== +-- INPUTS: +pipeline: [{$project: {foo: {$add: ['$b', 1]}, bar: {$add: ['$b', 1]}}}] +metadata: + number of partitions: 1 + scan definitions: + test: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_0 +| RefBlock: +| Variable [combinedProjection_0] +Evaluation [] +| BindBlock: +| [combinedProjection_0] +| EvalPath [] +| | Variable [scan_0] +| PathComposeM [] +| | PathDefault [] +| | Const [{}] +| PathComposeM [] +| | PathField [foo] +| | PathConstant [] +| | Variable [projGetPath_0] +| PathComposeM [] +| | PathField [bar] +| | PathConstant [] +| | Variable [projGetPath_0] +| PathKeep [_id, bar, foo] +Evaluation [] +| BindBlock: +| [projGetPath_0] +| BinaryOp [Add] +| | Const [1] +| EvalPath [] +| | Variable [scan_0] +| PathGet [b] +| PathIdentity [] +Scan [test] + BindBlock: + [scan_0] + Source [] + + +==== VARIATION: optimized group by dependency: demonstrate that "c" is set to the array size (not the array itself coming from the group) ==== +-- INPUTS: +pipeline: [{$group: {_id: {}, b: {$addToSet: '$a'}}}, {$project: {_id: 0, b: {$size: '$b'}}}, {$project: {_id: 0, c: '$b'}}] +metadata: + number of partitions: 1 + scan definitions: + test: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + +-- OUTPUT: +Root [] +| | projections: +| | combinedProjection_1 +| RefBlock: +| Variable [combinedProjection_1] +Evaluation [] +| BindBlock: +| [combinedProjection_1] +| EvalPath [] +| | Const [{}] +| PathComposeM [] +| | PathField [c] +| | PathConstant [] +| | FunctionCall [getArraySize] +| | Variable [b_agg_0] +| PathKeep [] +GroupBy [] +| | groupings: +| | RefBlock: +| | Variable [groupByProj_0] +| aggregations: +| [b_agg_0] +| FunctionCall [$addToSet] +| Variable [groupByInputProj_0] +Evaluation [] +| BindBlock: +| [groupByProj_0] +| Const [{}] +PhysicalScan [{'a': groupByInputProj_0}, test] + BindBlock: + [groupByInputProj_0] + Source [] + + +==== VARIATION: optimized double $elemMatch ==== +-- INPUTS: +pipeline: [{$match: {a: {$elemMatch: {$gte: 5, $lte: 6}}, b: {$elemMatch: {$gte: 1, $lte: 3}}}}] +metadata: + number of partitions: 1 + scan definitions: + test: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + MemoSubstitutionPhase + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Sargable [Complete] +| | | | | requirementsMap: +| | | | | refProjection: scan_0, path: 'PathGet [a] PathIdentity []', intervals: {{{[Const [[]], Const [BinData(0, )])}}} +| | | | | refProjection: scan_0, path: 'PathGet [a] PathTraverse [1] PathIdentity []', intervals: {{{[Const [5], Const [6]]}}} +| | | | | refProjection: scan_0, path: 'PathGet [b] PathIdentity []', intervals: {{{[Const [[]], Const [BinData(0, )])}}} +| | | | | refProjection: scan_0, path: 'PathGet [b] PathTraverse [1] PathIdentity []', intervals: {{{[Const [1], Const [3]]}}} +| | | | candidateIndexes: +| | | scanParams: +| | | {'a': evalTemp_7, 'b': evalTemp_8} +| | | residualReqs: +| | | refProjection: evalTemp_7, path: 'PathIdentity []', intervals: {{{[Const [[]], Const [BinData(0, )])}}}, entryIndex: 0 +| | | refProjection: evalTemp_7, path: 'PathTraverse [1] PathIdentity []', intervals: {{{[Const [5], Const [6]]}}}, entryIndex: 1 +| | | refProjection: evalTemp_8, path: 'PathIdentity []', intervals: {{{[Const [[]], Const [BinData(0, )])}}}, entryIndex: 2 +| | | refProjection: evalTemp_8, path: 'PathTraverse [1] PathIdentity []', intervals: {{{[Const [1], Const [3]]}}}, entryIndex: 3 +| | BindBlock: +| RefBlock: +| Variable [scan_0] +Scan [test] + BindBlock: + [scan_0] + Source [] + + diff --git a/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/partial_index.txt b/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/partial_index.txt new file mode 100644 index 00000000000..398b1092a35 --- /dev/null +++ b/src/mongo/db/test_output/pipeline/abt/a_b_t_translate/partial_index.txt @@ -0,0 +1,148 @@ +==== VARIATION: optimized partial index: the expression matches the pipeline ==== +-- INPUTS: +pipeline: [{$match: {'a': 3, 'b': 2}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + refProjection: scan_0, path: 'PathGet [b] PathTraverse [1] PathIdentity []', intervals: {{{[Const [2], Const [2]]}}} + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPost + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + PathLower + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +BinaryJoin [joinType: Inner, {rid_0}] +| | Const [true] +| Filter [] +| | FunctionCall [traverseF] +| | | | Const [false] +| | | LambdaAbstraction [valCmp_0] +| | | BinaryOp [Eq] +| | | | Const [2] +| | | Variable [valCmp_0] +| | Variable [evalTemp_4] +| LimitSkip [] +| | limitSkip: +| | limit: 1 +| | skip: 0 +| Seek [ridProjection: rid_0, {'<root>': scan_0, 'b': evalTemp_4}, collection] +| | BindBlock: +| | [evalTemp_4] +| | Source [] +| | [scan_0] +| | Source [] +| RefBlock: +| Variable [rid_0] +IndexScan [{'<rid>': rid_0}, scanDefName: collection, indexDefName: index1, interval: {[Const [3], Const [3]]}] + BindBlock: + [rid_0] + Source [] + + +==== VARIATION: optimized partial index negative: the expression does not match the pipeline ==== +-- INPUTS: +pipeline: [{$match: {'a': 3, 'b': 3}}] +metadata: + number of partitions: 1 + scan definitions: + collection: + options: + distribution and paths: + distribution type: Centralized + distribution paths: + indexes: + index1: + collation spec: + ABT path: + PathGet [a] + PathTraverse [1] + PathIdentity [] + + collation op: Ascending + version: 2 + ordering bits: 0 + is multi-key: 1 + distribution and paths: + distribution type: Centralized + distribution paths: + requirementsMap: + refProjection: scan_0, path: 'PathGet [b] PathTraverse [1] PathIdentity []', intervals: {{{[Const [2], Const [2]]}}} + + non multi-key index paths: + collection exists: 1 + CE type: -1 +optimization phases: + ConstEvalPost + ConstEvalPre + MemoExplorationPhase + MemoImplementationPhase + MemoSubstitutionPhase + PathFuse + PathLower + +-- OUTPUT: +Root [] +| | projections: +| | scan_0 +| RefBlock: +| Variable [scan_0] +Filter [] +| FunctionCall [traverseF] +| | | Const [false] +| | LambdaAbstraction [valCmp_1] +| | BinaryOp [Eq] +| | | Const [3] +| | Variable [valCmp_1] +| Variable [evalTemp_3] +Filter [] +| FunctionCall [traverseF] +| | | Const [false] +| | LambdaAbstraction [valCmp_0] +| | BinaryOp [Eq] +| | | Const [3] +| | Variable [valCmp_0] +| Variable [evalTemp_2] +PhysicalScan [{'<root>': scan_0, 'a': evalTemp_2, 'b': evalTemp_3}, collection] + BindBlock: + [evalTemp_2] + Source [] + [evalTemp_3] + Source [] + [scan_0] + Source [] + + |