1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
32 
33 #include "mongo/db/jsobj.h"
34 
35 #include <boost/lexical_cast.hpp>
36 
37 #include "mongo/bson/timestamp.h"
38 #include "mongo/util/log.h"
39 
40 namespace mongo {
41 
42 using std::string;
43 
appendMinForType(StringData fieldName,int t)44 void BSONObjBuilder::appendMinForType(StringData fieldName, int t) {
45     switch (t) {
46         // Shared canonical types
47         case NumberInt:
48         case NumberDouble:
49         case NumberLong:
50         case NumberDecimal:
51             append(fieldName, std::numeric_limits<double>::quiet_NaN());
52             return;
53         case Symbol:
54         case String:
55             append(fieldName, "");
56             return;
57         case Date:
58             // min varies with V0 and V1 indexes, so we go one type lower.
59             appendBool(fieldName, true);
60             // appendDate( fieldName , numeric_limits<long long>::min() );
61             return;
62         case bsonTimestamp:
63             appendTimestamp(fieldName, 0);
64             return;
65         case Undefined:  // shared with EOO
66             appendUndefined(fieldName);
67             return;
68 
69         // Separate canonical types
70         case MinKey:
71             appendMinKey(fieldName);
72             return;
73         case MaxKey:
74             appendMaxKey(fieldName);
75             return;
76         case jstOID: {
77             OID o;
78             appendOID(fieldName, &o);
79             return;
80         }
81         case Bool:
82             appendBool(fieldName, false);
83             return;
84         case jstNULL:
85             appendNull(fieldName);
86             return;
87         case Object:
88             append(fieldName, BSONObj());
89             return;
90         case Array:
91             appendArray(fieldName, BSONObj());
92             return;
93         case BinData:
94             appendBinData(fieldName, 0, BinDataGeneral, (const char*)0);
95             return;
96         case RegEx:
97             appendRegex(fieldName, "");
98             return;
99         case DBRef: {
100             OID o;
101             appendDBRef(fieldName, "", o);
102             return;
103         }
104         case Code:
105             appendCode(fieldName, "");
106             return;
107         case CodeWScope:
108             appendCodeWScope(fieldName, "", BSONObj());
109             return;
110     };
111     log() << "type not supported for appendMinElementForType: " << t;
112     uassert(10061, "type not supported for appendMinElementForType", false);
113 }
114 
appendMaxForType(StringData fieldName,int t)115 void BSONObjBuilder::appendMaxForType(StringData fieldName, int t) {
116     switch (t) {
117         // Shared canonical types
118         case NumberInt:
119         case NumberDouble:
120         case NumberLong:
121         case NumberDecimal:
122             append(fieldName, std::numeric_limits<double>::infinity());
123             return;
124         case Symbol:
125         case String:
126             appendMinForType(fieldName, Object);
127             return;
128         case Date:
129             appendDate(fieldName,
130                        Date_t::fromMillisSinceEpoch(std::numeric_limits<long long>::max()));
131             return;
132         case bsonTimestamp:
133             append(fieldName, Timestamp::max());
134             return;
135         case Undefined:  // shared with EOO
136             appendUndefined(fieldName);
137             return;
138 
139         // Separate canonical types
140         case MinKey:
141             appendMinKey(fieldName);
142             return;
143         case MaxKey:
144             appendMaxKey(fieldName);
145             return;
146         case jstOID: {
147             OID o = OID::max();
148             appendOID(fieldName, &o);
149             return;
150         }
151         case Bool:
152             appendBool(fieldName, true);
153             return;
154         case jstNULL:
155             appendNull(fieldName);
156             return;
157         case Object:
158             appendMinForType(fieldName, Array);
159             return;
160         case Array:
161             appendMinForType(fieldName, BinData);
162             return;
163         case BinData:
164             appendMinForType(fieldName, jstOID);
165             return;
166         case RegEx:
167             appendMinForType(fieldName, DBRef);
168             return;
169         case DBRef:
170             appendMinForType(fieldName, Code);
171             return;
172         case Code:
173             appendMinForType(fieldName, CodeWScope);
174             return;
175         case CodeWScope:
176             // This upper bound may change if a new bson type is added.
177             appendMinForType(fieldName, MaxKey);
178             return;
179     }
180     log() << "type not supported for appendMaxElementForType: " << t;
181     uassert(14853, "type not supported for appendMaxElementForType", false);
182 }
183 
appendDate(StringData fieldName,Date_t dt)184 BSONObjBuilder& BSONObjBuilder::appendDate(StringData fieldName, Date_t dt) {
185     _b.appendNum((char)Date);
186     _b.appendStr(fieldName);
187     _b.appendNum(dt.toMillisSinceEpoch());
188     return *this;
189 }
190 
191 /* add all the fields from the object specified to this object */
appendElements(const BSONObj & x)192 BSONObjBuilder& BSONObjBuilder::appendElements(const BSONObj& x) {
193     if (!x.isEmpty())
194         _b.appendBuf(x.objdata() + 4,   // skip over leading length
195                      x.objsize() - 5);  // ignore leading length and trailing \0
196     return *this;
197 }
198 
199 /* add all the fields from the object specified to this object if they don't exist */
appendElementsUnique(const BSONObj & x)200 BSONObjBuilder& BSONObjBuilder::appendElementsUnique(const BSONObj& x) {
201     std::set<std::string> have;
202     {
203         BSONObjIterator i = iterator();
204         while (i.more())
205             have.insert(i.next().fieldName());
206     }
207 
208     BSONObjIterator it(x);
209     while (it.more()) {
210         BSONElement e = it.next();
211         if (have.count(e.fieldName()))
212             continue;
213         append(e);
214     }
215     return *this;
216 }
217 
appendKeys(const BSONObj & keyPattern,const BSONObj & values)218 void BSONObjBuilder::appendKeys(const BSONObj& keyPattern, const BSONObj& values) {
219     BSONObjIterator i(keyPattern);
220     BSONObjIterator j(values);
221 
222     while (i.more() && j.more()) {
223         appendAs(j.next(), i.next().fieldName());
224     }
225 
226     verify(!i.more());
227     verify(!j.more());
228 }
229 
iterator() const230 BSONObjIterator BSONObjBuilder::iterator() const {
231     const char* s = _b.buf() + _offset;
232     const char* e = _b.buf() + _b.len();
233     return BSONObjIterator(s, e);
234 }
235 
hasField(StringData name) const236 bool BSONObjBuilder::hasField(StringData name) const {
237     BSONObjIterator i = iterator();
238     while (i.more())
239         if (name == i.next().fieldName())
240             return true;
241     return false;
242 }
243 
244 const string BSONObjBuilder::numStrs[] = {
245     "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",  "9",  "10", "11", "12", "13", "14",
246     "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
247     "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44",
248     "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
249     "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74",
250     "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
251     "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
252 };
253 
254 // This is to ensure that BSONObjBuilder doesn't try to use numStrs before the strings have
255 // been constructed I've tested just making numStrs a char[][], but the overhead of
256 // constructing the strings each time was too high numStrsReady will be 0 until after
257 // numStrs is initialized because it is a static variable
258 bool BSONObjBuilder::numStrsReady = (numStrs[0].size() > 0);
259 
260 }  // namespace mongo
261