Пример #1
0
        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(), &params.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;
            }
        }
Пример #2
0
        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;
            }
        }