• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) {
322         return -E_INVALID_ARGS;
323     }
324     if (!isValid_ || schemaType_ != SchemaType::FLATBUFFER) {
325         return -E_NOT_PERMIT;
326     }
327     if (inValue.second <= schemaSkipSize_) {
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) {
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) {
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) {
355         return -E_NOT_PERMIT;
356     }
357     if (inPath == nullptr || inValue.first == nullptr) {
358         return -E_INVALID_ARGS;
359     }
360     if (inValue.second <= schemaSkipSize_) {
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) {
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) {
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             // Deal with the nestpath and check depth limitation
559             if (subField.second == FieldType::INTERNAL_FIELD_OBJECT) {
560                 if (depth == SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX - 1) { // Minus 1 to be the boundary
561                     LOGE("[Schema][ParseDefine] node is INTERNAL_FIELD_OBJECT but reach schema depth limitation.");
562                     return -E_SCHEMA_PARSE_FAIL;
563                 }
564                 nestPathCurDepth.insert(subField.first);
565             }
566         }
567         // If no deeper schema define, quit loop in advance
568         if (nestPathCurDepth.empty()) {
569             break;
570         }
571     }
572     if (fieldNameCount > SchemaConstant::SCHEMA_FEILD_NAME_COUNT_MAX) {
573         // Check Field Count Here
574         LOGE("[Schema][ParseDefine] FieldName count=%" PRIu32 " exceed the limitation.", fieldNameCount);
575         return -E_SCHEMA_PARSE_FAIL;
576     }
577     return E_OK;
578 }
579 
CheckSchemaDefineItemDecideAttribute(const JsonObject & inJsonObject,const FieldPath & inPath,FieldType inType,SchemaAttribute & outAttr) const580 int SchemaObject::CheckSchemaDefineItemDecideAttribute(const JsonObject& inJsonObject, const FieldPath &inPath,
581     FieldType inType, SchemaAttribute &outAttr) const
582 {
583     // Note: inPath will never be an empty vector, internal logic guarantee it, see the caller logic
584     if (inPath.empty()) { // Not Possible. Just For Clear CodeDEX.
585         return -E_INTERNAL_ERROR;
586     }
587     int errCode = SchemaUtils::CheckFieldName(inPath.back());
588     if (errCode != E_OK) {
589         LOGE("[Schema][CheckItemDecideAttr] Invalid fieldName, errCode=%d.", errCode);
590         return -E_SCHEMA_PARSE_FAIL;
591     }
592     if (inType == FieldType::LEAF_FIELD_STRING) {
593         FieldValue subFieldValue;
594         errCode = inJsonObject.GetFieldValueByFieldPath(inPath, subFieldValue);
595         if (errCode != E_OK) { // Unlikely
596             LOGE("[Schema][CheckItemDecideAttr] Internal Error: GetFieldValueByFieldPath Fail.");
597             return -E_INTERNAL_ERROR;
598         }
599         errCode = SchemaUtils::ParseAndCheckSchemaAttribute(subFieldValue.stringValue, outAttr);
600         if (errCode != E_OK) {
601             LOGE("[Schema][CheckItemDecideAttr] ParseAndCheckSchemaAttribute Fail, errCode=%d.", errCode);
602             return -E_SCHEMA_PARSE_FAIL;
603         }
604         // The ParseAndCheckSchemaAttribute do not cope with isIndexable field. Need to set it true here
605         outAttr.isIndexable = true;
606     } else if (inType == FieldType::LEAF_FIELD_ARRAY) {
607         uint32_t arraySize = 0;
608         errCode = inJsonObject.GetArraySize(inPath, arraySize);
609         if (errCode != E_OK) {
610             LOGE("[Schema][CheckItemDecideAttr] Internal Error: GetArraySize Fail.");
611             return -E_INTERNAL_ERROR;
612         }
613         if (arraySize != 0) {
614             LOGE("[Schema][CheckItemDecideAttr] Expect array empty but size=%u.", arraySize);
615             return -E_SCHEMA_PARSE_FAIL;
616         }
617         outAttr = SchemaAttribute{inType, false, false, false, FieldValue()};
618     } else if (inType == FieldType::LEAF_FIELD_OBJECT) {
619         outAttr = SchemaAttribute{inType, false, false, false, FieldValue()};
620     } else if (inType == FieldType::INTERNAL_FIELD_OBJECT) {
621         outAttr = SchemaAttribute{inType, false, false, false, FieldValue()}; // hasNotNull set false is OK for this
622     } else {
623         LOGE("[Schema][CheckItemDecideAttr] Unexpected FieldType=%s.", SchemaUtils::FieldTypeString(inType).c_str());
624         return -E_SCHEMA_PARSE_FAIL;
625     }
626     return E_OK;
627 }
628 
ParseCheckSchemaIndexes(const JsonObject & inJsonObject)629 int SchemaObject::ParseCheckSchemaIndexes(const JsonObject& inJsonObject)
630 {
631     // Clear schemaIndexes_ to recover from a fail parse
632     schemaIndexes_.clear();
633     // No SCHEMA_INDEXES field is allowed
634     if (!inJsonObject.IsFieldPathExist(FieldPath{SchemaConstant::KEYWORD_SCHEMA_INDEXES})) {
635         LOGD("[Schema][ParseIndex] No SCHEMA_INDEXES Field.");
636         return E_OK;
637     }
638     // The type of SCHEMA_INDEXES field has been checked in CheckMetaFieldCountAndType to be an array
639     // If not all members of the array are string type or string-array, this call will return error
640     std::vector<std::vector<std::string>> oriIndexArray;
641     int errCode = inJsonObject.GetArrayContentOfStringOrStringArray(FieldPath{SchemaConstant::KEYWORD_SCHEMA_INDEXES},
642         oriIndexArray);
643     if (errCode != E_OK) {
644         LOGE("[Schema][ParseIndex] GetArrayContent Fail, errCode=%d.", errCode);
645         return -E_SCHEMA_PARSE_FAIL;
646     }
647     if (oriIndexArray.size() > SchemaConstant::SCHEMA_INDEX_COUNT_MAX) {
648         LOGE("[Schema][ParseIndex] Index(Ori) count=%zu exceed limitation.", oriIndexArray.size());
649         return -E_SCHEMA_PARSE_FAIL;
650     }
651     for (const auto &entry : oriIndexArray) {
652         errCode = ParseCheckEachIndexFromStringArray(entry);
653         if (errCode != E_OK) {
654             return errCode;
655         }
656     }
657     return E_OK;
658 }
659 
ParseCheckSchemaSkipSize(const JsonObject & inJsonObject)660 int SchemaObject::ParseCheckSchemaSkipSize(const JsonObject& inJsonObject)
661 {
662     // No SCHEMA_SKIPSIZE field is allowed
663     if (!inJsonObject.IsFieldPathExist(FieldPath{SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE})) {
664         LOGD("[Schema][ParseSkipSize] No SCHEMA_SKIPSIZE Field.");
665         return E_OK;
666     }
667     // The type of SCHEMA_SKIPSIZE field has been checked in CheckMetaFieldCountAndType to be an INTEGER
668     FieldValue skipSizeValue;
669     int errCode = inJsonObject.GetFieldValueByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE},
670         skipSizeValue);
671     if (errCode != E_OK) {
672         return -E_INTERNAL_ERROR;
673     }
674     if (skipSizeValue.integerValue < 0 ||
675         static_cast<uint32_t>(skipSizeValue.integerValue) > SchemaConstant::SCHEMA_SKIPSIZE_MAX) {
676         LOGE("[Schema][ParseSkipSize] Unexpected SCHEMA_SKIPSIZE=%d.", skipSizeValue.integerValue);
677         return -E_SCHEMA_PARSE_FAIL;
678     }
679     schemaSkipSize_ = static_cast<uint32_t>(skipSizeValue.integerValue);
680     return E_OK;
681 }
682 
ParseCheckEachIndexFromStringArray(const std::vector<std::string> & inStrArray)683 int SchemaObject::ParseCheckEachIndexFromStringArray(const std::vector<std::string> &inStrArray)
684 {
685     std::vector<FieldPath> indexPathVec;
686     std::set<FieldPath> indexPathSet;
687     // Parse each indexFieldPathString and check duplication
688     for (const auto &eachPathStr : inStrArray) {
689         FieldPath eachPath;
690         int errCode = SchemaUtils::ParseAndCheckFieldPath(eachPathStr, eachPath);
691         if (errCode != E_OK) {
692             LOGE("[Schema][ParseEachIndex] IndexPath Invalid.");
693             return -E_SCHEMA_PARSE_FAIL;
694         }
695         if (eachPath.size() == 0 || eachPath.size() > SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX) {
696             LOGE("[Schema][ParseEachIndex] Root not indexable or path depth exceed limit.");
697             return -E_SCHEMA_PARSE_FAIL;
698         }
699         if (indexPathSet.count(eachPath) != 0) {
700             LOGE("[Schema][ParseEachIndex] IndexPath Duplicated.");
701             return -E_SCHEMA_PARSE_FAIL;
702         }
703         indexPathVec.push_back(eachPath);
704         indexPathSet.insert(eachPath);
705     }
706     if (indexPathVec.empty()) { // Unlikely, empty JsonArray had been eliminated by GetArrayContent Method
707         return -E_INTERNAL_ERROR;
708     }
709     // Check indexDefine duplication, Use Sort-Column(the first fieldPath in index) as the indexName.
710     const IndexName &indexName = indexPathVec.front();
711     if (schemaIndexes_.count(indexName) != 0) {
712         LOGE("[Schema][ParseEachIndex] IndexName Already Defined.");
713         return -E_SCHEMA_PARSE_FAIL;
714     }
715     // Create new indexInfo entry, then check indexable for each indexFieldPath against schemaDefine
716     return CheckFieldPathIndexableThenSave(indexPathVec, schemaIndexes_[indexName]);
717 }
718 
CheckFieldPathIndexableThenSave(const std::vector<FieldPath> & inPathVec,IndexInfo & infoToSave)719 int SchemaObject::CheckFieldPathIndexableThenSave(const std::vector<FieldPath> &inPathVec, IndexInfo &infoToSave)
720 {
721     for (const auto &eachPath : inPathVec) {
722         // Previous logic guarantee eachPath.size greater than zero
723         uint32_t depth = eachPath.size() - 1; // minus 1 to change depth count from zero
724         if (schemaDefine_.count(depth) == 0) {
725             LOGE("[Schema][CheckIndexable] No schema define of this depth.");
726             return -E_SCHEMA_PARSE_FAIL;
727         }
728         if (schemaDefine_[depth].count(eachPath) == 0) {
729             LOGE("[Schema][CheckIndexable] No such path in schema define.");
730             return -E_SCHEMA_PARSE_FAIL;
731         }
732         if (!schemaDefine_[depth][eachPath].isIndexable) {
733             LOGE("[Schema][CheckIndexable] Path is not indexable.");
734             return -E_SCHEMA_PARSE_FAIL;
735         }
736         // Save this indexField to indexInfo
737         infoToSave.push_back({eachPath, schemaDefine_[depth][eachPath].type});
738     }
739     return E_OK;
740 }
741 
CompareSchemaVersionMode(const SchemaObject & newSchema) const742 int SchemaObject::CompareSchemaVersionMode(const SchemaObject &newSchema) const
743 {
744     if (schemaVersion_ != newSchema.schemaVersion_) {
745         LOGE("[Schema][CompareVerMode] OldVer=%s mismatch newVer=%s.", schemaVersion_.c_str(),
746             newSchema.schemaVersion_.c_str());
747         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
748     }
749 
750     // Only Json-Schema need to compare mode
751     if (schemaType_ == SchemaType::JSON && schemaMode_ != newSchema.schemaMode_) {
752         static std::map<SchemaMode, std::string> modeMapString = {
753             {SchemaMode::STRICT, "STRICT"},
754             {SchemaMode::COMPATIBLE, "COMPATIBLE"},
755         };
756         LOGE("[Schema][CompareVerMode] OldMode=%s mismatch newMode=%s.", modeMapString[schemaMode_].c_str(),
757             modeMapString[newSchema.schemaMode_].c_str());
758         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
759     }
760     // Do not return E_OK here, E_OK is ambiguous.
761     return -E_SCHEMA_EQUAL_EXACTLY;
762 }
763 
CompareSchemaSkipSize(const SchemaObject & newSchema) const764 int SchemaObject::CompareSchemaSkipSize(const SchemaObject &newSchema) const
765 {
766     if (schemaSkipSize_ != newSchema.schemaSkipSize_) {
767         LOGE("[Schema][CompareSkipSize] OldSkip=%u mismatch newSkip=%u.", schemaSkipSize_, newSchema.schemaSkipSize_);
768         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
769     }
770     // Do not return E_OK here, E_OK is ambiguous.
771     return -E_SCHEMA_EQUAL_EXACTLY;
772 }
773 
CompareSchemaDefine(const SchemaObject & newSchema) const774 int SchemaObject::CompareSchemaDefine(const SchemaObject &newSchema) const
775 {
776     bool isEqualExactly = true;
777     for (uint32_t depth = 0; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
778         SchemaDefine emptyDefine;
779         const SchemaDefine &defineInOldSchema =
780             (schemaDefine_.count(depth) == 0 ? emptyDefine : schemaDefine_.at(depth));
781         const SchemaDefine &defineInNewSchema =
782             (newSchema.schemaDefine_.count(depth) == 0 ? emptyDefine : newSchema.schemaDefine_.at(depth));
783 
784         // No define at this depth for both schema
785         if (defineInNewSchema.empty() && defineInOldSchema.empty()) {
786             break;
787         }
788         // No matter strict or compatible mode, newSchema can't have less field than oldSchema
789         if (defineInNewSchema.size() < defineInOldSchema.size()) {
790             LOGE("[Schema][CompareDefine] newSize=%zu less than oldSize=%zu at depth=%" PRIu32,
791                 defineInNewSchema.size(), defineInOldSchema.size(), depth);
792             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
793         }
794         if (defineInNewSchema.size() > defineInOldSchema.size()) {
795             // Strict mode not support increase fieldDefine
796             if (schemaMode_ == SchemaMode::STRICT) {
797                 LOGE("[Schema][CompareDefine] newSize=%zu more than oldSize=%zu at depth=%" PRIu32 " in STRICT mode.",
798                     defineInNewSchema.size(), defineInOldSchema.size(), depth);
799                 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
800             }
801             isEqualExactly = false;
802         }
803 
804         // Compare schema define of this depth, looking for incompatible
805         int errCode = CompareSchemaDefineByDepth(defineInOldSchema, defineInNewSchema);
806         if (errCode == -E_SCHEMA_UNEQUAL_INCOMPATIBLE) {
807             return errCode;
808         }
809     }
810     // Do not return E_OK here, E_OK is ambiguous.
811     return (isEqualExactly ? -E_SCHEMA_EQUAL_EXACTLY : -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE);
812 }
813 
814 namespace {
IsExtraFieldConformToCompatibility(const SchemaAttribute & inAttr)815 inline bool IsExtraFieldConformToCompatibility(const SchemaAttribute &inAttr)
816 {
817     return (!inAttr.hasNotNullConstraint || inAttr.hasDefaultValue);
818 }
819 }
820 
CompareSchemaDefineByDepth(const SchemaDefine & oldDefine,const SchemaDefine & newDefine) const821 int SchemaObject::CompareSchemaDefineByDepth(const SchemaDefine &oldDefine, const SchemaDefine &newDefine) const
822 {
823     // Looking for incompatible : new define should at least contain all field the old define hold
824     for (auto &entry : oldDefine) {
825         if (newDefine.count(entry.first) == 0) {
826             LOGE("[Schema][CompareDefineDepth] fieldpath not found in new schema.");
827             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
828         }
829         // SchemaAttribute require to be equal exactly
830         int errCode = CompareSchemaAttribute(entry.second, newDefine.at(entry.first));
831         if (errCode != -E_SCHEMA_EQUAL_EXACTLY) {
832             LOGE("[Schema][CompareDefineDepth] Attribute mismatch at fieldpath.");
833             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
834         }
835     }
836     // Looking for incompatible : the extra field in new schema should has default or can be null
837     for (auto &entry : newDefine) {
838         if (oldDefine.count(entry.first) != 0) {
839             continue;
840         }
841         if (!IsExtraFieldConformToCompatibility(entry.second)) {
842             LOGE("[Schema][CompareDefineDepth] ExtraField, {notnull=%d, default=%d}, not conform compatibility.",
843                 entry.second.hasNotNullConstraint, entry.second.hasDefaultValue);
844             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
845         }
846     }
847     return -E_SCHEMA_EQUAL_EXACTLY;
848 }
849 
CompareSchemaAttribute(const SchemaAttribute & oldAttr,const SchemaAttribute & newAttr) const850 int SchemaObject::CompareSchemaAttribute(const SchemaAttribute &oldAttr, const SchemaAttribute &newAttr) const
851 {
852     if (oldAttr.type != newAttr.type) {
853         // The exceptional case is that the field type changed from the leaf_object to internal_object,
854         // which indicate that sub fields are added to it. Changed from internal_object to leaf_object will
855         // sooner or later cause an incompatible detection in next depth, we discern this situation here in advance.
856         if (!(oldAttr.type == FieldType::LEAF_FIELD_OBJECT && newAttr.type == FieldType::INTERNAL_FIELD_OBJECT)) {
857             LOGE("[Schema][CompareAttr] OldType=%s mismatch newType=%s.",
858                 SchemaUtils::FieldTypeString(oldAttr.type).c_str(), SchemaUtils::FieldTypeString(newAttr.type).c_str());
859             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
860         }
861     }
862     // Here we use isIndexable info to distinguish two categories of type.
863     // "BOOL, INTEGER, LONG, DOUBLE, STRING" are all indexable type, NULL type will not appear in Schema
864     // "ARRAY, LEAF_OBJECT, INTERNAL_OBJECT" are all not indexable type.
865     // They have been checked same type just above. No need to check more for not indexable type
866     if (oldAttr.isIndexable) {
867         if (oldAttr.hasNotNullConstraint != newAttr.hasNotNullConstraint) {
868             LOGE("[Schema][CompareAttr] OldNotNull=%d mismatch newNotNull=%d.", oldAttr.hasNotNullConstraint,
869                 newAttr.hasNotNullConstraint);
870             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
871         }
872         if (oldAttr.hasDefaultValue != newAttr.hasDefaultValue) {
873             LOGE("[Schema][CompareAttr] OldHasDefault=%d mismatch newHasDefault=%d.", oldAttr.hasDefaultValue,
874                 newAttr.hasDefaultValue);
875             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
876         }
877         if (oldAttr.hasDefaultValue) {
878             // DefaultValue require to be equal exactly
879             int errCode = CompareSchemaDefaultValue(oldAttr, newAttr);
880             if (errCode != -E_SCHEMA_EQUAL_EXACTLY) {
881                 return errCode;
882             }
883         }
884     }
885     return -E_SCHEMA_EQUAL_EXACTLY;
886 }
887 
888 namespace {
IsDoubleBinaryEqual(double left,double right)889 inline bool IsDoubleBinaryEqual(double left, double right)
890 {
891     return *(reinterpret_cast<uint64_t *>(&left)) == *(reinterpret_cast<uint64_t *>(&right));
892 }
893 }
894 
CompareSchemaDefaultValue(const SchemaAttribute & oldAttr,const SchemaAttribute & newAttr) const895 int SchemaObject::CompareSchemaDefaultValue(const SchemaAttribute &oldAttr, const SchemaAttribute &newAttr) const
896 {
897     // Value type has been check equal for both attribute in the caller
898     if (oldAttr.type == FieldType::LEAF_FIELD_BOOL) {
899         if (oldAttr.defaultValue.boolValue != newAttr.defaultValue.boolValue) {
900             LOGE("[Schema][CompareDefault] OldDefault=%d mismatch newDefault=%d.", oldAttr.defaultValue.boolValue,
901                 newAttr.defaultValue.boolValue);
902             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
903         }
904     } else if (oldAttr.type == FieldType::LEAF_FIELD_INTEGER) {
905         if (oldAttr.defaultValue.integerValue != newAttr.defaultValue.integerValue) {
906             LOGE("[Schema][CompareDefault] OldDefault=%d mismatch newDefault=%d.", oldAttr.defaultValue.integerValue,
907                 newAttr.defaultValue.integerValue);
908             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
909         }
910     } else if (oldAttr.type == FieldType::LEAF_FIELD_LONG) {
911         if (oldAttr.defaultValue.longValue != newAttr.defaultValue.longValue) {
912             LOGE("[Schema][CompareDefault] OldDefault=%" PRId64 " mismatch newDefault=%" PRId64 ".",
913                 oldAttr.defaultValue.longValue, newAttr.defaultValue.longValue);
914             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
915         }
916     } else if (oldAttr.type == FieldType::LEAF_FIELD_DOUBLE) {
917         // ATTENTION: Here we should compare two double by their binary layout. We should not judge them equal when
918         // difference is small enough, since two different default double value may diff so little. The binary
919         // layout of the double value will be the same if the original string is the same, so we directly compare them.
920         if (!IsDoubleBinaryEqual(oldAttr.defaultValue.doubleValue, newAttr.defaultValue.doubleValue)) {
921             LOGE("[Schema][CompareDefault] OldDefault=%f mismatch newDefault=%f.", oldAttr.defaultValue.doubleValue,
922                 newAttr.defaultValue.doubleValue);
923             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
924         }
925     } else if (oldAttr.type == FieldType::LEAF_FIELD_STRING) {
926         if (oldAttr.defaultValue.stringValue != newAttr.defaultValue.stringValue) {
927             LOGE("[Schema][CompareDefault] OldDefault=%s mismatch newDefault=%s.",
928                 oldAttr.defaultValue.stringValue.c_str(), newAttr.defaultValue.stringValue.c_str());
929             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
930         }
931     }
932     // The caller logic guarantee that both attribute type will not be null, array, object
933     return -E_SCHEMA_EQUAL_EXACTLY;
934 }
935 
936 namespace {
ClearIndexDifference(IndexDifference & indexDiffer)937 inline void ClearIndexDifference(IndexDifference &indexDiffer)
938 {
939     indexDiffer.change.clear();
940     indexDiffer.increase.clear();
941     indexDiffer.decrease.clear();
942 }
943 
IsIndexInfoExactlyEqual(const IndexInfo & leftInfo,const IndexInfo & rightInfo)944 inline bool IsIndexInfoExactlyEqual(const IndexInfo &leftInfo, const IndexInfo &rightInfo)
945 {
946     // Exactly equal require count, order and type of each indexField in the index be the same
947     return leftInfo == rightInfo;
948 }
949 
IsSchemaIndexesExactlyEqual(const IndexDifference & indexDiffer)950 inline bool IsSchemaIndexesExactlyEqual(const IndexDifference &indexDiffer)
951 {
952     return (indexDiffer.change.empty() && indexDiffer.increase.empty() && indexDiffer.decrease.empty());
953 }
954 }
955 
CompareSchemaIndexes(const SchemaObject & newSchema,IndexDifference & indexDiffer) const956 int SchemaObject::CompareSchemaIndexes(const SchemaObject &newSchema, IndexDifference &indexDiffer) const
957 {
958     ClearIndexDifference(indexDiffer);
959     // Find the increase and change index
960     for (const auto &entry : newSchema.schemaIndexes_) {
961         if (schemaIndexes_.count(entry.first) == 0) {
962             LOGD("[Schema][CompareIndex] Increase indexName.");
963             indexDiffer.increase[entry.first] = entry.second;
964         } else {
965             // Both schema have same IndexName, Check whether indexInfo differs
966             if (!IsIndexInfoExactlyEqual(entry.second, schemaIndexes_.at(entry.first))) {
967                 LOGD("[Schema][CompareIndex] Change indexName.");
968                 indexDiffer.change[entry.first] = entry.second;
969             }
970         }
971     }
972     // Find the decrease index
973     for (const auto &entry : schemaIndexes_) {
974         if (newSchema.schemaIndexes_.count(entry.first) == 0) {
975             LOGD("[Schema][CompareIndex] Decrease indexName.");
976             indexDiffer.decrease.insert(entry.first);
977         }
978     }
979     // Do not return E_OK here, E_OK is ambiguous.
980     return IsSchemaIndexesExactlyEqual(indexDiffer) ? -E_SCHEMA_EQUAL_EXACTLY : -E_SCHEMA_UNEQUAL_COMPATIBLE;
981 }
982 
983 namespace {
CheckValueItemNumericType(FieldType typeInValue,FieldType typeInSchema)984 int CheckValueItemNumericType(FieldType typeInValue, FieldType typeInSchema)
985 {
986     if (typeInValue == FieldType::LEAF_FIELD_DOUBLE) {
987         if (typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
988             return -E_VALUE_MISMATCH_FEILD_TYPE;
989         }
990     } else if (typeInValue == FieldType::LEAF_FIELD_LONG) {
991         if (typeInSchema != FieldType::LEAF_FIELD_LONG &&
992             typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
993             return -E_VALUE_MISMATCH_FEILD_TYPE;
994         }
995     } else {
996         // LEAF_FIELD_INTEGER
997         if (typeInSchema != FieldType::LEAF_FIELD_INTEGER &&
998             typeInSchema != FieldType::LEAF_FIELD_LONG &&
999             typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
1000             return -E_VALUE_MISMATCH_FEILD_TYPE;
1001         }
1002     }
1003     return -E_VALUE_MATCH;
1004 }
1005 
IsTypeMustBeExactlyEqualBetweenSchemaAndValue(FieldType inType)1006 inline bool IsTypeMustBeExactlyEqualBetweenSchemaAndValue(FieldType inType)
1007 {
1008     return (inType == FieldType::LEAF_FIELD_BOOL ||
1009             inType == FieldType::LEAF_FIELD_STRING ||
1010             inType == FieldType::LEAF_FIELD_ARRAY);
1011 }
1012 
IsObjectType(FieldType inType)1013 inline bool IsObjectType(FieldType inType)
1014 {
1015     return (inType == FieldType::LEAF_FIELD_OBJECT || inType == FieldType::INTERNAL_FIELD_OBJECT);
1016 }
1017 
1018 // Check in the value-view for convenience
CheckValueItem(const SchemaAttribute & refAttr,FieldType typeInValue)1019 int CheckValueItem(const SchemaAttribute &refAttr, FieldType typeInValue)
1020 {
1021     FieldType typeInSchema = refAttr.type;
1022     if (typeInSchema == FieldType::LEAF_FIELD_NULL) { // Unlikely
1023         return -E_INTERNAL_ERROR;
1024     }
1025     // Check NotNull-Constraint first
1026     if (typeInValue == FieldType::LEAF_FIELD_NULL) {
1027         if (refAttr.hasNotNullConstraint) {
1028             return -E_VALUE_MISMATCH_CONSTRAINT;
1029         }
1030         return -E_VALUE_MATCH;
1031     }
1032     // If typeInValue not NULL, check against schema. First check type that must be equal.
1033     if (IsTypeMustBeExactlyEqualBetweenSchemaAndValue(typeInValue)) {
1034         if (typeInValue != typeInSchema) {
1035             return -E_VALUE_MISMATCH_FEILD_TYPE;
1036         }
1037         return -E_VALUE_MATCH;
1038     }
1039     // Check Object related type, lack or more field will be deal with at next depth
1040     // typeInSchema/typeInValue     LEAF_OBJECT                         INTERNAL_OBJECT
1041     //              LEAF_OBJECT     MATCH                               MATCH(More field at next depth)
1042     //          INTERNAL_OBJECT     MATCH(Lack field at next depth)     MATCH
1043     //           ELSE(POSSIBLE)     TYPE_MISMATCH                       TYPE_MISMATCH
1044     if (IsObjectType(typeInValue)) {
1045         if (!IsObjectType(typeInSchema)) {
1046             return -E_VALUE_MISMATCH_FEILD_TYPE;
1047         }
1048         return -E_VALUE_MATCH;
1049     }
1050     // Check Numeric related type, at last
1051     return CheckValueItemNumericType(typeInValue, typeInSchema);
1052 }
1053 
IsLackingFieldViolateNotNullConstraint(const SchemaAttribute & refAttr)1054 inline bool IsLackingFieldViolateNotNullConstraint(const SchemaAttribute &refAttr)
1055 {
1056     return (refAttr.hasNotNullConstraint && !refAttr.hasDefaultValue);
1057 }
1058 
1059 // Function only for split big function
CheckValueBySchemaItem(const std::pair<FieldPath,SchemaAttribute> & schemaItem,const std::map<FieldPath,FieldType> & subPathType,std::set<FieldPath> & lackingPaths)1060 int CheckValueBySchemaItem(const std::pair<FieldPath, SchemaAttribute> &schemaItem,
1061     const std::map<FieldPath, FieldType> &subPathType, std::set<FieldPath> &lackingPaths)
1062 {
1063     if (subPathType.count(schemaItem.first) == 0) { // Value do not contain this field
1064         if (IsLackingFieldViolateNotNullConstraint(schemaItem.second)) {
1065             return -E_VALUE_MISMATCH_CONSTRAINT;
1066         }
1067         lackingPaths.insert(schemaItem.first);
1068         return -E_VALUE_MATCH;
1069     }
1070     // Value contain this field, check its type
1071     return CheckValueItem(schemaItem.second, subPathType.at(schemaItem.first));
1072 }
1073 
ValueFieldType(const std::map<FieldPath,FieldType> & subPathType,const FieldPath & inPath)1074 inline std::string ValueFieldType(const std::map<FieldPath, FieldType> &subPathType, const FieldPath &inPath)
1075 {
1076     if (subPathType.count(inPath) == 0) {
1077         return "NotExist";
1078     }
1079     return SchemaUtils::FieldTypeString(subPathType.at(inPath));
1080 }
1081 }
1082 
CheckValue(const ValueObject & inValue,std::set<FieldPath> & lackingPaths) const1083 int SchemaObject::CheckValue(const ValueObject &inValue, std::set<FieldPath> &lackingPaths) const
1084 {
1085     std::set<FieldPath> nestPathCurDepth{FieldPath()}; // Empty path represent root path
1086     for (uint32_t depth = 0; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
1087         if (schemaDefine_.count(depth) == 0 || schemaDefine_.at(depth).empty()) { // No schema define in this depth
1088             break;
1089         }
1090 
1091         std::map<FieldPath, FieldType> subPathType;
1092         int errCode = inValue.GetSubFieldPathAndType(nestPathCurDepth, subPathType); // Value field of current depth
1093         if (errCode != E_OK && errCode != -E_INVALID_PATH) { // E_INVALID_PATH for path not exist
1094             LOGE("[Schema][CheckValue] GetSubFieldPathAndType Fail=%d, Depth=%" PRIu32, errCode, depth);
1095             return -E_VALUE_MISMATCH_FEILD_TYPE;
1096         }
1097         nestPathCurDepth.clear(); // Clear it for collecting new nestPath
1098 
1099         if (schemaMode_ == SchemaMode::STRICT) {
1100             bool hasUndefined = std::any_of(subPathType.begin(), subPathType.end(), [this, depth] (const auto &it) {
1101                 return (schemaDefine_.at(depth).count(it.first) == 0);
1102             });
1103             if (hasUndefined) {
1104                 LOGE("[Schema][CheckValue] Undefined field in STRICT mode");
1105                 return -E_VALUE_MISMATCH_FEILD_COUNT; // Value contain more field than schema
1106             }
1107         }
1108 
1109         for (const auto &schemaItem : schemaDefine_.at(depth)) { // Check each field define in schema
1110             if (schemaItem.second.type == FieldType::INTERNAL_FIELD_OBJECT) {
1111                 nestPathCurDepth.insert(schemaItem.first); // This field has subfield in schema
1112             }
1113             errCode = CheckValueBySchemaItem(schemaItem, subPathType, lackingPaths);
1114             if (errCode != -E_VALUE_MATCH) {
1115                 LOGE("[Schema][CheckValue] Schema{NotNull=%d,Default=%d,Type=%s}, Value{Type=%s}, errCode=%d.",
1116                     schemaItem.second.hasNotNullConstraint,
1117                     schemaItem.second.hasDefaultValue, SchemaUtils::FieldTypeString(schemaItem.second.type).c_str(),
1118                     ValueFieldType(subPathType, schemaItem.first).c_str(), errCode);
1119                 return errCode;
1120             }
1121         }
1122     }
1123     return -E_VALUE_MATCH;
1124 }
1125 
AmendValueIfNeed(ValueObject & inValue,const std::set<FieldPath> & lackingPaths,bool & amended) const1126 int SchemaObject::AmendValueIfNeed(ValueObject &inValue, const std::set<FieldPath> &lackingPaths, bool &amended) const
1127 {
1128     for (const auto &eachLackingPath : lackingPaths) {
1129         // Note: The upper code logic guarantee that eachLackingPath won't be empty and must exist in schemaDefine_
1130         uint32_t depth = eachLackingPath.size() - 1; // Depth count from zero
1131         const SchemaAttribute &lackingPathAttr = schemaDefine_.at(depth).at(eachLackingPath);
1132         // If no default value, just ignore this lackingPath
1133         if (!lackingPathAttr.hasDefaultValue) {
1134             continue;
1135         }
1136         // If has default value, the ParseSchema logic guarantee that fieldType won't be NULL, ARRAY or OBJECT
1137         // The lacking intermediate field will be automatically insert for this lackingPath
1138         int errCode = inValue.InsertField(eachLackingPath, lackingPathAttr.type, lackingPathAttr.defaultValue);
1139         if (errCode != E_OK) { // Unlikely
1140             LOGE("[Schema][AmendValue] InsertField fail, errCode=%d, Type=%s.", errCode,
1141                 SchemaUtils::FieldTypeString(lackingPathAttr.type).c_str());
1142             return -E_INTERNAL_ERROR;
1143         }
1144         amended = true;
1145     }
1146     return E_OK;
1147 }
1148 } // namespace DistributedDB
1149