1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <boost/optional.hpp> 34 #include <string> 35 36 #include "mongo/db/catalog/collection_options.h" 37 #include "mongo/db/jsobj.h" 38 #include "mongo/db/namespace_string.h" 39 #include "mongo/db/operation_context.h" 40 #include "mongo/db/query/tailable_mode.h" 41 42 namespace mongo { 43 44 class QueryMessage; 45 class Status; 46 template <typename T> 47 class StatusWith; 48 49 /** 50 * Parses the QueryMessage or find command received from the user and makes the various fields 51 * more easily accessible. 52 */ 53 class QueryRequest { 54 public: 55 static const char kFindCommandName[]; 56 static const char kShardVersionField[]; 57 58 QueryRequest(NamespaceString nss); 59 60 QueryRequest(CollectionUUID uuid); 61 62 /** 63 * Returns a non-OK status if any property of the QR has a bad value (e.g. a negative skip 64 * value) or if there is a bad combination of options (e.g. awaitData is illegal without 65 * tailable). 66 */ 67 Status validate() const; 68 69 /** 70 * Parses a find command object, 'cmdObj'. Caller must indicate whether or not this lite 71 * parsed query is an explained query or not via 'isExplain'. Accepts a NSS with which 72 * to initialize the QueryRequest if there is no UUID in cmdObj. 73 * 74 * Returns a heap allocated QueryRequest on success or an error if 'cmdObj' is not well 75 * formed. 76 */ 77 static StatusWith<std::unique_ptr<QueryRequest>> makeFromFindCommand(NamespaceString nss, 78 const BSONObj& cmdObj, 79 bool isExplain); 80 81 /** 82 * If _uuid exists for this QueryRequest, use it to update the value of _nss via the 83 * UUIDCatalog associated with opCtx. This should only be called when we hold a DBLock 84 * on the database to which _uuid belongs, if the _uuid is present in the UUIDCatalog. 85 */ 86 void refreshNSS(OperationContext* opCtx); 87 88 /** 89 * Converts this QR into a find command. 90 */ 91 BSONObj asFindCommand() const; 92 void asFindCommand(BSONObjBuilder* cmdBuilder) const; 93 94 /** 95 * Converts this QR into an aggregation using $match. If this QR has options that cannot be 96 * satisfied by aggregation, a non-OK status is returned and 'cmdBuilder' is not modified. 97 */ 98 StatusWith<BSONObj> asAggregationCommand() const; 99 100 /** 101 * Parses maxTimeMS from the BSONElement containing its value. 102 */ 103 static StatusWith<int> parseMaxTimeMS(BSONElement maxTimeMSElt); 104 105 /** 106 * Helper function to identify text search sort key 107 * Example: {a: {$meta: "textScore"}} 108 */ 109 static bool isTextScoreMeta(BSONElement elt); 110 111 /** 112 * Helper function to validate a sort object. 113 * Returns true if each element satisfies one of: 114 * 1. a number with value 1 115 * 2. a number with value -1 116 * 3. isTextScoreMeta 117 */ 118 static bool isValidSortOrder(const BSONObj& sortObj); 119 120 /** 121 * Returns true if the query described by "query" should execute 122 * at an elevated level of isolation (i.e., $isolated was specified). 123 */ 124 static bool isQueryIsolated(const BSONObj& query); 125 126 // Read preference is attached to commands in "wrapped" form, e.g. 127 // { $query: { <cmd>: ... } , <kWrappedReadPrefField>: { ... } } 128 // 129 // However, mongos internally "unwraps" the read preference and adds it as a parameter to the 130 // command, e.g. 131 // { <cmd>: ... , <kUnwrappedReadPrefField>: { <kWrappedReadPrefField>: { ... } } } 132 static const std::string kWrappedReadPrefField; 133 static const std::string kUnwrappedReadPrefField; 134 135 // Names of the maxTimeMS command and query option. 136 // Char arrays because they are used in static initialization. 137 static const char cmdOptionMaxTimeMS[]; 138 static const char queryOptionMaxTimeMS[]; 139 140 // Names of the $meta projection values. 141 static const std::string metaGeoNearDistance; 142 static const std::string metaGeoNearPoint; 143 static const std::string metaIndexKey; 144 static const std::string metaRecordId; 145 static const std::string metaSortKey; 146 static const std::string metaTextScore; 147 nss()148 const NamespaceString& nss() const { 149 invariant(!_nss.isEmpty()); 150 return _nss; 151 } 152 getFilter()153 const BSONObj& getFilter() const { 154 return _filter; 155 } 156 setFilter(BSONObj filter)157 void setFilter(BSONObj filter) { 158 _filter = filter.getOwned(); 159 } 160 getProj()161 const BSONObj& getProj() const { 162 return _proj; 163 } 164 setProj(BSONObj proj)165 void setProj(BSONObj proj) { 166 _proj = proj.getOwned(); 167 } 168 getSort()169 const BSONObj& getSort() const { 170 return _sort; 171 } 172 setSort(BSONObj sort)173 void setSort(BSONObj sort) { 174 _sort = sort.getOwned(); 175 } 176 getHint()177 const BSONObj& getHint() const { 178 return _hint; 179 } 180 setHint(BSONObj hint)181 void setHint(BSONObj hint) { 182 _hint = hint.getOwned(); 183 } 184 getReadConcern()185 const BSONObj& getReadConcern() const { 186 return _readConcern; 187 } 188 setReadConcern(BSONObj readConcern)189 void setReadConcern(BSONObj readConcern) { 190 _readConcern = readConcern.getOwned(); 191 } 192 getCollation()193 const BSONObj& getCollation() const { 194 return _collation; 195 } 196 setCollation(BSONObj collation)197 void setCollation(BSONObj collation) { 198 _collation = collation.getOwned(); 199 } 200 201 static const long long kDefaultBatchSize; 202 getSkip()203 boost::optional<long long> getSkip() const { 204 return _skip; 205 } 206 setSkip(boost::optional<long long> skip)207 void setSkip(boost::optional<long long> skip) { 208 _skip = skip; 209 } 210 getLimit()211 boost::optional<long long> getLimit() const { 212 return _limit; 213 } 214 setLimit(boost::optional<long long> limit)215 void setLimit(boost::optional<long long> limit) { 216 _limit = limit; 217 } 218 getBatchSize()219 boost::optional<long long> getBatchSize() const { 220 return _batchSize; 221 } 222 setBatchSize(boost::optional<long long> batchSize)223 void setBatchSize(boost::optional<long long> batchSize) { 224 _batchSize = batchSize; 225 } 226 getNToReturn()227 boost::optional<long long> getNToReturn() const { 228 return _ntoreturn; 229 } 230 setNToReturn(boost::optional<long long> ntoreturn)231 void setNToReturn(boost::optional<long long> ntoreturn) { 232 _ntoreturn = ntoreturn; 233 } 234 235 /** 236 * Returns batchSize or ntoreturn value if either is set. If neither is set, 237 * returns boost::none. 238 */ 239 boost::optional<long long> getEffectiveBatchSize() const; 240 wantMore()241 bool wantMore() const { 242 return _wantMore; 243 } 244 setWantMore(bool wantMore)245 void setWantMore(bool wantMore) { 246 _wantMore = wantMore; 247 } 248 isExplain()249 bool isExplain() const { 250 return _explain; 251 } 252 setExplain(bool explain)253 void setExplain(bool explain) { 254 _explain = explain; 255 } 256 getComment()257 const std::string& getComment() const { 258 return _comment; 259 } 260 setComment(const std::string & comment)261 void setComment(const std::string& comment) { 262 _comment = comment; 263 } 264 getUnwrappedReadPref()265 const BSONObj& getUnwrappedReadPref() const { 266 return _unwrappedReadPref; 267 } 268 setUnwrappedReadPref(BSONObj unwrappedReadPref)269 void setUnwrappedReadPref(BSONObj unwrappedReadPref) { 270 _unwrappedReadPref = unwrappedReadPref.getOwned(); 271 } 272 getMaxScan()273 int getMaxScan() const { 274 return _maxScan; 275 } 276 setMaxScan(int maxScan)277 void setMaxScan(int maxScan) { 278 _maxScan = maxScan; 279 } 280 getMaxTimeMS()281 int getMaxTimeMS() const { 282 return _maxTimeMS; 283 } 284 setMaxTimeMS(int maxTimeMS)285 void setMaxTimeMS(int maxTimeMS) { 286 _maxTimeMS = maxTimeMS; 287 } 288 getMin()289 const BSONObj& getMin() const { 290 return _min; 291 } 292 setMin(BSONObj min)293 void setMin(BSONObj min) { 294 _min = min.getOwned(); 295 } 296 getMax()297 const BSONObj& getMax() const { 298 return _max; 299 } 300 setMax(BSONObj max)301 void setMax(BSONObj max) { 302 _max = max.getOwned(); 303 } 304 returnKey()305 bool returnKey() const { 306 return _returnKey; 307 } 308 setReturnKey(bool returnKey)309 void setReturnKey(bool returnKey) { 310 _returnKey = returnKey; 311 } 312 showRecordId()313 bool showRecordId() const { 314 return _showRecordId; 315 } 316 setShowRecordId(bool showRecordId)317 void setShowRecordId(bool showRecordId) { 318 _showRecordId = showRecordId; 319 } 320 isSnapshot()321 bool isSnapshot() const { 322 return _snapshot; 323 } 324 setSnapshot(bool snapshot)325 void setSnapshot(bool snapshot) { 326 _snapshot = snapshot; 327 } 328 hasReadPref()329 bool hasReadPref() const { 330 return _hasReadPref; 331 } 332 setHasReadPref(bool hasReadPref)333 void setHasReadPref(bool hasReadPref) { 334 _hasReadPref = hasReadPref; 335 } 336 isTailable()337 bool isTailable() const { 338 return _tailableMode == TailableMode::kTailable || 339 _tailableMode == TailableMode::kTailableAndAwaitData; 340 } 341 isTailableAndAwaitData()342 bool isTailableAndAwaitData() const { 343 return _tailableMode == TailableMode::kTailableAndAwaitData; 344 } 345 setTailableMode(TailableMode tailableMode)346 void setTailableMode(TailableMode tailableMode) { 347 _tailableMode = tailableMode; 348 } 349 getTailableMode()350 TailableMode getTailableMode() const { 351 return _tailableMode; 352 } 353 isSlaveOk()354 bool isSlaveOk() const { 355 return _slaveOk; 356 } 357 setSlaveOk(bool slaveOk)358 void setSlaveOk(bool slaveOk) { 359 _slaveOk = slaveOk; 360 } 361 isOplogReplay()362 bool isOplogReplay() const { 363 return _oplogReplay; 364 } 365 setOplogReplay(bool oplogReplay)366 void setOplogReplay(bool oplogReplay) { 367 _oplogReplay = oplogReplay; 368 } 369 isNoCursorTimeout()370 bool isNoCursorTimeout() const { 371 return _noCursorTimeout; 372 } 373 setNoCursorTimeout(bool noCursorTimeout)374 void setNoCursorTimeout(bool noCursorTimeout) { 375 _noCursorTimeout = noCursorTimeout; 376 } 377 isExhaust()378 bool isExhaust() const { 379 return _exhaust; 380 } 381 setExhaust(bool exhaust)382 void setExhaust(bool exhaust) { 383 _exhaust = exhaust; 384 } 385 isAllowPartialResults()386 bool isAllowPartialResults() const { 387 return _allowPartialResults; 388 } 389 setAllowPartialResults(bool allowPartialResults)390 void setAllowPartialResults(bool allowPartialResults) { 391 _allowPartialResults = allowPartialResults; 392 } 393 getReplicationTerm()394 boost::optional<long long> getReplicationTerm() const { 395 return _replicationTerm; 396 } 397 setReplicationTerm(boost::optional<long long> replicationTerm)398 void setReplicationTerm(boost::optional<long long> replicationTerm) { 399 _replicationTerm = replicationTerm; 400 } 401 402 /** 403 * Return options as a bit vector. 404 */ 405 int getOptions() const; 406 407 // 408 // Old parsing code: SOON TO BE DEPRECATED. 409 // 410 411 /** 412 * Parse the provided QueryMessage and return a heap constructed QueryRequest, which 413 * represents it or an error. 414 */ 415 static StatusWith<std::unique_ptr<QueryRequest>> fromLegacyQueryMessage(const QueryMessage& qm); 416 417 /** 418 * Parse the provided legacy query object and parameters to construct a QueryRequest. 419 */ 420 static StatusWith<std::unique_ptr<QueryRequest>> fromLegacyQuery(NamespaceString nss, 421 const BSONObj& queryObj, 422 const BSONObj& proj, 423 int ntoskip, 424 int ntoreturn, 425 int queryOptions); 426 427 private: 428 static StatusWith<std::unique_ptr<QueryRequest>> parseFromFindCommand( 429 std::unique_ptr<QueryRequest> qr, const BSONObj& cmdObj, bool isExplain); 430 Status init(int ntoskip, 431 int ntoreturn, 432 int queryOptions, 433 const BSONObj& queryObj, 434 const BSONObj& proj, 435 bool fromQueryMessage); 436 437 Status initFullQuery(const BSONObj& top); 438 439 /** 440 * Updates the projection object with a $meta projection for the returnKey option. 441 */ 442 void addReturnKeyMetaProj(); 443 444 /** 445 * Updates the projection object with a $meta projection for the showRecordId option. 446 */ 447 void addShowRecordIdMetaProj(); 448 449 /** 450 * Initializes options based on the value of the 'options' bit vector. 451 * 452 * This contains flags such as tailable, exhaust, and noCursorTimeout. 453 */ 454 void initFromInt(int options); 455 456 /** 457 * Add the meta projection to this object if needed. 458 */ 459 void addMetaProjection(); 460 461 NamespaceString _nss; 462 OptionalCollectionUUID _uuid; 463 464 BSONObj _filter; 465 BSONObj _proj; 466 BSONObj _sort; 467 // The hint provided, if any. If the hint was by index key pattern, the value of '_hint' is 468 // the key pattern hinted. If the hint was by index name, the value of '_hint' is 469 // {$hint: <String>}, where <String> is the index name hinted. 470 BSONObj _hint; 471 // The read concern is parsed elsewhere. 472 BSONObj _readConcern; 473 // The collation is parsed elsewhere. 474 BSONObj _collation; 475 476 // The unwrapped readPreference object, if one was given to us by the mongos command processor. 477 // This object will be empty when no readPreference is specified or if the request does not 478 // originate from mongos. 479 BSONObj _unwrappedReadPref; 480 481 bool _wantMore = true; 482 483 // Must be either unset or positive. Negative skip is illegal and a skip of zero received from 484 // the client is interpreted as the absence of a skip value. 485 boost::optional<long long> _skip; 486 487 // Must be either unset or positive. Negative limit is illegal and a limit value of zero 488 // received from the client is interpreted as the absence of a limit value. 489 boost::optional<long long> _limit; 490 491 // Must be either unset or non-negative. Negative batchSize is illegal but batchSize of 0 is 492 // allowed. 493 boost::optional<long long> _batchSize; 494 495 // Set only when parsed from an OP_QUERY find message. The value is computed by driver or shell 496 // and is set to be a min of batchSize and limit provided by user. QR can have set either 497 // ntoreturn or batchSize / limit. 498 boost::optional<long long> _ntoreturn; 499 500 bool _explain = false; 501 502 std::string _comment; 503 504 int _maxScan = 0; 505 506 // A user-specified maxTimeMS limit, or a value of '0' if not specified. 507 int _maxTimeMS = 0; 508 509 BSONObj _min; 510 BSONObj _max; 511 512 bool _returnKey = false; 513 bool _showRecordId = false; 514 bool _snapshot = false; 515 bool _hasReadPref = false; 516 517 // Options that can be specified in the OP_QUERY 'flags' header. 518 TailableMode _tailableMode = TailableMode::kNormal; 519 bool _slaveOk = false; 520 bool _oplogReplay = false; 521 bool _noCursorTimeout = false; 522 bool _exhaust = false; 523 bool _allowPartialResults = false; 524 525 boost::optional<long long> _replicationTerm; 526 }; 527 528 } // namespace mongo 529