PlanStage* parseQuery(OperationContext* txn, Collection* collection, BSONObj obj, WorkingSet* workingSet, OwnedPointerVector<MatchExpression>* exprs) { BSONElement firstElt = obj.firstElement(); if (!firstElt.isABSONObj()) { return NULL; } BSONObj paramObj = firstElt.Obj(); MatchExpression* matcher = NULL; BSONObj nodeArgs; // Every node has these two fields. const string filterTag = "filter"; const string argsTag = "args"; BSONObjIterator it(paramObj); while (it.more()) { BSONElement e = it.next(); if (!e.isABSONObj()) { return NULL; } BSONObj argObj = e.Obj(); if (filterTag == e.fieldName()) { StatusWithMatchExpression swme = MatchExpressionParser::parse( argObj, WhereCallbackReal(txn, collection->ns().db())); if (!swme.isOK()) { return NULL; } // exprs is what will wind up deleting this. matcher = swme.getValue(); verify(NULL != matcher); exprs->mutableVector().push_back(matcher); } else if (argsTag == e.fieldName()) { nodeArgs = argObj; } else { uasserted(16910, "Unknown fieldname " + string(e.fieldName()) + " in query node " + obj.toString()); return NULL; } } string nodeName = firstElt.fieldName(); if ("ixscan" == nodeName) { // This'll throw if it's not an obj but that's OK. BSONObj keyPatternObj = nodeArgs["keyPattern"].Obj(); IndexDescriptor* desc = collection->getIndexCatalog()->findIndexByKeyPattern(keyPatternObj); uassert(16890, "Can't find index: " + keyPatternObj.toString(), desc); IndexScanParams params; params.descriptor = desc; params.bounds.isSimpleRange = true; params.bounds.startKey = nodeArgs["startKey"].Obj(); params.bounds.endKey = nodeArgs["endKey"].Obj(); params.bounds.endKeyInclusive = nodeArgs["endKeyInclusive"].Bool(); params.direction = nodeArgs["direction"].numberInt(); return new IndexScan(txn, params, workingSet, matcher); } else if ("andHash" == nodeName) { uassert(16921, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); auto_ptr<AndHashStage> andStage(new AndHashStage(workingSet, matcher, collection)); int nodesAdded = 0; BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16922, "node of AND isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(txn, collection, e.Obj(), workingSet, exprs); uassert(16923, "Can't parse sub-node of AND: " + e.Obj().toString(), NULL != subNode); // takes ownership andStage->addChild(subNode); ++nodesAdded; } uassert(16927, "AND requires more than one child", nodesAdded >= 2); return andStage.release(); } else if ("andSorted" == nodeName) { uassert(16924, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); auto_ptr<AndSortedStage> andStage( new AndSortedStage(workingSet, matcher, collection)); int nodesAdded = 0; BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16925, "node of AND isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(txn, collection, e.Obj(), workingSet, exprs); uassert(16926, "Can't parse sub-node of AND: " + e.Obj().toString(), NULL != subNode); // takes ownership andStage->addChild(subNode); ++nodesAdded; } uassert(16928, "AND requires more than one child", nodesAdded >= 2); return andStage.release(); } else if ("or" == nodeName) { uassert(16934, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); uassert(16935, "Dedup argument must be provided to OR", !nodeArgs["dedup"].eoo()); BSONObjIterator it(nodeArgs["nodes"].Obj()); auto_ptr<OrStage> orStage(new OrStage(workingSet, nodeArgs["dedup"].Bool(), matcher)); while (it.more()) { BSONElement e = it.next(); if (!e.isABSONObj()) { return NULL; } PlanStage* subNode = parseQuery(txn, collection, e.Obj(), workingSet, exprs); uassert(16936, "Can't parse sub-node of OR: " + e.Obj().toString(), NULL != subNode); // takes ownership orStage->addChild(subNode); } return orStage.release(); } else if ("fetch" == nodeName) { uassert(16929, "Node argument must be provided to fetch", nodeArgs["node"].isABSONObj()); PlanStage* subNode = parseQuery(txn, collection, nodeArgs["node"].Obj(), workingSet, exprs); return new FetchStage(workingSet, subNode, matcher, collection); } else if ("limit" == nodeName) { uassert(16937, "Limit stage doesn't have a filter (put it on the child)", NULL == matcher); uassert(16930, "Node argument must be provided to limit", nodeArgs["node"].isABSONObj()); uassert(16931, "Num argument must be provided to limit", nodeArgs["num"].isNumber()); PlanStage* subNode = parseQuery(txn, collection, nodeArgs["node"].Obj(), workingSet, exprs); return new LimitStage(nodeArgs["num"].numberInt(), workingSet, subNode); } else if ("skip" == nodeName) { uassert(16938, "Skip stage doesn't have a filter (put it on the child)", NULL == matcher); uassert(16932, "Node argument must be provided to skip", nodeArgs["node"].isABSONObj()); uassert(16933, "Num argument must be provided to skip", nodeArgs["num"].isNumber()); PlanStage* subNode = parseQuery(txn, collection, nodeArgs["node"].Obj(), workingSet, exprs); return new SkipStage(nodeArgs["num"].numberInt(), workingSet, subNode); } else if ("cscan" == nodeName) { CollectionScanParams params; params.collection = collection; // What direction? uassert(16963, "Direction argument must be specified and be a number", nodeArgs["direction"].isNumber()); if (1 == nodeArgs["direction"].numberInt()) { params.direction = CollectionScanParams::FORWARD; } else { params.direction = CollectionScanParams::BACKWARD; } return new CollectionScan(txn, params, workingSet, matcher); } // sort is disabled for now. #if 0 else if ("sort" == nodeName) { uassert(16969, "Node argument must be provided to sort", nodeArgs["node"].isABSONObj()); uassert(16970, "Pattern argument must be provided to sort", nodeArgs["pattern"].isABSONObj()); PlanStage* subNode = parseQuery(txn, db, nodeArgs["node"].Obj(), workingSet, exprs); SortStageParams params; params.pattern = nodeArgs["pattern"].Obj(); return new SortStage(params, workingSet, subNode); } #endif else if ("mergeSort" == nodeName) { uassert(16971, "Nodes argument must be provided to sort", nodeArgs["nodes"].isABSONObj()); uassert(16972, "Pattern argument must be provided to sort", nodeArgs["pattern"].isABSONObj()); MergeSortStageParams params; params.pattern = nodeArgs["pattern"].Obj(); // Dedup is true by default. auto_ptr<MergeSortStage> mergeStage( new MergeSortStage(params, workingSet, collection)); BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16973, "node of mergeSort isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(txn, collection, e.Obj(), workingSet, exprs); uassert(16974, "Can't parse sub-node of mergeSort: " + e.Obj().toString(), NULL != subNode); // takes ownership mergeStage->addChild(subNode); } return mergeStage.release(); } else if ("text" == nodeName) { string search = nodeArgs["search"].String(); vector<IndexDescriptor*> idxMatches; collection->getIndexCatalog()->findIndexByType("text", idxMatches); uassert(17194, "Expected exactly one text index", idxMatches.size() == 1); IndexDescriptor* index = idxMatches[0]; FTSAccessMethod* fam = dynamic_cast<FTSAccessMethod*>( collection->getIndexCatalog()->getIndex( index ) ); TextStageParams params(fam->getSpec()); params.index = index; // TODO: Deal with non-empty filters. This is a hack to put in covering information // that can only be checked for equality. We ignore this now. Status s = fam->getSpec().getIndexPrefix(BSONObj(), ¶ms.indexPrefix); if (!s.isOK()) { // errmsg = s.toString(); return NULL; } params.spec = fam->getSpec(); if (!params.query.parse(search, fam->getSpec().defaultLanguage().str().c_str()).isOK()) { return NULL; } return new TextStage(txn, params, workingSet, matcher); } else if ("delete" == nodeName) { uassert(18636, "Delete stage doesn't have a filter (put it on the child)", NULL == matcher); uassert(18637, "node argument must be provided to delete", nodeArgs["node"].isABSONObj()); uassert(18638, "isMulti argument must be provided to delete", nodeArgs["isMulti"].type() == Bool); uassert(18639, "shouldCallLogOp argument must be provided to delete", nodeArgs["shouldCallLogOp"].type() == Bool); PlanStage* subNode = parseQuery(txn, collection, nodeArgs["node"].Obj(), workingSet, exprs); DeleteStageParams params; params.isMulti = nodeArgs["isMulti"].Bool(); params.shouldCallLogOp = nodeArgs["shouldCallLogOp"].Bool(); return new DeleteStage(txn, params, workingSet, collection, subNode); } else { return NULL; } }
PlanStage* parseQuery(const string& dbname, BSONObj obj, WorkingSet* workingSet, OwnedPointerVector<MatchExpression>* exprs) { BSONElement firstElt = obj.firstElement(); if (!firstElt.isABSONObj()) { return NULL; } BSONObj paramObj = firstElt.Obj(); MatchExpression* matcher = NULL; BSONObj nodeArgs; // Every node has these two fields. const string filterTag = "filter"; const string argsTag = "args"; BSONObjIterator it(paramObj); while (it.more()) { BSONElement e = it.next(); if (!e.isABSONObj()) { return NULL; } BSONObj argObj = e.Obj(); if (filterTag == e.fieldName()) { StatusWithMatchExpression swme = MatchExpressionParser::parse(argObj); if (!swme.isOK()) { return NULL; } // exprs is what will wind up deleting this. matcher = swme.getValue(); verify(NULL != matcher); exprs->mutableVector().push_back(matcher); } else if (argsTag == e.fieldName()) { nodeArgs = argObj; } else { uasserted(16910, "Unknown fieldname " + string(e.fieldName()) + " in query node " + obj.toString()); return NULL; } } string nodeName = firstElt.fieldName(); if ("ixscan" == nodeName) { NamespaceDetails* nsd = nsdetails(dbname + "." + nodeArgs["name"].String()); uassert(16913, "Can't find collection " + nodeArgs["name"].String(), nsd); int idxNo = nsd->findIndexByKeyPattern(nodeArgs["keyPattern"].Obj()); uassert(16890, "Can't find index: " + nodeArgs["keyPattern"].Obj().toString(), idxNo != -1); IndexScanParams params; params.descriptor = CatalogHack::getDescriptor(nsd, idxNo); params.startKey = nodeArgs["startKey"].Obj(); params.endKey = nodeArgs["endKey"].Obj(); params.endKeyInclusive = nodeArgs["endKeyInclusive"].Bool(); params.direction = nodeArgs["direction"].numberInt(); params.limit = nodeArgs["limit"].numberInt(); params.forceBtreeAccessMethod = false; return new IndexScan(params, workingSet, matcher); } else if ("andHash" == nodeName) { uassert(16921, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); auto_ptr<AndHashStage> andStage(new AndHashStage(workingSet, matcher)); int nodesAdded = 0; BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16922, "node of AND isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(dbname, e.Obj(), workingSet, exprs); uassert(16923, "Can't parse sub-node of AND: " + e.Obj().toString(), NULL != subNode); // takes ownership andStage->addChild(subNode); ++nodesAdded; } uassert(16927, "AND requires more than one child", nodesAdded >= 2); return andStage.release(); } else if ("andSorted" == nodeName) { uassert(16924, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); auto_ptr<AndSortedStage> andStage(new AndSortedStage(workingSet, matcher)); int nodesAdded = 0; BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16925, "node of AND isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(dbname, e.Obj(), workingSet, exprs); uassert(16926, "Can't parse sub-node of AND: " + e.Obj().toString(), NULL != subNode); // takes ownership andStage->addChild(subNode); ++nodesAdded; } uassert(16928, "AND requires more than one child", nodesAdded >= 2); return andStage.release(); } else if ("or" == nodeName) { uassert(16934, "Nodes argument must be provided to AND", nodeArgs["nodes"].isABSONObj()); uassert(16935, "Dedup argument must be provided to OR", !nodeArgs["dedup"].eoo()); BSONObjIterator it(nodeArgs["nodes"].Obj()); auto_ptr<OrStage> orStage(new OrStage(workingSet, nodeArgs["dedup"].Bool(), matcher)); while (it.more()) { BSONElement e = it.next(); if (!e.isABSONObj()) { return NULL; } PlanStage* subNode = parseQuery(dbname, e.Obj(), workingSet, exprs); uassert(16936, "Can't parse sub-node of OR: " + e.Obj().toString(), NULL != subNode); // takes ownership orStage->addChild(subNode); } return orStage.release(); } else if ("fetch" == nodeName) { uassert(16929, "Node argument must be provided to fetch", nodeArgs["node"].isABSONObj()); PlanStage* subNode = parseQuery(dbname, nodeArgs["node"].Obj(), workingSet, exprs); return new FetchStage(workingSet, subNode, matcher); } else if ("limit" == nodeName) { uassert(16937, "Limit stage doesn't have a filter (put it on the child)", NULL == matcher); uassert(16930, "Node argument must be provided to limit", nodeArgs["node"].isABSONObj()); uassert(16931, "Num argument must be provided to limit", nodeArgs["num"].isNumber()); PlanStage* subNode = parseQuery(dbname, nodeArgs["node"].Obj(), workingSet, exprs); return new LimitStage(nodeArgs["num"].numberInt(), workingSet, subNode); } else if ("skip" == nodeName) { uassert(16938, "Skip stage doesn't have a filter (put it on the child)", NULL == matcher); uassert(16932, "Node argument must be provided to skip", nodeArgs["node"].isABSONObj()); uassert(16933, "Num argument must be provided to skip", nodeArgs["num"].isNumber()); PlanStage* subNode = parseQuery(dbname, nodeArgs["node"].Obj(), workingSet, exprs); return new SkipStage(nodeArgs["num"].numberInt(), workingSet, subNode); } else if ("cscan" == nodeName) { CollectionScanParams params; // What collection? params.ns = dbname + "." + nodeArgs["name"].String(); uassert(16962, "Can't find collection " + nodeArgs["name"].String(), NULL != nsdetails(params.ns)); // What direction? uassert(16963, "Direction argument must be specified and be a number", nodeArgs["direction"].isNumber()); if (1 == nodeArgs["direction"].numberInt()) { params.direction = CollectionScanParams::FORWARD; } else { params.direction = CollectionScanParams::BACKWARD; } return new CollectionScan(params, workingSet, matcher); } else if ("sort" == nodeName) { uassert(16969, "Node argument must be provided to sort", nodeArgs["node"].isABSONObj()); uassert(16970, "Pattern argument must be provided to sort", nodeArgs["pattern"].isABSONObj()); PlanStage* subNode = parseQuery(dbname, nodeArgs["node"].Obj(), workingSet, exprs); SortStageParams params; params.pattern = nodeArgs["pattern"].Obj(); return new SortStage(params, workingSet, subNode); } else if ("mergeSort" == nodeName) { uassert(16971, "Nodes argument must be provided to sort", nodeArgs["nodes"].isABSONObj()); uassert(16972, "Pattern argument must be provided to sort", nodeArgs["pattern"].isABSONObj()); MergeSortStageParams params; params.pattern = nodeArgs["pattern"].Obj(); // Dedup is true by default. auto_ptr<MergeSortStage> mergeStage(new MergeSortStage(params, workingSet)); BSONObjIterator it(nodeArgs["nodes"].Obj()); while (it.more()) { BSONElement e = it.next(); uassert(16973, "node of mergeSort isn't an obj?: " + e.toString(), e.isABSONObj()); PlanStage* subNode = parseQuery(dbname, e.Obj(), workingSet, exprs); uassert(16974, "Can't parse sub-node of mergeSort: " + e.Obj().toString(), NULL != subNode); // takes ownership mergeStage->addChild(subNode); } return mergeStage.release(); } else { return NULL; } }