1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "schema_object.h"
17 #include "db_errno.h"
18 #include "log_print.h"
19 #include "schema_constant.h"
20 #include "schema_utils.h"
21
22 namespace DistributedDB {
23 namespace {
24 const std::string JSON_EXTRACT_FUNC_NAME = "json_extract_by_path";
25 const std::string FLATBUFFER_EXTRACT_FUNC_NAME = "flatbuffer_extract_by_path";
26
27 // For Json-Schema, display its original content before parse. For FlatBuffer-Schema, only display its parsed content.
DisplaySchemaLineByLine(SchemaType inType,const std::string & inSchema)28 void DisplaySchemaLineByLine(SchemaType inType, const std::string &inSchema)
29 {
30 #ifdef TRACE_SCHEMA_INFO
31 constexpr uint32_t lengthPerLine = 400; // 400 char per line
32 constexpr uint32_t usualMaxLine = 25; // For normal schema, 25 line for 10k length is quite enough
33 LOGD("[Schema][Display] IS %s, LENGTH=%zu.", SchemaUtils::SchemaTypeString(inType).c_str(), inSchema.size());
34 uint32_t totalLine = (inSchema.size() + lengthPerLine - 1) / lengthPerLine;
35 for (uint32_t line = 0; line < totalLine; line++) {
36 if (line >= usualMaxLine) {
37 LOGD("......(UNCOMPLETED SCHEMA)");
38 break;
39 }
40 std::string lineStr = inSchema.substr(line * lengthPerLine, lengthPerLine);
41 LOGD("%s", lineStr.c_str());
42 }
43 #endif
44 }
45 }
46
GetExtractFuncName(SchemaType inSchemaType)47 std::string SchemaObject::GetExtractFuncName(SchemaType inSchemaType)
48 {
49 if (inSchemaType == SchemaType::JSON) {
50 return JSON_EXTRACT_FUNC_NAME;
51 } else {
52 return FLATBUFFER_EXTRACT_FUNC_NAME;
53 }
54 }
55
GenerateExtractSQL(SchemaType inSchemaType,const FieldPath & inFieldpath,FieldType inFieldType,uint32_t skipSize,const std::string & accessStr)56 std::string SchemaObject::GenerateExtractSQL(SchemaType inSchemaType, const FieldPath &inFieldpath,
57 FieldType inFieldType, uint32_t skipSize, const std::string &accessStr)
58 {
59 static std::map<FieldType, std::string> fieldTypeMapSQLiteType {
60 {FieldType::LEAF_FIELD_BOOL, "INT"},
61 {FieldType::LEAF_FIELD_INTEGER, "INT"},
62 {FieldType::LEAF_FIELD_LONG, "INT"},
63 {FieldType::LEAF_FIELD_DOUBLE, "REAL"},
64 {FieldType::LEAF_FIELD_STRING, "TEXT"},
65 };
66 if (inFieldpath.empty()) {
67 LOGE("[Schema][GenExtract] Path empty.");
68 return "";
69 }
70 if (fieldTypeMapSQLiteType.count(inFieldType) == 0) {
71 LOGE("[Schema][GenExtract] FieldType not support.");
72 return "";
73 }
74 std::string resultSql = " CAST("; // Reserve blank at begin for convenience.
75 resultSql += GetExtractFuncName(inSchemaType);
76 resultSql += "(" + accessStr + "value, '";
77 resultSql += SchemaUtils::FieldPathString(inFieldpath);
78 resultSql += "', ";
79 resultSql += std::to_string(skipSize);
80 resultSql += ") AS ";
81 resultSql += fieldTypeMapSQLiteType[inFieldType];
82 resultSql += ") "; // Reserve blank at end for convenience.
83 return resultSql;
84 }
85
SchemaObject()86 SchemaObject::SchemaObject() : flatbufferSchema_(*this) {};
87
SchemaObject(const SchemaObject & other)88 SchemaObject::SchemaObject(const SchemaObject &other)
89 : flatbufferSchema_(*this)
90 {
91 isValid_ = other.isValid_;
92 schemaType_ = other.schemaType_;
93 schemaString_ = other.schemaString_;
94 schemaVersion_ = other.schemaVersion_;
95 schemaMode_ = other.schemaMode_;
96 schemaSkipSize_ = other.schemaSkipSize_;
97 schemaIndexes_ = other.schemaIndexes_;
98 schemaDefine_ = other.schemaDefine_;
99 }
100
operator =(const SchemaObject & other)101 SchemaObject& SchemaObject::operator=(const SchemaObject &other)
102 {
103 if (&other != this) {
104 isValid_ = other.isValid_;
105 schemaType_ = other.schemaType_;
106 flatbufferSchema_.CopyFrom(other.flatbufferSchema_);
107 schemaString_ = other.schemaString_;
108 schemaVersion_ = other.schemaVersion_;
109 schemaMode_ = other.schemaMode_;
110 schemaSkipSize_ = other.schemaSkipSize_;
111 schemaIndexes_ = other.schemaIndexes_;
112 schemaDefine_ = other.schemaDefine_;
113 }
114 return *this;
115 }
116
117 #ifdef RELATIONAL_STORE
SchemaObject(const TableInfo & tableInfo)118 SchemaObject::SchemaObject(const TableInfo &tableInfo) : flatbufferSchema_(*this)
119 {
120 isValid_ = true;
121 schemaType_ = SchemaType::NONE; // Default NONE
122 schemaVersion_ = "1.0";
123 SchemaDefine schemaDefine = tableInfo.GetSchemaDefine();
124 schemaDefine_.insert({ 0, schemaDefine });
125 }
126 #endif // RELATIONAL_STORE
127
ParseFromSchemaString(const std::string & inSchemaString)128 int SchemaObject::ParseFromSchemaString(const std::string &inSchemaString)
129 {
130 if (isValid_) {
131 return -E_NOT_PERMIT;
132 }
133
134 // Judge whether it is FlatBuffer-Schema then check the schema-size first
135 SchemaType estimateType = SchemaType::JSON; // Estimate as JSON type firstly
136 std::string decoded;
137 if (FlatBufferSchema::IsFlatBufferSchema(inSchemaString, decoded)) {
138 estimateType = SchemaType::FLATBUFFER;
139 LOGD("[Schema][Parse] FlatBuffer-Type, Decode before=%zu, after=%zu.", inSchemaString.size(), decoded.size());
140 }
141 const std::string &oriSchema = ((estimateType == SchemaType::FLATBUFFER) ? decoded : inSchemaString);
142 if (oriSchema.size() > SchemaConstant::SCHEMA_STRING_SIZE_LIMIT) {
143 LOGE("[Schema][Parse] SchemaSize=%zu Too Large.", oriSchema.size());
144 return -E_INVALID_ARGS;
145 }
146
147 // Parse the corresponding type schema
148 if (estimateType == SchemaType::FLATBUFFER) {
149 int errCode = flatbufferSchema_.ParseFlatBufferSchema(oriSchema);
150 if (errCode != E_OK) {
151 return errCode;
152 }
153 DisplaySchemaLineByLine(SchemaType::FLATBUFFER, flatbufferSchema_.GetDescription());
154 schemaType_ = SchemaType::FLATBUFFER;
155 schemaString_ = oriSchema;
156 } else {
157 DisplaySchemaLineByLine(SchemaType::JSON, oriSchema);
158 JsonObject schemaJson;
159 int errCode = schemaJson.Parse(oriSchema);
160 if (errCode != E_OK) {
161 LOGE("[Schema][Parse] Json parse schema fail, errCode=%d, Not FlatBuffer Not Json.", errCode);
162 return errCode;
163 }
164 errCode = ParseJsonSchema(schemaJson);
165 if (errCode != E_OK) {
166 return errCode;
167 }
168 schemaType_ = SchemaType::JSON;
169 schemaString_ = schemaJson.ToString(); // Save the minify type of version string
170 }
171
172 isValid_ = true;
173 return E_OK;
174 }
175
IsSchemaValid() const176 bool SchemaObject::IsSchemaValid() const
177 {
178 return isValid_;
179 }
180
GetSchemaType() const181 SchemaType SchemaObject::GetSchemaType() const
182 {
183 return schemaType_;
184 }
185
ToSchemaString() const186 std::string SchemaObject::ToSchemaString() const
187 {
188 return schemaString_;
189 }
190
GetSkipSize() const191 uint32_t SchemaObject::GetSkipSize() const
192 {
193 return schemaSkipSize_;
194 }
195
GetIndexInfo() const196 std::map<IndexName, IndexInfo> SchemaObject::GetIndexInfo() const
197 {
198 if (!isValid_) {
199 // An invalid SchemaObject may contain some dirty info produced by failed parse.
200 return std::map<IndexName, IndexInfo>();
201 }
202 return schemaIndexes_;
203 }
204
IsIndexExist(const IndexName & indexName) const205 bool SchemaObject::IsIndexExist(const IndexName &indexName) const
206 {
207 if (!isValid_) {
208 return false;
209 }
210 return (schemaIndexes_.count(indexName) != 0);
211 }
212
CheckQueryableAndGetFieldType(const FieldPath & inPath,FieldType & outType) const213 int SchemaObject::CheckQueryableAndGetFieldType(const FieldPath &inPath, FieldType &outType) const
214 {
215 if (inPath.empty()) {
216 return -E_INVALID_ARGS;
217 }
218 if (schemaDefine_.count(inPath.size() - 1) == 0) {
219 return -E_NOT_FOUND;
220 }
221 if (schemaDefine_.at(inPath.size() - 1).count(inPath) == 0) {
222 return -E_NOT_FOUND;
223 }
224 const SchemaAttribute &targetAttr = schemaDefine_.at(inPath.size() - 1).at(inPath);
225 outType = targetAttr.type;
226 return (targetAttr.isIndexable ? E_OK : -E_NOT_SUPPORT);
227 }
228
CompareAgainstSchemaString(const std::string & inSchemaString) const229 int SchemaObject::CompareAgainstSchemaString(const std::string &inSchemaString) const
230 {
231 IndexDifference indexDiffer;
232 return CompareAgainstSchemaString(inSchemaString, indexDiffer);
233 }
234
CompareAgainstSchemaString(const std::string & inSchemaString,IndexDifference & indexDiffer) const235 int SchemaObject::CompareAgainstSchemaString(const std::string &inSchemaString, IndexDifference &indexDiffer) const
236 {
237 if (!isValid_) {
238 return -E_NOT_PERMIT;
239 }
240 SchemaObject newSchema;
241 int errCode = newSchema.ParseFromSchemaString(inSchemaString);
242 if (errCode != E_OK) {
243 return errCode;
244 }
245 return CompareAgainstSchemaObject(newSchema, indexDiffer);
246 }
247
CompareAgainstSchemaObject(const SchemaObject & inSchemaObject) const248 int SchemaObject::CompareAgainstSchemaObject(const SchemaObject &inSchemaObject) const
249 {
250 IndexDifference indexDiffer;
251 return CompareAgainstSchemaObject(inSchemaObject, indexDiffer);
252 }
253
CompareAgainstSchemaObject(const SchemaObject & inSchemaObject,IndexDifference & indexDiffer) const254 int SchemaObject::CompareAgainstSchemaObject(const SchemaObject &inSchemaObject, IndexDifference &indexDiffer) const
255 {
256 if (!isValid_ || !inSchemaObject.isValid_) {
257 return -E_NOT_PERMIT;
258 }
259 if (schemaType_ != inSchemaObject.schemaType_) {
260 LOGE("[Schema][Compare] Self is %s, other is %s.", SchemaUtils::SchemaTypeString(schemaType_).c_str(),
261 SchemaUtils::SchemaTypeString(inSchemaObject.schemaType_).c_str());
262 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
263 }
264
265 // Return E_SCHEMA_EQUAL_EXACTLY or E_SCHEMA_UNEQUAL_INCOMPATIBLE
266 int verModeResult = CompareSchemaVersionMode(inSchemaObject);
267 if (verModeResult == -E_SCHEMA_UNEQUAL_INCOMPATIBLE) {
268 return verModeResult;
269 }
270
271 // Return E_SCHEMA_EQUAL_EXACTLY or E_SCHEMA_UNEQUAL_INCOMPATIBLE
272 int skipSizeResult = CompareSchemaSkipSize(inSchemaObject);
273 if (skipSizeResult == -E_SCHEMA_UNEQUAL_INCOMPATIBLE) {
274 return skipSizeResult;
275 }
276
277 // Return E_SCHEMA_EQUAL_EXACTLY or E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE or E_SCHEMA_UNEQUAL_INCOMPATIBLE
278 int defineResult;
279 if (schemaType_ == SchemaType::JSON) {
280 defineResult = CompareSchemaDefine(inSchemaObject);
281 } else {
282 defineResult = flatbufferSchema_.CompareFlatBufferDefine(inSchemaObject.flatbufferSchema_);
283 }
284 if (defineResult == -E_SCHEMA_UNEQUAL_INCOMPATIBLE) {
285 return defineResult;
286 }
287
288 // Return E_SCHEMA_EQUAL_EXACTLY or E_SCHEMA_UNEQUAL_COMPATIBLE
289 int indexResult = CompareSchemaIndexes(inSchemaObject, indexDiffer);
290 return ((defineResult == -E_SCHEMA_EQUAL_EXACTLY) ? indexResult : defineResult);
291 }
292
CheckValueAndAmendIfNeed(ValueSource sourceType,ValueObject & inValue) const293 int SchemaObject::CheckValueAndAmendIfNeed(ValueSource sourceType, ValueObject &inValue) const
294 {
295 if (!isValid_ || schemaType_ != SchemaType::JSON) { // Currently this methed only support Json-Schema
296 return -E_NOT_PERMIT;
297 }
298
299 std::set<FieldPath> lackingPaths;
300 int errCode = CheckValue(inValue, lackingPaths);
301 if (errCode != -E_VALUE_MATCH) {
302 return errCode;
303 }
304
305 bool amended = false;
306 errCode = AmendValueIfNeed(inValue, lackingPaths, amended);
307 if (errCode != E_OK) { // Unlikely
308 LOGE("[Schema][CheckAmend] Amend fail, errCode=%d, srcType=%d.", errCode, static_cast<int>(sourceType));
309 return -E_INTERNAL_ERROR;
310 }
311 return (amended ? -E_VALUE_MATCH_AMENDED : -E_VALUE_MATCH);
312 }
313
VerifyValue(ValueSource sourceType,const Value & inValue) const314 int SchemaObject::VerifyValue(ValueSource sourceType, const Value &inValue) const
315 {
316 return VerifyValue(sourceType, RawValue{inValue.data(), inValue.size()});
317 }
318
VerifyValue(ValueSource sourceType,const RawValue & inValue) const319 int SchemaObject::VerifyValue(ValueSource sourceType, const RawValue &inValue) const
320 {
321 if (inValue.first == nullptr) { // LCOV_EXCL_BR_LINE
322 return -E_INVALID_ARGS;
323 }
324 if (!isValid_ || schemaType_ != SchemaType::FLATBUFFER) { // LCOV_EXCL_BR_LINE
325 return -E_NOT_PERMIT;
326 }
327 if (inValue.second <= schemaSkipSize_) { // LCOV_EXCL_BR_LINE
328 LOGE("[Schema][Verify] Value length=%" PRIu32 " invalid, skipsize=%" PRIu32, inValue.second, schemaSkipSize_);
329 return -E_FLATBUFFER_VERIFY_FAIL;
330 }
331
332 RawValue rawValue;
333 std::vector<uint8_t> cache;
334 if (schemaSkipSize_ % SchemaConstant::SECURE_BYTE_ALIGN == 0) { // LCOV_EXCL_BR_LINE
335 rawValue = {inValue.first + schemaSkipSize_, inValue.second - schemaSkipSize_};
336 } else {
337 cache.assign(inValue.first + schemaSkipSize_, inValue.first + inValue.second);
338 rawValue = {cache.data(), cache.size()};
339 }
340
341 // Currently do not try no sizePrefix, future may depend on sourceType
342 int errCode = flatbufferSchema_.VerifyFlatBufferValue(rawValue, false);
343 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
344 LOGE("[Schema][Verify] Value verify fail, srcType=%d.", static_cast<int>(sourceType));
345 return errCode;
346 }
347 return E_OK;
348 }
349
ExtractValue(ValueSource sourceType,RawString inPath,const RawValue & inValue,TypeValue & outExtract,std::vector<uint8_t> * cache) const350 int SchemaObject::ExtractValue(ValueSource sourceType, RawString inPath, const RawValue &inValue,
351 TypeValue &outExtract, std::vector<uint8_t> *cache) const
352 {
353 // NOTE!!! This function is performance sensitive !!! Carefully not to allocate memory often!!!
354 if (!isValid_ || schemaType_ != SchemaType::FLATBUFFER) { // LCOV_EXCL_BR_LINE
355 return -E_NOT_PERMIT;
356 }
357 if (inPath == nullptr || inValue.first == nullptr) { // LCOV_EXCL_BR_LINE
358 return -E_INVALID_ARGS;
359 }
360 if (inValue.second <= schemaSkipSize_) { // LCOV_EXCL_BR_LINE
361 LOGE("[Schema][Extract] Value length=%" PRIu32 " invalid, skip:%" PRIu32, inValue.second, schemaSkipSize_);
362 return -E_FLATBUFFER_VERIFY_FAIL;
363 }
364
365 RawValue rawValue;
366 std::vector<uint8_t> *tempCache = nullptr; // A temporary cache for use when input cache can not hold.
367 if (schemaSkipSize_ % SchemaConstant::SECURE_BYTE_ALIGN == 0) { // LCOV_EXCL_BR_LINE
368 rawValue = {inValue.first + schemaSkipSize_, inValue.second - schemaSkipSize_};
369 } else if ((cache != nullptr) && (cache->size() >= (inValue.second - schemaSkipSize_))) {
370 // Do not expand the cache if it can not hold
371 cache->assign(inValue.first + schemaSkipSize_, inValue.first + inValue.second);
372 rawValue = {cache->data(), inValue.second - schemaSkipSize_}; // Attention: Do not use cache.size() as second.
373 } else {
374 // Use a temporary cache, which will release its memory quickly
375 tempCache = new (std::nothrow) std::vector<uint8_t>;
376 if (tempCache == nullptr) {
377 LOGE("[Schema][Extract] OOM.");
378 return -E_OUT_OF_MEMORY;
379 }
380 tempCache->resize(inValue.second - schemaSkipSize_);
381 tempCache->assign(inValue.first + schemaSkipSize_, inValue.first + inValue.second);
382 rawValue = {tempCache->data(), tempCache->size()};
383 }
384
385 // Currently do not try no sizePrefix, future may depend on sourceType
386 int errCode = flatbufferSchema_.ExtractFlatBufferValue(inPath, rawValue, outExtract, false);
387 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
388 LOGE("[Schema][Extract] Fail, srcType=%d.", static_cast<int>(sourceType));
389 }
390 delete tempCache; // delete nullptr is safe
391 tempCache = nullptr;
392 return errCode;
393 }
394
ParseJsonSchema(const JsonObject & inJsonObject)395 int SchemaObject::ParseJsonSchema(const JsonObject &inJsonObject)
396 {
397 // Parse and check mandatory metaField below
398 int errCode = CheckMetaFieldCountAndType(inJsonObject);
399 if (errCode != E_OK) {
400 return errCode;
401 }
402 errCode = ParseCheckSchemaVersionMode(inJsonObject);
403 if (errCode != E_OK) {
404 return errCode;
405 }
406 errCode = ParseCheckSchemaDefine(inJsonObject);
407 if (errCode != E_OK) {
408 return errCode;
409 }
410 // Parse and check optional metaField below
411 errCode = ParseCheckSchemaIndexes(inJsonObject);
412 if (errCode != E_OK) {
413 return errCode;
414 }
415 return ParseCheckSchemaSkipSize(inJsonObject);
416 }
417
418 namespace {
CheckOptionalMetaFieldCountAndType(const std::map<FieldPath,FieldType> & metaFieldPathType)419 int CheckOptionalMetaFieldCountAndType(const std::map<FieldPath, FieldType> &metaFieldPathType)
420 {
421 uint32_t indexMetaFieldCount = 0;
422 uint32_t skipSizeMetaFieldCount = 0;
423 if (metaFieldPathType.count(FieldPath{SchemaConstant::KEYWORD_SCHEMA_INDEXES}) != 0) {
424 indexMetaFieldCount++;
425 FieldType type = metaFieldPathType.at(FieldPath{SchemaConstant::KEYWORD_SCHEMA_INDEXES});
426 if (type != FieldType::LEAF_FIELD_ARRAY) {
427 LOGE("[Schema][CheckMeta] Expect SCHEMA_INDEXES type ARRAY but %s.",
428 SchemaUtils::FieldTypeString(type).c_str());
429 return -E_SCHEMA_PARSE_FAIL;
430 }
431 }
432 if (metaFieldPathType.count(FieldPath{SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE}) != 0) {
433 skipSizeMetaFieldCount++;
434 FieldType type = metaFieldPathType.at(FieldPath{SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE});
435 if (type != FieldType::LEAF_FIELD_INTEGER) {
436 LOGE("[Schema][CheckMeta] Expect SCHEMA_SKIPSIZE type INTEGER but %s.",
437 SchemaUtils::FieldTypeString(type).c_str());
438 return -E_SCHEMA_PARSE_FAIL;
439 }
440 }
441 if (metaFieldPathType.size() != (SchemaConstant::SCHEMA_META_FEILD_COUNT_MIN + indexMetaFieldCount +
442 skipSizeMetaFieldCount)) {
443 LOGE("[Schema][CheckMeta] Unrecognized metaField exist: total=%zu, indexField=%" PRIu32 ", skipSizeField=%"
444 PRIu32, metaFieldPathType.size(), indexMetaFieldCount, skipSizeMetaFieldCount);
445 return -E_SCHEMA_PARSE_FAIL;
446 }
447 return E_OK;
448 }
449 }
450
CheckMetaFieldCountAndType(const JsonObject & inJsonObject) const451 int SchemaObject::CheckMetaFieldCountAndType(const JsonObject& inJsonObject) const
452 {
453 std::map<FieldPath, FieldType> metaFieldPathType;
454 int errCode = inJsonObject.GetSubFieldPathAndType(FieldPath(), metaFieldPathType);
455 if (errCode != E_OK) {
456 LOGE("[Schema][CheckMeta] GetSubFieldPathAndType fail, errCode=%d.", errCode);
457 return errCode;
458 }
459 if (metaFieldPathType.size() < SchemaConstant::SCHEMA_META_FEILD_COUNT_MIN ||
460 metaFieldPathType.size() > SchemaConstant::SCHEMA_META_FEILD_COUNT_MAX) {
461 LOGE("[Schema][CheckMeta] Unexpected metafield count=%zu.", metaFieldPathType.size());
462 return -E_SCHEMA_PARSE_FAIL;
463 }
464 // Check KeyWord SCHEMA_VERSION
465 if (metaFieldPathType.count(FieldPath{SchemaConstant::KEYWORD_SCHEMA_VERSION}) == 0) {
466 LOGE("[Schema][CheckMeta] Expect metafield SCHEMA_VERSION but not find.");
467 return -E_SCHEMA_PARSE_FAIL;
468 }
469 FieldType type = metaFieldPathType.at(FieldPath{SchemaConstant::KEYWORD_SCHEMA_VERSION});
470 if (type != FieldType::LEAF_FIELD_STRING) {
471 LOGE("[Schema][CheckMeta] Expect SCHEMA_VERSION type STRING but %s.",
472 SchemaUtils::FieldTypeString(type).c_str());
473 return -E_SCHEMA_PARSE_FAIL;
474 }
475 // Check KeyWord SCHEMA_MODE
476 if (metaFieldPathType.count(FieldPath{SchemaConstant::KEYWORD_SCHEMA_MODE}) == 0) {
477 LOGE("[Schema][CheckMeta] Expect metafield SCHEMA_MODE but not find.");
478 return -E_SCHEMA_PARSE_FAIL;
479 }
480 type = metaFieldPathType.at(FieldPath{SchemaConstant::KEYWORD_SCHEMA_MODE});
481 if (type != FieldType::LEAF_FIELD_STRING) {
482 LOGE("[Schema][CheckMeta] Expect SCHEMA_MODE type STRING but %s.", SchemaUtils::FieldTypeString(type).c_str());
483 return -E_SCHEMA_PARSE_FAIL;
484 }
485 // Check KeyWord SCHEMA_DEFINE
486 if (metaFieldPathType.count(FieldPath{SchemaConstant::KEYWORD_SCHEMA_DEFINE}) == 0) {
487 LOGE("[Schema][CheckMeta] Expect metafield SCHEMA_DEFINE but not find.");
488 return -E_SCHEMA_PARSE_FAIL;
489 }
490 type = metaFieldPathType.at(FieldPath{SchemaConstant::KEYWORD_SCHEMA_DEFINE});
491 if (type != FieldType::INTERNAL_FIELD_OBJECT) { // LEAF_FIELD_OBJECT indicate an empty object which is not allowed
492 LOGE("[Schema][CheckMeta] Expect SCHEMA_DEFINE type INTERNAL_OBJECT but %s.",
493 SchemaUtils::FieldTypeString(type).c_str());
494 return -E_SCHEMA_PARSE_FAIL;
495 }
496 // Check KeyWord SCHEMA_INDEXES If Need
497 return CheckOptionalMetaFieldCountAndType(metaFieldPathType);
498 }
499
ParseCheckSchemaVersionMode(const JsonObject & inJsonObject)500 int SchemaObject::ParseCheckSchemaVersionMode(const JsonObject& inJsonObject)
501 {
502 // Note: it has been checked in CheckMetaFieldCountAndType that SCHEMA_VERSION field exists and its type is string.
503 FieldValue versionValue;
504 int errCode = inJsonObject.GetFieldValueByFieldPath(FieldPath{SchemaConstant::KEYWORD_SCHEMA_VERSION},
505 versionValue);
506 if (errCode != E_OK) {
507 return -E_INTERNAL_ERROR;
508 }
509 if (SchemaUtils::Strip(versionValue.stringValue) != SchemaConstant::SCHEMA_SUPPORT_VERSION) {
510 LOGE("[Schema][ParseVerMode] Unexpected SCHEMA_VERSION=%s.", versionValue.stringValue.c_str());
511 return -E_SCHEMA_PARSE_FAIL;
512 }
513 schemaVersion_ = SchemaConstant::SCHEMA_SUPPORT_VERSION;
514
515 // Note: it has been checked in CheckMetaFieldCountAndType that SCHEMA_MODE field exists and its type is string.
516 FieldValue modeValue;
517 errCode = inJsonObject.GetFieldValueByFieldPath(FieldPath{SchemaConstant::KEYWORD_SCHEMA_MODE}, modeValue);
518 if (errCode != E_OK) {
519 return -E_INTERNAL_ERROR;
520 }
521 std::string modeStripped = SchemaUtils::Strip(modeValue.stringValue);
522 if (modeStripped != SchemaConstant::KEYWORD_MODE_STRICT &&
523 modeStripped != SchemaConstant::KEYWORD_MODE_COMPATIBLE) {
524 LOGE("[Schema][ParseVerMode] Unexpected SCHEMA_MODE=%s.", modeValue.stringValue.c_str());
525 return -E_SCHEMA_PARSE_FAIL;
526 }
527 schemaMode_ = ((modeStripped == SchemaConstant::KEYWORD_MODE_STRICT) ? SchemaMode::STRICT : SchemaMode::COMPATIBLE);
528 return E_OK;
529 }
530
ParseCheckSchemaDefine(const JsonObject & inJsonObject)531 int SchemaObject::ParseCheckSchemaDefine(const JsonObject& inJsonObject)
532 {
533 // Clear schemaDefine_ to recover from a fail parse
534 schemaDefine_.clear();
535 // Note: it has been checked in CheckMetaFieldCountAndType that SCHEMA_DEFINE field exists and its type is
536 // internal-object. Nest path refer to those field with type internal object that has sub field.
537 std::set<FieldPath> nestPathCurDepth{FieldPath{SchemaConstant::KEYWORD_SCHEMA_DEFINE}};
538 uint32_t fieldNameCount = 0;
539 for (uint32_t depth = 0; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
540 std::map<FieldPath, FieldType> subPathType;
541 int errCode = inJsonObject.GetSubFieldPathAndType(nestPathCurDepth, subPathType);
542 if (errCode != E_OK) { // Unlikely
543 LOGE("[Schema][ParseDefine] Internal Error: GetSubFieldPathAndType Fail, Depth=%" PRIu32, depth);
544 return -E_INTERNAL_ERROR;
545 }
546 fieldNameCount += subPathType.size();
547 nestPathCurDepth.clear(); // Clear it for collecting new nestPath
548 for (const auto &subField : subPathType) {
549 SchemaAttribute attribute;
550 errCode = CheckSchemaDefineItemDecideAttribute(inJsonObject, subField.first, subField.second, attribute);
551 if (errCode != E_OK) {
552 LOGE("[Schema][ParseDefine] CheckSchemaDefineItemDecideAttribute Fail.");
553 return -E_SCHEMA_PARSE_FAIL;
554 }
555 // If everything ok, insert this schema item into schema define
556 // Remember to remove SCHEMA_DEFINE in the front of the fieldpath
557 schemaDefine_[depth][FieldPath(++(subField.first.begin()), subField.first.end())] = attribute;
558 if (subField.second != FieldType::INTERNAL_FIELD_OBJECT) {
559 continue;
560 }
561 // Deal with the nestpath and check depth limitation
562 if (depth == (SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX - 1)) { // Minus 1 to be the boundary
563 LOGE("[Schema][ParseDefine] node is INTERNAL_FIELD_OBJECT but reach schema depth limitation.");
564 return -E_SCHEMA_PARSE_FAIL;
565 }
566 nestPathCurDepth.insert(subField.first);
567 }
568 // If no deeper schema define, quit loop in advance
569 if (nestPathCurDepth.empty()) {
570 break;
571 }
572 }
573 if (fieldNameCount > SchemaConstant::SCHEMA_FEILD_NAME_COUNT_MAX) {
574 // Check Field Count Here
575 LOGE("[Schema][ParseDefine] FieldName count=%" PRIu32 " exceed the limitation.", fieldNameCount);
576 return -E_SCHEMA_PARSE_FAIL;
577 }
578 return E_OK;
579 }
580
CheckSchemaDefineItemDecideAttribute(const JsonObject & inJsonObject,const FieldPath & inPath,FieldType inType,SchemaAttribute & outAttr) const581 int SchemaObject::CheckSchemaDefineItemDecideAttribute(const JsonObject& inJsonObject, const FieldPath &inPath,
582 FieldType inType, SchemaAttribute &outAttr) const
583 {
584 // Note: inPath will never be an empty vector, internal logic guarantee it, see the caller logic
585 if (inPath.empty()) { // Not Possible. Just For Clear CodeDEX.
586 return -E_INTERNAL_ERROR;
587 }
588 int errCode = SchemaUtils::CheckFieldName(inPath.back());
589 if (errCode != E_OK) {
590 LOGE("[Schema][CheckItemDecideAttr] Invalid fieldName, errCode=%d.", errCode);
591 return -E_SCHEMA_PARSE_FAIL;
592 }
593 if (inType == FieldType::LEAF_FIELD_STRING) {
594 FieldValue subFieldValue;
595 errCode = inJsonObject.GetFieldValueByFieldPath(inPath, subFieldValue);
596 if (errCode != E_OK) { // Unlikely
597 LOGE("[Schema][CheckItemDecideAttr] Internal Error: GetFieldValueByFieldPath Fail.");
598 return -E_INTERNAL_ERROR;
599 }
600 errCode = SchemaUtils::ParseAndCheckSchemaAttribute(subFieldValue.stringValue, outAttr);
601 if (errCode != E_OK) {
602 LOGE("[Schema][CheckItemDecideAttr] ParseAndCheckSchemaAttribute Fail, errCode=%d.", errCode);
603 return -E_SCHEMA_PARSE_FAIL;
604 }
605 // The ParseAndCheckSchemaAttribute do not cope with isIndexable field. Need to set it true here
606 outAttr.isIndexable = true;
607 } else if (inType == FieldType::LEAF_FIELD_ARRAY) {
608 uint32_t arraySize = 0;
609 errCode = inJsonObject.GetArraySize(inPath, arraySize);
610 if (errCode != E_OK) {
611 LOGE("[Schema][CheckItemDecideAttr] Internal Error: GetArraySize Fail.");
612 return -E_INTERNAL_ERROR;
613 }
614 if (arraySize != 0) {
615 LOGE("[Schema][CheckItemDecideAttr] Expect array empty but size=%u.", arraySize);
616 return -E_SCHEMA_PARSE_FAIL;
617 }
618 outAttr = SchemaAttribute{inType, false, false, false, FieldValue()};
619 } else if (inType == FieldType::LEAF_FIELD_OBJECT) {
620 outAttr = SchemaAttribute{inType, false, false, false, FieldValue()};
621 } else if (inType == FieldType::INTERNAL_FIELD_OBJECT) {
622 outAttr = SchemaAttribute{inType, false, false, false, FieldValue()}; // hasNotNull set false is OK for this
623 } else {
624 LOGE("[Schema][CheckItemDecideAttr] Unexpected FieldType=%s.", SchemaUtils::FieldTypeString(inType).c_str());
625 return -E_SCHEMA_PARSE_FAIL;
626 }
627 return E_OK;
628 }
629
ParseCheckSchemaIndexes(const JsonObject & inJsonObject)630 int SchemaObject::ParseCheckSchemaIndexes(const JsonObject& inJsonObject)
631 {
632 // Clear schemaIndexes_ to recover from a fail parse
633 schemaIndexes_.clear();
634 // No SCHEMA_INDEXES field is allowed
635 if (!inJsonObject.IsFieldPathExist(FieldPath{SchemaConstant::KEYWORD_SCHEMA_INDEXES})) {
636 LOGD("[Schema][ParseIndex] No SCHEMA_INDEXES Field.");
637 return E_OK;
638 }
639 // The type of SCHEMA_INDEXES field has been checked in CheckMetaFieldCountAndType to be an array
640 // If not all members of the array are string type or string-array, this call will return error
641 std::vector<std::vector<std::string>> oriIndexArray;
642 int errCode = inJsonObject.GetArrayContentOfStringOrStringArray(FieldPath{SchemaConstant::KEYWORD_SCHEMA_INDEXES},
643 oriIndexArray);
644 if (errCode != E_OK) {
645 LOGE("[Schema][ParseIndex] GetArrayContent Fail, errCode=%d.", errCode);
646 return -E_SCHEMA_PARSE_FAIL;
647 }
648 if (oriIndexArray.size() > SchemaConstant::SCHEMA_INDEX_COUNT_MAX) {
649 LOGE("[Schema][ParseIndex] Index(Ori) count=%zu exceed limitation.", oriIndexArray.size());
650 return -E_SCHEMA_PARSE_FAIL;
651 }
652 for (const auto &entry : oriIndexArray) {
653 errCode = ParseCheckEachIndexFromStringArray(entry);
654 if (errCode != E_OK) {
655 return errCode;
656 }
657 }
658 return E_OK;
659 }
660
ParseCheckSchemaSkipSize(const JsonObject & inJsonObject)661 int SchemaObject::ParseCheckSchemaSkipSize(const JsonObject& inJsonObject)
662 {
663 // No SCHEMA_SKIPSIZE field is allowed
664 if (!inJsonObject.IsFieldPathExist(FieldPath{SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE})) {
665 LOGD("[Schema][ParseSkipSize] No SCHEMA_SKIPSIZE Field.");
666 return E_OK;
667 }
668 // The type of SCHEMA_SKIPSIZE field has been checked in CheckMetaFieldCountAndType to be an INTEGER
669 FieldValue skipSizeValue;
670 int errCode = inJsonObject.GetFieldValueByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE},
671 skipSizeValue);
672 if (errCode != E_OK) {
673 return -E_INTERNAL_ERROR;
674 }
675 if (skipSizeValue.integerValue < 0 ||
676 static_cast<uint32_t>(skipSizeValue.integerValue) > SchemaConstant::SCHEMA_SKIPSIZE_MAX) {
677 LOGE("[Schema][ParseSkipSize] Unexpected SCHEMA_SKIPSIZE=%d.", skipSizeValue.integerValue);
678 return -E_SCHEMA_PARSE_FAIL;
679 }
680 schemaSkipSize_ = static_cast<uint32_t>(skipSizeValue.integerValue);
681 return E_OK;
682 }
683
ParseCheckEachIndexFromStringArray(const std::vector<std::string> & inStrArray)684 int SchemaObject::ParseCheckEachIndexFromStringArray(const std::vector<std::string> &inStrArray)
685 {
686 std::vector<FieldPath> indexPathVec;
687 std::set<FieldPath> indexPathSet;
688 // Parse each indexFieldPathString and check duplication
689 for (const auto &eachPathStr : inStrArray) {
690 FieldPath eachPath;
691 int errCode = SchemaUtils::ParseAndCheckFieldPath(eachPathStr, eachPath);
692 if (errCode != E_OK) {
693 LOGE("[Schema][ParseEachIndex] IndexPath Invalid.");
694 return -E_SCHEMA_PARSE_FAIL;
695 }
696 if (eachPath.size() == 0 || eachPath.size() > SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX) {
697 LOGE("[Schema][ParseEachIndex] Root not indexable or path depth exceed limit.");
698 return -E_SCHEMA_PARSE_FAIL;
699 }
700 if (indexPathSet.count(eachPath) != 0) {
701 LOGE("[Schema][ParseEachIndex] IndexPath Duplicated.");
702 return -E_SCHEMA_PARSE_FAIL;
703 }
704 indexPathVec.push_back(eachPath);
705 indexPathSet.insert(eachPath);
706 }
707 if (indexPathVec.empty()) { // Unlikely, empty JsonArray had been eliminated by GetArrayContent Method
708 return -E_INTERNAL_ERROR;
709 }
710 // Check indexDefine duplication, Use Sort-Column(the first fieldPath in index) as the indexName.
711 const IndexName &indexName = indexPathVec.front();
712 if (schemaIndexes_.count(indexName) != 0) {
713 LOGE("[Schema][ParseEachIndex] IndexName Already Defined.");
714 return -E_SCHEMA_PARSE_FAIL;
715 }
716 // Create new indexInfo entry, then check indexable for each indexFieldPath against schemaDefine
717 return CheckFieldPathIndexableThenSave(indexPathVec, schemaIndexes_[indexName]);
718 }
719
CheckFieldPathIndexableThenSave(const std::vector<FieldPath> & inPathVec,IndexInfo & infoToSave)720 int SchemaObject::CheckFieldPathIndexableThenSave(const std::vector<FieldPath> &inPathVec, IndexInfo &infoToSave)
721 {
722 for (const auto &eachPath : inPathVec) {
723 // Previous logic guarantee eachPath.size greater than zero
724 uint32_t depth = eachPath.size() - 1; // minus 1 to change depth count from zero
725 if (schemaDefine_.count(depth) == 0) {
726 LOGE("[Schema][CheckIndexable] No schema define of this depth.");
727 return -E_SCHEMA_PARSE_FAIL;
728 }
729 if (schemaDefine_[depth].count(eachPath) == 0) {
730 LOGE("[Schema][CheckIndexable] No such path in schema define.");
731 return -E_SCHEMA_PARSE_FAIL;
732 }
733 if (!schemaDefine_[depth][eachPath].isIndexable) {
734 LOGE("[Schema][CheckIndexable] Path is not indexable.");
735 return -E_SCHEMA_PARSE_FAIL;
736 }
737 // Save this indexField to indexInfo
738 infoToSave.push_back({eachPath, schemaDefine_[depth][eachPath].type});
739 }
740 return E_OK;
741 }
742
CompareSchemaVersionMode(const SchemaObject & newSchema) const743 int SchemaObject::CompareSchemaVersionMode(const SchemaObject &newSchema) const
744 {
745 if (schemaVersion_ != newSchema.schemaVersion_) {
746 LOGE("[Schema][CompareVerMode] OldVer=%s mismatch newVer=%s.", schemaVersion_.c_str(),
747 newSchema.schemaVersion_.c_str());
748 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
749 }
750
751 // Only Json-Schema need to compare mode
752 if (schemaType_ == SchemaType::JSON && schemaMode_ != newSchema.schemaMode_) {
753 static std::map<SchemaMode, std::string> modeMapString = {
754 {SchemaMode::STRICT, "STRICT"},
755 {SchemaMode::COMPATIBLE, "COMPATIBLE"},
756 };
757 LOGE("[Schema][CompareVerMode] OldMode=%s mismatch newMode=%s.", modeMapString[schemaMode_].c_str(),
758 modeMapString[newSchema.schemaMode_].c_str());
759 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
760 }
761 // Do not return E_OK here, E_OK is ambiguous.
762 return -E_SCHEMA_EQUAL_EXACTLY;
763 }
764
CompareSchemaSkipSize(const SchemaObject & newSchema) const765 int SchemaObject::CompareSchemaSkipSize(const SchemaObject &newSchema) const
766 {
767 if (schemaSkipSize_ != newSchema.schemaSkipSize_) {
768 LOGE("[Schema][CompareSkipSize] OldSkip=%u mismatch newSkip=%u.", schemaSkipSize_, newSchema.schemaSkipSize_);
769 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
770 }
771 // Do not return E_OK here, E_OK is ambiguous.
772 return -E_SCHEMA_EQUAL_EXACTLY;
773 }
774
CompareSchemaDefine(const SchemaObject & newSchema) const775 int SchemaObject::CompareSchemaDefine(const SchemaObject &newSchema) const
776 {
777 bool isEqualExactly = true;
778 for (uint32_t depth = 0; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
779 SchemaDefine emptyDefine;
780 const SchemaDefine &defineInOldSchema =
781 (schemaDefine_.count(depth) == 0 ? emptyDefine : schemaDefine_.at(depth));
782 const SchemaDefine &defineInNewSchema =
783 (newSchema.schemaDefine_.count(depth) == 0 ? emptyDefine : newSchema.schemaDefine_.at(depth));
784
785 // No define at this depth for both schema
786 if (defineInNewSchema.empty() && defineInOldSchema.empty()) {
787 break;
788 }
789 // No matter strict or compatible mode, newSchema can't have less field than oldSchema
790 if (defineInNewSchema.size() < defineInOldSchema.size()) {
791 LOGE("[Schema][CompareDefine] newSize=%zu less than oldSize=%zu at depth=%" PRIu32,
792 defineInNewSchema.size(), defineInOldSchema.size(), depth);
793 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
794 }
795 if (defineInNewSchema.size() > defineInOldSchema.size()) {
796 // Strict mode not support increase fieldDefine
797 if (schemaMode_ == SchemaMode::STRICT) {
798 LOGE("[Schema][CompareDefine] newSize=%zu more than oldSize=%zu at depth=%" PRIu32 " in STRICT mode.",
799 defineInNewSchema.size(), defineInOldSchema.size(), depth);
800 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
801 }
802 isEqualExactly = false;
803 }
804
805 // Compare schema define of this depth, looking for incompatible
806 int errCode = CompareSchemaDefineByDepth(defineInOldSchema, defineInNewSchema);
807 if (errCode == -E_SCHEMA_UNEQUAL_INCOMPATIBLE) {
808 return errCode;
809 }
810 }
811 // Do not return E_OK here, E_OK is ambiguous.
812 return (isEqualExactly ? -E_SCHEMA_EQUAL_EXACTLY : -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE);
813 }
814
815 namespace {
IsExtraFieldConformToCompatibility(const SchemaAttribute & inAttr)816 inline bool IsExtraFieldConformToCompatibility(const SchemaAttribute &inAttr)
817 {
818 return (!inAttr.hasNotNullConstraint || inAttr.hasDefaultValue);
819 }
820 }
821
CompareSchemaDefineByDepth(const SchemaDefine & oldDefine,const SchemaDefine & newDefine) const822 int SchemaObject::CompareSchemaDefineByDepth(const SchemaDefine &oldDefine, const SchemaDefine &newDefine) const
823 {
824 // Looking for incompatible : new define should at least contain all field the old define hold
825 for (auto &entry : oldDefine) {
826 if (newDefine.count(entry.first) == 0) {
827 LOGE("[Schema][CompareDefineDepth] fieldpath not found in new schema.");
828 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
829 }
830 // SchemaAttribute require to be equal exactly
831 int errCode = CompareSchemaAttribute(entry.second, newDefine.at(entry.first));
832 if (errCode != -E_SCHEMA_EQUAL_EXACTLY) {
833 LOGE("[Schema][CompareDefineDepth] Attribute mismatch at fieldpath.");
834 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
835 }
836 }
837 // Looking for incompatible : the extra field in new schema should has default or can be null
838 for (auto &entry : newDefine) {
839 if (oldDefine.count(entry.first) != 0) {
840 continue;
841 }
842 if (!IsExtraFieldConformToCompatibility(entry.second)) {
843 LOGE("[Schema][CompareDefineDepth] ExtraField, {notnull=%d, default=%d}, not conform compatibility.",
844 entry.second.hasNotNullConstraint, entry.second.hasDefaultValue);
845 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
846 }
847 }
848 return -E_SCHEMA_EQUAL_EXACTLY;
849 }
850
CompareSchemaAttribute(const SchemaAttribute & oldAttr,const SchemaAttribute & newAttr) const851 int SchemaObject::CompareSchemaAttribute(const SchemaAttribute &oldAttr, const SchemaAttribute &newAttr) const
852 {
853 if (oldAttr.type != newAttr.type) {
854 // The exceptional case is that the field type changed from the leaf_object to internal_object,
855 // which indicate that sub fields are added to it. Changed from internal_object to leaf_object will
856 // sooner or later cause an incompatible detection in next depth, we discern this situation here in advance.
857 if (!(oldAttr.type == FieldType::LEAF_FIELD_OBJECT && newAttr.type == FieldType::INTERNAL_FIELD_OBJECT)) {
858 LOGE("[Schema][CompareAttr] OldType=%s mismatch newType=%s.",
859 SchemaUtils::FieldTypeString(oldAttr.type).c_str(), SchemaUtils::FieldTypeString(newAttr.type).c_str());
860 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
861 }
862 }
863 // Here we use isIndexable info to distinguish two categories of type.
864 // "BOOL, INTEGER, LONG, DOUBLE, STRING" are all indexable type, NULL type will not appear in Schema
865 // "ARRAY, LEAF_OBJECT, INTERNAL_OBJECT" are all not indexable type.
866 // They have been checked same type just above. No need to check more for not indexable type
867 if (oldAttr.isIndexable) {
868 if (oldAttr.hasNotNullConstraint != newAttr.hasNotNullConstraint) {
869 LOGE("[Schema][CompareAttr] OldNotNull=%d mismatch newNotNull=%d.", oldAttr.hasNotNullConstraint,
870 newAttr.hasNotNullConstraint);
871 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
872 }
873 if (oldAttr.hasDefaultValue != newAttr.hasDefaultValue) {
874 LOGE("[Schema][CompareAttr] OldHasDefault=%d mismatch newHasDefault=%d.", oldAttr.hasDefaultValue,
875 newAttr.hasDefaultValue);
876 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
877 }
878 if (oldAttr.hasDefaultValue) {
879 // DefaultValue require to be equal exactly
880 int errCode = CompareSchemaDefaultValue(oldAttr, newAttr);
881 if (errCode != -E_SCHEMA_EQUAL_EXACTLY) {
882 return errCode;
883 }
884 }
885 }
886 return -E_SCHEMA_EQUAL_EXACTLY;
887 }
888
889 namespace {
IsDoubleBinaryEqual(double left,double right)890 inline bool IsDoubleBinaryEqual(double left, double right)
891 {
892 return *(reinterpret_cast<uint64_t *>(&left)) == *(reinterpret_cast<uint64_t *>(&right));
893 }
894 }
895
CompareSchemaDefaultValue(const SchemaAttribute & oldAttr,const SchemaAttribute & newAttr) const896 int SchemaObject::CompareSchemaDefaultValue(const SchemaAttribute &oldAttr, const SchemaAttribute &newAttr) const
897 {
898 // Value type has been check equal for both attribute in the caller
899 if (oldAttr.type == FieldType::LEAF_FIELD_BOOL) {
900 if (oldAttr.defaultValue.boolValue != newAttr.defaultValue.boolValue) {
901 LOGE("[Schema][CompareDefault] OldDefault=%d mismatch newDefault=%d.", oldAttr.defaultValue.boolValue,
902 newAttr.defaultValue.boolValue);
903 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
904 }
905 } else if (oldAttr.type == FieldType::LEAF_FIELD_INTEGER) {
906 if (oldAttr.defaultValue.integerValue != newAttr.defaultValue.integerValue) {
907 LOGE("[Schema][CompareDefault] OldDefault=%d mismatch newDefault=%d.", oldAttr.defaultValue.integerValue,
908 newAttr.defaultValue.integerValue);
909 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
910 }
911 } else if (oldAttr.type == FieldType::LEAF_FIELD_LONG) {
912 if (oldAttr.defaultValue.longValue != newAttr.defaultValue.longValue) {
913 LOGE("[Schema][CompareDefault] OldDefault=%" PRId64 " mismatch newDefault=%" PRId64 ".",
914 oldAttr.defaultValue.longValue, newAttr.defaultValue.longValue);
915 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
916 }
917 } else if (oldAttr.type == FieldType::LEAF_FIELD_DOUBLE) {
918 // ATTENTION: Here we should compare two double by their binary layout. We should not judge them equal when
919 // difference is small enough, since two different default double value may diff so little. The binary
920 // layout of the double value will be the same if the original string is the same, so we directly compare them.
921 if (!IsDoubleBinaryEqual(oldAttr.defaultValue.doubleValue, newAttr.defaultValue.doubleValue)) {
922 LOGE("[Schema][CompareDefault] OldDefault=%f mismatch newDefault=%f.", oldAttr.defaultValue.doubleValue,
923 newAttr.defaultValue.doubleValue);
924 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
925 }
926 } else if (oldAttr.type == FieldType::LEAF_FIELD_STRING) {
927 if (oldAttr.defaultValue.stringValue != newAttr.defaultValue.stringValue) {
928 LOGE("[Schema][CompareDefault] OldDefault=%s mismatch newDefault=%s.",
929 oldAttr.defaultValue.stringValue.c_str(), newAttr.defaultValue.stringValue.c_str());
930 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
931 }
932 }
933 // The caller logic guarantee that both attribute type will not be null, array, object
934 return -E_SCHEMA_EQUAL_EXACTLY;
935 }
936
937 namespace {
ClearIndexDifference(IndexDifference & indexDiffer)938 inline void ClearIndexDifference(IndexDifference &indexDiffer)
939 {
940 indexDiffer.change.clear();
941 indexDiffer.increase.clear();
942 indexDiffer.decrease.clear();
943 }
944
IsIndexInfoExactlyEqual(const IndexInfo & leftInfo,const IndexInfo & rightInfo)945 inline bool IsIndexInfoExactlyEqual(const IndexInfo &leftInfo, const IndexInfo &rightInfo)
946 {
947 // Exactly equal require count, order and type of each indexField in the index be the same
948 return leftInfo == rightInfo;
949 }
950
IsSchemaIndexesExactlyEqual(const IndexDifference & indexDiffer)951 inline bool IsSchemaIndexesExactlyEqual(const IndexDifference &indexDiffer)
952 {
953 return (indexDiffer.change.empty() && indexDiffer.increase.empty() && indexDiffer.decrease.empty());
954 }
955 }
956
CompareSchemaIndexes(const SchemaObject & newSchema,IndexDifference & indexDiffer) const957 int SchemaObject::CompareSchemaIndexes(const SchemaObject &newSchema, IndexDifference &indexDiffer) const
958 {
959 ClearIndexDifference(indexDiffer);
960 // Find the increase and change index
961 for (const auto &entry : newSchema.schemaIndexes_) {
962 if (schemaIndexes_.count(entry.first) == 0) {
963 LOGD("[Schema][CompareIndex] Increase indexName.");
964 indexDiffer.increase[entry.first] = entry.second;
965 } else {
966 // Both schema have same IndexName, Check whether indexInfo differs
967 if (!IsIndexInfoExactlyEqual(entry.second, schemaIndexes_.at(entry.first))) {
968 LOGD("[Schema][CompareIndex] Change indexName.");
969 indexDiffer.change[entry.first] = entry.second;
970 }
971 }
972 }
973 // Find the decrease index
974 for (const auto &entry : schemaIndexes_) {
975 if (newSchema.schemaIndexes_.count(entry.first) == 0) {
976 LOGD("[Schema][CompareIndex] Decrease indexName.");
977 indexDiffer.decrease.insert(entry.first);
978 }
979 }
980 // Do not return E_OK here, E_OK is ambiguous.
981 return IsSchemaIndexesExactlyEqual(indexDiffer) ? -E_SCHEMA_EQUAL_EXACTLY : -E_SCHEMA_UNEQUAL_COMPATIBLE;
982 }
983
984 namespace {
CheckValueItemNumericType(FieldType typeInValue,FieldType typeInSchema)985 int CheckValueItemNumericType(FieldType typeInValue, FieldType typeInSchema)
986 {
987 if (typeInValue == FieldType::LEAF_FIELD_DOUBLE) {
988 if (typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
989 return -E_VALUE_MISMATCH_FEILD_TYPE;
990 }
991 } else if (typeInValue == FieldType::LEAF_FIELD_LONG) {
992 if (typeInSchema != FieldType::LEAF_FIELD_LONG &&
993 typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
994 return -E_VALUE_MISMATCH_FEILD_TYPE;
995 }
996 } else {
997 // LEAF_FIELD_INTEGER
998 if (typeInSchema != FieldType::LEAF_FIELD_INTEGER &&
999 typeInSchema != FieldType::LEAF_FIELD_LONG &&
1000 typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
1001 return -E_VALUE_MISMATCH_FEILD_TYPE;
1002 }
1003 }
1004 return -E_VALUE_MATCH;
1005 }
1006
IsTypeMustBeExactlyEqualBetweenSchemaAndValue(FieldType inType)1007 inline bool IsTypeMustBeExactlyEqualBetweenSchemaAndValue(FieldType inType)
1008 {
1009 return (inType == FieldType::LEAF_FIELD_BOOL ||
1010 inType == FieldType::LEAF_FIELD_STRING ||
1011 inType == FieldType::LEAF_FIELD_ARRAY);
1012 }
1013
IsObjectType(FieldType inType)1014 inline bool IsObjectType(FieldType inType)
1015 {
1016 return (inType == FieldType::LEAF_FIELD_OBJECT || inType == FieldType::INTERNAL_FIELD_OBJECT);
1017 }
1018
1019 // Check in the value-view for convenience
CheckValueItem(const SchemaAttribute & refAttr,FieldType typeInValue)1020 int CheckValueItem(const SchemaAttribute &refAttr, FieldType typeInValue)
1021 {
1022 FieldType typeInSchema = refAttr.type;
1023 if (typeInSchema == FieldType::LEAF_FIELD_NULL) { // Unlikely
1024 return -E_INTERNAL_ERROR;
1025 }
1026 // Check NotNull-Constraint first
1027 if (typeInValue == FieldType::LEAF_FIELD_NULL) {
1028 if (refAttr.hasNotNullConstraint) {
1029 return -E_VALUE_MISMATCH_CONSTRAINT;
1030 }
1031 return -E_VALUE_MATCH;
1032 }
1033 // If typeInValue not NULL, check against schema. First check type that must be equal.
1034 if (IsTypeMustBeExactlyEqualBetweenSchemaAndValue(typeInValue)) {
1035 if (typeInValue != typeInSchema) {
1036 return -E_VALUE_MISMATCH_FEILD_TYPE;
1037 }
1038 return -E_VALUE_MATCH;
1039 }
1040 // Check Object related type, lack or more field will be deal with at next depth
1041 // typeInSchema/typeInValue LEAF_OBJECT INTERNAL_OBJECT
1042 // LEAF_OBJECT MATCH MATCH(More field at next depth)
1043 // INTERNAL_OBJECT MATCH(Lack field at next depth) MATCH
1044 // ELSE(POSSIBLE) TYPE_MISMATCH TYPE_MISMATCH
1045 if (IsObjectType(typeInValue)) {
1046 if (!IsObjectType(typeInSchema)) {
1047 return -E_VALUE_MISMATCH_FEILD_TYPE;
1048 }
1049 return -E_VALUE_MATCH;
1050 }
1051 // Check Numeric related type, at last
1052 return CheckValueItemNumericType(typeInValue, typeInSchema);
1053 }
1054
IsLackingFieldViolateNotNullConstraint(const SchemaAttribute & refAttr)1055 inline bool IsLackingFieldViolateNotNullConstraint(const SchemaAttribute &refAttr)
1056 {
1057 return (refAttr.hasNotNullConstraint && !refAttr.hasDefaultValue);
1058 }
1059
1060 // Function only for split big function
CheckValueBySchemaItem(const std::pair<FieldPath,SchemaAttribute> & schemaItem,const std::map<FieldPath,FieldType> & subPathType,std::set<FieldPath> & lackingPaths)1061 int CheckValueBySchemaItem(const std::pair<FieldPath, SchemaAttribute> &schemaItem,
1062 const std::map<FieldPath, FieldType> &subPathType, std::set<FieldPath> &lackingPaths)
1063 {
1064 if (subPathType.count(schemaItem.first) == 0) { // Value do not contain this field
1065 if (IsLackingFieldViolateNotNullConstraint(schemaItem.second)) {
1066 return -E_VALUE_MISMATCH_CONSTRAINT;
1067 }
1068 lackingPaths.insert(schemaItem.first);
1069 return -E_VALUE_MATCH;
1070 }
1071 // Value contain this field, check its type
1072 return CheckValueItem(schemaItem.second, subPathType.at(schemaItem.first));
1073 }
1074
ValueFieldType(const std::map<FieldPath,FieldType> & subPathType,const FieldPath & inPath)1075 inline std::string ValueFieldType(const std::map<FieldPath, FieldType> &subPathType, const FieldPath &inPath)
1076 {
1077 if (subPathType.count(inPath) == 0) {
1078 return "NotExist";
1079 }
1080 return SchemaUtils::FieldTypeString(subPathType.at(inPath));
1081 }
1082 }
1083
CheckValue(const ValueObject & inValue,std::set<FieldPath> & lackingPaths) const1084 int SchemaObject::CheckValue(const ValueObject &inValue, std::set<FieldPath> &lackingPaths) const
1085 {
1086 std::set<FieldPath> nestPathCurDepth{FieldPath()}; // Empty path represent root path
1087 for (uint32_t depth = 0; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
1088 if (schemaDefine_.count(depth) == 0 || schemaDefine_.at(depth).empty()) { // No schema define in this depth
1089 break;
1090 }
1091
1092 std::map<FieldPath, FieldType> subPathType;
1093 int errCode = inValue.GetSubFieldPathAndType(nestPathCurDepth, subPathType); // Value field of current depth
1094 if (errCode != E_OK && errCode != -E_INVALID_PATH) { // E_INVALID_PATH for path not exist
1095 LOGE("[Schema][CheckValue] GetSubFieldPathAndType Fail=%d, Depth=%" PRIu32, errCode, depth);
1096 return -E_VALUE_MISMATCH_FEILD_TYPE;
1097 }
1098 nestPathCurDepth.clear(); // Clear it for collecting new nestPath
1099
1100 if (schemaMode_ == SchemaMode::STRICT) {
1101 bool hasUndefined = std::any_of(subPathType.begin(), subPathType.end(), [this, depth] (const auto &it) {
1102 return (schemaDefine_.at(depth).count(it.first) == 0);
1103 });
1104 if (hasUndefined) {
1105 LOGE("[Schema][CheckValue] Undefined field in STRICT mode");
1106 return -E_VALUE_MISMATCH_FEILD_COUNT; // Value contain more field than schema
1107 }
1108 }
1109
1110 for (const auto &schemaItem : schemaDefine_.at(depth)) { // Check each field define in schema
1111 if (schemaItem.second.type == FieldType::INTERNAL_FIELD_OBJECT) {
1112 nestPathCurDepth.insert(schemaItem.first); // This field has subfield in schema
1113 }
1114 errCode = CheckValueBySchemaItem(schemaItem, subPathType, lackingPaths);
1115 if (errCode != -E_VALUE_MATCH) {
1116 LOGE("[Schema][CheckValue] Schema{NotNull=%d,Default=%d,Type=%s}, Value{Type=%s}, errCode=%d.",
1117 schemaItem.second.hasNotNullConstraint,
1118 schemaItem.second.hasDefaultValue, SchemaUtils::FieldTypeString(schemaItem.second.type).c_str(),
1119 ValueFieldType(subPathType, schemaItem.first).c_str(), errCode);
1120 return errCode;
1121 }
1122 }
1123 }
1124 return -E_VALUE_MATCH;
1125 }
1126
AmendValueIfNeed(ValueObject & inValue,const std::set<FieldPath> & lackingPaths,bool & amended) const1127 int SchemaObject::AmendValueIfNeed(ValueObject &inValue, const std::set<FieldPath> &lackingPaths, bool &amended) const
1128 {
1129 for (const auto &eachLackingPath : lackingPaths) {
1130 // Note: The upper code logic guarantee that eachLackingPath won't be empty and must exist in schemaDefine_
1131 uint32_t depth = eachLackingPath.size() - 1; // Depth count from zero
1132 const SchemaAttribute &lackingPathAttr = schemaDefine_.at(depth).at(eachLackingPath);
1133 // If no default value, just ignore this lackingPath
1134 if (!lackingPathAttr.hasDefaultValue) {
1135 continue;
1136 }
1137 // If has default value, the ParseSchema logic guarantee that fieldType won't be NULL, ARRAY or OBJECT
1138 // The lacking intermediate field will be automatically insert for this lackingPath
1139 int errCode = inValue.InsertField(eachLackingPath, lackingPathAttr.type, lackingPathAttr.defaultValue);
1140 if (errCode != E_OK) { // Unlikely
1141 LOGE("[Schema][AmendValue] InsertField fail, errCode=%d, Type=%s.", errCode,
1142 SchemaUtils::FieldTypeString(lackingPathAttr.type).c_str());
1143 return -E_INTERNAL_ERROR;
1144 }
1145 amended = true;
1146 }
1147 return E_OK;
1148 }
1149 } // namespace DistributedDB
1150