diff options
-rw-r--r-- | src/mongo/db/index/multikey_paths.h | 45 | ||||
-rw-r--r-- | src/mongo/db/query/index_entry.h | 11 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_array_test.cpp | 42 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_test_fixture.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_test_fixture.h | 4 |
5 files changed, 70 insertions, 34 deletions
diff --git a/src/mongo/db/index/multikey_paths.h b/src/mongo/db/index/multikey_paths.h new file mode 100644 index 00000000000..7f0eb2e0b6a --- /dev/null +++ b/src/mongo/db/index/multikey_paths.h @@ -0,0 +1,45 @@ +/** + * Copyright (C) 2016 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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. + */ + +#pragma once + +#include <cstddef> +#include <set> +#include <vector> + +namespace mongo { + +// A vector with size equal to the number of elements in the index key pattern. Each element in +// the vector is an ordered set of positions (starting at 0) into the corresponding indexed +// field that represent what prefixes of the indexed field causes the index to be multikey. +// +// For example, with the index {'a.b': 1, 'a.c': 1} where the paths "a" and "a.b" cause the +// index to be multikey, we'd have a std::vector<std::set<size_t>>{{0U, 1U}, {0U}}. +using MultikeyPaths = std::vector<std::set<std::size_t>>; + +} // namespace mongo diff --git a/src/mongo/db/query/index_entry.h b/src/mongo/db/query/index_entry.h index daf43cc8fb4..7b336515954 100644 --- a/src/mongo/db/query/index_entry.h +++ b/src/mongo/db/query/index_entry.h @@ -29,10 +29,9 @@ #pragma once #include <boost/optional.hpp> -#include <set> #include <string> -#include <vector> +#include "mongo/db/index/multikey_paths.h" #include "mongo/db/index_names.h" #include "mongo/db/jsobj.h" #include "mongo/util/mongoutils/str.h" @@ -46,14 +45,6 @@ class MatchExpression; * This name sucks, but every name involving 'index' is used somewhere. */ struct IndexEntry { - // A vector with size equal to the number of elements in the index key pattern. Each element in - // the vector is an ordered set of positions (starting at 0) into the corresponding indexed - // field that represent what prefixes of the indexed field cause the index to be multikey. - // - // For example, with the index {'a.b': 1, 'a.c': 1} where the paths "a" and "a.b" cause the - // index to be multikey, we'd have a std::vector<std::set<size_t>>{{0U, 1U}, {0U}}. - using MultikeyPaths = std::vector<std::set<size_t>>; - /** * Use this constructor if you're making an IndexEntry from the catalog. */ diff --git a/src/mongo/db/query/query_planner_array_test.cpp b/src/mongo/db/query/query_planner_array_test.cpp index 2123217780c..6ff77e845f7 100644 --- a/src/mongo/db/query/query_planner_array_test.cpp +++ b/src/mongo/db/query/query_planner_array_test.cpp @@ -1138,7 +1138,7 @@ TEST_F(QueryPlannerTest, MultikeyElemMatchAllCompound3) { } TEST_F(QueryPlannerTest, CanIntersectBoundsWhenFirstFieldIsNotMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; + MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: {$gte: 0, $lt: 10}}")); @@ -1150,7 +1150,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsWhenFirstFieldIsNotMultikey) { } TEST_F(QueryPlannerTest, CanIntersectBoundsOnFirstFieldWhenItAndSharedPrefixAreNotMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{std::set<size_t>{}, {1U}}; + MultikeyPaths multikeyPaths{std::set<size_t>{}, {1U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{'a.b': {$gte: 0, $lt: 10}}")); @@ -1162,7 +1162,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsOnFirstFieldWhenItAndSharedPrefixAreN } TEST_F(QueryPlannerTest, CannotIntersectBoundsWhenFirstFieldIsMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; + MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: {$gte: 0, $lt: 10}}")); @@ -1177,7 +1177,7 @@ TEST_F(QueryPlannerTest, CannotIntersectBoundsWhenFirstFieldIsMultikey) { } TEST_F(QueryPlannerTest, CanIntersectBoundsWhenFirstFieldIsMultikeyButHasElemMatch) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; + MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: {$elemMatch: {$gte: 0, $lt: 10}}}")); @@ -1191,7 +1191,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsWhenFirstFieldIsMultikeyButHasElemMat TEST_F(QueryPlannerTest, CanComplementBoundsOnFirstFieldWhenItIsMultikeyAndHasNotEqualExpr) { params.options = QueryPlannerParams::NO_TABLE_SCAN; - IndexEntry::MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; + MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: {$ne: 3}, b: 2}")); @@ -1205,7 +1205,7 @@ TEST_F(QueryPlannerTest, CanComplementBoundsOnFirstFieldWhenItIsMultikeyAndHasNo TEST_F(QueryPlannerTest, CanIntersectBoundsWhenFirstFieldIsMultikeyAndHasNotInsideElemMatch) { params.options = QueryPlannerParams::NO_TABLE_SCAN; - IndexEntry::MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; + MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: {$elemMatch: {$not: {$gte: 10}, $gte: 0}}, b: 2}")); @@ -1216,7 +1216,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsWhenFirstFieldIsMultikeyAndHasNotInsi } TEST_F(QueryPlannerTest, CanIntersectBoundsOnFirstFieldWhenSharedPrefixIsMultikeyButHasElemMatch) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, {0U}}; + MultikeyPaths multikeyPaths{{0U}, {0U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{a: {$elemMatch: {b: {$gte: 0, $lt: 10}}}}")); @@ -1228,7 +1228,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsOnFirstFieldWhenSharedPrefixIsMultike } TEST_F(QueryPlannerTest, CannotIntersectBoundsOnFirstFieldWhenItAndSharedPrefixAreMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{{0U, 1U}, {0U}}; + MultikeyPaths multikeyPaths{{0U, 1U}, {0U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{a: {$elemMatch: {b: {$gte: 0, $lt: 10}, c: 2}}}")); @@ -1244,7 +1244,7 @@ TEST_F(QueryPlannerTest, CannotIntersectBoundsOnFirstFieldWhenItAndSharedPrefixA } TEST_F(QueryPlannerTest, CanIntersectBoundsWhenSecondFieldIsNotMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; + MultikeyPaths multikeyPaths{{0U}, std::set<size_t>{}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: 2, b: {$gte: 0, $lt: 10}}")); @@ -1256,7 +1256,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsWhenSecondFieldIsNotMultikey) { } TEST_F(QueryPlannerTest, CanIntersectBoundsOnSecondFieldWhenItAndSharedPrefixAreNotMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{{1U}, std::set<size_t>{}}; + MultikeyPaths multikeyPaths{{1U}, std::set<size_t>{}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{'a.b': 2, 'a.c': {$gte: 0, $lt: 10}}")); @@ -1268,7 +1268,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsOnSecondFieldWhenItAndSharedPrefixAre } TEST_F(QueryPlannerTest, CannotIntersectBoundsWhenSecondFieldIsMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; + MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: 2, b: {$gte: 0, $lt: 10}}")); @@ -1280,7 +1280,7 @@ TEST_F(QueryPlannerTest, CannotIntersectBoundsWhenSecondFieldIsMultikey) { } TEST_F(QueryPlannerTest, CanIntersectBoundsWhenSecondFieldIsMultikeyButHasElemMatch) { - IndexEntry::MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; + MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: 2, b: {$elemMatch: {$gte: 0, $lt: 10}}}")); @@ -1294,7 +1294,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsWhenSecondFieldIsMultikeyButHasElemMa TEST_F(QueryPlannerTest, CanComplementBoundsOnSecondFieldWhenItIsMultikeyAndHasNotEqualExpr) { params.options = QueryPlannerParams::NO_TABLE_SCAN; - IndexEntry::MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; + MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: 2, b: {$ne: 3}}")); @@ -1308,7 +1308,7 @@ TEST_F(QueryPlannerTest, CanComplementBoundsOnSecondFieldWhenItIsMultikeyAndHasN TEST_F(QueryPlannerTest, CanIntersectBoundsWhenSecondFieldIsMultikeyAndHasNotInsideElemMatch) { params.options = QueryPlannerParams::NO_TABLE_SCAN; - IndexEntry::MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; + MultikeyPaths multikeyPaths{std::set<size_t>{}, {0U}}; addIndex(BSON("a" << 1 << "b" << 1), multikeyPaths); runQuery(fromjson("{a: 2, b: {$elemMatch: {$not: {$gte: 10}, $gte: 0}}}")); @@ -1319,7 +1319,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsWhenSecondFieldIsMultikeyAndHasNotIns } TEST_F(QueryPlannerTest, CanIntersectBoundsOnSecondFieldWhenSharedPrefixIsMultikeyButHasElemMatch) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, {0U}}; + MultikeyPaths multikeyPaths{{0U}, {0U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{a: {$elemMatch: {b: 2, c: {$gte: 0, $lt: 10}}}}")); @@ -1332,7 +1332,7 @@ TEST_F(QueryPlannerTest, CanIntersectBoundsOnSecondFieldWhenSharedPrefixIsMultik } TEST_F(QueryPlannerTest, CannotIntersectBoundsOnSecondFieldWhenItAndSharedPrefixAreMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, {0U, 1U}}; + MultikeyPaths multikeyPaths{{0U}, {0U, 1U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{a: {$elemMatch: {b: 2, c: {$gte: 0, $lt: 10}}}}")); @@ -1345,7 +1345,7 @@ TEST_F(QueryPlannerTest, CannotIntersectBoundsOnSecondFieldWhenItAndSharedPrefix } TEST_F(QueryPlannerTest, CannotIntersectBoundsOfTwoSeparateElemMatches) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, {0U}}; + MultikeyPaths multikeyPaths{{0U}, {0U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson( @@ -1366,7 +1366,7 @@ TEST_F(QueryPlannerTest, CannotIntersectBoundsOfTwoSeparateElemMatches) { } TEST_F(QueryPlannerTest, CanCompoundBoundsWhenSharedPrefixIsNotMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{{1U}, {1U}}; + MultikeyPaths multikeyPaths{{1U}, {1U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{'a.b': 2, 'a.c': 3}")); @@ -1378,7 +1378,7 @@ TEST_F(QueryPlannerTest, CanCompoundBoundsWhenSharedPrefixIsNotMultikey) { } TEST_F(QueryPlannerTest, CannotCompoundBoundsWhenSharedPrefixIsMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, {0U}}; + MultikeyPaths multikeyPaths{{0U}, {0U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{'a.b': 2, 'a.c': 3}")); @@ -1390,7 +1390,7 @@ TEST_F(QueryPlannerTest, CannotCompoundBoundsWhenSharedPrefixIsMultikey) { } TEST_F(QueryPlannerTest, CanCompoundBoundsWhenSharedPrefixIsMultikeyButHasElemMatch) { - IndexEntry::MultikeyPaths multikeyPaths{{0U}, {0U}}; + MultikeyPaths multikeyPaths{{0U}, {0U}}; addIndex(BSON("a.b" << 1 << "a.c" << 1), multikeyPaths); runQuery(fromjson("{a: {$elemMatch: {b: 2, c: 3}}}")); @@ -1402,7 +1402,7 @@ TEST_F(QueryPlannerTest, CanCompoundBoundsWhenSharedPrefixIsMultikeyButHasElemMa } TEST_F(QueryPlannerTest, CannotCompoundBoundsWhenSharedPrefixInsideElemMatchIsMultikey) { - IndexEntry::MultikeyPaths multikeyPaths{{0U, 1U}, {0U, 1U}}; + MultikeyPaths multikeyPaths{{0U, 1U}, {0U, 1U}}; addIndex(BSON("a.b.c" << 1 << "a.b.d" << 1), multikeyPaths); runQuery(fromjson("{a: {$elemMatch: {'b.c': 2, 'b.d': 3}}}")); diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp index 5fe406c0a95..0ea798d2afb 100644 --- a/src/mongo/db/query/query_planner_test_fixture.cpp +++ b/src/mongo/db/query/query_planner_test_fixture.cpp @@ -105,7 +105,7 @@ void QueryPlannerTest::addIndex(BSONObj keyPattern, MatchExpression* filterExpr) BSONObj())); } -void QueryPlannerTest::addIndex(BSONObj keyPattern, IndexEntry::MultikeyPaths multikeyPaths) { +void QueryPlannerTest::addIndex(BSONObj keyPattern, MultikeyPaths multikeyPaths) { invariant(multikeyPaths.size() == static_cast<size_t>(keyPattern.nFields())); const bool multikey = diff --git a/src/mongo/db/query/query_planner_test_fixture.h b/src/mongo/db/query/query_planner_test_fixture.h index 438f46eedfe..30eed2f8cff 100644 --- a/src/mongo/db/query/query_planner_test_fixture.h +++ b/src/mongo/db/query/query_planner_test_fixture.h @@ -34,10 +34,10 @@ #include <vector> #include "mongo/base/owned_pointer_vector.h" +#include "mongo/db/index/multikey_paths.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" #include "mongo/db/query/collation/collator_interface.h" -#include "mongo/db/query/index_entry.h" #include "mongo/db/query/query_solution.h" #include "mongo/unittest/unittest.h" @@ -61,7 +61,7 @@ protected: void addIndex(BSONObj keyPattern, MatchExpression* filterExpr); - void addIndex(BSONObj keyPattern, IndexEntry::MultikeyPaths multikeyPaths); + void addIndex(BSONObj keyPattern, MultikeyPaths multikeyPaths); void addIndex(BSONObj keyPattern, std::unique_ptr<CollatorInterface> collator); |