diff options
Diffstat (limited to 'src/mongo/db/query/lite_parsed_query.cpp')
-rw-r--r-- | src/mongo/db/query/lite_parsed_query.cpp | 1490 |
1 files changed, 726 insertions, 764 deletions
diff --git a/src/mongo/db/query/lite_parsed_query.cpp b/src/mongo/db/query/lite_parsed_query.cpp index 1b2ce795eb0..6b8a25abe48 100644 --- a/src/mongo/db/query/lite_parsed_query.cpp +++ b/src/mongo/db/query/lite_parsed_query.cpp @@ -41,922 +41,884 @@ namespace mongo { - using std::unique_ptr; - using std::string; +using std::unique_ptr; +using std::string; - const string LiteParsedQuery::cmdOptionMaxTimeMS("maxTimeMS"); - const string LiteParsedQuery::queryOptionMaxTimeMS("$maxTimeMS"); +const string LiteParsedQuery::cmdOptionMaxTimeMS("maxTimeMS"); +const string LiteParsedQuery::queryOptionMaxTimeMS("$maxTimeMS"); - const string LiteParsedQuery::metaTextScore("textScore"); - const string LiteParsedQuery::metaGeoNearDistance("geoNearDistance"); - const string LiteParsedQuery::metaGeoNearPoint("geoNearPoint"); - const string LiteParsedQuery::metaRecordId("recordId"); - const string LiteParsedQuery::metaIndexKey("indexKey"); +const string LiteParsedQuery::metaTextScore("textScore"); +const string LiteParsedQuery::metaGeoNearDistance("geoNearDistance"); +const string LiteParsedQuery::metaGeoNearPoint("geoNearPoint"); +const string LiteParsedQuery::metaRecordId("recordId"); +const string LiteParsedQuery::metaIndexKey("indexKey"); - const int LiteParsedQuery::kDefaultBatchSize = 101; +const int LiteParsedQuery::kDefaultBatchSize = 101; namespace { - Status checkFieldType(const BSONElement& el, BSONType type) { - if (type != el.type()) { - str::stream ss; - ss << "Failed to parse: " << el.toString() << ". " - << "'" << el.fieldName() << "' field must be of BSON type " - << typeName(type) << "."; - return Status(ErrorCodes::FailedToParse, ss); - } +Status checkFieldType(const BSONElement& el, BSONType type) { + if (type != el.type()) { + str::stream ss; + ss << "Failed to parse: " << el.toString() << ". " + << "'" << el.fieldName() << "' field must be of BSON type " << typeName(type) << "."; + return Status(ErrorCodes::FailedToParse, ss); + } - return Status::OK(); - } - - // Find command field names. - const char kCmdName[] = "find"; - const char kFilterField[] = "filter"; - const char kProjectionField[] = "projection"; - const char kSortField[] = "sort"; - const char kHintField[] = "hint"; - const char kSkipField[] = "skip"; - const char kLimitField[] = "limit"; - const char kBatchSizeField[] = "batchSize"; - const char kSingleBatchField[] = "singleBatch"; - const char kCommentField[] = "comment"; - const char kMaxScanField[] = "maxScan"; - const char kMaxField[] = "max"; - const char kMinField[] = "min"; - const char kReturnKeyField[] = "returnKey"; - const char kShowRecordIdField[] = "showRecordId"; - const char kSnapshotField[] = "snapshot"; - const char kTailableField[] = "tailable"; - const char kOplogReplayField[] = "oplogReplay"; - const char kNoCursorTimeoutField[] = "noCursorTimeout"; - const char kAwaitDataField[] = "awaitData"; - const char kPartialField[] = "partial"; - -} // namespace - - // static - StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeFromFindCommand( - const NamespaceString& nss, - const BSONObj& cmdObj, - bool isExplain) { - - unique_ptr<LiteParsedQuery> pq(new LiteParsedQuery()); - pq->_ns = nss.ns(); - pq->_fromCommand = true; - pq->_explain = isExplain; - - // Parse the command BSON by looping through one element at a time. - BSONObjIterator it(cmdObj); - while (it.more()) { - BSONElement el = it.next(); - const char* fieldName = el.fieldName(); - if (str::equals(fieldName, kCmdName)) { - Status status = checkFieldType(el, String); - if (!status.isOK()) { - return status; - } + return Status::OK(); +} + +// Find command field names. +const char kCmdName[] = "find"; +const char kFilterField[] = "filter"; +const char kProjectionField[] = "projection"; +const char kSortField[] = "sort"; +const char kHintField[] = "hint"; +const char kSkipField[] = "skip"; +const char kLimitField[] = "limit"; +const char kBatchSizeField[] = "batchSize"; +const char kSingleBatchField[] = "singleBatch"; +const char kCommentField[] = "comment"; +const char kMaxScanField[] = "maxScan"; +const char kMaxField[] = "max"; +const char kMinField[] = "min"; +const char kReturnKeyField[] = "returnKey"; +const char kShowRecordIdField[] = "showRecordId"; +const char kSnapshotField[] = "snapshot"; +const char kTailableField[] = "tailable"; +const char kOplogReplayField[] = "oplogReplay"; +const char kNoCursorTimeoutField[] = "noCursorTimeout"; +const char kAwaitDataField[] = "awaitData"; +const char kPartialField[] = "partial"; + +} // namespace + +// static +StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeFromFindCommand( + const NamespaceString& nss, const BSONObj& cmdObj, bool isExplain) { + unique_ptr<LiteParsedQuery> pq(new LiteParsedQuery()); + pq->_ns = nss.ns(); + pq->_fromCommand = true; + pq->_explain = isExplain; + + // Parse the command BSON by looping through one element at a time. + BSONObjIterator it(cmdObj); + while (it.more()) { + BSONElement el = it.next(); + const char* fieldName = el.fieldName(); + if (str::equals(fieldName, kCmdName)) { + Status status = checkFieldType(el, String); + if (!status.isOK()) { + return status; + } + } else if (str::equals(fieldName, kFilterField)) { + Status status = checkFieldType(el, Object); + if (!status.isOK()) { + return status; + } + + pq->_filter = el.Obj().getOwned(); + } else if (str::equals(fieldName, kProjectionField)) { + Status status = checkFieldType(el, Object); + if (!status.isOK()) { + return status; + } + + pq->_proj = el.Obj().getOwned(); + } else if (str::equals(fieldName, kSortField)) { + Status status = checkFieldType(el, Object); + if (!status.isOK()) { + return status; + } + + // Sort document normalization. + BSONObj sort = el.Obj().getOwned(); + if (!isValidSortOrder(sort)) { + return Status(ErrorCodes::BadValue, "bad sort specification"); + } + + pq->_sort = sort; + } else if (str::equals(fieldName, kHintField)) { + BSONObj hintObj; + if (Object == el.type()) { + hintObj = cmdObj["hint"].Obj().getOwned(); + } else if (String == el.type()) { + hintObj = el.wrap("$hint"); + } else { + return Status(ErrorCodes::FailedToParse, + "hint must be either a string or nested object"); } - else if (str::equals(fieldName, kFilterField)) { - Status status = checkFieldType(el, Object); - if (!status.isOK()) { - return status; - } - pq->_filter = el.Obj().getOwned(); + pq->_hint = hintObj; + } else if (str::equals(fieldName, kSkipField)) { + if (!el.isNumber()) { + str::stream ss; + ss << "Failed to parse: " << cmdObj.toString() << ". " + << "'skip' field must be numeric."; + return Status(ErrorCodes::FailedToParse, ss); } - else if (str::equals(fieldName, kProjectionField)) { - Status status = checkFieldType(el, Object); - if (!status.isOK()) { - return status; - } - pq->_proj = el.Obj().getOwned(); + int skip = el.numberInt(); + if (skip < 0) { + return Status(ErrorCodes::BadValue, "skip value must be non-negative"); } - else if (str::equals(fieldName, kSortField)) { - Status status = checkFieldType(el, Object); - if (!status.isOK()) { - return status; - } - // Sort document normalization. - BSONObj sort = el.Obj().getOwned(); - if (!isValidSortOrder(sort)) { - return Status(ErrorCodes::BadValue, "bad sort specification"); - } - - pq->_sort = sort; + pq->_skip = skip; + } else if (str::equals(fieldName, kLimitField)) { + if (!el.isNumber()) { + str::stream ss; + ss << "Failed to parse: " << cmdObj.toString() << ". " + << "'limit' field must be numeric."; + return Status(ErrorCodes::FailedToParse, ss); } - else if (str::equals(fieldName, kHintField)) { - BSONObj hintObj; - if (Object == el.type()) { - hintObj = cmdObj["hint"].Obj().getOwned(); - } - else if (String == el.type()) { - hintObj = el.wrap("$hint"); - } - else { - return Status(ErrorCodes::FailedToParse, - "hint must be either a string or nested object"); - } - pq->_hint = hintObj; + int limit = el.numberInt(); + if (limit <= 0) { + return Status(ErrorCodes::BadValue, "limit value must be positive"); } - else if (str::equals(fieldName, kSkipField)) { - if (!el.isNumber()) { - str::stream ss; - ss << "Failed to parse: " << cmdObj.toString() << ". " - << "'skip' field must be numeric."; - return Status(ErrorCodes::FailedToParse, ss); - } - int skip = el.numberInt(); - if (skip < 0) { - return Status(ErrorCodes::BadValue, "skip value must be non-negative"); - } - - pq->_skip = skip; + pq->_limit = limit; + } else if (str::equals(fieldName, kBatchSizeField)) { + if (!el.isNumber()) { + str::stream ss; + ss << "Failed to parse: " << cmdObj.toString() << ". " + << "'batchSize' field must be numeric."; + return Status(ErrorCodes::FailedToParse, ss); } - else if (str::equals(fieldName, kLimitField)) { - if (!el.isNumber()) { - str::stream ss; - ss << "Failed to parse: " << cmdObj.toString() << ". " - << "'limit' field must be numeric."; - return Status(ErrorCodes::FailedToParse, ss); - } - int limit = el.numberInt(); - if (limit <= 0) { - return Status(ErrorCodes::BadValue, "limit value must be positive"); - } - - pq->_limit = limit; + int batchSize = el.numberInt(); + if (batchSize < 0) { + return Status(ErrorCodes::BadValue, "batchSize value must be non-negative"); } - else if (str::equals(fieldName, kBatchSizeField)) { - if (!el.isNumber()) { - str::stream ss; - ss << "Failed to parse: " << cmdObj.toString() << ". " - << "'batchSize' field must be numeric."; - return Status(ErrorCodes::FailedToParse, ss); - } - - int batchSize = el.numberInt(); - if (batchSize < 0) { - return Status(ErrorCodes::BadValue, "batchSize value must be non-negative"); - } - pq->_batchSize = batchSize; + pq->_batchSize = batchSize; + } else if (str::equals(fieldName, kSingleBatchField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kSingleBatchField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_wantMore = !el.boolean(); + pq->_wantMore = !el.boolean(); + } else if (str::equals(fieldName, kCommentField)) { + Status status = checkFieldType(el, String); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kCommentField)) { - Status status = checkFieldType(el, String); - if (!status.isOK()) { - return status; - } - pq->_comment = el.str(); + pq->_comment = el.str(); + } else if (str::equals(fieldName, kMaxScanField)) { + if (!el.isNumber()) { + str::stream ss; + ss << "Failed to parse: " << cmdObj.toString() << ". " + << "'maxScan' field must be numeric."; + return Status(ErrorCodes::FailedToParse, ss); } - else if (str::equals(fieldName, kMaxScanField)) { - if (!el.isNumber()) { - str::stream ss; - ss << "Failed to parse: " << cmdObj.toString() << ". " - << "'maxScan' field must be numeric."; - return Status(ErrorCodes::FailedToParse, ss); - } - int maxScan = el.numberInt(); - if (maxScan < 0) { - return Status(ErrorCodes::BadValue, "maxScan value must be non-negative"); - } - - pq->_maxScan = maxScan; + int maxScan = el.numberInt(); + if (maxScan < 0) { + return Status(ErrorCodes::BadValue, "maxScan value must be non-negative"); } - else if (str::equals(fieldName, cmdOptionMaxTimeMS.c_str())) { - StatusWith<int> maxTimeMS = parseMaxTimeMS(el); - if (!maxTimeMS.isOK()) { - return maxTimeMS.getStatus(); - } - pq->_maxTimeMS = maxTimeMS.getValue(); + pq->_maxScan = maxScan; + } else if (str::equals(fieldName, cmdOptionMaxTimeMS.c_str())) { + StatusWith<int> maxTimeMS = parseMaxTimeMS(el); + if (!maxTimeMS.isOK()) { + return maxTimeMS.getStatus(); } - else if (str::equals(fieldName, kMinField)) { - Status status = checkFieldType(el, Object); - if (!status.isOK()) { - return status; - } - pq->_min = el.Obj().getOwned(); + pq->_maxTimeMS = maxTimeMS.getValue(); + } else if (str::equals(fieldName, kMinField)) { + Status status = checkFieldType(el, Object); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kMaxField)) { - Status status = checkFieldType(el, Object); - if (!status.isOK()) { - return status; - } - pq->_max = el.Obj().getOwned(); + pq->_min = el.Obj().getOwned(); + } else if (str::equals(fieldName, kMaxField)) { + Status status = checkFieldType(el, Object); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kReturnKeyField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_returnKey = el.boolean(); + pq->_max = el.Obj().getOwned(); + } else if (str::equals(fieldName, kReturnKeyField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kShowRecordIdField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_showRecordId = el.boolean(); + pq->_returnKey = el.boolean(); + } else if (str::equals(fieldName, kShowRecordIdField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kSnapshotField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_snapshot = el.boolean(); + pq->_showRecordId = el.boolean(); + } else if (str::equals(fieldName, kSnapshotField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, "$readPreference")) { - pq->_hasReadPref = true; - } - else if (str::equals(fieldName, kTailableField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_tailable = el.boolean(); + pq->_snapshot = el.boolean(); + } else if (str::equals(fieldName, "$readPreference")) { + pq->_hasReadPref = true; + } else if (str::equals(fieldName, kTailableField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, "slaveOk")) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_slaveOk = el.boolean(); + pq->_tailable = el.boolean(); + } else if (str::equals(fieldName, "slaveOk")) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kOplogReplayField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_oplogReplay = el.boolean(); + pq->_slaveOk = el.boolean(); + } else if (str::equals(fieldName, kOplogReplayField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kNoCursorTimeoutField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_noCursorTimeout = el.boolean(); + pq->_oplogReplay = el.boolean(); + } else if (str::equals(fieldName, kNoCursorTimeoutField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kAwaitDataField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_awaitData = el.boolean(); + pq->_noCursorTimeout = el.boolean(); + } else if (str::equals(fieldName, kAwaitDataField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else if (str::equals(fieldName, kPartialField)) { - Status status = checkFieldType(el, Bool); - if (!status.isOK()) { - return status; - } - pq->_partial = el.boolean(); - } - else if (str::equals(fieldName, "options")) { - // 3.0.x versions of the shell may generate an explain of a find command with an - // 'options' field. We accept this only if the 'options' field is empty so that - // the shell's explain implementation is forwards compatible. - // - // TODO: Remove for 3.4. - if (!pq->isExplain()) { - return Status(ErrorCodes::FailedToParse, - "Field 'options' is only allowed for explain."); - } - - Status status = checkFieldType(el, Object); - if (!status.isOK()) { - return status; - } - - BSONObj optionsObj = el.Obj(); - if (!optionsObj.isEmpty()) { - return Status(ErrorCodes::FailedToParse, - str::stream() << "Failed to parse options: " - << optionsObj.toString() << ". " - << "You may need to update your shell or driver."); - } - } - else if (str::equals(fieldName, - repl::ReadAfterOpTimeArgs::kRootFieldName.c_str())) { - // read after optime parsing is handled elsewhere. - continue; + pq->_awaitData = el.boolean(); + } else if (str::equals(fieldName, kPartialField)) { + Status status = checkFieldType(el, Bool); + if (!status.isOK()) { + return status; } - else { + + pq->_partial = el.boolean(); + } else if (str::equals(fieldName, "options")) { + // 3.0.x versions of the shell may generate an explain of a find command with an + // 'options' field. We accept this only if the 'options' field is empty so that + // the shell's explain implementation is forwards compatible. + // + // TODO: Remove for 3.4. + if (!pq->isExplain()) { return Status(ErrorCodes::FailedToParse, - str::stream() << "Failed to parse: " << cmdObj.toString() << ". " - << "Unrecognized field '" << fieldName << "'."); + "Field 'options' is only allowed for explain."); } - } - pq->addMetaProjection(); + Status status = checkFieldType(el, Object); + if (!status.isOK()) { + return status; + } - Status validateStatus = pq->validateFindCmd(); - if (!validateStatus.isOK()) { - return validateStatus; + BSONObj optionsObj = el.Obj(); + if (!optionsObj.isEmpty()) { + return Status(ErrorCodes::FailedToParse, + str::stream() << "Failed to parse options: " << optionsObj.toString() + << ". " + << "You may need to update your shell or driver."); + } + } else if (str::equals(fieldName, repl::ReadAfterOpTimeArgs::kRootFieldName.c_str())) { + // read after optime parsing is handled elsewhere. + continue; + } else { + return Status(ErrorCodes::FailedToParse, + str::stream() << "Failed to parse: " << cmdObj.toString() << ". " + << "Unrecognized field '" << fieldName << "'."); } + } - return std::move(pq); - } - - // static - StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeAsOpQuery(const string& ns, - int ntoskip, - int ntoreturn, - int queryOptions, - const BSONObj& query, - const BSONObj& proj, - const BSONObj& sort, - const BSONObj& hint, - const BSONObj& minObj, - const BSONObj& maxObj, - bool snapshot, - bool explain) { - unique_ptr<LiteParsedQuery> pq(new LiteParsedQuery()); - pq->_sort = sort.getOwned(); - pq->_hint = hint.getOwned(); - pq->_min = minObj.getOwned(); - pq->_max = maxObj.getOwned(); - pq->_snapshot = snapshot; - pq->_explain = explain; - - Status status = pq->init(ns, ntoskip, ntoreturn, queryOptions, query, proj, false); - if (!status.isOK()) { - return status; - } + pq->addMetaProjection(); - return std::move(pq); + Status validateStatus = pq->validateFindCmd(); + if (!validateStatus.isOK()) { + return validateStatus; } - // static - StatusWith<unique_ptr<LiteParsedQuery>> - LiteParsedQuery::makeAsFindCmd(const NamespaceString& ns, - const BSONObj& query, - boost::optional<int> limit) { - unique_ptr<LiteParsedQuery> pq(new LiteParsedQuery()); + return std::move(pq); +} + +// static +StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeAsOpQuery(const string& ns, + int ntoskip, + int ntoreturn, + int queryOptions, + const BSONObj& query, + const BSONObj& proj, + const BSONObj& sort, + const BSONObj& hint, + const BSONObj& minObj, + const BSONObj& maxObj, + bool snapshot, + bool explain) { + unique_ptr<LiteParsedQuery> pq(new LiteParsedQuery()); + pq->_sort = sort.getOwned(); + pq->_hint = hint.getOwned(); + pq->_min = minObj.getOwned(); + pq->_max = maxObj.getOwned(); + pq->_snapshot = snapshot; + pq->_explain = explain; + + Status status = pq->init(ns, ntoskip, ntoreturn, queryOptions, query, proj, false); + if (!status.isOK()) { + return status; + } - pq->_fromCommand = true; - pq->_ns = ns.ns(); - pq->_filter = query.getOwned(); + return std::move(pq); +} - if (limit) { - if (limit <= 0) { - return Status(ErrorCodes::BadValue, "limit value must be positive"); - } - - pq->_limit = std::move(limit); - } +// static +StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeAsFindCmd(const NamespaceString& ns, + const BSONObj& query, + boost::optional<int> limit) { + unique_ptr<LiteParsedQuery> pq(new LiteParsedQuery()); - pq->addMetaProjection(); + pq->_fromCommand = true; + pq->_ns = ns.ns(); + pq->_filter = query.getOwned(); - Status validateStatus = pq->validateFindCmd(); - if (!validateStatus.isOK()) { - return validateStatus; + if (limit) { + if (limit <= 0) { + return Status(ErrorCodes::BadValue, "limit value must be positive"); } - return std::move(pq); + pq->_limit = std::move(limit); } - BSONObj LiteParsedQuery::asFindCommand() const { - BSONObjBuilder bob; + pq->addMetaProjection(); - const NamespaceString nss(_ns); - bob.append(kCmdName, nss.coll()); + Status validateStatus = pq->validateFindCmd(); + if (!validateStatus.isOK()) { + return validateStatus; + } - if (!_filter.isEmpty()) { - bob.append(kFilterField, _filter); - } + return std::move(pq); +} - if (!_proj.isEmpty()) { - bob.append(kProjectionField, _proj); - } +BSONObj LiteParsedQuery::asFindCommand() const { + BSONObjBuilder bob; - if (!_sort.isEmpty()) { - bob.append(kSortField, _sort); - } + const NamespaceString nss(_ns); + bob.append(kCmdName, nss.coll()); - if (!_hint.isEmpty()) { - bob.append(kHintField, _hint); - } + if (!_filter.isEmpty()) { + bob.append(kFilterField, _filter); + } - if (_skip > 0) { - bob.append(kSkipField, _skip); - } + if (!_proj.isEmpty()) { + bob.append(kProjectionField, _proj); + } - if (_limit) { - bob.append(kLimitField, *_limit); - } + if (!_sort.isEmpty()) { + bob.append(kSortField, _sort); + } - if (_batchSize) { - bob.append(kBatchSizeField, *_batchSize); - } + if (!_hint.isEmpty()) { + bob.append(kHintField, _hint); + } - if (!_wantMore) { - bob.append(kSingleBatchField, true); - } + if (_skip > 0) { + bob.append(kSkipField, _skip); + } - if (!_comment.empty()) { - bob.append(kCommentField, _comment); - } + if (_limit) { + bob.append(kLimitField, *_limit); + } - if (_maxScan > 0) { - bob.append(kMaxScanField, _maxScan); - } + if (_batchSize) { + bob.append(kBatchSizeField, *_batchSize); + } - if (_maxTimeMS > 0) { - bob.append(cmdOptionMaxTimeMS, _maxTimeMS); - } + if (!_wantMore) { + bob.append(kSingleBatchField, true); + } - if (!_max.isEmpty()) { - bob.append(kMaxField, _max); - } + if (!_comment.empty()) { + bob.append(kCommentField, _comment); + } - if (!_min.isEmpty()) { - bob.append(kMinField, _min); - } + if (_maxScan > 0) { + bob.append(kMaxScanField, _maxScan); + } - if (_returnKey) { - bob.append(kReturnKeyField, true); - } + if (_maxTimeMS > 0) { + bob.append(cmdOptionMaxTimeMS, _maxTimeMS); + } - if (_showRecordId) { - bob.append(kShowRecordIdField, true); - } + if (!_max.isEmpty()) { + bob.append(kMaxField, _max); + } - if (_snapshot) { - bob.append(kSnapshotField, true); - } + if (!_min.isEmpty()) { + bob.append(kMinField, _min); + } - if (_tailable) { - bob.append(kTailableField, true); - } + if (_returnKey) { + bob.append(kReturnKeyField, true); + } - if (_oplogReplay) { - bob.append(kOplogReplayField, true); - } + if (_showRecordId) { + bob.append(kShowRecordIdField, true); + } - if (_noCursorTimeout) { - bob.append(kNoCursorTimeoutField, true); - } + if (_snapshot) { + bob.append(kSnapshotField, true); + } - if (_awaitData) { - bob.append(kAwaitDataField, true); - } + if (_tailable) { + bob.append(kTailableField, true); + } - if (_partial) { - bob.append(kPartialField, true); - } + if (_oplogReplay) { + bob.append(kOplogReplayField, true); + } - return bob.obj(); + if (_noCursorTimeout) { + bob.append(kNoCursorTimeoutField, true); } - void LiteParsedQuery::addReturnKeyMetaProj() { - BSONObjBuilder projBob; - projBob.appendElements(_proj); - // We use $$ because it's never going to show up in a user's projection. - // The exact text doesn't matter. - BSONObj indexKey = BSON("$$" << - BSON("$meta" << LiteParsedQuery::metaIndexKey)); - projBob.append(indexKey.firstElement()); - _proj = projBob.obj(); + if (_awaitData) { + bob.append(kAwaitDataField, true); } - void LiteParsedQuery::addShowRecordIdMetaProj() { - BSONObjBuilder projBob; - projBob.appendElements(_proj); - BSONObj metaRecordId = BSON("$recordId" << - BSON("$meta" << LiteParsedQuery::metaRecordId)); - projBob.append(metaRecordId.firstElement()); - _proj = projBob.obj(); + if (_partial) { + bob.append(kPartialField, true); } - Status LiteParsedQuery::validate() const { - // Min and Max objects must have the same fields. - if (!_min.isEmpty() && !_max.isEmpty()) { - if (!_min.isFieldNamePrefixOf(_max) || - (_min.nFields() != _max.nFields())) { - return Status(ErrorCodes::BadValue, "min and max must have the same field names"); - } + return bob.obj(); +} + +void LiteParsedQuery::addReturnKeyMetaProj() { + BSONObjBuilder projBob; + projBob.appendElements(_proj); + // We use $$ because it's never going to show up in a user's projection. + // The exact text doesn't matter. + BSONObj indexKey = BSON("$$" << BSON("$meta" << LiteParsedQuery::metaIndexKey)); + projBob.append(indexKey.firstElement()); + _proj = projBob.obj(); +} + +void LiteParsedQuery::addShowRecordIdMetaProj() { + BSONObjBuilder projBob; + projBob.appendElements(_proj); + BSONObj metaRecordId = BSON("$recordId" << BSON("$meta" << LiteParsedQuery::metaRecordId)); + projBob.append(metaRecordId.firstElement()); + _proj = projBob.obj(); +} + +Status LiteParsedQuery::validate() const { + // Min and Max objects must have the same fields. + if (!_min.isEmpty() && !_max.isEmpty()) { + if (!_min.isFieldNamePrefixOf(_max) || (_min.nFields() != _max.nFields())) { + return Status(ErrorCodes::BadValue, "min and max must have the same field names"); } + } - // Can't combine a normal sort and a $meta projection on the same field. - BSONObjIterator projIt(_proj); - while (projIt.more()) { - BSONElement projElt = projIt.next(); - if (isTextScoreMeta(projElt)) { - BSONElement sortElt = _sort[projElt.fieldName()]; - if (!sortElt.eoo() && !isTextScoreMeta(sortElt)) { - return Status(ErrorCodes::BadValue, - "can't have a non-$meta sort on a $meta projection"); - } + // Can't combine a normal sort and a $meta projection on the same field. + BSONObjIterator projIt(_proj); + while (projIt.more()) { + BSONElement projElt = projIt.next(); + if (isTextScoreMeta(projElt)) { + BSONElement sortElt = _sort[projElt.fieldName()]; + if (!sortElt.eoo() && !isTextScoreMeta(sortElt)) { + return Status(ErrorCodes::BadValue, + "can't have a non-$meta sort on a $meta projection"); } } + } - // All fields with a $meta sort must have a corresponding $meta projection. - BSONObjIterator sortIt(_sort); - while (sortIt.more()) { - BSONElement sortElt = sortIt.next(); - if (isTextScoreMeta(sortElt)) { - BSONElement projElt = _proj[sortElt.fieldName()]; - if (projElt.eoo() || !isTextScoreMeta(projElt)) { - return Status(ErrorCodes::BadValue, - "must have $meta projection for all $meta sort keys"); - } + // All fields with a $meta sort must have a corresponding $meta projection. + BSONObjIterator sortIt(_sort); + while (sortIt.more()) { + BSONElement sortElt = sortIt.next(); + if (isTextScoreMeta(sortElt)) { + BSONElement projElt = _proj[sortElt.fieldName()]; + if (projElt.eoo() || !isTextScoreMeta(projElt)) { + return Status(ErrorCodes::BadValue, + "must have $meta projection for all $meta sort keys"); } } + } - if (_snapshot) { - if (!_sort.isEmpty()) { - return Status(ErrorCodes::BadValue, "E12001 can't use sort with $snapshot"); - } - if (!_hint.isEmpty()) { - return Status(ErrorCodes::BadValue, "E12002 can't use hint with $snapshot"); - } + if (_snapshot) { + if (!_sort.isEmpty()) { + return Status(ErrorCodes::BadValue, "E12001 can't use sort with $snapshot"); + } + if (!_hint.isEmpty()) { + return Status(ErrorCodes::BadValue, "E12002 can't use hint with $snapshot"); } - - return Status::OK(); } - // static - StatusWith<int> LiteParsedQuery::parseMaxTimeMSCommand(const BSONObj& cmdObj) { - return parseMaxTimeMS(cmdObj[cmdOptionMaxTimeMS]); + return Status::OK(); +} + +// static +StatusWith<int> LiteParsedQuery::parseMaxTimeMSCommand(const BSONObj& cmdObj) { + return parseMaxTimeMS(cmdObj[cmdOptionMaxTimeMS]); +} + +// static +StatusWith<int> LiteParsedQuery::parseMaxTimeMSQuery(const BSONObj& queryObj) { + return parseMaxTimeMS(queryObj[queryOptionMaxTimeMS]); +} + +// static +StatusWith<int> LiteParsedQuery::parseMaxTimeMS(const BSONElement& maxTimeMSElt) { + if (!maxTimeMSElt.eoo() && !maxTimeMSElt.isNumber()) { + return StatusWith<int>( + ErrorCodes::BadValue, + (StringBuilder() << maxTimeMSElt.fieldNameStringData() << " must be a number").str()); } - - // static - StatusWith<int> LiteParsedQuery::parseMaxTimeMSQuery(const BSONObj& queryObj) { - return parseMaxTimeMS(queryObj[queryOptionMaxTimeMS]); + long long maxTimeMSLongLong = maxTimeMSElt.safeNumberLong(); // returns 0 on EOO + if (maxTimeMSLongLong < 0 || maxTimeMSLongLong > INT_MAX) { + return StatusWith<int>( + ErrorCodes::BadValue, + (StringBuilder() << maxTimeMSElt.fieldNameStringData() << " is out of range").str()); } - - // static - StatusWith<int> LiteParsedQuery::parseMaxTimeMS(const BSONElement& maxTimeMSElt) { - if (!maxTimeMSElt.eoo() && !maxTimeMSElt.isNumber()) { - return StatusWith<int>(ErrorCodes::BadValue, - (StringBuilder() - << maxTimeMSElt.fieldNameStringData() - << " must be a number").str()); - } - long long maxTimeMSLongLong = maxTimeMSElt.safeNumberLong(); // returns 0 on EOO - if (maxTimeMSLongLong < 0 || maxTimeMSLongLong > INT_MAX) { - return StatusWith<int>(ErrorCodes::BadValue, - (StringBuilder() - << maxTimeMSElt.fieldNameStringData() - << " is out of range").str()); - } - double maxTimeMSDouble = maxTimeMSElt.numberDouble(); - if (maxTimeMSElt.type() == mongo::NumberDouble - && floor(maxTimeMSDouble) != maxTimeMSDouble) { - return StatusWith<int>(ErrorCodes::BadValue, - (StringBuilder() - << maxTimeMSElt.fieldNameStringData() - << " has non-integral value").str()); - } - return StatusWith<int>(static_cast<int>(maxTimeMSLongLong)); + double maxTimeMSDouble = maxTimeMSElt.numberDouble(); + if (maxTimeMSElt.type() == mongo::NumberDouble && floor(maxTimeMSDouble) != maxTimeMSDouble) { + return StatusWith<int>(ErrorCodes::BadValue, + (StringBuilder() << maxTimeMSElt.fieldNameStringData() + << " has non-integral value").str()); } + return StatusWith<int>(static_cast<int>(maxTimeMSLongLong)); +} - // static - bool LiteParsedQuery::isTextScoreMeta(BSONElement elt) { - // elt must be foo: {$meta: "textScore"} - if (mongo::Object != elt.type()) { - return false; - } - BSONObj metaObj = elt.Obj(); - BSONObjIterator metaIt(metaObj); - // must have exactly 1 element - if (!metaIt.more()) { - return false; - } - BSONElement metaElt = metaIt.next(); - if (!str::equals("$meta", metaElt.fieldName())) { - return false; - } - if (mongo::String != metaElt.type()) { - return false; - } - if (LiteParsedQuery::metaTextScore != metaElt.valuestr()) { - return false; - } - // must have exactly 1 element - if (metaIt.more()) { - return false; - } - return true; +// static +bool LiteParsedQuery::isTextScoreMeta(BSONElement elt) { + // elt must be foo: {$meta: "textScore"} + if (mongo::Object != elt.type()) { + return false; } + BSONObj metaObj = elt.Obj(); + BSONObjIterator metaIt(metaObj); + // must have exactly 1 element + if (!metaIt.more()) { + return false; + } + BSONElement metaElt = metaIt.next(); + if (!str::equals("$meta", metaElt.fieldName())) { + return false; + } + if (mongo::String != metaElt.type()) { + return false; + } + if (LiteParsedQuery::metaTextScore != metaElt.valuestr()) { + return false; + } + // must have exactly 1 element + if (metaIt.more()) { + return false; + } + return true; +} - // static - bool LiteParsedQuery::isRecordIdMeta(BSONElement elt) { - // elt must be foo: {$meta: "recordId"} - if (mongo::Object != elt.type()) { - return false; - } - BSONObj metaObj = elt.Obj(); - BSONObjIterator metaIt(metaObj); - // must have exactly 1 element - if (!metaIt.more()) { - return false; - } - BSONElement metaElt = metaIt.next(); - if (!str::equals("$meta", metaElt.fieldName())) { - return false; - } - if (mongo::String != metaElt.type()) { +// static +bool LiteParsedQuery::isRecordIdMeta(BSONElement elt) { + // elt must be foo: {$meta: "recordId"} + if (mongo::Object != elt.type()) { + return false; + } + BSONObj metaObj = elt.Obj(); + BSONObjIterator metaIt(metaObj); + // must have exactly 1 element + if (!metaIt.more()) { + return false; + } + BSONElement metaElt = metaIt.next(); + if (!str::equals("$meta", metaElt.fieldName())) { + return false; + } + if (mongo::String != metaElt.type()) { + return false; + } + if (LiteParsedQuery::metaRecordId != metaElt.valuestr()) { + return false; + } + // must have exactly 1 element + if (metaIt.more()) { + return false; + } + return true; +} + +// static +bool LiteParsedQuery::isValidSortOrder(const BSONObj& sortObj) { + BSONObjIterator i(sortObj); + while (i.more()) { + BSONElement e = i.next(); + // fieldNameSize() includes NULL terminator. For empty field name, + // we should be checking for 1 instead of 0. + if (1 == e.fieldNameSize()) { return false; } - if (LiteParsedQuery::metaRecordId != metaElt.valuestr()) { - return false; + if (isTextScoreMeta(e)) { + continue; } - // must have exactly 1 element - if (metaIt.more()) { + long long n = e.safeNumberLong(); + if (!(e.isNumber() && (n == -1LL || n == 1LL))) { return false; } - return true; } - - // static - bool LiteParsedQuery::isValidSortOrder(const BSONObj& sortObj) { - BSONObjIterator i(sortObj); - while (i.more()) { - BSONElement e = i.next(); - // fieldNameSize() includes NULL terminator. For empty field name, - // we should be checking for 1 instead of 0. - if (1 == e.fieldNameSize()) { - return false; - } - if (isTextScoreMeta(e)) { - continue; - } - long long n = e.safeNumberLong(); - if (!(e.isNumber() && (n == -1LL || n == 1LL))) { - return false; - } - } - return true; - } - - // static - bool LiteParsedQuery::isQueryIsolated(const BSONObj& query) { - BSONObjIterator iter(query); - while (iter.more()) { - BSONElement elt = iter.next(); - if (str::equals(elt.fieldName(), "$isolated") && elt.trueValue()) - return true; - if (str::equals(elt.fieldName(), "$atomic") && elt.trueValue()) - return true; - } - return false; + return true; +} + +// static +bool LiteParsedQuery::isQueryIsolated(const BSONObj& query) { + BSONObjIterator iter(query); + while (iter.more()) { + BSONElement elt = iter.next(); + if (str::equals(elt.fieldName(), "$isolated") && elt.trueValue()) + return true; + if (str::equals(elt.fieldName(), "$atomic") && elt.trueValue()) + return true; } - - // - // Old LiteParsedQuery parsing code: SOON TO BE DEPRECATED. - // - - // static - StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::fromLegacyQueryMessage( - const QueryMessage& qm) { - - unique_ptr<LiteParsedQuery> pq(new LiteParsedQuery()); - - Status status = pq->init(qm.ns, - qm.ntoskip, - qm.ntoreturn, - qm.queryOptions, - qm.query, - qm.fields, - true); - if (!status.isOK()) { - return status; - } - - return std::move(pq); + return false; +} + +// +// Old LiteParsedQuery parsing code: SOON TO BE DEPRECATED. +// + +// static +StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::fromLegacyQueryMessage( + const QueryMessage& qm) { + unique_ptr<LiteParsedQuery> pq(new LiteParsedQuery()); + + Status status = + pq->init(qm.ns, qm.ntoskip, qm.ntoreturn, qm.queryOptions, qm.query, qm.fields, true); + if (!status.isOK()) { + return status; } - Status LiteParsedQuery::init(const string& ns, int ntoskip, int ntoreturn, int queryOptions, - const BSONObj& queryObj, const BSONObj& proj, - bool fromQueryMessage) { - _ns = ns; - _skip = ntoskip; - _proj = proj.getOwned(); + return std::move(pq); +} + +Status LiteParsedQuery::init(const string& ns, + int ntoskip, + int ntoreturn, + int queryOptions, + const BSONObj& queryObj, + const BSONObj& proj, + bool fromQueryMessage) { + _ns = ns; + _skip = ntoskip; + _proj = proj.getOwned(); + + if (ntoreturn) { + _batchSize = ntoreturn; + } - if (ntoreturn) { - _batchSize = ntoreturn; - } + // Initialize flags passed as 'queryOptions' bit vector. + initFromInt(queryOptions); - // Initialize flags passed as 'queryOptions' bit vector. - initFromInt(queryOptions); + if (_skip < 0) { + return Status(ErrorCodes::BadValue, "bad skip value in query"); + } - if (_skip < 0) { - return Status(ErrorCodes::BadValue, "bad skip value in query"); + if (_batchSize && *_batchSize < 0) { + if (*_batchSize == std::numeric_limits<int>::min()) { + // _batchSize is negative but can't be negated. + return Status(ErrorCodes::BadValue, "bad limit value in query"); } - if (_batchSize && *_batchSize < 0) { - if (*_batchSize == std::numeric_limits<int>::min()) { - // _batchSize is negative but can't be negated. - return Status(ErrorCodes::BadValue, "bad limit value in query"); - } + // A negative number indicates that the cursor should be closed after the first batch. + _wantMore = false; + _batchSize = -*_batchSize; + } - // A negative number indicates that the cursor should be closed after the first batch. - _wantMore = false; - _batchSize = -*_batchSize; + if (fromQueryMessage) { + BSONElement queryField = queryObj["query"]; + if (!queryField.isABSONObj()) { + queryField = queryObj["$query"]; } - - if (fromQueryMessage) { - BSONElement queryField = queryObj["query"]; - if (!queryField.isABSONObj()) { queryField = queryObj["$query"]; } - if (queryField.isABSONObj()) { - _filter = queryField.embeddedObject().getOwned(); - Status status = initFullQuery(queryObj); - if (!status.isOK()) { return status; } - } - else { - _filter = queryObj.getOwned(); + if (queryField.isABSONObj()) { + _filter = queryField.embeddedObject().getOwned(); + Status status = initFullQuery(queryObj); + if (!status.isOK()) { + return status; } - } - else { - // This is the debugging code path. + } else { _filter = queryObj.getOwned(); } - - _hasReadPref = queryObj.hasField("$readPreference"); - - if (!isValidSortOrder(_sort)) { - return Status(ErrorCodes::BadValue, "bad sort specification"); - } - - return validate(); + } else { + // This is the debugging code path. + _filter = queryObj.getOwned(); } - Status LiteParsedQuery::initFullQuery(const BSONObj& top) { - BSONObjIterator i(top); - - while (i.more()) { - BSONElement e = i.next(); - const char* name = e.fieldName(); + _hasReadPref = queryObj.hasField("$readPreference"); - if (0 == strcmp("$orderby", name) || 0 == strcmp("orderby", name)) { - if (Object == e.type()) { - _sort = e.embeddedObject().getOwned(); - } - else if (Array == e.type()) { - _sort = 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 = _sort.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"); - } - } + if (!isValidSortOrder(_sort)) { + return Status(ErrorCodes::BadValue, "bad sort specification"); + } - _sort = b.obj(); - } - else { - return Status(ErrorCodes::BadValue, "sort must be object or array"); - } - } - else if ('$' == *name) { - name++; - if (str::equals("explain", name)) { - // Won't throw. - _explain = e.trueValue(); - } - else if (str::equals("snapshot", name)) { - // Won't throw. - _snapshot = e.trueValue(); - } - else if (str::equals("min", name)) { - if (!e.isABSONObj()) { - return Status(ErrorCodes::BadValue, "$min must be a BSONObj"); + return validate(); +} + +Status LiteParsedQuery::initFullQuery(const BSONObj& top) { + BSONObjIterator i(top); + + while (i.more()) { + BSONElement e = i.next(); + const char* name = e.fieldName(); + + if (0 == strcmp("$orderby", name) || 0 == strcmp("orderby", name)) { + if (Object == e.type()) { + _sort = e.embeddedObject().getOwned(); + } else if (Array == e.type()) { + _sort = 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 = _sort.getObjectField(p); + if (j.isEmpty()) { + break; } - _min = e.embeddedObject().getOwned(); - } - else if (str::equals("max", name)) { - if (!e.isABSONObj()) { - return Status(ErrorCodes::BadValue, "$max must be a BSONObj"); - } - _max = e.embeddedObject().getOwned(); - } - else if (str::equals("hint", name)) { - if (e.isABSONObj()) { - _hint = e.embeddedObject().getOwned(); - } - else if (String == e.type()) { - _hint = e.wrap(); + BSONElement e = j.firstElement(); + if (e.eoo()) { + return Status(ErrorCodes::BadValue, "bad order array"); } - else { - return Status(ErrorCodes::BadValue, - "$hint must be either a string or nested object"); + if (!e.isNumber()) { + return Status(ErrorCodes::BadValue, "bad order array [2]"); } - } - else if (str::equals("returnKey", name)) { - // Won't throw. - if (e.trueValue()) { - _returnKey = true; - addReturnKeyMetaProj(); - } - } - else if (str::equals("maxScan", name)) { - // Won't throw. - _maxScan = e.numberInt(); - } - else if (str::equals("showDiskLoc", name)) { - // Won't throw. - if (e.trueValue()) { - _showRecordId = true; - addShowRecordIdMetaProj(); + b.append(e); + (*p)++; + if (!(*p <= '9')) { + return Status(ErrorCodes::BadValue, "too many ordering elements"); } } - else if (str::equals("maxTimeMS", name)) { - StatusWith<int> maxTimeMS = parseMaxTimeMS(e); - if (!maxTimeMS.isOK()) { - return maxTimeMS.getStatus(); - } - _maxTimeMS = maxTimeMS.getValue(); + + _sort = b.obj(); + } else { + return Status(ErrorCodes::BadValue, "sort must be object or array"); + } + } else if ('$' == *name) { + name++; + if (str::equals("explain", name)) { + // Won't throw. + _explain = e.trueValue(); + } else if (str::equals("snapshot", name)) { + // Won't throw. + _snapshot = e.trueValue(); + } else if (str::equals("min", name)) { + if (!e.isABSONObj()) { + return Status(ErrorCodes::BadValue, "$min must be a BSONObj"); + } + _min = e.embeddedObject().getOwned(); + } else if (str::equals("max", name)) { + if (!e.isABSONObj()) { + return Status(ErrorCodes::BadValue, "$max must be a BSONObj"); + } + _max = e.embeddedObject().getOwned(); + } else if (str::equals("hint", name)) { + if (e.isABSONObj()) { + _hint = e.embeddedObject().getOwned(); + } else if (String == e.type()) { + _hint = e.wrap(); + } else { + return Status(ErrorCodes::BadValue, + "$hint must be either a string or nested object"); + } + } else if (str::equals("returnKey", name)) { + // Won't throw. + if (e.trueValue()) { + _returnKey = true; + addReturnKeyMetaProj(); + } + } else if (str::equals("maxScan", name)) { + // Won't throw. + _maxScan = e.numberInt(); + } else if (str::equals("showDiskLoc", name)) { + // Won't throw. + if (e.trueValue()) { + _showRecordId = true; + addShowRecordIdMetaProj(); + } + } else if (str::equals("maxTimeMS", name)) { + StatusWith<int> maxTimeMS = parseMaxTimeMS(e); + if (!maxTimeMS.isOK()) { + return maxTimeMS.getStatus(); } + _maxTimeMS = maxTimeMS.getValue(); } } - - return Status::OK(); } - int LiteParsedQuery::getOptions() const { - int options = 0; - if (_tailable) { options |= QueryOption_CursorTailable; } - if (_slaveOk) { options |= QueryOption_SlaveOk; } - if (_oplogReplay) { options |= QueryOption_OplogReplay; } - if (_noCursorTimeout) { options |= QueryOption_NoCursorTimeout; } - if (_awaitData) { options |= QueryOption_AwaitData; } - if (_exhaust) { options |= QueryOption_Exhaust; } - if (_partial) { options |= QueryOption_PartialResults; } - return options; - } + return Status::OK(); +} - void LiteParsedQuery::initFromInt(int options) { - _tailable = (options & QueryOption_CursorTailable) != 0; - _slaveOk = (options & QueryOption_SlaveOk) != 0; - _oplogReplay = (options & QueryOption_OplogReplay) != 0; - _noCursorTimeout = (options & QueryOption_NoCursorTimeout) != 0; - _awaitData = (options & QueryOption_AwaitData) != 0; - _exhaust = (options & QueryOption_Exhaust) != 0; - _partial = (options & QueryOption_PartialResults) != 0; +int LiteParsedQuery::getOptions() const { + int options = 0; + if (_tailable) { + options |= QueryOption_CursorTailable; } - - void LiteParsedQuery::addMetaProjection() { - // We might need to update the projection object with a $meta projection. - if (returnKey()) { - addReturnKeyMetaProj(); - } - - if (showRecordId()) { - addShowRecordIdMetaProj(); - } + if (_slaveOk) { + options |= QueryOption_SlaveOk; + } + if (_oplogReplay) { + options |= QueryOption_OplogReplay; + } + if (_noCursorTimeout) { + options |= QueryOption_NoCursorTimeout; + } + if (_awaitData) { + options |= QueryOption_AwaitData; + } + if (_exhaust) { + options |= QueryOption_Exhaust; + } + if (_partial) { + options |= QueryOption_PartialResults; + } + return options; +} + +void LiteParsedQuery::initFromInt(int options) { + _tailable = (options & QueryOption_CursorTailable) != 0; + _slaveOk = (options & QueryOption_SlaveOk) != 0; + _oplogReplay = (options & QueryOption_OplogReplay) != 0; + _noCursorTimeout = (options & QueryOption_NoCursorTimeout) != 0; + _awaitData = (options & QueryOption_AwaitData) != 0; + _exhaust = (options & QueryOption_Exhaust) != 0; + _partial = (options & QueryOption_PartialResults) != 0; +} + +void LiteParsedQuery::addMetaProjection() { + // We might need to update the projection object with a $meta projection. + if (returnKey()) { + addReturnKeyMetaProj(); } - Status LiteParsedQuery::validateFindCmd() { - if (isAwaitData() && !isTailable()) { - return Status(ErrorCodes::BadValue, "Cannot set awaitData without tailable"); - } + if (showRecordId()) { + addShowRecordIdMetaProj(); + } +} - return validate(); +Status LiteParsedQuery::validateFindCmd() { + if (isAwaitData() && !isTailable()) { + return Status(ErrorCodes::BadValue, "Cannot set awaitData without tailable"); } -} // namespace mongo + return validate(); +} + +} // namespace mongo |