mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
more flexibility and sanity checks for min/max query specs
This commit is contained in:
parent
af59c4ea9e
commit
a229845ceb
@ -822,6 +822,14 @@ namespace mongo {
|
||||
}
|
||||
} cmdFileMD5;
|
||||
|
||||
const IndexDetails *cmdIndexDetailsForRange( const char *ns, string &errmsg, BSONObj &min, BSONObj &max, BSONObj &keyPattern ) {
|
||||
if ( ns[ 0 ] == '\0' || min.isEmpty() || max.isEmpty() ) {
|
||||
errmsg = "invalid command syntax (note: min and max are required)";
|
||||
return 0;
|
||||
}
|
||||
return indexDetailsForRange( ns, errmsg, min, max, keyPattern );
|
||||
}
|
||||
|
||||
class CmdMedianKey : public Command {
|
||||
public:
|
||||
CmdMedianKey() : Command( "medianKey" ) {}
|
||||
@ -836,7 +844,7 @@ namespace mongo {
|
||||
BSONObj max = jsobj.getObjectField( "max" );
|
||||
BSONObj keyPattern = jsobj.getObjectField( "keyPattern" );
|
||||
|
||||
const IndexDetails *id = indexDetailsForRange( ns, errmsg, min, max, keyPattern );
|
||||
const IndexDetails *id = cmdIndexDetailsForRange( ns, errmsg, min, max, keyPattern );
|
||||
if ( id == 0 )
|
||||
return false;
|
||||
|
||||
@ -883,7 +891,7 @@ namespace mongo {
|
||||
errmsg = "only one of min or max specified";
|
||||
return false;
|
||||
} else {
|
||||
const IndexDetails *id = indexDetailsForRange( ns, errmsg, min, max, keyPattern );
|
||||
const IndexDetails *id = cmdIndexDetailsForRange( ns, errmsg, min, max, keyPattern );
|
||||
if ( id == 0 )
|
||||
return false;
|
||||
c.reset( new BtreeCursor( *id, min, max, 1 ) );
|
||||
|
@ -199,9 +199,6 @@ namespace mongo {
|
||||
}
|
||||
|
||||
void QueryPlanSet::init() {
|
||||
// TEMP
|
||||
uassert( "min and max must be specified together", ( min_.isEmpty() + max_.isEmpty() ) % 2 == 0 );
|
||||
|
||||
plans_.clear();
|
||||
mayRecordPlan_ = true;
|
||||
usingPrerecordedPlan_ = false;
|
||||
@ -442,10 +439,66 @@ namespace mongo {
|
||||
return false;
|
||||
}
|
||||
|
||||
BSONObj extremeKeyForIndex( const BSONObj &idxPattern, int baseDirection ) {
|
||||
BSONObjIterator i( idxPattern );
|
||||
BSONObjBuilder b;
|
||||
while( i.more() ) {
|
||||
BSONElement e = i.next();
|
||||
if ( e.eoo() )
|
||||
break;
|
||||
int idxDirection = e.number() >= 0 ? 1 : -1;
|
||||
int direction = idxDirection * baseDirection;
|
||||
switch( direction ) {
|
||||
case 1:
|
||||
b.appendMaxKey( e.fieldName() );
|
||||
break;
|
||||
case -1:
|
||||
b.appendMinKey( e.fieldName() );
|
||||
break;
|
||||
default:
|
||||
assert( false );
|
||||
}
|
||||
}
|
||||
return b.obj();
|
||||
}
|
||||
|
||||
pair< int, int > keyAudit( const BSONObj &min, const BSONObj &max ) {
|
||||
int direction = 0;
|
||||
int firstSignificantField = 0;
|
||||
BSONObjIterator i( min );
|
||||
BSONObjIterator a( max );
|
||||
while( 1 ) {
|
||||
BSONElement ie = i.next();
|
||||
BSONElement ae = a.next();
|
||||
if ( ie.eoo() && ae.eoo() )
|
||||
break;
|
||||
if ( ie.eoo() || ae.eoo() || strcmp( ie.fieldName(), ae.fieldName() ) != 0 ) {
|
||||
return make_pair( -1, -1 );
|
||||
}
|
||||
int cmp = ie.woCompare( ae );
|
||||
if ( cmp < 0 )
|
||||
direction = 1;
|
||||
if ( cmp > 0 )
|
||||
direction = -1;
|
||||
if ( direction != 0 )
|
||||
break;
|
||||
++firstSignificantField;
|
||||
}
|
||||
return make_pair( direction, firstSignificantField );
|
||||
}
|
||||
|
||||
pair< int, int > flexibleKeyAudit( const BSONObj &min, const BSONObj &max ) {
|
||||
if ( min.isEmpty() || max.isEmpty() ) {
|
||||
return make_pair( 1, -1 );
|
||||
} else {
|
||||
return keyAudit( min, max );
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE min, max, and keyPattern will be updated to be consistent with the selected index.
|
||||
const IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSONObj &min, BSONObj &max, BSONObj &keyPattern ) {
|
||||
if ( ns[ 0 ] == '\0' || min.isEmpty() || max.isEmpty() ) {
|
||||
errmsg = "invalid command syntax (note: min and max are required)";
|
||||
if ( min.isEmpty() && max.isEmpty() ) {
|
||||
errmsg = "one of min or max must be specified";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -457,32 +510,15 @@ namespace mongo {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( keyPattern.isEmpty() ) {
|
||||
BSONObjIterator i( min );
|
||||
BSONObjIterator a( max );
|
||||
int direction = 0;
|
||||
int firstSignificantField = 0;
|
||||
while( 1 ) {
|
||||
BSONElement ie = i.next();
|
||||
BSONElement ae = a.next();
|
||||
if ( ie.eoo() && ae.eoo() )
|
||||
break;
|
||||
if ( ie.eoo() || ae.eoo() || strcmp( ie.fieldName(), ae.fieldName() ) != 0 ) {
|
||||
pair< int, int > ret = flexibleKeyAudit( min, max );
|
||||
if ( ret == make_pair( -1, -1 ) ) {
|
||||
errmsg = "min and max keys do not share pattern";
|
||||
return 0;
|
||||
}
|
||||
int cmp = ie.woCompare( ae );
|
||||
if ( cmp < 0 )
|
||||
direction = 1;
|
||||
if ( cmp > 0 )
|
||||
direction = -1;
|
||||
if ( direction != 0 )
|
||||
break;
|
||||
++firstSignificantField;
|
||||
}
|
||||
if ( keyPattern.isEmpty() ) {
|
||||
for (int i = 0; i < d->nIndexes; i++ ) {
|
||||
IndexDetails& ii = d->indexes[i];
|
||||
if ( indexWorks( ii.keyPattern(), min, direction, firstSignificantField ) ) {
|
||||
if ( indexWorks( ii.keyPattern(), min.isEmpty() ? max : min, ret.first, ret.second ) ) {
|
||||
id = ⅈ
|
||||
keyPattern = ii.keyPattern();
|
||||
break;
|
||||
@ -490,6 +526,10 @@ namespace mongo {
|
||||
}
|
||||
|
||||
} else {
|
||||
if ( !indexWorks( keyPattern, min.isEmpty() ? max : min, ret.first, ret.second ) ) {
|
||||
errmsg = "requested keyPattern does not match specified keys";
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < d->nIndexes; i++ ) {
|
||||
IndexDetails& ii = d->indexes[i];
|
||||
if( ii.keyPattern().woCompare(keyPattern) == 0 ) {
|
||||
@ -499,6 +539,12 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
|
||||
if ( min.isEmpty() ) {
|
||||
min = extremeKeyForIndex( keyPattern, -1 );
|
||||
} else if ( max.isEmpty() ) {
|
||||
max = extremeKeyForIndex( keyPattern, 1 );
|
||||
}
|
||||
|
||||
if ( !id ) {
|
||||
errmsg = "no index found for specified keyPattern";
|
||||
return 0;
|
||||
|
@ -575,11 +575,6 @@ namespace QueryTests {
|
||||
ASSERT_EQUALS( 1, obj.getIntField( "b" ) );
|
||||
ASSERT( !c->more() );
|
||||
}
|
||||
|
||||
// TEMP
|
||||
ASSERT( !error() );
|
||||
client().findOne( ns, Query().min( BSON( "a" << 1 << "b" << 1 ) ) );
|
||||
ASSERT( error() );
|
||||
}
|
||||
private:
|
||||
auto_ptr< DBClientCursor > query( int minA, int minB, int maxA, int maxB, const BSONObj &hint ) {
|
||||
|
@ -250,6 +250,7 @@
|
||||
93B4A8290F1C024C000C862C /* cursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cursor.cpp; sourceTree = "<group>"; };
|
||||
93B4A82A0F1C0256000C862C /* pdfiletests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pdfiletests.cpp; sourceTree = "<group>"; };
|
||||
93C38E940FA66622007D6E4A /* basictests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = basictests.cpp; sourceTree = "<group>"; };
|
||||
93C392D00FAA4162007D6E4A /* minmax.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = minmax.js; sourceTree = "<group>"; };
|
||||
93CCC87F0F8562E900E20FA0 /* datasize.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = datasize.js; sourceTree = "<group>"; };
|
||||
93D0C1520EF1D377005253B7 /* jsobjtests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsobjtests.cpp; sourceTree = "<group>"; };
|
||||
93D0C1FB0EF1E267005253B7 /* namespacetests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = namespacetests.cpp; sourceTree = "<group>"; };
|
||||
@ -547,6 +548,7 @@
|
||||
93A8D1D10F37544800C92B85 /* jstests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
93C392D00FAA4162007D6E4A /* minmax.js */,
|
||||
9343373F0F9CD6900019D5C0 /* index8.js */,
|
||||
93AE6FB10F9631A200857F1C /* disk */,
|
||||
93DCDB5B0F93ED98005349BC /* nin.js */,
|
||||
|
@ -140,6 +140,17 @@ DBQuery.prototype.hint = function( hint ){
|
||||
return this;
|
||||
}
|
||||
|
||||
DBQuery.prototype.min = function( min ) {
|
||||
this._ensureSpecial();
|
||||
this._query["$min"] = min;
|
||||
return this;
|
||||
}
|
||||
|
||||
DBQuery.prototype.max = function( max ) {
|
||||
this._ensureSpecial();
|
||||
this._query["$max"] = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
DBQuery.prototype.forEach = function( func ){
|
||||
while ( this.hasNext() )
|
||||
|
Loading…
Reference in New Issue
Block a user