summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--db/update.cpp15
-rw-r--r--dbtests/updatetests.cpp15
-rw-r--r--jstests/inc1.js32
-rw-r--r--jstests/inc2.js22
-rw-r--r--jstests/update2.js2
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();