summaryrefslogtreecommitdiff
path: root/db/jsobj.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/jsobj.cpp')
-rw-r--r--db/jsobj.cpp733
1 files changed, 265 insertions, 468 deletions
diff --git a/db/jsobj.cpp b/db/jsobj.cpp
index 9f9a684..9f613c7 100644
--- a/db/jsobj.cpp
+++ b/db/jsobj.cpp
@@ -17,11 +17,10 @@
* limitations under the License.
*/
-#include "stdafx.h"
+#include "pch.h"
#include "jsobj.h"
#include "nonce.h"
-#include "../util/atomic_int.h"
-#include "../util/goodies.h"
+#include "../bson/util/atomic_int.h"
#include "../util/base64.h"
#include "../util/md5.hpp"
#include <limits>
@@ -31,9 +30,8 @@
#include "jsobjmanipulator.h"
#include "../util/optime.h"
#include <boost/static_assert.hpp>
-#include <boost/any.hpp>
#undef assert
-#define assert xassert
+#define assert MONGO_assert
// make sure our assumptions are valid
BOOST_STATIC_ASSERT( sizeof(int) == 4 );
@@ -46,114 +44,12 @@ namespace mongo {
BSONElement nullElement;
- ostream& operator<<( ostream &s, const OID &o ) {
- s << o.str();
- return s;
- }
-
- IDLabeler GENOID;
+ GENOIDLabeler GENOID;
DateNowLabeler DATENOW;
- string BSONElement::toString( bool includeFieldName ) const {
- stringstream s;
- if ( includeFieldName && type() != EOO )
- s << fieldName() << ": ";
- switch ( type() ) {
- case EOO:
- return "EOO";
- case Date:
- s << "new Date(" << date() << ')';
- break;
- case RegEx:
- {
- s << "/" << regex() << '/';
- const char *p = regexFlags();
- if ( p ) s << p;
- }
- break;
- case NumberDouble:
- {
- stringstream tmp;
- tmp.precision( 16 );
- tmp << number();
- string n = tmp.str();
- s << n;
- // indicate this is a double:
- if( strchr(n.c_str(), '.') == 0 && strchr(n.c_str(), 'E') == 0 && strchr(n.c_str(), 'N') == 0 )
- s << ".0";
- }
- break;
- case NumberLong:
- s << _numberLong();
- break;
- case NumberInt:
- s << _numberInt();
- break;
- case Bool:
- s << ( boolean() ? "true" : "false" );
- break;
- case Object:
- case Array:
- s << embeddedObject().toString();
- break;
- case Undefined:
- s << "undefined";
- break;
- case jstNULL:
- s << "null";
- break;
- case MaxKey:
- s << "MaxKey";
- break;
- case MinKey:
- s << "MinKey";
- break;
- case CodeWScope:
- s << "CodeWScope( "
- << codeWScopeCode() << ", " << codeWScopeObject().toString() << ")";
- break;
- case Code:
- if ( valuestrsize() > 80 )
- s << string(valuestr()).substr(0, 70) << "...";
- else {
- s << valuestr();
- }
- break;
- case Symbol:
- case String:
- if ( valuestrsize() > 80 )
- s << '"' << string(valuestr()).substr(0, 70) << "...\"";
- else {
- s << '"' << valuestr() << '"';
- }
- break;
- case DBRef:
- s << "DBRef('" << valuestr() << "',";
- {
- OID *x = (OID *) (valuestr() + valuestrsize());
- s << *x << ')';
- }
- break;
- case jstOID:
- s << "ObjId(";
- s << __oid() << ')';
- break;
- case BinData:
- s << "BinData";
- break;
- case Timestamp:
- s << "Timestamp " << timestampTime() << "|" << timestampInc();
- break;
- default:
- s << "?type=" << type();
- break;
- }
- return s.str();
- }
-
string escape( string s , bool escape_slash=false) {
- stringstream ret;
+ StringBuilder ret;
for ( string::iterator i = s.begin(); i != s.end(); ++i ) {
switch ( *i ) {
case '"':
@@ -182,11 +78,9 @@ namespace mongo {
break;
default:
if ( *i >= 0 && *i <= 0x1f ) {
- ret << "\\u";
- ret << hex;
- ret.width( 4 );
- ret.fill( '0' );
- ret << int( *i );
+ //TODO: these should be utf16 code-units not bytes
+ char c = *i;
+ ret << "\\u00" << toHexLower(&c, 1);
} else {
ret << *i;
}
@@ -195,14 +89,18 @@ namespace mongo {
return ret.str();
}
- string BSONElement::jsonString( JsonStringFormat format, bool includeFieldNames ) const {
+ string BSONElement::jsonString( JsonStringFormat format, bool includeFieldNames, int pretty ) const {
+ BSONType t = type();
+ if ( t == Undefined )
+ return "";
+
stringstream s;
if ( includeFieldNames )
s << '"' << escape( fieldName() ) << "\" : ";
switch ( type() ) {
- case String:
+ case mongo::String:
case Symbol:
- s << '"' << escape( valuestr() ) << '"';
+ s << '"' << escape( string(valuestr(), valuestrsize()-1) ) << '"';
break;
case NumberLong:
s << _numberLong();
@@ -214,22 +112,22 @@ namespace mongo {
s.precision( 16 );
s << number();
} else {
- stringstream ss;
+ StringBuilder ss;
ss << "Number " << number() << " cannot be represented in JSON";
string message = ss.str();
massert( 10311 , message.c_str(), false );
}
break;
- case Bool:
+ case mongo::Bool:
s << ( boolean() ? "true" : "false" );
break;
case jstNULL:
s << "null";
break;
case Object:
- s << embeddedObject().jsonString( format );
+ s << embeddedObject().jsonString( format, pretty );
break;
- case Array: {
+ case mongo::Array: {
if ( embeddedObject().isEmpty() ) {
s << "[]";
break;
@@ -239,7 +137,12 @@ namespace mongo {
BSONElement e = i.next();
if ( !e.eoo() )
while ( 1 ) {
- s << e.jsonString( format, false );
+ if( pretty ) {
+ s << '\n';
+ for( int x = 0; x < pretty; x++ )
+ s << " ";
+ }
+ s << e.jsonString( format, false, pretty?pretty+1:0 );
e = i.next();
if ( e.eoo() )
break;
@@ -249,7 +152,7 @@ namespace mongo {
break;
}
case DBRef: {
- OID *x = (OID *) (valuestr() + valuestrsize());
+ mongo::OID *x = (mongo::OID *) (valuestr() + valuestrsize());
if ( format == TenGen )
s << "Dbref( ";
else
@@ -290,12 +193,18 @@ namespace mongo {
s << "\" }";
break;
}
- case Date:
+ case mongo::Date:
if ( format == Strict )
s << "{ \"$date\" : ";
else
s << "Date( ";
- s << date();
+ if( pretty ) {
+ Date_t d = date();
+ if( d == 0 ) s << '0';
+ else
+ s << '"' << date().toString() << '"';
+ } else
+ s << date();
if ( format == Strict )
s << " }";
else
@@ -321,16 +230,34 @@ namespace mongo {
}
break;
+ case CodeWScope: {
+ BSONObj scope = codeWScopeObject();
+ if ( ! scope.isEmpty() ){
+ s << "{ \"$code\" : " << _asCode() << " , "
+ << " \"$scope\" : " << scope.jsonString() << " }";
+ break;
+ }
+ }
+
+
case Code:
- s << ascode();
+ s << _asCode();
break;
-
+
case Timestamp:
s << "{ \"t\" : " << timestampTime() << " , \"i\" : " << timestampInc() << " }";
break;
+ case MinKey:
+ s << "{ \"$minKey\" : 1 }";
+ break;
+
+ case MaxKey:
+ s << "{ \"$maxKey\" : 1 }";
+ break;
+
default:
- stringstream ss;
+ StringBuilder ss;
ss << "Cannot create a properly formatted JSON string with "
<< "element: " << toString() << " of type: " << type();
string message = ss.str();
@@ -339,82 +266,6 @@ namespace mongo {
return s.str();
}
- int BSONElement::size( int maxLen ) const {
- if ( totalSize >= 0 )
- return totalSize;
-
- int remain = maxLen - fieldNameSize() - 1;
-
- int x = 0;
- switch ( type() ) {
- case EOO:
- case Undefined:
- case jstNULL:
- case MaxKey:
- case MinKey:
- break;
- case Bool:
- x = 1;
- break;
- case NumberInt:
- x = 4;
- break;
- case Timestamp:
- case Date:
- case NumberDouble:
- case NumberLong:
- x = 8;
- break;
- case jstOID:
- x = 12;
- break;
- case Symbol:
- case Code:
- case String:
- massert( 10313 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 );
- x = valuestrsize() + 4;
- break;
- case CodeWScope:
- massert( 10314 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 );
- x = objsize();
- break;
-
- case DBRef:
- massert( 10315 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 );
- x = valuestrsize() + 4 + 12;
- break;
- case Object:
- case Array:
- massert( 10316 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 );
- x = objsize();
- break;
- case BinData:
- massert( 10317 , "Insufficient bytes to calculate element size", maxLen == -1 || remain > 3 );
- x = valuestrsize() + 4 + 1/*subtype*/;
- break;
- case RegEx:
- {
- const char *p = value();
- int len1 = ( maxLen == -1 ) ? strlen( p ) : strnlen( p, remain );
- massert( 10318 , "Invalid regex string", len1 != -1 );
- p = p + len1 + 1;
- int len2 = ( maxLen == -1 ) ? strlen( p ) : strnlen( p, remain - len1 - 1 );
- massert( 10319 , "Invalid regex options string", len2 != -1 );
- x = len1 + 1 + len2 + 1;
- }
- break;
- default: {
- stringstream ss;
- ss << "BSONElement: bad type " << (int) type();
- string msg = ss.str();
- massert( 10320 , msg.c_str(),false);
- }
- }
- totalSize = x + fieldNameSize() + 1; // BSONType
-
- return totalSize;
- }
-
int BSONElement::getGtLtOp( int def ) const {
const char *fn = fieldName();
if ( fn[0] == '$' && fn[1] ) {
@@ -434,8 +285,12 @@ namespace mongo {
if ( fn[3] == 'a' && fn[4] == 'r' && fn[5] == 0 )
return BSONObj::opNEAR;
}
- else if ( fn[1] == 'm' && fn[2] == 'o' && fn[3] == 'd' && fn[4] == 0 )
- return BSONObj::opMOD;
+ else if ( fn[1] == 'm' ){
+ if ( fn[2] == 'o' && fn[3] == 'd' && fn[4] == 0 )
+ return BSONObj::opMOD;
+ if ( fn[2] == 'a' && fn[3] == 'x' && fn[4] == 'D' && fn[5] == 'i' && fn[6] == 's' && fn[7] == 't' && fn[8] == 'a' && fn[9] == 'n' && fn[10] == 'c' && fn[11] == 'e' && fn[12] == 0 )
+ return BSONObj::opMAX_DISTANCE;
+ }
else if ( fn[1] == 't' && fn[2] == 'y' && fn[3] == 'p' && fn[4] == 'e' && fn[5] == 0 )
return BSONObj::opTYPE;
else if ( fn[1] == 'i' && fn[2] == 'n' && fn[3] == 0 )
@@ -579,40 +434,6 @@ namespace mongo {
return -1;
}
- void BSONElement::validate() const {
- switch( type() ) {
- case DBRef:
- case Code:
- case Symbol:
- case String: {
- int x = valuestrsize();
- if ( x > 0 && valuestr()[x-1] == 0 )
- return;
- StringBuilder buf;
- buf << "Invalid dbref/code/string/symbol size: " << x << " strnlen:" << strnlen( valuestr() , x );
- massert( 10321 , buf.str() , 0 );
- break;
- }
- case CodeWScope: {
- int totalSize = *( int * )( value() );
- massert( 10322 , "Invalid CodeWScope size", totalSize >= 8 );
- int strSizeWNull = *( int * )( value() + 4 );
- massert( 10323 , "Invalid CodeWScope string size", totalSize >= strSizeWNull + 4 + 4 );
- massert( 10324 , "Invalid CodeWScope string size",
- strSizeWNull > 0 &&
- strSizeWNull - 1 == strnlen( codeWScopeCode(), strSizeWNull ) );
- massert( 10325 , "Invalid CodeWScope size", totalSize >= strSizeWNull + 4 + 4 + 4 );
- int objSize = *( int * )( value() + 4 + 4 + strSizeWNull );
- massert( 10326 , "Invalid CodeWScope object size", totalSize == 4 + 4 + strSizeWNull + objSize );
- // Subobject validation handled elsewhere.
- }
- case Object:
- // We expect Object size validation to be handled elsewhere.
- default:
- break;
- }
- }
-
/* Matcher --------------------------------------*/
// If the element is something like:
@@ -676,39 +497,6 @@ namespace mongo {
/* BSONObj ------------------------------------------------------------*/
- BSONObj::EmptyObject BSONObj::emptyObject;
-
- string BSONObj::toString() const {
- if ( isEmpty() ) return "{}";
-
- stringstream s;
- s << "{ ";
- BSONObjIterator i(*this);
- bool first = true;
- while ( 1 ) {
- massert( 10327 , "Object does not end with EOO", i.moreWithEOO() );
- BSONElement e = i.next( true );
- massert( 10328 , "Invalid element size", e.size() > 0 );
- massert( 10329 , "Element too large", e.size() < ( 1 << 30 ) );
- int offset = e.rawdata() - this->objdata();
- massert( 10330 , "Element extends past end of object",
- e.size() + offset <= this->objsize() );
- e.validate();
- bool end = ( e.size() + offset == this->objsize() );
- if ( e.eoo() ) {
- massert( 10331 , "EOO Before end of object", end );
- break;
- }
- if ( first )
- first = false;
- else
- s << ", ";
- s << e.toString();
- }
- s << " }";
- return s.str();
- }
-
string BSONObj::md5() const {
md5digest d;
md5_state_t st;
@@ -718,21 +506,29 @@ namespace mongo {
return digestToString( d );
}
- string BSONObj::jsonString( JsonStringFormat format ) const {
+ string BSONObj::jsonString( JsonStringFormat format, int pretty ) const {
if ( isEmpty() ) return "{}";
- stringstream s;
+ StringBuilder s;
s << "{ ";
BSONObjIterator i(*this);
BSONElement e = i.next();
if ( !e.eoo() )
while ( 1 ) {
- s << e.jsonString( format );
+ s << e.jsonString( format, true, pretty?pretty+1:0 );
e = i.next();
if ( e.eoo() )
break;
- s << ", ";
+ s << ",";
+ if ( pretty ) {
+ s << '\n';
+ for( int x = 0; x < pretty; x++ )
+ s << " ";
+ }
+ else {
+ s << " ";
+ }
}
s << " }";
return s.str();
@@ -740,13 +536,60 @@ namespace mongo {
// todo: can be a little faster if we don't use toString() here.
bool BSONObj::valid() const {
- try {
- toString();
+ try{
+ BSONObjIterator it(*this);
+ while( it.moreWithEOO() ){
+ // both throw exception on failure
+ BSONElement e = it.next(true);
+ e.validate();
+
+ if (e.eoo()){
+ if (it.moreWithEOO())
+ return false;
+ return true;
+ }else if (e.isABSONObj()){
+ if(!e.embeddedObject().valid())
+ return false;
+ }else if (e.type() == CodeWScope){
+ if(!e.codeWScopeObject().valid())
+ return false;
+ }
+ }
+ } catch (...) {
}
- catch (...) {
- return false;
+ return false;
+ }
+
+ int BSONObj::woCompare(const BSONObj& r, const Ordering &o, bool considerFieldName) const {
+ if ( isEmpty() )
+ return r.isEmpty() ? 0 : -1;
+ if ( r.isEmpty() )
+ return 1;
+
+ BSONObjIterator i(*this);
+ BSONObjIterator j(r);
+ unsigned mask = 1;
+ while ( 1 ) {
+ // so far, equal...
+
+ BSONElement l = i.next();
+ BSONElement r = j.next();
+ if ( l.eoo() )
+ return r.eoo() ? 0 : -1;
+ if ( r.eoo() )
+ return 1;
+
+ int x;
+ {
+ x = l.woCompare( r, considerFieldName );
+ if( o.descending(mask) )
+ x = -x;
+ }
+ if ( x != 0 )
+ return x;
+ mask <<= 1;
}
- return true;
+ return -1;
}
/* well ordered compare */
@@ -796,7 +639,7 @@ namespace mongo {
BSONObj staticNull = fromjson( "{'':null}" );
/* well ordered compare */
- int BSONObj::woSortOrder(const BSONObj& other, const BSONObj& sortKey ) const{
+ int BSONObj::woSortOrder(const BSONObj& other, const BSONObj& sortKey , bool useDotted ) const{
if ( isEmpty() )
return other.isEmpty() ? 0 : -1;
if ( other.isEmpty() )
@@ -810,10 +653,10 @@ namespace mongo {
if ( f.eoo() )
return 0;
- BSONElement l = getField( f.fieldName() );
+ BSONElement l = useDotted ? getFieldDotted( f.fieldName() ) : getField( f.fieldName() );
if ( l.eoo() )
l = staticNull.firstElement();
- BSONElement r = other.getField( f.fieldName() );
+ BSONElement r = useDotted ? other.getFieldDotted( f.fieldName() ) : other.getField( f.fieldName() );
if ( r.eoo() )
r = staticNull.firstElement();
@@ -826,78 +669,46 @@ namespace mongo {
return -1;
}
-
- /* return has eoo() true if no match
- supports "." notation to reach into embedded objects
- */
- BSONElement BSONObj::getFieldDotted(const char *name) const {
+ void BSONObj::getFieldsDotted(const StringData& name, BSONElementSet &ret ) const {
BSONElement e = getField( name );
if ( e.eoo() ) {
- const char *p = strchr(name, '.');
+ const char *p = strchr(name.data(), '.');
if ( p ) {
- string left(name, p-name);
- BSONObj sub = getObjectField(left.c_str());
- return sub.isEmpty() ? nullElement : sub.getFieldDotted(p+1);
- }
- }
-
- return e;
- }
-
- void BSONObj::getFieldsDotted(const char *name, BSONElementSet &ret ) const {
- BSONObjIterator i(*this);
- while ( i.more() ){
- BSONElement e = i.next();
- FieldCompareResult cmp = compareDottedFieldNames( name , e.fieldName() );
- switch ( cmp ){
-
- case LEFT_BEFORE:
- case RIGHT_BEFORE:
- break;
-
- case RIGHT_SUBFIELD:
- assert(0);
- break;
-
- case LEFT_SUBFIELD: {
- const char * next = name + strlen( e.fieldName() ) + 1;
- bool allDigits = false;
- if ( isdigit( *next ) ){
- const char * temp = next + 1;
- while ( isdigit( *temp ) )
- temp++;
- allDigits = *temp == '.';
- }
-
- if ( e.type() == Object || allDigits ){
- e.embeddedObject().getFieldsDotted( next , ret );
- }
- else if ( e.type() == Array ){
- BSONObjIterator j( e.embeddedObject() );
- while ( j.more() ){
- BSONElement f = j.next();
- if ( f.type() == Object )
- f.embeddedObject().getFieldsDotted( next , ret );
+ string left(name.data(), p-name.data());
+ const char* next = p+1;
+ BSONElement e = getField( left.c_str() );
+
+ if (e.type() == Object){
+ e.embeddedObject().getFieldsDotted(next, ret);
+ } else if (e.type() == Array) {
+ bool allDigits = false;
+ if ( isdigit( *next ) ){
+ const char * temp = next + 1;
+ while ( isdigit( *temp ) )
+ temp++;
+ allDigits = *temp == '.';
}
+ if (allDigits) {
+ e.embeddedObject().getFieldsDotted(next, ret);
+ } else {
+ BSONObjIterator i(e.embeddedObject());
+ while ( i.more() ){
+ BSONElement e2 = i.next();
+ if (e2.type() == Object || e2.type() == Array)
+ e2.embeddedObject().getFieldsDotted(next, ret);
+ }
+ }
+ } else {
+ // do nothing: no match
}
- else {
- // intentially left blank, this means no match
- }
- return;
- }
-
- case SAME: {
- if ( e.type() == Array ){
- BSONObjIterator j( e.embeddedObject() );
- while ( j.more() )
- ret.insert( j.next() );
- }
- else {
- ret.insert( e );
- }
- return;
}
-
+ } else {
+ if (e.type() == Array){
+ BSONObjIterator i(e.embeddedObject());
+ while ( i.more() )
+ ret.insert(i.next());
+ } else {
+ ret.insert(e);
}
}
}
@@ -915,7 +726,7 @@ namespace mongo {
BSONElement sub = getField(left.c_str());
if ( sub.eoo() )
return nullElement;
- else if ( sub.type() == Array || strlen( name ) == 0 )
+ else if ( sub.type() == Array || name[0] == '\0')
return sub;
else if ( sub.type() == Object )
return sub.embeddedObject().getFieldDottedOrArray( name );
@@ -923,31 +734,6 @@ namespace mongo {
return nullElement;
}
- /* makes a new BSONObj with the fields specified in pattern.
- fields returned in the order they appear in pattern.
- if any field missing or undefined in the original object, that field
- in the output will be null.
-
- n^2 implementation bad if pattern and object have lots
- of fields - normally pattern doesn't so should be fine.
- */
- BSONObj BSONObj::extractFieldsDotted(BSONObj pattern) const {
- BSONObjBuilder b;
- BSONObjIterator i(pattern);
- while (i.more()) {
- BSONElement e = i.next();
- const char *name = e.fieldName();
-
- BSONElement x = getFieldDotted( name );
- if ( x.eoo() || x.type() == Undefined ) {
- b.appendNull(name);
- } else {
- b.appendAs(x, name);
- }
- }
- return b.done();
- }
-
/**
sets element field names to empty string
If a field in pattern is missing, it is omitted from the returned
@@ -1037,24 +823,6 @@ namespace mongo {
return e.type() == String ? e.valuestr() : "";
}
- BSONObj BSONObj::getObjectField(const char *name) const {
- BSONElement e = getField(name);
- BSONType t = e.type();
- return t == Object || t == Array ? e.embeddedObject() : BSONObj();
- }
-
- int BSONObj::nFields() const {
- int n = 0;
- BSONObjIterator i(*this);
- while ( i.moreWithEOO() ) {
- BSONElement e = i.next();
- if ( e.eoo() )
- break;
- n++;
- }
- return n;
- }
-
/* grab names of all the fields in this object */
int BSONObj::getFieldNames(set<string>& fields) const {
int n = 0;
@@ -1186,6 +954,18 @@ namespace mongo {
return true;
}
+ void BSONObj::dump() const {
+ out() << hex;
+ const char *p = objdata();
+ for ( int i = 0; i < objsize(); i++ ) {
+ out() << i << '\t' << ( 0xff & ( (unsigned) *p ) );
+ if ( *p >= 'A' && *p <= 'z' )
+ out() << '\t' << *p;
+ out() << endl;
+ p++;
+ }
+ }
+
string BSONObj::hexDump() const {
stringstream ss;
const char *d = objdata();
@@ -1202,14 +982,6 @@ namespace mongo {
return ss.str();
}
- ostream& operator<<( ostream &s, const BSONObj &o ) {
- return s << o.toString();
- }
-
- ostream& operator<<( ostream &s, const BSONElement &e ) {
- return s << e.toString();
- }
-
void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const string& base){
BSONObjIterator it(obj);
while (it.more()){
@@ -1219,7 +991,7 @@ namespace mongo {
nested2dotted(b, e.embeddedObject(), newbase);
}else{
string newbase = base + e.fieldName();
- b.appendAs(e, newbase.c_str());
+ b.appendAs(e, newbase);
}
}
}
@@ -1265,6 +1037,7 @@ namespace mongo {
} minkeydata;
BSONObj minKey((const char *) &minkeydata);
+/*
struct JSObj0 {
JSObj0() {
totsize = 5;
@@ -1273,14 +1046,9 @@ namespace mongo {
int totsize;
char eoo;
} js0;
+*/
#pragma pack()
- BSONElement::BSONElement() {
- data = &js0.eoo;
- fieldNameSize_ = 0;
- totalSize = 1;
- }
-
struct BsonUnitTest : public UnitTest {
void testRegex() {
@@ -1425,14 +1193,8 @@ namespace mongo {
}
*/
- unsigned OID::_machine = (unsigned) security.getNonceInitSafe();
- void OID::newState(){
- // using fresh Security object to avoid buffered devrandom
- _machine = (unsigned) Security().getNonce();
- }
-
void OID::init() {
- static AtomicUInt inc = (unsigned) security.getNonce();
+ static AtomicUInt inc = getRandomNumber();
unsigned t = (unsigned) time(0);
char *T = (char *) &t;
data[0] = T[3];
@@ -1451,31 +1213,45 @@ namespace mongo {
raw[3] = T[0];
}
+ unsigned OID::_machine = (unsigned) security.getNonceInitSafe();
+ void OID::newState(){
+ unsigned before = _machine;
+ // using fresh Security object to avoid buffered devrandom
+ _machine = (unsigned)security.getNonce();
+ assert( _machine != before );
+ }
+
void OID::init( string s ){
assert( s.size() == 24 );
const char *p = s.c_str();
- char buf[3];
- buf[2] = 0;
for( int i = 0; i < 12; i++ ) {
- buf[0] = p[0];
- buf[1] = p[1];
+ data[i] = fromHex(p);
p += 2;
- stringstream ss(buf);
- unsigned z;
- ss >> hex >> z;
- data[i] = z;
}
+ }
-/*
- string as = s.substr( 0 , 16 );
- string bs = s.substr( 16 );
+ void OID::init(Date_t date, bool max){
+ int time = (int) (date / 1000);
+ char* T = (char *) &time;
+ data[0] = T[3];
+ data[1] = T[2];
+ data[2] = T[1];
+ data[3] = T[0];
- stringstream ssa(as);
- ssa >> hex >> a;
+ if (max)
+ *(long long*)(data + 4) = 0xFFFFFFFFFFFFFFFFll;
+ else
+ *(long long*)(data + 4) = 0x0000000000000000ll;
+ }
- stringstream ssb(bs);
- ssb >> hex >> b;
-*/
+ time_t OID::asTimeT(){
+ int time;
+ char* T = (char *) &time;
+ T[0] = data[3];
+ T[1] = data[2];
+ T[2] = data[1];
+ T[3] = data[0];
+ return time;
}
Labeler::Label GT( "$gt" );
@@ -1492,84 +1268,83 @@ namespace mongo {
timestamp = OpTime::now().asDate();
}
-
- void BSONObjBuilder::appendMinForType( const string& field , int t ){
+ void BSONObjBuilder::appendMinForType( const StringData& fieldName , int t ){
switch ( t ){
- case MinKey: appendMinKey( field.c_str() ); return;
- case MaxKey: appendMinKey( field.c_str() ); return;
+ case MinKey: appendMinKey( fieldName ); return;
+ case MaxKey: appendMinKey( fieldName ); return;
case NumberInt:
case NumberDouble:
case NumberLong:
- append( field.c_str() , - numeric_limits<double>::max() ); return;
+ append( fieldName , - numeric_limits<double>::max() ); return;
case jstOID:
{
OID o;
memset(&o, 0, sizeof(o));
- appendOID( field.c_str() , &o);
+ appendOID( fieldName , &o);
return;
}
- case Bool: appendBool( field.c_str() , false); return;
- case Date: appendDate( field.c_str() , 0); return;
- case jstNULL: appendNull( field.c_str() ); return;
+ case Bool: appendBool( fieldName , false); return;
+ case Date: appendDate( fieldName , 0); return;
+ case jstNULL: appendNull( fieldName ); return;
case Symbol:
- case String: append( field.c_str() , "" ); return;
- case Object: append( field.c_str() , BSONObj() ); return;
+ case String: append( fieldName , "" ); return;
+ case Object: append( fieldName , BSONObj() ); return;
case Array:
- appendArray( field.c_str() , BSONObj() ); return;
+ appendArray( fieldName , BSONObj() ); return;
case BinData:
- appendBinData( field.c_str() , 0 , Function , (const char *) 0 ); return;
+ appendBinData( fieldName , 0 , Function , (const char *) 0 ); return;
case Undefined:
- appendUndefined( field.c_str() ); return;
- case RegEx: appendRegex( field.c_str() , "" ); return;
+ appendUndefined( fieldName ); return;
+ case RegEx: appendRegex( fieldName , "" ); return;
case DBRef:
{
OID o;
memset(&o, 0, sizeof(o));
- appendDBRef( field.c_str() , "" , o );
+ appendDBRef( fieldName , "" , o );
return;
}
- case Code: appendCode( field.c_str() , "" ); return;
- case CodeWScope: appendCodeWScope( field.c_str() , "" , BSONObj() ); return;
- case Timestamp: appendTimestamp( field.c_str() , 0); return;
+ case Code: appendCode( fieldName , "" ); return;
+ case CodeWScope: appendCodeWScope( fieldName , "" , BSONObj() ); return;
+ case Timestamp: appendTimestamp( fieldName , 0); return;
};
log() << "type not support for appendMinElementForType: " << t << endl;
uassert( 10061 , "type not supported for appendMinElementForType" , false );
}
- void BSONObjBuilder::appendMaxForType( const string& field , int t ){
+ void BSONObjBuilder::appendMaxForType( const StringData& fieldName , int t ){
switch ( t ){
- case MinKey: appendMaxKey( field.c_str() ); break;
- case MaxKey: appendMaxKey( field.c_str() ); break;
+ case MinKey: appendMaxKey( fieldName ); break;
+ case MaxKey: appendMaxKey( fieldName ); break;
case NumberInt:
case NumberDouble:
case NumberLong:
- append( field.c_str() , numeric_limits<double>::max() );
+ append( fieldName , numeric_limits<double>::max() );
break;
case BinData:
- appendMinForType( field , jstOID );
+ appendMinForType( fieldName , jstOID );
break;
case jstOID:
{
OID o;
memset(&o, 0xFF, sizeof(o));
- appendOID( field.c_str() , &o);
+ appendOID( fieldName , &o);
break;
}
case Undefined:
case jstNULL:
- appendMinForType( field , NumberInt );
- case Bool: appendBool( field.c_str() , true); break;
- case Date: appendDate( field.c_str() , 0xFFFFFFFFFFFFFFFFLL ); break;
+ appendMinForType( fieldName , NumberInt );
+ case Bool: appendBool( fieldName , true); break;
+ case Date: appendDate( fieldName , 0xFFFFFFFFFFFFFFFFLL ); break;
case Symbol:
- case String: append( field.c_str() , BSONObj() ); break;
+ case String: append( fieldName , BSONObj() ); break;
case Code:
case CodeWScope:
- appendCodeWScope( field.c_str() , "ZZZ" , BSONObj() ); break;
+ appendCodeWScope( fieldName , "ZZZ" , BSONObj() ); break;
case Timestamp:
- appendTimestamp( field.c_str() , numeric_limits<unsigned long long>::max() ); break;
+ appendTimestamp( fieldName , numeric_limits<unsigned long long>::max() ); break;
default:
- appendMinForType( field , t + 1 );
+ appendMinForType( fieldName , t + 1 );
}
}
@@ -1586,8 +1361,8 @@ namespace mongo {
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
};
- bool BSONObjBuilder::appendAsNumber( const string& fieldName , const string& data ){
- if ( data.size() == 0 )
+ bool BSONObjBuilder::appendAsNumber( const StringData& fieldName , const string& data ){
+ if ( data.size() == 0 || data == "-")
return false;
unsigned int pos=0;
@@ -1612,7 +1387,7 @@ namespace mongo {
if ( hasDec ){
double d = atof( data.c_str() );
- append( fieldName.c_str() , d );
+ append( fieldName , d );
return true;
}
@@ -1665,5 +1440,27 @@ namespace mongo {
_cur = 0;
}
+ /** transform a BSON array into a vector of BSONElements.
+ we match array # positions with their vector position, and ignore
+ any non-numeric fields.
+ */
+ vector<BSONElement> BSONElement::Array() const {
+ chk(mongo::Array);
+ vector<BSONElement> v;
+ BSONObjIterator i(Obj());
+ while( i.more() ) {
+ BSONElement e = i.next();
+ const char *f = e.fieldName();
+ try {
+ unsigned u = stringToNum(f);
+ assert( u < 4096 );
+ if( u >= v.size() )
+ v.resize(u+1);
+ v[u] = e;
+ }
+ catch(unsigned) { }
+ }
+ return v;
+ }
} // namespace mongo