• 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 <cmath>
18 #include <algorithm>
19 #include "schema_constant.h"
20 #include "schema_utils.h"
21 #include "db_errno.h"
22 #include "log_print.h"
23 
24 namespace DistributedDB {
25 namespace {
26 #ifndef OMIT_FLATBUFFER
27 constexpr double EPSILON = 0.000001; // 0.000001 for tolerance
IsDoubleNearlyEqual(double left,double right)28 inline bool IsDoubleNearlyEqual(double left, double right)
29 {
30     if (std::fabs(left - right) < EPSILON) {
31         return true;
32     }
33     double absBigger = std::max(std::fabs(left), std::fabs(right));
34     double relativeDiff = ((absBigger == 0.0) ? 0.0 : (std::fabs(left - right) / absBigger)); // 0.0 for double 0
35     return relativeDiff < EPSILON;
36 }
37 #endif // OMIT_FLATBUFFER
38 }
39 
CopyFrom(const FlatBufferSchema & other)40 void SchemaObject::FlatBufferSchema::CopyFrom(const FlatBufferSchema &other)
41 {
42     // The SchemaObject guarantee not CopyFrom "Self"; owner_ can only be set at construction.
43     description_ = other.description_;
44 }
45 
GetDescription() const46 std::string SchemaObject::FlatBufferSchema::GetDescription() const
47 {
48     return description_;
49 }
50 
51 #ifndef OMIT_FLATBUFFER
IsFlatBufferSchema(const std::string & inOriginal,std::string & outDecoded)52 bool SchemaObject::FlatBufferSchema::IsFlatBufferSchema(const std::string &inOriginal, std::string &outDecoded)
53 {
54     if (inOriginal.empty()) {
55         LOGE("[FBSchema][Is] OriSchema empty.");
56         return false;
57     }
58     if (inOriginal.size() >= SchemaConstant::SCHEMA_STRING_SIZE_LIMIT * 2) { // 2 :Maximum base64 encode size multiple
59         // Base64 encode will not exceed 2 times original binary
60         LOGE("[FBSchema][Is] OriSchemaSize=%zu too large even after base64 encode.", inOriginal.size());
61         return false;
62     }
63     auto oriSchemaBuf = reinterpret_cast<const uint8_t *>(inOriginal.c_str());
64     flatbuffers::Verifier oriVerifier(oriSchemaBuf, inOriginal.size());
65     if (reflection::VerifySizePrefixedSchemaBuffer(oriVerifier)) {
66         outDecoded = inOriginal; // The original one is the decoded one
67         return true;
68     }
69     outDecoded.clear();
70     return false;
71 }
72 
73 // A macro check pointer get from flatbuffer that won't be nullptr(required field) in fact after verified by flatbuffer
74 #define CHECK_NULL_UNLIKELY_RETURN_ERROR(pointer) \
75     if ((pointer) == nullptr) { \
76         return -E_INTERNAL_ERROR; \
77     }
78 
79 namespace {
80 constexpr uint32_t ROOT_DEFINE_DEPTH = 0;
81 constexpr uint32_t SIZE_PREFIX_SIZE = sizeof(flatbuffers::uoffset_t);
82 constexpr int32_t INDEX_OF_NOT_ENUM = -1;
83 
AttributeExistAndHasValue(const reflection::KeyValue * inAttr)84 inline bool AttributeExistAndHasValue(const reflection::KeyValue *inAttr)
85 {
86     return (inAttr != nullptr) && (inAttr->value() != nullptr) && (inAttr->value()->size() > 0);
87 }
88 
IsIntegerType(reflection::BaseType inType)89 inline bool IsIntegerType(reflection::BaseType inType)
90 {
91     return (inType >= reflection::BaseType::Bool) && (inType <= reflection::BaseType::ULong);
92 }
93 
IsRealType(reflection::BaseType inType)94 inline bool IsRealType(reflection::BaseType inType)
95 {
96     return (inType >= reflection::BaseType::Float) && (inType <= reflection::BaseType::Double);
97 }
98 
IsScalarType(reflection::BaseType inType)99 inline bool IsScalarType(reflection::BaseType inType)
100 {
101     return IsIntegerType(inType) || IsRealType(inType);
102 }
103 
IsStringType(reflection::BaseType inType)104 inline bool IsStringType(reflection::BaseType inType)
105 {
106     return inType == reflection::BaseType::String;
107 }
108 
IsIndexableType(reflection::BaseType inType)109 inline bool IsIndexableType(reflection::BaseType inType)
110 {
111     return IsScalarType(inType) || IsStringType(inType);
112 }
113 
IsVectorType(reflection::BaseType inType)114 inline bool IsVectorType(reflection::BaseType inType)
115 {
116     return inType == reflection::BaseType::Vector;
117 }
118 
IsStringOrVectorType(reflection::BaseType inType)119 inline bool IsStringOrVectorType(reflection::BaseType inType)
120 {
121     return IsStringType(inType) || IsVectorType(inType);
122 }
123 
IsObjectType(reflection::BaseType inType)124 inline bool IsObjectType(reflection::BaseType inType)
125 {
126     return inType == reflection::BaseType::Obj;
127 }
128 
IsSupportTypeAtRoot(reflection::BaseType inType)129 inline bool IsSupportTypeAtRoot(reflection::BaseType inType)
130 {
131     return IsIndexableType(inType) || IsVectorType(inType) || IsObjectType(inType);
132 }
133 
IsRequiredSupportType(reflection::BaseType inType)134 inline bool IsRequiredSupportType(reflection::BaseType inType)
135 {
136     return IsStringOrVectorType(inType) || IsObjectType(inType);
137 }
138 
IsConflict(bool deprecated,bool required)139 inline bool IsConflict(bool deprecated, bool required)
140 {
141     return deprecated && required;
142 }
143 }
144 
ParseFlatBufferSchema(const std::string & inDecoded)145 int SchemaObject::FlatBufferSchema::ParseFlatBufferSchema(const std::string &inDecoded)
146 {
147     description_.clear(); // For recovering from a fail parse
148     // The upper logic had guaranteed that the inDecoded be verified OK
149     auto schema = reflection::GetSizePrefixedSchema(inDecoded.c_str());
150     CHECK_NULL_UNLIKELY_RETURN_ERROR(schema);
151     auto rootTable = schema->root_table();
152     if (rootTable == nullptr || rootTable->is_struct()) {
153         LOGE("[FBSchema][Parse] Root table nullptr or is struct.");
154         return -E_SCHEMA_PARSE_FAIL;
155     }
156 
157     auto rootTableName = rootTable->name();
158     CHECK_NULL_UNLIKELY_RETURN_ERROR(rootTableName);
159     description_ += ("RootTableName=" + SchemaUtils::StripNameSpace(rootTableName->str()) + ";");
160 
161     int errCode = ParseCheckRootTableAttribute(*rootTable);
162     if (errCode != E_OK) {
163         return errCode;
164     }
165 
166     RawIndexInfos indexCollect;
167     errCode = ParseCheckRootTableDefine(*schema, *rootTable, indexCollect);
168     if (errCode != E_OK) {
169         return errCode;
170     }
171 
172     errCode = ParseCheckIndexes(indexCollect);
173     if (errCode != E_OK) {
174         return errCode;
175     }
176     return E_OK;
177 }
178 
CompareFlatBufferDefine(const FlatBufferSchema & other) const179 int SchemaObject::FlatBufferSchema::CompareFlatBufferDefine(const FlatBufferSchema &other) const
180 {
181     // Schema had been parsed and constraint checked before this function is called, so as we assumed.
182     // Here in the compare procedure, we only check null-point, do not check or suspect of constraint any more.
183     auto selfSchema = GetSchema();
184     auto otherSchema = other.GetSchema();
185     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfSchema);
186     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherSchema);
187     auto selfRootTable = selfSchema->root_table();
188     auto otherRootTable = otherSchema->root_table();
189     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfRootTable);
190     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherRootTable);
191     auto selfRootTableName = selfRootTable->name();
192     auto otherRootTableName = otherRootTable->name();
193     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfRootTableName);
194     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherRootTableName);
195 
196     std::string selfRootName = SchemaUtils::StripNameSpace(selfRootTableName->str());
197     std::string otherRootName = SchemaUtils::StripNameSpace(otherRootTableName->str());
198     if (selfRootName != otherRootName) {
199         LOGE("[FBSchema][Compare] RootName differ, self=%s, other=%s.", selfRootName.c_str(), otherRootName.c_str());
200         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
201     }
202     // We don't have to compare rootTableAttribute or index here, they are done by SchemaObject
203     std::set<std::string> comparedTypeNameSet;
204     return CompareTableOrStructDefine({selfSchema, otherSchema}, {selfRootTable, otherRootTable}, true,
205         comparedTypeNameSet);
206 }
207 
208 namespace {
CheckSizePrefixRawValue(const RawValue & inValue)209 int CheckSizePrefixRawValue(const RawValue &inValue)
210 {
211     if (inValue.first == nullptr) { // Unlikely
212         return -E_INVALID_ARGS;
213     }
214     if (inValue.second <= SIZE_PREFIX_SIZE) {
215         LOGE("[FBSchema][CheckSizePreValue] ValueSize=%u too short.", inValue.second);
216         return -E_INVALID_ARGS;
217     }
218     auto realSize = flatbuffers::ReadScalar<flatbuffers::uoffset_t>(inValue.first);
219     if (realSize != inValue.second - SIZE_PREFIX_SIZE) {
220         LOGE("[FBSchema][CheckSizePreValue] RealSize=%u mismatch valueSize=(%u-4).", realSize, inValue.second);
221         return -E_INVALID_ARGS;
222     }
223     return E_OK;
224 }
225 }
226 
VerifyFlatBufferValue(const RawValue & inValue,bool tryNoSizePrefix) const227 int SchemaObject::FlatBufferSchema::VerifyFlatBufferValue(const RawValue &inValue, bool tryNoSizePrefix) const
228 {
229     (void)tryNoSizePrefix; // Use it in the future, currently we demand value is sizePrefixed
230     int errCode = CheckSizePrefixRawValue(inValue);
231     if (errCode != E_OK) {
232         return errCode;
233     }
234     auto schema = GetSchema();
235     CHECK_NULL_UNLIKELY_RETURN_ERROR(schema);
236     auto rootTable = schema->root_table();
237     CHECK_NULL_UNLIKELY_RETURN_ERROR(rootTable);
238     if (!flatbuffers::Verify(*schema, *rootTable, inValue.first + SIZE_PREFIX_SIZE,
239         inValue.second - SIZE_PREFIX_SIZE)) {
240         return -E_FLATBUFFER_VERIFY_FAIL;
241     }
242     return E_OK;
243 }
244 
245 namespace {
MapFieldType(reflection::BaseType inType)246 FieldType MapFieldType(reflection::BaseType inType)
247 {
248     static std::map<reflection::BaseType, FieldType> fieldTypeMap{
249         {reflection::BaseType::Bool, FieldType::LEAF_FIELD_BOOL},
250         {reflection::BaseType::Byte, FieldType::LEAF_FIELD_INTEGER},
251         {reflection::BaseType::UByte, FieldType::LEAF_FIELD_INTEGER},
252         {reflection::BaseType::Short, FieldType::LEAF_FIELD_INTEGER},
253         {reflection::BaseType::UShort, FieldType::LEAF_FIELD_INTEGER},
254         {reflection::BaseType::Int, FieldType::LEAF_FIELD_INTEGER},
255         {reflection::BaseType::UInt, FieldType::LEAF_FIELD_LONG},
256         {reflection::BaseType::Long, FieldType::LEAF_FIELD_LONG},
257         {reflection::BaseType::ULong, FieldType::LEAF_FIELD_DOUBLE},
258         {reflection::BaseType::Float, FieldType::LEAF_FIELD_DOUBLE},
259         {reflection::BaseType::Double, FieldType::LEAF_FIELD_DOUBLE},
260         {reflection::BaseType::String, FieldType::LEAF_FIELD_STRING},
261         {reflection::BaseType::Vector, FieldType::LEAF_FIELD_ARRAY},
262         {reflection::BaseType::Obj, FieldType::INTERNAL_FIELD_OBJECT},
263     };
264     if (fieldTypeMap.count(inType) == 0) {
265         return FieldType::LEAF_FIELD_NULL;
266     }
267     return fieldTypeMap[inType];
268 }
269 
CheckDollarDotAndSkipIt(RawString inPath)270 RawString CheckDollarDotAndSkipIt(RawString inPath)
271 {
272     if (inPath == nullptr) {
273         return nullptr;
274     }
275     auto pathStr = inPath;
276     if (*pathStr++ != '$') {
277         return nullptr;
278     }
279     if (*pathStr++ != '.') {
280         return nullptr;
281     }
282     if (*pathStr == 0) {
283         return nullptr;
284     }
285     return pathStr;
286 }
287 
GetFieldInfoFromSchemaByPath(const reflection::Schema & schema,RawString pathStr)288 const reflection::Field *GetFieldInfoFromSchemaByPath(const reflection::Schema &schema, RawString pathStr)
289 {
290     auto rootTable = schema.root_table();
291     if (rootTable == nullptr) { // Unlikely
292         return nullptr;
293     }
294     auto rootFields = rootTable->fields();
295     if (rootFields == nullptr) { // Unlikely
296         return nullptr;
297     }
298     // Unlikely to return nullptr, except internal-error happened
299     return rootFields->LookupByKey(pathStr);
300 }
301 
DoVerifyBeforeExtract(const flatbuffers::Table & rootValue,const reflection::Field & fieldInfo,const flatbuffers::Verifier & verifier)302 int DoVerifyBeforeExtract(const flatbuffers::Table &rootValue, const reflection::Field &fieldInfo,
303     const flatbuffers::Verifier &verifier)
304 {
305     auto type = fieldInfo.type();
306     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
307     bool verifyResult = true;
308     switch (type->base_type()) {
309         case reflection::Bool:
310         case reflection::Byte:
311         case reflection::UByte:
312             verifyResult = rootValue.VerifyField<int8_t>(verifier, fieldInfo.offset());
313             break;
314         case reflection::Short:
315         case reflection::UShort:
316             verifyResult = rootValue.VerifyField<int16_t>(verifier, fieldInfo.offset());
317             break;
318         case reflection::Int:
319         case reflection::UInt:
320             verifyResult = rootValue.VerifyField<int32_t>(verifier, fieldInfo.offset());
321             break;
322         case reflection::Long:
323         case reflection::ULong:
324             verifyResult = rootValue.VerifyField<uint64_t>(verifier, fieldInfo.offset());
325             break;
326         case reflection::Float:
327             verifyResult = rootValue.VerifyField<float>(verifier, fieldInfo.offset());
328             break;
329         case reflection::Double:
330             verifyResult = rootValue.VerifyField<double>(verifier, fieldInfo.offset());
331             break;
332         case reflection::String:
333             verifyResult = rootValue.VerifyField<flatbuffers::uoffset_t>(verifier, fieldInfo.offset()) &&
334                 verifier.VerifyString(flatbuffers::GetFieldS(rootValue, fieldInfo)); // VerifyString can accept null
335             break;
336         default:
337             return -E_NOT_SUPPORT;
338     }
339     return (verifyResult ? E_OK : -E_FLATBUFFER_VERIFY_FAIL);
340 }
341 
DoExtractString(const flatbuffers::Table & rootValue,const reflection::Field & fieldInfo)342 inline std::string DoExtractString(const flatbuffers::Table &rootValue, const reflection::Field &fieldInfo)
343 {
344     auto strVal = flatbuffers::GetFieldS(rootValue, fieldInfo);
345     if (strVal == nullptr) {
346         return "";
347     }
348     return strVal->str();
349 }
350 
DoExtractValue(const flatbuffers::Table & rootValue,const reflection::Field & fieldInfo,TypeValue & outExtract)351 int DoExtractValue(const flatbuffers::Table &rootValue, const reflection::Field &fieldInfo, TypeValue &outExtract)
352 {
353     auto type = fieldInfo.type();
354     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
355     switch (type->base_type()) {
356         case reflection::Bool:
357             outExtract.second.boolValue = (flatbuffers::GetFieldI<int8_t>(rootValue, fieldInfo) != 0);
358             break;
359         case reflection::Byte:
360             outExtract.second.integerValue = flatbuffers::GetFieldI<int8_t>(rootValue, fieldInfo);
361             break;
362         case reflection::UByte:
363             outExtract.second.integerValue = flatbuffers::GetFieldI<uint8_t>(rootValue, fieldInfo);
364             break;
365         case reflection::Short:
366             outExtract.second.integerValue = flatbuffers::GetFieldI<int16_t>(rootValue, fieldInfo);
367             break;
368         case reflection::UShort:
369             outExtract.second.integerValue = flatbuffers::GetFieldI<uint16_t>(rootValue, fieldInfo);
370             break;
371         case reflection::Int:
372             outExtract.second.integerValue = flatbuffers::GetFieldI<int32_t>(rootValue, fieldInfo);
373             break;
374         case reflection::UInt:
375             outExtract.second.longValue = flatbuffers::GetFieldI<uint32_t>(rootValue, fieldInfo);
376             break;
377         case reflection::Long:
378             outExtract.second.longValue = flatbuffers::GetFieldI<int64_t>(rootValue, fieldInfo);
379             break;
380         case reflection::ULong:
381             outExtract.second.doubleValue = flatbuffers::GetFieldI<uint64_t>(rootValue, fieldInfo);
382             break;
383         case reflection::Float:
384             outExtract.second.doubleValue = flatbuffers::GetFieldF<float>(rootValue, fieldInfo);
385             break;
386         case reflection::Double:
387             outExtract.second.doubleValue = flatbuffers::GetFieldF<double>(rootValue, fieldInfo);
388             break;
389         case reflection::String:
390             outExtract.second.stringValue = DoExtractString(rootValue, fieldInfo);
391             break;
392         default:
393             return -E_NOT_SUPPORT;
394     }
395     return E_OK;
396 }
397 
ExtractFlatBufferValueFinal(const flatbuffers::Table & rootValue,const reflection::Field & fieldInfo,const flatbuffers::Verifier & verifier,TypeValue & outExtract)398 int ExtractFlatBufferValueFinal(const flatbuffers::Table &rootValue, const reflection::Field &fieldInfo,
399     const flatbuffers::Verifier &verifier, TypeValue &outExtract)
400 {
401     auto type = fieldInfo.type();
402     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
403     auto baseType = type->base_type();
404     if (!IsIndexableType(baseType)) {
405         LOGE("[ExtractFinal] BaseType=%s not indexable.", reflection::EnumNameBaseType(baseType));
406         return -E_NOT_SUPPORT;
407     }
408     outExtract.first = MapFieldType(type->base_type());
409     int errCode = DoVerifyBeforeExtract(rootValue, fieldInfo, verifier);
410     if (errCode != E_OK) {
411         LOGE("[ExtractFinal] DoVerify fail, errCode=%d.", errCode);
412         return errCode;
413     }
414     errCode = DoExtractValue(rootValue, fieldInfo, outExtract);
415     if (errCode != E_OK) {
416         LOGE("[ExtractFinal] DoExtract fail, errCode=%d.", errCode);
417         return errCode;
418     }
419     return E_OK;
420 }
421 }
422 
ExtractFlatBufferValue(RawString inPath,const RawValue & inValue,TypeValue & outExtract,bool tryNoSizePrefix) const423 int SchemaObject::FlatBufferSchema::ExtractFlatBufferValue(RawString inPath, const RawValue &inValue,
424     TypeValue &outExtract, bool tryNoSizePrefix) const
425 {
426     // NOTE!!! This function is performance sensitive !!! Carefully not to allocate memory often!!!
427     (void)tryNoSizePrefix; // Use it in the future, currently we demand value is sizePrefixed
428     int errCode = CheckSizePrefixRawValue(inValue);
429     if (errCode != E_OK) {
430         return errCode;
431     }
432     auto pathStr = CheckDollarDotAndSkipIt(inPath);
433     if (pathStr == nullptr) { // Unlikely
434         LOGE("[FBSchema][Extract] inPath not begin with $. or nothing after it.");
435         return -E_INVALID_ARGS;
436     }
437     auto schema = GetSchema();
438     CHECK_NULL_UNLIKELY_RETURN_ERROR(schema);
439     // Currently we don't support nest-path
440     auto fieldInfo = GetFieldInfoFromSchemaByPath(*schema, pathStr);
441     if (fieldInfo == nullptr) {
442         LOGE("[FBSchema][Extract] FieldInfo of path=%s not found.", pathStr);
443         return -E_INTERNAL_ERROR;
444     }
445     // Begin extract, we have to minimal verify if we don't trust value from database
446     auto valueRealBegin = inValue.first + SIZE_PREFIX_SIZE;
447     auto valueRealSize = inValue.second - SIZE_PREFIX_SIZE;
448     flatbuffers::Verifier verifier(valueRealBegin, valueRealSize);
449     auto offset = verifier.VerifyOffset(0); // Attention: Verify root offset before we call GetAnyRoot
450     if (offset == 0) {
451         LOGE("[FBSchema][Extract] Verity root offset failed.");
452         return -E_FLATBUFFER_VERIFY_FAIL;
453     }
454     auto rootValue = flatbuffers::GetAnyRoot(valueRealBegin);
455     if (rootValue == nullptr) {
456         LOGE("[FBSchema][Extract] Get rootTable from value fail.");
457         return -E_INVALID_DATA;
458     }
459     // Verity vTable of rootTable before we extract anything from rootValue by reflection
460     bool vTableOk = rootValue->VerifyTableStart(verifier);
461     if (!vTableOk) {
462         LOGE("[FBSchema][Extract] Verify vTable of rootTable of value fail.");
463         return -E_FLATBUFFER_VERIFY_FAIL;
464     }
465     errCode = ExtractFlatBufferValueFinal(*rootValue, *fieldInfo, verifier, outExtract);
466     if (errCode != E_OK) {
467         return errCode;
468     }
469     verifier.EndTable();
470     return E_OK;
471 }
472 
GetSchema() const473 const reflection::Schema *SchemaObject::FlatBufferSchema::GetSchema() const
474 {
475     // This function is called after schemaString_ had been verified by flatbuffer
476     return reflection::GetSizePrefixedSchema(owner_.schemaString_.c_str());
477 }
478 
ParseCheckRootTableAttribute(const reflection::Object & rootTable)479 int SchemaObject::FlatBufferSchema::ParseCheckRootTableAttribute(const reflection::Object &rootTable)
480 {
481     auto rootTableAttr = rootTable.attributes();
482     if (rootTableAttr == nullptr) {
483         LOGE("[FBSchema][ParseRootAttr] Root table no attribute.");
484         return -E_SCHEMA_PARSE_FAIL;
485     }
486 
487     auto versionAttr = rootTableAttr->LookupByKey(SchemaConstant::KEYWORD_SCHEMA_VERSION.c_str());
488     if (!AttributeExistAndHasValue(versionAttr)) {
489         LOGE("[FBSchema][ParseRootAttr] No SCHEMA_VERSION attribute or no value.");
490         return -E_SCHEMA_PARSE_FAIL;
491     }
492     if (SchemaUtils::Strip(versionAttr->value()->str()) != SchemaConstant::SCHEMA_SUPPORT_VERSION) {
493         LOGE("[FBSchema][ParseRootAttr] Unexpect SCHEMA_VERSION=%s.", versionAttr->value()->c_str());
494         return -E_SCHEMA_PARSE_FAIL;
495     }
496     owner_.schemaVersion_ = SchemaConstant::SCHEMA_SUPPORT_VERSION;
497     description_ += (SchemaConstant::KEYWORD_SCHEMA_VERSION + "=" + SchemaConstant::SCHEMA_SUPPORT_VERSION + ";");
498 
499     auto skipsizeAttr = rootTableAttr->LookupByKey(SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE.c_str());
500     if (!AttributeExistAndHasValue(skipsizeAttr)) {
501         LOGI("[FBSchema][ParseRootAttr] No SCHEMA_SKIPSIZE attribute or no value.");
502         owner_.schemaSkipSize_ = 0; // Default skipsize value
503         return E_OK;
504     }
505     std::string skipsizeStr = SchemaUtils::Strip(skipsizeAttr->value()->str());
506     int skipsizeInt = std::atoi(skipsizeStr.c_str()); // std::stoi will throw exception
507     if (std::to_string(skipsizeInt) != skipsizeStr || skipsizeInt < 0 ||
508         static_cast<uint32_t>(skipsizeInt) > SchemaConstant::SCHEMA_SKIPSIZE_MAX) {
509         LOGE("[FBSchema][ParseRootAttr] Unexpect SCHEMA_SKIPSIZE value=%s.", skipsizeAttr->value()->c_str());
510         return -E_SCHEMA_PARSE_FAIL;
511     }
512     owner_.schemaSkipSize_ = static_cast<uint32_t>(skipsizeInt);
513     description_ += (SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE + "=" + skipsizeStr + ";");
514     return E_OK;
515 }
516 
ParseCheckRootTableDefine(const reflection::Schema & schema,const reflection::Object & rootTable,RawIndexInfos & indexCollect)517 int SchemaObject::FlatBufferSchema::ParseCheckRootTableDefine(const reflection::Schema &schema,
518     const reflection::Object &rootTable, RawIndexInfos &indexCollect)
519 {
520     // Clear schemaDefine_ to recover from a fail parse
521     owner_.schemaDefine_.clear();
522     auto fields = rootTable.fields();
523     if (fields == nullptr || fields->size() == 0) {
524         LOGE("[FBSchema][ParseRootDefine] Empty define.");
525         return -E_SCHEMA_PARSE_FAIL;
526     }
527     for (uint32_t i = 0; i < fields->size(); i++) {
528         auto eachField = (*fields)[i];
529         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachField);
530 
531         auto name = eachField->name();
532         CHECK_NULL_UNLIKELY_RETURN_ERROR(name);
533         int errCode = SchemaUtils::CheckFieldName(name->str());
534         if (errCode != E_OK) {
535             LOGE("[FBSchema][ParseRootDefine] Invalid fieldName=%s, errCode=%d.", name->c_str(), errCode);
536             return -E_SCHEMA_PARSE_FAIL;
537         }
538         FieldPath path{name->str()};
539         if (owner_.schemaDefine_[ROOT_DEFINE_DEPTH].count(path) != 0) { // Unlikely
540             LOGE("[FBSchema][ParseRootDefine] FieldPath=%s already exist at root.", name->c_str());
541             return -E_SCHEMA_PARSE_FAIL;
542         }
543 
544         errCode = ParseCheckFieldInfo(schema, *eachField, path, indexCollect);
545         if (errCode != E_OK) {
546             LOGE("[FBSchema][ParseRootDefine] ParseFieldInfo errCode=%d, FieldPath=%s.", errCode,
547                 SchemaUtils::FieldPathString(path).c_str());
548             return errCode;
549         }
550     }
551     uint32_t fieldPathCount = 0;
552     for (uint32_t depth = ROOT_DEFINE_DEPTH; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
553         if (owner_.schemaDefine_.count(depth) != 0) {
554             fieldPathCount += owner_.schemaDefine_[depth].size();
555         }
556     }
557     if (fieldPathCount > SchemaConstant::SCHEMA_FEILD_NAME_COUNT_MAX) {
558         LOGE("[FBSchema][ParseRootDefine] FieldPath count=%u exceed the limitation.", fieldPathCount);
559         return -E_SCHEMA_PARSE_FAIL;
560     }
561     return E_OK;
562 }
563 
564 namespace {
CheckFieldTypeSupport(const reflection::Type & inType,bool isRootField)565 bool CheckFieldTypeSupport(const reflection::Type &inType, bool isRootField)
566 {
567     auto baseType = inType.base_type();
568     if (isRootField) {
569         if (!IsSupportTypeAtRoot(baseType)) {
570             LOGE("[FBSchema][DecideType] BaseType=%s not support at root.", reflection::EnumNameBaseType(baseType));
571             return false;
572         }
573         if (IsIntegerType(baseType) && (inType.index() != INDEX_OF_NOT_ENUM)) {
574             LOGE("[FBSchema][DecideType] BaseType=%s is enum, not support.", reflection::EnumNameBaseType(baseType));
575             return false;
576         }
577         if (IsVectorType(baseType)) {
578             auto elementType = inType.element();
579             if (!IsIndexableType(elementType)) {
580                 LOGE("[FBSchema][DecideType] ElementType=%s not support for vector.",
581                     reflection::EnumNameBaseType(elementType));
582                 return false;
583             }
584         }
585     } else {
586         // Currently only support nest in Struct, support only scalar and nest-struct
587         if (!IsScalarType(baseType) && !IsObjectType(baseType)) {
588             LOGE("[FBSchema][DecideType] BaseType=%s not support for struct.", reflection::EnumNameBaseType(baseType));
589             return false;
590         }
591     }
592     return true;
593 }
594 }
595 
ParseCheckFieldInfo(const reflection::Schema & schema,const reflection::Field & field,const FieldPath & path,RawIndexInfos & indexCollect)596 int SchemaObject::FlatBufferSchema::ParseCheckFieldInfo(const reflection::Schema &schema,
597     const reflection::Field &field, const FieldPath &path, RawIndexInfos &indexCollect)
598 {
599     if (path.empty() || path.size() > SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX) {
600         LOGE("[FBSchema][ParseField] FieldPath size=%zu invalid.", path.size());
601         return -E_SCHEMA_PARSE_FAIL;
602     }
603     uint32_t depth = path.size() - 1; // Depth count from zero
604     bool isRootField = (depth == ROOT_DEFINE_DEPTH);
605     SchemaAttribute &fieldInfo = owner_.schemaDefine_[depth][path]; // Create new entry in schemaDefine_
606 
607     auto type = field.type();
608     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
609     if (!CheckFieldTypeSupport(*type, isRootField)) {
610         return -E_SCHEMA_PARSE_FAIL;
611     }
612     auto baseType = type->base_type();
613     // Only type and isIndexable of SchemaAttribute is necessary
614     fieldInfo.type = MapFieldType(baseType);
615     fieldInfo.isIndexable = (IsIndexableType(baseType) && isRootField);
616     description_ += (SchemaUtils::FieldPathString(path) + "=" + reflection::EnumNameBaseType(baseType) + ";");
617 
618     if (IsRequiredSupportType(baseType)) {
619         if (IsConflict(field.deprecated(), field.required())) {
620             LOGE("[FBSchema][ParseField] Deprecated conflict with required.");
621             return -E_SCHEMA_PARSE_FAIL;
622         }
623     }
624     if (fieldInfo.isIndexable) {
625         CollectRawIndexInfos(field, indexCollect);
626     }
627     if (IsObjectType(baseType)) {
628         int errCode = ParseCheckStructDefine(schema, field, path);
629         if (errCode != E_OK) {
630             return errCode;
631         }
632     }
633     return E_OK;
634 }
635 
CollectRawIndexInfos(const reflection::Field & field,RawIndexInfos & indexCollect) const636 void SchemaObject::FlatBufferSchema::CollectRawIndexInfos(const reflection::Field &field,
637     RawIndexInfos &indexCollect) const
638 {
639     auto name = field.name();
640     if (name == nullptr) { // Not possible
641         return;
642     }
643     auto fieldAttr = field.attributes();
644     if (fieldAttr == nullptr) {
645         return;
646     }
647     auto indexAttr = fieldAttr->LookupByKey(SchemaConstant::KEYWORD_INDEX.c_str());
648     if (indexAttr == nullptr) {
649         return;
650     }
651     if (indexAttr->value() == nullptr) {
652         indexCollect[name->str()] = ""; // Must be SingleField-Index
653         return;
654     }
655     indexCollect[name->str()] = indexAttr->value()->str(); // May still be empty string
656 }
657 
ParseCheckStructDefine(const reflection::Schema & schema,const reflection::Field & field,const FieldPath & path)658 int SchemaObject::FlatBufferSchema::ParseCheckStructDefine(const reflection::Schema &schema,
659     const reflection::Field &field, const FieldPath &path)
660 {
661     if (path.size() >= SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX) {
662         LOGE("[FBSchema][ParseStruct] Struct define at depth limitation.");
663         return -E_SCHEMA_PARSE_FAIL;
664     }
665     auto objects = schema.objects();
666     CHECK_NULL_UNLIKELY_RETURN_ERROR(objects);
667     auto type = field.type();
668     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
669     auto objIndex = type->index();
670     if (objIndex < 0 || static_cast<uint32_t>(objIndex) >= objects->size()) { // Unlikely
671         return -E_INTERNAL_ERROR;
672     }
673     auto structObj = (*objects)[objIndex];
674     CHECK_NULL_UNLIKELY_RETURN_ERROR(structObj);
675     auto structName = structObj->name();
676     CHECK_NULL_UNLIKELY_RETURN_ERROR(structName);
677     if (!structObj->is_struct()) {
678         LOGE("[FBSchema][ParseStruct] Nest table=%s not support.", structName->c_str());
679         return -E_SCHEMA_PARSE_FAIL;
680     }
681     description_ += ("StructName=" + SchemaUtils::StripNameSpace(structName->str()) + ";");
682 
683     // Parse fields
684     auto structFields = structObj->fields();
685     CHECK_NULL_UNLIKELY_RETURN_ERROR(structFields);
686     // Flatbuffer guarantee that struct will not be empty size, even if it is empty, we just ignore it
687     for (uint32_t i = 0; i < structFields->size(); i++) {
688         auto eachField = (*structFields)[i];
689         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachField);
690         auto eachName = eachField->name();
691         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachName);
692         int errCode = SchemaUtils::CheckFieldName(eachName->str());
693         if (errCode != E_OK) {
694             LOGE("[FBSchema][ParseStruct] Invalid fieldName=%s, errCode=%d.", eachName->c_str(), errCode);
695             return -E_SCHEMA_PARSE_FAIL;
696         }
697         FieldPath eachPath = path;
698         eachPath.push_back(eachName->str());
699         RawIndexInfos notUsed;
700         errCode = ParseCheckFieldInfo(schema, *eachField, eachPath, notUsed);
701         if (errCode != E_OK) {
702             LOGE("[FBSchema][ParseStruct] ParseFieldInfo errCode=%d, FieldPath=%s.", errCode,
703                 SchemaUtils::FieldPathString(eachPath).c_str());
704             return errCode;
705         }
706     }
707     return E_OK;
708 }
709 
710 namespace {
IsNotCompositeIndex(const std::string & indexStr)711 inline bool IsNotCompositeIndex(const std::string &indexStr)
712 {
713     if (indexStr.empty()) {
714         return true;
715     }
716     if (indexStr == std::string("0")) { // In fact, test found that attrValue will be "0" if not exist
717         return true;
718     }
719     return false;
720 }
721 }
722 
ParseCheckIndexes(const RawIndexInfos & indexCollect)723 int SchemaObject::FlatBufferSchema::ParseCheckIndexes(const RawIndexInfos &indexCollect)
724 {
725     for (const auto &entry : indexCollect) {
726         std::vector<std::string> indexStrArray{entry.first}; // Entry.first is fieldName at root that was checked valid
727         const std::string &rawIndexStr = entry.second;
728         if (IsNotCompositeIndex(rawIndexStr)) {
729             int errCode = owner_.ParseCheckEachIndexFromStringArray(indexStrArray);
730             if (errCode != E_OK) {
731                 LOGE("[FBSchema][ParseIndex] Create single-index=%s fail, errCode=%d.", entry.first.c_str(), errCode);
732                 return errCode;
733             }
734             description_ += ("INDEX=" + entry.first + ";");
735             continue;
736         }
737         // Parse other indexField
738         for (uint32_t curPos = 0; curPos < rawIndexStr.size();) {
739             uint32_t nextCommaPos = rawIndexStr.find_first_of(',', curPos);
740             std::string eachIndexField = rawIndexStr.substr(curPos, nextCommaPos - curPos);
741             eachIndexField = SchemaUtils::Strip(eachIndexField);
742             if (!eachIndexField.empty()) { // Continuous ',' just ignore
743                 indexStrArray.push_back(eachIndexField);
744             }
745             if (nextCommaPos >= rawIndexStr.size()) { // No ',' anymore
746                 break;
747             }
748             curPos = nextCommaPos + 1;
749         }
750         int errCode = owner_.ParseCheckEachIndexFromStringArray(indexStrArray);
751         if (errCode != E_OK) {
752             LOGE("[FBSchema][ParseIndex] Create composite-index=%s, rawStr=%s fail, errCode=%d.", entry.first.c_str(),
753                 rawIndexStr.c_str(), errCode);
754             return errCode;
755         }
756         description_ += ("INDEX=" + entry.first + ";");
757     }
758     if (owner_.schemaIndexes_.size() > SchemaConstant::SCHEMA_INDEX_COUNT_MAX) {
759         LOGE("[FBSchema][ParseIndex] Index count=%zu exceed limitation.", owner_.schemaIndexes_.size());
760         return -E_SCHEMA_PARSE_FAIL;
761     }
762     return E_OK;
763 }
764 
765 namespace {
IsNotEqualNotCompatible(int errCode)766 inline bool IsNotEqualNotCompatible(int errCode)
767 {
768     return (errCode != -E_SCHEMA_EQUAL_EXACTLY) && (errCode != -E_SCHEMA_UNEQUAL_COMPATIBLE) &&
769         (errCode != -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE);
770 }
771 
CompareFieldCount(bool isRoot,uint32_t selfCount,uint32_t otherCount)772 int CompareFieldCount(bool isRoot, uint32_t selfCount, uint32_t otherCount)
773 {
774     if (isRoot) {
775         if (otherCount < selfCount) {
776             LOGE("[FBSchema][CompareRoot] RootFieldSize: other=%u less than self=%u.", otherCount, selfCount);
777             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
778         }
779     } else {
780         if (selfCount != otherCount) {
781             LOGE("[FBSchema][CompareRoot] StructFieldSize: self=%u differ with other=%u.", selfCount, otherCount);
782             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
783         }
784     }
785     return (selfCount == otherCount) ? -E_SCHEMA_EQUAL_EXACTLY : -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE;
786 }
787 
CompareFieldInfoBesideType(const reflection::Field & selfField,const reflection::Field & otherField,reflection::BaseType theType)788 int CompareFieldInfoBesideType(const reflection::Field &selfField, const reflection::Field &otherField,
789     reflection::BaseType theType)
790 {
791     // Compare offset
792     if (selfField.offset() != otherField.offset()) {
793         LOGE("[FBSchema][CompareField] Offset differ: self=%u, other=%u.", selfField.offset(), otherField.offset());
794         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
795     }
796     // Compare default value
797     if (selfField.default_integer() != otherField.default_integer()) {
798         LOGE("[FBSchema][CompareField] DefaultInteger differ: self=%lld, other=%lld.",
799             static_cast<long long>(selfField.default_integer()), static_cast<long long>(otherField.default_integer()));
800         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
801     }
802     // QUEER: for the same default_real value in fbs, flatbuffer will generate different value in binary ???
803     if (!IsDoubleNearlyEqual(selfField.default_real(), otherField.default_real())) {
804         LOGE("[FBSchema][CompareField] DefaultReal differ: self=%f, other=%f.", selfField.default_real(),
805             otherField.default_real());
806         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
807     }
808     // Ignore deprecated, Compare required
809     if (IsRequiredSupportType(theType)) {
810         if (selfField.required() != otherField.required()) {
811             LOGE("[FBSchema][CompareField] Require differ: self=%d, other=%d.", selfField.required(),
812                 otherField.required());
813             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
814         }
815     }
816     return -E_SCHEMA_EQUAL_EXACTLY;
817 }
818 
CompareFieldInfo(const reflection::Field & selfField,const reflection::Field & otherField,bool & isStruct)819 int CompareFieldInfo(const reflection::Field &selfField, const reflection::Field &otherField, bool &isStruct)
820 {
821     auto selfType = selfField.type();
822     auto otherType = otherField.type();
823     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfType);
824     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherType);
825     // Compare type
826     auto selfBaseType = selfType->base_type();
827     auto otherBaseType = otherType->base_type();
828     if (selfBaseType != otherBaseType) {
829         LOGE("[FBSchema][CompareField] BaseType differ: self=%s, other=%s.", reflection::EnumNameBaseType(selfBaseType),
830             reflection::EnumNameBaseType(otherBaseType));
831         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
832     }
833     if (IsVectorType(selfBaseType)) {
834         auto selfElementType = selfType->element();
835         auto otherElementType = otherType->element();
836         if (selfElementType != otherElementType) {
837             LOGE("[FBSchema][CompareField] ElementType differ: self=%u, other=%u.", selfElementType, otherElementType);
838             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
839         }
840     }
841     if (IsObjectType(selfBaseType)) {
842         isStruct = true;
843     }
844     return CompareFieldInfoBesideType(selfField, otherField, selfBaseType);
845 }
846 
847 // Split from original functions which would be longer than 50 line
CompareExtraField(const PairConstPointer<reflection::Object> & bothObject)848 int CompareExtraField(const PairConstPointer<reflection::Object> &bothObject)
849 {
850     // This is private function, the caller guarantee that inputParameter not nullptr
851     auto selfFields = bothObject.first->fields();
852     auto otherFields = bothObject.second->fields();
853     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfFields);
854     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherFields);
855     // Each field in other not in self, should not be required
856     for (uint32_t i = 0; i < otherFields->size(); i++) {
857         auto eachOtherField = (*otherFields)[i];
858         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachOtherField);
859         auto otherName = eachOtherField->name();
860         CHECK_NULL_UNLIKELY_RETURN_ERROR(otherName);
861         auto correspondSelfField = selfFields->LookupByKey(otherName->c_str());
862         if (correspondSelfField != nullptr) {
863             continue;
864         }
865         if (eachOtherField->required()) {
866             LOGE("[FBSchema][CompareDefine] Extra field=%s should not be required.", otherName->c_str());
867             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
868         }
869     }
870     return -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE;
871 }
872 }
873 
CompareTableOrStructDefine(const PairConstPointer<reflection::Schema> & bothSchema,const PairConstPointer<reflection::Object> & bothObject,bool isRoot,std::set<std::string> & compared) const874 int SchemaObject::FlatBufferSchema::CompareTableOrStructDefine(const PairConstPointer<reflection::Schema> &bothSchema,
875     const PairConstPointer<reflection::Object> &bothObject, bool isRoot, std::set<std::string> &compared) const
876 {
877     // This is private function, the caller guarantee that inputParameter not nullptr
878     auto selfFields = bothObject.first->fields();
879     auto otherFields = bothObject.second->fields();
880     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfFields);
881     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherFields);
882     int errCode = CompareFieldCount(isRoot, selfFields->size(), otherFields->size());
883     if (errCode == -E_SCHEMA_UNEQUAL_INCOMPATIBLE) {
884         return errCode;
885     }
886     // Each field in self should be in other, and they should be same
887     for (uint32_t i = 0; i < selfFields->size(); i++) {
888         auto eachSelfField = (*selfFields)[i];
889         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachSelfField);
890         auto selfName = eachSelfField->name();
891         CHECK_NULL_UNLIKELY_RETURN_ERROR(selfName);
892         auto correspondOtherField = otherFields->LookupByKey(selfName->c_str());
893         if (correspondOtherField == nullptr) {
894             LOGE("[FBSchema][CompareDefine] SelfField=%s not found in other.", selfName->c_str());
895             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
896         }
897         bool isStruct = false;
898         errCode = CompareFieldInfo(*eachSelfField, *correspondOtherField, isStruct);
899         if (IsNotEqualNotCompatible(errCode)) {
900             LOGE("[FBSchema][CompareDefine] Compare info of field=%s fail, errCode=%d.", selfName->c_str(), errCode);
901             return errCode;
902         }
903         if (isStruct) {
904             // Previous parse guarantee that recursion will not be unlimited, don't be afraid.
905             errCode = CompareStruct(bothSchema, {eachSelfField, correspondOtherField}, compared);
906             if (IsNotEqualNotCompatible(errCode)) {
907                 return errCode;
908             }
909         }
910     }
911     if (selfFields->size() == otherFields->size()) {
912         return -E_SCHEMA_EQUAL_EXACTLY;
913     }
914     return CompareExtraField(bothObject);
915 }
916 
CompareStruct(const PairConstPointer<reflection::Schema> & bothSchema,const PairConstPointer<reflection::Field> & bothField,std::set<std::string> & compared) const917 int SchemaObject::FlatBufferSchema::CompareStruct(const PairConstPointer<reflection::Schema> &bothSchema,
918     const PairConstPointer<reflection::Field> &bothField, std::set<std::string> &compared) const
919 {
920     // This is private function, the caller guarantee that inputParameter not nullptr
921     auto selfObjects = bothSchema.first->objects();
922     auto otherObjects = bothSchema.second->objects();
923     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfObjects);
924     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherObjects);
925     auto selfType = bothField.first->type();
926     auto otherType = bothField.second->type();
927     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfType);
928     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherType);
929     auto selfObjIndex = selfType->index();
930     auto otherObjIndex = otherType->index();
931     if (selfObjIndex < 0 || static_cast<uint32_t>(selfObjIndex) >= selfObjects->size()) { // Unlikely
932         return -E_INTERNAL_ERROR;
933     }
934     if (otherObjIndex < 0 || static_cast<uint32_t>(otherObjIndex) >= otherObjects->size()) { // Unlikely
935         return -E_INTERNAL_ERROR;
936     }
937     auto selfStructObj = (*selfObjects)[selfObjIndex];
938     auto otherStructObj = (*otherObjects)[otherObjIndex];
939     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfStructObj);
940     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherStructObj);
941     // Previous parse can guarantee that they are both struct, no need to check again
942     auto selfStructName = selfStructObj->name();
943     auto otherStructName = otherStructObj->name();
944     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfStructName);
945     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherStructName);
946     std::string selfName = SchemaUtils::StripNameSpace(selfStructName->str());
947     std::string otherName = SchemaUtils::StripNameSpace(otherStructName->str());
948     if (selfName != otherName) {
949         LOGE("[FBSchema][CompareStruct] The field is not of same struct type, self=%s, other=%s.",
950             selfName.c_str(), otherName.c_str());
951         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
952     }
953     if (compared.count(selfName) != 0) { // This struct-type had already been compared, no need to do recurse again
954         return -E_SCHEMA_EQUAL_EXACTLY;
955     }
956     compared.insert(selfName);
957     // Compare struct detail
958     if (selfStructObj->minalign() != otherStructObj->minalign()) {
959         LOGE("[FBSchema][CompareStruct] The struct minalign differ, self=%d, other=%d.",
960             selfStructObj->minalign(), otherStructObj->minalign());
961         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
962     }
963     if (selfStructObj->bytesize() != otherStructObj->bytesize()) {
964         LOGE("[FBSchema][CompareStruct] The struct bytesize differ, self=%d, other=%d.",
965             selfStructObj->bytesize(), otherStructObj->bytesize());
966         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
967     }
968     // Previous parse guarantee that recursion will not be unlimited, don't be afraid.
969     return CompareTableOrStructDefine(bothSchema, {selfStructObj, otherStructObj}, false, compared);
970 }
971 #else // OMIT_FLATBUFFER
IsFlatBufferSchema(const std::string & inOriginal,std::string & outDecoded)972 bool SchemaObject::FlatBufferSchema::IsFlatBufferSchema(const std::string &inOriginal, std::string &outDecoded)
973 {
974     LOGW("FlatBuffer Omit From Compile.");
975     return false;
976 }
977 
ParseFlatBufferSchema(const std::string & inDecoded)978 int SchemaObject::FlatBufferSchema::ParseFlatBufferSchema(const std::string &inDecoded)
979 {
980     owner_.schemaType_ = SchemaType::FLATBUFFER; // For fix compile warning
981     return -E_NOT_PERMIT;
982 }
983 
CompareFlatBufferDefine(const FlatBufferSchema & other) const984 int SchemaObject::FlatBufferSchema::CompareFlatBufferDefine(const FlatBufferSchema &other) const
985 {
986     return -E_NOT_PERMIT;
987 }
988 
VerifyFlatBufferValue(const RawValue & inValue,bool tryNoSizePrefix) const989 int SchemaObject::FlatBufferSchema::VerifyFlatBufferValue(const RawValue &inValue, bool tryNoSizePrefix) const
990 {
991     return -E_NOT_PERMIT;
992 }
993 
ExtractFlatBufferValue(RawString inPath,const RawValue & inValue,TypeValue & outExtract,bool tryNoSizePrefix) const994 int SchemaObject::FlatBufferSchema::ExtractFlatBufferValue(RawString inPath, const RawValue &inValue,
995     TypeValue &outExtract, bool tryNoSizePrefix) const
996 {
997     return -E_NOT_PERMIT;
998 }
999 #endif // OMIT_FLATBUFFER
1000 } // namespace DistributedDB
1001