-
Type: Bug
-
Resolution: Done
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: Aggregation Framework
-
None
-
ALL
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