diff --git a/db/queryoptimizer.cpp b/db/queryoptimizer.cpp index 4173eaaa2cd..4f394ce8b3d 100644 --- a/db/queryoptimizer.cpp +++ b/db/queryoptimizer.cpp @@ -52,7 +52,7 @@ namespace mongo { QueryPlan::QueryPlan( NamespaceDetails *d, int idxNo, - const FieldRangeSetPair &frsp, const FieldRangeSetPair &originalFrsp, const BSONObj &originalQuery, const BSONObj &order, const BSONObj &startKey, const BSONObj &endKey , string special ) : + const FieldRangeSetPair &frsp, const FieldRangeSetPair *originalFrsp, const BSONObj &originalQuery, const BSONObj &order, const BSONObj &startKey, const BSONObj &endKey , string special ) : _d(d), _idxNo(idxNo), _frs( frsp.frsForIndex( _d, _idxNo ) ), _frsMulti( frsp.frsForIndex( _d, -1 ) ), @@ -166,12 +166,17 @@ doneCheckOrder: _optimal = true; if ( exactIndexedQueryCount == _frs.nNontrivialRanges() && orderFieldsUnindexed.size() == 0 && - exactIndexedQueryCount == _index->keyPattern().nFields() && + exactIndexedQueryCount == idxKey.nFields() && exactIndexedQueryCount == _originalQuery.nFields() ) { _exactKeyMatch = true; } _frv.reset( new FieldRangeVector( _frs, idxSpec, _direction ) ); - _originalFrv.reset( new FieldRangeVector( originalFrsp.frsForIndex( _d, _idxNo ), idxSpec, _direction ) ); + if ( originalFrsp ) { + _originalFrv.reset( new FieldRangeVector( originalFrsp->frsForIndex( _d, _idxNo ), idxSpec, _direction ) ); + } + else { + _originalFrv = _frv; + } if ( _startOrEndSpec ) { BSONObj newStart, newEnd; if ( !startKey.isEmpty() ) @@ -328,7 +333,7 @@ doneCheckOrder: massert( 10365 , errmsg, indexDetailsForRange( _frsp->ns(), errmsg, _min, _max, keyPattern ) ); } NamespaceDetails *d = nsdetails(_ns); - _plans.push_back( QueryPlanPtr( new QueryPlan( d, d->idxNo(id), *_frsp, *_originalFrsp, _originalQuery, _order, _min, _max ) ) ); + _plans.push_back( QueryPlanPtr( new QueryPlan( d, d->idxNo(id), *_frsp, _originalFrsp.get(), _originalQuery, _order, _min, _max ) ) ); } // returns an IndexDetails * for a hint, 0 if hint is $natural. @@ -374,7 +379,7 @@ doneCheckOrder: NamespaceDetails *d = nsdetails( ns ); if ( !d || !_frsp->matchPossible() ) { // Table scan plan, when no matches are possible - _plans.push_back( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, *_originalFrsp, _originalQuery, _order ) ) ); + _plans.push_back( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ) ); return; } @@ -388,7 +393,7 @@ doneCheckOrder: else { massert( 10366 , "natural order cannot be specified with $min/$max", _min.isEmpty() && _max.isEmpty() ); // Table scan plan - _plans.push_back( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, *_originalFrsp, _originalQuery, _order ) ) ); + _plans.push_back( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ) ); } return; } @@ -398,7 +403,7 @@ doneCheckOrder: BSONObj keyPattern; IndexDetails *idx = indexDetailsForRange( ns, errmsg, _min, _max, keyPattern ); massert( 10367 , errmsg, idx ); - _plans.push_back( QueryPlanPtr( new QueryPlan( d, d->idxNo(*idx), *_frsp, *_originalFrsp, _originalQuery, _order, _min, _max ) ) ); + _plans.push_back( QueryPlanPtr( new QueryPlan( d, d->idxNo(*idx), *_frsp, _originalFrsp.get(), _originalQuery, _order, _min, _max ) ) ); return; } @@ -407,13 +412,13 @@ doneCheckOrder: if ( idx >= 0 ) { _usingPrerecordedPlan = true; _mayRecordPlan = false; - _plans.push_back( QueryPlanPtr( new QueryPlan( d , idx , *_frsp , *_originalFrsp , _originalQuery, _order ) ) ); + _plans.push_back( QueryPlanPtr( new QueryPlan( d , idx , *_frsp , _originalFrsp.get() , _originalQuery, _order ) ) ); return; } } if ( _originalQuery.isEmpty() && _order.isEmpty() ) { - _plans.push_back( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, *_originalFrsp, _originalQuery, _order ) ) ); + _plans.push_back( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ) ); return; } @@ -428,7 +433,7 @@ doneCheckOrder: if ( spec.getTypeName() == _special && spec.suitability( _originalQuery , _order ) ) { _usingPrerecordedPlan = true; _mayRecordPlan = false; - _plans.push_back( QueryPlanPtr( new QueryPlan( d , j , *_frsp , *_originalFrsp , _originalQuery, _order , + _plans.push_back( QueryPlanPtr( new QueryPlan( d , j , *_frsp , _originalFrsp.get() , _originalQuery, _order , BSONObj() , BSONObj() , _special ) ) ); return; } @@ -445,7 +450,7 @@ doneCheckOrder: _oldNScanned = oldNScanned; if ( !strcmp( bestIndex.firstElementFieldName(), "$natural" ) ) { // Table scan plan - p.reset( new QueryPlan( d, -1, *_frsp, *_originalFrsp, _originalQuery, _order ) ); + p.reset( new QueryPlan( d, -1, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ); } NamespaceDetails::IndexIterator i = d->ii(); @@ -453,7 +458,7 @@ doneCheckOrder: int j = i.pos(); IndexDetails& ii = i.next(); if( ii.keyPattern().woCompare(bestIndex) == 0 ) { - p.reset( new QueryPlan( d, j, *_frsp, *_originalFrsp, _originalQuery, _order ) ); + p.reset( new QueryPlan( d, j, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ); } } @@ -480,7 +485,7 @@ doneCheckOrder: if ( !_frsp->matchPossible() || ( _frsp->noNontrivialRanges() && _order.isEmpty() ) || ( !_order.isEmpty() && !strcmp( _order.firstElementFieldName(), "$natural" ) ) ) { // Table scan plan - addPlan( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, *_originalFrsp, _originalQuery, _order ) ), checkFirst ); + addPlan( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ), checkFirst ); return; } @@ -490,10 +495,11 @@ doneCheckOrder: QueryPlanPtr optimalPlan; for( int i = 0; i < d->nIndexes; ++i ) { if ( normalQuery ) { - if ( !_frsp->matchPossibleForIndex( d, i, d->idx( i ).keyPattern() ) ) { + BSONObj keyPattern = d->idx( i ).keyPattern(); + if ( !_frsp->matchPossibleForIndex( d, i, keyPattern ) ) { // If no match is possible, only generate a trival plan that won't // scan any documents. - QueryPlanPtr p( new QueryPlan( d, i, *_frsp, *_originalFrsp, _originalQuery, _order ) ); + QueryPlanPtr p( new QueryPlan( d, i, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ); addPlan( p, checkFirst ); return; } @@ -502,7 +508,7 @@ doneCheckOrder: } } - QueryPlanPtr p( new QueryPlan( d, i, *_frsp, *_originalFrsp, _originalQuery, _order ) ); + QueryPlanPtr p( new QueryPlan( d, i, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ); if ( p->optimal() ) { if ( !optimalPlan.get() ) { optimalPlan = p; @@ -520,7 +526,7 @@ doneCheckOrder: addPlan( *i, checkFirst ); // Table scan plan - addPlan( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, *_originalFrsp, _originalQuery, _order ) ), checkFirst ); + addPlan( QueryPlanPtr( new QueryPlan( d, -1, *_frsp, _originalFrsp.get(), _originalQuery, _order ) ), checkFirst ); } shared_ptr QueryPlanSet::runOp( QueryOp &op ) { @@ -815,24 +821,29 @@ doneCheckOrder: _ns( ns ), _or( !query.getField( "$or" ).eoo() ), _query( query.getOwned() ), - _org( ns, _query ), _i(), _honorRecordedPlan( honorRecordedPlan ), _bestGuessOnly( bestGuessOnly ), _hint( ( hint && !hint->eoo() ) ? hint->wrap() : BSONObj() ), _mayYield( mayYield ), _tableScanned() { - if ( !order.isEmpty() || !min.isEmpty() || !max.isEmpty() || !_org.getSpecial().empty() ) { + if ( !order.isEmpty() || !min.isEmpty() || !max.isEmpty() ) { _or = false; } - if ( _or && uselessOr( _hint.firstElement() ) ) { - _or = false; + if ( _or ) { + // Only construct an OrRangeGenerator if we may handle $or clauses. + _org.reset( new OrRangeGenerator( ns, _query ) ); + if ( !_org->getSpecial().empty() ) { + _or = false; + } + if ( uselessOr( _hint.firstElement() ) ) { + _or = false; + } } // if _or == false, don't use or clauses for index selection if ( !_or ) { auto_ptr frsp( new FieldRangeSetPair( ns, _query, true ) ); - auto_ptr oldFrsp( new FieldRangeSetPair( *frsp ) ); - _currentQps.reset( new QueryPlanSet( ns, frsp, oldFrsp, _query, order, hint, honorRecordedPlan, min, max, _bestGuessOnly, _mayYield ) ); + _currentQps.reset( new QueryPlanSet( ns, frsp, auto_ptr(), _query, order, hint, honorRecordedPlan, min, max, _bestGuessOnly, _mayYield ) ); } else { BSONElement e = _query.getField( "$or" ); @@ -847,8 +858,8 @@ doneCheckOrder: return _currentQps->runOp( op ); } ++_i; - auto_ptr frsp( _org.topFrsp() ); - auto_ptr originalFrsp( _org.topFrspOriginal() ); + auto_ptr frsp( _org->topFrsp() ); + auto_ptr originalFrsp( _org->topFrspOriginal() ); BSONElement hintElt = _hint.firstElement(); _currentQps.reset( new QueryPlanSet( _ns, frsp, originalFrsp, _query, BSONObj(), &hintElt, _honorRecordedPlan, BSONObj(), BSONObj(), _bestGuessOnly, _mayYield ) ); shared_ptr ret( _currentQps->runOp( op ) ); @@ -856,7 +867,7 @@ doneCheckOrder: _tableScanned = true; } else { // If the full table was scanned, don't bother popping the last or clause. - _org.popOrClause( ret->qp().nsd(), ret->qp().idxNo(), ret->qp().indexed() ? ret->qp().indexKey() : BSONObj() ); + _org->popOrClause( ret->qp().nsd(), ret->qp().idxNo(), ret->qp().indexed() ? ret->qp().indexKey() : BSONObj() ); } return ret; } @@ -877,7 +888,7 @@ doneCheckOrder: if ( op->qp().willScanTable() ) { _tableScanned = true; } else { - _org.popOrClause( op->qp().nsd(), op->qp().idxNo(), op->qp().indexed() ? op->qp().indexKey() : BSONObj() ); + _org->popOrClause( op->qp().nsd(), op->qp().idxNo(), op->qp().indexed() ? op->qp().indexKey() : BSONObj() ); } return op; } @@ -887,8 +898,8 @@ doneCheckOrder: shared_ptr op; while( mayRunMore() ) { ++_i; - auto_ptr frsp( _org.topFrsp() ); - auto_ptr originalFrsp( _org.topFrspOriginal() ); + auto_ptr frsp( _org->topFrsp() ); + auto_ptr originalFrsp( _org->topFrspOriginal() ); BSONElement hintElt = _hint.firstElement(); _currentQps.reset( new QueryPlanSet( _ns, frsp, originalFrsp, _query, BSONObj(), &hintElt, _honorRecordedPlan, BSONObj(), BSONObj(), _bestGuessOnly, _mayYield ) ); op = nextOpHandleEndOfClause(); @@ -954,9 +965,9 @@ doneCheckOrder: if ( !id ) { return true; } - return QueryUtilIndexed::uselessOr( _org, nsd, nsd->idxNo( *id ) ); + return QueryUtilIndexed::uselessOr( *_org, nsd, nsd->idxNo( *id ) ); } - return QueryUtilIndexed::uselessOr( _org, nsd, -1 ); + return QueryUtilIndexed::uselessOr( *_org, nsd, -1 ); } MultiCursor::MultiCursor( const char *ns, const BSONObj &pattern, const BSONObj &order, shared_ptr op, bool mayYield ) @@ -1199,12 +1210,13 @@ doneCheckOrder: } bool QueryUtilIndexed::indexUseful( const FieldRangeSetPair &frsp, NamespaceDetails *d, int idxNo, const BSONObj &order ) { - frsp.assertValidIndex( d, idxNo ); - if ( !frsp.matchPossibleForIndex( d, idxNo, d->idx( idxNo ).keyPattern() ) ) { + DEV frsp.assertValidIndex( d, idxNo ); + BSONObj keyPattern = d->idx( idxNo ).keyPattern(); + if ( !frsp.matchPossibleForIndex( d, idxNo, keyPattern ) ) { // No matches are possible in the index so the index may be useful. return true; } - return d->idx( idxNo ).getSpec().suitability( frsp.simplifiedQueryForIndex( d, idxNo, d->idx( idxNo ).keyPattern() ), order ) != USELESS; + return d->idx( idxNo ).getSpec().suitability( frsp.simplifiedQueryForIndex( d, idxNo, keyPattern ), order ) != USELESS; } void QueryUtilIndexed::clearIndexesForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order ) { diff --git a/db/queryoptimizer.h b/db/queryoptimizer.h index e55e791e1ca..65bd17ca4da 100644 --- a/db/queryoptimizer.h +++ b/db/queryoptimizer.h @@ -35,10 +35,13 @@ namespace mongo { class QueryPlan : boost::noncopyable { public: + /** + * @param originalFrsp - original constraints for this query clause. If null, frsp will be used instead. + */ QueryPlan(NamespaceDetails *d, int idxNo, // -1 = no index const FieldRangeSetPair &frsp, - const FieldRangeSetPair &originalFrsp, + const FieldRangeSetPair *originalFrsp, const BSONObj &originalQuery, const BSONObj &order, const BSONObj &startKey = BSONObj(), @@ -245,6 +248,9 @@ namespace mongo { typedef boost::shared_ptr QueryPlanPtr; typedef vector PlanSet; + /** + * @param originalFrsp - original constraints for this query clause; if null, frsp will be used. + */ QueryPlanSet( const char *ns, auto_ptr frsp, auto_ptr originalFrsp, @@ -290,7 +296,7 @@ namespace mongo { //for testing const FieldRangeSetPair &frsp() const { return *_frsp; } - const FieldRangeSetPair &originalFrsp() const { return *_originalFrsp; } + const FieldRangeSetPair *originalFrsp() const { return _originalFrsp.get(); } bool modifiedKeys() const; bool hasMultiKey() const; @@ -420,7 +426,7 @@ namespace mongo { shared_ptr singleCursor() const; /** @return true iff more $or clauses need to be scanned. */ - bool mayRunMore() const { return _or ? ( !_tableScanned && !_org.orFinished() ) : _i == 0; } + bool mayRunMore() const { return _or ? ( !_tableScanned && !_org->orFinished() ) : _i == 0; } /** @return non-$or version of explain output. */ BSONObj oldExplain() const { assertNotOr(); return _currentQps->explain(); } /** @return true iff this is not a $or query and a plan is selected based on previous success of this plan. */ @@ -445,7 +451,7 @@ namespace mongo { const char * _ns; bool _or; BSONObj _query; - OrRangeGenerator _org; + shared_ptr _org; // May be null in certain non $or query cases. auto_ptr _currentQps; int _i; bool _honorRecordedPlan; diff --git a/db/queryutil-inl.h b/db/queryutil-inl.h index 2c3a757b385..d0fc212cef9 100644 --- a/db/queryutil-inl.h +++ b/db/queryutil-inl.h @@ -130,5 +130,24 @@ namespace mongo { } return ret; } + + inline bool FieldRangeSetPair::matchPossibleForIndex( NamespaceDetails *d, int idxNo, const BSONObj &keyPattern ) const { + assertValidIndexOrNoIndex( d, idxNo ); + if ( !matchPossible() ) { + return false; + } + if ( idxNo < 0 ) { + // multi key matchPossible() is true, so return true. + return true; + } + return frsForIndex( d, idxNo ).matchPossibleForIndex( keyPattern ); + } + inline void FieldRangeSetPair::assertValidIndexOrNoIndex( const NamespaceDetails *d, int idxNo ) const { + massert( 14049, "FieldRangeSetPair invalid index specified", idxNo >= -1 ); + if ( idxNo >= 0 ) { + assertValidIndex( d, idxNo ); + } + } + } // namespace mongo diff --git a/db/queryutil.cpp b/db/queryutil.cpp index a972375990f..dd3b536fb51 100644 --- a/db/queryutil.cpp +++ b/db/queryutil.cpp @@ -158,8 +158,10 @@ namespace mongo { FieldRange::FieldRange( const BSONElement &e, bool singleKey, bool isNot, bool optimize ) : _singleKey( singleKey ) { + int op = e.getGtLtOp(); + // NOTE with $not, we could potentially form a complementary set of intervals. - if ( !isNot && !e.eoo() && e.type() != RegEx && e.getGtLtOp() == BSONObj::opIN ) { + if ( !isNot && !e.eoo() && e.type() != RegEx && op == BSONObj::opIN ) { set vals; vector regexes; uassert( 12580 , "invalid query" , e.isABSONObj() ); @@ -196,7 +198,7 @@ namespace mongo { // A document array may be indexed by its first element, by undefined // if it is empty, or as a full array if it is embedded within another // array. - if ( e.type() == Array && e.getGtLtOp() == BSONObj::Equality ) { + if ( e.type() == Array && op == BSONObj::Equality ) { _intervals.push_back( FieldInterval(e) ); BSONElement temp = e.embeddedObject().firstElement(); @@ -227,8 +229,6 @@ namespace mongo { if ( e.eoo() ) return; - int op = e.getGtLtOp(); - bool existsSpec = false; if ( op == BSONObj::opEXISTS ) { existsSpec = e.trueValue(); @@ -785,30 +785,32 @@ namespace mongo { } void FieldRangeSet::processQueryField( const BSONElement &e, bool optimize ) { - if ( strcmp( e.fieldName(), "$and" ) == 0 ) { - uassert( 14816 , "$and expression must be a nonempty array" , e.type() == Array && e.embeddedObject().nFields() > 0 ); - BSONObjIterator i( e.embeddedObject() ); - while( i.more() ) { - BSONElement e = i.next(); - uassert( 14817 , "$and elements must be objects" , e.type() == Object ); - BSONObjIterator j( e.embeddedObject() ); - while( j.more() ) { - processQueryField( j.next(), optimize ); - } - } - } + if ( e.fieldName()[ 0 ] == '$' ) { + if ( strcmp( e.fieldName(), "$and" ) == 0 ) { + uassert( 14816 , "$and expression must be a nonempty array" , e.type() == Array && e.embeddedObject().nFields() > 0 ); + BSONObjIterator i( e.embeddedObject() ); + while( i.more() ) { + BSONElement e = i.next(); + uassert( 14817 , "$and elements must be objects" , e.type() == Object ); + BSONObjIterator j( e.embeddedObject() ); + while( j.more() ) { + processQueryField( j.next(), optimize ); + } + } + } - if ( strcmp( e.fieldName(), "$where" ) == 0 ) { - return; - } + if ( strcmp( e.fieldName(), "$where" ) == 0 ) { + return; + } - if ( strcmp( e.fieldName(), "$or" ) == 0 ) { - return; - } + if ( strcmp( e.fieldName(), "$or" ) == 0 ) { + return; + } - if ( strcmp( e.fieldName(), "$nor" ) == 0 ) { - return; - } + if ( strcmp( e.fieldName(), "$nor" ) == 0 ) { + return; + } + } bool equality = ( getGtLtOp( e ) == BSONObj::Equality ); if ( equality && e.type() == Object ) { @@ -1067,32 +1069,11 @@ namespace mongo { return ret; } - const FieldRangeSet &FieldRangeSetPair::frsForIndex( const NamespaceDetails* nsd, int idxNo ) const { - assertValidIndexOrNoIndex( nsd, idxNo ); - if ( idxNo < 0 ) { - // An unindexed cursor cannot have a "single key" constraint. - return _multiKey; - } - return nsd->isMultikey( idxNo ) ? _multiKey : _singleKey; - } - bool FieldRangeSetPair::noNontrivialRanges() const { return _singleKey.matchPossible() && _singleKey.nNontrivialRanges() == 0 && _multiKey.matchPossible() && _multiKey.nNontrivialRanges() == 0; } - bool FieldRangeSetPair::matchPossibleForIndex( NamespaceDetails *d, int idxNo, const BSONObj &keyPattern ) const { - assertValidIndexOrNoIndex( d, idxNo ); - if ( !matchPossible() ) { - return false; - } - if ( idxNo < 0 ) { - // multi key matchPossible() is true, so return true. - return true; - } - return frsForIndex( d, idxNo ).matchPossibleForIndex( keyPattern ); - } - FieldRangeSetPair &FieldRangeSetPair::operator&=( const FieldRangeSetPair &other ) { _singleKey &= other._singleKey; _multiKey &= other._multiKey; @@ -1105,21 +1086,23 @@ namespace mongo { return *this; } - void FieldRangeSetPair::assertValidIndex( const NamespaceDetails *d, int idxNo ) const { - massert( 14048, "FieldRangeSetPair invalid index specified", idxNo >= 0 && idxNo < d->nIndexes ); - } - - void FieldRangeSetPair::assertValidIndexOrNoIndex( const NamespaceDetails *d, int idxNo ) const { - massert( 14049, "FieldRangeSetPair invalid index specified", idxNo >= -1 ); - if ( idxNo >= 0 ) { - assertValidIndex( d, idxNo ); - } - } - BSONObj FieldRangeSetPair::simplifiedQueryForIndex( NamespaceDetails *d, int idxNo, const BSONObj &keyPattern ) const { return frsForIndex( d, idxNo ).simplifiedQuery( keyPattern ); } + void FieldRangeSetPair::assertValidIndex( const NamespaceDetails *d, int idxNo ) const { + massert( 14048, "FieldRangeSetPair invalid index specified", idxNo >= 0 && idxNo < d->nIndexes ); + } + + const FieldRangeSet &FieldRangeSetPair::frsForIndex( const NamespaceDetails* nsd, int idxNo ) const { + assertValidIndexOrNoIndex( nsd, idxNo ); + if ( idxNo < 0 ) { + // An unindexed cursor cannot have a "single key" constraint. + return _multiKey; + } + return nsd->isMultikey( idxNo ) ? _multiKey : _singleKey; + } + bool FieldRangeVector::matchesElement( const BSONElement &e, int i, bool forward ) const { bool eq; int l = matchingLowElement( e, i, forward, eq ); diff --git a/dbtests/queryoptimizertests.cpp b/dbtests/queryoptimizertests.cpp index bd597572d52..32d18544a36 100644 --- a/dbtests/queryoptimizertests.cpp +++ b/dbtests/queryoptimizertests.cpp @@ -104,7 +104,7 @@ namespace QueryOptimizerTests { auto_ptr< FieldRangeSetPair > FieldRangeSetPair_GLOBAL; #define FRSP(x) ( FieldRangeSetPair_GLOBAL.reset( new FieldRangeSetPair( ns(), x ) ), *FieldRangeSetPair_GLOBAL ) auto_ptr< FieldRangeSetPair > FieldRangeSetPair_GLOBAL2; -#define FRSP2(x) ( FieldRangeSetPair_GLOBAL2.reset( new FieldRangeSetPair( ns(), x ) ), *FieldRangeSetPair_GLOBAL2 ) +#define FRSP2(x) ( FieldRangeSetPair_GLOBAL2.reset( new FieldRangeSetPair( ns(), x ) ), FieldRangeSetPair_GLOBAL2.get() ) class NoIndex : public Base { public: @@ -886,7 +886,7 @@ namespace QueryOptimizerTests { } BSONObj hint = fromjson( "{$hint:{a:1,b:1}}" ); auto_ptr< FieldRangeSetPair > frsp( new FieldRangeSetPair( ns(), fromjson( "{a:5,b:{$in:[2,3,6,9,11]}}" ) ) ); - QueryPlan qp( nsd(), 1, *frsp, *frsp, fromjson( "{a:5,b:{$in:[2,3,6,9,11]}}" ), BSONObj() ); + QueryPlan qp( nsd(), 1, *frsp, frsp.get(), fromjson( "{a:5,b:{$in:[2,3,6,9,11]}}" ), BSONObj() ); boost::shared_ptr c = qp.newCursor(); double expected[] = { 2, 3, 6, 9 }; ASSERT( c->ok() ); @@ -908,7 +908,7 @@ namespace QueryOptimizerTests { } BSONObj hint = fromjson( "{$hint:{a:1,b:1}}" ); auto_ptr< FieldRangeSetPair > frsp( new FieldRangeSetPair( ns(), fromjson( "{a:{$gte:5},b:{$in:[2,3,6,9,11]}}" ) ) ); - QueryPlan qp( nsd(), 1, *frsp, *frsp, fromjson( "{a:{$gte:5},b:{$in:[2,3,6,9,11]}}" ), BSONObj() ); + QueryPlan qp( nsd(), 1, *frsp, frsp.get(), fromjson( "{a:{$gte:5},b:{$in:[2,3,6,9,11]}}" ), BSONObj() ); boost::shared_ptr c = qp.newCursor(); int matches[] = { 2, 3, 6, 9 }; for( int i = 0; i < 4; ++i, c->advance() ) { diff --git a/dbtests/repltests.cpp b/dbtests/repltests.cpp index 7009b556899..2bf522555ab 100644 --- a/dbtests/repltests.cpp +++ b/dbtests/repltests.cpp @@ -1069,7 +1069,7 @@ namespace ReplTests { BSONObj query = BSON( "ts" << b.obj() ); FieldRangeSetPair frsp( cllNS(), query ); BSONObj order = BSON( "$natural" << 1 ); - QueryPlan qp( nsd, -1, frsp, frsp, query, order ); + QueryPlan qp( nsd, -1, frsp, &frsp, query, order ); FindingStartCursor fsc( qp ); ASSERT( fsc.done() ); ASSERT_EQUALS( 0, fsc.cursor()->current()[ "o" ].Obj()[ "_id" ].Int() );