/**
* Copyright (C) 2014 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
#include "mongo/db/jsobj.h"
#include
#include "mongo/bson/optime.h"
#include "mongo/util/log.h"
namespace mongo {
using std::string;
void BSONObjBuilder::appendMinForType( StringData fieldName , int t ) {
switch ( t ) {
// Shared canonical types
case NumberInt:
case NumberDouble:
case NumberLong:
append( fieldName , - std::numeric_limits::max() ); return;
case Symbol:
case String:
append( fieldName , "" ); return;
case Date:
// min varies with V0 and V1 indexes, so we go one type lower.
appendBool(fieldName, true);
//appendDate( fieldName , numeric_limits::min() );
return;
case Timestamp:
appendTimestamp( fieldName , 0 ); return;
case Undefined: // shared with EOO
appendUndefined( fieldName ); return;
// Separate canonical types
case MinKey:
appendMinKey( fieldName ); return;
case MaxKey:
appendMaxKey( fieldName ); return;
case jstOID: {
OID o;
appendOID( fieldName , &o);
return;
}
case Bool:
appendBool( fieldName , false); return;
case jstNULL:
appendNull( fieldName ); return;
case Object:
append( fieldName , BSONObj() ); return;
case Array:
appendArray( fieldName , BSONObj() ); return;
case BinData:
appendBinData( fieldName , 0 , BinDataGeneral , (const char *) 0 ); return;
case RegEx:
appendRegex( fieldName , "" ); return;
case DBRef: {
OID o;
appendDBRef( fieldName , "" , o );
return;
}
case Code:
appendCode( fieldName , "" ); return;
case CodeWScope:
appendCodeWScope( fieldName , "" , BSONObj() ); return;
};
log() << "type not supported for appendMinElementForType: " << t;
uassert( 10061 , "type not supported for appendMinElementForType" , false );
}
void BSONObjBuilder::appendMaxForType( StringData fieldName , int t ) {
switch ( t ) {
// Shared canonical types
case NumberInt:
case NumberDouble:
case NumberLong:
append( fieldName , std::numeric_limits::max() ); return;
case Symbol:
case String:
appendMinForType( fieldName, Object ); return;
case Date:
appendDate( fieldName , std::numeric_limits::max() ); return;
case Timestamp:
append( fieldName , OpTime::max() ); return;
case Undefined: // shared with EOO
appendUndefined( fieldName ); return;
// Separate canonical types
case MinKey:
appendMinKey( fieldName ); return;
case MaxKey:
appendMaxKey( fieldName ); return;
case jstOID: {
OID o = OID::max();
appendOID( fieldName , &o);
return;
}
case Bool:
appendBool( fieldName , true ); return;
case jstNULL:
appendNull( fieldName ); return;
case Object:
appendMinForType( fieldName, Array ); return;
case Array:
appendMinForType( fieldName, BinData ); return;
case BinData:
appendMinForType( fieldName, jstOID ); return;
case RegEx:
appendMinForType( fieldName, DBRef ); return;
case DBRef:
appendMinForType( fieldName, Code ); return;
case Code:
appendMinForType( fieldName, CodeWScope ); return;
case CodeWScope:
// This upper bound may change if a new bson type is added.
appendMinForType( fieldName , MaxKey ); return;
}
log() << "type not supported for appendMaxElementForType: " << t;
uassert( 14853 , "type not supported for appendMaxElementForType" , false );
}
bool BSONObjBuilder::appendAsNumber( StringData fieldName , const string& data ) {
if ( data.size() == 0 || data == "-" || data == ".")
return false;
unsigned int pos=0;
if ( data[0] == '-' )
pos++;
bool hasDec = false;
for ( ; pos( data );
append( fieldName , num );
return true;
}
catch(boost::bad_lexical_cast &) {
return false;
}
}
BSONObjBuilder& BSONObjBuilder::appendDate(StringData fieldName, Date_t dt) {
/* easy to pass a time_t to this and get a bad result. thus this warning. */
if ( kDebugBuild && dt > 0 && dt <= 0xffffffff ) {
static int n;
if( n++ == 0 )
log() << "DEV WARNING appendDate() called with a tiny (but nonzero) date" << std::endl;
}
_b.appendNum((char) Date);
_b.appendStr(fieldName);
_b.appendNum(dt);
return *this;
}
/* add all the fields from the object specified to this object */
BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) {
if (!x.isEmpty())
_b.appendBuf(
x.objdata() + 4, // skip over leading length
x.objsize() - 5); // ignore leading length and trailing \0
return *this;
}
/* add all the fields from the object specified to this object if they don't exist */
BSONObjBuilder& BSONObjBuilder::appendElementsUnique(BSONObj x) {
std::set have;
{
BSONObjIterator i = iterator();
while ( i.more() )
have.insert( i.next().fieldName() );
}
BSONObjIterator it(x);
while ( it.more() ) {
BSONElement e = it.next();
if ( have.count( e.fieldName() ) )
continue;
append(e);
}
return *this;
}
void BSONObjBuilder::appendKeys( const BSONObj& keyPattern , const BSONObj& values ) {
BSONObjIterator i(keyPattern);
BSONObjIterator j(values);
while ( i.more() && j.more() ) {
appendAs( j.next() , i.next().fieldName() );
}
verify( ! i.more() );
verify( ! j.more() );
}
BSONObjIterator BSONObjBuilder::iterator() const {
const char * s = _b.buf() + _offset;
const char * e = _b.buf() + _b.len();
return BSONObjIterator( s , e );
}
bool BSONObjBuilder::hasField( StringData name ) const {
BSONObjIterator i = iterator();
while ( i.more() )
if ( name == i.next().fieldName() )
return true;
return false;
}
const string BSONObjBuilder::numStrs[] = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
};
// This is to ensure that BSONObjBuilder doesn't try to use numStrs before the strings have
// been constructed I've tested just making numStrs a char[][], but the overhead of
// constructing the strings each time was too high numStrsReady will be 0 until after
// numStrs is initialized because it is a static variable
bool BSONObjBuilder::numStrsReady = (numStrs[0].size() > 0);
} // namespace mongo