diff options
author | Antonin Kral <a.kral@bobek.cz> | 2010-08-11 12:38:57 +0200 |
---|---|---|
committer | Antonin Kral <a.kral@bobek.cz> | 2010-08-11 12:38:57 +0200 |
commit | 7645618fd3914cb8a20561625913c20d49504a49 (patch) | |
tree | 8370f846f58f6d71165b7a0e2eda04648584ec76 /scripting | |
parent | 68c73c3c7608b4c87f07440dc3232801720b1168 (diff) | |
download | mongodb-7645618fd3914cb8a20561625913c20d49504a49.tar.gz |
Imported Upstream version 1.6.0
Diffstat (limited to 'scripting')
-rw-r--r-- | scripting/engine.cpp | 24 | ||||
-rw-r--r-- | scripting/engine.h | 4 | ||||
-rw-r--r-- | scripting/engine_java.cpp | 2 | ||||
-rw-r--r-- | scripting/engine_java.h | 3 | ||||
-rw-r--r-- | scripting/engine_spidermonkey.cpp | 237 | ||||
-rw-r--r-- | scripting/engine_spidermonkey.h | 2 | ||||
-rw-r--r-- | scripting/engine_v8.cpp | 10 | ||||
-rw-r--r-- | scripting/sm_db.cpp | 254 | ||||
-rw-r--r-- | scripting/utils.cpp | 3 | ||||
-rw-r--r-- | scripting/v8_db.cpp | 148 | ||||
-rw-r--r-- | scripting/v8_db.h | 1 | ||||
-rw-r--r-- | scripting/v8_utils.cpp | 7 | ||||
-rw-r--r-- | scripting/v8_utils.h | 1 | ||||
-rw-r--r-- | scripting/v8_wrapper.cpp | 40 |
14 files changed, 524 insertions, 212 deletions
diff --git a/scripting/engine.cpp b/scripting/engine.cpp index cc245b6..9e20a3a 100644 --- a/scripting/engine.cpp +++ b/scripting/engine.cpp @@ -15,7 +15,7 @@ * limitations under the License. */ -#include "stdafx.h" +#include "pch.h" #include "engine.h" #include "../util/file.h" #include "../client/dbclient.h" @@ -73,6 +73,9 @@ namespace mongo { // TODO: make signed builder.appendDate( fieldName , Date_t((unsigned long long)getNumber( scopeName )) ); break; + case Code: + builder.appendCode( fieldName , getString( scopeName ).c_str() ); + break; default: stringstream temp; temp << "can't append type from:"; @@ -93,7 +96,7 @@ namespace mongo { path p( filename ); if ( ! exists( p ) ){ - cout << "file [" << filename << "] doesn't exist" << endl; + log() << "file [" << filename << "] doesn't exist" << endl; if ( assertOnError ) assert( 0 ); return false; @@ -113,7 +116,7 @@ namespace mongo { } if (empty){ - cout << "directory [" << filename << "] doesn't have any *.js files" << endl; + log() << "directory [" << filename << "] doesn't have any *.js files" << endl; if ( assertOnError ) assert( 0 ); return false; @@ -167,6 +170,7 @@ namespace mongo { static DBClientBase * db = createDirectClient(); auto_ptr<DBClientCursor> c = db->query( coll , Query() ); + assert( c.get() ); set<string> thisTime; @@ -228,7 +232,7 @@ namespace mongo { class ScopeCache { public: - ScopeCache(){ + ScopeCache() : _mutex("ScopeCache") { _magic = 17; } @@ -421,5 +425,15 @@ namespace mongo { void ( *ScriptEngine::_connectCallback )( DBClientWithCommands & ) = 0; ScriptEngine * globalScriptEngine; + + bool hasJSReturn( const string& code ){ + size_t x = code.find( "return" ); + if ( x == string::npos ) + return false; + + return + ( x == 0 || ! isalpha( code[x-1] ) ) && + ! isalpha( code[x+6] ); + } } -
\ No newline at end of file + diff --git a/scripting/engine.h b/scripting/engine.h index 9907d31..e097401 100644 --- a/scripting/engine.h +++ b/scripting/engine.h @@ -17,7 +17,7 @@ #pragma once -#include "../stdafx.h" +#include "../pch.h" #include "../db/jsobj.h" extern const char * jsconcatcode; // TODO: change name to mongoJSCode @@ -162,5 +162,7 @@ namespace mongo { static void ( *_connectCallback )( DBClientWithCommands & ); }; + bool hasJSReturn( const string& s ); + extern ScriptEngine * globalScriptEngine; } diff --git a/scripting/engine_java.cpp b/scripting/engine_java.cpp index 0ed6f1d..dacf532 100644 --- a/scripting/engine_java.cpp +++ b/scripting/engine_java.cpp @@ -16,7 +16,7 @@ */ -#include "stdafx.h" +#include "pch.h" #include "engine_java.h" #include <iostream> #include <map> diff --git a/scripting/engine_java.h b/scripting/engine_java.h index ae11cc1..5c6bc3b 100644 --- a/scripting/engine_java.h +++ b/scripting/engine_java.h @@ -19,10 +19,9 @@ #pragma once -#include "../stdafx.h" +#include "../pch.h" #include <jni.h> -#include <boost/thread/tss.hpp> #include <errno.h> #include <sys/types.h> diff --git a/scripting/engine_spidermonkey.cpp b/scripting/engine_spidermonkey.cpp index 6609925..22102ba 100644 --- a/scripting/engine_spidermonkey.cpp +++ b/scripting/engine_spidermonkey.cpp @@ -15,15 +15,14 @@ * limitations under the License. */ -#include "stdafx.h" +#include "pch.h" #include "engine_spidermonkey.h" - #include "../client/dbclient.h" #ifndef _WIN32 #include <boost/date_time/posix_time/posix_time.hpp> #undef assert -#define assert xassert +#define assert MONGO_assert #endif #define smuassert( cx , msg , val ) \ @@ -38,6 +37,12 @@ } namespace mongo { + + class InvalidUTF8Exception : public UserException { + public: + InvalidUTF8Exception() : UserException( 9006 , "invalid utf8" ){ + } + }; string trim( string s ){ while ( s.size() && isspace( s[0] ) ) @@ -128,6 +133,54 @@ namespace mongo { return new BSONFieldIterator( this ); } + class TraverseStack { + public: + TraverseStack(){ + _o = 0; + _parent = 0; + } + + TraverseStack( JSObject * o , const TraverseStack * parent ){ + _o = o; + _parent = parent; + } + + TraverseStack dive( JSObject * o ) const { + if ( o ){ + uassert( 13076 , (string)"recursive toObject" , ! has( o ) ); + } + return TraverseStack( o , this ); + } + + int depth() const { + int d = 0; + const TraverseStack * s = _parent; + while ( s ){ + s = s->_parent; + d++; + } + return d; + } + + bool isTop() const { + return _parent == 0; + } + + bool has( JSObject * o ) const { + if ( ! o ) + return false; + const TraverseStack * s = this; + while ( s ){ + if ( s->_o == o ) + return true; + s = s->_parent; + } + return false; + } + + JSObject * _o; + const TraverseStack * _parent; + }; class Convertor : boost::noncopyable { public: @@ -171,7 +224,7 @@ namespace mongo { ( (boost::uint64_t)(boost::uint32_t)getNumber( o , "top" ) << 32 ) + ( boost::uint32_t)( getNumber( o , "bottom" ) ); } else { - val = (boost::uint64_t) getNumber( o, "floatApprox" ); + val = (boost::uint64_t)(boost::int64_t) getNumber( o, "floatApprox" ); } return val; } @@ -198,7 +251,7 @@ namespace mongo { return oid; } - BSONObj toObject( JSObject * o , int depth = 0){ + BSONObj toObject( JSObject * o , const TraverseStack& stack=TraverseStack() ){ if ( ! o ) return BSONObj(); @@ -222,10 +275,10 @@ namespace mongo { if ( ! appendSpecialDBObject( this , b , "value" , OBJECT_TO_JSVAL( o ) , o ) ){ - if ( depth == 0 ){ + if ( stack.isTop() ){ jsval theid = getProperty( o , "_id" ); if ( ! JSVAL_IS_VOID( theid ) ){ - append( b , "_id" , theid , EOO , depth + 1 ); + append( b , "_id" , theid , EOO , stack.dive( o ) ); } } @@ -237,10 +290,10 @@ namespace mongo { jsval nameval; assert( JS_IdToValue( _context ,id , &nameval ) ); string name = toString( nameval ); - if ( depth == 0 && name == "_id" ) + if ( stack.isTop() && name == "_id" ) continue; - append( b , name , getProperty( o , name.c_str() ) , orig[name].type() , depth + 1 ); + append( b , name , getProperty( o , name.c_str() ) , orig[name].type() , stack.dive( o ) ); } JS_DestroyIdArray( _context , properties ); @@ -271,39 +324,39 @@ namespace mongo { assert( s[0] == '/' ); s = s.substr(1); string::size_type end = s.rfind( '/' ); - b.appendRegex( name.c_str() , s.substr( 0 , end ).c_str() , s.substr( end + 1 ).c_str() ); + b.appendRegex( name , s.substr( 0 , end ).c_str() , s.substr( end + 1 ).c_str() ); } - void append( BSONObjBuilder& b , string name , jsval val , BSONType oldType = EOO , int depth=0 ){ + void append( BSONObjBuilder& b , string name , jsval val , BSONType oldType = EOO , const TraverseStack& stack=TraverseStack() ){ //cout << "name: " << name << "\t" << typeString( val ) << " oldType: " << oldType << endl; switch ( JS_TypeOfValue( _context , val ) ){ - case JSTYPE_VOID: b.appendUndefined( name.c_str() ); break; - case JSTYPE_NULL: b.appendNull( name.c_str() ); break; + case JSTYPE_VOID: b.appendUndefined( name ); break; + case JSTYPE_NULL: b.appendNull( name ); break; case JSTYPE_NUMBER: { double d = toNumber( val ); if ( oldType == NumberInt && ((int)d) == d ) - b.append( name.c_str() , (int)d ); + b.append( name , (int)d ); else - b.append( name.c_str() , d ); + b.append( name , d ); break; } - case JSTYPE_STRING: b.append( name.c_str() , toString( val ) ); break; - case JSTYPE_BOOLEAN: b.appendBool( name.c_str() , toBoolean( val ) ); break; + case JSTYPE_STRING: b.append( name , toString( val ) ); break; + case JSTYPE_BOOLEAN: b.appendBool( name , toBoolean( val ) ); break; case JSTYPE_OBJECT: { JSObject * o = JSVAL_TO_OBJECT( val ); if ( ! o || o == JSVAL_NULL ){ - b.appendNull( name.c_str() ); + b.appendNull( name ); } else if ( ! appendSpecialDBObject( this , b , name , val , o ) ){ - BSONObj sub = toObject( o , depth ); + BSONObj sub = toObject( o , stack ); if ( JS_IsArrayObject( _context , o ) ){ - b.appendArray( name.c_str() , sub ); + b.appendArray( name , sub ); } else { - b.append( name.c_str() , sub ); + b.append( name , sub ); } } break; @@ -315,7 +368,7 @@ namespace mongo { appendRegex( b , name , s ); } else { - b.appendCode( name.c_str() , getFunctionCode( val ).c_str() ); + b.appendCode( name , getFunctionCode( val ).c_str() ); } break; } @@ -334,7 +387,7 @@ namespace mongo { } bool isSimpleStatement( const string& code ){ - if ( code.find( "return" ) != string::npos ) + if ( hasJSReturn( code ) ) return false; if ( code.find( ";" ) != string::npos && @@ -416,7 +469,7 @@ namespace mongo { JSFunction * func = JS_CompileFunction( _context , assoc , fname.str().c_str() , params.size() , paramArray.get() , code.c_str() , strlen( code.c_str() ) , "nofile_b" , 0 ); if ( ! func ){ - cout << "compile failed for: " << raw << endl; + log() << "compile failed for: " << raw << endl; return 0; } gcName = "cf normal"; @@ -449,11 +502,11 @@ namespace mongo { free( dst ); if ( ! res ){ - cout << "decode failed. probably invalid utf-8 string [" << c << "]" << endl; + tlog() << "decode failed. probably invalid utf-8 string [" << c << "]" << endl; jsval v; if ( JS_GetPendingException( _context , &v ) ) - cout << "\t why: " << toString( v ) << endl; - throw UserException( 9006 , "invalid utf8" ); + tlog() << "\t why: " << toString( v ) << endl; + throw InvalidUTF8Exception(); } assert( s ); @@ -479,6 +532,24 @@ namespace mongo { return OBJECT_TO_JSVAL( o ); } + void makeLongObj( long long n, JSObject * o ) { + boost::uint64_t val = (boost::uint64_t)n; + CHECKNEWOBJECT(o,_context,"NumberLong1"); + setProperty( o , "floatApprox" , toval( (double)(boost::int64_t)( val ) ) ); + if ( (boost::int64_t)val != (boost::int64_t)(double)(boost::int64_t)( val ) ) { + // using 2 doubles here instead of a single double because certain double + // bit patterns represent undefined values and sm might trash them + setProperty( o , "top" , toval( (double)(boost::uint32_t)( val >> 32 ) ) ); + setProperty( o , "bottom" , toval( (double)(boost::uint32_t)( val & 0x00000000ffffffff ) ) ); + } + } + + jsval toval( long long n ) { + JSObject * o = JS_NewObject( _context , &numberlong_class , 0 , 0 ); + makeLongObj( n, o ); + return OBJECT_TO_JSVAL( o ); + } + jsval toval( const BSONElement& e ){ switch( e.type() ){ @@ -549,7 +620,9 @@ namespace mongo { } case Code:{ JSFunction * func = compileFunction( e.valuestr() ); - return OBJECT_TO_JSVAL( JS_GetFunctionObject( func ) ); + if ( func ) + return OBJECT_TO_JSVAL( JS_GetFunctionObject( func ) ); + return JSVAL_NULL; } case CodeWScope:{ JSFunction * func = compileFunction( e.codeWScopeCode() ); @@ -578,17 +651,7 @@ namespace mongo { return OBJECT_TO_JSVAL( o ); } case NumberLong: { - boost::uint64_t val = (boost::uint64_t)e.numberLong(); - JSObject * o = JS_NewObject( _context , &numberlong_class , 0 , 0 ); - CHECKNEWOBJECT(o,_context,"NumberLong1"); - setProperty( o , "floatApprox" , toval( (double)(boost::int64_t)( val ) ) ); - if ( (boost::int64_t)val != (boost::int64_t)(double)(boost::int64_t)( val ) ) { - // using 2 doubles here instead of a single double because certain double - // bit patterns represent undefined values and sm might trash them - setProperty( o , "top" , toval( (double)(boost::uint32_t)( val >> 32 ) ) ); - setProperty( o , "bottom" , toval( (double)(boost::uint32_t)( val & 0x00000000ffffffff ) ) ); - } - return OBJECT_TO_JSVAL( o ); + return toval( e.numberLong() ); } case DBRef: { JSObject * o = JS_NewObject( _context , &dbpointer_class , 0 , 0 ); @@ -609,13 +672,13 @@ namespace mongo { const char * data = e.binData( len ); assert( JS_SetPrivate( _context , o , new BinDataHolder( data ) ) ); - setProperty( o , "len" , toval( len ) ); - setProperty( o , "type" , toval( (int)e.binDataType() ) ); + setProperty( o , "len" , toval( (double)len ) ); + setProperty( o , "type" , toval( (double)e.binDataType() ) ); return OBJECT_TO_JSVAL( o ); } } - cout << "toval: unknown type: " << e.type() << endl; + log() << "toval: unknown type: " << (int) e.type() << endl; uassert( 10218 , "not done: toval" , 0 ); return 0; } @@ -824,13 +887,15 @@ namespace mongo { // --- global helpers --- JSBool native_print( JSContext * cx , JSObject * obj , uintN argc, jsval *argv, jsval *rval ){ + stringstream ss; Convertor c( cx ); for ( uintN i=0; i<argc; i++ ){ if ( i > 0 ) - cout << " "; - cout << c.toString( argv[i] ); + ss << " "; + ss << c.toString( argv[i] ); } - cout << endl; + ss << "\n"; + Logstream::logLockless( ss.str() ); return JS_TRUE; } @@ -894,14 +959,25 @@ namespace mongo { return JS_FALSE; } - BSONHolder * o = GETHOLDER( cx , JSVAL_TO_OBJECT( argv[ 0 ] ) ); + JSObject * o = JSVAL_TO_OBJECT( argv[0] ); + + Convertor c(cx); double size = 0; - if ( o ){ - size = o->_obj.objsize(); + + if ( JS_InstanceOf( cx , o , &bson_ro_class , 0 ) || + JS_InstanceOf( cx , o , &bson_class , 0 ) ){ + BSONHolder * h = GETHOLDER( cx , o ); + if ( h ){ + size = h->_obj.objsize(); + } } - Convertor c(cx); + else { + BSONObj temp = c.toObject( o ); + size = temp.objsize(); + } + *rval = c.toval( size ); - return JS_TRUE; + return JS_TRUE; } JSFunctionSpec objectHelpers[] = { @@ -934,7 +1010,15 @@ namespace mongo { return JS_TRUE; } - jsval val = c.toval( e ); + jsval val; + try { + val = c.toval( e ); + } + catch ( InvalidUTF8Exception& ) { + JS_LeaveLocalRootScope( cx ); + JS_ReportError( cx , "invalid utf8" ); + return JS_FALSE; + } assert( ! holder->_inResolve ); holder->_inResolve = true; @@ -1115,20 +1199,22 @@ namespace mongo { } void localConnect( const char * dbName ){ - smlock; - uassert( 10225 , "already setup for external db" , ! _externalSetup ); - if ( _localConnect ){ - uassert( 10226 , "connected to different db" , _localDBName == dbName ); - return; + { + smlock; + uassert( 10225 , "already setup for external db" , ! _externalSetup ); + if ( _localConnect ){ + uassert( 10226 , "connected to different db" , _localDBName == dbName ); + return; + } + + initMongoJS( this , _context , _global , true ); + + exec( "_mongo = new Mongo();" ); + exec( ((string)"db = _mongo.getDB( \"" + dbName + "\" ); ").c_str() ); + + _localConnect = true; + _localDBName = dbName; } - - initMongoJS( this , _context , _global , true ); - - exec( "_mongo = new Mongo();" ); - exec( ((string)"db = _mongo.getDB( \"" + dbName + "\" ); ").c_str() ); - - _localConnect = true; - _localDBName = dbName; loadStored(); } @@ -1309,6 +1395,15 @@ namespace mongo { JSBool worked = JS_EvaluateScript( _context , _global , code.c_str() , strlen( code.c_str() ) , name.c_str() , 0 , &ret ); uninstallCheckTimeout( timeoutMs ); + if ( ! worked && _error.size() == 0 ){ + jsval v; + if ( JS_GetPendingException( _context , &v ) ){ + _error = _convertor->toString( v ); + if ( reportError ) + cout << _error << endl; + } + } + if ( assertOnError ) uassert( 10228 , name + " exec failed" , worked ); @@ -1387,7 +1482,6 @@ namespace mongo { code << field << "_" << " = { x : " << field << "_ }; "; code << field << " = function(){ return nativeHelper.apply( " << field << "_ , arguments ); }"; exec( code.str().c_str() ); - } virtual void gc(){ @@ -1424,15 +1518,20 @@ namespace mongo { }; + /* used to make the logging not overly chatty in the mongo shell. */ + extern bool isShell; + void errorReporter( JSContext *cx, const char *message, JSErrorReport *report ){ stringstream ss; - ss << "JS Error: " << message; + if( !isShell ) + ss << "JS Error: "; + ss << message; if ( report && report->filename ){ ss << " " << report->filename << ":" << report->lineno; } - log() << ss.str() << endl; + tlog() << ss.str() << endl; if ( currentScope.get() ){ currentScope->gotError( ss.str() ); @@ -1446,10 +1545,10 @@ namespace mongo { for ( uintN i=0; i<argc; i++ ){ string filename = c.toString( argv[i] ); - cout << "should load [" << filename << "]" << endl; + //cout << "load [" << filename << "]" << endl; if ( ! s->execFile( filename , false , true , false ) ){ - JS_ReportError( cx , ((string)"error loading file: " + filename ).c_str() ); + JS_ReportError( cx , ((string)"error loading js file: " + filename ).c_str() ); return JS_FALSE; } } diff --git a/scripting/engine_spidermonkey.h b/scripting/engine_spidermonkey.h index 4e420de..4617b5d 100644 --- a/scripting/engine_spidermonkey.h +++ b/scripting/engine_spidermonkey.h @@ -37,7 +37,7 @@ #include "jstypes.h" #undef JS_PUBLIC_API #undef JS_PUBLIC_DATA -#define JS_PUBLIC_API(t) t +#define JS_PUBLIC_API(t) t __cdecl #define JS_PUBLIC_DATA(t) t #endif diff --git a/scripting/engine_v8.cpp b/scripting/engine_v8.cpp index 35f2eb8..08826b1 100644 --- a/scripting/engine_v8.cpp +++ b/scripting/engine_v8.cpp @@ -57,9 +57,12 @@ namespace mongo { _global->Set(v8::String::New("load"), v8::FunctionTemplate::New(loadCallback, v8::External::New(this))->GetFunction() ); - - _wrapper = Persistent< v8::Function >::New( getObjectWrapperTemplate()->GetFunction() ); + _wrapper = Persistent< v8::Function >::New( getObjectWrapperTemplate()->GetFunction() ); + + _global->Set(v8::String::New("gc"), v8::FunctionTemplate::New(GCV8)->GetFunction() ); + + installDBTypes( _global ); } @@ -232,7 +235,7 @@ namespace mongo { string code = raw; if ( code.find( "function" ) == string::npos ){ if ( code.find( "\n" ) == string::npos && - code.find( "return" ) == string::npos && + ! hasJSReturn( code ) && ( code.find( ";" ) == string::npos || code.find( ";" ) == code.size() - 1 ) ){ code = "return " + code; } @@ -383,6 +386,7 @@ namespace mongo { } void V8Scope::gc() { + cout << "in gc" << endl; Locker l; while( V8::IdleNotification() ); } diff --git a/scripting/sm_db.cpp b/scripting/sm_db.cpp index 1c15170..855a50d 100644 --- a/scripting/sm_db.cpp +++ b/scripting/sm_db.cpp @@ -19,6 +19,15 @@ #include "../client/syncclusterconnection.h" #include "../util/base64.h" +#include "../util/text.h" +#include "../util/hex.h" + +#if( BOOST_VERSION >= 104200 ) +//#include <boost/uuid/uuid.hpp> +#define HAVE_UUID 1 +#else +; +#endif namespace mongo { @@ -90,6 +99,13 @@ namespace mongo { return JS_TRUE; } + JSBool internal_cursor_objsLeftInBatch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ + DBClientCursor *cursor = getCursor( cx, obj ); + Convertor c(cx); + *rval = c.toval((double) cursor->objsLeftInBatch() ); + return JS_TRUE; + } + JSBool internal_cursor_next(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ DBClientCursor *cursor = getCursor( cx, obj ); if ( ! cursor->more() ){ @@ -105,6 +121,7 @@ namespace mongo { JSFunctionSpec internal_cursor_functions[] = { { "hasNext" , internal_cursor_hasNext , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } , + { "objsLeftInBatch" , internal_cursor_objsLeftInBatch , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } , { "next" , internal_cursor_next , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } , { 0 } }; @@ -145,37 +162,22 @@ namespace mongo { if ( argc > 0 ) host = c.toString( argv[0] ); - int numCommas = DBClientBase::countCommas( host ); - - shared_ptr< DBClientWithCommands > conn; - string errmsg; - if ( numCommas == 0 ){ - DBClientConnection * c = new DBClientConnection( true ); - conn.reset( c ); - if ( ! c->connect( host , errmsg ) ){ - JS_ReportError( cx , ((string)"couldn't connect: " + errmsg).c_str() ); - return JS_FALSE; - } - ScriptEngine::runConnectCallback( *c ); - } - else if ( numCommas == 1 ){ // paired - DBClientPaired * c = new DBClientPaired(); - conn.reset( c ); - if ( ! c->connect( host ) ){ - JS_ReportError( cx , "couldn't connect to pair" ); - return JS_FALSE; - } - } - else if ( numCommas == 2 ){ - conn.reset( new SyncClusterConnection( host ) ); + + ConnectionString cs = ConnectionString::parse( host , errmsg ); + if ( ! cs.isValid() ){ + JS_ReportError( cx , errmsg.c_str() ); + return JS_FALSE; } - else { - JS_ReportError( cx , "1 (paired) or 2(quorum) commas are allowed" ); + + shared_ptr< DBClientWithCommands > conn( cs.connect( errmsg ) ); + if ( ! conn ){ + JS_ReportError( cx , errmsg.c_str() ); return JS_FALSE; } - + ScriptEngine::runConnectCallback( *conn ); + assert( JS_SetPrivate( cx , obj , (void*)( new shared_ptr< DBClientWithCommands >( conn ) ) ) ); jsval host_val = c.toval( host.c_str() ); assert( JS_SetProperty( cx , obj , "host" , &host_val ) ); @@ -342,7 +344,6 @@ namespace mongo { { 0 } }; - // ------------- db_collection ------------- JSBool db_collection_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){ @@ -516,7 +517,7 @@ namespace mongo { JSBool object_id_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ Convertor c(cx); - return *rval = c.getProperty( obj , "str" ); + return (JSBool) (*rval = c.getProperty( obj , "str" )); } JSFunctionSpec object_id_functions[] = { @@ -524,7 +525,6 @@ namespace mongo { { 0 } }; - // dbpointer JSBool dbpointer_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){ @@ -580,8 +580,78 @@ namespace mongo { JSClass dbref_class = bson_class; // name will be fixed later - // BinData + // UUID ************************** + + JSBool uuid_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){ + Convertor c( cx ); + + if( argc == 0 ) { +#if defined(HAVE_UUID) + //uuids::uuid +#else +#endif + JS_ReportError( cx , "UUID needs 1 argument -- UUID(hexstr)" ); + return JS_FALSE; + } + else if ( argc == 1 ) { + + string encoded = c.toString( argv[ 0 ] ); + if( encoded.size() != 32 ) { + JS_ReportError( cx, "expect 32 char hex string to UUID()" ); + return JS_FALSE; + } + + char buf[16]; + for( int i = 0; i < 16; i++ ) { + buf[i] = fromHex(encoded.c_str() + i * 2); + } + + assert( JS_SetPrivate( cx, obj, new BinDataHolder( buf, 16 ) ) ); + c.setProperty( obj, "len", c.toval( (double)16 ) ); + c.setProperty( obj, "type", c.toval( (double)3 ) ); + + return JS_TRUE; + } + else { + JS_ReportError( cx , "UUID needs 1 argument -- UUID(hexstr)" ); + return JS_FALSE; + } + } + + JSBool uuid_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ + Convertor c(cx); + void *holder = JS_GetPrivate( cx, obj ); + assert( holder ); + const char *data = ( ( BinDataHolder* )( holder ) )->c_; + stringstream ss; + ss << "UUID(\"" << toHex(data, 16); + ss << "\")"; + string ret = ss.str(); + return *rval = c.toval( ret.c_str() ); + } + + void uuid_finalize( JSContext * cx , JSObject * obj ){ + Convertor c(cx); + void *holder = JS_GetPrivate( cx, obj ); + if ( holder ){ + delete ( BinDataHolder* )holder; + assert( JS_SetPrivate( cx , obj , 0 ) ); + } + } + + JSClass uuid_class = { + "UUID" , JSCLASS_HAS_PRIVATE , + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, uuid_finalize, + JSCLASS_NO_OPTIONAL_MEMBERS + }; + JSFunctionSpec uuid_functions[] = { + { "toString" , uuid_tostring , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } , + { 0 } + }; + + // BinData ************************** JSBool bindata_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){ Convertor c( cx ); @@ -589,17 +659,28 @@ namespace mongo { if ( argc == 2 ){ int type = (int)c.toNumber( argv[ 0 ] ); + if( type < 0 || type > 255 ) { + JS_ReportError( cx , "invalid BinData subtype -- range is 0..255 see bsonspec.org" ); + return JS_FALSE; + } string encoded = c.toString( argv[ 1 ] ); - string decoded = base64::decode( encoded ); + string decoded; + try { + decoded = base64::decode( encoded ); + } + catch(...) { + JS_ReportError(cx, "BinData could not decode base64 parameter"); + return JS_FALSE; + } assert( JS_SetPrivate( cx, obj, new BinDataHolder( decoded.data(), decoded.length() ) ) ); - c.setProperty( obj, "len", c.toval( decoded.length() ) ); - c.setProperty( obj, "type", c.toval( type ) ); + c.setProperty( obj, "len", c.toval( (double)decoded.length() ) ); + c.setProperty( obj, "type", c.toval( (double)type ) ); return JS_TRUE; } else { - JS_ReportError( cx , "BinData needs 2 arguments" ); + JS_ReportError( cx , "BinData needs 2 arguments -- BinData(subtype,data)" ); return JS_FALSE; } } @@ -612,13 +693,53 @@ namespace mongo { assert( holder ); const char *data = ( ( BinDataHolder* )( holder ) )->c_; stringstream ss; - ss << "BinData( type: " << type << ", base64: \""; + ss << "BinData(" << type << ",\""; base64::encode( ss, (const char *)data, len ); - ss << "\" )"; + ss << "\")"; + string ret = ss.str(); + return *rval = c.toval( ret.c_str() ); + } + + JSBool bindataBase64(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ + Convertor c(cx); + int len = (int)c.getNumber( obj, "len" ); + void *holder = JS_GetPrivate( cx, obj ); + assert( holder ); + const char *data = ( ( BinDataHolder* )( holder ) )->c_; + stringstream ss; + base64::encode( ss, (const char *)data, len ); + string ret = ss.str(); + return *rval = c.toval( ret.c_str() ); + } + + JSBool bindataAsHex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ + Convertor c(cx); + int len = (int)c.getNumber( obj, "len" ); + void *holder = JS_GetPrivate( cx, obj ); + assert( holder ); + const char *data = ( ( BinDataHolder* )( holder ) )->c_; + stringstream ss; + ss << hex; + for( int i = 0; i < len; i++ ) { + unsigned v = (unsigned char) data[i]; + ss << v; + } string ret = ss.str(); return *rval = c.toval( ret.c_str() ); } + JSBool bindataLength(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ + Convertor c(cx); + int len = (int)c.getNumber( obj, "len" ); + return *rval = c.toval((double) len); + } + + JSBool bindataSubtype(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ + Convertor c(cx); + int t = (int)c.getNumber( obj, "type" ); + return *rval = c.toval((double) t); + } + void bindata_finalize( JSContext * cx , JSObject * obj ){ Convertor c(cx); void *holder = JS_GetPrivate( cx, obj ); @@ -637,6 +758,10 @@ namespace mongo { JSFunctionSpec bindata_functions[] = { { "toString" , bindata_tostring , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } , + { "hex", bindataAsHex, 0, JSPROP_READONLY | JSPROP_PERMANENT, 0 } , + { "base64", bindataBase64, 0, JSPROP_READONLY | JSPROP_PERMANENT, 0 } , + { "length", bindataLength, 0, JSPROP_READONLY | JSPROP_PERMANENT, 0 } , + { "subtype", bindataSubtype, 0, JSPROP_READONLY | JSPROP_PERMANENT, 0 } , { 0 } }; @@ -699,6 +824,31 @@ namespace mongo { JSCLASS_NO_OPTIONAL_MEMBERS }; + JSBool numberlong_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){ + smuassert( cx , "NumberLong needs 0 or 1 args" , argc == 0 || argc == 1 ); + + Convertor c( cx ); + if ( argc == 0 ) { + c.setProperty( obj, "floatApprox", c.toval( 0.0 ) ); + } else if ( JSVAL_IS_NUMBER( argv[ 0 ] ) ) { + c.setProperty( obj, "floatApprox", argv[ 0 ] ); + } else { + string num = c.toString( argv[ 0 ] ); + //PRINT(num); + const char *numStr = num.c_str(); + long long n; + try { + n = parseLL( numStr ); + //PRINT(n); + } catch ( const AssertionException & ) { + smuassert( cx , "could not convert string to long long" , false ); + } + c.makeLongObj( n, obj ); + } + + return JS_TRUE; + } + JSBool numberlong_valueof(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ Convertor c(cx); return *rval = c.toval( double( c.toNumberLongUnsafe( obj ) ) ); @@ -711,7 +861,12 @@ namespace mongo { JSBool numberlong_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){ Convertor c(cx); stringstream ss; - ss << c.toNumberLongUnsafe( obj ); + if ( c.hasProperty( obj, "top" ) ) { + long long val = c.toNumberLongUnsafe( obj ); + ss << "NumberLong( \"" << val << "\" )"; + } else { + ss << "NumberLong( " << c.getNumber( obj, "floatApprox" ) << " )"; + } string ret = ss.str(); return *rval = c.toval( ret.c_str() ); } @@ -819,9 +974,10 @@ namespace mongo { assert( JS_InitClass( cx , global , 0 , &dbquery_class , dbquery_constructor , 0 , 0 , 0 , 0 , 0 ) ); assert( JS_InitClass( cx , global , 0 , &dbpointer_class , dbpointer_constructor , 0 , 0 , dbpointer_functions , 0 , 0 ) ); assert( JS_InitClass( cx , global , 0 , &bindata_class , bindata_constructor , 0 , 0 , bindata_functions , 0 , 0 ) ); + assert( JS_InitClass( cx , global , 0 , &uuid_class , uuid_constructor , 0 , 0 , uuid_functions , 0 , 0 ) ); assert( JS_InitClass( cx , global , 0 , ×tamp_class , 0 , 0 , 0 , 0 , 0 , 0 ) ); - assert( JS_InitClass( cx , global , 0 , &numberlong_class , 0 , 0 , 0 , numberlong_functions , 0 , 0 ) ); + assert( JS_InitClass( cx , global , 0 , &numberlong_class , numberlong_constructor , 0 , 0 , numberlong_functions , 0 , 0 ) ); assert( JS_InitClass( cx , global , 0 , &minkey_class , 0 , 0 , 0 , 0 , 0 , 0 ) ); assert( JS_InitClass( cx , global , 0 , &maxkey_class , 0 , 0 , 0 , 0 , 0 , 0 ) ); @@ -842,39 +998,39 @@ namespace mongo { if ( JS_InstanceOf( c->_context , o , &object_id_class , 0 ) ){ OID oid; oid.init( c->getString( o , "str" ) ); - b.append( name.c_str() , oid ); + b.append( name , oid ); return true; } if ( JS_InstanceOf( c->_context , o , &minkey_class , 0 ) ){ - b.appendMinKey( name.c_str() ); + b.appendMinKey( name ); return true; } if ( JS_InstanceOf( c->_context , o , &maxkey_class , 0 ) ){ - b.appendMaxKey( name.c_str() ); + b.appendMaxKey( name ); return true; } if ( JS_InstanceOf( c->_context , o , ×tamp_class , 0 ) ){ - b.appendTimestamp( name.c_str() , (unsigned long long)c->getNumber( o , "t" ) , (unsigned int )c->getNumber( o , "i" ) ); + b.appendTimestamp( name , (unsigned long long)c->getNumber( o , "t" ) , (unsigned int )c->getNumber( o , "i" ) ); return true; } if ( JS_InstanceOf( c->_context , o , &numberlong_class , 0 ) ){ - b.append( name.c_str() , c->toNumberLongUnsafe( o ) ); + b.append( name , c->toNumberLongUnsafe( o ) ); return true; } if ( JS_InstanceOf( c->_context , o , &dbpointer_class , 0 ) ){ - b.appendDBRef( name.c_str() , c->getString( o , "ns" ).c_str() , c->toOID( c->getProperty( o , "id" ) ) ); + b.appendDBRef( name , c->getString( o , "ns" ).c_str() , c->toOID( c->getProperty( o , "id" ) ) ); return true; } if ( JS_InstanceOf( c->_context , o , &bindata_class , 0 ) ){ void *holder = JS_GetPrivate( c->_context , o ); const char *data = ( ( BinDataHolder * )( holder ) )->c_; - b.appendBinData( name.c_str() , + b.appendBinData( name , (int)(c->getNumber( o , "len" )) , (BinDataType)((char)(c->getNumber( o , "type" ) ) ) , data ); @@ -886,21 +1042,21 @@ namespace mongo { { jsdouble d = js_DateGetMsecSinceEpoch( c->_context , o ); if ( d ){ - b.appendDate( name.c_str() , Date_t(d) ); + b.appendDate( name , Date_t(d) ); return true; } } #elif defined( XULRUNNER ) if ( JS_InstanceOf( c->_context , o, globalSMEngine->_dateClass , 0 ) ){ jsdouble d = js_DateGetMsecSinceEpoch( c->_context , o ); - b.appendDate( name.c_str() , Date_t(d) ); + b.appendDate( name , Date_t(d) ); return true; } #else if ( JS_InstanceOf( c->_context , o, &js_DateClass , 0 ) ){ jsdouble d = js_DateGetMsecSinceEpoch( c->_context , o ); //TODO: make signed - b.appendDate( name.c_str() , Date_t((unsigned long long)d) ); + b.appendDate( name , Date_t((unsigned long long)d) ); return true; } #endif @@ -909,7 +1065,7 @@ namespace mongo { if ( JS_InstanceOf( c->_context , o , &dbquery_class , 0 ) || JS_InstanceOf( c->_context , o , &mongo_class , 0 ) || JS_InstanceOf( c->_context , o , &db_collection_class , 0 ) ){ - b.append( name.c_str() , c->toString( val ) ); + b.append( name , c->toString( val ) ); return true; } diff --git a/scripting/utils.cpp b/scripting/utils.cpp index 21089ac..ee01bb2 100644 --- a/scripting/utils.cpp +++ b/scripting/utils.cpp @@ -16,9 +16,10 @@ */ -#include "stdafx.h" +#include "pch.h" #include "engine.h" #include "../util/md5.hpp" +#include "../util/version.h" namespace mongo { diff --git a/scripting/v8_db.cpp b/scripting/v8_db.cpp index 4d14a03..5752fde 100644 --- a/scripting/v8_db.cpp +++ b/scripting/v8_db.cpp @@ -20,6 +20,7 @@ #include "v8_db.h" #include "engine.h" #include "util/base64.h" +#include "util/text.h" #include "../client/syncclusterconnection.h" #include <iostream> @@ -28,12 +29,11 @@ using namespace v8; namespace mongo { -#define CONN_STRING (v8::String::New( "_conn" )) - #define DDD(x) v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( bool local ){ v8::Local<v8::FunctionTemplate> mongo = FunctionTemplate::New( local ? mongoConsLocal : mongoConsExternal ); + mongo->InstanceTemplate()->SetInternalFieldCount( 1 ); v8::Local<v8::Template> proto = mongo->PrototypeTemplate(); @@ -43,9 +43,13 @@ namespace mongo { proto->Set( v8::String::New( "update" ) , FunctionTemplate::New( mongoUpdate ) ); Local<FunctionTemplate> ic = FunctionTemplate::New( internalCursorCons ); + ic->InstanceTemplate()->SetInternalFieldCount( 1 ); ic->PrototypeTemplate()->Set( v8::String::New("next") , FunctionTemplate::New( internalCursorNext ) ); ic->PrototypeTemplate()->Set( v8::String::New("hasNext") , FunctionTemplate::New( internalCursorHasNext ) ); + ic->PrototypeTemplate()->Set( v8::String::New("objsLeftInBatch") , FunctionTemplate::New( internalCursorObjsLeftInBatch ) ); proto->Set( v8::String::New( "internalCursor" ) , ic ); + + return mongo; } @@ -131,9 +135,10 @@ namespace mongo { global->Get( v8::String::New( "Object" ) )->ToObject()->Set( v8::String::New("bsonsize") , FunctionTemplate::New( bsonsize )->GetFunction() ); } - void destroyConnection( Persistent<Value> object, void* parameter){ - // TODO - cout << "warning: destroyConnection not implemented" << endl; + void destroyConnection( Persistent<Value> self, void* parameter){ + delete static_cast<DBClientBase*>(parameter); + self.Dispose(); + self.Clear(); } Handle<Value> mongoConsExternal(const Arguments& args){ @@ -148,47 +153,22 @@ namespace mongo { strcpy( host , "127.0.0.1" ); } - DBClientWithCommands * conn = 0; - int commas = 0; - for ( int i=0; i<255; i++ ){ - if ( host[i] == ',' ) - commas++; - else if ( host[i] == 0 ) - break; - } + string errmsg; + ConnectionString cs = ConnectionString::parse( host , errmsg ); + if ( ! cs.isValid() ) + return v8::ThrowException( v8::String::New( errmsg.c_str() ) ); - if ( commas == 0 ){ - DBClientConnection * c = new DBClientConnection( true ); - string errmsg; - if ( ! c->connect( host , errmsg ) ){ - delete c; - string x = "couldn't connect: "; - x += errmsg; - return v8::ThrowException( v8::String::New( x.c_str() ) ); - } - conn = c; - } - else if ( commas == 1 ){ - DBClientPaired * c = new DBClientPaired(); - if ( ! c->connect( host ) ){ - delete c; - return v8::ThrowException( v8::String::New( "couldn't connect to pair" ) ); - } - conn = c; - } - else if ( commas == 2 ){ - conn = new SyncClusterConnection( host ); - } - else { - return v8::ThrowException( v8::String::New( "too many commas" ) ); - } - - Persistent<v8::Object> self = Persistent<v8::Object>::New( args.This() ); + + DBClientWithCommands * conn = cs.connect( errmsg ); + if ( ! conn ) + return v8::ThrowException( v8::String::New( errmsg.c_str() ) ); + + Persistent<v8::Object> self = Persistent<v8::Object>::New( args.Holder() ); self.MakeWeak( conn , destroyConnection ); ScriptEngine::runConnectCallback( *conn ); - // NOTE I don't believe the conn object will ever be freed. - args.This()->Set( CONN_STRING , External::New( conn ) ); + + args.This()->SetInternalField( 0 , External::New( conn ) ); args.This()->Set( v8::String::New( "slaveOk" ) , Boolean::New( false ) ); args.This()->Set( v8::String::New( "host" ) , v8::String::New( host ) ); @@ -206,7 +186,7 @@ namespace mongo { self.MakeWeak( conn , destroyConnection ); // NOTE I don't believe the conn object will ever be freed. - args.This()->Set( CONN_STRING , External::New( conn ) ); + args.This()->SetInternalField( 0 , External::New( conn ) ); args.This()->Set( v8::String::New( "slaveOk" ) , Boolean::New( false ) ); args.This()->Set( v8::String::New( "host" ) , v8::String::New( "EMBEDDED" ) ); @@ -223,7 +203,7 @@ namespace mongo { #endif DBClientBase * getConnection( const Arguments& args ){ - Local<External> c = External::Cast( *(args.This()->Get( CONN_STRING )) ); + Local<External> c = External::Cast( *(args.This()->GetInternalField( 0 )) ); DBClientBase * conn = (DBClientBase*)(c->Value()); assert( conn ); return conn; @@ -231,6 +211,12 @@ namespace mongo { // ---- real methods + void destroyCursor( Persistent<Value> self, void* parameter){ + delete static_cast<mongo::DBClientCursor*>(parameter); + self.Dispose(); + self.Clear(); + } + /** 0 - namespace 1 - query @@ -239,6 +225,8 @@ namespace mongo { 4 - skip */ Handle<Value> mongoFind(const Arguments& args){ + HandleScope handle_scope; + jsassert( args.Length() == 6 , "find needs 6 args" ); jsassert( args[1]->IsObject() , "needs to be an object" ); DBClientBase * conn = getConnection( args ); @@ -268,11 +256,12 @@ namespace mongo { } v8::Function * cons = (v8::Function*)( *( mongo->Get( v8::String::New( "internalCursor" ) ) ) ); assert( cons ); - Local<v8::Object> c = cons->NewInstance(); - - // NOTE I don't believe the cursor object will ever be freed. - c->Set( v8::String::New( "cursor" ) , External::New( cursor.release() ) ); - return c; + + Persistent<v8::Object> c = Persistent<v8::Object>::New( cons->NewInstance() ); + c.MakeWeak( cursor.get() , destroyCursor ); + + c->SetInternalField( 0 , External::New( cursor.release() ) ); + return handle_scope.Close(c); } catch ( ... ){ return v8::ThrowException( v8::String::New( "socket error on query" ) ); @@ -362,7 +351,8 @@ namespace mongo { // --- cursor --- mongo::DBClientCursor * getCursor( const Arguments& args ){ - Local<External> c = External::Cast( *(args.This()->Get( v8::String::New( "cursor" ) ) ) ); + Local<External> c = External::Cast( *(args.This()->GetInternalField( 0 ) ) ); + mongo::DBClientCursor * cursor = (mongo::DBClientCursor*)(c->Value()); return cursor; } @@ -395,6 +385,18 @@ namespace mongo { return Boolean::New( ret ); } + v8::Handle<v8::Value> internalCursorObjsLeftInBatch(const v8::Arguments& args){ + mongo::DBClientCursor * cursor = getCursor( args ); + if ( ! cursor ) + return v8::Number::New( (double) 0 ); + int ret; + { + v8::Unlocker u; + ret = cursor->objsLeftInBatch(); + } + return v8::Number::New( (double) ret ); + } + // --- DB ---- @@ -623,17 +625,17 @@ namespace mongo { v8::String::Utf8Value data( it->Get( v8::String::New( "data" ) ) ); stringstream ss; - ss << "BinData( type: " << type << ", base64: \""; + ss << "BinData(" << type << ",\""; base64::encode( ss, *data, len ); - ss << "\" )"; + ss << "\")"; string ret = ss.str(); return v8::String::New( ret.c_str() ); } v8::Handle<v8::Value> numberLongInit( const v8::Arguments& args ) { - if (args.Length() != 1 && args.Length() != 3) { - return v8::ThrowException( v8::String::New( "NumberLong needs 1 or 3 arguments" ) ); + if (args.Length() != 0 && args.Length() != 1 && args.Length() != 3) { + return v8::ThrowException( v8::String::New( "NumberLong needs 0, 1 or 3 arguments" ) ); } v8::Handle<v8::Object> it = args.This(); @@ -642,9 +644,33 @@ namespace mongo { v8::Function* f = getNamedCons( "NumberLong" ); it = f->NewInstance(); } - - it->Set( v8::String::New( "floatApprox" ) , args[0] ); - if ( args.Length() == 3 ) { + + if ( args.Length() == 0 ) { + it->Set( v8::String::New( "floatApprox" ), v8::Number::New( 0 ) ); + } else if ( args.Length() == 1 ) { + if ( args[ 0 ]->IsNumber() ) { + it->Set( v8::String::New( "floatApprox" ), args[ 0 ] ); + } else { + v8::String::Utf8Value data( args[ 0 ] ); + string num = *data; + const char *numStr = num.c_str(); + long long n; + try { + n = parseLL( numStr ); + } catch ( const AssertionException & ) { + return v8::ThrowException( v8::String::New( "could not convert string to long long" ) ); + } + unsigned long long val = n; + if ( (long long)val == (long long)(double)(long long)(val) ) { + it->Set( v8::String::New( "floatApprox" ), v8::Number::New( (double)(long long)( val ) ) ); + } else { + it->Set( v8::String::New( "floatApprox" ), v8::Number::New( (double)(long long)( val ) ) ); + it->Set( v8::String::New( "top" ), v8::Integer::New( val >> 32 ) ); + it->Set( v8::String::New( "bottom" ), v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) ) ); + } + } + } else { + it->Set( v8::String::New( "floatApprox" ) , args[0] ); it->Set( v8::String::New( "top" ) , args[1] ); it->Set( v8::String::New( "bottom" ) , args[2] ); } @@ -687,10 +713,12 @@ namespace mongo { v8::Handle<v8::Object> it = args.This(); - long long val = numberLongVal( it ); - stringstream ss; - ss << val; + if ( !it->Has( v8::String::New( "top" ) ) ) { + ss << "NumberLong( " << it->Get( v8::String::New( "floatApprox" ) )->NumberValue() << " )"; + } else { + ss << "NumberLong( \"" << numberLongVal( it ) << "\" )"; + } string ret = ss.str(); return v8::String::New( ret.c_str() ); } diff --git a/scripting/v8_db.h b/scripting/v8_db.h index 92e2ae2..4bebb32 100644 --- a/scripting/v8_db.h +++ b/scripting/v8_db.h @@ -49,6 +49,7 @@ namespace mongo { v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args); v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args); v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args); + v8::Handle<v8::Value> internalCursorObjsLeftInBatch(const v8::Arguments& args); // DB members diff --git a/scripting/v8_utils.cpp b/scripting/v8_utils.cpp index 5e56245..5a07a80 100644 --- a/scripting/v8_utils.cpp +++ b/scripting/v8_utils.cpp @@ -302,4 +302,11 @@ namespace mongo { global->Set( v8::String::New( "_scopedThreadInject" ), FunctionTemplate::New( ScopedThreadInject )->GetFunction() ); } + Handle<v8::Value> GCV8(const Arguments& args) { + Locker l; + while( V8::IdleNotification() ); + return v8::Undefined(); + } + + } diff --git a/scripting/v8_utils.h b/scripting/v8_utils.h index 8218455..bc4b524 100644 --- a/scripting/v8_utils.h +++ b/scripting/v8_utils.h @@ -29,6 +29,7 @@ namespace mongo { v8::Handle<v8::Value> Print(const v8::Arguments& args); v8::Handle<v8::Value> Version(const v8::Arguments& args); + v8::Handle<v8::Value> GCV8(const v8::Arguments& args); void ReportException(v8::TryCatch* handler); diff --git a/scripting/v8_wrapper.cpp b/scripting/v8_wrapper.cpp index c4e6b7d..0e71c9a 100644 --- a/scripting/v8_wrapper.cpp +++ b/scripting/v8_wrapper.cpp @@ -395,31 +395,31 @@ namespace mongo { void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name , const string sname , v8::Handle<v8::Value> value , int depth ){ if ( value->IsString() ){ - b.append( sname.c_str() , toSTLString( value ).c_str() ); + b.append( sname , toSTLString( value ).c_str() ); return; } if ( value->IsFunction() ){ - b.appendCode( sname.c_str() , toSTLString( value ).c_str() ); + b.appendCode( sname , toSTLString( value ).c_str() ); return; } if ( value->IsNumber() ){ if ( value->IsInt32() ) - b.append( sname.c_str(), int( value->ToInt32()->Value() ) ); + b.append( sname, int( value->ToInt32()->Value() ) ); else - b.append( sname.c_str() , value->ToNumber()->Value() ); + b.append( sname , value->ToNumber()->Value() ); return; } if ( value->IsArray() ){ BSONObj sub = v8ToMongo( value->ToObject() , depth ); - b.appendArray( sname.c_str() , sub ); + b.appendArray( sname , sub ); return; } if ( value->IsDate() ){ - b.appendDate( sname.c_str() , Date_t(v8::Date::Cast( *value )->NumberValue()) ); + b.appendDate( sname , Date_t( (unsigned long long)(v8::Date::Cast( *value )->NumberValue())) ); return; } @@ -434,15 +434,15 @@ namespace mongo { if ( obj->InternalFieldCount() && obj->GetInternalField( 0 )->IsNumber() ) { switch( obj->GetInternalField( 0 )->ToInt32()->Value() ) { // NOTE Uint32's Value() gave me a linking error, so going with this instead case Timestamp: - b.appendTimestamp( sname.c_str(), - Date_t( obj->Get( v8::String::New( "t" ) )->ToNumber()->Value() ), - obj->Get( v8::String::New( "i" ) )->ToInt32()->Value() ); + b.appendTimestamp( sname, + Date_t( (unsigned long long)(obj->Get( v8::String::New( "t" ) )->ToNumber()->Value() )), + obj->Get( v8::String::New( "i" ) )->ToInt32()->Value() ); return; case MinKey: - b.appendMinKey( sname.c_str() ); + b.appendMinKey( sname ); return; case MaxKey: - b.appendMaxKey( sname.c_str() ); + b.appendMaxKey( sname ); return; default: assert( "invalid internal field" == 0 ); @@ -453,13 +453,13 @@ namespace mongo { s = s.substr( 1 ); string r = s.substr( 0 , s.rfind( "/" ) ); string o = s.substr( s.rfind( "/" ) + 1 ); - b.appendRegex( sname.c_str() , r.c_str() , o.c_str() ); + b.appendRegex( sname , r.c_str() , o.c_str() ); } else if ( value->ToObject()->GetPrototype()->IsObject() && value->ToObject()->GetPrototype()->ToObject()->HasRealNamedProperty( v8::String::New( "isObjectId" ) ) ){ OID oid; oid.init( toSTLString( value ) ); - b.appendOID( sname.c_str() , &oid ); + b.appendOID( sname , &oid ); } else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__NumberLong" ) ).IsEmpty() ) { // TODO might be nice to potentially speed this up with an indexed internal @@ -475,42 +475,42 @@ namespace mongo { (unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() ); } - b.append( sname.c_str(), val ); + b.append( sname, 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" ) ) ); - b.appendDBRef( sname.c_str(), ns.c_str(), oid ); + b.appendDBRef( sname, ns.c_str(), oid ); } else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__BinData" ) ).IsEmpty() ) { int len = obj->Get( v8::String::New( "len" ) )->ToInt32()->Value(); v8::String::Utf8Value data( obj->Get( v8::String::New( "data" ) ) ); const char *dataArray = *data; assert( data.length() == len ); - b.appendBinData( sname.c_str(), + b.appendBinData( sname, len, mongo::BinDataType( obj->Get( v8::String::New( "type" ) )->ToInt32()->Value() ), dataArray ); } else { BSONObj sub = v8ToMongo( value->ToObject() , depth ); - b.append( sname.c_str() , sub ); + b.append( sname , sub ); } return; } if ( value->IsBoolean() ){ - b.appendBool( sname.c_str() , value->ToBoolean()->Value() ); + b.appendBool( sname , value->ToBoolean()->Value() ); return; } else if ( value->IsUndefined() ){ - b.appendUndefined( sname.c_str() ); + b.appendUndefined( sname ); return; } else if ( value->IsNull() ){ - b.appendNull( sname.c_str() ); + b.appendNull( sname ); return; } |