diff options
-rw-r--r-- | db/update.cpp | 15 | ||||
-rw-r--r-- | dbtests/updatetests.cpp | 15 | ||||
-rw-r--r-- | jstests/inc1.js | 32 | ||||
-rw-r--r-- | jstests/inc2.js | 22 | ||||
-rw-r--r-- | jstests/update2.js | 2 |
5 files changed, 71 insertions, 15 deletions
diff --git a/db/update.cpp b/db/update.cpp index f220685afed..e11ef356b86 100644 --- a/db/update.cpp +++ b/db/update.cpp @@ -218,22 +218,22 @@ namespace mongo { bool applyModsInPlace( const BSONObj &obj ) const; BSONObj createNewFromMods( const BSONObj &obj ); - void checkUnindexed( const set<string>& idxKeys ) const { + bool isIndexed( const set<string>& idxKeys ) const { for ( vector<Mod>::const_iterator i = _mods.begin(); i != _mods.end(); i++ ) { // check if there is an index key that is a parent of mod for( const char *dot = strchr( i->fieldName, '.' ); dot; dot = strchr( dot + 1, '.' ) ) if ( idxKeys.count( string( i->fieldName, dot - i->fieldName ) ) ) - uassert("E12010 can't $inc/$set an indexed field ", false); + return true; string fullName = i->fieldName; // check if there is an index key equal to mod if ( idxKeys.count(fullName) ) - uassert("E12011 can't $inc/$set an indexed field", false); + return true; // check if there is an index key that is a child of mod set< string >::const_iterator j = idxKeys.upper_bound( fullName ); - if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[fullName.size()] == '.' ){ - uassert("E12012 can't $inc/$set an indexed field", false); - } + if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[fullName.size()] == '.' ) + return true; } + return false; } unsigned size() const { return _mods.size(); } @@ -698,8 +698,7 @@ namespace mongo { mods.getMods(updateobj); NamespaceDetailsTransient& ndt = NamespaceDetailsTransient::get(ns); set<string>& idxKeys = ndt.indexKeys(); - mods.checkUnindexed( idxKeys ); - if ( mods.applyModsInPlace( c->currLoc().obj() ) ) { + if ( ! mods.isIndexed( idxKeys ) && mods.applyModsInPlace( c->currLoc().obj() ) ) { if ( profile ) ss << " fastmod "; } else { diff --git a/dbtests/updatetests.cpp b/dbtests/updatetests.cpp index 9990f930291..24326f1b7ee 100644 --- a/dbtests/updatetests.cpp +++ b/dbtests/updatetests.cpp @@ -439,20 +439,23 @@ namespace UpdateTests { client().ensureIndex( ns(), BSON( "a" << 1 ) ); client().insert( ns(), fromjson( "{'_id':0}" ) ); client().update( ns(), Query(), fromjson( "{$set:{'a.b':4}}" ) ); - ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0}" ) ) == 0 ); + ASSERT_EQUALS( fromjson( "{'_id':0,a:{b:4}}" ) , client().findOne( ns(), Query() ) ); + ASSERT_EQUALS( fromjson( "{'_id':0,a:{b:4}}" ) , client().findOne( ns(), fromjson( "{'a.b':4}" ) ) ); // make sure the index works } }; - class ModParentOfIndex : public SetBase { + class IndexModSet : public SetBase { public: void run() { client().ensureIndex( ns(), BSON( "a.b" << 1 ) ); - client().insert( ns(), fromjson( "{'_id':0}" ) ); - client().update( ns(), Query(), fromjson( "{$set:{'a':4}}" ) ); - ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0}" ) ) == 0 ); + client().insert( ns(), fromjson( "{'_id':0,a:{b:3}}" ) ); + client().update( ns(), Query(), fromjson( "{$set:{'a.b':4}}" ) ); + ASSERT_EQUALS( fromjson( "{'_id':0,a:{b:4}}" ) , client().findOne( ns(), Query() ) ); + ASSERT_EQUALS( fromjson( "{'_id':0,a:{b:4}}" ) , client().findOne( ns(), fromjson( "{'a.b':4}" ) ) ); // make sure the index works } }; + class PreserveIdWithIndex : public SetBase { // Not using $set, but base class is still useful public: void run() { @@ -528,7 +531,7 @@ namespace UpdateTests { add< DontDropEmpty >(); add< InsertInEmpty >(); add< IndexParentOfMod >(); - add< ModParentOfIndex >(); + add< IndexModSet >(); add< PreserveIdWithIndex >(); add< CheckNoMods >(); add< UpdateMissingToNull >(); diff --git a/jstests/inc1.js b/jstests/inc1.js new file mode 100644 index 00000000000..027f307a476 --- /dev/null +++ b/jstests/inc1.js @@ -0,0 +1,32 @@ + +t = db.inc1; +t.drop(); + +function test( num , name ){ + assert.eq( 1 , t.count() , name + " count" ); + assert.eq( num , t.findOne().x , name + " value" ); +} + +t.save( { _id : 1 , x : 1 } ); +test( 1 , "A" ); + +t.update( { _id : 1 } , { $inc : { x : 1 } } ); +test( 2 , "B" ); + +t.update( { _id : 1 } , { $inc : { x : 1 } } ); +test( 3 , "C" ); + +t.update( { _id : 2 } , { $inc : { x : 1 } } ); +test( 3 , "D" ); + +t.update( { _id : 1 } , { $inc : { x : 2 } } ); +test( 5 , "E" ); + +t.update( { _id : 1 } , { $inc : { x : -1 } } ); +test( 4 , "F" ); + +t.ensureIndex( { x : 1 } ); + +t.update( { _id : 1 } , { $inc : { x : 1 } } ); +test( 5 , "G" ); + diff --git a/jstests/inc2.js b/jstests/inc2.js new file mode 100644 index 00000000000..8442f1494df --- /dev/null +++ b/jstests/inc2.js @@ -0,0 +1,22 @@ + +t = db.inc1 +t.drop(); + +t.save( { _id : 1 , x : 1 } ); +t.save( { _id : 2 , x : 2 } ); +t.save( { _id : 3 , x : 3 } ); + +function order(){ + return t.find().sort( { x : 1 } ).map( function(z){ return z._id; } ); +} + +assert.eq( "1,2,3" , order() , "A" ); + +t.update( { _id : 1 } , { $inc : { x : 4 } } ); +assert.eq( "2,3,1" , order() , "B" ); + +t.ensureIndex( { x : 1 } ); +assert.eq( "2,3,1" , order() , "C" ); + +t.update( { _id : 3 } , { $inc : { x : 4 } } ); +assert.eq( "2,1,3" , order() , "D" ); diff --git a/jstests/update2.js b/jstests/update2.js index ff9783348d4..654914c1f45 100644 --- a/jstests/update2.js +++ b/jstests/update2.js @@ -9,7 +9,7 @@ f.drop(); f.save( { a: 4 } ); f.ensureIndex( { a: 1 } ); f.update( { a: 4 }, { $inc: { a: 2 } } ); -assert.eq( 4, f.findOne().a ); +assert.eq( 6, f.findOne().a ); // Verify that drop clears the index f.drop(); |