diff options
author | Jason Rassi <rassi@10gen.com> | 2015-10-30 14:51:02 -0400 |
---|---|---|
committer | Jason Rassi <rassi@10gen.com> | 2015-11-06 12:08:52 -0500 |
commit | 81aca0ec6827eaffd54c91af46f9041ce62587c4 (patch) | |
tree | 17957a7ad33ad80d6c059a891434a0b924ec2e55 /src/mongo | |
parent | d393cfcf7fefe99b1ffba05ce6282bb5c97f20fb (diff) | |
download | mongo-81aca0ec6827eaffd54c91af46f9041ce62587c4.tar.gz |
SERVER-19510 Refactor WhereMatchExpression/WhereNoOpMatchExpression
- Moves ExtensionsCallbackReal and ExtensionsCallbackNoop to their own
files, and introduces a new library 'expressions_mongod_only' in
db/matcher/.
- Introduces a common base class for WhereMatchExpression and
WhereNoOpMatchExpression.
- Introduces a protected method extractWhereMatchExpressionParams() on
ExtensionsCallback.
Diffstat (limited to 'src/mongo')
41 files changed, 680 insertions, 241 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 8b9d7a7854f..b52da371023 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -590,7 +590,6 @@ serverOnlyFiles = [ "index_rebuilder.cpp", "instance.cpp", "introspect.cpp", - "matcher/expression_where.cpp", "op_observer.cpp", "operation_context_impl.cpp", "ops/delete.cpp", @@ -668,6 +667,7 @@ serveronlyLibdeps = [ "ftdc/ftdc_mongod", "global_timestamp", "index/index_descriptor", + "matcher/expressions_mongod_only", "ops/update_driver", "pipeline/document_source", "pipeline/pipeline", diff --git a/src/mongo/db/commands/current_op.cpp b/src/mongo/db/commands/current_op.cpp index 224105b4ce4..f15f60807e7 100644 --- a/src/mongo/db/commands/current_op.cpp +++ b/src/mongo/db/commands/current_op.cpp @@ -40,6 +40,7 @@ #include "mongo/db/curop.h" #include "mongo/db/dbmessage.h" #include "mongo/db/jsobj.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/matcher/matcher.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index e0977c97845..853bdb3d850 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -42,6 +42,7 @@ #include "mongo/db/db_raii.h" #include "mongo/db/exec/working_set_common.h" #include "mongo/db/service_context.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/query/cursor_response.h" #include "mongo/db/query/explain.h" diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp index 91b01ac481b..f26d4e5e59e 100644 --- a/src/mongo/db/commands/geo_near_cmd.cpp +++ b/src/mongo/db/commands/geo_near_cmd.cpp @@ -46,6 +46,7 @@ #include "mongo/db/index_names.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression_geo.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/query/explain.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/range_preserver.h" diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp index d9b5c8b20c0..a02ca782417 100644 --- a/src/mongo/db/commands/index_filter_commands.cpp +++ b/src/mongo/db/commands/index_filter_commands.cpp @@ -43,6 +43,7 @@ #include "mongo/db/db_raii.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/extensions_callback_real.h" namespace { diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 57ec5779a55..1d9a52067fa 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -49,6 +49,7 @@ #include "mongo/db/index/index_descriptor.h" #include "mongo/db/instance.h" #include "mongo/db/matcher/matcher.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/namespace_string.h" #include "mongo/db/op_observer.h" #include "mongo/db/operation_context_impl.h" diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp index b4d56421a33..8b5c94e74e7 100644 --- a/src/mongo/db/commands/plan_cache_commands.cpp +++ b/src/mongo/db/commands/plan_cache_commands.cpp @@ -42,6 +42,7 @@ #include "mongo/db/commands/plan_cache_commands.h" #include "mongo/db/db_raii.h" #include "mongo/db/jsobj.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/query/explain.h" #include "mongo/db/query/plan_ranker.h" #include "mongo/util/log.h" diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index cbf7259d0f6..f0cc920452f 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -44,6 +44,7 @@ #include "mongo/db/index/btree_access_method.h" #include "mongo/db/json.h" #include "mongo/db/keypattern.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/op_observer.h" #include "mongo/db/ops/delete.h" #include "mongo/db/ops/update.h" diff --git a/src/mongo/db/exec/sort_key_generator.cpp b/src/mongo/db/exec/sort_key_generator.cpp index 0287c2287f6..26e9d6886db 100644 --- a/src/mongo/db/exec/sort_key_generator.cpp +++ b/src/mongo/db/exec/sort_key_generator.cpp @@ -39,6 +39,7 @@ #include "mongo/db/exec/working_set.h" #include "mongo/db/exec/working_set_common.h" #include "mongo/db/exec/working_set_computed_data.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/query/query_planner.h" #include "mongo/stdx/memory.h" #include "mongo/util/log.h" diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index 6adae8898fc..261df368104 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -54,6 +54,7 @@ #include "mongo/db/index/fts_access_method.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/query/plan_executor.h" #include "mongo/stdx/memory.h" #include "mongo/util/log.h" diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp index efed540c37d..c77b7d05454 100644 --- a/src/mongo/db/exec/subplan.cpp +++ b/src/mongo/db/exec/subplan.cpp @@ -35,6 +35,7 @@ #include "mongo/client/dbclientinterface.h" #include "mongo/db/exec/multi_plan.h" #include "mongo/db/exec/scoped_timer.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/plan_executor.h" #include "mongo/db/query/planner_analysis.h" diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript index f91ca8b2b34..b4b62c29b55 100644 --- a/src/mongo/db/matcher/SConscript +++ b/src/mongo/db/matcher/SConscript @@ -33,7 +33,9 @@ env.Library( 'expression_parser.cpp', 'expression_parser_tree.cpp', 'expression_tree.cpp', + 'expression_where_base.cpp', 'expression_where_noop.cpp', + 'extensions_callback_noop.cpp', 'match_details.cpp', 'matchable.cpp', "matcher.cpp", @@ -137,3 +139,16 @@ env.CppUnitTest( 'expressions_text', ], ) + +env.Library( + target='expressions_mongod_only', + source=[ + 'extensions_callback_real.cpp', + 'expression_where.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/db/auth/authorization_manager_global', + '$BUILD_DIR/mongo/scripting/scripting_server', + 'expressions', + ], +) diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index 818c92c6376..afbff931422 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -36,6 +36,7 @@ #include "mongo/db/matcher/expression_array.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_tree.h" +#include "mongo/db/namespace_string.h" #include "mongo/stdx/memory.h" #include "mongo/util/mongoutils/str.h" @@ -955,10 +956,35 @@ StatusWith<std::vector<uint32_t>> MatchExpressionParser::_parseBitPositionsArray } StatusWithMatchExpression MatchExpressionParser::ExtensionsCallback::parseWhere( - const BSONElement& where) const { + BSONElement where) const { return {Status(ErrorCodes::NoWhereParseContext, "no context for parsing $where")}; } +StatusWith<WhereMatchExpressionBase::WhereParams> +MatchExpressionParser::ExtensionsCallback::extractWhereMatchExpressionParams(BSONElement where) { + WhereMatchExpressionBase::WhereParams params; + + switch (where.type()) { + case mongo::String: + case mongo::Code: + params.code = where._asCode(); + params.scope = BSONObj(); + break; + case mongo::CodeWScope: + params.code = where._asCode(); + params.scope = where.codeWScopeObject().getOwned(); + break; + default: + return {ErrorCodes::BadValue, "$where got bad type"}; + } + + if (params.code.empty()) { + return {ErrorCodes::BadValue, "code for $where cannot be empty"}; + } + + return params; +} + // Geo StatusWithMatchExpression expressionParserGeoCallbackDefault(const char* name, int type, diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h index 1b8c71a3539..4b7bf4a751c 100644 --- a/src/mongo/db/matcher/expression_parser.h +++ b/src/mongo/db/matcher/expression_parser.h @@ -35,11 +35,11 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_tree.h" +#include "mongo/db/matcher/expression_where_base.h" #include "mongo/stdx/functional.h" namespace mongo { -class NamespaceString; class OperationContext; typedef StatusWith<std::unique_ptr<MatchExpression>> StatusWithMatchExpression; @@ -56,9 +56,16 @@ public: */ class ExtensionsCallback { public: - virtual StatusWithMatchExpression parseWhere(const BSONElement& where) const; + virtual StatusWithMatchExpression parseWhere(BSONElement where) const; virtual ~ExtensionsCallback() {} + + protected: + /** + * Helper method which extracts parameters from the given $where element. + */ + static StatusWith<WhereMatchExpressionBase::WhereParams> extractWhereMatchExpressionParams( + BSONElement where); }; /** @@ -168,38 +175,6 @@ private: const ExtensionsCallback* _extensionsCallback; }; -/** - * This implementation is used for the server-side code. - */ -class ExtensionsCallbackReal : public MatchExpressionParser::ExtensionsCallback { -public: - /** - * Does not take ownership of 'nss' or 'txn'. - * - * 'nss' must outlive this object. 'txn' must outlive this object also; in addition, 'txn' must - * outlive any MatchExpression objects generated by these callbacks (as the generated objects - * are allowed to keep a reference to 'txn'). - */ - ExtensionsCallbackReal(OperationContext* txn, const NamespaceString* nss); - - virtual StatusWithMatchExpression parseWhere(const BSONElement& where) const; - -private: - OperationContext* const _txn; - const NamespaceString* const _nss; -}; - -/** - * This is just a pass-through implementation, used by sharding only. - */ -class ExtensionsCallbackNoop : public MatchExpressionParser::ExtensionsCallback { -public: - ExtensionsCallbackNoop(); - - virtual StatusWithMatchExpression parseWhere(const BSONElement& where) const; -}; - - typedef stdx::function<StatusWithMatchExpression( const char* name, int type, const BSONObj& section)> MatchExpressionParserGeoCallback; extern MatchExpressionParserGeoCallback expressionParserGeoCallback; diff --git a/src/mongo/db/matcher/expression_where.cpp b/src/mongo/db/matcher/expression_where.cpp index 09cdd3d6417..63b705f6127 100644 --- a/src/mongo/db/matcher/expression_where.cpp +++ b/src/mongo/db/matcher/expression_where.cpp @@ -30,6 +30,8 @@ #include "mongo/platform/basic.h" +#include "mongo/db/matcher/expression_where.h" + #include "mongo/base/init.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/namespace_string.h" @@ -44,79 +46,34 @@ namespace mongo { using std::unique_ptr; -using std::endl; using std::string; using std::stringstream; using stdx::make_unique; -class WhereMatchExpression : public MatchExpression { -public: - WhereMatchExpression(OperationContext* txn) : MatchExpression(WHERE), _txn(txn) { - invariant(_txn != NULL); - - _func = 0; - } - - virtual ~WhereMatchExpression() {} - - Status init(StringData dbName, StringData theCode, const BSONObj& scope); - - virtual bool matches(const MatchableDocument* doc, MatchDetails* details = 0) const; - - virtual bool matchesSingleElement(const BSONElement& e) const { - return false; - } - - virtual unique_ptr<MatchExpression> shallowClone() const { - unique_ptr<WhereMatchExpression> e = make_unique<WhereMatchExpression>(_txn); - e->init(_dbName, _code, _userScope); - if (getTag()) { - e->setTag(getTag()->clone()); - } - return std::move(e); - } - - virtual void debugString(StringBuilder& debug, int level = 0) const; - - virtual void toBSON(BSONObjBuilder* out) const; +WhereMatchExpression::WhereMatchExpression(OperationContext* txn, WhereParams params) + : WhereMatchExpressionBase(std::move(params)), _txn(txn) { + invariant(_txn != NULL); - virtual bool equivalent(const MatchExpression* other) const; + _func = 0; +} - virtual void resetTag() { - setTag(NULL); +Status WhereMatchExpression::init(StringData dbName) { + if (!globalScriptEngine) { + return Status(ErrorCodes::BadValue, "no globalScriptEngine in $where parsing"); } -private: - string _dbName; - string _code; - BSONObj _userScope; - - unique_ptr<Scope> _scope; - ScriptingFunction _func; - - // Not owned. See comments insde ExtensionsCallbackReal for the lifetime of this pointer. - OperationContext* _txn; -}; - -Status WhereMatchExpression::init(StringData dbName, StringData theCode, const BSONObj& scope) { if (dbName.size() == 0) { return Status(ErrorCodes::BadValue, "ns for $where cannot be empty"); } - if (theCode.size() == 0) { - return Status(ErrorCodes::BadValue, "code for $where cannot be empty"); - } - _dbName = dbName.toString(); - _code = theCode.toString(); - _userScope = scope.getOwned(); const string userToken = AuthorizationSession::get(ClientBasic::getCurrent())->getAuthenticatedUserNamesToken(); try { _scope = globalScriptEngine->getPooledScope(_txn, _dbName, "where" + userToken); - _func = _scope->createFunction(_code.c_str()); + _func = _scope->createFunction(getCode().c_str()); } catch (...) { return exceptionToStatus(); } @@ -131,8 +88,8 @@ bool WhereMatchExpression::matches(const MatchableDocument* doc, MatchDetails* d uassert(28692, "$where compile error", _func); BSONObj obj = doc->toBSON(); - if (!_userScope.isEmpty()) { - _scope->init(&_userScope); + if (!getScope().isEmpty()) { + _scope->init(&getScope()); } _scope->advanceGeneration(); @@ -151,56 +108,15 @@ bool WhereMatchExpression::matches(const MatchableDocument* doc, MatchDetails* d return _scope->getBoolean("__returnValue") != 0; } -void WhereMatchExpression::debugString(StringBuilder& debug, int level) const { - _debugAddSpace(debug, level); - debug << "$where\n"; - - _debugAddSpace(debug, level + 1); - debug << "dbName: " << _dbName << "\n"; - - _debugAddSpace(debug, level + 1); - debug << "code: " << _code << "\n"; - - _debugAddSpace(debug, level + 1); - debug << "scope: " << _userScope << "\n"; -} - -void WhereMatchExpression::toBSON(BSONObjBuilder* out) const { - out->append("$where", _code); -} - -bool WhereMatchExpression::equivalent(const MatchExpression* other) const { - if (matchType() != other->matchType()) - return false; - const WhereMatchExpression* realOther = static_cast<const WhereMatchExpression*>(other); - return _dbName == realOther->_dbName && _code == realOther->_code && - _userScope == realOther->_userScope; -} - -ExtensionsCallbackReal::ExtensionsCallbackReal(OperationContext* txn, const NamespaceString* nss) - : _txn(txn), _nss(nss) {} - -StatusWithMatchExpression ExtensionsCallbackReal::parseWhere(const BSONElement& where) const { - if (!globalScriptEngine) - return StatusWithMatchExpression(ErrorCodes::BadValue, - "no globalScriptEngine in $where parsing"); - - unique_ptr<WhereMatchExpression> exp(new WhereMatchExpression(_txn)); - if (where.type() == String || where.type() == Code) { - Status s = exp->init(_nss->db(), where.valuestr(), BSONObj()); - if (!s.isOK()) - return StatusWithMatchExpression(s); - return {std::move(exp)}; - } - - if (where.type() == CodeWScope) { - Status s = exp->init( - _nss->db(), where.codeWScopeCode(), BSONObj(where.codeWScopeScopeDataUnsafe())); - if (!s.isOK()) - return StatusWithMatchExpression(s); - return {std::move(exp)}; +unique_ptr<MatchExpression> WhereMatchExpression::shallowClone() const { + WhereParams params; + params.code = getCode(); + params.scope = getScope(); + unique_ptr<WhereMatchExpression> e = make_unique<WhereMatchExpression>(_txn, std::move(params)); + e->init(_dbName); + if (getTag()) { + e->setTag(getTag()->clone()); } - - return StatusWithMatchExpression(ErrorCodes::BadValue, "$where got bad type"); + return std::move(e); } } diff --git a/src/mongo/db/matcher/expression_where.h b/src/mongo/db/matcher/expression_where.h new file mode 100644 index 00000000000..780c169b217 --- /dev/null +++ b/src/mongo/db/matcher/expression_where.h @@ -0,0 +1,57 @@ +/** + * Copyright (C) 2015 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 "mongo/db/matcher/expression_where_base.h" +#include "mongo/scripting/engine.h" + +namespace mongo { + +class OperationContext; + +class WhereMatchExpression final : public WhereMatchExpressionBase { +public: + WhereMatchExpression(OperationContext* txn, WhereParams params); + + Status init(StringData dbName); + + bool matches(const MatchableDocument* doc, MatchDetails* details = nullptr) const final; + + std::unique_ptr<MatchExpression> shallowClone() const final; + +private: + std::string _dbName; + + std::unique_ptr<Scope> _scope; + ScriptingFunction _func; + + OperationContext* const _txn; +}; + +} // namespace mongo diff --git a/src/mongo/db/matcher/expression_where_base.cpp b/src/mongo/db/matcher/expression_where_base.cpp new file mode 100644 index 00000000000..1bd7c2bde22 --- /dev/null +++ b/src/mongo/db/matcher/expression_where_base.cpp @@ -0,0 +1,61 @@ +/** + * Copyright (C) 2015 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. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/matcher/expression_where_base.h" + +namespace mongo { + +WhereMatchExpressionBase::WhereMatchExpressionBase(WhereParams params) + : MatchExpression(WHERE), _code(std::move(params.code)), _scope(std::move(params.scope)) {} + +void WhereMatchExpressionBase::debugString(StringBuilder& debug, int level) const { + _debugAddSpace(debug, level); + debug << "$where\n"; + + _debugAddSpace(debug, level + 1); + debug << "code: " << getCode() << "\n"; + + _debugAddSpace(debug, level + 1); + debug << "scope: " << getScope() << "\n"; +} + +void WhereMatchExpressionBase::toBSON(BSONObjBuilder* out) const { + out->appendCodeWScope("$where", getCode(), getScope()); +} + +bool WhereMatchExpressionBase::equivalent(const MatchExpression* other) const { + if (matchType() != other->matchType()) { + return false; + } + const WhereMatchExpressionBase* realOther = static_cast<const WhereMatchExpressionBase*>(other); + return getCode() == realOther->getCode() && getScope() == realOther->getScope(); +} + +} // namespace mongo diff --git a/src/mongo/db/matcher/expression_where_base.h b/src/mongo/db/matcher/expression_where_base.h new file mode 100644 index 00000000000..8aabbed669d --- /dev/null +++ b/src/mongo/db/matcher/expression_where_base.h @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2015 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 "mongo/db/matcher/expression.h" + +namespace mongo { + +/** + * Common base class for $where match expression implementations. + */ +class WhereMatchExpressionBase : public MatchExpression { +public: + struct WhereParams { + std::string code; + BSONObj scope; // Owned. + }; + + WhereMatchExpressionBase(WhereParams params); + + // + // Methods inherited from MatchExpression. + // + + bool matchesSingleElement(const BSONElement& e) const final { + return false; + } + + void debugString(StringBuilder& debug, int level = 0) const final; + + void toBSON(BSONObjBuilder* out) const final; + + bool equivalent(const MatchExpression* other) const final; + +protected: + const std::string& getCode() const { + return _code; + } + + const BSONObj& getScope() const { + return _scope; + } + +private: + const std::string _code; + const BSONObj _scope; // Owned. +}; + +} // namespace mongo diff --git a/src/mongo/db/matcher/expression_where_noop.cpp b/src/mongo/db/matcher/expression_where_noop.cpp index ccb64190690..23bb7c287e5 100644 --- a/src/mongo/db/matcher/expression_where_noop.cpp +++ b/src/mongo/db/matcher/expression_where_noop.cpp @@ -29,110 +29,29 @@ */ #include "mongo/platform/basic.h" -#include "mongo/base/init.h" -#include "mongo/db/matcher/expression.h" -#include "mongo/db/matcher/expression_parser.h" -#include "mongo/stdx/memory.h" - -namespace mongo { - -using std::unique_ptr; -using std::string; -using stdx::make_unique; - -/** - * Bogus no-op $where match expression to parse $where in mongos, - * since mongos doesn't have script engine to compile JS functions. - * - * Linked into mongos, instead of the real WhereMatchExpression. - */ -class WhereNoOpMatchExpression : public MatchExpression { -public: - WhereNoOpMatchExpression() : MatchExpression(WHERE) {} - virtual ~WhereNoOpMatchExpression() {} - - Status init(StringData theCode); - - virtual bool matches(const MatchableDocument* doc, MatchDetails* details = 0) const { - return false; - } - - virtual bool matchesSingleElement(const BSONElement& e) const { - return false; - } - - virtual unique_ptr<MatchExpression> shallowClone() const { - unique_ptr<WhereNoOpMatchExpression> e = make_unique<WhereNoOpMatchExpression>(); - e->init(_code); - if (getTag()) { - e->setTag(getTag()->clone()); - } - return std::move(e); - } - - virtual void debugString(StringBuilder& debug, int level = 0) const; - - virtual void toBSON(BSONObjBuilder* out) const; - virtual bool equivalent(const MatchExpression* other) const; +#include "mongo/db/matcher/expression_where_noop.h" - virtual void resetTag() { - setTag(NULL); - } - -private: - string _code; -}; - -Status WhereNoOpMatchExpression::init(StringData theCode) { - if (theCode.size() == 0) - return Status(ErrorCodes::BadValue, "code for $where cannot be empty"); - - _code = theCode.toString(); - - return Status::OK(); -} - -void WhereNoOpMatchExpression::debugString(StringBuilder& debug, int level) const { - _debugAddSpace(debug, level); - debug << "$where (only in mongos)\n"; +#include "mongo/stdx/memory.h" - _debugAddSpace(debug, level + 1); - debug << "code: " << _code << "\n"; -} +namespace mongo { -void WhereNoOpMatchExpression::toBSON(BSONObjBuilder* out) const { - out->append("$where", _code); -} +WhereNoOpMatchExpression::WhereNoOpMatchExpression(WhereParams params) + : WhereMatchExpressionBase(std::move(params)) {} -bool WhereNoOpMatchExpression::equivalent(const MatchExpression* other) const { - if (matchType() != other->matchType()) - return false; - const WhereNoOpMatchExpression* noopOther = static_cast<const WhereNoOpMatchExpression*>(other); - return _code == noopOther->_code; +bool WhereNoOpMatchExpression::matches(const MatchableDocument* doc, MatchDetails* details) const { + return false; } - -// ----------------- - -ExtensionsCallbackNoop::ExtensionsCallbackNoop() {} - -StatusWithMatchExpression ExtensionsCallbackNoop::parseWhere(const BSONElement& where) const { - unique_ptr<WhereNoOpMatchExpression> exp(new WhereNoOpMatchExpression()); - if (where.type() == String || where.type() == Code) { - Status s = exp->init(where.valuestr()); - if (!s.isOK()) - return StatusWithMatchExpression(s); - return {std::move(exp)}; - } - - if (where.type() == CodeWScope) { - Status s = exp->init(where.codeWScopeCode()); - if (!s.isOK()) - return StatusWithMatchExpression(s); - return {std::move(exp)}; +std::unique_ptr<MatchExpression> WhereNoOpMatchExpression::shallowClone() const { + WhereParams params; + params.code = getCode(); + params.scope = getScope(); + std::unique_ptr<WhereNoOpMatchExpression> e = + stdx::make_unique<WhereNoOpMatchExpression>(std::move(params)); + if (getTag()) { + e->setTag(getTag()->clone()); } - - return StatusWithMatchExpression(ErrorCodes::BadValue, "$where got bad type"); + return std::move(e); } } diff --git a/src/mongo/db/matcher/expression_where_noop.h b/src/mongo/db/matcher/expression_where_noop.h new file mode 100644 index 00000000000..10235e3176f --- /dev/null +++ b/src/mongo/db/matcher/expression_where_noop.h @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2015 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 "mongo/db/matcher/expression_where_base.h" + +namespace mongo { + +/** + * Bogus no-op $where match expression to parse $where in mongos, since mongos doesn't have script + * engine to compile JS functions. + * + * Linked into mongos, instead of the real WhereMatchExpression. + */ +class WhereNoOpMatchExpression final : public WhereMatchExpressionBase { +public: + WhereNoOpMatchExpression(WhereParams params); + + bool matches(const MatchableDocument* doc, MatchDetails* details = nullptr) const final; + + std::unique_ptr<MatchExpression> shallowClone() const final; +}; + +} // namespace mongo diff --git a/src/mongo/db/matcher/extensions_callback_noop.cpp b/src/mongo/db/matcher/extensions_callback_noop.cpp new file mode 100644 index 00000000000..ca51ae22b76 --- /dev/null +++ b/src/mongo/db/matcher/extensions_callback_noop.cpp @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2015 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. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/matcher/extensions_callback_noop.h" + +#include "mongo/db/matcher/expression_where_noop.h" + +namespace mongo { + +StatusWithMatchExpression ExtensionsCallbackNoop::parseWhere(BSONElement where) const { + auto whereParams = extractWhereMatchExpressionParams(where); + if (!whereParams.isOK()) { + return whereParams.getStatus(); + } + + return {stdx::make_unique<WhereNoOpMatchExpression>(std::move(whereParams.getValue()))}; +} + +} // namespace mongo diff --git a/src/mongo/db/matcher/extensions_callback_noop.h b/src/mongo/db/matcher/extensions_callback_noop.h new file mode 100644 index 00000000000..9ac019e3947 --- /dev/null +++ b/src/mongo/db/matcher/extensions_callback_noop.h @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2015 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 "mongo/db/matcher/expression_parser.h" + +namespace mongo { + +/** + * This is just a pass-through implementation, used by sharding only. + */ +class ExtensionsCallbackNoop : public MatchExpressionParser::ExtensionsCallback { +public: + StatusWithMatchExpression parseWhere(BSONElement where) const final; +}; + +} // namespace mongo diff --git a/src/mongo/db/matcher/extensions_callback_real.cpp b/src/mongo/db/matcher/extensions_callback_real.cpp new file mode 100644 index 00000000000..e07a098fc87 --- /dev/null +++ b/src/mongo/db/matcher/extensions_callback_real.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2015 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. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/matcher/extensions_callback_real.h" + +#include "mongo/db/matcher/expression_where.h" +#include "mongo/db/namespace_string.h" + +namespace mongo { + +ExtensionsCallbackReal::ExtensionsCallbackReal(OperationContext* txn, const NamespaceString* nss) + : _txn(txn), _nss(nss) {} + +StatusWithMatchExpression ExtensionsCallbackReal::parseWhere(BSONElement where) const { + auto whereParams = extractWhereMatchExpressionParams(where); + if (!whereParams.isOK()) { + return whereParams.getStatus(); + } + + auto exp = stdx::make_unique<WhereMatchExpression>(_txn, std::move(whereParams.getValue())); + Status status = exp->init(_nss->db()); + if (!status.isOK()) { + return status; + } + return {std::move(exp)}; +} + +} // namespace mongo diff --git a/src/mongo/db/matcher/extensions_callback_real.h b/src/mongo/db/matcher/extensions_callback_real.h new file mode 100644 index 00000000000..b820a300dec --- /dev/null +++ b/src/mongo/db/matcher/extensions_callback_real.h @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2015 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 "mongo/db/matcher/expression_parser.h" + +namespace mongo { + +class NamespaceString; + +/** + * This implementation is used for the server-side code. + */ +class ExtensionsCallbackReal : public MatchExpressionParser::ExtensionsCallback { +public: + /** + * Does not take ownership of 'nss' or 'txn'. + * + * 'nss' must outlive this object. 'txn' must outlive this object also; in addition, 'txn' must + * outlive any MatchExpression objects generated by these callbacks (as the generated objects + * are allowed to keep a reference to 'txn'). + */ + ExtensionsCallbackReal(OperationContext* txn, const NamespaceString* nss); + + StatusWithMatchExpression parseWhere(BSONElement where) const final; + +private: + OperationContext* const _txn; + const NamespaceString* const _nss; +}; + +} // namespace mongo diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp index 91031ab8ef3..1acc76dcb3e 100644 --- a/src/mongo/db/ops/parsed_delete.cpp +++ b/src/mongo/db/ops/parsed_delete.cpp @@ -36,6 +36,7 @@ #include "mongo/db/catalog/database.h" #include "mongo/db/exec/delete.h" #include "mongo/db/ops/delete_request.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/query_planner_common.h" diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index c905e9b9c1e..d24a2aeef95 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -29,6 +29,8 @@ #include "mongo/platform/basic.h" #include "mongo/db/ops/parsed_update.h" + +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/ops/update_request.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/query_planner_common.h" diff --git a/src/mongo/db/ops/path_support_test.cpp b/src/mongo/db/ops/path_support_test.cpp index bac517aec4b..8167504f4c0 100644 --- a/src/mongo/db/ops/path_support_test.cpp +++ b/src/mongo/db/ops/path_support_test.cpp @@ -44,6 +44,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_leaf.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/unittest/unittest.h" #include "mongo/util/mongoutils/str.h" @@ -490,8 +491,7 @@ TEST_F(ArrayDoc, NonNumericPathInArray) { // static MatchExpression* makeExpr(const BSONObj& exprBSON) { - static const ExtensionsCallbackNoop callbackNoop; - return MatchExpressionParser::parse(exprBSON, callbackNoop).getValue().release(); + return MatchExpressionParser::parse(exprBSON, ExtensionsCallbackNoop()).getValue().release(); } static void assertContains(const EqualityMatches& equalities, const BSONObj& wrapped) { diff --git a/src/mongo/db/ops/update_driver.cpp b/src/mongo/db/ops/update_driver.cpp index e66264e2027..251d2aabae4 100644 --- a/src/mongo/db/ops/update_driver.cpp +++ b/src/mongo/db/ops/update_driver.cpp @@ -35,6 +35,7 @@ #include "mongo/bson/mutable/document.h" #include "mongo/db/field_ref.h" #include "mongo/db/matcher/expression_leaf.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/ops/log_builder.h" #include "mongo/db/ops/modifier_object_replace.h" #include "mongo/db/ops/modifier_table.h" diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index c52f3183ef7..06114c90404 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -45,6 +45,7 @@ #include "mongo/db/db_raii.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/index/index_access_method.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/pipeline/document_source.h" #include "mongo/db/pipeline/pipeline.h" #include "mongo/db/query/get_executor.h" diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index c06ba454168..6423d965fc6 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -44,6 +44,7 @@ #include "mongo/db/exec/working_set_common.h" #include "mongo/db/service_context.h" #include "mongo/db/keypattern.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/query/explain.h" #include "mongo/db/query/find_common.h" #include "mongo/db/query/get_executor.h" diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index a35e543733d..497f1221e57 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -53,6 +53,8 @@ #include "mongo/db/exec/update.h" #include "mongo/db/index_names.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/matcher/extensions_callback_noop.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/ops/update_lifecycle.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/query/explain.h" diff --git a/src/mongo/db/query/query_planner_test_fixture.cpp b/src/mongo/db/query/query_planner_test_fixture.cpp index 3042665fadd..8d559f24c7f 100644 --- a/src/mongo/db/query/query_planner_test_fixture.cpp +++ b/src/mongo/db/query/query_planner_test_fixture.cpp @@ -34,6 +34,7 @@ #include "mongo/db/namespace_string.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/query/query_knobs.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/query/query_planner_test_lib.h" diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index 06eab97b70e..d23c16ad38b 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -52,6 +52,7 @@ #include "mongo/db/exec/skip.h" #include "mongo/db/exec/text.h" #include "mongo/db/index/fts_access_method.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" #include "mongo/db/s/sharding_state.h" diff --git a/src/mongo/dbtests/SConscript b/src/mongo/dbtests/SConscript index aaf6aa069c1..b353987ac96 100644 --- a/src/mongo/dbtests/SConscript +++ b/src/mongo/dbtests/SConscript @@ -69,6 +69,7 @@ dbtest = env.Program( 'directclienttests.cpp', 'documentsourcetests.cpp', 'executor_registry.cpp', + 'expression_where_test.cpp', 'gle_test.cpp', 'indexcatalogtests.cpp', 'indexupdatetests.cpp', diff --git a/src/mongo/dbtests/expression_where_test.cpp b/src/mongo/dbtests/expression_where_test.cpp new file mode 100644 index 00000000000..047027022e0 --- /dev/null +++ b/src/mongo/dbtests/expression_where_test.cpp @@ -0,0 +1,116 @@ +/** + * Copyright (C) 2015 10gen 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. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/json.h" +#include "mongo/db/matcher/expression.h" +#include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/matcher/expression_where.h" +#include "mongo/db/matcher/extensions_callback_real.h" +#include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context_impl.h" +#include "mongo/unittest/unittest.h" + +namespace mongo { +namespace { + +const NamespaceString nss("unittests.expression_where_test"); + +TEST(ExpressionWhere, WhereExpressionsWithSameScopeHaveSameBSONRepresentation) { + OperationContextImpl txn; + const char code[] = "function(){ return a; }"; + + BSONObj query1 = BSON("$where" << BSONCodeWScope(code, BSON("a" << true))); + auto expr1 = unittest::assertGet( + MatchExpressionParser::parse(query1, ExtensionsCallbackReal(&txn, &nss))); + BSONObjBuilder builder1; + expr1->toBSON(&builder1); + + BSONObj query2 = BSON("$where" << BSONCodeWScope(code, BSON("a" << true))); + auto expr2 = unittest::assertGet( + MatchExpressionParser::parse(query2, ExtensionsCallbackReal(&txn, &nss))); + BSONObjBuilder builder2; + expr2->toBSON(&builder2); + + ASSERT_EQ(builder1.obj(), builder2.obj()); +} + +TEST(ExpressionWhere, WhereExpressionsWithDifferentScopesHaveDifferentBSONRepresentations) { + OperationContextImpl txn; + const char code[] = "function(){ return a; }"; + + BSONObj query1 = BSON("$where" << BSONCodeWScope(code, BSON("a" << true))); + auto expr1 = unittest::assertGet( + MatchExpressionParser::parse(query1, ExtensionsCallbackReal(&txn, &nss))); + BSONObjBuilder builder1; + expr1->toBSON(&builder1); + + BSONObj query2 = BSON("$where" << BSONCodeWScope(code, BSON("a" << false))); + auto expr2 = unittest::assertGet( + MatchExpressionParser::parse(query2, ExtensionsCallbackReal(&txn, &nss))); + BSONObjBuilder builder2; + expr2->toBSON(&builder2); + + ASSERT_NE(builder1.obj(), builder2.obj()); +} + +TEST(ExpressionWhere, WhereExpressionsWithSameScopeAreEquivalent) { + OperationContextImpl txn; + const char code[] = "function(){ return a; }"; + + BSONObj query1 = BSON("$where" << BSONCodeWScope(code, BSON("a" << true))); + auto expr1 = unittest::assertGet( + MatchExpressionParser::parse(query1, ExtensionsCallbackReal(&txn, &nss))); + + BSONObj query2 = BSON("$where" << BSONCodeWScope(code, BSON("a" << true))); + auto expr2 = unittest::assertGet( + MatchExpressionParser::parse(query2, ExtensionsCallbackReal(&txn, &nss))); + + ASSERT(expr1->equivalent(expr2.get())); + ASSERT(expr2->equivalent(expr1.get())); +} + +TEST(ExpressionWhere, WhereExpressionsWithDifferentScopesAreNotEquivalent) { + OperationContextImpl txn; + const char code[] = "function(){ return a; }"; + + BSONObj query1 = BSON("$where" << BSONCodeWScope(code, BSON("a" << true))); + auto expr1 = unittest::assertGet( + MatchExpressionParser::parse(query1, ExtensionsCallbackReal(&txn, &nss))); + + BSONObj query2 = BSON("$where" << BSONCodeWScope(code, BSON("a" << false))); + auto expr2 = unittest::assertGet( + MatchExpressionParser::parse(query2, ExtensionsCallbackReal(&txn, &nss))); + + ASSERT_FALSE(expr1->equivalent(expr2.get())); + ASSERT_FALSE(expr2->equivalent(expr1.get())); +} + +} // namespace +} // namespace mongo diff --git a/src/mongo/dbtests/matchertests.cpp b/src/mongo/dbtests/matchertests.cpp index 694c9cf5553..2d009406e24 100644 --- a/src/mongo/dbtests/matchertests.cpp +++ b/src/mongo/dbtests/matchertests.cpp @@ -33,6 +33,7 @@ #include "mongo/db/db_raii.h" #include "mongo/db/json.h" +#include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/matcher/matcher.h" #include "mongo/db/operation_context_impl.h" #include "mongo/dbtests/dbtests.h" diff --git a/src/mongo/s/chunk_manager.cpp b/src/mongo/s/chunk_manager.cpp index cd5bd4e223d..95fe87de933 100644 --- a/src/mongo/s/chunk_manager.cpp +++ b/src/mongo/s/chunk_manager.cpp @@ -39,6 +39,7 @@ #include "mongo/bson/util/bson_extract.h" #include "mongo/client/remote_command_targeter.h" #include "mongo/db/commands.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/query_planner.h" diff --git a/src/mongo/s/chunk_manager_targeter_test.cpp b/src/mongo/s/chunk_manager_targeter_test.cpp index c7e870c5391..b811edf87e1 100644 --- a/src/mongo/s/chunk_manager_targeter_test.cpp +++ b/src/mongo/s/chunk_manager_targeter_test.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" #include "mongo/db/json.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/canonical_query.h" #include "mongo/s/chunk_manager.h" diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp index d2ae3ef6080..f49c4ebd3c6 100644 --- a/src/mongo/s/commands/cluster_find_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_cmd.cpp @@ -33,6 +33,7 @@ #include "mongo/client/read_preference.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/query/cursor_response.h" #include "mongo/db/stats/counters.h" #include "mongo/s/query/cluster_find.h" diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp index ae7f569c845..30dbc63ee72 100644 --- a/src/mongo/s/shard_key_pattern.cpp +++ b/src/mongo/s/shard_key_pattern.cpp @@ -34,6 +34,7 @@ #include "mongo/db/field_ref_set.h" #include "mongo/db/hasher.h" #include "mongo/db/index_names.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/ops/path_support.h" #include "mongo/db/query/canonical_query.h" #include "mongo/util/mongoutils/str.h" diff --git a/src/mongo/s/strategy.cpp b/src/mongo/s/strategy.cpp index 911c23971ea..9534192381b 100644 --- a/src/mongo/s/strategy.cpp +++ b/src/mongo/s/strategy.cpp @@ -45,6 +45,7 @@ #include "mongo/db/commands.h" #include "mongo/db/max_time.h" #include "mongo/db/server_parameters.h" +#include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/namespace_string.h" #include "mongo/db/query/lite_parsed_query.h" #include "mongo/db/query/getmore_request.h" |