0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00
mongodb/db/queryutil.cpp
2009-02-24 14:14:45 -05:00

143 lines
4.7 KiB
C++

// queryutil.cpp
/**
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stdafx.h"
#include "btree.h"
#include "pdfile.h"
#include "queryoptimizer.h"
namespace mongo {
FieldBound::FieldBound( const BSONElement &e ) :
lower_( minKey.firstElement() ),
upper_( maxKey.firstElement() ) {
if ( e.eoo() )
return;
if ( e.type() == RegEx ) {
const char *r = e.simpleRegex();
if ( r ) {
lower_ = addObj( BSON( "" << r ) ).firstElement();
upper_ = addObj( BSON( "" << simpleRegexEnd( r ) ) ).firstElement();
}
return;
}
switch( e.getGtLtOp() ) {
case JSMatcher::Equality:
lower_ = e;
upper_ = e;
break;
case JSMatcher::LT:
case JSMatcher::LTE:
upper_ = e;
break;
case JSMatcher::GT:
case JSMatcher::GTE:
lower_ = e;
break;
case JSMatcher::opIN: {
massert( "$in requires array", e.type() == Array );
BSONElement max = minKey.firstElement();
BSONElement min = maxKey.firstElement();
BSONObjIterator i( e.embeddedObject() );
while( i.more() ) {
BSONElement f = i.next();
if ( f.eoo() )
break;
if ( max.woCompare( f, false ) < 0 )
max = f;
if ( min.woCompare( f, false ) > 0 )
min = f;
}
lower_ = min;
upper_ = max;
}
default:
break;
}
}
FieldBound &FieldBound::operator&=( const FieldBound &other ) {
if ( other.upper_.woCompare( upper_, false ) < 0 )
upper_ = other.upper_;
if ( other.lower_.woCompare( lower_, false ) > 0 )
lower_ = other.lower_;
for( vector< BSONObj >::const_iterator i = other.objData_.begin(); i != other.objData_.end(); ++i )
objData_.push_back( *i );
return *this;
}
string FieldBound::simpleRegexEnd( string regex ) {
++regex[ regex.length() - 1 ];
return regex;
}
BSONObj FieldBound::addObj( const BSONObj &o ) {
objData_.push_back( o );
return o;
}
FieldBoundSet::FieldBoundSet( const char *ns, const BSONObj &query ) :
ns_( ns ),
query_( query.copy() ) {
BSONObjIterator i( query_ );
while( i.more() ) {
BSONElement e = i.next();
if ( e.eoo() )
break;
if ( getGtLtOp( e ) == JSMatcher::Equality ) {
bounds_[ e.fieldName() ] &= FieldBound( e );
}
else {
BSONObjIterator i( e.embeddedObject() );
while( i.more() ) {
BSONElement f = i.next();
if ( f.eoo() )
break;
bounds_[ e.fieldName() ] &= FieldBound( f );
}
}
}
}
FieldBound *FieldBoundSet::trivialBound_ = 0;
FieldBound &FieldBoundSet::trivialBound() {
if ( trivialBound_ == 0 )
trivialBound_ = new FieldBound();
return *trivialBound_;
}
BSONObj FieldBoundSet::simplifiedQuery() const {
BSONObjBuilder b;
for( map< string, FieldBound >::const_iterator i = bounds_.begin(); i != bounds_.end(); ++i ) {
if ( i->second.equality() )
b.appendAs( i->second.lower(), i->first.c_str() );
else if ( i->second.nontrivial() ) {
BSONObjBuilder c;
if ( i->second.lower().type() != MinKey )
c.appendAs( i->second.lower(), "$gte" );
if ( i->second.upper().type() != MaxKey )
c.appendAs( i->second.upper(), "$lte" );
b.append( i->first.c_str(), c.done() );
}
}
return b.obj();
}
} // namespace mongo