• 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         LOGE("[Schema][CompareVerMode] OldMode=%d mismatch newMode=%d.", static_cast<int>(schemaMode_),
753             static_cast<int>(newSchema.schemaMode_));
754         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
755     }
756     // Do not return E_OK here, E_OK is ambiguous.
757     return -E_SCHEMA_EQUAL_EXACTLY;
758 }
759 
CompareSchemaSkipSize(const SchemaObject & newSchema) const760 int SchemaObject::CompareSchemaSkipSize(const SchemaObject &newSchema) const
761 {
762     if (schemaSkipSize_ != newSchema.schemaSkipSize_) {
763         LOGE("[Schema][CompareSkipSize] OldSkip=%u mismatch newSkip=%u.", schemaSkipSize_, newSchema.schemaSkipSize_);
764         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
765     }
766     // Do not return E_OK here, E_OK is ambiguous.
767     return -E_SCHEMA_EQUAL_EXACTLY;
768 }
769 
CompareSchemaDefine(const SchemaObject & newSchema) const770 int SchemaObject::CompareSchemaDefine(const SchemaObject &newSchema) const
771 {
772     bool isEqualExactly = true;
773     for (uint32_t depth = 0; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
774         SchemaDefine emptyDefine;
775         const SchemaDefine &defineInOldSchema =
776             (schemaDefine_.count(depth) == 0 ? emptyDefine : schemaDefine_.at(depth));
777         const SchemaDefine &defineInNewSchema =
778             (newSchema.schemaDefine_.count(depth) == 0 ? emptyDefine : newSchema.schemaDefine_.at(depth));
779 
780         // No define at this depth for both schema
781         if (defineInNewSchema.empty() && defineInOldSchema.empty()) {
782             break;
783         }
784         // No matter strict or compatible mode, newSchema can't have less field than oldSchema
785         if (defineInNewSchema.size() < defineInOldSchema.size()) {
786             LOGE("[Schema][CompareDefine] newSize=%zu less than oldSize=%zu at depth=%" PRIu32,
787                 defineInNewSchema.size(), defineInOldSchema.size(), depth);
788             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
789         }
790         if (defineInNewSchema.size() > defineInOldSchema.size()) {
791             // Strict mode not support increase fieldDefine
792             if (schemaMode_ == SchemaMode::STRICT) {
793                 LOGE("[Schema][CompareDefine] newSize=%zu more than oldSize=%zu at depth=%" PRIu32 " in STRICT mode.",
794                     defineInNewSchema.size(), defineInOldSchema.size(), depth);
795                 return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
796             }
797             isEqualExactly = false;
798         }
799 
800         // Compare schema define of this depth, looking for incompatible
801         int errCode = CompareSchemaDefineByDepth(defineInOldSchema, defineInNewSchema);
802         if (errCode == -E_SCHEMA_UNEQUAL_INCOMPATIBLE) {
803             return errCode;
804         }
805     }
806     // Do not return E_OK here, E_OK is ambiguous.
807     return (isEqualExactly ? -E_SCHEMA_EQUAL_EXACTLY : -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE);
808 }
809 
810 namespace {
IsExtraFieldConformToCompatibility(const SchemaAttribute & inAttr)811 inline bool IsExtraFieldConformToCompatibility(const SchemaAttribute &inAttr)
812 {
813     return (!inAttr.hasNotNullConstraint || inAttr.hasDefaultValue);
814 }
815 }
816 
CompareSchemaDefineByDepth(const SchemaDefine & oldDefine,const SchemaDefine & newDefine) const817 int SchemaObject::CompareSchemaDefineByDepth(const SchemaDefine &oldDefine, const SchemaDefine &newDefine) const
818 {
819     // Looking for incompatible : new define should at least contain all field the old define hold
820     for (auto &entry : oldDefine) {
821         if (newDefine.count(entry.first) == 0) {
822             LOGE("[Schema][CompareDefineDepth] fieldpath not found in new schema.");
823             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
824         }
825         // SchemaAttribute require to be equal exactly
826         int errCode = CompareSchemaAttribute(entry.second, newDefine.at(entry.first));
827         if (errCode != -E_SCHEMA_EQUAL_EXACTLY) {
828             LOGE("[Schema][CompareDefineDepth] Attribute mismatch at fieldpath.");
829             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
830         }
831     }
832     // Looking for incompatible : the extra field in new schema should has default or can be null
833     for (auto &entry : newDefine) {
834         if (oldDefine.count(entry.first) != 0) {
835             continue;
836         }
837         if (!IsExtraFieldConformToCompatibility(entry.second)) {
838             LOGE("[Schema][CompareDefineDepth] ExtraField, {notnull=%d, default=%d}, not conform compatibility.",
839                 entry.second.hasNotNullConstraint, entry.second.hasDefaultValue);
840             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
841         }
842     }
843     return -E_SCHEMA_EQUAL_EXACTLY;
844 }
845 
CompareSchemaAttribute(const SchemaAttribute & oldAttr,const SchemaAttribute & newAttr) const846 int SchemaObject::CompareSchemaAttribute(const SchemaAttribute &oldAttr, const SchemaAttribute &newAttr) const
847 {
848     if (oldAttr.type != newAttr.type) {
849         // The exceptional case is that the field type changed from the leaf_object to internal_object,
850         // which indicate that sub fields are added to it. Changed from internal_object to leaf_object will
851         // sooner or later cause an incompatible detection in next depth, we discern this situation here in advance.
852         if (!(oldAttr.type == FieldType::LEAF_FIELD_OBJECT && newAttr.type == FieldType::INTERNAL_FIELD_OBJECT)) {
853             LOGE("[Schema][CompareAttr] OldType=%s mismatch newType=%s.",
854                 SchemaUtils::FieldTypeString(oldAttr.type).c_str(), SchemaUtils::FieldTypeString(newAttr.type).c_str());
855             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
856         }
857     }
858     // Here we use isIndexable info to distinguish two categories of type.
859     // "BOOL, INTEGER, LONG, DOUBLE, STRING" are all indexable type, NULL type will not appear in Schema
860     // "ARRAY, LEAF_OBJECT, INTERNAL_OBJECT" are all not indexable type.
861     // They have been checked same type just above. No need to check more for not indexable type
862     if (oldAttr.isIndexable) {
863         if (oldAttr.hasNotNullConstraint != newAttr.hasNotNullConstraint) {
864             LOGE("[Schema][CompareAttr] OldNotNull=%d mismatch newNotNull=%d.", oldAttr.hasNotNullConstraint,
865                 newAttr.hasNotNullConstraint);
866             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
867         }
868         if (oldAttr.hasDefaultValue != newAttr.hasDefaultValue) {
869             LOGE("[Schema][CompareAttr] OldHasDefault=%d mismatch newHasDefault=%d.", oldAttr.hasDefaultValue,
870                 newAttr.hasDefaultValue);
871             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
872         }
873         if (oldAttr.hasDefaultValue) {
874             // DefaultValue require to be equal exactly
875             int errCode = CompareSchemaDefaultValue(oldAttr, newAttr);
876             if (errCode != -E_SCHEMA_EQUAL_EXACTLY) {
877                 return errCode;
878             }
879         }
880     }
881     return -E_SCHEMA_EQUAL_EXACTLY;
882 }
883 
884 namespace {
IsDoubleBinaryEqual(double left,double right)885 inline bool IsDoubleBinaryEqual(double left, double right)
886 {
887     return *(reinterpret_cast<uint64_t *>(&left)) == *(reinterpret_cast<uint64_t *>(&right));
888 }
889 }
890 
CompareSchemaDefaultValue(const SchemaAttribute & oldAttr,const SchemaAttribute & newAttr) const891 int SchemaObject::CompareSchemaDefaultValue(const SchemaAttribute &oldAttr, const SchemaAttribute &newAttr) const
892 {
893     // Value type has been check equal for both attribute in the caller
894     if (oldAttr.type == FieldType::LEAF_FIELD_BOOL) {
895         if (oldAttr.defaultValue.boolValue != newAttr.defaultValue.boolValue) {
896             LOGE("[Schema][CompareDefault] OldDefault=%d mismatch newDefault=%d.", oldAttr.defaultValue.boolValue,
897                 newAttr.defaultValue.boolValue);
898             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
899         }
900     } else if (oldAttr.type == FieldType::LEAF_FIELD_INTEGER) {
901         if (oldAttr.defaultValue.integerValue != newAttr.defaultValue.integerValue) {
902             LOGE("[Schema][CompareDefault] OldDefault=%d mismatch newDefault=%d.", oldAttr.defaultValue.integerValue,
903                 newAttr.defaultValue.integerValue);
904             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
905         }
906     } else if (oldAttr.type == FieldType::LEAF_FIELD_LONG) {
907         if (oldAttr.defaultValue.longValue != newAttr.defaultValue.longValue) {
908             LOGE("[Schema][CompareDefault] OldDefault=%" PRId64 " mismatch newDefault=%" PRId64 ".",
909                 oldAttr.defaultValue.longValue, newAttr.defaultValue.longValue);
910             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
911         }
912     } else if (oldAttr.type == FieldType::LEAF_FIELD_DOUBLE) {
913         // ATTENTION: Here we should compare two double by their binary layout. We should not judge them equal when
914         // difference is small enough, since two different default double value may diff so little. The binary
915         // layout of the double value will be the same if the original string is the same, so we directly compare them.
916         if (!IsDoubleBinaryEqual(oldAttr.defaultValue.doubleValue, newAttr.defaultValue.doubleValue)) {
917             LOGE("[Schema][CompareDefault] OldDefault=%f mismatch newDefault=%f.", oldAttr.defaultValue.doubleValue,
918                 newAttr.defaultValue.doubleValue);
919             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
920         }
921     } else if (oldAttr.type == FieldType::LEAF_FIELD_STRING) {
922         if (oldAttr.defaultValue.stringValue != newAttr.defaultValue.stringValue) {
923             LOGE("[Schema][CompareDefault] OldDefault=%s mismatch newDefault=%s.",
924                 oldAttr.defaultValue.stringValue.c_str(), newAttr.defaultValue.stringValue.c_str());
925             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
926         }
927     }
928     // The caller logic guarantee that both attribute type will not be null, array, object
929     return -E_SCHEMA_EQUAL_EXACTLY;
930 }
931 
932 namespace {
ClearIndexDifference(IndexDifference & indexDiffer)933 inline void ClearIndexDifference(IndexDifference &indexDiffer)
934 {
935     indexDiffer.change.clear();
936     indexDiffer.increase.clear();
937     indexDiffer.decrease.clear();
938 }
939 
IsIndexInfoExactlyEqual(const IndexInfo & leftInfo,const IndexInfo & rightInfo)940 inline bool IsIndexInfoExactlyEqual(const IndexInfo &leftInfo, const IndexInfo &rightInfo)
941 {
942     // Exactly equal require count, order and type of each indexField in the index be the same
943     return leftInfo == rightInfo;
944 }
945 
IsSchemaIndexesExactlyEqual(const IndexDifference & indexDiffer)946 inline bool IsSchemaIndexesExactlyEqual(const IndexDifference &indexDiffer)
947 {
948     return (indexDiffer.change.empty() && indexDiffer.increase.empty() && indexDiffer.decrease.empty());
949 }
950 }
951 
CompareSchemaIndexes(const SchemaObject & newSchema,IndexDifference & indexDiffer) const952 int SchemaObject::CompareSchemaIndexes(const SchemaObject &newSchema, IndexDifference &indexDiffer) const
953 {
954     ClearIndexDifference(indexDiffer);
955     // Find the increase and change index
956     for (const auto &entry : newSchema.schemaIndexes_) {
957         if (schemaIndexes_.count(entry.first) == 0) {
958             LOGD("[Schema][CompareIndex] Increase indexName.");
959             indexDiffer.increase[entry.first] = entry.second;
960         } else {
961             // Both schema have same IndexName, Check whether indexInfo differs
962             if (!IsIndexInfoExactlyEqual(entry.second, schemaIndexes_.at(entry.first))) {
963                 LOGD("[Schema][CompareIndex] Change indexName.");
964                 indexDiffer.change[entry.first] = entry.second;
965             }
966         }
967     }
968     // Find the decrease index
969     for (const auto &entry : schemaIndexes_) {
970         if (newSchema.schemaIndexes_.count(entry.first) == 0) {
971             LOGD("[Schema][CompareIndex] Decrease indexName.");
972             indexDiffer.decrease.insert(entry.first);
973         }
974     }
975     // Do not return E_OK here, E_OK is ambiguous.
976     return IsSchemaIndexesExactlyEqual(indexDiffer) ? -E_SCHEMA_EQUAL_EXACTLY : -E_SCHEMA_UNEQUAL_COMPATIBLE;
977 }
978 
979 namespace {
CheckValueItemNumericType(FieldType typeInValue,FieldType typeInSchema)980 int CheckValueItemNumericType(FieldType typeInValue, FieldType typeInSchema)
981 {
982     if (typeInValue == FieldType::LEAF_FIELD_DOUBLE) {
983         if (typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
984             return -E_VALUE_MISMATCH_FEILD_TYPE;
985         }
986     } else if (typeInValue == FieldType::LEAF_FIELD_LONG) {
987         if (typeInSchema != FieldType::LEAF_FIELD_LONG &&
988             typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
989             return -E_VALUE_MISMATCH_FEILD_TYPE;
990         }
991     } else {
992         // LEAF_FIELD_INTEGER
993         if (typeInSchema != FieldType::LEAF_FIELD_INTEGER &&
994             typeInSchema != FieldType::LEAF_FIELD_LONG &&
995             typeInSchema != FieldType::LEAF_FIELD_DOUBLE) {
996             return -E_VALUE_MISMATCH_FEILD_TYPE;
997         }
998     }
999     return -E_VALUE_MATCH;
1000 }
1001 
IsTypeMustBeExactlyEqualBetweenSchemaAndValue(FieldType inType)1002 inline bool IsTypeMustBeExactlyEqualBetweenSchemaAndValue(FieldType inType)
1003 {
1004     return (inType == FieldType::LEAF_FIELD_BOOL ||
1005             inType == FieldType::LEAF_FIELD_STRING ||
1006             inType == FieldType::LEAF_FIELD_ARRAY);
1007 }
1008 
IsObjectType(FieldType inType)1009 inline bool IsObjectType(FieldType inType)
1010 {
1011     return (inType == FieldType::LEAF_FIELD_OBJECT || inType == FieldType::INTERNAL_FIELD_OBJECT);
1012 }
1013 
1014 // Check in the value-view for convenience
CheckValueItem(const SchemaAttribute & refAttr,FieldType typeInValue)1015 int CheckValueItem(const SchemaAttribute &refAttr, FieldType typeInValue)
1016 {
1017     FieldType typeInSchema = refAttr.type;
1018     if (typeInSchema == FieldType::LEAF_FIELD_NULL) { // Unlikely
1019         return -E_INTERNAL_ERROR;
1020     }
1021     // Check NotNull-Constraint first
1022     if (typeInValue == FieldType::LEAF_FIELD_NULL) {
1023         if (refAttr.hasNotNullConstraint) {
1024             return -E_VALUE_MISMATCH_CONSTRAINT;
1025         }
1026         return -E_VALUE_MATCH;
1027     }
1028     // If typeInValue not NULL, check against schema. First check type that must be equal.
1029     if (IsTypeMustBeExactlyEqualBetweenSchemaAndValue(typeInValue)) {
1030         if (typeInValue != typeInSchema) {
1031             return -E_VALUE_MISMATCH_FEILD_TYPE;
1032         }
1033         return -E_VALUE_MATCH;
1034     }
1035     // Check Object related type, lack or more field will be deal with at next depth
1036     // typeInSchema/typeInValue     LEAF_OBJECT                         INTERNAL_OBJECT
1037     //              LEAF_OBJECT     MATCH                               MATCH(More field at next depth)
1038     //          INTERNAL_OBJECT     MATCH(Lack field at next depth)     MATCH
1039     //           ELSE(POSSIBLE)     TYPE_MISMATCH                       TYPE_MISMATCH
1040     if (IsObjectType(typeInValue)) {
1041         if (!IsObjectType(typeInSchema)) {
1042             return -E_VALUE_MISMATCH_FEILD_TYPE;
1043         }
1044         return -E_VALUE_MATCH;
1045     }
1046     // Check Numeric related type, at last
1047     return CheckValueItemNumericType(typeInValue, typeInSchema);
1048 }
1049 
IsLackingFieldViolateNotNullConstraint(const SchemaAttribute & refAttr)1050 inline bool IsLackingFieldViolateNotNullConstraint(const SchemaAttribute &refAttr)
1051 {
1052     return (refAttr.hasNotNullConstraint && !refAttr.hasDefaultValue);
1053 }
1054 
1055 // Function only for split big function
CheckValueBySchemaItem(const std::pair<FieldPath,SchemaAttribute> & schemaItem,const std::map<FieldPath,FieldType> & subPathType,std::set<FieldPath> & lackingPaths)1056 int CheckValueBySchemaItem(const std::pair<FieldPath, SchemaAttribute> &schemaItem,
1057     const std::map<FieldPath, FieldType> &subPathType, std::set<FieldPath> &lackingPaths)
1058 {
1059     if (subPathType.count(schemaItem.first) == 0) { // Value do not contain this field
1060         if (IsLackingFieldViolateNotNullConstraint(schemaItem.second)) {
1061             return -E_VALUE_MISMATCH_CONSTRAINT;
1062         }
1063         lackingPaths.insert(schemaItem.first);
1064         return -E_VALUE_MATCH;
1065     }
1066     // Value contain this field, check its type
1067     return CheckValueItem(schemaItem.second, subPathType.at(schemaItem.first));
1068 }
1069 
ValueFieldType(const std::map<FieldPath,FieldType> & subPathType,const FieldPath & inPath)1070 inline std::string ValueFieldType(const std::map<FieldPath, FieldType> &subPathType, const FieldPath &inPath)
1071 {
1072     if (subPathType.count(inPath) == 0) {
1073         return "NotExist";
1074     }
1075     return SchemaUtils::FieldTypeString(subPathType.at(inPath));
1076 }
1077 }
1078 
CheckValue(const ValueObject & inValue,std::set<FieldPath> & lackingPaths) const1079 int SchemaObject::CheckValue(const ValueObject &inValue, std::set<FieldPath> &lackingPaths) const
1080 {
1081     std::set<FieldPath> nestPathCurDepth{FieldPath()}; // Empty path represent root path
1082     for (uint32_t depth = 0; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
1083         if (schemaDefine_.count(depth) == 0 || schemaDefine_.at(depth).empty()) { // No schema define in this depth
1084             break;
1085         }
1086 
1087         std::map<FieldPath, FieldType> subPathType;
1088         int errCode = inValue.GetSubFieldPathAndType(nestPathCurDepth, subPathType); // Value field of current depth
1089         if (errCode != E_OK && errCode != -E_INVALID_PATH) { // E_INVALID_PATH for path not exist
1090             LOGE("[Schema][CheckValue] GetSubFieldPathAndType Fail=%d, Depth=%" PRIu32, errCode, depth);
1091             return -E_VALUE_MISMATCH_FEILD_TYPE;
1092         }
1093         nestPathCurDepth.clear(); // Clear it for collecting new nestPath
1094 
1095         if (schemaMode_ == SchemaMode::STRICT) {
1096             bool hasUndefined = std::any_of(subPathType.begin(), subPathType.end(), [this, depth] (const auto &it) {
1097                 return (schemaDefine_.at(depth).count(it.first) == 0);
1098             });
1099             if (hasUndefined) {
1100                 LOGE("[Schema][CheckValue] Undefined field in STRICT mode");
1101                 return -E_VALUE_MISMATCH_FEILD_COUNT; // Value contain more field than schema
1102             }
1103         }
1104 
1105         for (const auto &schemaItem : schemaDefine_.at(depth)) { // Check each field define in schema
1106             if (schemaItem.second.type == FieldType::INTERNAL_FIELD_OBJECT) {
1107                 nestPathCurDepth.insert(schemaItem.first); // This field has subfield in schema
1108             }
1109             errCode = CheckValueBySchemaItem(schemaItem, subPathType, lackingPaths);
1110             if (errCode != -E_VALUE_MATCH) {
1111                 LOGE("[Schema][CheckValue] Schema{NotNull=%d,Default=%d,Type=%s}, Value{Type=%s}, errCode=%d.",
1112                     schemaItem.second.hasNotNullConstraint,
1113                     schemaItem.second.hasDefaultValue, SchemaUtils::FieldTypeString(schemaItem.second.type).c_str(),
1114                     ValueFieldType(subPathType, schemaItem.first).c_str(), errCode);
1115                 return errCode;
1116             }
1117         }
1118     }
1119     return -E_VALUE_MATCH;
1120 }
1121 
AmendValueIfNeed(ValueObject & inValue,const std::set<FieldPath> & lackingPaths,bool & amended) const1122 int SchemaObject::AmendValueIfNeed(ValueObject &inValue, const std::set<FieldPath> &lackingPaths, bool &amended) const
1123 {
1124     for (const auto &eachLackingPath : lackingPaths) {
1125         // Note: The upper code logic guarantee that eachLackingPath won't be empty and must exist in schemaDefine_
1126         uint32_t depth = eachLackingPath.size() - 1; // Depth count from zero
1127         const SchemaAttribute &lackingPathAttr = schemaDefine_.at(depth).at(eachLackingPath);
1128         // If no default value, just ignore this lackingPath
1129         if (!lackingPathAttr.hasDefaultValue) {
1130             continue;
1131         }
1132         // If has default value, the ParseSchema logic guarantee that fieldType won't be NULL, ARRAY or OBJECT
1133         // The lacking intermediate field will be automatically insert for this lackingPath
1134         int errCode = inValue.InsertField(eachLackingPath, lackingPathAttr.type, lackingPathAttr.defaultValue);
1135         if (errCode != E_OK) { // Unlikely
1136             LOGE("[Schema][AmendValue] InsertField fail, errCode=%d, Type=%s.", errCode,
1137                 SchemaUtils::FieldTypeString(lackingPathAttr.type).c_str());
1138             return -E_INTERNAL_ERROR;
1139         }
1140         amended = true;
1141     }
1142     return E_OK;
1143 }
1144 } // namespace DistributedDB
1145