Permalink
Browse files

SERVER-3222 min and max for type cleaning and fixes

  • Loading branch information...
1 parent 473a982 commit 4de924a3d9f49181015e2e819afe0bedb3224cb7 @astaple astaple committed Jun 21, 2011
Showing with 229 additions and 45 deletions.
  1. +71 −40 db/jsobj.cpp
  2. +4 −5 dbtests/jsobjtests.cpp
  3. +86 −0 dbtests/querytests.cpp
  4. +68 −0 jstests/type3.js
View
@@ -1101,83 +1101,114 @@ namespace mongo {
void BSONObjBuilder::appendMinForType( const StringData& fieldName , int t ) {
switch ( t ) {
- case MinKey: appendMinKey( fieldName ); return;
- case MaxKey: appendMinKey( fieldName ); return;
+
+ // Shared canonical types
case NumberInt:
case NumberDouble:
case NumberLong:
append( fieldName , - numeric_limits<double>::max() ); return;
+ case Symbol:
+ case String:
+ append( fieldName , "" ); return;
+ case Date:
+ // min varies with V0 and V1 indexes, so we go one type lower.
+ appendBool(fieldName, true);
+ //appendDate( fieldName , numeric_limits<long long>::min() );
+ return;
+ case Timestamp: // TODO integrate with Date SERVER-3304
+ appendTimestamp( fieldName , 0 ); return;
+ case Undefined: // shared with EOO
+ appendUndefined( fieldName ); return;
+
+ // Separate canonical types
+ case MinKey:
+ appendMinKey( fieldName ); return;
+ case MaxKey:
+ appendMaxKey( fieldName ); return;
case jstOID: {
OID o;
memset(&o, 0, sizeof(o));
appendOID( fieldName , &o);
return;
}
- case Bool: appendBool( fieldName , false); return;
- case Date:
- // min varies with V0 and V1 indexes, so we go one type lower.
- appendBool(fieldName, true);
- //appendDate( fieldName , numeric_limits<long long>::min() );
- return;
- case jstNULL: appendNull( fieldName ); return;
- case Symbol:
- case String: append( fieldName , "" ); return;
- case Object: append( fieldName , BSONObj() ); return;
+ case Bool:
+ appendBool( fieldName , false); return;
+ case jstNULL:
+ appendNull( fieldName ); return;
+ case Object:
+ append( fieldName , BSONObj() ); return;
case Array:
appendArray( fieldName , BSONObj() ); return;
case BinData:
- appendBinData( fieldName , 0 , Function , (const char *) 0 ); return;
- case Undefined:
- appendUndefined( fieldName ); return;
- case RegEx: appendRegex( fieldName , "" ); return;
+ appendBinData( fieldName , 0 , BinDataGeneral , (const char *) 0 ); return;
+ case RegEx:
+ appendRegex( fieldName , "" ); return;
case DBRef: {
OID o;
memset(&o, 0, sizeof(o));
appendDBRef( fieldName , "" , o );
return;
}
- case Code: appendCode( fieldName , "" ); return;
- case CodeWScope: appendCodeWScope( fieldName , "" , BSONObj() ); return;
- case Timestamp: appendTimestamp( fieldName , 0); return;
-
+ case Code:
+ appendCode( fieldName , "" ); return;
+ case CodeWScope:
+ appendCodeWScope( fieldName , "" , BSONObj() ); return;
};
- log() << "type not support for appendMinElementForType: " << t << endl;
+ log() << "type not supported for appendMinElementForType: " << t << endl;
uassert( 10061 , "type not supported for appendMinElementForType" , false );
}
void BSONObjBuilder::appendMaxForType( const StringData& fieldName , int t ) {
switch ( t ) {
- case MinKey: appendMaxKey( fieldName ); break;
- case MaxKey: appendMaxKey( fieldName ); break;
+
+ // Shared canonical types
case NumberInt:
case NumberDouble:
case NumberLong:
- append( fieldName , numeric_limits<double>::max() );
- break;
- case BinData:
- appendMinForType( fieldName , jstOID );
- break;
+ append( fieldName , numeric_limits<double>::max() ); return;
+ case Symbol:
+ case String:
+ appendMinForType( fieldName, Object ); return;
+ case Date:
+ appendDate( fieldName , numeric_limits<long long>::max() ); return;
+ case Timestamp: // TODO integrate with Date SERVER-3304
+ appendTimestamp( fieldName , numeric_limits<unsigned long long>::max() ); return;
+ case Undefined: // shared with EOO
+ appendUndefined( fieldName ); return;
+
+ // Separate canonical types
+ case MinKey:
+ appendMinKey( fieldName ); return;
+ case MaxKey:
+ appendMaxKey( fieldName ); return;
case jstOID: {
OID o;
memset(&o, 0xFF, sizeof(o));
appendOID( fieldName , &o);
- break;
+ return;
}
- case Undefined:
+ case Bool:
+ appendBool( fieldName , true ); return;
case jstNULL:
- appendMinForType( fieldName , NumberInt );
- case Bool: appendBool( fieldName , true); break;
- case Date: appendDate( fieldName , numeric_limits<long long>::max() ); break;
- case Symbol:
- case String: append( fieldName , BSONObj() ); break;
+ appendNull( fieldName ); return;
+ case Object:
+ appendMinForType( fieldName, Array ); return;
+ case Array:
+ appendMinForType( fieldName, BinData ); return;
+ case BinData:
+ appendMinForType( fieldName, jstOID ); return;
+ case RegEx:
+ appendMinForType( fieldName, DBRef ); return;
+ case DBRef:
+ appendMinForType( fieldName, Code ); return;
case Code:
+ appendMinForType( fieldName, CodeWScope ); return;
case CodeWScope:
- appendCodeWScope( fieldName , "ZZZ" , BSONObj() ); break;
- case Timestamp:
- appendTimestamp( fieldName , numeric_limits<unsigned long long>::max() ); break;
- default:
- appendMinForType( fieldName , t + 1 );
+ // This upper bound may change if a new bson type is added.
+ appendMinForType( fieldName , MaxKey ); return;
}
+ log() << "type not supported for appendMaxElementForType: " << t << endl;
+ uassert( 14836 , "type not supported for appendMaxElementForType" , false );
}
const string BSONObjBuilder::numStrs[] = {
View
@@ -1298,11 +1298,10 @@ namespace JsobjTests {
stringstream ss;
ss << "type: " << t;
string s = ss.str();
- massert( 10403 , s , min( t ).woCompare( max( t ) ) < 0 );
- massert( 10404 , s , max( t ).woCompare( min( t ) ) > 0 );
- massert( 10405 , s , min( t ).woCompare( min( t ) ) == 0 );
- massert( 10406 , s , max( t ).woCompare( max( t ) ) == 0 );
- massert( 10407 , s , abs( min( t ).firstElement().canonicalType() - max( t ).firstElement().canonicalType() ) <= 10 );
+ ASSERT( min( t ).woCompare( max( t ) ) <= 0 );
+ ASSERT( max( t ).woCompare( min( t ) ) >= 0 );
+ ASSERT( min( t ).woCompare( min( t ) ) == 0 );
+ ASSERT( max( t ).woCompare( max( t ) ) == 0 );
}
}
};
View
@@ -732,6 +732,90 @@ namespace QueryTests {
};
BSONObj MinMax::empty_;
+ class MatchCodeCodeWScope : public ClientBase {
+ public:
+ MatchCodeCodeWScope() : _ns( "unittests.querytests.MatchCodeCodeWScope" ) {}
+ ~MatchCodeCodeWScope() {
+ client().dropCollection( "unittests.querytests.MatchCodeCodeWScope" );
+ }
+ void run() {
+ checkMatch();
+ client().ensureIndex( _ns, BSON( "a" << 1 ) );
+ checkMatch();
+ // Use explain queries to check index bounds.
+ {
+ BSONObj explain = client().findOne( _ns, QUERY( "a" << BSON( "$type" << (int)Code ) ).explain() );
+ BSONObjBuilder lower;
+ lower.appendCode( "", "" );
+ BSONObjBuilder upper;
+ upper.appendCodeWScope( "", "", BSONObj() );
+ ASSERT( lower.done().firstElement().valuesEqual( explain[ "indexBounds" ].Obj()[ "a" ].Array()[ 0 ].Array()[ 0 ] ) );
+ ASSERT( upper.done().firstElement().valuesEqual( explain[ "indexBounds" ].Obj()[ "a" ].Array()[ 0 ].Array()[ 1 ] ) );
+ }
+ {
+ BSONObj explain = client().findOne( _ns, QUERY( "a" << BSON( "$type" << (int)CodeWScope ) ).explain() );
+ BSONObjBuilder lower;
+ lower.appendCodeWScope( "", "", BSONObj() );
+ // This upper bound may change if a new bson type is added.
+ BSONObjBuilder upper;
+ upper << "" << BSON( "$maxElement" << 1 );
+ ASSERT( lower.done().firstElement().valuesEqual( explain[ "indexBounds" ].Obj()[ "a" ].Array()[ 0 ].Array()[ 0 ] ) );
+ ASSERT( upper.done().firstElement().valuesEqual( explain[ "indexBounds" ].Obj()[ "a" ].Array()[ 0 ].Array()[ 1 ] ) );
+ }
+ }
+ private:
+ void checkMatch() {
+ client().remove( _ns, BSONObj() );
+
+ client().insert( _ns, code() );
+ client().insert( _ns, codeWScope() );
+
+ ASSERT_EQUALS( 1U, client().count( _ns, code() ) );
+ ASSERT_EQUALS( 1U, client().count( _ns, codeWScope() ) );
+
+ ASSERT_EQUALS( 1U, client().count( _ns, BSON( "a" << BSON( "$type" << (int)Code ) ) ) );
+ ASSERT_EQUALS( 1U, client().count( _ns, BSON( "a" << BSON( "$type" << (int)CodeWScope ) ) ) );
+ }
+ BSONObj code() const {
+ BSONObjBuilder codeBuilder;
+ codeBuilder.appendCode( "a", "return 1;" );
+ return codeBuilder.obj();
+ }
+ BSONObj codeWScope() const {
+ BSONObjBuilder codeWScopeBuilder;
+ codeWScopeBuilder.appendCodeWScope( "a", "return 1;", BSONObj() );
+ return codeWScopeBuilder.obj();
+ }
+ const char *_ns;
+ };
+
+ class MatchDBRefType : public ClientBase {
+ public:
+ MatchDBRefType() : _ns( "unittests.querytests.MatchDBRefType" ) {}
+ ~MatchDBRefType() {
+ client().dropCollection( "unittests.querytests.MatchDBRefType" );
+ }
+ void run() {
+ checkMatch();
+ client().ensureIndex( _ns, BSON( "a" << 1 ) );
+ checkMatch();
+ }
+ private:
+ void checkMatch() {
+ client().remove( _ns, BSONObj() );
+ client().insert( _ns, dbref() );
+ ASSERT_EQUALS( 1U, client().count( _ns, dbref() ) );
+ ASSERT_EQUALS( 1U, client().count( _ns, BSON( "a" << BSON( "$type" << (int)DBRef ) ) ) );
+ }
+ BSONObj dbref() const {
+ BSONObjBuilder b;
+ OID oid;
+ b.appendDBRef( "a", "ns", oid );
+ return b.obj();
+ }
+ const char *_ns;
+ };
+
class DirectLocking : public ClientBase {
public:
void run() {
@@ -1265,6 +1349,8 @@ namespace QueryTests {
add< IndexInsideArrayCorrect >();
add< SubobjArr >();
add< MinMax >();
+ add< MatchCodeCodeWScope >();
+ add< MatchDBRefType >();
add< DirectLocking >();
add< FastCountIn >();
add< EmbeddedArray >();
View
@@ -0,0 +1,68 @@
+// Check query type bracketing SERVER-3222
+
+t = db.jstests_type3;
+t.drop();
+
+t.ensureIndex( {a:1} );
+
+// Type Object
+t.save( {a:{'':''}} );
+assert.eq( 1, t.find( {a:{$type:3}} ).hint( {a:1} ).itcount() );
+
+// Type Array
+t.remove();
+t.save( {a:[['c']]} );
+assert.eq( 1, t.find( {a:{$type:4}} ).hint( {a:1} ).itcount() );
+
+// Type RegEx
+t.remove();
+t.save( {a:/r/} );
+assert.eq( 1, t.find( {a:{$type:11}} ).hint( {a:1} ).itcount() );
+
+// Type jstNULL
+t.remove();
+assert.eq( [[null,null]], t.find( {a:{$type:10}} ).hint( {a:1} ).explain().indexBounds.a );
+
+// Type Undefined
+t.remove();
+// 'null' is the client friendly version of undefined.
+assert.eq( [[null,null]], t.find( {a:{$type:6}} ).hint( {a:1} ).explain().indexBounds.a );
+
+t.save( {a:undefined} );
+assert.eq( 1, t.find( {a:{$type:6}} ).hint( {a:1} ).itcount() );
+
+// This one won't be returned.
+t.save( {a:null} );
+assert.eq( 1, t.find( {a:{$type:6}} ).hint( {a:1} ).itcount() );
+
+t.remove();
+// Type MinKey
+assert.eq( [[{$minElement:1},{$minElement:1}]], t.find( {a:{$type:-1}} ).hint( {a:1} ).explain().indexBounds.a );
+// Type MaxKey
+assert.eq( [[{$maxElement:1},{$maxElement:1}]], t.find( {a:{$type:127}} ).hint( {a:1} ).explain().indexBounds.a );
+
+// Type Timestamp
+t.remove();
+t.save( {a:new Timestamp()} );
+assert.eq( 1, t.find( {a:{$type:17}} ).itcount() );
+if ( 0 ) { // SERVER-3304
+assert.eq( 0, t.find( {a:{$type:9}} ).itcount() );
+}
+
+// Type Date
+t.remove();
+t.save( {a:new Date()} );
+if ( 0 ) { // SERVER-3304
+assert.eq( 0, t.find( {a:{$type:17}} ).itcount() );
+}
+assert.eq( 1, t.find( {a:{$type:9}} ).itcount() );
+
+// Type Code
+t.remove();
+t.save( {a:function(){var a = 0;}} );
+assert.eq( 1, t.find( {a:{$type:13}} ).itcount() );
+
+// Type BinData
+t.remove();
+t.save( {a:new BinData(0,'')} );
+assert.eq( 1, t.find( {a:{$type:5}} ).itcount() );

0 comments on commit 4de924a

Please sign in to comment.