2009-02-24 20:14:45 +01:00
|
|
|
// queryutil.h
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "jsobj.h"
|
|
|
|
|
|
|
|
namespace mongo {
|
|
|
|
|
|
|
|
class FieldBound {
|
|
|
|
public:
|
|
|
|
FieldBound( const BSONElement &e = emptyObj.firstElement() );
|
2009-02-25 00:37:42 +01:00
|
|
|
const FieldBound &operator&=( const FieldBound &other );
|
2009-02-24 20:14:45 +01:00
|
|
|
BSONElement lower() const { return lower_; }
|
|
|
|
BSONElement upper() const { return upper_; }
|
2009-02-27 17:22:12 +01:00
|
|
|
bool lowerInclusive() const { return lowerInclusive_; }
|
|
|
|
bool upperInclusive() const { return upperInclusive_; }
|
|
|
|
bool equality() const {
|
|
|
|
return
|
|
|
|
lower_.woCompare( upper_, false ) == 0 &&
|
|
|
|
upperInclusive_ &&
|
|
|
|
lowerInclusive_;
|
|
|
|
}
|
2009-02-24 20:14:45 +01:00
|
|
|
bool nontrivial() const {
|
|
|
|
return
|
|
|
|
minKey.firstElement().woCompare( lower_, false ) != 0 ||
|
|
|
|
maxKey.firstElement().woCompare( upper_, false ) != 0;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
BSONObj addObj( const BSONObj &o );
|
|
|
|
string simpleRegexEnd( string regex );
|
|
|
|
BSONElement lower_;
|
2009-02-27 17:22:12 +01:00
|
|
|
bool lowerInclusive_;
|
2009-02-24 20:14:45 +01:00
|
|
|
BSONElement upper_;
|
2009-02-27 17:22:12 +01:00
|
|
|
bool upperInclusive_;
|
2009-02-24 20:14:45 +01:00
|
|
|
vector< BSONObj > objData_;
|
|
|
|
};
|
|
|
|
|
2009-02-24 21:20:29 +01:00
|
|
|
class QueryPattern {
|
|
|
|
public:
|
|
|
|
friend class FieldBoundSet;
|
|
|
|
enum Type {
|
|
|
|
Equality,
|
|
|
|
LowerBound,
|
|
|
|
UpperBound,
|
|
|
|
UpperAndLowerBound
|
|
|
|
};
|
2009-02-25 16:06:56 +01:00
|
|
|
// for testing only, speed unimportant
|
2009-02-24 21:20:29 +01:00
|
|
|
bool operator==( const QueryPattern &other ) const {
|
2009-02-25 16:06:56 +01:00
|
|
|
bool less = operator<( other );
|
|
|
|
bool more = other.operator<( *this );
|
|
|
|
assert( !( less && more ) );
|
|
|
|
return !( less || more );
|
2009-02-24 21:20:29 +01:00
|
|
|
}
|
|
|
|
bool operator!=( const QueryPattern &other ) const {
|
|
|
|
return !operator==( other );
|
|
|
|
}
|
2009-02-24 23:48:06 +01:00
|
|
|
bool operator<( const QueryPattern &other ) const {
|
|
|
|
map< string, Type >::const_iterator i = fieldTypes_.begin();
|
|
|
|
map< string, Type >::const_iterator j = other.fieldTypes_.begin();
|
|
|
|
while( i != fieldTypes_.end() ) {
|
|
|
|
if ( j == other.fieldTypes_.end() )
|
|
|
|
return false;
|
|
|
|
if ( i->first < j->first )
|
|
|
|
return true;
|
|
|
|
else if ( i->first > j->first )
|
|
|
|
return false;
|
|
|
|
if ( i->second < j->second )
|
|
|
|
return true;
|
|
|
|
else if ( i->second > j->second )
|
|
|
|
return false;
|
|
|
|
++i;
|
|
|
|
++j;
|
|
|
|
}
|
2009-02-26 17:13:36 +01:00
|
|
|
if ( j != other.fieldTypes_.end() )
|
|
|
|
return true;
|
|
|
|
return sort_.woCompare( other.sort_ ) < 0;
|
2009-02-24 23:48:06 +01:00
|
|
|
}
|
2009-02-24 21:20:29 +01:00
|
|
|
private:
|
|
|
|
QueryPattern() {}
|
2009-02-26 17:13:36 +01:00
|
|
|
void setSort( const BSONObj sort ) {
|
|
|
|
sort_ = normalizeSort( sort );
|
|
|
|
}
|
|
|
|
BSONObj static normalizeSort( const BSONObj &spec ) {
|
2009-02-26 17:33:23 +01:00
|
|
|
if ( spec.isEmpty() )
|
|
|
|
return spec;
|
2009-02-26 17:13:36 +01:00
|
|
|
int direction = ( spec.firstElement().number() >= 0 ) ? 1 : -1;
|
|
|
|
BSONObjIterator i( spec );
|
|
|
|
BSONObjBuilder b;
|
|
|
|
while( i.more() ) {
|
|
|
|
BSONElement e = i.next();
|
|
|
|
if ( e.eoo() )
|
|
|
|
break;
|
|
|
|
b.append( e.fieldName(), direction * ( ( e.number() >= 0 ) ? -1 : 1 ) );
|
|
|
|
}
|
|
|
|
return b.obj();
|
|
|
|
}
|
2009-02-24 21:20:29 +01:00
|
|
|
map< string, Type > fieldTypes_;
|
2009-02-26 17:13:36 +01:00
|
|
|
BSONObj sort_;
|
2009-02-24 21:20:29 +01:00
|
|
|
};
|
|
|
|
|
2009-02-24 20:14:45 +01:00
|
|
|
class FieldBoundSet {
|
|
|
|
public:
|
|
|
|
FieldBoundSet( const char *ns, const BSONObj &query );
|
|
|
|
const FieldBound &bound( const char *fieldName ) const {
|
|
|
|
map< string, FieldBound >::const_iterator f = bounds_.find( fieldName );
|
|
|
|
if ( f == bounds_.end() )
|
|
|
|
return trivialBound();
|
|
|
|
return f->second;
|
|
|
|
}
|
|
|
|
int nBounds() const {
|
|
|
|
int count = 0;
|
|
|
|
for( map< string, FieldBound >::const_iterator i = bounds_.begin(); i != bounds_.end(); ++i )
|
|
|
|
++count;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
int nNontrivialBounds() const {
|
|
|
|
int count = 0;
|
|
|
|
for( map< string, FieldBound >::const_iterator i = bounds_.begin(); i != bounds_.end(); ++i )
|
|
|
|
if ( i->second.nontrivial() )
|
|
|
|
++count;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
const char *ns() const { return ns_; }
|
|
|
|
BSONObj query() const { return query_; }
|
|
|
|
BSONObj simplifiedQuery() const;
|
|
|
|
bool matchPossible() const {
|
|
|
|
for( map< string, FieldBound >::const_iterator i = bounds_.begin(); i != bounds_.end(); ++i )
|
|
|
|
if ( i->second.lower().woCompare( i->second.upper(), false ) > 0 )
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
2009-02-26 17:13:36 +01:00
|
|
|
QueryPattern pattern( const BSONObj &sort = emptyObj ) const;
|
2009-02-24 20:14:45 +01:00
|
|
|
private:
|
|
|
|
static FieldBound *trivialBound_;
|
|
|
|
static FieldBound &trivialBound();
|
|
|
|
map< string, FieldBound > bounds_;
|
|
|
|
const char *ns_;
|
|
|
|
BSONObj query_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace mongo
|