Skip to content

Commit 59ff12a

Browse files
committed
Make sure all aggregation operations round-trip correctly through BSON
Also fixes expressions that didn't round-trip correctly
1 parent 7fe6b77 commit 59ff12a

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

src/mongo/db/commands/pipeline_command.cpp

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ namespace mongo {
102102
bool runExecute(
103103
BSONObjBuilder &result, string &errmsg,
104104
const string &ns, const string &db,
105-
intrusive_ptr<Pipeline> &pPipeline,
106-
intrusive_ptr<ExpressionContext> &pCtx);
105+
intrusive_ptr<Pipeline> pPipeline,
106+
intrusive_ptr<ExpressionContext> pCtx);
107107
};
108108

109109
// self-registering singleton static instance
@@ -155,8 +155,26 @@ namespace mongo {
155155
bool PipelineCommand::runExecute(
156156
BSONObjBuilder &result, string &errmsg,
157157
const string &ns, const string &db,
158-
intrusive_ptr<Pipeline> &pPipeline,
159-
intrusive_ptr<ExpressionContext> &pCtx) {
158+
intrusive_ptr<Pipeline> pPipeline,
159+
intrusive_ptr<ExpressionContext> pCtx) {
160+
161+
#if _DEBUG
162+
// This is outside of the if block to keep the object alive until the pipeline is finished.
163+
BSONObj parsed;
164+
if (!pCtx->getInShard()) {
165+
// Make sure all operations round-trip through Pipeline::toBson()
166+
// correctly by reparsing every command on DEBUG builds. This is
167+
// important because sharded aggregations rely on this ability.
168+
// Skipping when inShard because this has already been through the
169+
// transformation (and this unsets pCtx->inShard).
170+
BSONObjBuilder bb;
171+
pPipeline->toBson(&bb);
172+
parsed = bb.obj();
173+
// PRINT(parsed); // when debugging failures uncomment this and the matching one in run
174+
pPipeline = Pipeline::parseCommand(errmsg, parsed, pCtx);
175+
verify(pPipeline);
176+
}
177+
#endif
160178

161179
// The DocumentSourceCursor manages a read lock internally, see SERVER-6123.
162180
intrusive_ptr<DocumentSourceCursor> pSource(
@@ -252,6 +270,7 @@ namespace mongo {
252270
bool PipelineCommand::run(const string &db, BSONObj &cmdObj,
253271
int options, string &errmsg,
254272
BSONObjBuilder &result, bool fromRepl) {
273+
// PRINT(cmdObj); // uncomment when debugging
255274

256275
intrusive_ptr<ExpressionContext> pCtx(
257276
ExpressionContext::create(&InterruptStatusMongod::status));

src/mongo/db/pipeline/expression.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,9 @@ namespace mongo {
13821382
}
13831383

13841384
void ExpressionObject::documentToBson(BSONObjBuilder *pBuilder, bool requireExpression) const {
1385+
if (_excludeId)
1386+
pBuilder->appendBool("_id", false);
1387+
13851388
for (vector<string>::const_iterator it(_order.begin()); it!=_order.end(); ++it) {
13861389
string fieldName = *it;
13871390
verify(_expressions.find(fieldName) != _expressions.end());
@@ -2280,21 +2283,14 @@ namespace mongo {
22802283
return NULL;
22812284
}
22822285

2283-
void ExpressionNary::toBson(
2284-
BSONObjBuilder *pBuilder, const char *pOpName) const {
2286+
void ExpressionNary::toBson(BSONObjBuilder *pBuilder, const char *pOpName) const {
22852287
const size_t nOperand = vpOperand.size();
2286-
verify(nOperand > 0);
2287-
if (nOperand == 1) {
2288-
vpOperand[0]->addToBsonObj(pBuilder, pOpName, false);
2289-
return;
2290-
}
22912288

22922289
/* build up the array */
2293-
BSONArrayBuilder arrBuilder;
2290+
BSONArrayBuilder arrBuilder (pBuilder->subarrayStart(pOpName));
22942291
for(size_t i = 0; i < nOperand; ++i)
22952292
vpOperand[i]->addToBsonArray(&arrBuilder);
2296-
2297-
pBuilder->append(pOpName, arrBuilder.arr());
2293+
arrBuilder.doneFast();
22982294
}
22992295

23002296
void ExpressionNary::addToBsonObj(

0 commit comments

Comments
 (0)