Skip to content

Commit

Permalink
start work on bit operators SERVER-503
Browse files Browse the repository at this point in the history
only ugly syntax works and not idempotent yet
  • Loading branch information
erh committed Dec 21, 2009
1 parent a9ba768 commit 62a4aef
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 12 deletions.
41 changes: 41 additions & 0 deletions db/update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,48 @@ namespace mongo {
bb.done();
break;
}

case BIT: {
uassert( "$bit needs an array" , elt.type() == Object );
uassert( "$bit can only be applied to numbers" , in.isNumber() );
uassert( "$bit can't use a double" , in.type() != NumberDouble );

int x = in.numberInt();
long long y = in.numberLong();

BSONObjIterator it( elt.embeddedObject() );
while ( it.more() ){
BSONElement e = it.next();
uassert( "$bit field must be number" , e.isNumber() );
if ( strcmp( e.fieldName() , "and" ) == 0 ){
switch( in.type() ){
case NumberInt: x = x&e.numberInt(); break;
case NumberLong: y = y&e.numberLong(); break;
default: assert( 0 );
}
}
else if ( strcmp( e.fieldName() , "or" ) == 0 ){
switch( in.type() ){
case NumberInt: x = x|e.numberInt(); break;
case NumberLong: y = y|e.numberLong(); break;
default: assert( 0 );
}
}

else {
throw UserException( (string)"unknown bit mod:" + e.fieldName() );
}
}

switch( in.type() ){
case NumberInt: b.append( shortFieldName , x ); break;
case NumberLong: b.append( shortFieldName , y ); break;
default: assert( 0 );
}

break;
}

default:
stringstream ss;
ss << "Mod::apply can't handle type: " << op;
Expand Down
8 changes: 5 additions & 3 deletions db/update.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ namespace mongo {
/* Used for modifiers such as $inc, $set, ... */
struct Mod {
// See opFromStr below
// 0 1 2 3 4 5 6 7
enum Op { INC, SET, PUSH, PUSH_ALL, PULL, PULL_ALL , POP, UNSET} op;
// 0 1 2 3 4 5 6 7 8 9 10
enum Op { INC, SET, PUSH, PUSH_ALL, PULL, PULL_ALL , POP, UNSET, BITAND, BITOR , BIT } op;
const char *fieldName;
const char *shortFieldName;

Expand Down Expand Up @@ -197,10 +197,12 @@ namespace mongo {
return true;
}
static Mod::Op opFromStr( const char *fn ) {
const char *valid[] = { "$inc", "$set", "$push", "$pushAll", "$pull", "$pullAll" , "$pop", "$unset" };
const char *valid[] = { "$inc", "$set", "$push", "$pushAll", "$pull", "$pullAll" , "$pop", "$unset" ,
"$bitand" , "$bitor" , "$bit" };
for( unsigned i = 0; i < (sizeof(valid) / sizeof(*valid)); ++i )
if ( strcmp( fn, valid[ i ] ) == 0 )
return Mod::Op( i );

uassert( "Invalid modifier specified " + string( fn ), false );
return Mod::INC;
}
Expand Down
66 changes: 57 additions & 9 deletions dbtests/updatetests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -604,28 +604,51 @@ namespace UpdateTests {

namespace basic {
class Base : public ClientBase {
virtual BSONObj initial() = 0;
virtual BSONObj mod() = 0;
virtual BSONObj after() = 0;
virtual const char * ns() = 0;
virtual void dotest() = 0;

protected:

void test( const char* initial , const char* mod , const char* after ){
test( fromjson( initial ) , fromjson( mod ) , fromjson( after ) );
}


void test( const BSONObj& initial , const BSONObj& mod , const BSONObj& after ){
client().dropCollection( ns() );
client().insert( ns() , initial );
client().update( ns() , BSONObj() , mod );
ASSERT_EQUALS( after , client().findOne( ns(), BSONObj() ));
client().dropCollection( ns() );
}

public:

Base(){}
virtual ~Base(){}
virtual ~Base(){
}

void run(){
client().dropCollection( ns() );

client().insert( ns() , initial() );
client().update( ns() , BSONObj() , mod() );
ASSERT_EQUALS( after() , client().findOne( ns(), BSONObj() ));
dotest();

client().dropCollection( ns() );
}
};

class SingleTest : public Base {
virtual BSONObj initial() = 0;
virtual BSONObj mod() = 0;
virtual BSONObj after() = 0;

void dotest(){
test( initial() , mod() , after() );
}

};

class inc1 : public Base {
class inc1 : public SingleTest {
virtual BSONObj initial(){
return BSON( "_id" << 1 << "x" << 1 );
}
Expand All @@ -641,6 +664,29 @@ namespace UpdateTests {

};

class bit1 : public Base {
const char * ns(){
return "unittests.bit1";
}
void dotest(){
test( BSON( "_id" << 1 << "x" << 3 ) , BSON( "$bit" << BSON( "x" << BSON( "and" << 2 ) ) ) , BSON( "_id" << 1 << "x" << ( 3 & 2 ) ) );
test( BSON( "_id" << 1 << "x" << 1 ) , BSON( "$bit" << BSON( "x" << BSON( "or" << 4 ) ) ) , BSON( "_id" << 1 << "x" << ( 1 | 4 ) ) );
test( BSON( "_id" << 1 << "x" << 3 ) , BSON( "$bit" << BSON( "x" << BSON( "and" << 2 << "or" << 8 ) ) ) , BSON( "_id" << 1 << "x" << ( ( 3 & 2 ) | 8 ) ) );
test( BSON( "_id" << 1 << "x" << 3 ) , BSON( "$bit" << BSON( "x" << BSON( "or" << 2 << "and" << 8 ) ) ) , BSON( "_id" << 1 << "x" << ( ( 3 | 2 ) & 8 ) ) );

}
};

class unset : public Base {
const char * ns(){
return "unittests.unset";
}
void dotest(){
test( "{_id:1,x:1}" , "{$unset:{x:1}}" , "{_id:1}" );
}
};


};

class All : public Suite {
Expand Down Expand Up @@ -702,8 +748,10 @@ namespace UpdateTests {
add< ModSetTests::inc2 >();
add< ModSetTests::set1 >();
add< ModSetTests::push1 >();

add< basic::inc1 >();
add< basic::bit1 >();
add< basic::unset >();
}
} myall;

Expand Down

0 comments on commit 62a4aef

Please sign in to comment.