YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/rocksdb/utilities/document/json_document.cc
Line
Count
Source (jump to first uncovered line)
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under the BSD-style license found in the
3
//  LICENSE file in the root directory of this source tree. An additional grant
4
//  of patent rights can be found in the PATENTS file in the same directory.
5
//
6
// The following only applies to changes made to this file as part of YugaByte development.
7
//
8
// Portions Copyright (c) YugaByte, Inc.
9
//
10
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
11
// in compliance with the License.  You may obtain a copy of the License at
12
//
13
// http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software distributed under the License
16
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17
// or implied.  See the License for the specific language governing permissions and limitations
18
// under the License.
19
//
20
#ifndef ROCKSDB_LITE
21
22
#include "yb/rocksdb/utilities/json_document.h"
23
24
#ifndef __STDC_FORMAT_MACROS
25
#define __STDC_FORMAT_MACROS
26
#endif
27
28
#include <assert.h>
29
#include <inttypes.h>
30
#include <string.h>
31
32
#include <functional>
33
#include <limits>
34
#include <map>
35
#include <memory>
36
#include <string>
37
#include <vector>
38
39
40
#include "yb/rocksdb/third-party/fbson/FbsonDocument.h"
41
#include "yb/rocksdb/third-party/fbson/FbsonJsonParser.h"
42
#include "yb/rocksdb/third-party/fbson/FbsonUtil.h"
43
#include "yb/rocksdb/util/coding.h"
44
45
namespace {
46
47
using namespace std::placeholders;
48
49
50
size_t ObjectNumElem(const fbson::ObjectVal& objectVal) {
50
50
  size_t size = 0;
51
88
  for (auto keyValuePair : objectVal) {
52
88
    (void)keyValuePair;
53
88
    ++size;
54
88
  }
55
50
  return size;
56
50
}
57
58
template <typename Func>
59
void InitJSONDocument(std::unique_ptr<char[]>* data,
60
                      fbson::FbsonValue** value,
61
79
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
79
  fbson::FbsonWriter writer;
64
79
  bool res __attribute__((unused)) = writer.writeStartArray();
65
79
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
79
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
79
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
79
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
79
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
79
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
79
  data->reset(buf);
78
79
}
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<(anonymous namespace)::InitString(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::$_0, std::__1::placeholders::__ph<1> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<(anonymous namespace)::InitString(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)::$_0, std::__1::placeholders::__ph<1> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&>)
Line
Count
Source
61
8
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
8
  fbson::FbsonWriter writer;
64
8
  bool res __attribute__((unused)) = writer.writeStartArray();
65
8
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
8
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
8
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
8
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
8
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
8
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
8
  data->reset(buf);
78
8
}
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(), std::__1::placeholders::__ph<1> const&> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(), std::__1::placeholders::__ph<1> const&>)
Line
Count
Source
61
42
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
42
  fbson::FbsonWriter writer;
64
42
  bool res __attribute__((unused)) = writer.writeStartArray();
65
42
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
42
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
42
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
42
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
42
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
42
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
42
  data->reset(buf);
78
42
}
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(bool), std::__1::placeholders::__ph<1> const&, bool&> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(bool), std::__1::placeholders::__ph<1> const&, bool&>)
Line
Count
Source
61
9
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
9
  fbson::FbsonWriter writer;
64
9
  bool res __attribute__((unused)) = writer.writeStartArray();
65
9
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
9
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
9
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
9
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
9
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
9
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
9
  data->reset(buf);
78
9
}
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(double), std::__1::placeholders::__ph<1> const&, double&> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(double), std::__1::placeholders::__ph<1> const&, double&>)
Line
Count
Source
61
6
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
6
  fbson::FbsonWriter writer;
64
6
  bool res __attribute__((unused)) = writer.writeStartArray();
65
6
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
6
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
6
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
6
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
6
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
6
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
6
  data->reset(buf);
78
6
}
Unexecuted instantiation: json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(signed char), std::__1::placeholders::__ph<1> const&, signed char&> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(signed char), std::__1::placeholders::__ph<1> const&, signed char&>)
Unexecuted instantiation: json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(short), std::__1::placeholders::__ph<1> const&, short&> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(short), std::__1::placeholders::__ph<1> const&, short&>)
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(int), std::__1::placeholders::__ph<1> const&, int&> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(int), std::__1::placeholders::__ph<1> const&, int&>)
Line
Count
Source
61
2
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
2
  fbson::FbsonWriter writer;
64
2
  bool res __attribute__((unused)) = writer.writeStartArray();
65
2
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
2
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
2
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
2
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
2
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
2
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
2
  data->reset(buf);
78
2
}
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(long long), std::__1::placeholders::__ph<1> const&, long long&> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(long long), std::__1::placeholders::__ph<1> const&, long long&>)
Line
Count
Source
61
9
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
9
  fbson::FbsonWriter writer;
64
9
  bool res __attribute__((unused)) = writer.writeStartArray();
65
9
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
9
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
9
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
9
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
9
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
9
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
9
  data->reset(buf);
78
9
}
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(bool), std::__1::placeholders::__ph<1> const&, bool> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(bool), std::__1::placeholders::__ph<1> const&, bool>)
Line
Count
Source
61
1
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
1
  fbson::FbsonWriter writer;
64
1
  bool res __attribute__((unused)) = writer.writeStartArray();
65
1
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
1
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
1
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
1
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
1
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
1
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
1
  data->reset(buf);
78
1
}
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(double), std::__1::placeholders::__ph<1> const&, double> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(double), std::__1::placeholders::__ph<1> const&, double>)
Line
Count
Source
61
1
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
1
  fbson::FbsonWriter writer;
64
1
  bool res __attribute__((unused)) = writer.writeStartArray();
65
1
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
1
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
1
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
1
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
1
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
1
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
1
  data->reset(buf);
78
1
}
json_document.cc:void (anonymous namespace)::InitJSONDocument<std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(long long), std::__1::placeholders::__ph<1> const&, int> >(std::__1::unique_ptr<char [], std::__1::default_delete<char []> >*, fbson::FbsonValue**, std::__1::__bind<unsigned int (fbson::FbsonWriterT<fbson::FbsonOutStream>::*)(long long), std::__1::placeholders::__ph<1> const&, int>)
Line
Count
Source
61
1
                      Func f) {
62
  // TODO(stash): maybe add function to FbsonDocument to avoid creating array?
63
1
  fbson::FbsonWriter writer;
64
1
  bool res __attribute__((unused)) = writer.writeStartArray();
65
1
  assert(res);
66
0
  uint32_t bytesWritten __attribute__((unused)) = f(writer);
67
1
  assert(bytesWritten != 0);
68
0
  res = writer.writeEndArray();
69
1
  assert(res);
70
0
  char* buf = new char[writer.getOutput()->getSize()];
71
1
  memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize());
72
73
1
  *value = ((fbson::FbsonDocument *)buf)->getValue();
74
1
  assert((*value)->isArray());
75
0
  assert(((fbson::ArrayVal*)*value)->numElem() == 1);
76
0
  *value = ((fbson::ArrayVal*)*value)->get(0);
77
1
  data->reset(buf);
78
1
}
79
80
void InitString(std::unique_ptr<char[]>* data,
81
                fbson::FbsonValue** value,
82
8
                const std::string& s) {
83
8
  InitJSONDocument(data, value, std::bind(
84
8
      [](fbson::FbsonWriter& writer, const std::string& str) -> uint32_t {
85
8
        bool res __attribute__((unused)) = writer.writeStartString();
86
8
        assert(res);
87
0
        auto bytesWritten = writer.writeString(str.c_str(),
88
8
                            static_cast<uint32_t>(str.length()));
89
8
        res = writer.writeEndString();
90
8
        assert(res);
91
        // If the string is empty, then bytesWritten == 0, and assert in
92
        // InitJsonDocument will fail.
93
0
        return bytesWritten + static_cast<uint32_t>(str.empty());
94
8
      },
95
8
  _1, s));
96
8
}
97
98
55
bool IsNumeric(fbson::FbsonValue* value) {
99
55
  return value->isInt8() || 
value->isInt16()42
||
100
55
         
value->isInt32()40
||
value->isInt64()38
;
101
55
}
102
103
364
int64_t GetInt64ValFromFbsonNumericType(fbson::FbsonValue* value) {
104
364
  switch (value->type()) {
105
306
    case fbson::FbsonType::T_Int8:
106
306
      return reinterpret_cast<fbson::Int8Val*>(value)->val();
107
1
    case fbson::FbsonType::T_Int16:
108
1
      return reinterpret_cast<fbson::Int16Val*>(value)->val();
109
3
    case fbson::FbsonType::T_Int32:
110
3
      return reinterpret_cast<fbson::Int32Val*>(value)->val();
111
54
    case fbson::FbsonType::T_Int64:
112
54
      return reinterpret_cast<fbson::Int64Val*>(value)->val();
113
0
    default:
114
0
      assert(false);
115
364
  }
116
0
  return 0;
117
364
}
118
119
50
bool IsComparable(fbson::FbsonValue* left, fbson::FbsonValue* right) {
120
50
  if (left->type() == right->type()) {
121
39
    return true;
122
39
  }
123
11
  if (IsNumeric(left) && 
IsNumeric(right)7
) {
124
5
    return true;
125
5
  }
126
6
  return false;
127
11
}
128
129
1
void CreateArray(std::unique_ptr<char[]>* data, fbson::FbsonValue** value) {
130
1
  fbson::FbsonWriter writer;
131
1
  bool res __attribute__((unused)) = writer.writeStartArray();
132
1
  assert(res);
133
0
  res = writer.writeEndArray();
134
1
  assert(res);
135
0
  data->reset(new char[writer.getOutput()->getSize()]);
136
1
  memcpy(data->get(),
137
1
         writer.getOutput()->getBuffer(),
138
1
         writer.getOutput()->getSize());
139
1
  *value = reinterpret_cast<fbson::FbsonDocument*>(data->get())->getValue();
140
1
}
141
142
1
void CreateObject(std::unique_ptr<char[]>* data, fbson::FbsonValue** value) {
143
1
  fbson::FbsonWriter writer;
144
1
  bool res __attribute__((unused)) = writer.writeStartObject();
145
1
  assert(res);
146
0
  res = writer.writeEndObject();
147
1
  assert(res);
148
0
  data->reset(new char[writer.getOutput()->getSize()]);
149
1
  memcpy(data->get(),
150
1
         writer.getOutput()->getBuffer(),
151
1
         writer.getOutput()->getSize());
152
1
  *value = reinterpret_cast<fbson::FbsonDocument*>(data->get())->getValue();
153
1
}
154
155
}  // namespace
156
157
namespace rocksdb {
158
159
160
// TODO(stash): find smth easier
161
41
JSONDocument::JSONDocument() {
162
41
  InitJSONDocument(&data_,
163
41
                   &value_,
164
41
                   std::bind(&fbson::FbsonWriter::writeNull, _1));
165
41
}
166
167
9
JSONDocument::JSONDocument(bool b) {
168
9
  InitJSONDocument(&data_,
169
9
                   &value_,
170
9
                   std::bind(&fbson::FbsonWriter::writeBool, _1, b));
171
9
}
172
173
6
JSONDocument::JSONDocument(double d) {
174
6
  InitJSONDocument(&data_,
175
6
                   &value_,
176
6
                   std::bind(&fbson::FbsonWriter::writeDouble, _1, d));
177
6
}
178
179
0
JSONDocument::JSONDocument(int8_t i) {
180
0
  InitJSONDocument(&data_,
181
0
                   &value_,
182
0
                   std::bind(&fbson::FbsonWriter::writeInt8, _1, i));
183
0
}
184
185
0
JSONDocument::JSONDocument(int16_t i) {
186
0
  InitJSONDocument(&data_,
187
0
                   &value_,
188
0
                   std::bind(&fbson::FbsonWriter::writeInt16, _1, i));
189
0
}
190
191
2
JSONDocument::JSONDocument(int32_t i) {
192
2
  InitJSONDocument(&data_,
193
2
                   &value_,
194
2
                   std::bind(&fbson::FbsonWriter::writeInt32, _1, i));
195
2
}
196
197
9
JSONDocument::JSONDocument(int64_t i) {
198
9
  InitJSONDocument(&data_,
199
9
                   &value_,
200
9
                   std::bind(&fbson::FbsonWriter::writeInt64, _1, i));
201
9
}
202
203
7
JSONDocument::JSONDocument(const std::string& s) {
204
7
  InitString(&data_, &value_, s);
205
7
}
206
207
7
JSONDocument::JSONDocument(const char* s) : JSONDocument(std::string(s)) {
208
7
}
Unexecuted instantiation: rocksdb::JSONDocument::JSONDocument(char const*)
rocksdb::JSONDocument::JSONDocument(char const*)
Line
Count
Source
207
7
JSONDocument::JSONDocument(const char* s) : JSONDocument(std::string(s)) {
208
7
}
209
210
206
void JSONDocument::InitFromValue(const fbson::FbsonValue* val) {
211
206
  data_.reset(new char[val->numPackedBytes()]);
212
206
  memcpy(data_.get(), val, val->numPackedBytes());
213
206
  value_ = reinterpret_cast<fbson::FbsonValue*>(data_.get());
214
206
}
215
216
// Private constructor
217
867
JSONDocument::JSONDocument(fbson::FbsonValue* val, bool makeCopy) {
218
867
  if (makeCopy) {
219
189
    InitFromValue(val);
220
678
  } else {
221
678
    value_ = val;
222
678
  }
223
867
}
224
225
7
JSONDocument::JSONDocument(Type _type) {
226
  // TODO(icanadi) make all of this better by using templates
227
7
  switch (_type) {
228
1
    case kNull:
229
1
      InitJSONDocument(&data_, &value_,
230
1
                       std::bind(&fbson::FbsonWriter::writeNull, _1));
231
1
      break;
232
1
    case kObject:
233
1
      CreateObject(&data_, &value_);
234
1
      break;
235
1
    case kBool:
236
1
      InitJSONDocument(&data_, &value_,
237
1
                       std::bind(&fbson::FbsonWriter::writeBool, _1, false));
238
1
      break;
239
1
    case kDouble:
240
1
      InitJSONDocument(&data_, &value_,
241
1
                       std::bind(&fbson::FbsonWriter::writeDouble, _1, 0.));
242
1
      break;
243
1
    case kArray:
244
1
      CreateArray(&data_, &value_);
245
1
      break;
246
1
    case kInt64:
247
1
      InitJSONDocument(&data_, &value_,
248
1
                       std::bind(&fbson::FbsonWriter::writeInt64, _1, 0));
249
1
      break;
250
1
    case kString:
251
1
      InitString(&data_, &value_, "");
252
1
      break;
253
0
    default:
254
0
      assert(false);
255
7
  }
256
7
}
257
258
79
JSONDocument::JSONDocument(const JSONDocument& jsonDocument) {
259
79
  if (jsonDocument.IsOwner()) {
260
17
    InitFromValue(jsonDocument.value_);
261
62
  } else {
262
62
    value_ = jsonDocument.value_;
263
62
  }
264
79
}
265
266
212
JSONDocument::JSONDocument(JSONDocument&& jsonDocument) {
267
212
  value_ = jsonDocument.value_;
268
212
  data_.swap(jsonDocument.data_);
269
212
}
270
271
37
JSONDocument& JSONDocument::operator=(JSONDocument jsonDocument) {
272
37
  value_ = jsonDocument.value_;
273
37
  data_.swap(jsonDocument.data_);
274
37
  return *this;
275
37
}
276
277
1.09k
JSONDocument::Type JSONDocument::type() const {
278
1.09k
  switch (value_->type()) {
279
0
    case fbson::FbsonType::T_Null:
280
0
      return JSONDocument::kNull;
281
282
0
    case fbson::FbsonType::T_True:
283
0
    case fbson::FbsonType::T_False:
284
0
      return JSONDocument::kBool;
285
286
477
    case fbson::FbsonType::T_Int8:
287
477
    case fbson::FbsonType::T_Int16:
288
479
    case fbson::FbsonType::T_Int32:
289
523
    case fbson::FbsonType::T_Int64:
290
523
      return JSONDocument::kInt64;
291
292
211
    case fbson::FbsonType::T_Double:
293
211
      return JSONDocument::kDouble;
294
295
363
    case fbson::FbsonType::T_String:
296
363
      return JSONDocument::kString;
297
298
0
    case fbson::FbsonType::T_Object:
299
0
      return JSONDocument::kObject;
300
301
0
    case fbson::FbsonType::T_Array:
302
0
      return JSONDocument::kArray;
303
304
0
    case fbson::FbsonType::T_Binary:
305
0
      assert(false);
306
      // Added to avoid a compile error of the YugaByte codebase (we treat unannotated fall-through
307
      // as an error).
308
0
      break;
309
310
0
    default:
311
0
      assert(false);
312
1.09k
  }
313
0
  return JSONDocument::kNull;
314
1.09k
}
315
316
364
bool JSONDocument::Contains(const std::string& key) const {
317
364
  assert(IsObject());
318
0
  auto objectVal = reinterpret_cast<fbson::ObjectVal*>(value_);
319
364
  return objectVal->find(key.c_str()) != nullptr;
320
364
}
321
322
469
JSONDocument JSONDocument::operator[](const std::string& key) const {
323
469
  assert(IsObject());
324
0
  auto objectVal = reinterpret_cast<fbson::ObjectVal*>(value_);
325
469
  auto foundValue = objectVal->find(key.c_str());
326
469
  assert(foundValue != nullptr);
327
  // No need to save paths in const objects
328
0
  JSONDocument ans(foundValue, false);
329
469
  return ans;
330
469
}
331
332
71
size_t JSONDocument::Count() const {
333
71
  assert(IsObject() || IsArray());
334
71
  if (IsObject()) {
335
    // TODO(stash): add to fbson?
336
36
    const fbson::ObjectVal& objectVal =
337
36
          *reinterpret_cast<fbson::ObjectVal*>(value_);
338
36
    return ObjectNumElem(objectVal);
339
36
  } else 
if (35
IsArray()35
) {
340
35
    auto arrayVal = reinterpret_cast<fbson::ArrayVal*>(value_);
341
35
    return arrayVal->numElem();
342
35
  }
343
0
  assert(false);
344
0
  return 0;
345
71
}
346
347
53
JSONDocument JSONDocument::operator[](size_t i) const {
348
53
  assert(IsArray());
349
0
  auto arrayVal = reinterpret_cast<fbson::ArrayVal*>(value_);
350
53
  auto foundValue = arrayVal->get(static_cast<int>(i));
351
53
  JSONDocument ans(foundValue, false);
352
53
  return ans;
353
53
}
354
355
356
bool JSONDocument::IsNull() const {
356
356
  return value_->isNull();
357
356
}
358
359
175
bool JSONDocument::IsArray() const {
360
175
  return value_->isArray();
361
175
}
362
363
15
bool JSONDocument::IsBool() const {
364
15
  return value_->isTrue() || 
value_->isFalse()7
;
365
15
}
366
367
132
bool JSONDocument::IsDouble() const {
368
132
  return value_->isDouble();
369
132
}
370
371
394
bool JSONDocument::IsInt64() const {
372
394
  return value_->isInt8() || 
value_->isInt16()60
||
373
394
         
value_->isInt32()59
||
value_->isInt64()56
;
374
394
}
375
376
1.51k
bool JSONDocument::IsObject() const {
377
1.51k
  return value_->isObject();
378
1.51k
}
379
380
268
bool JSONDocument::IsString() const {
381
268
  return value_->isString();
382
268
}
383
384
5
bool JSONDocument::GetBool() const {
385
5
  assert(IsBool());
386
0
  return value_->isTrue();
387
5
}
388
389
121
double JSONDocument::GetDouble() const {
390
121
  assert(IsDouble());
391
0
  return ((fbson::DoubleVal*)value_)->val();
392
121
}
393
394
344
int64_t JSONDocument::GetInt64() const {
395
344
  assert(IsInt64());
396
0
  return GetInt64ValFromFbsonNumericType(value_);
397
344
}
398
399
208
std::string JSONDocument::GetString() const {
400
208
  assert(IsString());
401
0
  fbson::StringVal* stringVal = (fbson::StringVal*)value_;
402
208
  return std::string(stringVal->getBlob(), stringVal->getBlobLen());
403
208
}
404
405
namespace {
406
407
// FbsonValue can be int8, int16, int32, int64
408
10
bool CompareNumeric(fbson::FbsonValue* left, fbson::FbsonValue* right) {
409
10
  assert(IsNumeric(left) && IsNumeric(right));
410
0
  return GetInt64ValFromFbsonNumericType(left) ==
411
10
         GetInt64ValFromFbsonNumericType(right);
412
10
}
413
414
17
bool CompareSimpleTypes(fbson::FbsonValue* left, fbson::FbsonValue* right) {
415
17
  if (IsNumeric(left)) {
416
0
    return CompareNumeric(left, right);
417
0
  }
418
17
  if (left->numPackedBytes() != right->numPackedBytes()) {
419
0
    return false;
420
0
  }
421
17
  return memcmp(left, right, left->numPackedBytes()) == 0;
422
17
}
423
424
50
bool CompareFbsonValue(fbson::FbsonValue* left, fbson::FbsonValue* right) {
425
50
  if (!IsComparable(left, right)) {
426
6
    return false;
427
6
  }
428
429
44
  switch (left->type()) {
430
2
    case fbson::FbsonType::T_True:
431
3
    case fbson::FbsonType::T_False:
432
5
    case fbson::FbsonType::T_Null:
433
5
      return true;
434
6
    case fbson::FbsonType::T_Int8:
435
7
    case fbson::FbsonType::T_Int16:
436
8
    case fbson::FbsonType::T_Int32:
437
10
    case fbson::FbsonType::T_Int64:
438
10
      return CompareNumeric(left, right);
439
12
    case fbson::FbsonType::T_String:
440
17
    case fbson::FbsonType::T_Double:
441
17
      return CompareSimpleTypes(left, right);
442
7
    case fbson::FbsonType::T_Object:
443
7
    {
444
7
      auto leftObject = reinterpret_cast<fbson::ObjectVal*>(left);
445
7
      auto rightObject = reinterpret_cast<fbson::ObjectVal*>(right);
446
7
      if (ObjectNumElem(*leftObject) != ObjectNumElem(*rightObject)) {
447
0
        return false;
448
0
      }
449
17
      
for (auto && keyValue : *leftObject)7
{
450
17
        std::string str(keyValue.getKeyStr(), keyValue.klen());
451
17
        if (rightObject->find(str.c_str()) == nullptr) {
452
0
          return false;
453
0
        }
454
17
        if (!CompareFbsonValue(keyValue.value(),
455
17
                               rightObject->find(str.c_str()))) {
456
3
          return false;
457
3
        }
458
17
      }
459
4
      return true;
460
7
    }
461
5
    case fbson::FbsonType::T_Array:
462
5
    {
463
5
      auto leftArr = reinterpret_cast<fbson::ArrayVal*>(left);
464
5
      auto rightArr = reinterpret_cast<fbson::ArrayVal*>(right);
465
5
      if (leftArr->numElem() != rightArr->numElem()) {
466
0
        return false;
467
0
      }
468
18
      
for (int i = 0; 5
i < static_cast<int>(leftArr->numElem());
++i13
) {
469
14
        if (!CompareFbsonValue(leftArr->get(i), rightArr->get(i))) {
470
1
          return false;
471
1
        }
472
14
      }
473
4
      return true;
474
5
    }
475
0
    default:
476
0
      assert(false);
477
44
  }
478
0
  return false;
479
44
}
480
481
}  // namespace
482
483
19
bool JSONDocument::operator==(const JSONDocument& rhs) const {
484
19
  return CompareFbsonValue(value_, rhs.value_);
485
19
}
486
487
7
bool JSONDocument::operator!=(const JSONDocument& rhs) const {
488
7
  return !(*this == rhs);
489
7
}
490
491
19
JSONDocument JSONDocument::Copy() const {
492
19
  return JSONDocument(value_, true);
493
19
}
494
495
184
bool JSONDocument::IsOwner() const {
496
184
  return data_.get() != nullptr;
497
184
}
498
499
0
std::string JSONDocument::DebugString() const {
500
0
  fbson::FbsonToJson fbsonToJson;
501
0
  return fbsonToJson.json(value_);
502
0
}
503
504
84
JSONDocument::ItemsIteratorGenerator JSONDocument::Items() const {
505
84
  assert(IsObject());
506
0
  return ItemsIteratorGenerator(*(reinterpret_cast<fbson::ObjectVal*>(value_)));
507
84
}
508
509
// TODO(icanadi) (perf) allocate objects with arena
510
54
JSONDocument* JSONDocument::ParseJSON(const char* json) {
511
54
  fbson::FbsonJsonParser parser;
512
54
  if (!parser.parse(json)) {
513
1
    return nullptr;
514
1
  }
515
516
53
  auto fbsonVal = fbson::FbsonDocument::createValue(
517
53
                    parser.getWriter().getOutput()->getBuffer(),
518
53
              static_cast<uint32_t>(parser.getWriter().getOutput()->getSize()));
519
520
53
  if (fbsonVal == nullptr) {
521
0
    return nullptr;
522
0
  }
523
524
53
  return new JSONDocument(fbsonVal, true);
525
53
}
526
527
25
void JSONDocument::Serialize(std::string* dst) const {
528
  // first byte is reserved for header
529
  // currently, header is only version number. that will help us provide
530
  // backwards compatility. we might also store more information here if
531
  // necessary
532
25
  dst->push_back(kSerializationFormatVersion);
533
25
  dst->push_back(FBSON_VER);
534
25
  dst->append(reinterpret_cast<char*>(value_), value_->numPackedBytes());
535
25
}
536
537
const char JSONDocument::kSerializationFormatVersion = 2;
538
539
97
JSONDocument* JSONDocument::Deserialize(const Slice& src) {
540
97
  Slice input(src);
541
97
  if (src.size() == 0) {
542
0
    return nullptr;
543
0
  }
544
97
  char header = input[0];
545
97
  if (header == 1) {
546
0
    assert(false);
547
0
  }
548
0
  input.remove_prefix(1);
549
97
  auto value = fbson::FbsonDocument::createValue(input.cdata(),
550
97
                                                 static_cast<uint32_t>(input.size()));
551
97
  if (value == nullptr) {
552
1
    return nullptr;
553
1
  }
554
555
96
  return new JSONDocument(value, true);
556
97
}
557
558
class JSONDocument::const_item_iterator::Impl {
559
 public:
560
  typedef fbson::ObjectVal::const_iterator It;
561
562
149
  explicit Impl(It it) : it_(it) {}
563
564
156
  const char* getKeyStr() const {
565
156
    return it_->getKeyStr();
566
156
  }
567
568
156
  uint8_t klen() const {
569
156
    return it_->klen();
570
156
  }
571
572
137
  It& operator++() {
573
137
    return ++it_;
574
137
  }
575
576
202
  bool operator!=(const Impl& other) {
577
202
    return it_ != other.it_;
578
202
  }
579
580
156
  fbson::FbsonValue* value() const {
581
156
    return it_->value();
582
156
  }
583
584
 private:
585
  It it_;
586
};
587
588
JSONDocument::const_item_iterator::const_item_iterator(Impl* impl)
589
149
: it_(impl) {}
590
591
JSONDocument::const_item_iterator::const_item_iterator(const_item_iterator&& a)
592
0
: it_(std::move(a.it_)) {}
593
594
JSONDocument::const_item_iterator&
595
137
  JSONDocument::const_item_iterator::operator++() {
596
137
  ++(*it_);
597
137
  return *this;
598
137
}
599
600
bool JSONDocument::const_item_iterator::operator!=(
601
202
                                  const const_item_iterator& other) {
602
202
  return *it_ != *(other.it_);
603
202
}
604
605
149
JSONDocument::const_item_iterator::~const_item_iterator() {
606
149
}
607
608
JSONDocument::const_item_iterator::value_type
609
156
  JSONDocument::const_item_iterator::operator*() {
610
156
  return JSONDocument::const_item_iterator::value_type(std::string(it_->getKeyStr(), it_->klen()),
611
156
    JSONDocument(it_->value(), false));
612
156
}
613
614
JSONDocument::ItemsIteratorGenerator::ItemsIteratorGenerator(
615
                                      const fbson::ObjectVal& object)
616
84
  : object_(object) {}
617
618
JSONDocument::const_item_iterator
619
84
      JSONDocument::ItemsIteratorGenerator::begin() const {
620
84
  return const_item_iterator(new const_item_iterator::Impl(object_.begin()));
621
84
}
622
623
JSONDocument::const_item_iterator
624
65
      JSONDocument::ItemsIteratorGenerator::end() const {
625
65
  return const_item_iterator(new const_item_iterator::Impl(object_.end()));
626
65
}
627
628
}  // namespace rocksdb
629
#endif  // ROCKSDB_LITE