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