StatusWithMatchExpression expressionParserWhereCallbackReal(const BSONElement& where) { if ( !haveClient() ) return StatusWithMatchExpression( ErrorCodes::BadValue, "no current client needed for $where" ); Client::Context* context = cc().getContext(); if ( !context ) return StatusWithMatchExpression( ErrorCodes::BadValue, "no context in $where parsing" ); const char* ns = context->ns(); if ( !ns ) return StatusWithMatchExpression( ErrorCodes::BadValue, "no ns in $where parsing" ); if ( !globalScriptEngine ) return StatusWithMatchExpression( ErrorCodes::BadValue, "no globalScriptEngine in $where parsing" ); auto_ptr<WhereMatchExpression> exp( new WhereMatchExpression() ); if ( where.type() == String || where.type() == Code ) { Status s = exp->init( ns, where.valuestr(), BSONObj() ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( exp.release() ); } if ( where.type() == CodeWScope ) { Status s = exp->init( ns, where.codeWScopeCode(), BSONObj( where.codeWScopeScopeDataUnsafe() ) ); if ( !s.isOK() ) return StatusWithMatchExpression( s ); return StatusWithMatchExpression( exp.release() ); } return StatusWithMatchExpression( ErrorCodes::BadValue, "$where got bad type" ); }
StatusWithMatchExpression WhereCallbackNoop::parseWhere(const BSONElement& where) const { unique_ptr<WhereNoOpMatchExpression> exp(new WhereNoOpMatchExpression()); if (where.type() == String || where.type() == Code) { Status s = exp->init(where.valuestr()); if (!s.isOK()) return StatusWithMatchExpression(s); return StatusWithMatchExpression(exp.release()); } if (where.type() == CodeWScope) { Status s = exp->init(where.codeWScopeCode()); if (!s.isOK()) return StatusWithMatchExpression(s); return StatusWithMatchExpression(exp.release()); } return StatusWithMatchExpression(ErrorCodes::BadValue, "$where got bad type"); }
void BSONElementHasher::recursiveHash( Hasher* h , const BSONElement& e , bool includeFieldName ) { int canonicalType = e.canonicalType(); h->addData( &canonicalType , sizeof( canonicalType ) ); if ( includeFieldName ){ h->addData( e.fieldName() , e.fieldNameSize() ); } if ( !e.mayEncapsulate() ){ //if there are no embedded objects (subobjects or arrays), //compute the hash, squashing numeric types to 64-bit ints if ( e.isNumber() ){ long long int i = e.safeNumberLong(); //well-defined for troublesome doubles h->addData( &i , sizeof( i ) ); } else { h->addData( e.value() , e.valuesize() ); } } else { //else identify the subobject. //hash any preceding stuff (in the case of codeWscope) //then each sub-element //then finish with the EOO element. BSONObj b; if ( e.type() == CodeWScope ) { h->addData( e.codeWScopeCode() , e.codeWScopeCodeLen() ); b = e.codeWScopeObject(); } else { b = e.embeddedObject(); } BSONObjIterator i(b); while( i.moreWithEOO() ) { BSONElement el = i.next(); recursiveHash( h , el , true ); } } }
StatusWithMatchExpression WhereCallbackReal::parseWhere(const BSONElement& where) const { if (!globalScriptEngine) return StatusWithMatchExpression(ErrorCodes::BadValue, "no globalScriptEngine in $where parsing"); auto_ptr<WhereMatchExpression> exp(new WhereMatchExpression(_txn)); if (where.type() == String || where.type() == Code) { Status s = exp->init(_dbName, where.valuestr(), BSONObj()); if (!s.isOK()) return StatusWithMatchExpression(s); return StatusWithMatchExpression(exp.release()); } if (where.type() == CodeWScope) { Status s = exp->init(_dbName, where.codeWScopeCode(), BSONObj(where.codeWScopeScopeDataUnsafe())); if (!s.isOK()) return StatusWithMatchExpression(s); return StatusWithMatchExpression(exp.release()); } return StatusWithMatchExpression(ErrorCodes::BadValue, "$where got bad type"); }
bool dbEval(const string& dbName, BSONObj& cmd, BSONObjBuilder& result, string& errmsg) { BSONElement e = cmd.firstElement(); uassert( 10046 , "eval needs Code" , e.type() == Code || e.type() == CodeWScope || e.type() == String ); const char *code = 0; switch ( e.type() ) { case String: case Code: code = e.valuestr(); break; case CodeWScope: code = e.codeWScopeCode(); break; default: verify(0); } verify( code ); if ( ! globalScriptEngine ) { errmsg = "db side execution is disabled"; return false; } auto_ptr<Scope> s = globalScriptEngine->getPooledScope( dbName, "dbeval" ); ScriptingFunction f = s->createFunction(code); if ( f == 0 ) { errmsg = (string)"compile failed: " + s->getError(); return false; } if ( e.type() == CodeWScope ) s->init( e.codeWScopeScopeDataUnsafe() ); s->localConnect( dbName.c_str() ); BSONObj args; { BSONElement argsElement = cmd.getField("args"); if ( argsElement.type() == Array ) { args = argsElement.embeddedObject(); if ( edebug ) { out() << "args:" << args.toString() << endl; out() << "code:\n" << code << endl; } } } int res; { Timer t; res = s->invoke(f, &args, 0, cmdLine.quota ? 10 * 60 * 1000 : 0 ); int m = t.millis(); if ( m > cmdLine.slowMS ) { out() << "dbeval slow, time: " << dec << m << "ms " << dbName << endl; if ( m >= 1000 ) log() << code << endl; else OCCASIONALLY log() << code << endl; } } if (res || s->isLastRetNativeCode()) { result.append("errno", (double) res); errmsg = "invoke failed: "; if (s->isLastRetNativeCode()) errmsg += "cannot return native function"; else errmsg += s->getError(); return false; } s->append( result , "retval" , "__returnValue" ); return true; }
/* must be same type when called, unless both sides are #s */ int compareElementValues(const BSONElement& l, const BSONElement& r) { int f; double x; switch ( l.type() ) { case EOO: case Undefined: case jstNULL: case MaxKey: case MinKey: f = l.type() - r.type(); if ( f<0 ) return -1; return f==0 ? 0 : 1; case Bool: return *l.value() - *r.value(); case Timestamp: case Date: if ( l.date() < r.date() ) return -1; return l.date() == r.date() ? 0 : 1; case NumberLong: if( r.type() == NumberLong ) { long long L = l._numberLong(); long long R = r._numberLong(); if( L < R ) return -1; if( L == R ) return 0; return 1; } // else fall through case NumberInt: case NumberDouble: { double left = l.number(); double right = r.number(); bool lNan = !( left <= numeric_limits< double >::max() && left >= -numeric_limits< double >::max() ); bool rNan = !( right <= numeric_limits< double >::max() && right >= -numeric_limits< double >::max() ); if ( lNan ) { if ( rNan ) { return 0; } else { return -1; } } else if ( rNan ) { return 1; } x = left - right; if ( x < 0 ) return -1; return x == 0 ? 0 : 1; } case jstOID: return memcmp(l.value(), r.value(), 12); case Code: case Symbol: case String: /* todo: utf version */ return strcmp(l.valuestr(), r.valuestr()); case Object: case Array: return l.embeddedObject().woCompare( r.embeddedObject() ); case DBRef: case BinData: { int lsz = l.valuesize(); int rsz = r.valuesize(); if ( lsz - rsz != 0 ) return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case RegEx: { int c = strcmp(l.regex(), r.regex()); if ( c ) return c; return strcmp(l.regexFlags(), r.regexFlags()); } case CodeWScope : { f = l.type() - r.type(); if ( f ) return f; f = strcmp( l.codeWScopeCode() , r.codeWScopeCode() ); if ( f ) return f; f = strcmp( l.codeWScopeScopeData() , r.codeWScopeScopeData() ); if ( f ) return f; return 0; } default: out() << "compareElementValues: bad type " << (int) l.type() << endl; assert(false); } return -1; }
bool dbEval(const char *ns, BSONObj& cmd, BSONObjBuilder& result, string& errmsg) { BSONElement e = cmd.firstElement(); uassert( "eval needs Code" , e.type() == Code || e.type() == CodeWScope || e.type() == String ); const char *code = 0; switch ( e.type() ) { case String: case Code: code = e.valuestr(); break; case CodeWScope: code = e.codeWScopeCode(); break; default: assert(0); } assert( code ); if ( ! globalScriptEngine ) { errmsg = "db side execution is disabled"; return false; } auto_ptr<Scope> s = globalScriptEngine->getPooledScope( ns ); ScriptingFunction f = s->createFunction(code); if ( f == 0 ) { errmsg = (string)"compile failed: " + s->getError(); return false; } if ( e.type() == CodeWScope ) s->init( e.codeWScopeScopeData() ); s->localConnect( database->name.c_str() ); BSONObj args; { BSONElement argsElement = cmd.findElement("args"); if ( argsElement.type() == Array ) { args = argsElement.embeddedObject(); if ( edebug ) { out() << "args:" << args.toString() << endl; out() << "code:\n" << code << endl; } } } int res; { Timer t; res = s->invoke(f,args, 10 * 60 * 1000); int m = t.millis(); if ( m > 100 ) { out() << "dbeval slow, time: " << dec << m << "ms " << ns << endl; if ( m >= 1000 ) log() << code << endl; else OCCASIONALLY log() << code << endl; } } if ( res ) { result.append("errno", (double) res); errmsg = "invoke failed: "; errmsg += s->getError(); return false; } s->append( result , "retval" , "return" ); return true; }
void BSONComparatorInterfaceBase<T>::hashCombineBSONElement( size_t& hash, BSONElement elemToHash, bool considerFieldName, const StringData::ComparatorInterface* stringComparator) { boost::hash_combine(hash, elemToHash.canonicalType()); const StringData fieldName = elemToHash.fieldNameStringData(); if (considerFieldName && !fieldName.empty()) { SimpleStringDataComparator::kInstance.hash_combine(hash, fieldName); } switch (elemToHash.type()) { // Order of types is the same as in compareElementValues(). case mongo::EOO: case mongo::Undefined: case mongo::jstNULL: case mongo::MaxKey: case mongo::MinKey: // These are valueless types break; case mongo::Bool: boost::hash_combine(hash, elemToHash.boolean()); break; case mongo::bsonTimestamp: boost::hash_combine(hash, elemToHash.timestamp().asULL()); break; case mongo::Date: boost::hash_combine(hash, elemToHash.date().asInt64()); break; case mongo::NumberDecimal: { const Decimal128 dcml = elemToHash.numberDecimal(); if (dcml.toAbs().isGreater(Decimal128(std::numeric_limits<double>::max(), Decimal128::kRoundTo34Digits, Decimal128::kRoundTowardZero)) && !dcml.isInfinite() && !dcml.isNaN()) { // Normalize our decimal to force equivalent decimals // in the same cohort to hash to the same value Decimal128 dcmlNorm(dcml.normalize()); boost::hash_combine(hash, dcmlNorm.getValue().low64); boost::hash_combine(hash, dcmlNorm.getValue().high64); break; } // Else, fall through and convert the decimal to a double and hash. // At this point the decimal fits into the range of doubles, is infinity, or is NaN, // which doubles have a cheaper representation for. } case mongo::NumberDouble: case mongo::NumberLong: case mongo::NumberInt: { // This converts all numbers to doubles, which ignores the low-order bits of // NumberLongs > 2**53 and precise decimal numbers without double representations, // but that is ok since the hash will still be the same for equal numbers and is // still likely to be different for different numbers. (Note: this issue only // applies for decimals when they are outside of the valid double range. See // the above case.) // SERVER-16851 const double dbl = elemToHash.numberDouble(); if (std::isnan(dbl)) { boost::hash_combine(hash, std::numeric_limits<double>::quiet_NaN()); } else { boost::hash_combine(hash, dbl); } break; } case mongo::jstOID: elemToHash.__oid().hash_combine(hash); break; case mongo::String: { if (stringComparator) { stringComparator->hash_combine(hash, elemToHash.valueStringData()); } else { SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.valueStringData()); } break; } case mongo::Code: case mongo::Symbol: SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.valueStringData()); break; case mongo::Object: case mongo::Array: hashCombineBSONObj(hash, elemToHash.embeddedObject(), true, // considerFieldName stringComparator); break; case mongo::DBRef: case mongo::BinData: // All bytes of the value are required to be identical. SimpleStringDataComparator::kInstance.hash_combine( hash, StringData(elemToHash.value(), elemToHash.valuesize())); break; case mongo::RegEx: SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.regex()); SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.regexFlags()); break; case mongo::CodeWScope: { SimpleStringDataComparator::kInstance.hash_combine( hash, StringData(elemToHash.codeWScopeCode(), elemToHash.codeWScopeCodeLen())); hashCombineBSONObj(hash, elemToHash.codeWScopeObject(), true, // considerFieldName &SimpleStringDataComparator::kInstance); break; } } }
int BSONElement::compareElements(const BSONElement& l, const BSONElement& r, ComparisonRulesSet rules, const StringData::ComparatorInterface* comparator) { switch (l.type()) { case BSONType::EOO: case BSONType::Undefined: // EOO and Undefined are same canonicalType case BSONType::jstNULL: case BSONType::MaxKey: case BSONType::MinKey: { auto f = l.canonicalType() - r.canonicalType(); if (f < 0) return -1; return f == 0 ? 0 : 1; } case BSONType::Bool: return *l.value() - *r.value(); case BSONType::bsonTimestamp: // unsigned compare for timestamps - note they are not really dates but (ordinal + // time_t) if (l.timestamp() < r.timestamp()) return -1; return l.timestamp() == r.timestamp() ? 0 : 1; case BSONType::Date: // Signed comparisons for Dates. { const Date_t a = l.Date(); const Date_t b = r.Date(); if (a < b) return -1; return a == b ? 0 : 1; } case BSONType::NumberInt: { // All types can precisely represent all NumberInts, so it is safe to simply convert to // whatever rhs's type is. switch (r.type()) { case NumberInt: return compareInts(l._numberInt(), r._numberInt()); case NumberLong: return compareLongs(l._numberInt(), r._numberLong()); case NumberDouble: return compareDoubles(l._numberInt(), r._numberDouble()); case NumberDecimal: return compareIntToDecimal(l._numberInt(), r._numberDecimal()); default: MONGO_UNREACHABLE; } } case BSONType::NumberLong: { switch (r.type()) { case NumberLong: return compareLongs(l._numberLong(), r._numberLong()); case NumberInt: return compareLongs(l._numberLong(), r._numberInt()); case NumberDouble: return compareLongToDouble(l._numberLong(), r._numberDouble()); case NumberDecimal: return compareLongToDecimal(l._numberLong(), r._numberDecimal()); default: MONGO_UNREACHABLE; } } case BSONType::NumberDouble: { switch (r.type()) { case NumberDouble: return compareDoubles(l._numberDouble(), r._numberDouble()); case NumberInt: return compareDoubles(l._numberDouble(), r._numberInt()); case NumberLong: return compareDoubleToLong(l._numberDouble(), r._numberLong()); case NumberDecimal: return compareDoubleToDecimal(l._numberDouble(), r._numberDecimal()); default: MONGO_UNREACHABLE; } } case BSONType::NumberDecimal: { switch (r.type()) { case NumberDecimal: return compareDecimals(l._numberDecimal(), r._numberDecimal()); case NumberInt: return compareDecimalToInt(l._numberDecimal(), r._numberInt()); case NumberLong: return compareDecimalToLong(l._numberDecimal(), r._numberLong()); case NumberDouble: return compareDecimalToDouble(l._numberDecimal(), r._numberDouble()); default: MONGO_UNREACHABLE; } } case BSONType::jstOID: return memcmp(l.value(), r.value(), OID::kOIDSize); case BSONType::Code: return compareElementStringValues(l, r); case BSONType::Symbol: case BSONType::String: { if (comparator) { return comparator->compare(l.valueStringData(), r.valueStringData()); } else { return compareElementStringValues(l, r); } } case BSONType::Object: case BSONType::Array: { return l.embeddedObject().woCompare( r.embeddedObject(), BSONObj(), rules | BSONElement::ComparisonRules::kConsiderFieldName, comparator); } case BSONType::DBRef: { int lsz = l.valuesize(); int rsz = r.valuesize(); if (lsz - rsz != 0) return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case BSONType::BinData: { int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte int rsz = r.objsize(); if (lsz - rsz != 0) return lsz - rsz; return memcmp(l.value() + 4, r.value() + 4, lsz + 1 /*+1 for subtype byte*/); } case BSONType::RegEx: { int c = strcmp(l.regex(), r.regex()); if (c) return c; return strcmp(l.regexFlags(), r.regexFlags()); } case BSONType::CodeWScope: { int cmp = StringData(l.codeWScopeCode(), l.codeWScopeCodeLen() - 1) .compare(StringData(r.codeWScopeCode(), r.codeWScopeCodeLen() - 1)); if (cmp) return cmp; // When comparing the scope object, we should consider field names. Special string // comparison semantics do not apply to strings nested inside the CodeWScope scope // object, so we do not pass through the string comparator. return l.codeWScopeObject().woCompare( r.codeWScopeObject(), BSONObj(), rules | BSONElement::ComparisonRules::kConsiderFieldName); } } MONGO_UNREACHABLE; }
Handle<v8::Value> mongoToV8Element( const BSONElement &f ) { Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New(); internalFieldObjects->SetInternalFieldCount( 1 ); switch ( f.type() ){ case mongo::Code: return newFunction( f.valuestr() ); case CodeWScope: if ( f.codeWScopeObject().isEmpty() ) log() << "warning: CodeWScope doesn't transfer to db.eval" << endl; return newFunction( f.codeWScopeCode() ); case mongo::String: return v8::String::New( f.valuestr() ); case mongo::jstOID: return newId( f.__oid() ); case mongo::NumberDouble: case mongo::NumberInt: return v8::Number::New( f.number() ); case mongo::Array: case mongo::Object: return mongoToV8( f.embeddedObject() , f.type() == mongo::Array ); case mongo::Date: return v8::Date::New( f.date() ); case mongo::Bool: return v8::Boolean::New( f.boolean() ); case mongo::EOO: case mongo::jstNULL: case mongo::Undefined: // duplicate sm behavior return v8::Null(); case mongo::RegEx: { v8::Function * regex = getNamedCons( "RegExp" ); v8::Handle<v8::Value> argv[2]; argv[0] = v8::String::New( f.regex() ); argv[1] = v8::String::New( f.regexFlags() ); return regex->NewInstance( 2 , argv ); break; } case mongo::BinData: { int len; const char *data = f.binData( len ); v8::Function* binData = getNamedCons( "BinData" ); v8::Handle<v8::Value> argv[3]; argv[0] = v8::Number::New( len ); argv[1] = v8::Number::New( f.binDataType() ); argv[2] = v8::String::New( data, len ); return binData->NewInstance( 3, argv ); }; case mongo::Timestamp: { Local<v8::Object> sub = internalFieldObjects->NewInstance(); sub->Set( v8::String::New( "time" ) , v8::Date::New( f.timestampTime() ) ); sub->Set( v8::String::New( "i" ) , v8::Number::New( f.timestampInc() ) ); sub->SetInternalField( 0, v8::Uint32::New( f.type() ) ); return sub; } case mongo::NumberLong: { Local<v8::Object> sub = internalFieldObjects->NewInstance(); unsigned long long val = f.numberLong(); v8::Function* numberLong = getNamedCons( "NumberLong" ); v8::Handle<v8::Value> 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<v8::Object> sub = internalFieldObjects->NewInstance(); sub->Set( v8::String::New( "$MinKey" ), v8::Boolean::New( true ) ); sub->SetInternalField( 0, v8::Uint32::New( f.type() ) ); return sub; } case mongo::MaxKey: { Local<v8::Object> sub = internalFieldObjects->NewInstance(); sub->Set( v8::String::New( "$MaxKey" ), v8::Boolean::New( true ) ); sub->SetInternalField( 0, v8::Uint32::New( f.type() ) ); return sub; } case mongo::DBRef: { v8::Function* dbPointer = getNamedCons( "DBPointer" ); v8::Handle<v8::Value> argv[2]; argv[0] = v8::String::New( f.dbrefNS() ); argv[1] = newId( f.dbrefOID() ); return dbPointer->NewInstance(2, argv); } default: cout << "can't handle type: "; cout << f.type() << " "; cout << f.toString(); cout << endl; break; } return v8::Undefined(); }
jsval toval( const BSONElement& e ) { switch( e.type() ) { case EOO: case jstNULL: case Undefined: return JSVAL_NULL; case NumberDouble: case NumberInt: return toval( e.number() ); case Symbol: // TODO: should we make a special class for this case String: return toval( e.valuestr() ); case Bool: return e.boolean() ? JSVAL_TRUE : JSVAL_FALSE; case Object: { BSONObj embed = e.embeddedObject().getOwned(); return toval( &embed ); } case Array: { BSONObj embed = e.embeddedObject().getOwned(); if ( embed.isEmpty() ) { return OBJECT_TO_JSVAL( JS_NewArrayObject( _context , 0 , 0 ) ); } int n = embed.nFields(); JSObject * array = JS_NewArrayObject( _context , n , 0 ); assert( array ); jsval myarray = OBJECT_TO_JSVAL( array ); for ( int i=0; i<n; i++ ) { jsval v = toval( embed[i] ); assert( JS_SetElement( _context , array , i , &v ) ); } return myarray; } case jstOID: { OID oid = e.__oid(); JSObject * o = JS_NewObject( _context , &object_id_class , 0 , 0 ); setProperty( o , "str" , toval( oid.str().c_str() ) ); return OBJECT_TO_JSVAL( o ); } case RegEx: { const char * flags = e.regexFlags(); uintN flagNumber = 0; while ( *flags ) { switch ( *flags ) { case 'g': flagNumber |= JSREG_GLOB; break; case 'i': flagNumber |= JSREG_FOLD; break; case 'm': flagNumber |= JSREG_MULTILINE; break; //case 'y': flagNumber |= JSREG_STICKY; break; default: log() << "warning: unknown regex flag:" << *flags << endl; } flags++; } JSObject * r = JS_NewRegExpObject( _context , (char*)e.regex() , strlen( e.regex() ) , flagNumber ); assert( r ); return OBJECT_TO_JSVAL( r ); } case Code: { JSFunction * func = compileFunction( e.valuestr() ); return OBJECT_TO_JSVAL( JS_GetFunctionObject( func ) ); } case CodeWScope: { JSFunction * func = compileFunction( e.codeWScopeCode() ); BSONObj extraScope = e.codeWScopeObject(); if ( ! extraScope.isEmpty() ) { log() << "warning: CodeWScope doesn't transfer to db.eval" << endl; } return OBJECT_TO_JSVAL( JS_GetFunctionObject( func ) ); } case Date: return OBJECT_TO_JSVAL( js_NewDateObjectMsec( _context , (jsdouble) e.date().millis ) ); case MinKey: return OBJECT_TO_JSVAL( JS_NewObject( _context , &minkey_class , 0 , 0 ) ); case MaxKey: return OBJECT_TO_JSVAL( JS_NewObject( _context , &maxkey_class , 0 , 0 ) ); case Timestamp: { JSObject * o = JS_NewObject( _context , ×tamp_class , 0 , 0 ); setProperty( o , "t" , toval( (double)(e.timestampTime()) ) ); setProperty( o , "i" , toval( (double)(e.timestampInc()) ) ); 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 ); 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 ); } case DBRef: { JSObject * o = JS_NewObject( _context , &dbpointer_class , 0 , 0 ); setProperty( o , "ns" , toval( e.dbrefNS() ) ); JSObject * oid = JS_NewObject( _context , &object_id_class , 0 , 0 ); setProperty( oid , "str" , toval( e.dbrefOID().str().c_str() ) ); setProperty( o , "id" , OBJECT_TO_JSVAL( oid ) ); return OBJECT_TO_JSVAL( o ); } case BinData: { JSObject * o = JS_NewObject( _context , &bindata_class , 0 , 0 ); int len; 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() ) ); return OBJECT_TO_JSVAL( o ); } }