void run() { Client::WriteContext ctx(&_txn, ns()); Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(&_txn, ns()); if (!coll) { coll = db->createCollection(&_txn, ns()); } const int N = 50; for (int i = 0; i < N; ++i) { // We insert a:1 c:i for i=0..49 but in reverse order for the heck of it. insert(BSON("a" << 1 << "c" << N - i - 1)); insert(BSON("b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << -1); BSONObj secondIndex = BSON("b" << 1 << "c" << -1); addIndex(firstIndex); addIndex(secondIndex); WorkingSet* ws = new WorkingSet(); // Sort by c:-1 MergeSortStageParams msparams; msparams.pattern = BSON("c" << -1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMaxKey(1); params.bounds.endKey = objWithMinKey(1); params.bounds.endKeyInclusive = true; // This is the direction along the index. params.direction = 1; ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); for (int i = 0; i < N; ++i) { BSONObj first, second; ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&first, NULL)); ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(N - i - 1, first["c"].numberInt()); ASSERT((first.hasField("a") && second.hasField("b")) || (first.hasField("b") && second.hasField("a"))); } // Should be done now. BSONObj foo; ASSERT_EQUALS(Runner::RUNNER_EOF, runner.getNext(&foo, NULL)); }
void run() { Client::WriteContext ctx(ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { coll = db->createCollection(&txn, ns()); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1); addIndex(firstIndex); addIndex(secondIndex); WorkingSet* ws = new WorkingSet(); // Sort by c:1 MergeSortStageParams msparams; msparams.dedup = false; msparams.pattern = BSON("c" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; ms->addChild(new IndexScan(params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(params, ws, NULL)); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); for (int i = 0; i < N; ++i) { BSONObj first, second; // We inserted N objects but we get 2 * N from the runner because of dups. ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&first, NULL)); ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(i, first["c"].numberInt()); ASSERT((first.hasField("a") && second.hasField("b")) || (first.hasField("b") && second.hasField("a"))); } // Should be done now. BSONObj foo; ASSERT_EQUALS(Runner::RUNNER_EOF, runner.getNext(&foo, NULL)); }
void run() { Client::WriteContext ctx(&_txn, ns()); Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(&_txn, ns()); if (!coll) { coll = db->createCollection(&_txn, ns()); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "c" << i)); insert(BSON("b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1); addIndex(firstIndex); addIndex(secondIndex); WorkingSet* ws = new WorkingSet(); // Sort by c:1 MergeSortStageParams msparams; msparams.pattern = BSON("c" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:51 (EOF) params.descriptor = getIndex(secondIndex, coll); params.bounds.startKey = BSON("" << 51 << "" << MinKey); params.bounds.endKey = BSON("" << 51 << "" << MaxKey); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); // Only getting results from the a:1 index scan. for (int i = 0; i < N; ++i) { BSONObj obj; ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&obj, NULL)); ASSERT_EQUALS(i, obj["c"].numberInt()); ASSERT_EQUALS(1, obj["a"].numberInt()); } // Should be done now. BSONObj foo; ASSERT_EQUALS(Runner::RUNNER_EOF, runner.getNext(&foo, NULL)); }
void run() { OldClientWriteContext ctx(&_txn, ns()); Database* db = ctx.db(); Collection* coll = db->getCollection(ns()); if (!coll) { WriteUnitOfWork wuow(&_txn); coll = db->createCollection(&_txn, ns()); wuow.commit(); } unique_ptr<WorkingSet> ws = make_unique<WorkingSet>(); // Sort by foo:1 MergeSortStageParams msparams; msparams.pattern = BSON("foo" << 1); MergeSortStage* ms = new MergeSortStage(&_txn, msparams, ws.get(), coll); IndexScanParams params; params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; int numIndices = 20; for (int i = 0; i < numIndices; ++i) { // 'a', 'b', ... string index(1, 'a' + i); insert(BSON(index << 1 << "foo" << i)); BSONObj indexSpec = BSON(index << 1 << "foo" << 1); addIndex(indexSpec); params.descriptor = getIndex(indexSpec, coll); ms->addChild(new IndexScan(&_txn, params, ws.get(), NULL)); } unique_ptr<FetchStage> fetchStage = make_unique<FetchStage>(&_txn, ws.get(), ms, nullptr, coll); auto statusWithPlanExecutor = PlanExecutor::make( &_txn, std::move(ws), std::move(fetchStage), coll, PlanExecutor::YIELD_MANUAL); ASSERT_OK(statusWithPlanExecutor.getStatus()); unique_ptr<PlanExecutor> exec = std::move(statusWithPlanExecutor.getValue()); for (int i = 0; i < numIndices; ++i) { BSONObj obj; ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&obj, NULL)); ASSERT_EQUALS(i, obj["foo"].numberInt()); string index(1, 'a' + i); ASSERT_EQUALS(1, obj[index].numberInt()); } // Should be done now. BSONObj foo; ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&foo, NULL)); }
void run() { Client::WriteContext ctx(&_txn, ns()); Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(&_txn, ns()); if (!coll) { WriteUnitOfWork wuow(&_txn); coll = db->createCollection(&_txn, ns()); wuow.commit(); } WorkingSet* ws = new WorkingSet(); // Sort by foo:1 MergeSortStageParams msparams; msparams.pattern = BSON("foo" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); IndexScanParams params; params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; int numIndices = 20; for (int i = 0; i < numIndices; ++i) { // 'a', 'b', ... string index(1, 'a' + i); insert(BSON(index << 1 << "foo" << i)); BSONObj indexSpec = BSON(index << 1 << "foo" << 1); addIndex(indexSpec); params.descriptor = getIndex(indexSpec, coll); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); } PlanExecutor* rawExec; Status status = PlanExecutor::make(&_txn, ws, new FetchStage(&_txn, ws, ms, NULL, coll), coll, PlanExecutor::YIELD_MANUAL, &rawExec); ASSERT_OK(status); boost::scoped_ptr<PlanExecutor> exec(rawExec); for (int i = 0; i < numIndices; ++i) { BSONObj obj; ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&obj, NULL)); ASSERT_EQUALS(i, obj["foo"].numberInt()); string index(1, 'a' + i); ASSERT_EQUALS(1, obj[index].numberInt()); } // Should be done now. BSONObj foo; ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&foo, NULL)); }
void run() { Client::WriteContext ctx(&_txn, ns()); Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(&_txn, ns()); if (!coll) { coll = db->createCollection(&_txn, ns()); } WorkingSet* ws = new WorkingSet(); // Sort by foo:1 MergeSortStageParams msparams; msparams.pattern = BSON("foo" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); IndexScanParams params; params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; int numIndices = 20; for (int i = 0; i < numIndices; ++i) { // 'a', 'b', ... string index(1, 'a' + i); insert(BSON(index << 1 << "foo" << i)); BSONObj indexSpec = BSON(index << 1 << "foo" << 1); addIndex(indexSpec); params.descriptor = getIndex(indexSpec, coll); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); } ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); for (int i = 0; i < numIndices; ++i) { BSONObj obj; ASSERT_EQUALS(Runner::RUNNER_ADVANCED, runner.getNext(&obj, NULL)); ASSERT_EQUALS(i, obj["foo"].numberInt()); string index(1, 'a' + i); ASSERT_EQUALS(1, obj[index].numberInt()); } // Should be done now. BSONObj foo; ASSERT_EQUALS(Runner::RUNNER_EOF, runner.getNext(&foo, NULL)); }
void run() { OldClientWriteContext ctx(&_txn, ns()); Database* db = ctx.db(); Collection* coll = db->getCollection(ns()); if (!coll) { WriteUnitOfWork wuow(&_txn); coll = db->createCollection(&_txn, ns()); wuow.commit(); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "c" << i)); insert(BSON("b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1); addIndex(firstIndex); addIndex(secondIndex); unique_ptr<WorkingSet> ws = make_unique<WorkingSet>(); // Sort by c:1 MergeSortStageParams msparams; msparams.pattern = BSON("c" << 1); MergeSortStage* ms = new MergeSortStage(&_txn, msparams, ws.get(), coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; ms->addChild(new IndexScan(&_txn, params, ws.get(), NULL)); // b:51 (EOF) params.descriptor = getIndex(secondIndex, coll); params.bounds.startKey = BSON("" << 51 << "" << MinKey); params.bounds.endKey = BSON("" << 51 << "" << MaxKey); ms->addChild(new IndexScan(&_txn, params, ws.get(), NULL)); unique_ptr<FetchStage> fetchStage = make_unique<FetchStage>(&_txn, ws.get(), ms, nullptr, coll); auto statusWithPlanExecutor = PlanExecutor::make( &_txn, std::move(ws), std::move(fetchStage), coll, PlanExecutor::YIELD_MANUAL); ASSERT_OK(statusWithPlanExecutor.getStatus()); unique_ptr<PlanExecutor> exec = std::move(statusWithPlanExecutor.getValue()); // Only getting results from the a:1 index scan. for (int i = 0; i < N; ++i) { BSONObj obj; ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&obj, NULL)); ASSERT_EQUALS(i, obj["c"].numberInt()); ASSERT_EQUALS(1, obj["a"].numberInt()); } // Should be done now. BSONObj foo; ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&foo, NULL)); }
void run() { OldClientWriteContext ctx(&_txn, ns()); Database* db = ctx.db(); Collection* coll = db->getCollection(ns()); if (!coll) { WriteUnitOfWork wuow(&_txn); coll = db->createCollection(&_txn, ns()); wuow.commit(); } const int N = 50; for (int i = 0; i < N; ++i) { // We insert a:1 c:i for i=0..49 but in reverse order for the heck of it. insert(BSON("a" << 1 << "c" << N - i - 1)); insert(BSON("b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << -1); BSONObj secondIndex = BSON("b" << 1 << "c" << -1); addIndex(firstIndex); addIndex(secondIndex); unique_ptr<WorkingSet> ws = make_unique<WorkingSet>(); // Sort by c:-1 MergeSortStageParams msparams; msparams.pattern = BSON("c" << -1); MergeSortStage* ms = new MergeSortStage(&_txn, msparams, ws.get(), coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMaxKey(1); params.bounds.endKey = objWithMinKey(1); params.bounds.endKeyInclusive = true; // This is the direction along the index. params.direction = 1; ms->addChild(new IndexScan(&_txn, params, ws.get(), NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(&_txn, params, ws.get(), NULL)); unique_ptr<FetchStage> fetchStage = make_unique<FetchStage>(&_txn, ws.get(), ms, nullptr, coll); auto statusWithPlanExecutor = PlanExecutor::make( &_txn, std::move(ws), std::move(fetchStage), coll, PlanExecutor::YIELD_MANUAL); ASSERT_OK(statusWithPlanExecutor.getStatus()); unique_ptr<PlanExecutor> exec = std::move(statusWithPlanExecutor.getValue()); for (int i = 0; i < N; ++i) { BSONObj first, second; ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&first, NULL)); first = first.getOwned(); ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(N - i - 1, first["c"].numberInt()); ASSERT((first.hasField("a") && second.hasField("b")) || (first.hasField("b") && second.hasField("a"))); } // Should be done now. BSONObj foo; ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&foo, NULL)); }
void run() { Client::WriteContext ctx(&_txn, ns()); Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(&_txn, ns()); if (!coll) { WriteUnitOfWork wuow(&_txn); coll = db->createCollection(&_txn, ns()); wuow.commit(); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1); addIndex(firstIndex); addIndex(secondIndex); WorkingSet* ws = new WorkingSet(); // Sort by c:1 MergeSortStageParams msparams; msparams.dedup = false; msparams.pattern = BSON("c" << 1); MergeSortStage* ms = new MergeSortStage(msparams, ws, coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(&_txn, params, ws, NULL)); PlanExecutor* rawExec; Status status = PlanExecutor::make(&_txn, ws, new FetchStage(&_txn, ws, ms, NULL, coll), coll, PlanExecutor::YIELD_MANUAL, &rawExec); ASSERT_OK(status); boost::scoped_ptr<PlanExecutor> exec(rawExec); for (int i = 0; i < N; ++i) { BSONObj first, second; // We inserted N objects but we get 2 * N from the runner because of dups. ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&first, NULL)); ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(i, first["c"].numberInt()); ASSERT((first.hasField("a") && second.hasField("b")) || (first.hasField("b") && second.hasField("a"))); } // Should be done now. BSONObj foo; ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&foo, NULL)); }
void run() { OldClientWriteContext ctx(&_opCtx, ns()); Database* db = ctx.db(); Collection* coll = db->getCollection(&_opCtx, ns()); if (!coll) { WriteUnitOfWork wuow(&_opCtx); coll = db->createCollection(&_opCtx, ns()); wuow.commit(); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "c" << i << "d" << "abc")); insert(BSON("b" << 1 << "c" << i << "d" << "cba")); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1 << "d" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1 << "d" << 1); addIndex(firstIndex); addIndex(secondIndex); unique_ptr<WorkingSet> ws = make_unique<WorkingSet>(); // Sort by c:1, d:1 MergeSortStageParams msparams; msparams.pattern = BSON("c" << 1 << "d" << 1); CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); msparams.collator = &collator; MergeSortStage* ms = new MergeSortStage(&_opCtx, msparams, ws.get(), coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.boundInclusion = BoundInclusion::kIncludeBothStartAndEndKeys; params.direction = 1; ms->addChild(new IndexScan(&_opCtx, params, ws.get(), NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(&_opCtx, params, ws.get(), NULL)); unique_ptr<FetchStage> fetchStage = make_unique<FetchStage>(&_opCtx, ws.get(), ms, nullptr, coll); // Must fetch if we want to easily pull out an obj. auto statusWithPlanExecutor = PlanExecutor::make( &_opCtx, std::move(ws), std::move(fetchStage), coll, PlanExecutor::NO_YIELD); ASSERT_OK(statusWithPlanExecutor.getStatus()); auto exec = std::move(statusWithPlanExecutor.getValue()); for (int i = 0; i < N; ++i) { BSONObj first, second; ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&first, NULL)); first = first.getOwned(); ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(i, first["c"].numberInt()); // {b: 1, c: i, d: "cba"} should precede {a: 1, c: i, d: "abc"}. ASSERT(first.hasField("b") && second.hasField("a")); } // Should be done now. BSONObj foo; ASSERT_NOT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&foo, NULL)); }
void run() { OldClientWriteContext ctx(&_opCtx, ns()); Database* db = ctx.db(); Collection* coll = db->getCollection(&_opCtx, ns()); if (!coll) { WriteUnitOfWork wuow(&_opCtx); coll = db->createCollection(&_opCtx, ns()); wuow.commit(); } const int N = 50; for (int i = 0; i < N; ++i) { insert(BSON("a" << 1 << "b" << 1 << "c" << i)); } BSONObj firstIndex = BSON("a" << 1 << "c" << 1); BSONObj secondIndex = BSON("b" << 1 << "c" << 1); addIndex(firstIndex); addIndex(secondIndex); unique_ptr<WorkingSet> ws = make_unique<WorkingSet>(); // Sort by c:1 MergeSortStageParams msparams; msparams.dedup = false; msparams.pattern = BSON("c" << 1); MergeSortStage* ms = new MergeSortStage(&_opCtx, msparams, ws.get(), coll); // a:1 IndexScanParams params; params.descriptor = getIndex(firstIndex, coll); params.bounds.isSimpleRange = true; params.bounds.startKey = objWithMinKey(1); params.bounds.endKey = objWithMaxKey(1); params.bounds.boundInclusion = BoundInclusion::kIncludeBothStartAndEndKeys; params.direction = 1; ms->addChild(new IndexScan(&_opCtx, params, ws.get(), NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); ms->addChild(new IndexScan(&_opCtx, params, ws.get(), NULL)); unique_ptr<FetchStage> fetchStage = make_unique<FetchStage>(&_opCtx, ws.get(), ms, nullptr, coll); auto statusWithPlanExecutor = PlanExecutor::make( &_opCtx, std::move(ws), std::move(fetchStage), coll, PlanExecutor::NO_YIELD); ASSERT_OK(statusWithPlanExecutor.getStatus()); auto exec = std::move(statusWithPlanExecutor.getValue()); for (int i = 0; i < N; ++i) { BSONObj first, second; // We inserted N objects but we get 2 * N from the runner because of dups. ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&first, NULL)); first = first.getOwned(); ASSERT_EQUALS(PlanExecutor::ADVANCED, exec->getNext(&second, NULL)); ASSERT_EQUALS(first["c"].numberInt(), second["c"].numberInt()); ASSERT_EQUALS(i, first["c"].numberInt()); ASSERT((first.hasField("a") && second.hasField("b")) || (first.hasField("b") && second.hasField("a"))); } // Should be done now. BSONObj foo; ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&foo, NULL)); }