diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/exec/stagedebug_cmd.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/fts/fts_matcher_test.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/fts/fts_query.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/fts/fts_query.h | 10 | ||||
-rw-r--r-- | src/mongo/db/fts/fts_query_test.cpp | 51 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_text.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_text_test.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/query/stage_builder.cpp | 14 |
8 files changed, 84 insertions, 56 deletions
diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index 8ee9f8b0e36..a3f5d29765e 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -457,11 +457,13 @@ public: params.spec = fam->getSpec(); - params.query.parse(search, - fam->getSpec().defaultLanguage().str().c_str(), - fts::FTSQuery::caseSensitiveDefault, - fts::FTSQuery::diacriticSensitiveDefault, - fam->getSpec().getTextIndexVersion()); + if (!params.query.parse(search, + fam->getSpec().defaultLanguage().str().c_str(), + fts::FTSQuery::caseSensitiveDefault, + fts::FTSQuery::diacriticSensitiveDefault, + fam->getSpec().getTextIndexVersion()).isOK()) { + return NULL; + } return new TextStage(txn, params, workingSet, matcher); } else if ("delete" == nodeName) { diff --git a/src/mongo/db/fts/fts_matcher_test.cpp b/src/mongo/db/fts/fts_matcher_test.cpp index 7694732e2e1..246510a9e70 100644 --- a/src/mongo/db/fts/fts_matcher_test.cpp +++ b/src/mongo/db/fts/fts_matcher_test.cpp @@ -38,7 +38,7 @@ namespace fts { TEST(FTSMatcher, NegWild1) { FTSQuery q; - q.parse("foo -bar", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse("foo -bar", "english", false, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("$**" << "text"))))); @@ -52,7 +52,7 @@ TEST(FTSMatcher, NegWild1) { // Regression test for SERVER-11994. TEST(FTSMatcher, NegWild2) { FTSQuery q; - q.parse("pizza -restaurant", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse("pizza -restaurant", "english", false, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("$**" << "text"))))); @@ -65,7 +65,7 @@ TEST(FTSMatcher, NegWild2) { TEST(FTSMatcher, Phrase1) { FTSQuery q; - q.parse("foo \"table top\"", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse("foo \"table top\"", "english", false, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("$**" << "text"))))); @@ -87,7 +87,7 @@ TEST(FTSMatcher, Phrase1) { TEST(FTSMatcher, Phrase2) { FTSQuery q; - q.parse("foo \"table top\"", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse("foo \"table top\"", "english", false, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("x" << "text"))))); @@ -98,7 +98,7 @@ TEST(FTSMatcher, Phrase2) { // language. TEST(FTSMatcher, ParsesUsingDocLanguage) { FTSQuery q; - q.parse("-glad", "none", false, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse("-glad", "none", false, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("x" << "text"))))); @@ -112,7 +112,7 @@ TEST(FTSMatcher, ParsesUsingDocLanguage) { // Test the matcher does not filter out stop words from positive terms TEST(FTSMatcher, MatcherDoesNotFilterStopWordsNeg) { FTSQuery q; - q.parse("-the", "none", false, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse("-the", "none", false, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("x" << "text"))))); @@ -124,7 +124,7 @@ TEST(FTSMatcher, MatcherDoesNotFilterStopWordsNeg) { // Test the matcher does not filter out stop words from negative terms TEST(FTSMatcher, MatcherDoesNotFilterStopWordsPos) { FTSQuery q; - q.parse("the", "none", false, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse("the", "none", false, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("x" << "text"))))); @@ -137,7 +137,7 @@ TEST(FTSMatcher, MatcherDoesNotFilterStopWordsPos) { // case-sensitive text query 'search'. static bool docHasPositiveTermWithCase(const std::string& doc, const std::string& search) { FTSQuery q; - q.parse(search, "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse(search, "english", true, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("x" << "text"))))); @@ -164,7 +164,7 @@ TEST(FTSMatcher, HasPositiveTermCaseSensitive) { // case-sensitive text query 'search'. static bool docHasNegativeTermWithCase(const std::string& doc, const std::string& search) { FTSQuery q; - q.parse(search, "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse(search, "english", true, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("x" << "text"))))); @@ -191,7 +191,7 @@ TEST(FTSMatcher, HasNegativeTermCaseSensitive) { // from case-sensitive text query 'search'. static bool docPositivePhrasesMatchWithCase(const std::string& doc, const std::string& search) { FTSQuery q; - q.parse(search, "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse(search, "english", true, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("x" << "text"))))); @@ -214,7 +214,7 @@ TEST(FTSMatcher, PositivePhrasesMatchWithCase) { // from case-sensitive text query 'search'. static bool docNegativePhrasesMatchWithCase(const std::string& doc, const std::string& search) { FTSQuery q; - q.parse(search, "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT_OK(q.parse(search, "english", true, false, TEXT_INDEX_VERSION_3)); FTSMatcher m(q, FTSSpec(FTSSpec::fixSpec(BSON("key" << BSON("x" << "text"))))); diff --git a/src/mongo/db/fts/fts_query.cpp b/src/mongo/db/fts/fts_query.cpp index 2dc9b222d3a..f162481066b 100644 --- a/src/mongo/db/fts/fts_query.cpp +++ b/src/mongo/db/fts/fts_query.cpp @@ -52,14 +52,15 @@ using std::vector; const bool FTSQuery::caseSensitiveDefault = false; const bool FTSQuery::diacriticSensitiveDefault = false; -void FTSQuery::parse(const string& query, - StringData language, - bool caseSensitive, - bool diacriticSensitive, - TextIndexVersion textIndexVersion) { +Status FTSQuery::parse(const string& query, + StringData language, + bool caseSensitive, + bool diacriticSensitive, + TextIndexVersion textIndexVersion) { StatusWithFTSLanguage swl = FTSLanguage::make(language, textIndexVersion); - uassertStatusOK(swl.getStatus()); - + if (!swl.getStatus().isOK()) { + return swl.getStatus(); + } _language = swl.getValue(); _caseSensitive = caseSensitive; _diacriticSensitive = diacriticSensitive; @@ -130,6 +131,8 @@ void FTSQuery::parse(const string& query, _addTerms(tokenizer.get(), positiveTermSentence, false); _addTerms(tokenizer.get(), negativeTermSentence, true); + + return Status::OK(); } void FTSQuery::_addTerms(FTSTokenizer* tokenizer, const string& sentence, bool negated) { diff --git a/src/mongo/db/fts/fts_query.h b/src/mongo/db/fts/fts_query.h index 3b7fbaa16f3..ea1882e4baf 100644 --- a/src/mongo/db/fts/fts_query.h +++ b/src/mongo/db/fts/fts_query.h @@ -50,11 +50,11 @@ public: // version 1 (see fts_language.cpp for a list of language strings specific to version // 1). Note that the diacritic sensitive option has no effect on FTS queries below index version // 3. - void parse(const std::string& query, - StringData language, - bool caseSensitive, - bool diacriticSensitive, - TextIndexVersion textIndexVersion); + Status parse(const std::string& query, + StringData language, + bool caseSensitive, + bool diacriticSensitive, + TextIndexVersion textIndexVersion); const std::set<std::string>& getPositiveTerms() const { return _positiveTerms; diff --git a/src/mongo/db/fts/fts_query_test.cpp b/src/mongo/db/fts/fts_query_test.cpp index dfdeeba68e7..bcf9e537142 100644 --- a/src/mongo/db/fts/fts_query_test.cpp +++ b/src/mongo/db/fts/fts_query_test.cpp @@ -37,7 +37,7 @@ namespace fts { TEST(FTSQuery, Basic1) { FTSQuery q; - q.parse("this is fun", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("this is fun", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); ASSERT_EQUALS(false, q.getCaseSensitive()); ASSERT_EQUALS(1U, q.getPositiveTerms().size()); @@ -50,7 +50,7 @@ TEST(FTSQuery, Basic1) { TEST(FTSQuery, ParsePunctuation) { FTSQuery q; - q.parse("hello.world", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("hello.world", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); ASSERT_EQUALS(false, q.getCaseSensitive()); ASSERT_EQUALS(2U, q.getPositiveTerms().size()); @@ -64,7 +64,7 @@ TEST(FTSQuery, ParsePunctuation) { TEST(FTSQuery, Neg1) { FTSQuery q; - q.parse("this is -really fun", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("this is -really fun", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); ASSERT_EQUALS(1U, q.getPositiveTerms().size()); ASSERT_EQUALS("fun", *q.getPositiveTerms().begin()); @@ -75,7 +75,8 @@ TEST(FTSQuery, Neg1) { TEST(FTSQuery, Phrase1) { FTSQuery q; - q.parse("doing a \"phrase test\" for fun", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("doing a \"phrase test\" for fun", "english", false, false, TEXT_INDEX_VERSION_3) + .isOK()); ASSERT_EQUALS(3U, q.getPositiveTerms().size()); ASSERT_EQUALS(0U, q.getNegatedTerms().size()); @@ -89,26 +90,29 @@ TEST(FTSQuery, Phrase1) { TEST(FTSQuery, Phrase2) { FTSQuery q; - q.parse("doing a \"phrase-test\" for fun", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("doing a \"phrase-test\" for fun", "english", false, false, TEXT_INDEX_VERSION_3) + .isOK()); ASSERT_EQUALS(1U, q.getPositivePhr().size()); ASSERT_EQUALS("phrase-test", q.getPositivePhr()[0]); } TEST(FTSQuery, NegPhrase1) { FTSQuery q; - q.parse("doing a -\"phrase test\" for fun", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT( + q.parse("doing a -\"phrase test\" for fun", "english", false, false, TEXT_INDEX_VERSION_3) + .isOK()); ASSERT_EQUALS("fun||||||phrase test", q.debugString()); } TEST(FTSQuery, CaseSensitiveOption) { FTSQuery q; - q.parse("this is fun", "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("this is fun", "english", true, false, TEXT_INDEX_VERSION_3).isOK()); ASSERT_EQUALS(true, q.getCaseSensitive()); } TEST(FTSQuery, CaseSensitivePositiveTerms) { FTSQuery q; - q.parse("This is Positively fun", "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("This is Positively fun", "english", true, false, TEXT_INDEX_VERSION_3).isOK()); ASSERT_EQUALS(2U, q.getTermsForBounds().size()); ASSERT_EQUALS(1, @@ -124,7 +128,8 @@ TEST(FTSQuery, CaseSensitivePositiveTerms) { TEST(FTSQuery, CaseSensitiveNegativeTerms) { FTSQuery q; - q.parse("-This -is -Negatively -miserable", "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("-This -is -Negatively -miserable", "english", true, false, TEXT_INDEX_VERSION_3) + .isOK()); ASSERT_EQUALS(0U, q.getPositiveTerms().size()); ASSERT_EQUALS(0U, q.getTermsForBounds().size()); @@ -137,7 +142,8 @@ TEST(FTSQuery, CaseSensitiveNegativeTerms) { TEST(FTSQuery, CaseSensitivePositivePhrases) { FTSQuery q; - q.parse("doing a \"Phrase Test\" for fun", "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("doing a \"Phrase Test\" for fun", "english", true, false, TEXT_INDEX_VERSION_3) + .isOK()); ASSERT_EQUALS(1U, q.getPositivePhr().size()); ASSERT_EQUALS(0U, q.getNegatedPhr().size()); @@ -146,7 +152,8 @@ TEST(FTSQuery, CaseSensitivePositivePhrases) { TEST(FTSQuery, CaseSensitiveNegativePhrases) { FTSQuery q; - q.parse("doing a -\"Phrase Test\" for fun", "english", true, false, TEXT_INDEX_VERSION_3); + ASSERT(q.parse("doing a -\"Phrase Test\" for fun", "english", true, false, TEXT_INDEX_VERSION_3) + .isOK()); ASSERT_EQUALS(0U, q.getPositivePhr().size()); ASSERT_EQUALS(1U, q.getNegatedPhr().size()); @@ -155,15 +162,17 @@ TEST(FTSQuery, CaseSensitiveNegativePhrases) { TEST(FTSQuery, Mix1) { FTSQuery q; - q.parse("\"industry\" -Melbourne -Physics", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT( + q.parse("\"industry\" -Melbourne -Physics", "english", false, false, TEXT_INDEX_VERSION_3) + .isOK()); ASSERT_EQUALS("industri||melbourn|physic||industry||", q.debugString()); } TEST(FTSQuery, NegPhrase2) { FTSQuery q1, q2, q3; - q1.parse("foo \"bar\"", "english", false, false, TEXT_INDEX_VERSION_3); - q2.parse("foo \"-bar\"", "english", false, false, TEXT_INDEX_VERSION_3); - q3.parse("foo \" -bar\"", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT(q1.parse("foo \"bar\"", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); + ASSERT(q2.parse("foo \"-bar\"", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); + ASSERT(q3.parse("foo \" -bar\"", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); ASSERT_EQUALS(2U, q1.getPositiveTerms().size()); ASSERT_EQUALS(2U, q2.getPositiveTerms().size()); @@ -184,9 +193,9 @@ TEST(FTSQuery, NegPhrase2) { TEST(FTSQuery, NegPhrase3) { FTSQuery q1, q2, q3; - q1.parse("foo -\"bar\"", "english", false, false, TEXT_INDEX_VERSION_3); - q2.parse("foo -\"-bar\"", "english", false, false, TEXT_INDEX_VERSION_3); - q3.parse("foo -\" -bar\"", "english", false, false, TEXT_INDEX_VERSION_3); + ASSERT(q1.parse("foo -\"bar\"", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); + ASSERT(q2.parse("foo -\"-bar\"", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); + ASSERT(q3.parse("foo -\" -bar\"", "english", false, false, TEXT_INDEX_VERSION_3).isOK()); ASSERT_EQUALS(1U, q1.getPositiveTerms().size()); ASSERT_EQUALS(1U, q2.getPositiveTerms().size()); @@ -209,7 +218,7 @@ TEST(FTSQuery, NegPhrase3) { // stemmer and stopword list. TEST(FTSQuery, TextIndexVersion1LanguageEnglish) { FTSQuery q; - q.parse("the running", "english", false, false, TEXT_INDEX_VERSION_1); + ASSERT(q.parse("the running", "english", false, false, TEXT_INDEX_VERSION_1).isOK()); ASSERT_EQUALS(1U, q.getPositiveTerms().size()); ASSERT_EQUALS("run", *q.getPositiveTerms().begin()); ASSERT_EQUALS(0U, q.getNegatedTerms().size()); @@ -221,7 +230,7 @@ TEST(FTSQuery, TextIndexVersion1LanguageEnglish) { // no stopword list. TEST(FTSQuery, TextIndexVersion1LanguageEng) { FTSQuery q; - q.parse("the running", "eng", false, false, TEXT_INDEX_VERSION_1); + ASSERT(q.parse("the running", "eng", false, false, TEXT_INDEX_VERSION_1).isOK()); ASSERT_EQUALS(2U, q.getPositiveTerms().size()); ASSERT_EQUALS(1, std::count(q.getPositiveTerms().begin(), q.getPositiveTerms().end(), "the")); ASSERT_EQUALS(1, std::count(q.getPositiveTerms().begin(), q.getPositiveTerms().end(), "run")); @@ -234,7 +243,7 @@ TEST(FTSQuery, TextIndexVersion1LanguageEng) { // and no stopword list will be used. TEST(FTSQuery, TextIndexVersion1LanguageInvalid) { FTSQuery q; - q.parse("the running", "invalid", false, false, TEXT_INDEX_VERSION_1); + ASSERT(q.parse("the running", "invalid", false, false, TEXT_INDEX_VERSION_1).isOK()); ASSERT_EQUALS(2U, q.getPositiveTerms().size()); ASSERT_EQUALS(1, std::count(q.getPositiveTerms().begin(), q.getPositiveTerms().end(), "the")); ASSERT_EQUALS(1, diff --git a/src/mongo/db/matcher/expression_parser_text.cpp b/src/mongo/db/matcher/expression_parser_text.cpp index d8dd49f4b85..6968dc6c0cb 100644 --- a/src/mongo/db/matcher/expression_parser_text.cpp +++ b/src/mongo/db/matcher/expression_parser_text.cpp @@ -60,8 +60,11 @@ StatusWithMatchExpression expressionParserTextCallbackReal(const BSONObj& queryO "$language requires a string value"); } language = languageElt.String(); - // NOTE: the language parameter is validated during FTSQuery::Parse when we have the index - // spec and know which version of the index to use for the language list + Status status = fts::FTSLanguage::make(language, fts::TEXT_INDEX_VERSION_2).getStatus(); + if (!status.isOK()) { + return StatusWithMatchExpression(ErrorCodes::BadValue, + "$language specifies unsupported language"); + } } string query = queryObj["$search"].String(); diff --git a/src/mongo/db/matcher/expression_parser_text_test.cpp b/src/mongo/db/matcher/expression_parser_text_test.cpp index 5aae8f0acd0..3d51604f7ef 100644 --- a/src/mongo/db/matcher/expression_parser_text_test.cpp +++ b/src/mongo/db/matcher/expression_parser_text_test.cpp @@ -54,6 +54,13 @@ TEST(MatchExpressionParserText, Basic) { ASSERT_EQUALS(textExp->getDiacriticSensitive(), fts::FTSQuery::diacriticSensitiveDefault); } +TEST(MatchExpressionParserText, LanguageError) { + BSONObj query = fromjson("{$text: {$search:\"awesome\", $language:\"spanglish\"}}"); + + StatusWithMatchExpression result = MatchExpressionParser::parse(query); + ASSERT_FALSE(result.isOK()); +} + TEST(MatchExpressionParserText, CaseSensitiveTrue) { BSONObj query = fromjson("{$text: {$search:\"awesome\", $caseSensitive: true}}"); diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index 5395294c1c6..b971c44288a 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -279,11 +279,15 @@ PlanStage* buildStages(OperationContext* txn, const std::string& language = ("" == node->language ? fam->getSpec().defaultLanguage().str() : node->language); - params.query.parse(node->query, - language, - node->caseSensitive, - node->diacriticSensitive, - fam->getSpec().getTextIndexVersion()); + Status parseStatus = params.query.parse(node->query, + language, + node->caseSensitive, + node->diacriticSensitive, + fam->getSpec().getTextIndexVersion()); + if (!parseStatus.isOK()) { + warning() << "Can't parse text search query"; + return NULL; + } return new TextStage(txn, params, ws, node->filter.get()); } else if (STAGE_SHARDING_FILTER == root->getType()) { |