diff --git a/dbtests/jstests.cpp b/dbtests/jstests.cpp index c89104ff144..599d2a7ec41 100644 --- a/dbtests/jstests.cpp +++ b/dbtests/jstests.cpp @@ -521,7 +521,7 @@ namespace JSTests { Scope * s = globalScriptEngine->newScope(); s->localConnect( "blah" ); BSONObjBuilder b; - long long val = (long long)( 0xdeadbeefbaddULL ); + long long val = (long long)( 0xbabadeadbeefbaddULL ); b.append( "a", val ); BSONObj in = b.obj(); s->setObject( "a", in ); diff --git a/scripting/engine_spidermonkey.cpp b/scripting/engine_spidermonkey.cpp index 09906b3ba4d..ecba2cdf449 100644 --- a/scripting/engine_spidermonkey.cpp +++ b/scripting/engine_spidermonkey.cpp @@ -162,7 +162,7 @@ namespace mongo { long long toNumberLongUnsafe( JSObject *o ) { unsigned long long val = ( (unsigned long long)( getNumber( o , "top" ) ) << 32 ) + - ( unsigned long long )( getNumber( o , "bottom" ) ); + ( unsigned )( getNumber( o , "bottom" ) ); return val; } diff --git a/scripting/v8_db.cpp b/scripting/v8_db.cpp index 6d859d4f0d1..a24d008380c 100644 --- a/scripting/v8_db.cpp +++ b/scripting/v8_db.cpp @@ -49,6 +49,17 @@ namespace mongo { return mongo; } + v8::Handle getNumberLongFunctionTemplate() { + v8::Local numberLong = FunctionTemplate::New( numberLongInit ); + v8::Local proto = numberLong->PrototypeTemplate(); + + proto->Set( v8::String::New( "toString" ) , FunctionTemplate::New( numberLongToString ) ); + proto->Set( v8::String::New( "toNumber" ) , FunctionTemplate::New( numberLongToNumber ) ); + + return numberLong; + } + + void installDBTypes( Handle& global ){ v8::Local db = FunctionTemplate::New( dbInit ); db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); @@ -71,6 +82,8 @@ namespace mongo { global->Set( v8::String::New("BinData") , FunctionTemplate::New( binDataInit ) ); + global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate() ); + } void installDBTypes( Handle& global ){ @@ -95,6 +108,8 @@ namespace mongo { global->Set( v8::String::New("BinData") , FunctionTemplate::New( binDataInit )->GetFunction() ); + global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate()->GetFunction() ); + BSONObjBuilder b; b.appendMaxKey( "" ); b.appendMinKey( "" ); @@ -531,6 +546,59 @@ namespace mongo { return it; } + v8::Handle numberLongInit( const v8::Arguments& args ) { + + if (args.Length() != 2) { + return v8::ThrowException( v8::String::New( "NumberLong needs 2 arguments" ) ); + } + + v8::Handle it = args.This(); + + if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){ + v8::Function* f = getNamedCons( "NumberLong" ); + it = f->NewInstance(); + } + + it->Set( v8::String::New( "top" ) , args[0] ); + it->Set( v8::String::New( "bottom" ) , args[1] ); + it->SetHiddenValue( v8::String::New( "__NumberLong" ), v8::Number::New( 1 ) ); + + return it; + } + + v8::Handle numberLongToString( const v8::Arguments& args ) { + + if (args.Length() != 0) { + return v8::ThrowException( v8::String::New( "toString needs 0 arguments" ) ); + } + + v8::Handle it = args.This(); + + unsigned long long val = + ( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) + + (unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() ); + + stringstream ss; + ss << (long long)val; + string ret = ss.str(); + return v8::String::New( ret.c_str() ); + } + + v8::Handle numberLongToNumber( const v8::Arguments& args ) { + + if (args.Length() != 0) { + return v8::ThrowException( v8::String::New( "toNumber needs 0 arguments" ) ); + } + + v8::Handle it = args.This(); + + unsigned long long val = + ( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) + + (unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() ); + + return v8::Number::New( double( (long long)val ) ); + } + v8::Handle bsonsize( const v8::Arguments& args ) { if (args.Length() != 1 || !args[ 0 ]->IsObject()) { diff --git a/scripting/v8_db.h b/scripting/v8_db.h index c3f2ef17478..860593e33b7 100644 --- a/scripting/v8_db.h +++ b/scripting/v8_db.h @@ -60,6 +60,9 @@ namespace mongo { v8::Handle dbPointerInit( const v8::Arguments& args ); v8::Handle binDataInit( const v8::Arguments& args ); + v8::Handle numberLongInit( const v8::Arguments& args ); + v8::Handle numberLongToString(const v8::Arguments& args); + v8::Handle numberLongToNumber(const v8::Arguments& args); v8::Handle dbQueryInit( const v8::Arguments& args ); v8::Handle dbQueryIndexAccess( uint32_t index , const v8::AccessorInfo& info ); diff --git a/scripting/v8_wrapper.cpp b/scripting/v8_wrapper.cpp index 29a70ba74e5..24ff1778acb 100644 --- a/scripting/v8_wrapper.cpp +++ b/scripting/v8_wrapper.cpp @@ -149,7 +149,6 @@ namespace mongo { case mongo::NumberDouble: case mongo::NumberInt: - case mongo::NumberLong: // may lose information here - just copying sm engine behavior o->Set( v8::String::New( f.fieldName() ) , v8::Number::New( f.number() ) ); break; @@ -208,6 +207,17 @@ namespace mongo { break; } + case mongo::NumberLong: { + Local sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance(); + unsigned long long val = f.numberLong(); + v8::Function* numberLong = getNamedCons( "NumberLong" ); + v8::Handle argv[2]; + argv[0] = v8::Integer::New( val >> 32 ); + argv[1] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) ); + o->Set( v8::String::New( f.fieldName() ), numberLong->NewInstance(2, argv) ); + break; + } + case mongo::MinKey: { Local sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance(); sub->Set( v8::String::New( "$MinKey" ), v8::Boolean::New( true ) ); @@ -325,6 +335,16 @@ namespace mongo { return sub; } + + case mongo::NumberLong: { + Local sub = internalFieldObjects->NewInstance(); + unsigned long long val = f.numberLong(); + v8::Function* numberLong = getNamedCons( "NumberLong" ); + v8::Handle argv[2]; + argv[0] = v8::Integer::New( val >> 32 ); + argv[1] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) ); + return numberLong->NewInstance( 2, argv ); + } case mongo::MinKey: { Local sub = internalFieldObjects->NewInstance(); @@ -431,10 +451,16 @@ namespace mongo { oid.init( toSTLString( value ) ); b.appendOID( sname.c_str() , &oid ); } - else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__DBPointer" ) ).IsEmpty() ) { + else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__NumberLong" ) ).IsEmpty() ) { // TODO might be nice to potentially speed this up with an indexed internal // field, but I don't yet know how to use an ObjectTemplate with a // constructor. + unsigned long long val = + ( (unsigned long long)( value->ToObject()->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) + + (unsigned)( value->ToObject()->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() ); + b.append( sname.c_str(), (long long)val ); + } + else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__DBPointer" ) ).IsEmpty() ) { OID oid; oid.init( toSTLString( value->ToObject()->Get( v8::String::New( "id" ) ) ) ); string ns = toSTLString( value->ToObject()->Get( v8::String::New( "ns" ) ) );