Details
-
Bug
-
Resolution: Done
-
Major - P3
-
None
-
None
-
ALL
Description
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 );
|
Attachments
Issue Links
- is related to
-
SERVER-6195 consider $concat to concatenate strings instead of overloading $add
-
- Closed
-
- related to
-
SERVER-6570 disallow $add with strings
-
- Closed
-