summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/query_planner_text_test.cpp
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2014-03-05 16:54:14 -0500
committerDavid Storch <david.storch@10gen.com>2014-03-10 16:02:02 -0400
commit25596dbf48b18a76d3d2cdfdf1fcf23a43e46316 (patch)
treecf8a0e5225fad6b165d09f20feaec99d06a8ecc5 /src/mongo/db/query/query_planner_text_test.cpp
parent629de3b0f493ad7517b2aecd6ec616df015f53dc (diff)
downloadmongo-25596dbf48b18a76d3d2cdfdf1fcf23a43e46316.tar.gz
SERVER-13039 handle subnodes which require an index during plan enumeration
Diffstat (limited to 'src/mongo/db/query/query_planner_text_test.cpp')
-rw-r--r--src/mongo/db/query/query_planner_text_test.cpp114
1 files changed, 114 insertions, 0 deletions
diff --git a/src/mongo/db/query/query_planner_text_test.cpp b/src/mongo/db/query/query_planner_text_test.cpp
index c7d0c5974b1..e6d0a153543 100644
--- a/src/mongo/db/query/query_planner_text_test.cpp
+++ b/src/mongo/db/query/query_planner_text_test.cpp
@@ -439,4 +439,118 @@ namespace {
assertNumSolutions(1);
}
+ TEST_F(QueryPlannerTest, TextInsideAndWithCompoundIndex) {
+ params.options = QueryPlannerParams::NO_TABLE_SCAN;
+ addIndex(BSON("a" << 1 << "_fts" << "text" << "_ftsx" << 1));
+ runQuery(fromjson("{$and: [{a: 3}, {$text: {$search: 'foo'}}], a: 3}"));
+
+ assertNumSolutions(1U);
+ assertSolutionExists("{text: {prefix: {a:3}, search: 'foo'}}");
+ }
+
+ // SERVER-13039: Test that we don't generate invalid solutions when the TEXT node
+ // is buried beneath a logical node.
+ TEST_F(QueryPlannerTest, TextInsideOrBasic) {
+ params.options = QueryPlannerParams::NO_TABLE_SCAN;
+ addIndex(BSON("a" << 1));
+ addIndex(BSON("_fts" << "text" << "_ftsx" << 1));
+ runQuery(fromjson("{a: 0, $or: [{_id: 1}, {$text: {$search: 'foo'}}]}"));
+
+ assertNumSolutions(1U);
+ assertSolutionExists("{fetch: {filter: {a:0}, node: {or: {nodes: ["
+ "{text: {search: 'foo'}}, "
+ "{ixscan: {filter: null, pattern: {_id: 1}}}]}}}}");
+ }
+
+ // SERVER-13039
+ TEST_F(QueryPlannerTest, TextInsideOrWithAnotherOr) {
+ params.options = QueryPlannerParams::NO_TABLE_SCAN;
+ addIndex(BSON("a" << 1));
+ addIndex(BSON("_fts" << "text" << "_ftsx" << 1));
+ runQuery(fromjson("{$and: [{$or: [{a: 3}, {a: 4}]}, "
+ "{$or: [{$text: {$search: 'foo'}}, {a: 5}]}]}"));
+
+ assertNumSolutions(1U);
+ assertSolutionExists("{fetch: {filter: {$or: [{a: 3}, {a: 4}]}, node: "
+ "{or: {nodes: ["
+ "{text: {search: 'foo'}}, "
+ "{ixscan: {filter: null, pattern: {a: 1}}}]}}}}");
+ }
+
+ // SERVER-13039
+ TEST_F(QueryPlannerTest, TextInsideOrOfAnd) {
+ params.options = QueryPlannerParams::NO_TABLE_SCAN;
+ addIndex(BSON("a" << 1));
+ addIndex(BSON("_fts" << "text" << "_ftsx" << 1));
+ runQuery(fromjson("{$or: [{a: {$gt: 1, $gt: 2}}, "
+ "{a: {$gt: 3}, $text: {$search: 'foo'}}]}"));
+
+ assertNumSolutions(1U);
+ assertSolutionExists("{fetch: {filter: null, node: {or: {nodes: ["
+ "{ixscan: {filter: null, pattern: {a:1}, bounds: "
+ "{a: [[2,Infinity,false,true]]}}}, "
+ "{fetch: {filter: {a:{$gt:3}}, node: "
+ "{text: {search: 'foo'}}}}]}}}}");
+ }
+
+ // SERVER-13039
+ TEST_F(QueryPlannerTest, TextInsideAndOrAnd) {
+ params.options = QueryPlannerParams::NO_TABLE_SCAN;
+ addIndex(BSON("a" << 1));
+ addIndex(BSON("b" << 1));
+ addIndex(BSON("_fts" << "text" << "_ftsx" << 1));
+ runQuery(fromjson("{a: 1, $or: [{a:2}, {b:2}, "
+ "{a: 1, $text: {$search: 'foo'}}]}"));
+
+ assertNumSolutions(1U);
+ assertSolutionExists("{fetch: {filter: {a:1}, node: {or: {nodes: ["
+ "{ixscan: {filter: null, pattern: {a:1}}}, "
+ "{fetch: {filter: {a:1}, node: {text: {search: 'foo'}}}}, "
+ "{ixscan: {filter: null, pattern: {b:1}}}]}}}}");
+ }
+
+ // SERVER-13039
+ TEST_F(QueryPlannerTest, TextInsideAndOrAndOr) {
+ params.options = QueryPlannerParams::NO_TABLE_SCAN;
+ addIndex(BSON("a" << 1));
+ addIndex(BSON("_fts" << "text" << "_ftsx" << 1));
+ runQuery(fromjson("{$or: [{a: {$gt: 1, $gt: 2}}, "
+ "{a: {$gt: 3}, $or: [{$text: {$search: 'foo'}}, "
+ "{a: 6}]}], "
+ "a: 5}"));
+
+ assertNumSolutions(1U);
+ assertSolutionExists("{fetch: {filter: {a:5}, node: {or: {nodes: ["
+ "{ixscan: {filter: null, pattern: {a: 1}}}, "
+ "{fetch: {filter: {a:{$gt:3}}, node: {or: {nodes: ["
+ "{text: {search: 'foo'}}, "
+ "{ixscan: {filter: null, pattern: {a: 1}}}]}}}}]}}}}");
+ }
+
+ // If only one branch of the $or can be indexed, then no indexed
+ // solutions are generated, even if one branch is $text.
+ TEST_F(QueryPlannerTest, TextInsideOrOneBranchNotIndexed) {
+ params.options = QueryPlannerParams::NO_TABLE_SCAN;
+ addIndex(BSON("a" << 1));
+ addIndex(BSON("_fts" << "text" << "_ftsx" << 1));
+ runQuery(fromjson("{a: 1, $or: [{b: 2}, {$text: {$search: 'foo'}}]}"));
+
+ assertNumSolutions(0);
+ }
+
+ // If the unindexable $or is not the one containing the $text predicate,
+ // then we should still be able to generate an indexed solution.
+ TEST_F(QueryPlannerTest, TextInsideOrWithAnotherUnindexableOr) {
+ params.options = QueryPlannerParams::NO_TABLE_SCAN;
+ addIndex(BSON("a" << 1));
+ addIndex(BSON("_fts" << "text" << "_ftsx" << 1));
+ runQuery(fromjson("{$and: [{$or: [{a: 1}, {b: 1}]}, "
+ "{$or: [{a: 2}, {$text: {$search: 'foo'}}]}]}"));
+
+ assertNumSolutions(1U);
+ assertSolutionExists("{fetch: {filter: {$or:[{a:1},{b:1}]}, node: {or: {nodes: ["
+ "{text: {search: 'foo'}}, "
+ "{ixscan: {filter: null, pattern: {a:1}}}]}}}}");
+ }
+
} // namespace