-
Type:
Bug
-
Resolution: Done
-
Priority:
Major - P3
-
Affects Version/s: None
-
Component/s: Aggregation Framework
-
None
-
ALL
-
None
-
None
-
None
-
None
-
None
-
None
-
None
Observed behavior: When a nested $add is used for string concatenation, the arguments may be concatenated in the wrong order.
Expected behavior: Concatenation in the proper order.
There is some code to detect string $add operands and avoid an improper constant folding, but this is not applied for nested $add expressions:
/*
If the child operand is the same type as this, then we can
extract its operands and inline them here because we already
know this is commutative and associative because it has a
factory. We can detect sameness of the child operator by
checking for equality of the factory
Note we don't have to do this recursively, because we
called optimize() on all the children first thing in
this call to optimize().
*/
ExpressionNary *pNary =
dynamic_cast<ExpressionNary *>(pE.get());
if (!pNary)
pNew->addOperand(pE);
else {
intrusive_ptr<ExpressionNary> (*const pChildFactory)() =
pNary->getFactory();
if (pChildFactory != pFactory)
pNew->addOperand(pE);
else {
/* same factory, so flatten */
size_t nChild = pNary->vpOperand.size();
for(size_t iChild = 0; iChild < nChild; ++iChild) {
intrusive_ptr<Expression> pCE(
pNary->vpOperand[iChild]);
if (dynamic_cast<ExpressionConstant *>(pCE.get()))
pConst->addOperand(pCE);
else
pNew->addOperand(pCE);
}
}
}
Test:
c = db.c;
c.drop();
c.save( { x:3 } );
project = { $project:{ a:{ $add:[ 1, 2, { $add:[ 'foo', '$x' ] } ] } } };
printjson( c.runCommand( 'aggregate', { pipeline:[ project ], explain:true } ) );
// Actual result is '312foo'.
assert.eq( '12foo3', c.aggregate( project ).result[ 0 ].a );
- is related to
-
SERVER-6195 consider $concat to concatenate strings instead of overloading $add
-
- Closed
-
- related to
-
SERVER-6570 disallow $add with strings
-
- Closed
-