summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher
diff options
context:
space:
mode:
authorJason Rassi <rassi@10gen.com>2015-11-18 17:31:32 -0500
committerJason Rassi <rassi@10gen.com>2015-11-18 17:38:27 -0500
commit23136883e394b73cbc26f873cd0276779adef3df (patch)
treeb53259aeeaeb8a7e7450796dec662157d9b0a44d /src/mongo/db/matcher
parent7bac6c8f64019082f205c7606c65f173972960a3 (diff)
downloadmongo-23136883e394b73cbc26f873cd0276779adef3df.tar.gz
SERVER-19510 Move text query parsing to TextMatchExpression::init()
- Introduces FTSQuery, which is now the base class for FTSQueryImpl. - Introduces a derived class FTSQueryNoop (which TextNoOpMatchExpression now wraps). libfts_query_noop is now linked into db/matcher/expressions. - TextMatchExpression now parses the text query (which acquires a collection lock as part of the parsing process), and TextNode now stores a parsed version of the query. The FTSQuery::parse() call in buildStages() is removed. Behavior change: $text against a non-existent collection now returns an error, instead of an empty result set.
Diffstat (limited to 'src/mongo/db/matcher')
-rw-r--r--src/mongo/db/matcher/SConscript18
-rw-r--r--src/mongo/db/matcher/expression_text.cpp72
-rw-r--r--src/mongo/db/matcher/expression_text.h14
-rw-r--r--src/mongo/db/matcher/expression_text_base.cpp36
-rw-r--r--src/mongo/db/matcher/expression_text_base.h31
-rw-r--r--src/mongo/db/matcher/expression_text_noop.cpp23
-rw-r--r--src/mongo/db/matcher/expression_text_noop.h10
-rw-r--r--src/mongo/db/matcher/extensions_callback_noop.cpp4
-rw-r--r--src/mongo/db/matcher/extensions_callback_real.cpp4
9 files changed, 121 insertions, 91 deletions
diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript
index af686b9f96b..d8c4fbd8299 100644
--- a/src/mongo/db/matcher/SConscript
+++ b/src/mongo/db/matcher/SConscript
@@ -47,6 +47,7 @@ env.Library(
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/bson/util/bson_extract',
'$BUILD_DIR/mongo/db/common',
+ '$BUILD_DIR/mongo/db/fts/fts_query_noop',
'$BUILD_DIR/third_party/shim_pcrecpp',
'path',
],
@@ -123,26 +124,19 @@ env.CppUnitTest(
)
env.Library(
- target='expressions_text',
- source=[
- 'expression_text.cpp',
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/db/fts/base',
- 'expressions',
- ],
-)
-
-env.Library(
target='expressions_mongod_only',
source=[
'extensions_callback_real.cpp',
+ 'expression_text.cpp',
'expression_where.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/auth/authorization_manager_global',
'$BUILD_DIR/mongo/scripting/scripting_server',
'expressions',
- 'expressions_text',
+ ],
+ LIBDEPS_TAGS=[
+ # Depends on symbols from serverOnlyFiles.
+ 'incomplete',
],
)
diff --git a/src/mongo/db/matcher/expression_text.cpp b/src/mongo/db/matcher/expression_text.cpp
index 8ee279efc1d..b97c2ce2780 100644
--- a/src/mongo/db/matcher/expression_text.cpp
+++ b/src/mongo/db/matcher/expression_text.cpp
@@ -32,34 +32,76 @@
#include "mongo/db/matcher/expression_text.h"
+#include "mongo/db/catalog/collection.h"
+#include "mongo/db/db_raii.h"
#include "mongo/db/fts/fts_language.h"
+#include "mongo/db/fts/fts_spec.h"
+#include "mongo/db/index/fts_access_method.h"
#include "mongo/stdx/memory.h"
namespace mongo {
-TextMatchExpression::TextMatchExpression(TextParams params)
- : TextMatchExpressionBase(std::move(params)) {}
+Status TextMatchExpression::init(OperationContext* txn,
+ const NamespaceString& nss,
+ TextParams params) {
+ _ftsQuery.setQuery(std::move(params.query));
+ _ftsQuery.setLanguage(std::move(params.language));
+ _ftsQuery.setCaseSensitive(params.caseSensitive);
+ _ftsQuery.setDiacriticSensitive(params.diacriticSensitive);
-Status TextMatchExpression::init() {
- // Validate language, but defer construction of FTSQueryImpl (which requires access to the
- // target namespace) until stage building time.
- if (!getLanguage().empty()) {
- if (!fts::FTSLanguage::make(getLanguage(), fts::TEXT_INDEX_VERSION_2).isOK()) {
- return {ErrorCodes::BadValue, "$language specifies unsupported language"};
+ fts::TextIndexVersion version;
+ {
+ // Find text index.
+ ScopedTransaction transaction(txn, MODE_IS);
+ AutoGetDb autoDb(txn, nss.db(), MODE_IS);
+ Lock::CollectionLock collLock(txn->lockState(), nss.ns(), MODE_IS);
+ Database* db = autoDb.getDb();
+ if (!db) {
+ return {ErrorCodes::IndexNotFound,
+ str::stream() << "text index required for $text query (no such collection '"
+ << nss.ns() << "')"};
}
+ Collection* collection = db->getCollection(nss);
+ if (!collection) {
+ return {ErrorCodes::IndexNotFound,
+ str::stream() << "text index required for $text query (no such collection '"
+ << nss.ns() << "')"};
+ }
+ std::vector<IndexDescriptor*> idxMatches;
+ collection->getIndexCatalog()->findIndexByType(txn, IndexNames::TEXT, idxMatches);
+ if (idxMatches.empty()) {
+ return {ErrorCodes::IndexNotFound, "text index required for $text query"};
+ }
+ if (idxMatches.size() > 1) {
+ return {ErrorCodes::IndexNotFound, "more than one text index found for $text query"};
+ }
+ invariant(idxMatches.size() == 1);
+ IndexDescriptor* index = idxMatches[0];
+ const FTSAccessMethod* fam =
+ static_cast<FTSAccessMethod*>(collection->getIndexCatalog()->getIndex(index));
+ invariant(fam);
+
+ // Extract version and default language from text index.
+ version = fam->getSpec().getTextIndexVersion();
+ if (_ftsQuery.getLanguage().empty()) {
+ _ftsQuery.setLanguage(fam->getSpec().defaultLanguage().str());
+ }
+ }
+
+ Status parseStatus = _ftsQuery.parse(version);
+ if (!parseStatus.isOK()) {
+ return parseStatus;
}
return initPath("_fts");
}
std::unique_ptr<MatchExpression> TextMatchExpression::shallowClone() const {
- TextParams params;
- params.query = getQuery();
- params.language = getLanguage();
- params.caseSensitive = getCaseSensitive();
- params.diacriticSensitive = getDiacriticSensitive();
- auto expr = stdx::make_unique<TextMatchExpression>(std::move(params));
- expr->init();
+ auto expr = stdx::make_unique<TextMatchExpression>();
+ // We initialize _ftsQuery here directly rather than calling init(), to avoid needing to examine
+ // the index catalog.
+ expr->_ftsQuery = _ftsQuery;
+ invariantOK(expr->initPath("_fts"));
if (getTag()) {
expr->setTag(getTag()->clone());
}
diff --git a/src/mongo/db/matcher/expression_text.h b/src/mongo/db/matcher/expression_text.h
index dfe4cbd8204..3bd44b29da3 100644
--- a/src/mongo/db/matcher/expression_text.h
+++ b/src/mongo/db/matcher/expression_text.h
@@ -30,17 +30,27 @@
#pragma once
+#include "mongo/db/fts/fts_query_impl.h"
#include "mongo/db/matcher/expression_text_base.h"
+#include "mongo/db/namespace_string.h"
namespace mongo {
+class NamespaceString;
+class OperationContext;
+
class TextMatchExpression : public TextMatchExpressionBase {
public:
- TextMatchExpression(TextParams params);
+ Status init(OperationContext* txn, const NamespaceString& nss, TextParams params);
- Status init();
+ const fts::FTSQuery& getFTSQuery() const final {
+ return _ftsQuery;
+ }
std::unique_ptr<MatchExpression> shallowClone() const final;
+
+private:
+ fts::FTSQueryImpl _ftsQuery;
};
} // namespace mongo
diff --git a/src/mongo/db/matcher/expression_text_base.cpp b/src/mongo/db/matcher/expression_text_base.cpp
index 04b62ecd6b1..82fa7f9fd3e 100644
--- a/src/mongo/db/matcher/expression_text_base.cpp
+++ b/src/mongo/db/matcher/expression_text_base.cpp
@@ -30,23 +30,21 @@
#include "mongo/db/matcher/expression_text_base.h"
+#include "mongo/db/fts/fts_query.h"
+
namespace mongo {
const bool TextMatchExpressionBase::kCaseSensitiveDefault = false;
const bool TextMatchExpressionBase::kDiacriticSensitiveDefault = false;
-TextMatchExpressionBase::TextMatchExpressionBase(TextParams params)
- : LeafMatchExpression(TEXT),
- _query(std::move(params.query)),
- _language(std::move(params.language)),
- _caseSensitive(params.caseSensitive),
- _diacriticSensitive(params.diacriticSensitive) {}
+TextMatchExpressionBase::TextMatchExpressionBase() : LeafMatchExpression(TEXT) {}
void TextMatchExpressionBase::debugString(StringBuilder& debug, int level) const {
+ const fts::FTSQuery& ftsQuery = getFTSQuery();
_debugAddSpace(debug, level);
- debug << "TEXT : query=" << _query << ", language=" << _language
- << ", caseSensitive=" << _caseSensitive << ", diacriticSensitive=" << _diacriticSensitive
- << ", tag=";
+ debug << "TEXT : query=" << ftsQuery.getQuery() << ", language=" << ftsQuery.getLanguage()
+ << ", caseSensitive=" << ftsQuery.getCaseSensitive()
+ << ", diacriticSensitive=" << ftsQuery.getDiacriticSensitive() << ", tag=";
MatchExpression::TagData* td = getTag();
if (NULL != td) {
td->debugString(&debug);
@@ -57,9 +55,11 @@ void TextMatchExpressionBase::debugString(StringBuilder& debug, int level) const
}
void TextMatchExpressionBase::toBSON(BSONObjBuilder* out) const {
+ const fts::FTSQuery& ftsQuery = getFTSQuery();
out->append("$text",
- BSON("$search" << _query << "$language" << _language << "$caseSensitive"
- << _caseSensitive << "$diacriticSensitive" << _diacriticSensitive));
+ BSON("$search" << ftsQuery.getQuery() << "$language" << ftsQuery.getLanguage()
+ << "$caseSensitive" << ftsQuery.getCaseSensitive()
+ << "$diacriticSensitive" << ftsQuery.getDiacriticSensitive()));
}
bool TextMatchExpressionBase::equivalent(const MatchExpression* other) const {
@@ -68,19 +68,7 @@ bool TextMatchExpressionBase::equivalent(const MatchExpression* other) const {
}
const TextMatchExpressionBase* realOther = static_cast<const TextMatchExpressionBase*>(other);
- if (realOther->getQuery() != _query) {
- return false;
- }
- if (realOther->getLanguage() != _language) {
- return false;
- }
- if (realOther->getCaseSensitive() != _caseSensitive) {
- return false;
- }
- if (realOther->getDiacriticSensitive() != _diacriticSensitive) {
- return false;
- }
- return true;
+ return getFTSQuery().equivalent(realOther->getFTSQuery());
}
} // namespace mongo
diff --git a/src/mongo/db/matcher/expression_text_base.h b/src/mongo/db/matcher/expression_text_base.h
index 8ca25cf60eb..187a91bb2d4 100644
--- a/src/mongo/db/matcher/expression_text_base.h
+++ b/src/mongo/db/matcher/expression_text_base.h
@@ -32,6 +32,10 @@
namespace mongo {
+namespace fts {
+class FTSQuery;
+} // namespace fts
+
/**
* Common base class for $text match expression implementations.
*/
@@ -47,23 +51,12 @@ public:
static const bool kCaseSensitiveDefault;
static const bool kDiacriticSensitiveDefault;
- TextMatchExpressionBase(TextParams params);
+ TextMatchExpressionBase();
- const std::string& getQuery() const {
- return _query;
- }
-
- const std::string& getLanguage() const {
- return _language;
- }
-
- bool getCaseSensitive() const {
- return _caseSensitive;
- }
-
- bool getDiacriticSensitive() const {
- return _diacriticSensitive;
- }
+ /**
+ * Returns a reference to the parsed text query that this TextMatchExpressionBase owns.
+ */
+ virtual const fts::FTSQuery& getFTSQuery() const = 0;
//
// Methods inherited from MatchExpression.
@@ -89,12 +82,6 @@ public:
void toBSON(BSONObjBuilder* out) const final;
bool equivalent(const MatchExpression* other) const final;
-
-private:
- const std::string _query;
- const std::string _language;
- const bool _caseSensitive;
- const bool _diacriticSensitive;
};
} // namespace mongo
diff --git a/src/mongo/db/matcher/expression_text_noop.cpp b/src/mongo/db/matcher/expression_text_noop.cpp
index 7d2fb5c84b7..bfd61a54081 100644
--- a/src/mongo/db/matcher/expression_text_noop.cpp
+++ b/src/mongo/db/matcher/expression_text_noop.cpp
@@ -34,21 +34,24 @@
namespace mongo {
-TextNoOpMatchExpression::TextNoOpMatchExpression(TextParams params)
- : TextMatchExpressionBase(std::move(params)) {}
-
-Status TextNoOpMatchExpression::init() {
+Status TextNoOpMatchExpression::init(TextParams params) {
+ _ftsQuery.setQuery(std::move(params.query));
+ _ftsQuery.setLanguage(std::move(params.language));
+ _ftsQuery.setCaseSensitive(params.caseSensitive);
+ _ftsQuery.setDiacriticSensitive(params.diacriticSensitive);
+ invariantOK(_ftsQuery.parse(fts::TEXT_INDEX_VERSION_INVALID));
return initPath("_fts");
}
std::unique_ptr<MatchExpression> TextNoOpMatchExpression::shallowClone() const {
TextParams params;
- params.query = getQuery();
- params.language = getLanguage();
- params.caseSensitive = getCaseSensitive();
- params.diacriticSensitive = getDiacriticSensitive();
- auto expr = stdx::make_unique<TextNoOpMatchExpression>(std::move(params));
- expr->init();
+ params.query = _ftsQuery.getQuery();
+ params.language = _ftsQuery.getLanguage();
+ params.caseSensitive = _ftsQuery.getCaseSensitive();
+ params.diacriticSensitive = _ftsQuery.getDiacriticSensitive();
+
+ auto expr = stdx::make_unique<TextNoOpMatchExpression>();
+ invariantOK(expr->init(std::move(params)));
if (getTag()) {
expr->setTag(getTag()->clone());
}
diff --git a/src/mongo/db/matcher/expression_text_noop.h b/src/mongo/db/matcher/expression_text_noop.h
index de02bcfa3cf..8e01d40e70b 100644
--- a/src/mongo/db/matcher/expression_text_noop.h
+++ b/src/mongo/db/matcher/expression_text_noop.h
@@ -28,17 +28,23 @@
#pragma once
+#include "mongo/db/fts/fts_query_noop.h"
#include "mongo/db/matcher/expression_text_base.h"
namespace mongo {
class TextNoOpMatchExpression : public TextMatchExpressionBase {
public:
- TextNoOpMatchExpression(TextParams params);
+ Status init(TextParams params);
- Status init();
+ const fts::FTSQuery& getFTSQuery() const final {
+ return _ftsQuery;
+ }
std::unique_ptr<MatchExpression> shallowClone() const final;
+
+private:
+ fts::FTSQueryNoop _ftsQuery;
};
} // namespace mongo
diff --git a/src/mongo/db/matcher/extensions_callback_noop.cpp b/src/mongo/db/matcher/extensions_callback_noop.cpp
index e5941f73562..10026370e64 100644
--- a/src/mongo/db/matcher/extensions_callback_noop.cpp
+++ b/src/mongo/db/matcher/extensions_callback_noop.cpp
@@ -41,8 +41,8 @@ StatusWithMatchExpression ExtensionsCallbackNoop::parseText(BSONElement text) co
return textParams.getStatus();
}
- auto expr = stdx::make_unique<TextNoOpMatchExpression>(std::move(textParams.getValue()));
- Status initStatus = expr->init();
+ auto expr = stdx::make_unique<TextNoOpMatchExpression>();
+ Status initStatus = expr->init(std::move(textParams.getValue()));
if (!initStatus.isOK()) {
return initStatus;
}
diff --git a/src/mongo/db/matcher/extensions_callback_real.cpp b/src/mongo/db/matcher/extensions_callback_real.cpp
index 161e0fb2e79..0b7e815ca58 100644
--- a/src/mongo/db/matcher/extensions_callback_real.cpp
+++ b/src/mongo/db/matcher/extensions_callback_real.cpp
@@ -45,8 +45,8 @@ StatusWithMatchExpression ExtensionsCallbackReal::parseText(BSONElement text) co
return textParams.getStatus();
}
- auto exp = stdx::make_unique<TextMatchExpression>(std::move(textParams.getValue()));
- Status status = exp->init();
+ auto exp = stdx::make_unique<TextMatchExpression>();
+ Status status = exp->init(_txn, *_nss, std::move(textParams.getValue()));
if (!status.isOK()) {
return status;
}