/** * 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