Example #1
0
    intrusive_ptr<DocumentSource> DocumentSourceGroup::createFromBson(
	BSONElement *pBsonElement,
	const intrusive_ptr<ExpressionContext> &pCtx) {
	uassert(15947, "a group's fields must be specified in an object",
		pBsonElement->type() == Object);

        intrusive_ptr<DocumentSourceGroup> pGroup(
	    DocumentSourceGroup::create(pCtx));
        bool idSet = false;

        BSONObj groupObj(pBsonElement->Obj());
        BSONObjIterator groupIterator(groupObj);
        while(groupIterator.more()) {
            BSONElement groupField(groupIterator.next());
            const char *pFieldName = groupField.fieldName();

            if (strcmp(pFieldName, Document::idName.c_str()) == 0) {
		uassert(15948, "a group's _id may only be specified once",
			!idSet);

		BSONType groupType = groupField.type();

		if (groupType == Object) {
		    /*
		      Use the projection-like set of field paths to create the
		      group-by key.
		    */
		    Expression::ObjectCtx oCtx(
			Expression::ObjectCtx::DOCUMENT_OK);
		    intrusive_ptr<Expression> pId(
			Expression::parseObject(&groupField, &oCtx));

		    pGroup->setIdExpression(pId);
		    idSet = true;
		}
		else if (groupType == String) {
		    string groupString(groupField.String());
		    const char *pGroupString = groupString.c_str();
		    if ((groupString.length() == 0) ||
			(pGroupString[0] != '$'))
			goto StringConstantId;

		    string pathString(
			Expression::removeFieldPrefix(groupString));
		    intrusive_ptr<ExpressionFieldPath> pFieldPath(
			ExpressionFieldPath::create(pathString));
		    pGroup->setIdExpression(pFieldPath);
		    idSet = true;
		}
		else {
		    /* pick out the constant types that are allowed */
		    switch(groupType) {
		    case NumberDouble:
		    case String:
		    case Object:
		    case Array:
		    case jstOID:
		    case Bool:
		    case Date:
		    case NumberInt:
		    case Timestamp:
		    case NumberLong:
		    case jstNULL:
		    StringConstantId: // from string case above
		    {
			intrusive_ptr<const Value> pValue(
			    Value::createFromBsonElement(&groupField));
			intrusive_ptr<ExpressionConstant> pConstant(
			    ExpressionConstant::create(pValue));
			pGroup->setIdExpression(pConstant);
			idSet = true;
			break;
		    }

		    default:
			uassert(15949, str::stream() <<
				"a group's _id may not include fields of BSON type " << groupType,
				false);
		    }
		}
            }
            else {
                /*
                  Treat as a projection field with the additional ability to
                  add aggregation operators.
                */
		uassert(15950, str::stream() <<
			"the group aggregate field name " <<
			*pFieldName << " cannot be an operator name",
			*pFieldName != '$');

		uassert(15951, str::stream() << 
			"the group aggregate field " << *pFieldName <<
			"must be defined as an expression inside an object",
			groupField.type() == Object);

                BSONObj subField(groupField.Obj());
                BSONObjIterator subIterator(subField);
                size_t subCount = 0;
                for(; subIterator.more(); ++subCount) {
                    BSONElement subElement(subIterator.next());

                    /* look for the specified operator */
                    GroupOpDesc key;
                    key.pName = subElement.fieldName();
                    const GroupOpDesc *pOp =
			(const GroupOpDesc *)bsearch(
                              &key, GroupOpTable, NGroupOp, sizeof(GroupOpDesc),
                                      GroupOpDescCmp);

		    uassert(15952, str::stream() <<
			    "unknown group operator \"" <<
			    key.pName << "\"",
			    pOp);

                    intrusive_ptr<Expression> pGroupExpr;

                    BSONType elementType = subElement.type();
                    if (elementType == Object) {
			Expression::ObjectCtx oCtx(
			    Expression::ObjectCtx::DOCUMENT_OK);
                        pGroupExpr = Expression::parseObject(
			    &subElement, &oCtx);
		    }
                    else if (elementType == Array) {
			uassert(15953, str::stream() <<
				"aggregating group operators are unary (" <<
				key.pName << ")", false);
                    }
                    else { /* assume its an atomic single operand */
                        pGroupExpr = Expression::parseOperand(&subElement);
                    }

                    pGroup->addAccumulator(
                        pFieldName, pOp->pFactory, pGroupExpr);
                }

		uassert(15954, str::stream() <<
			"the computed aggregate \"" <<
			pFieldName << "\" must specify exactly one operator",
			subCount == 1);
            }
        }

	uassert(15955, "a group specification must include an _id", idSet);

        return pGroup;
    }
void Foam::mapDistribute::distribute
(
    const Pstream::commsTypes commsType,
    const List<labelPair>& schedule,
    const label constructSize,
    const labelListList& subMap,
    const labelListList& constructMap,
    List<T>& field
)
{
    if (commsType == Pstream::blocking)
    {
        // Since buffered sending can reuse the field to collect the
        // received data.

        // Send sub field to neighbour
        for (label domain = 0; domain < Pstream::nProcs(); domain++)
        {
            const labelList& map = subMap[domain];

            if (domain != Pstream::myProcNo() && map.size())
            {
                OPstream toNbr(Pstream::blocking, domain);
                toNbr << UIndirectList<T>(field, map);
            }
        }

        // Subset myself
        const labelList& mySubMap = subMap[Pstream::myProcNo()];

        List<T> subField(mySubMap.size());
        forAll(mySubMap, i)
        {
            subField[i] = field[mySubMap[i]];
        }

        // Receive sub field from myself (subField)
        const labelList& map = constructMap[Pstream::myProcNo()];

        field.setSize(constructSize);

        forAll(map, i)
        {
            field[map[i]] = subField[i];
        }

        // Receive sub field from neighbour
        for (label domain = 0; domain < Pstream::nProcs(); domain++)
        {
            const labelList& map = constructMap[domain];

            if (domain != Pstream::myProcNo() && map.size())
            {
                IPstream fromNbr(Pstream::blocking, domain);
                List<T> subField(fromNbr);

                if (subField.size() != map.size())
                {
                    FatalErrorIn
                    (
                        "template<class T>\n"
                        "void mapDistribute::distribute\n"
                        "(\n"
                        "    const Pstream::commsTypes commsType,\n"
                        "    const List<labelPair>& schedule,\n"
                        "    const label constructSize,\n"
                        "    const labelListList& subMap,\n"
                        "    const labelListList& constructMap,\n"
                        "    List<T>& field\n"
                        ")\n"
                    )   << "Expected from processor " << domain
                        << " " << map.size() << " but received "
                        << subField.size() << " elements."
                        << abort(FatalError);
                }

                forAll(map, i)
                {
                    field[map[i]] = subField[i];
                }
            }
        }
    }
    intrusive_ptr<DocumentSource> DocumentSourceGroup::createFromBson(
            BSONElement elem,
            const intrusive_ptr<ExpressionContext> &pExpCtx) {
        uassert(15947, "a group's fields must be specified in an object",
                elem.type() == Object);

        intrusive_ptr<DocumentSourceGroup> pGroup(
            DocumentSourceGroup::create(pExpCtx));

        BSONObj groupObj(elem.Obj());
        BSONObjIterator groupIterator(groupObj);
        VariablesIdGenerator idGenerator;
        VariablesParseState vps(&idGenerator);
        while(groupIterator.more()) {
            BSONElement groupField(groupIterator.next());
            const char *pFieldName = groupField.fieldName();

            if (str::equals(pFieldName, "_id")) {
                uassert(15948, "a group's _id may only be specified once",
                        pGroup->_idExpressions.empty());
                pGroup->parseIdExpression(groupField, vps);
                invariant(!pGroup->_idExpressions.empty());
            }
            else if (str::equals(pFieldName, "$doingMerge")) {
                massert(17030, "$doingMerge should be true if present",
                        groupField.Bool());

                pGroup->setDoingMerge(true);
            }
            else {
                /*
                  Treat as a projection field with the additional ability to
                  add aggregation operators.
                */
                uassert(16414, str::stream() <<
                        "the group aggregate field name '" << pFieldName <<
                        "' cannot be used because $group's field names cannot contain '.'",
                        !str::contains(pFieldName, '.') );

                uassert(15950, str::stream() <<
                        "the group aggregate field name '" <<
                        pFieldName << "' cannot be an operator name",
                        pFieldName[0] != '$');

                uassert(15951, str::stream() <<
                        "the group aggregate field '" << pFieldName <<
                        "' must be defined as an expression inside an object",
                        groupField.type() == Object);

                BSONObj subField(groupField.Obj());
                BSONObjIterator subIterator(subField);
                size_t subCount = 0;
                for(; subIterator.more(); ++subCount) {
                    BSONElement subElement(subIterator.next());

                    /* look for the specified operator */
                    GroupOpDesc key;
                    key.name = subElement.fieldName();
                    const GroupOpDesc *pOp =
                        (const GroupOpDesc *)bsearch(
                              &key, GroupOpTable, NGroupOp, sizeof(GroupOpDesc),
                                      GroupOpDescCmp);

                    uassert(15952, str::stream() << "unknown group operator '" << key.name << "'",
                            pOp);

                    intrusive_ptr<Expression> pGroupExpr;

                    BSONType elementType = subElement.type();
                    if (elementType == Object) {
                        Expression::ObjectCtx oCtx(Expression::ObjectCtx::DOCUMENT_OK);
                        pGroupExpr = Expression::parseObject(subElement.Obj(), &oCtx, vps);
                    }
                    else if (elementType == Array) {
                        uasserted(15953, str::stream()
                                << "aggregating group operators are unary (" << key.name << ")");
                    }
                    else { /* assume its an atomic single operand */
                        pGroupExpr = Expression::parseOperand(subElement, vps);
                    }

                    pGroup->addAccumulator(pFieldName, pOp->factory, pGroupExpr);
                }

                uassert(15954, str::stream() <<
                        "the computed aggregate '" <<
                        pFieldName << "' must specify exactly one operator",
                        subCount == 1);
            }
        }

        uassert(15955, "a group specification must include an _id",
                !pGroup->_idExpressions.empty());

        pGroup->_variables.reset(new Variables(idGenerator.getIdCount()));

        return pGroup;
    }
void Foam::mapDistribute::distribute
(
    const Pstream::commsTypes commsType,
    const List<labelPair>& schedule,
    const label constructSize,
    const labelListList& subMap,
    const labelListList& constructMap,
    List<T>& field,
    const int tag
)
{
    if (!Pstream::parRun())
    {
        // Do only me to me.

        const labelList& mySubMap = subMap[Pstream::myProcNo()];

        List<T> subField(mySubMap.size());
        forAll(mySubMap, i)
        {
            subField[i] = field[mySubMap[i]];
        }

        // Receive sub field from myself (subField)
        const labelList& map = constructMap[Pstream::myProcNo()];

        field.setSize(constructSize);

        forAll(map, i)
        {
            field[map[i]] = subField[i];
        }
        return;
    }

    if (commsType == Pstream::blocking)
    {
        // Since buffered sending can reuse the field to collect the
        // received data.

        // Send sub field to neighbour
        for (label domain = 0; domain < Pstream::nProcs(); domain++)
        {
            const labelList& map = subMap[domain];

            if (domain != Pstream::myProcNo() && map.size())
            {
                OPstream toNbr(Pstream::blocking, domain, 0, tag);
                toNbr << UIndirectList<T>(field, map);
            }
        }

        // Subset myself
        const labelList& mySubMap = subMap[Pstream::myProcNo()];

        List<T> subField(mySubMap.size());
        forAll(mySubMap, i)
        {
            subField[i] = field[mySubMap[i]];
        }

        // Receive sub field from myself (subField)
        const labelList& map = constructMap[Pstream::myProcNo()];

        field.setSize(constructSize);

        forAll(map, i)
        {
            field[map[i]] = subField[i];
        }

        // Receive sub field from neighbour
        for (label domain = 0; domain < Pstream::nProcs(); domain++)
        {
            const labelList& map = constructMap[domain];

            if (domain != Pstream::myProcNo() && map.size())
            {
                IPstream fromNbr(Pstream::blocking, domain, 0, tag);
                List<T> subField(fromNbr);

                checkReceivedSize(domain, map.size(), subField.size());

                forAll(map, i)
                {
                    field[map[i]] = subField[i];
                }
            }
        }
    }
Example #5
0
intrusive_ptr<DocumentSource> DocumentSourceGroup::createFromBson(
    BSONElement *pBsonElement,
    const intrusive_ptr<ExpressionContext> &pCtx) {
    assert(pBsonElement->type() == Object); // CW TODO must be an object

    intrusive_ptr<DocumentSourceGroup> pGroup(
        DocumentSourceGroup::create(pCtx));
    bool idSet = false;

    BSONObj groupObj(pBsonElement->Obj());
    BSONObjIterator groupIterator(groupObj);
    while(groupIterator.more()) {
        BSONElement groupField(groupIterator.next());
        const char *pFieldName = groupField.fieldName();

        if (strcmp(pFieldName, Document::idName.c_str()) == 0) {
            assert(!idSet); // CW TODO _id specified multiple times

            BSONType groupType = groupField.type();

            if (groupType == Object) {
                /*
                  Use the projection-like set of field paths to create the
                  group-by key.
                */
                Expression::ObjectCtx oCtx(
                    Expression::ObjectCtx::DOCUMENT_OK);
                intrusive_ptr<Expression> pId(
                    Expression::parseObject(&groupField, &oCtx));

                pGroup->setIdExpression(pId);
                idSet = true;
            }
            else if (groupType == String) {
                string groupString(groupField.String());
                const char *pGroupString = groupString.c_str();
                if ((groupString.length() == 0) ||
                        (pGroupString[0] != '$'))
                    goto StringConstantId;

                string pathString(
                    Expression::removeFieldPrefix(groupString));
                intrusive_ptr<ExpressionFieldPath> pFieldPath(
                    ExpressionFieldPath::create(pathString));
                pGroup->setIdExpression(pFieldPath);
                idSet = true;
            }
            else {
                /* pick out the constant types that are allowed */
                switch(groupType) {
                case NumberDouble:
                case String:
                case Object:
                case Array:
                case jstOID:
                case Bool:
                case Date:
                case NumberInt:
                case Timestamp:
                case NumberLong:
                case jstNULL:
StringConstantId: // from string case above
                    {
                        intrusive_ptr<const Value> pValue(
                            Value::createFromBsonElement(&groupField));
                        intrusive_ptr<ExpressionConstant> pConstant(
                            ExpressionConstant::create(pValue));
                        pGroup->setIdExpression(pConstant);
                        idSet = true;
                        break;
                    }

                default:
                    assert(false);
                    // CW TODO disallowed constant group key
                }
            }
        }
        else {
            /*
              Treat as a projection field with the additional ability to
              add aggregation operators.
            */
            assert(*pFieldName != '$');
            // CW TODO error: field name can't be an operator
            assert(groupField.type() == Object);
            // CW TODO error: must be an operator expression

            BSONObj subField(groupField.Obj());
            BSONObjIterator subIterator(subField);
            size_t subCount = 0;
            for(; subIterator.more(); ++subCount) {
                BSONElement subElement(subIterator.next());

                /* look for the specified operator */
                GroupOpDesc key;
                key.pName = subElement.fieldName();
                const GroupOpDesc *pOp =
                    (const GroupOpDesc *)bsearch(
                        &key, GroupOpTable, NGroupOp, sizeof(GroupOpDesc),
                        GroupOpDescCmp);

                assert(pOp); // CW TODO error: operator not found

                intrusive_ptr<Expression> pGroupExpr;

                BSONType elementType = subElement.type();
                if (elementType == Object) {
                    Expression::ObjectCtx oCtx(
                        Expression::ObjectCtx::DOCUMENT_OK);
                    pGroupExpr = Expression::parseObject(
                                     &subElement, &oCtx);
                }
                else if (elementType == Array) {
                    assert(false); // CW TODO group operators are unary
                }
                else { /* assume its an atomic single operand */
                    pGroupExpr = Expression::parseOperand(&subElement);
                }

                pGroup->addAccumulator(
                    pFieldName, pOp->pFactory, pGroupExpr);
            }

            assert(subCount == 1);
            // CW TODO error: only one operator allowed
        }
    }

    assert(idSet); // CW TODO error: missing _id specification

    return pGroup;
}
Example #6
0
    intrusive_ptr<DocumentSource> DocumentSourceGroup::createFromBson(
        BSONElement *pBsonElement,
        const intrusive_ptr<ExpressionContext> &pExpCtx) {
        uassert(15947, "a group's fields must be specified in an object",
                pBsonElement->type() == Object);

        intrusive_ptr<DocumentSourceGroup> pGroup(
            DocumentSourceGroup::create(pExpCtx));
        bool idSet = false;

        BSONObj groupObj(pBsonElement->Obj());
        BSONObjIterator groupIterator(groupObj);
        while(groupIterator.more()) {
            BSONElement groupField(groupIterator.next());
            const char *pFieldName = groupField.fieldName();

            if (str::equals(pFieldName, "_id")) {
                uassert(15948, "a group's _id may only be specified once",
                        !idSet);

                BSONType groupType = groupField.type();

                if (groupType == Object) {
                    /*
                      Use the projection-like set of field paths to create the
                      group-by key.
                    */
                    Expression::ObjectCtx oCtx(Expression::ObjectCtx::DOCUMENT_OK);
                    intrusive_ptr<Expression> pId(
                        Expression::parseObject(&groupField, &oCtx));

                    pGroup->setIdExpression(pId);
                    idSet = true;
                }
                else if (groupType == String) {
                    const string groupString = groupField.str();
                    if (!groupString.empty() && groupString[0] == '$') {
                        pGroup->setIdExpression(ExpressionFieldPath::parse(groupString));
                        idSet = true;
                    }
                }

                if (!idSet) {
                    // constant id - single group
                    pGroup->setIdExpression(ExpressionConstant::create(Value(groupField)));
                    idSet = true;
                }
            }
            else {
                /*
                  Treat as a projection field with the additional ability to
                  add aggregation operators.
                */
                uassert(16414, str::stream() <<
                        "the group aggregate field name '" << pFieldName <<
                        "' cannot be used because $group's field names cannot contain '.'",
                        !str::contains(pFieldName, '.') );

                uassert(15950, str::stream() <<
                        "the group aggregate field name '" <<
                        pFieldName << "' cannot be an operator name",
                        pFieldName[0] != '$');

                uassert(15951, str::stream() <<
                        "the group aggregate field '" << pFieldName <<
                        "' must be defined as an expression inside an object",
                        groupField.type() == Object);

                BSONObj subField(groupField.Obj());
                BSONObjIterator subIterator(subField);
                size_t subCount = 0;
                for(; subIterator.more(); ++subCount) {
                    BSONElement subElement(subIterator.next());

                    /* look for the specified operator */
                    GroupOpDesc key;
                    key.name = subElement.fieldName();
                    const GroupOpDesc *pOp =
                        (const GroupOpDesc *)bsearch(
                              &key, GroupOpTable, NGroupOp, sizeof(GroupOpDesc),
                                      GroupOpDescCmp);

                    uassert(15952, str::stream() << "unknown group operator '" << key.name << "'",
                            pOp);

                    intrusive_ptr<Expression> pGroupExpr;

                    BSONType elementType = subElement.type();
                    if (elementType == Object) {
                        Expression::ObjectCtx oCtx(
                            Expression::ObjectCtx::DOCUMENT_OK);
                        pGroupExpr = Expression::parseObject(
                            &subElement, &oCtx);
                    }
                    else if (elementType == Array) {
                        uasserted(15953, str::stream()
                                << "aggregating group operators are unary (" << key.name << ")");
                    }
                    else { /* assume its an atomic single operand */
                        pGroupExpr = Expression::parseOperand(&subElement);
                    }

                    pGroup->addAccumulator(pFieldName, pOp->factory, pGroupExpr);
                }

                uassert(15954, str::stream() <<
                        "the computed aggregate '" <<
                        pFieldName << "' must specify exactly one operator",
                        subCount == 1);
            }
        }

        uassert(15955, "a group specification must include an _id", idSet);

        return pGroup;
    }