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