diff options
Diffstat (limited to 'src/mongo/db/commands/distinct.cpp')
-rw-r--r-- | src/mongo/db/commands/distinct.cpp | 235 |
1 files changed, 120 insertions, 115 deletions
diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index ceae947fc52..2c281140c63 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -47,137 +47,142 @@ namespace mongo { - using std::unique_ptr; - using std::string; - using std::stringstream; - - class DistinctCommand : public Command { - public: - DistinctCommand() : Command("distinct") {} - - virtual bool slaveOk() const { return false; } - virtual bool slaveOverrideOk() const { return true; } - virtual bool isWriteCommandForConfigServer() const { return false; } - - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - ActionSet actions; - actions.addAction(ActionType::find); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); +using std::unique_ptr; +using std::string; +using std::stringstream; + +class DistinctCommand : public Command { +public: + DistinctCommand() : Command("distinct") {} + + virtual bool slaveOk() const { + return false; + } + virtual bool slaveOverrideOk() const { + return true; + } + virtual bool isWriteCommandForConfigServer() const { + return false; + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + ActionSet actions; + actions.addAction(ActionType::find); + out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + } + + virtual void help(stringstream& help) const { + help << "{ distinct : 'collection name' , key : 'a.b' , query : {} }"; + } + + bool run(OperationContext* txn, + const string& dbname, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Timer t; + + // ensure that the key is a string + uassert(18510, + mongoutils::str::stream() << "The first argument to the distinct command " + << "must be a string but was a " + << typeName(cmdObj["key"].type()), + cmdObj["key"].type() == mongo::String); + + // ensure that the where clause is a document + if (cmdObj["query"].isNull() == false && cmdObj["query"].eoo() == false) { + uassert(18511, + mongoutils::str::stream() << "The query for the distinct command must be a " + << "document but was a " + << typeName(cmdObj["query"].type()), + cmdObj["query"].type() == mongo::Object); } - virtual void help( stringstream &help ) const { - help << "{ distinct : 'collection name' , key : 'a.b' , query : {} }"; - } + string key = cmdObj["key"].valuestrsafe(); + BSONObj keyPattern = BSON(key << 1); - bool run(OperationContext* txn, - const string& dbname, - BSONObj& cmdObj, - int, - string& errmsg, - BSONObjBuilder& result) { - - Timer t; - - // ensure that the key is a string - uassert(18510, - mongoutils::str::stream() << "The first argument to the distinct command " << - "must be a string but was a " << typeName(cmdObj["key"].type()), - cmdObj["key"].type() == mongo::String); - - // ensure that the where clause is a document - if( cmdObj["query"].isNull() == false && cmdObj["query"].eoo() == false ){ - uassert(18511, - mongoutils::str::stream() << "The query for the distinct command must be a " << - "document but was a " << typeName(cmdObj["query"].type()), - cmdObj["query"].type() == mongo::Object); - } + BSONObj query = getQuery(cmdObj); - string key = cmdObj["key"].valuestrsafe(); - BSONObj keyPattern = BSON( key << 1 ); + int bufSize = BSONObjMaxUserSize - 4096; + BufBuilder bb(bufSize); + char* start = bb.buf(); - BSONObj query = getQuery( cmdObj ); + BSONArrayBuilder arr(bb); + BSONElementSet values; - int bufSize = BSONObjMaxUserSize - 4096; - BufBuilder bb( bufSize ); - char * start = bb.buf(); + const string ns = parseNs(dbname, cmdObj); + AutoGetCollectionForRead ctx(txn, ns); - BSONArrayBuilder arr( bb ); - BSONElementSet values; + Collection* collection = ctx.getCollection(); + if (!collection) { + result.appendArray("values", BSONObj()); + result.append("stats", BSON("n" << 0 << "nscanned" << 0 << "nscannedObjects" << 0)); + return true; + } - const string ns = parseNs(dbname, cmdObj); - AutoGetCollectionForRead ctx(txn, ns); + PlanExecutor* rawExec; + Status status = + getExecutorDistinct(txn, collection, query, key, PlanExecutor::YIELD_AUTO, &rawExec); + if (!status.isOK()) { + uasserted(17216, + mongoutils::str::stream() << "Can't get executor for query " << query << ": " + << status.toString()); + return 0; + } - Collection* collection = ctx.getCollection(); - if (!collection) { - result.appendArray( "values" , BSONObj() ); - result.append("stats", BSON("n" << 0 << - "nscanned" << 0 << - "nscannedObjects" << 0)); - return true; - } + unique_ptr<PlanExecutor> exec(rawExec); + + BSONObj obj; + PlanExecutor::ExecState state; + while (PlanExecutor::ADVANCED == (state = exec->getNext(&obj, NULL))) { + // Distinct expands arrays. + // + // If our query is covered, each value of the key should be in the index key and + // available to us without this. If a collection scan is providing the data, we may + // have to expand an array. + BSONElementSet elts; + obj.getFieldsDotted(key, elts); + + for (BSONElementSet::iterator it = elts.begin(); it != elts.end(); ++it) { + BSONElement elt = *it; + if (values.count(elt)) { + continue; + } + int currentBufPos = bb.len(); - PlanExecutor* rawExec; - Status status = getExecutorDistinct(txn, - collection, - query, - key, - PlanExecutor::YIELD_AUTO, - &rawExec); - if (!status.isOK()) { - uasserted(17216, mongoutils::str::stream() << "Can't get executor for query " - << query << ": " << status.toString()); - return 0; - } + uassert(17217, + "distinct too big, 16mb cap", + (currentBufPos + elt.size() + 1024) < bufSize); - unique_ptr<PlanExecutor> exec(rawExec); - - BSONObj obj; - PlanExecutor::ExecState state; - while (PlanExecutor::ADVANCED == (state = exec->getNext(&obj, NULL))) { - // Distinct expands arrays. - // - // If our query is covered, each value of the key should be in the index key and - // available to us without this. If a collection scan is providing the data, we may - // have to expand an array. - BSONElementSet elts; - obj.getFieldsDotted(key, elts); - - for (BSONElementSet::iterator it = elts.begin(); it != elts.end(); ++it) { - BSONElement elt = *it; - if (values.count(elt)) { continue; } - int currentBufPos = bb.len(); - - uassert(17217, "distinct too big, 16mb cap", - (currentBufPos + elt.size() + 1024) < bufSize); - - arr.append(elt); - BSONElement x(start + currentBufPos); - values.insert(x); - } + arr.append(elt); + BSONElement x(start + currentBufPos); + values.insert(x); } + } - // Get summary information about the plan. - PlanSummaryStats stats; - Explain::getSummaryStats(exec.get(), &stats); - - verify( start == bb.buf() ); + // Get summary information about the plan. + PlanSummaryStats stats; + Explain::getSummaryStats(exec.get(), &stats); - result.appendArray( "values" , arr.done() ); + verify(start == bb.buf()); - { - BSONObjBuilder b; - b.appendNumber( "n" , stats.nReturned ); - b.appendNumber( "nscanned" , stats.totalKeysExamined ); - b.appendNumber( "nscannedObjects" , stats.totalDocsExamined ); - b.appendNumber( "timems" , t.millis() ); - b.append( "planSummary" , Explain::getPlanSummary(exec.get()) ); - result.append( "stats" , b.obj() ); - } + result.appendArray("values", arr.done()); - return true; + { + BSONObjBuilder b; + b.appendNumber("n", stats.nReturned); + b.appendNumber("nscanned", stats.totalKeysExamined); + b.appendNumber("nscannedObjects", stats.totalDocsExamined); + b.appendNumber("timems", t.millis()); + b.append("planSummary", Explain::getPlanSummary(exec.get())); + result.append("stats", b.obj()); } - } distinctCmd; + + return true; + } +} distinctCmd; } // namespace mongo |