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