summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorJason Rassi <rassi@10gen.com>2015-10-30 14:51:02 -0400
committerJason Rassi <rassi@10gen.com>2015-11-06 12:08:52 -0500
commit81aca0ec6827eaffd54c91af46f9041ce62587c4 (patch)
tree17957a7ad33ad80d6c059a891434a0b924ec2e55 /src/mongo
parentd393cfcf7fefe99b1ffba05ce6282bb5c97f20fb (diff)
downloadmongo-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')
-rw-r--r--src/mongo/db/SConscript2
-rw-r--r--src/mongo/db/commands/current_op.cpp1
-rw-r--r--src/mongo/db/commands/find_cmd.cpp1
-rw-r--r--src/mongo/db/commands/geo_near_cmd.cpp1
-rw-r--r--src/mongo/db/commands/index_filter_commands.cpp1
-rw-r--r--src/mongo/db/commands/mr.cpp1
-rw-r--r--src/mongo/db/commands/plan_cache_commands.cpp1
-rw-r--r--src/mongo/db/dbhelpers.cpp1
-rw-r--r--src/mongo/db/exec/sort_key_generator.cpp1
-rw-r--r--src/mongo/db/exec/stagedebug_cmd.cpp1
-rw-r--r--src/mongo/db/exec/subplan.cpp1
-rw-r--r--src/mongo/db/matcher/SConscript15
-rw-r--r--src/mongo/db/matcher/expression_parser.cpp28
-rw-r--r--src/mongo/db/matcher/expression_parser.h43
-rw-r--r--src/mongo/db/matcher/expression_where.cpp128
-rw-r--r--src/mongo/db/matcher/expression_where.h57
-rw-r--r--src/mongo/db/matcher/expression_where_base.cpp61
-rw-r--r--src/mongo/db/matcher/expression_where_base.h75
-rw-r--r--src/mongo/db/matcher/expression_where_noop.cpp113
-rw-r--r--src/mongo/db/matcher/expression_where_noop.h50
-rw-r--r--src/mongo/db/matcher/extensions_callback_noop.cpp46
-rw-r--r--src/mongo/db/matcher/extensions_callback_noop.h43
-rw-r--r--src/mongo/db/matcher/extensions_callback_real.cpp55
-rw-r--r--src/mongo/db/matcher/extensions_callback_real.h58
-rw-r--r--src/mongo/db/ops/parsed_delete.cpp1
-rw-r--r--src/mongo/db/ops/parsed_update.cpp2
-rw-r--r--src/mongo/db/ops/path_support_test.cpp4
-rw-r--r--src/mongo/db/ops/update_driver.cpp1
-rw-r--r--src/mongo/db/pipeline/pipeline_d.cpp1
-rw-r--r--src/mongo/db/query/find.cpp1
-rw-r--r--src/mongo/db/query/get_executor.cpp2
-rw-r--r--src/mongo/db/query/query_planner_test_fixture.cpp1
-rw-r--r--src/mongo/db/query/stage_builder.cpp1
-rw-r--r--src/mongo/dbtests/SConscript1
-rw-r--r--src/mongo/dbtests/expression_where_test.cpp116
-rw-r--r--src/mongo/dbtests/matchertests.cpp1
-rw-r--r--src/mongo/s/chunk_manager.cpp1
-rw-r--r--src/mongo/s/chunk_manager_targeter_test.cpp1
-rw-r--r--src/mongo/s/commands/cluster_find_cmd.cpp1
-rw-r--r--src/mongo/s/shard_key_pattern.cpp1
-rw-r--r--src/mongo/s/strategy.cpp1
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"