diff options
author | David Storch <david.storch@mongodb.com> | 2022-06-10 21:50:45 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-06-10 22:53:08 +0000 |
commit | f6b83615b8a3435193e501424bf4b9b91f9e8a1d (patch) | |
tree | c97eb170d89b19b03392e8e5ddd1671982b2fb1a /src/mongo/client | |
parent | 8fca1562eae7c9441c664a5868c220b4b2aad050 (diff) | |
download | mongo-f6b83615b8a3435193e501424bf4b9b91f9e8a1d.tar.gz |
SERVER-65955 Migrate shell exhaust path onto modern internal client API
In doing so, this also fixes the shell's C++ native query
path to correctly handle negative limit. The patch also
includes additional preparatory work for deleting the
query_DEPRECATED() internal client API.
Diffstat (limited to 'src/mongo/client')
-rw-r--r-- | src/mongo/client/SConscript | 17 | ||||
-rw-r--r-- | src/mongo/client/client_deprecated.cpp | 284 | ||||
-rw-r--r-- | src/mongo/client/client_deprecated.h (renamed from src/mongo/client/query.h) | 23 | ||||
-rw-r--r-- | src/mongo/client/dbclient_base.cpp | 32 | ||||
-rw-r--r-- | src/mongo/client/dbclient_base.h | 37 | ||||
-rw-r--r-- | src/mongo/client/dbclient_connection.cpp | 2 | ||||
-rw-r--r-- | src/mongo/client/dbclient_connection.h | 5 | ||||
-rw-r--r-- | src/mongo/client/dbclient_cursor.cpp | 242 | ||||
-rw-r--r-- | src/mongo/client/dbclient_cursor.h | 11 | ||||
-rw-r--r-- | src/mongo/client/dbclient_cursor_test.cpp | 132 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs.cpp | 22 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs.h | 6 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs_test.cpp | 4 | ||||
-rw-r--r-- | src/mongo/client/query.cpp | 135 |
14 files changed, 459 insertions, 493 deletions
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript index 1e613f942a0..b04eca892a9 100644 --- a/src/mongo/client/SConscript +++ b/src/mongo/client/SConscript @@ -165,29 +165,20 @@ env.Library( ], ) -env.Library( - target='client_query', - source=[ - 'query.cpp', - ], - LIBDEPS=[ - '$BUILD_DIR/mongo/base', - 'read_preference', - ], -) - clientDriverEnv = env.Clone() clientDriverEnv.InjectThirdParty('asio') clientDriverEnv.Library( target='clientdriver_minimal', source=[ + 'client_api_version_parameters.idl', + 'client_deprecated.cpp', 'dbclient_base.cpp', 'dbclient_cursor.cpp', 'index_spec.cpp', - 'client_api_version_parameters.idl', ], LIBDEPS=[ + '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/dbmessage', '$BUILD_DIR/mongo/db/pipeline/aggregation_request_helper', '$BUILD_DIR/mongo/db/query/command_request_response', @@ -196,8 +187,8 @@ clientDriverEnv.Library( '$BUILD_DIR/mongo/rpc/command_status', '$BUILD_DIR/mongo/rpc/rpc', 'authentication', - 'client_query', 'connection_string', + 'read_preference', ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/idl/idl_parser', diff --git a/src/mongo/client/client_deprecated.cpp b/src/mongo/client/client_deprecated.cpp new file mode 100644 index 00000000000..e8bbf0542f3 --- /dev/null +++ b/src/mongo/client/client_deprecated.cpp @@ -0,0 +1,284 @@ +/** + * Copyright (C) 2018-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * 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 + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * 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 Server Side 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/client/client_deprecated.h" + +#include "mongo/base/status.h" +#include "mongo/base/status_with.h" +#include "mongo/bson/util/builder.h" +#include "mongo/db/query/query_request_helper.h" + +namespace mongo { +namespace client_deprecated { + +namespace { +bool isComplexQueryObj(const BSONObj& obj, bool* hasDollar) { + if (obj.hasElement("query")) { + if (hasDollar) + *hasDollar = false; + return true; + } + + if (obj.hasElement("$query")) { + if (hasDollar) + *hasDollar = true; + return true; + } + + return false; +} + +BSONObj filterFromOpQueryObj(const BSONObj& obj) { + bool hasDollar; + if (!isComplexQueryObj(obj, &hasDollar)) { + return obj; + } + + return obj.getObjectField(hasDollar ? "$query" : "query"); +} + +void initFindFromOptions(int options, FindCommandRequest* findCommand) { + bool tailable = (options & QueryOption_CursorTailable) != 0; + bool awaitData = (options & QueryOption_AwaitData) != 0; + if (awaitData) { + findCommand->setAwaitData(true); + } + if (tailable) { + findCommand->setTailable(true); + } + + if ((options & QueryOption_NoCursorTimeout) != 0) { + findCommand->setNoCursorTimeout(true); + } + if ((options & QueryOption_PartialResults) != 0) { + findCommand->setAllowPartialResults(true); + } +} + +/** + * Fills out the 'findCommand' output parameter based on the contents of 'querySettings'. Here, + * 'querySettings' has the same format as the "query" field of the no-longer-supported OP_QUERY wire + * protocol message. It can look something like this for example: + * + * {$query: ..., $hint: ..., $min: ..., $max: ...} + * + * Note that this does not set the filter itself on the 'FindCommandRequest' -- this function only + * deals with options that can be packed into the filter object. + * + * Although the OP_QUERY wire protocol message is no longer ever sent over the wire by the internal + * client, this supports old callers of that still specify the operation they want to perform using + * an OP_QUERY-inspired format. + */ +Status initFindFromOpQueryObj(const BSONObj& querySettings, FindCommandRequest* findCommand) { + for (auto&& e : querySettings) { + StringData name = e.fieldNameStringData(); + + if (name == "$orderby" || name == "orderby") { + if (Object == e.type()) { + findCommand->setSort(e.embeddedObject().getOwned()); + } else if (Array == e.type()) { + findCommand->setSort(e.embeddedObject()); + + // TODO: Is this ever used? I don't think so. + // Quote: + // This is for languages whose "objects" are not well ordered (JSON is well + // ordered). + // [ { a : ... } , { b : ... } ] -> { a : ..., b : ... } + // note: this is slow, but that is ok as order will have very few pieces + BSONObjBuilder b; + char p[2] = "0"; + + while (1) { + BSONObj j = findCommand->getSort().getObjectField(p); + if (j.isEmpty()) { + break; + } + BSONElement e = j.firstElement(); + if (e.eoo()) { + return Status(ErrorCodes::BadValue, "bad order array"); + } + if (!e.isNumber()) { + return Status(ErrorCodes::BadValue, "bad order array [2]"); + } + b.append(e); + (*p)++; + if (!(*p <= '9')) { + return Status(ErrorCodes::BadValue, "too many ordering elements"); + } + } + + findCommand->setSort(b.obj()); + } else { + return Status(ErrorCodes::BadValue, "sort must be object or array"); + } + } else if (name == "term") { + findCommand->setTerm(e.safeNumberLong()); + } else if (name == "readConcern") { + if (e.type() != BSONType::Object) { + return Status(ErrorCodes::BadValue, "readConcern must be an object"); + } + findCommand->setReadConcern(e.embeddedObject().getOwned()); + } else if (name.startsWith("$")) { + name = name.substr(1); // chop first char + if (name == "min") { + if (!e.isABSONObj()) { + return Status(ErrorCodes::BadValue, "$min must be a BSONObj"); + } + findCommand->setMin(e.embeddedObject().getOwned()); + } else if (name == "max") { + if (!e.isABSONObj()) { + return Status(ErrorCodes::BadValue, "$max must be a BSONObj"); + } + findCommand->setMax(e.embeddedObject().getOwned()); + } else if (name == "hint") { + if (e.isABSONObj()) { + findCommand->setHint(e.embeddedObject().getOwned()); + } else if (String == e.type()) { + findCommand->setHint(e.wrap()); + } else { + return Status(ErrorCodes::BadValue, + "$hint must be either a string or nested object"); + } + } else if (name == "returnKey") { + // Won't throw. + if (e.trueValue()) { + findCommand->setReturnKey(true); + } + } else if (name == "showDiskLoc") { + // Won't throw. + if (e.trueValue()) { + findCommand->setShowRecordId(true); + query_request_helper::addShowRecordIdMetaProj(findCommand); + } + } else if (name == "maxTimeMS") { + StatusWith<int> maxTimeMS = parseMaxTimeMS(e); + if (!maxTimeMS.isOK()) { + return maxTimeMS.getStatus(); + } + findCommand->setMaxTimeMS(maxTimeMS.getValue()); + } else if (name == "readOnce") { + if (e.booleanSafe()) { + findCommand->setReadOnce(true); + } + } else if (name == "_requestResumeToken") { + if (e.booleanSafe()) { + findCommand->setRequestResumeToken(true); + } + } else if (name == "_resumeAfter") { + findCommand->setResumeAfter(e.embeddedObjectUserCheck().getOwned()); + } + } + } + + return Status::OK(); +} + +} // namespace + +const BSONField<BSONObj> Query::ReadPrefField("$readPreference"); + +void Query::makeComplex() { + if (isComplex()) + return; + BSONObjBuilder b; + b.append("query", obj); + obj = b.obj(); +} + +Query& Query::sort(const BSONObj& s) { + appendComplex("orderby", s); + return *this; +} + +Query& Query::hint(BSONObj keyPattern) { + appendComplex("$hint", keyPattern); + return *this; +} + +Query& Query::readPref(ReadPreference pref, const BSONArray& tags) { + appendComplex(ReadPrefField.name().c_str(), + ReadPreferenceSetting(pref, TagSet(tags)).toInnerBSON()); + return *this; +} + +bool Query::isComplex(bool* hasDollar) const { + return isComplexQueryObj(obj, hasDollar); +} + +Query& Query::appendElements(BSONObj elements) { + makeComplex(); + BSONObjBuilder b(std::move(obj)); + b.appendElements(elements); + obj = b.obj(); + return *this; +} + +Query& Query::requestResumeToken(bool enable) { + appendComplex("$_requestResumeToken", enable); + return *this; +} + +Query& Query::resumeAfter(BSONObj point) { + appendComplex("$_resumeAfter", point); + return *this; +} + +Query& Query::maxTimeMS(long long timeout) { + appendComplex("$maxTimeMS", timeout); + return *this; +} + +Query& Query::term(long long value) { + appendComplex("term", value); + return *this; +} + +Query& Query::readConcern(BSONObj rc) { + appendComplex("readConcern", rc); + return *this; +} + +Query& Query::readOnce(bool enable) { + appendComplex("$readOnce", enable); + return *this; +} + +void initFindFromLegacyOptions(BSONObj bsonOptions, int options, FindCommandRequest* findCommand) { + invariant(findCommand); + BSONObj filter = filterFromOpQueryObj(bsonOptions); + if (!filter.isEmpty()) { + findCommand->setFilter(filter.getOwned()); + } + + uassertStatusOK(initFindFromOpQueryObj(bsonOptions, findCommand)); + initFindFromOptions(options, findCommand); +} + +} // namespace client_deprecated +} // namespace mongo diff --git a/src/mongo/client/query.h b/src/mongo/client/client_deprecated.h index af85022fb07..d8eb80e5afa 100644 --- a/src/mongo/client/query.h +++ b/src/mongo/client/client_deprecated.h @@ -31,9 +31,16 @@ #include "mongo/bson/json.h" #include "mongo/client/read_preference.h" +#include "mongo/db/query/find_command_gen.h" #include "mongo/rpc/message.h" namespace mongo { +/** + * WARNING: Do not add new uses of anything in this namespace! This exists only to support code + * paths that still use an OP_QUERY-derived query representation. Additional callers should not be + * added because OP_QUERY is no longer supported by the shell or server. + */ +namespace client_deprecated { /** * Represents a subset of query settings, such as sort, hint, etc. It is only used in the context of @@ -43,8 +50,6 @@ namespace mongo { class Query { public: static const BSONField<BSONObj> ReadPrefField; - static const BSONField<std::string> ReadPrefModeField; - static const BSONField<BSONArray> ReadPrefTagsField; /** * Creating a Query object from raw BSON is on its way out. Please don't add new callers under @@ -84,8 +89,6 @@ public: */ Query& readPref(ReadPreference pref, const BSONArray& tags); - BSONObj getFilter() const; - /** * A temporary accessor that returns a reference to the internal BSON object. No new callers * should be introduced! @@ -115,7 +118,6 @@ private: * @return true if this query has an orderby, hint, or some other field */ bool isComplex(bool* hasDollar = nullptr) const; - static bool isComplex(const BSONObj& obj, bool* hasDollar = nullptr); void makeComplex(); template <class T> @@ -131,4 +133,15 @@ inline std::ostream& operator<<(std::ostream& s, const Query& q) { return s << q.getFullSettingsDeprecated().toString(); } +/** + * WARNING: This function exists only to support special code paths that use an OP_QUERY-style query + * representation (even though the OP_QUERY wire protocol message itself is no longer supported). Do + * not add new callers. + * + * Sets the relevant fields in 'findCommand' based on the 'bsonOptions' object and the 'options' bit + * vector. 'bsonOptions' is formatted like the query object of an OP_QUERY wire protocol message. + * Similarly, 'options' is a bit vector which is interpreted like the OP_QUERY flags field. + */ +void initFindFromLegacyOptions(BSONObj bsonOptions, int options, FindCommandRequest* findCommand); +} // namespace client_deprecated } // namespace mongo diff --git a/src/mongo/client/dbclient_base.cpp b/src/mongo/client/dbclient_base.cpp index e0022ab5d03..cbef18c6867 100644 --- a/src/mongo/client/dbclient_base.cpp +++ b/src/mongo/client/dbclient_base.cpp @@ -584,15 +584,16 @@ bool DBClientBase::exists(const string& ns) { const uint64_t DBClientBase::INVALID_SOCK_CREATION_TIME = std::numeric_limits<uint64_t>::max(); -unique_ptr<DBClientCursor> DBClientBase::query_DEPRECATED(const NamespaceStringOrUUID& nsOrUuid, - const BSONObj& filter, - const Query& querySettings, - int limit, - int nToSkip, - const BSONObj* fieldsToReturn, - int queryOptions, - int batchSize, - boost::optional<BSONObj> readConcernObj) { +unique_ptr<DBClientCursor> DBClientBase::query_DEPRECATED( + const NamespaceStringOrUUID& nsOrUuid, + const BSONObj& filter, + const client_deprecated::Query& querySettings, + int limit, + int nToSkip, + const BSONObj* fieldsToReturn, + int queryOptions, + int batchSize, + boost::optional<BSONObj> readConcernObj) { unique_ptr<DBClientCursor> c(new DBClientCursor(this, nsOrUuid, filter, @@ -609,8 +610,10 @@ unique_ptr<DBClientCursor> DBClientBase::query_DEPRECATED(const NamespaceStringO } std::unique_ptr<DBClientCursor> DBClientBase::find(FindCommandRequest findRequest, - const ReadPreferenceSetting& readPref) { - auto cursor = std::make_unique<DBClientCursor>(this, std::move(findRequest), readPref); + const ReadPreferenceSetting& readPref, + ExhaustMode exhaustMode) { + auto cursor = std::make_unique<DBClientCursor>( + this, std::move(findRequest), readPref, exhaustMode == ExhaustMode::kOn); if (cursor->init()) { return cursor; } @@ -619,8 +622,9 @@ std::unique_ptr<DBClientCursor> DBClientBase::find(FindCommandRequest findReques void DBClientBase::find(FindCommandRequest findRequest, const ReadPreferenceSetting& readPref, + ExhaustMode exhaustMode, std::function<void(const BSONObj&)> callback) { - auto cursor = this->find(std::move(findRequest), readPref); + auto cursor = this->find(std::move(findRequest), readPref, exhaustMode); while (cursor->more()) { callback(cursor->nextSafe()); } @@ -632,7 +636,7 @@ BSONObj DBClientBase::findOne(FindCommandRequest findRequest, "caller cannot provide a limit when calling DBClientBase::findOne()", !findRequest.getLimit()); findRequest.setLimit(1); - auto cursor = this->find(std::move(findRequest), readPref); + auto cursor = this->find(std::move(findRequest), readPref, ExhaustMode::kOff); uassert(5951201, "DBClientBase::findOne() could not produce cursor", cursor); @@ -657,7 +661,7 @@ unsigned long long DBClientBase::query_DEPRECATED( std::function<void(DBClientCursorBatchIterator&)> f, const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, const BSONObj* fieldsToReturn, int queryOptions, int batchSize, diff --git a/src/mongo/client/dbclient_base.h b/src/mongo/client/dbclient_base.h index 28dda9ada30..0a1c7bdd77d 100644 --- a/src/mongo/client/dbclient_base.h +++ b/src/mongo/client/dbclient_base.h @@ -35,11 +35,11 @@ #include "mongo/base/string_data.h" #include "mongo/client/authenticate.h" #include "mongo/client/client_api_version_parameters_gen.h" +#include "mongo/client/client_deprecated.h" #include "mongo/client/connection_string.h" #include "mongo/client/dbclient_cursor.h" #include "mongo/client/index_spec.h" #include "mongo/client/mongo_uri.h" -#include "mongo/client/query.h" #include "mongo/client/read_preference.h" #include "mongo/config.h" #include "mongo/db/dbmessage.h" @@ -73,6 +73,15 @@ std::string nsGetDB(const std::string& ns); std::string nsGetCollection(const std::string& ns); /** + * Allows callers of the internal client 'find()' API below to request an exhaust cursor. + * + * Such cursors use a special OP_MSG facility under the hood. When exhaust is requested, the server + * writes the full results of the query into the socket (split into getMore batches), without + * waiting for explicit getMore requests from the client. + */ +enum class ExhaustMode { kOn, kOff }; + +/** * Abstract class that implements the core db operations. */ class DBClientBase { @@ -507,15 +516,21 @@ public: * Issues a find command described by 'findRequest', and returns the resulting cursor. */ virtual std::unique_ptr<DBClientCursor> find(FindCommandRequest findRequest, - const ReadPreferenceSetting& readPref); + const ReadPreferenceSetting& readPref, + ExhaustMode exhaustMode); /** - * Identical to the 'find()' overload above, but uses a default value of "primary" for the read - * preference. + * Convenience overloads. Identical to the 'find()' overload above, but default values of + * "primary" read preference and 'ExhaustMode::kOff' are used when not supplied by the caller. */ std::unique_ptr<DBClientCursor> find(FindCommandRequest findRequest) { ReadPreferenceSetting defaultReadPref{}; - return find(std::move(findRequest), defaultReadPref); + return find(std::move(findRequest), defaultReadPref, ExhaustMode::kOff); + } + + std::unique_ptr<DBClientCursor> find(FindCommandRequest findRequest, + const ReadPreferenceSetting& readPref) { + return find(std::move(findRequest), readPref, ExhaustMode::kOff); } /** @@ -523,8 +538,16 @@ public: * returning a cursor to the caller, iterates the cursor under the hood and calls the provided * 'callback' function against each of the documents produced by the cursor. */ + void find(FindCommandRequest findRequest, std::function<void(const BSONObj&)> callback) { + find(std::move(findRequest), + ReadPreferenceSetting{}, + ExhaustMode::kOff, + std::move(callback)); + } + void find(FindCommandRequest findRequest, const ReadPreferenceSetting& readPref, + ExhaustMode exhaustMode, std::function<void(const BSONObj&)> callback); /** @@ -560,7 +583,7 @@ public: virtual std::unique_ptr<DBClientCursor> query_DEPRECATED( const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings = Query(), + const client_deprecated::Query& querySettings = client_deprecated::Query(), int limit = 0, int nToSkip = 0, const BSONObj* fieldsToReturn = nullptr, @@ -571,7 +594,7 @@ public: std::function<void(DBClientCursorBatchIterator&)> f, const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings = Query(), + const client_deprecated::Query& querySettings = client_deprecated::Query(), const BSONObj* fieldsToReturn = nullptr, int queryOptions = QueryOption_Exhaust, int batchSize = 0, diff --git a/src/mongo/client/dbclient_connection.cpp b/src/mongo/client/dbclient_connection.cpp index 1c84cb370bf..c3651edb01c 100644 --- a/src/mongo/client/dbclient_connection.cpp +++ b/src/mongo/client/dbclient_connection.cpp @@ -629,7 +629,7 @@ unsigned long long DBClientConnection::query_DEPRECATED( std::function<void(DBClientCursorBatchIterator&)> f, const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, const BSONObj* fieldsToReturn, int queryOptions, int batchSize, diff --git a/src/mongo/client/dbclient_connection.h b/src/mongo/client/dbclient_connection.h index 9187852758d..45ffcf97b78 100644 --- a/src/mongo/client/dbclient_connection.h +++ b/src/mongo/client/dbclient_connection.h @@ -37,7 +37,6 @@ #include "mongo/client/dbclient_base.h" #include "mongo/client/index_spec.h" #include "mongo/client/mongo_uri.h" -#include "mongo/client/query.h" #include "mongo/client/read_preference.h" #include "mongo/config.h" #include "mongo/db/dbmessage.h" @@ -146,7 +145,7 @@ public: std::unique_ptr<DBClientCursor> query_DEPRECATED( const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings = Query(), + const client_deprecated::Query& querySettings = client_deprecated::Query(), int limit = 0, int nToSkip = 0, const BSONObj* fieldsToReturn = nullptr, @@ -169,7 +168,7 @@ public: std::function<void(DBClientCursorBatchIterator&)>, const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, const BSONObj* fieldsToReturn, int queryOptions, int batchSize = 0, diff --git a/src/mongo/client/dbclient_cursor.cpp b/src/mongo/client/dbclient_cursor.cpp index 735c8a28d00..33fb9e86508 100644 --- a/src/mongo/client/dbclient_cursor.cpp +++ b/src/mongo/client/dbclient_cursor.cpp @@ -27,13 +27,6 @@ * it in the license file. */ -/** - * Connect to a Mongo database as a database, from C++. - */ - - -#include "mongo/platform/basic.h" - #include "mongo/client/dbclient_cursor.h" #include <memory> @@ -106,134 +99,19 @@ Message assembleFromFindCommandRequest(DBClientBase* client, return opMsgRequest.serialize(); } -/** - * Initializes options based on the value of the 'options' bit vector. - * - * This contains flags such as tailable, exhaust, and noCursorTimeout. - */ -void initFromInt(int options, FindCommandRequest* findCommand) { - bool tailable = (options & QueryOption_CursorTailable) != 0; - bool awaitData = (options & QueryOption_AwaitData) != 0; - if (awaitData) { - findCommand->setAwaitData(true); - } - if (tailable) { - findCommand->setTailable(true); - } - - if ((options & QueryOption_NoCursorTimeout) != 0) { - findCommand->setNoCursorTimeout(true); - } - if ((options & QueryOption_PartialResults) != 0) { - findCommand->setAllowPartialResults(true); - } -} - -/** - * Fills out the 'findCommand' output parameter based on the contents of 'querySettings'. Here, - * 'querySettings' has the same format as the "query" field of the no-longer-supported OP_QUERY wire - * protocol message. It can look something like this for example: - * - * {$query: ..., $hint: ..., $min: ..., $max: ...} - * - * Although the OP_QUERY wire protocol message is no longer ever sent over the wire by the internal - * client, callers of the internal client may still specify the operation they want to perform using - * an OP_QUERY-inspired format until DBClientCursor's legacy API is removed. - */ -Status initFullQuery(const BSONObj& querySettings, FindCommandRequest* findCommand) { - for (auto&& e : querySettings) { - StringData name = e.fieldNameStringData(); - - if (name == "$orderby" || name == "orderby") { - if (Object == e.type()) { - findCommand->setSort(e.embeddedObject().getOwned()); - } else if (Array == e.type()) { - findCommand->setSort(e.embeddedObject()); - - // TODO: Is this ever used? I don't think so. - // Quote: - // This is for languages whose "objects" are not well ordered (JSON is well - // ordered). - // [ { a : ... } , { b : ... } ] -> { a : ..., b : ... } - // note: this is slow, but that is ok as order will have very few pieces - BSONObjBuilder b; - char p[2] = "0"; - - while (1) { - BSONObj j = findCommand->getSort().getObjectField(p); - if (j.isEmpty()) { - break; - } - BSONElement e = j.firstElement(); - if (e.eoo()) { - return Status(ErrorCodes::BadValue, "bad order array"); - } - if (!e.isNumber()) { - return Status(ErrorCodes::BadValue, "bad order array [2]"); - } - b.append(e); - (*p)++; - if (!(*p <= '9')) { - return Status(ErrorCodes::BadValue, "too many ordering elements"); - } - } - - findCommand->setSort(b.obj()); - } else { - return Status(ErrorCodes::BadValue, "sort must be object or array"); - } - } else if (name.startsWith("$")) { - name = name.substr(1); // chop first char - if (name == "min") { - if (!e.isABSONObj()) { - return Status(ErrorCodes::BadValue, "$min must be a BSONObj"); - } - findCommand->setMin(e.embeddedObject().getOwned()); - } else if (name == "max") { - if (!e.isABSONObj()) { - return Status(ErrorCodes::BadValue, "$max must be a BSONObj"); - } - findCommand->setMax(e.embeddedObject().getOwned()); - } else if (name == "hint") { - if (e.isABSONObj()) { - findCommand->setHint(e.embeddedObject().getOwned()); - } else if (String == e.type()) { - findCommand->setHint(e.wrap()); - } else { - return Status(ErrorCodes::BadValue, - "$hint must be either a string or nested object"); - } - } else if (name == "returnKey") { - // Won't throw. - if (e.trueValue()) { - findCommand->setReturnKey(true); - } - } else if (name == "showDiskLoc") { - // Won't throw. - if (e.trueValue()) { - findCommand->setShowRecordId(true); - query_request_helper::addShowRecordIdMetaProj(findCommand); - } - } else if (name == "maxTimeMS") { - StatusWith<int> maxTimeMS = parseMaxTimeMS(e); - if (!maxTimeMS.isOK()) { - return maxTimeMS.getStatus(); - } - findCommand->setMaxTimeMS(maxTimeMS.getValue()); - } - } - } +std::unique_ptr<FindCommandRequest> fromLegacyQuery(NamespaceStringOrUUID nssOrUuid, + const BSONObj& filter, + const client_deprecated::Query& querySettings, + const BSONObj& proj, + int ntoskip, + int queryOptions) { + auto findCommand = std::make_unique<FindCommandRequest>(std::move(nssOrUuid)); - return Status::OK(); -} + client_deprecated::initFindFromLegacyOptions( + querySettings.getFullSettingsDeprecated(), queryOptions, findCommand.get()); + findCommand->setFilter(filter.getOwned()); -Status initFindCommandRequest(int ntoskip, - int queryOptions, - const BSONObj& filter, - const Query& querySettings, - const BSONObj& proj, - FindCommandRequest* findCommand) { if (!proj.isEmpty()) { findCommand->setProjection(proj.getOwned()); } @@ -241,57 +119,32 @@ Status initFindCommandRequest(int ntoskip, findCommand->setSkip(ntoskip); } - // Initialize flags passed as 'queryOptions' bit vector. - initFromInt(queryOptions, findCommand); - - findCommand->setFilter(filter.getOwned()); - Status status = initFullQuery(querySettings.getFullSettingsDeprecated(), findCommand); - if (!status.isOK()) { - return status; - } - - // It's not possible to specify readConcern in a legacy query message, so initialize it to - // an empty readConcern object, ie. equivalent to `readConcern: {}`. This ensures that - // mongos passes this empty readConcern to shards. - findCommand->setReadConcern(BSONObj()); - - return query_request_helper::validateFindCommandRequest(*findCommand); -} - -StatusWith<std::unique_ptr<FindCommandRequest>> fromLegacyQuery(NamespaceStringOrUUID nssOrUuid, - const BSONObj& filter, - const Query& querySettings, - const BSONObj& proj, - int ntoskip, - int queryOptions) { - auto findCommand = std::make_unique<FindCommandRequest>(std::move(nssOrUuid)); - - Status status = initFindCommandRequest( - ntoskip, queryOptions, filter, querySettings, proj, findCommand.get()); - if (!status.isOK()) { - return status; - } + uassertStatusOK(query_request_helper::validateFindCommandRequest(*findCommand)); - return std::move(findCommand); + return findCommand; } int queryOptionsFromFindCommand(const FindCommandRequest& findCmd, - const ReadPreferenceSetting& readPref) { + const ReadPreferenceSetting& readPref, + bool isExhaust) { int queryOptions = 0; if (readPref.canRunOnSecondary()) { - queryOptions = queryOptions & QueryOption_SecondaryOk; + queryOptions = queryOptions | QueryOption_SecondaryOk; } if (findCmd.getTailable()) { - queryOptions = queryOptions & QueryOption_CursorTailable; + queryOptions = queryOptions | QueryOption_CursorTailable; } if (findCmd.getNoCursorTimeout()) { - queryOptions = queryOptions & QueryOption_NoCursorTimeout; + queryOptions = queryOptions | QueryOption_NoCursorTimeout; } if (findCmd.getAwaitData()) { - queryOptions = queryOptions & QueryOption_AwaitData; + queryOptions = queryOptions | QueryOption_AwaitData; } if (findCmd.getAllowPartialResults()) { - queryOptions = queryOptions & QueryOption_PartialResults; + queryOptions = queryOptions | QueryOption_PartialResults; + } + if (isExhaust) { + queryOptions = queryOptions | QueryOption_Exhaust; } return queryOptions; } @@ -305,42 +158,28 @@ Message DBClientCursor::initFromLegacyRequest() { _fieldsToReturn ? *_fieldsToReturn : BSONObj(), _nToSkip, _opts); - // If there was a problem building the query request, report that. - uassertStatusOK(findCommand.getStatus()); if (_limit) { - findCommand.getValue()->setLimit(_limit); + findCommand->setLimit(_limit); } if (_batchSize) { - findCommand.getValue()->setBatchSize(_batchSize); + findCommand->setBatchSize(_batchSize); } const BSONObj querySettings = _querySettings.getFullSettingsDeprecated(); - if (querySettings.getBoolField("$readOnce")) { - // Legacy queries don't handle readOnce. - findCommand.getValue()->setReadOnce(true); - } - if (querySettings.getBoolField(FindCommandRequest::kRequestResumeTokenFieldName)) { - // Legacy queries don't handle requestResumeToken. - findCommand.getValue()->setRequestResumeToken(true); - } - if (querySettings.hasField(FindCommandRequest::kResumeAfterFieldName)) { - // Legacy queries don't handle resumeAfter. - findCommand.getValue()->setResumeAfter( - querySettings.getObjectField(FindCommandRequest::kResumeAfterFieldName)); - } - if (auto replTerm = querySettings[FindCommandRequest::kTermFieldName]) { - // Legacy queries don't handle term. - findCommand.getValue()->setTerm(replTerm.numberLong()); - } - // Legacy queries don't handle readConcern. // We prioritize the readConcern parsed from the query object over '_readConcernObj'. - if (auto readConcern = querySettings[repl::ReadConcernArgs::kReadConcernFieldName]) { - findCommand.getValue()->setReadConcern(readConcern.Obj()); - } else if (_readConcernObj) { - findCommand.getValue()->setReadConcern(_readConcernObj); + if (!findCommand->getReadConcern()) { + if (_readConcernObj) { + findCommand->setReadConcern(_readConcernObj); + } else { + // If no readConcern was specified, initialize it to an empty readConcern object, ie. + // equivalent to `readConcern: {}`. This ensures that mongos passes this empty + // readConcern to shards. + findCommand->setReadConcern(BSONObj()); + } } - BSONObj cmd = findCommand.getValue()->toBSON(BSONObj()); + + BSONObj cmd = findCommand->toBSON(BSONObj()); if (auto readPref = querySettings["$readPreference"]) { // FindCommandRequest doesn't handle $readPreference. cmd = BSONObjBuilder(std::move(cmd)).append(readPref).obj(); @@ -593,7 +432,7 @@ void DBClientCursor::attach(AScopedConnection* conn) { DBClientCursor::DBClientCursor(DBClientBase* client, const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, int limit, int nToSkip, const BSONObj* fieldsToReturn, @@ -625,7 +464,7 @@ DBClientCursor::DBClientCursor(DBClientBase* client, : DBClientCursor(client, nsOrUuid, BSONObj(), // filter - Query(), // querySettings + client_deprecated::Query(), cursorId, limit, 0, // nToSkip @@ -640,7 +479,7 @@ DBClientCursor::DBClientCursor(DBClientBase* client, DBClientCursor::DBClientCursor(DBClientBase* client, const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, long long cursorId, int limit, int nToSkip, @@ -672,7 +511,8 @@ DBClientCursor::DBClientCursor(DBClientBase* client, DBClientCursor::DBClientCursor(DBClientBase* client, FindCommandRequest findRequest, - const ReadPreferenceSetting& readPref) + const ReadPreferenceSetting& readPref, + bool isExhaust) : _client(client), _originalHost(_client->getServerAddress()), _nsOrUuid(findRequest.getNamespaceOrUUID()), @@ -681,7 +521,7 @@ DBClientCursor::DBClientCursor(DBClientBase* client, _limit(findRequest.getLimit().value_or(0)), _findRequest(std::move(findRequest)), _readPref(readPref), - _opts(queryOptionsFromFindCommand(*_findRequest, _readPref)) { + _opts(queryOptionsFromFindCommand(*_findRequest, _readPref, isExhaust)) { // Internal clients should always pass an explicit readConcern. If the caller did not already // pass a readConcern than we must explicitly initialize an empty readConcern so that it ends up // in the serialized version of the find command which will be sent across the wire. diff --git a/src/mongo/client/dbclient_cursor.h b/src/mongo/client/dbclient_cursor.h index 520b1c1236c..941eda47318 100644 --- a/src/mongo/client/dbclient_cursor.h +++ b/src/mongo/client/dbclient_cursor.h @@ -31,7 +31,7 @@ #include <stack> -#include "mongo/client/query.h" +#include "mongo/client/client_deprecated.h" #include "mongo/db/dbmessage.h" #include "mongo/db/jsobj.h" #include "mongo/db/json.h" @@ -64,7 +64,7 @@ public: DBClientCursor(DBClientBase* client, const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, int limit, int nToSkip, const BSONObj* fieldsToReturn, @@ -83,7 +83,8 @@ public: DBClientCursor(DBClientBase* client, FindCommandRequest findRequest, - const ReadPreferenceSetting& readPref); + const ReadPreferenceSetting& readPref, + bool isExhaust); virtual ~DBClientCursor(); @@ -279,7 +280,7 @@ private: DBClientCursor(DBClientBase* client, const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, long long cursorId, int limit, int nToSkip, @@ -349,7 +350,7 @@ private: // OP_QUERY-inspired API. If the cursor was constructed using the 'FindCommandRequest'-based // API, these are initialized to their default values but never used. BSONObj _filter; - Query _querySettings; + client_deprecated::Query _querySettings; int _nToSkip = 0; const BSONObj* _fieldsToReturn = nullptr; boost::optional<BSONObj> _readConcernObj; diff --git a/src/mongo/client/dbclient_cursor_test.cpp b/src/mongo/client/dbclient_cursor_test.cpp index 10a23615ab0..21e9cfcf082 100644 --- a/src/mongo/client/dbclient_cursor_test.cpp +++ b/src/mongo/client/dbclient_cursor_test.cpp @@ -150,8 +150,8 @@ TEST_F(DBClientCursorTest, DBClientCursorCallsMetaDataReaderOncePerBatch) { // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor( - &conn, NamespaceStringOrUUID(nss), BSONObj{}, Query(), 0, 0, nullptr, 0, 0); + FindCommandRequest findCmd{nss}; + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, false); cursor.setBatchSize(2); // Set up mock 'find' response. @@ -197,15 +197,8 @@ TEST_F(DBClientCursorTest, DBClientCursorHandlesOpMsgExhaustCorrectly) { // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query(), - 0, - 0, - nullptr, - QueryOption_Exhaust, - 0); + FindCommandRequest findCmd{nss}; + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, true /*isExhaust*/); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -268,15 +261,8 @@ TEST_F(DBClientCursorTest, DBClientCursorResendsGetMoreIfMoreToComeFlagIsOmitted // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query(), - 0, - 0, - nullptr, - QueryOption_Exhaust, - 0); + FindCommandRequest findCmd{nss}; + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, true /*isExhaust*/); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -356,19 +342,11 @@ TEST_F(DBClientCursorTest, DBClientCursorResendsGetMoreIfMoreToComeFlagIsOmitted } TEST_F(DBClientCursorTest, DBClientCursorMoreThrowsExceptionOnNonOKResponse) { - // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query(), - 0, - 0, - nullptr, - QueryOption_Exhaust, - 0); + FindCommandRequest findCmd{nss}; + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, true /*isExhaust*/); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -395,19 +373,11 @@ TEST_F(DBClientCursorTest, DBClientCursorMoreThrowsExceptionOnNonOKResponse) { } TEST_F(DBClientCursorTest, DBClientCursorMoreThrowsExceptionWhenMoreToComeFlagSetWithZeroCursorId) { - // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query(), - 0, - 0, - nullptr, - QueryOption_Exhaust, - 0); + FindCommandRequest findCmd{nss}; + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, true /*isExhaust*/); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -436,19 +406,12 @@ TEST_F(DBClientCursorTest, DBClientCursorMoreThrowsExceptionWhenMoreToComeFlagSe } TEST_F(DBClientCursorTest, DBClientCursorPassesReadOnceFlag) { - // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query().readOnce(true), - 0, - 0, - nullptr, - /*QueryOption*/ 0, - 0); + FindCommandRequest findCmd{nss}; + findCmd.setReadOnce(true); + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, false); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -473,15 +436,10 @@ TEST_F(DBClientCursorTest, DBClientCursorPassesResumeFields) { // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query().requestResumeToken(true).resumeAfter(BSON("$recordId" << 5LL)), - 0, - 0, - nullptr, - /*QueryOption*/ 0, - 0); + FindCommandRequest findCmd{nss}; + findCmd.setRequestResumeToken(true); + findCmd.setResumeAfter(BSON("$recordId" << 5LL)); + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, false); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -514,15 +472,9 @@ TEST_F(DBClientCursorTest, DBClientCursorTailable) { // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query(), - 0, - 0, - nullptr, - QueryOption_CursorTailable, - 0); + FindCommandRequest findCmd{nss}; + findCmd.setTailable(true); + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, false); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -614,15 +566,10 @@ TEST_F(DBClientCursorTest, DBClientCursorTailableAwaitData) { // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query(), - 0, - 0, - nullptr, - QueryOption_CursorTailable | QueryOption_AwaitData, - 0); + FindCommandRequest findCmd{nss}; + findCmd.setTailable(true); + findCmd.setAwaitData(true); + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, false); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -681,15 +628,10 @@ TEST_F(DBClientCursorTest, DBClientCursorTailableAwaitDataExhaust) { // Set up the DBClientCursor and a mock client connection. DBClientConnectionForTest conn; const NamespaceString nss("test", "coll"); - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - BSONObj{}, - Query(), - 0, - 0, - nullptr, - QueryOption_CursorTailable | QueryOption_AwaitData | QueryOption_Exhaust, - 0); + FindCommandRequest findCmd{nss}; + findCmd.setTailable(true); + findCmd.setAwaitData(true); + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, true /*isExhaust*/); cursor.setBatchSize(0); // Set up mock 'find' response. @@ -835,15 +777,15 @@ TEST_F(DBClientCursorTest, DBClientCursorOplogQuery) { const long long maxTimeMS = 5000LL; const long long term = 5; - DBClientCursor cursor(&conn, - NamespaceStringOrUUID(nss), - filterObj, - Query().readConcern(readConcernObj).maxTimeMS(maxTimeMS).term(term), - 0, - 0, - nullptr, - QueryOption_CursorTailable | QueryOption_AwaitData, - 0); + FindCommandRequest findCmd{nss}; + findCmd.setFilter(filterObj); + findCmd.setReadConcern(readConcernObj); + findCmd.setMaxTimeMS(maxTimeMS); + findCmd.setTerm(term); + findCmd.setTailable(true); + findCmd.setAwaitData(true); + + DBClientCursor cursor(&conn, findCmd, ReadPreferenceSetting{}, false); cursor.setBatchSize(0); // Set up mock 'find' response. diff --git a/src/mongo/client/dbclient_rs.cpp b/src/mongo/client/dbclient_rs.cpp index 4b130c36142..bf4259dd6ed 100644 --- a/src/mongo/client/dbclient_rs.cpp +++ b/src/mongo/client/dbclient_rs.cpp @@ -107,8 +107,8 @@ const size_t MAX_RETRY = 3; * * @throws AssertionException if the read preference object is malformed */ -std::unique_ptr<ReadPreferenceSetting> _extractReadPref(const Query& querySettings, - int queryOptions) { +std::unique_ptr<ReadPreferenceSetting> _extractReadPref( + const client_deprecated::Query& querySettings, int queryOptions) { // Default read pref is primary only or secondary preferred with secondaryOK const auto defaultReadPref = queryOptions & QueryOption_SecondaryOk ? ReadPreference::SecondaryPreferred @@ -538,7 +538,8 @@ void DBClientReplicaSet::remove(const string& ns, } std::unique_ptr<DBClientCursor> DBClientReplicaSet::find(FindCommandRequest findRequest, - const ReadPreferenceSetting& readPref) { + const ReadPreferenceSetting& readPref, + ExhaustMode exhaustMode) { invariant(findRequest.getNamespaceOrUUID().nss()); const std::string nss = findRequest.getNamespaceOrUUID().nss()->ns(); if (_isSecondaryQuery(nss, findRequest.toBSON(BSONObj{}), readPref)) { @@ -562,7 +563,8 @@ std::unique_ptr<DBClientCursor> DBClientReplicaSet::find(FindCommandRequest find break; } - std::unique_ptr<DBClientCursor> cursor = conn->find(findRequest, readPref); + std::unique_ptr<DBClientCursor> cursor = + conn->find(findRequest, readPref, exhaustMode); return checkSecondaryQueryResult(std::move(cursor)); } catch (const DBException& ex) { @@ -587,13 +589,13 @@ std::unique_ptr<DBClientCursor> DBClientReplicaSet::find(FindCommandRequest find "dbclient_rs query to primary node", "replicaSet"_attr = _getMonitor()->getName()); - return checkPrimary()->find(std::move(findRequest), readPref); + return checkPrimary()->find(std::move(findRequest), readPref, exhaustMode); } unique_ptr<DBClientCursor> DBClientReplicaSet::query_DEPRECATED( const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, int limit, int nToSkip, const BSONObj* fieldsToReturn, @@ -824,8 +826,8 @@ void DBClientReplicaSet::say(Message& toSend, bool isRetry, string* actualServer DbMessage dm(toSend); QueryMessage qm(dm); - shared_ptr<ReadPreferenceSetting> readPref( - _extractReadPref(Query::fromBSONDeprecated(qm.query), qm.queryOptions)); + shared_ptr<ReadPreferenceSetting> readPref(_extractReadPref( + client_deprecated::Query::fromBSONDeprecated(qm.query), qm.queryOptions)); if (_isSecondaryQuery(qm.ns, qm.query, *readPref)) { LOGV2_DEBUG(20141, 3, @@ -990,8 +992,8 @@ bool DBClientReplicaSet::call(Message& toSend, QueryMessage qm(dm); ns = qm.ns; - shared_ptr<ReadPreferenceSetting> readPref( - _extractReadPref(Query::fromBSONDeprecated(qm.query), qm.queryOptions)); + shared_ptr<ReadPreferenceSetting> readPref(_extractReadPref( + client_deprecated::Query::fromBSONDeprecated(qm.query), qm.queryOptions)); if (_isSecondaryQuery(ns, qm.query, *readPref)) { LOGV2_DEBUG( 20145, diff --git a/src/mongo/client/dbclient_rs.h b/src/mongo/client/dbclient_rs.h index d31ff67f5b6..ebab6854ffc 100644 --- a/src/mongo/client/dbclient_rs.h +++ b/src/mongo/client/dbclient_rs.h @@ -57,6 +57,7 @@ typedef std::shared_ptr<ReplicaSetMonitor> ReplicaSetMonitorPtr; */ class DBClientReplicaSet : public DBClientBase { public: + using DBClientBase::find; using DBClientBase::query_DEPRECATED; /** Call connect() after constructing. autoReconnect is always on for DBClientReplicaSet @@ -89,13 +90,14 @@ public: // ----------- simple functions -------------- std::unique_ptr<DBClientCursor> find(FindCommandRequest findRequest, - const ReadPreferenceSetting& readPref) override; + const ReadPreferenceSetting& readPref, + ExhaustMode exhaustMode) override; /** throws userassertion "no primary found" */ std::unique_ptr<DBClientCursor> query_DEPRECATED( const NamespaceStringOrUUID& nsOrUuid, const BSONObj& filter, - const Query& querySettings, + const client_deprecated::Query& querySettings, int limit = 0, int nToSkip = 0, const BSONObj* fieldsToReturn = nullptr, diff --git a/src/mongo/client/dbclient_rs_test.cpp b/src/mongo/client/dbclient_rs_test.cpp index c04a2ddd7aa..2bbbc78858a 100644 --- a/src/mongo/client/dbclient_rs_test.cpp +++ b/src/mongo/client/dbclient_rs_test.cpp @@ -167,7 +167,7 @@ void assertWithBothQueryApis(DBClientReplicaSet& replConn, replConn.find(FindCommandRequest{nss}, ReadPreferenceSetting{readPref}); assertionFunc(std::move(cursor)); - Query readPrefHolder; + client_deprecated::Query readPrefHolder; readPrefHolder.readPref(readPref, BSONArray{}); cursor = replConn.query_DEPRECATED(nss, BSONObj{}, readPrefHolder); assertionFunc(std::move(cursor)); @@ -186,7 +186,7 @@ void assertBothQueryApisThrow(DBClientReplicaSet& replConn, ASSERT_THROWS(replConn.find(FindCommandRequest{nss}, ReadPreferenceSetting{readPref}), AssertionException); - Query readPrefHolder; + client_deprecated::Query readPrefHolder; readPrefHolder.readPref(readPref, BSONArray{}); ASSERT_THROWS(replConn.query_DEPRECATED(nss, BSONObj{}, readPrefHolder), AssertionException); } diff --git a/src/mongo/client/query.cpp b/src/mongo/client/query.cpp deleted file mode 100644 index 39d7e1316e2..00000000000 --- a/src/mongo/client/query.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * 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 - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * 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 Server Side 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/client/query.h" - -#include "mongo/base/status.h" -#include "mongo/base/status_with.h" -#include "mongo/bson/util/builder.h" - -namespace mongo { - -using std::string; - -const BSONField<BSONObj> Query::ReadPrefField("$readPreference"); -const BSONField<string> Query::ReadPrefModeField("mode"); -const BSONField<BSONArray> Query::ReadPrefTagsField("tags"); - -void Query::makeComplex() { - if (isComplex()) - return; - BSONObjBuilder b; - b.append("query", obj); - obj = b.obj(); -} - -Query& Query::sort(const BSONObj& s) { - appendComplex("orderby", s); - return *this; -} - -Query& Query::hint(BSONObj keyPattern) { - appendComplex("$hint", keyPattern); - return *this; -} - -bool Query::isComplex(const BSONObj& obj, bool* hasDollar) { - if (obj.hasElement("query")) { - if (hasDollar) - *hasDollar = false; - return true; - } - - if (obj.hasElement("$query")) { - if (hasDollar) - *hasDollar = true; - return true; - } - - return false; -} - -BSONObj Query::getFilter() const { - bool hasDollar; - if (!isComplex(&hasDollar)) - return obj; - - return obj.getObjectField(hasDollar ? "$query" : "query"); -} - -Query& Query::readPref(ReadPreference pref, const BSONArray& tags) { - appendComplex(ReadPrefField.name().c_str(), - ReadPreferenceSetting(pref, TagSet(tags)).toInnerBSON()); - return *this; -} - -bool Query::isComplex(bool* hasDollar) const { - return isComplex(obj, hasDollar); -} - -Query& Query::appendElements(BSONObj elements) { - makeComplex(); - BSONObjBuilder b(std::move(obj)); - b.appendElements(elements); - obj = b.obj(); - return *this; -} - -Query& Query::requestResumeToken(bool enable) { - appendComplex("$_requestResumeToken", enable); - return *this; -} - -Query& Query::resumeAfter(BSONObj point) { - appendComplex("$_resumeAfter", point); - return *this; -} - -Query& Query::maxTimeMS(long long timeout) { - appendComplex("$maxTimeMS", timeout); - return *this; -} - -Query& Query::term(long long value) { - appendComplex("term", value); - return *this; -} - -Query& Query::readConcern(BSONObj rc) { - appendComplex("readConcern", rc); - return *this; -} - -Query& Query::readOnce(bool enable) { - appendComplex("$readOnce", enable); - return *this; -} -} // namespace mongo |