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 {
244 struct BaseTypeNode {
245     reflection::BaseType type;
246     FieldType fieldType;
247 };
248 
MapFieldType(reflection::BaseType inType)249 FieldType MapFieldType(reflection::BaseType inType)
250 {
251     static const BaseTypeNode baseTypeNodes[] = {
252         {reflection::BaseType::Bool, FieldType::LEAF_FIELD_BOOL},
253         {reflection::BaseType::Byte, FieldType::LEAF_FIELD_INTEGER},
254         {reflection::BaseType::UByte, FieldType::LEAF_FIELD_INTEGER},
255         {reflection::BaseType::Short, FieldType::LEAF_FIELD_INTEGER},
256         {reflection::BaseType::UShort, FieldType::LEAF_FIELD_INTEGER},
257         {reflection::BaseType::Int, FieldType::LEAF_FIELD_INTEGER},
258         {reflection::BaseType::UInt, FieldType::LEAF_FIELD_LONG},
259         {reflection::BaseType::Long, FieldType::LEAF_FIELD_LONG},
260         {reflection::BaseType::ULong, FieldType::LEAF_FIELD_DOUBLE},
261         {reflection::BaseType::Float, FieldType::LEAF_FIELD_DOUBLE},
262         {reflection::BaseType::Double, FieldType::LEAF_FIELD_DOUBLE},
263         {reflection::BaseType::String, FieldType::LEAF_FIELD_STRING},
264         {reflection::BaseType::Vector, FieldType::LEAF_FIELD_ARRAY},
265         {reflection::BaseType::Obj, FieldType::INTERNAL_FIELD_OBJECT}
266     };
267     const auto &result = std::find_if(std::begin(baseTypeNodes), std::end(baseTypeNodes), [inType](const auto &node) {
268         return node.type == inType;
269     });
270     return result == std::end(baseTypeNodes) ? FieldType::LEAF_FIELD_NULL : (*result).fieldType;
271 }
272 
CheckDollarDotAndSkipIt(RawString inPath)273 RawString CheckDollarDotAndSkipIt(RawString inPath)
274 {
275     if (inPath == nullptr) {
276         return nullptr;
277     }
278     auto pathStr = inPath;
279     if (*pathStr++ != '$') {
280         return nullptr;
281     }
282     if (*pathStr++ != '.') {
283         return nullptr;
284     }
285     if (*pathStr == 0) {
286         return nullptr;
287     }
288     return pathStr;
289 }
290 
GetFieldInfoFromSchemaByPath(const reflection::Schema & schema,RawString pathStr)291 const reflection::Field *GetFieldInfoFromSchemaByPath(const reflection::Schema &schema, RawString pathStr)
292 {
293     auto rootTable = schema.root_table();
294     if (rootTable == nullptr) { // Unlikely
295         return nullptr;
296     }
297     auto rootFields = rootTable->fields();
298     if (rootFields == nullptr) { // Unlikely
299         return nullptr;
300     }
301     // Unlikely to return nullptr, except internal-error happened
302     return rootFields->LookupByKey(pathStr);
303 }
304 
DoVerifyBeforeExtract(const flatbuffers::Table & rootValue,const reflection::Field & fieldInfo,const flatbuffers::Verifier & verifier)305 int DoVerifyBeforeExtract(const flatbuffers::Table &rootValue, const reflection::Field &fieldInfo,
306     const flatbuffers::Verifier &verifier)
307 {
308     auto type = fieldInfo.type();
309     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
310     bool verifyResult = true;
311     switch (type->base_type()) {
312         case reflection::Bool:
313         case reflection::Byte:
314         case reflection::UByte:
315             verifyResult = rootValue.VerifyField<int8_t>(verifier, fieldInfo.offset());
316             break;
317         case reflection::Short:
318         case reflection::UShort:
319             verifyResult = rootValue.VerifyField<int16_t>(verifier, fieldInfo.offset());
320             break;
321         case reflection::Int:
322         case reflection::UInt:
323             verifyResult = rootValue.VerifyField<int32_t>(verifier, fieldInfo.offset());
324             break;
325         case reflection::Long:
326         case reflection::ULong:
327             verifyResult = rootValue.VerifyField<uint64_t>(verifier, fieldInfo.offset());
328             break;
329         case reflection::Float:
330             verifyResult = rootValue.VerifyField<float>(verifier, fieldInfo.offset());
331             break;
332         case reflection::Double:
333             verifyResult = rootValue.VerifyField<double>(verifier, fieldInfo.offset());
334             break;
335         case reflection::String:
336             verifyResult = rootValue.VerifyField<flatbuffers::uoffset_t>(verifier, fieldInfo.offset()) &&
337                 verifier.VerifyString(flatbuffers::GetFieldS(rootValue, fieldInfo)); // VerifyString can accept null
338             break;
339         default:
340             return -E_NOT_SUPPORT;
341     }
342     return (verifyResult ? E_OK : -E_FLATBUFFER_VERIFY_FAIL);
343 }
344 
DoExtractString(const flatbuffers::Table & rootValue,const reflection::Field & fieldInfo)345 inline std::string DoExtractString(const flatbuffers::Table &rootValue, const reflection::Field &fieldInfo)
346 {
347     auto strVal = flatbuffers::GetFieldS(rootValue, fieldInfo);
348     if (strVal == nullptr) {
349         return "";
350     }
351     return strVal->str();
352 }
353 
DoExtractValue(const flatbuffers::Table & rootValue,const reflection::Field & fieldInfo,TypeValue & outExtract)354 int DoExtractValue(const flatbuffers::Table &rootValue, const reflection::Field &fieldInfo, TypeValue &outExtract)
355 {
356     auto type = fieldInfo.type();
357     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
358     switch (type->base_type()) {
359         case reflection::Bool:
360             outExtract.second.boolValue = (flatbuffers::GetFieldI<int8_t>(rootValue, fieldInfo) != 0);
361             break;
362         case reflection::Byte:
363             outExtract.second.integerValue = flatbuffers::GetFieldI<int8_t>(rootValue, fieldInfo);
364             break;
365         case reflection::UByte:
366             outExtract.second.integerValue = flatbuffers::GetFieldI<uint8_t>(rootValue, fieldInfo);
367             break;
368         case reflection::Short:
369             outExtract.second.integerValue = flatbuffers::GetFieldI<int16_t>(rootValue, fieldInfo);
370             break;
371         case reflection::UShort:
372             outExtract.second.integerValue = flatbuffers::GetFieldI<uint16_t>(rootValue, fieldInfo);
373             break;
374         case reflection::Int:
375             outExtract.second.integerValue = flatbuffers::GetFieldI<int32_t>(rootValue, fieldInfo);
376             break;
377         case reflection::UInt:
378             outExtract.second.longValue = flatbuffers::GetFieldI<uint32_t>(rootValue, fieldInfo);
379             break;
380         case reflection::Long:
381             outExtract.second.longValue = flatbuffers::GetFieldI<int64_t>(rootValue, fieldInfo);
382             break;
383         case reflection::ULong:
384             outExtract.second.doubleValue = flatbuffers::GetFieldI<uint64_t>(rootValue, fieldInfo);
385             break;
386         case reflection::Float:
387             outExtract.second.doubleValue = flatbuffers::GetFieldF<float>(rootValue, fieldInfo);
388             break;
389         case reflection::Double:
390             outExtract.second.doubleValue = flatbuffers::GetFieldF<double>(rootValue, fieldInfo);
391             break;
392         case reflection::String:
393             outExtract.second.stringValue = DoExtractString(rootValue, fieldInfo);
394             break;
395         default:
396             return -E_NOT_SUPPORT;
397     }
398     return E_OK;
399 }
400 
ExtractFlatBufferValueFinal(const flatbuffers::Table & rootValue,const reflection::Field & fieldInfo,const flatbuffers::Verifier & verifier,TypeValue & outExtract)401 int ExtractFlatBufferValueFinal(const flatbuffers::Table &rootValue, const reflection::Field &fieldInfo,
402     const flatbuffers::Verifier &verifier, TypeValue &outExtract)
403 {
404     auto type = fieldInfo.type();
405     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
406     auto baseType = type->base_type();
407     if (!IsIndexableType(baseType)) {
408         LOGE("[ExtractFinal] BaseType=%s not indexable.", reflection::EnumNameBaseType(baseType));
409         return -E_NOT_SUPPORT;
410     }
411     outExtract.first = MapFieldType(type->base_type());
412     int errCode = DoVerifyBeforeExtract(rootValue, fieldInfo, verifier);
413     if (errCode != E_OK) {
414         LOGE("[ExtractFinal] DoVerify fail, errCode=%d.", errCode);
415         return errCode;
416     }
417     errCode = DoExtractValue(rootValue, fieldInfo, outExtract);
418     if (errCode != E_OK) {
419         LOGE("[ExtractFinal] DoExtract fail, errCode=%d.", errCode);
420         return errCode;
421     }
422     return E_OK;
423 }
424 }
425 
ExtractFlatBufferValue(RawString inPath,const RawValue & inValue,TypeValue & outExtract,bool tryNoSizePrefix) const426 int SchemaObject::FlatBufferSchema::ExtractFlatBufferValue(RawString inPath, const RawValue &inValue,
427     TypeValue &outExtract, bool tryNoSizePrefix) const
428 {
429     // NOTE!!! This function is performance sensitive !!! Carefully not to allocate memory often!!!
430     (void)tryNoSizePrefix; // Use it in the future, currently we demand value is sizePrefixed
431     int errCode = CheckSizePrefixRawValue(inValue);
432     if (errCode != E_OK) {
433         return errCode;
434     }
435     auto pathStr = CheckDollarDotAndSkipIt(inPath);
436     if (pathStr == nullptr) { // Unlikely
437         LOGE("[FBSchema][Extract] inPath not begin with $. or nothing after it.");
438         return -E_INVALID_ARGS;
439     }
440     auto schema = GetSchema();
441     CHECK_NULL_UNLIKELY_RETURN_ERROR(schema);
442     // Currently we don't support nest-path
443     auto fieldInfo = GetFieldInfoFromSchemaByPath(*schema, pathStr);
444     if (fieldInfo == nullptr) {
445         LOGW("[FBSchema][Extract] FieldInfo of path not found.");
446         return -E_INTERNAL_ERROR;
447     }
448     // Begin extract, we have to minimal verify if we don't trust value from database
449     auto valueRealBegin = inValue.first + SIZE_PREFIX_SIZE;
450     auto valueRealSize = inValue.second - SIZE_PREFIX_SIZE;
451     flatbuffers::Verifier verifier(valueRealBegin, valueRealSize);
452     auto offset = verifier.VerifyOffset(0); // Attention: Verify root offset before we call GetAnyRoot
453     if (offset == 0) {
454         LOGE("[FBSchema][Extract] Verity root offset failed.");
455         return -E_FLATBUFFER_VERIFY_FAIL;
456     }
457     auto rootValue = flatbuffers::GetAnyRoot(valueRealBegin);
458     if (rootValue == nullptr) {
459         LOGE("[FBSchema][Extract] Get rootTable from value fail.");
460         return -E_INVALID_DATA;
461     }
462     // Verity vTable of rootTable before we extract anything from rootValue by reflection
463     bool vTableOk = rootValue->VerifyTableStart(verifier);
464     if (!vTableOk) {
465         LOGE("[FBSchema][Extract] Verify vTable of rootTable of value fail.");
466         return -E_FLATBUFFER_VERIFY_FAIL;
467     }
468     errCode = ExtractFlatBufferValueFinal(*rootValue, *fieldInfo, verifier, outExtract);
469     if (errCode != E_OK) {
470         return errCode;
471     }
472     verifier.EndTable();
473     return E_OK;
474 }
475 
GetSchema() const476 const reflection::Schema *SchemaObject::FlatBufferSchema::GetSchema() const
477 {
478     // This function is called after schemaString_ had been verified by flatbuffer
479     return reflection::GetSizePrefixedSchema(owner_.schemaString_.c_str());
480 }
481 
ParseCheckRootTableAttribute(const reflection::Object & rootTable)482 int SchemaObject::FlatBufferSchema::ParseCheckRootTableAttribute(const reflection::Object &rootTable)
483 {
484     auto rootTableAttr = rootTable.attributes();
485     if (rootTableAttr == nullptr) {
486         LOGE("[FBSchema][ParseRootAttr] Root table no attribute.");
487         return -E_SCHEMA_PARSE_FAIL;
488     }
489 
490     auto versionAttr = rootTableAttr->LookupByKey(SchemaConstant::KEYWORD_SCHEMA_VERSION.c_str());
491     if (!AttributeExistAndHasValue(versionAttr)) {
492         LOGE("[FBSchema][ParseRootAttr] No SCHEMA_VERSION attribute or no value.");
493         return -E_SCHEMA_PARSE_FAIL;
494     }
495     if (SchemaUtils::Strip(versionAttr->value()->str()) != SchemaConstant::SCHEMA_SUPPORT_VERSION) {
496         LOGE("[FBSchema][ParseRootAttr] Unexpect SCHEMA_VERSION=%s.", versionAttr->value()->c_str());
497         return -E_SCHEMA_PARSE_FAIL;
498     }
499     owner_.schemaVersion_ = SchemaConstant::SCHEMA_SUPPORT_VERSION;
500     description_ += (SchemaConstant::KEYWORD_SCHEMA_VERSION + "=" + SchemaConstant::SCHEMA_SUPPORT_VERSION + ";");
501 
502     auto skipsizeAttr = rootTableAttr->LookupByKey(SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE.c_str());
503     if (!AttributeExistAndHasValue(skipsizeAttr)) {
504         LOGI("[FBSchema][ParseRootAttr] No SCHEMA_SKIPSIZE attribute or no value.");
505         owner_.schemaSkipSize_ = 0; // Default skipsize value
506         return E_OK;
507     }
508     std::string skipsizeStr = SchemaUtils::Strip(skipsizeAttr->value()->str());
509     int skipsizeInt = strtol(skipsizeStr.c_str(), nullptr, 10); // 10: decimal
510     if (std::to_string(skipsizeInt) != skipsizeStr || skipsizeInt < 0 ||
511         static_cast<uint32_t>(skipsizeInt) > SchemaConstant::SCHEMA_SKIPSIZE_MAX) {
512         LOGE("[FBSchema][ParseRootAttr] Unexpect SCHEMA_SKIPSIZE value=%s.", skipsizeAttr->value()->c_str());
513         return -E_SCHEMA_PARSE_FAIL;
514     }
515     owner_.schemaSkipSize_ = static_cast<uint32_t>(skipsizeInt);
516     description_ += (SchemaConstant::KEYWORD_SCHEMA_SKIPSIZE + "=" + skipsizeStr + ";");
517     return E_OK;
518 }
519 
ParseCheckRootTableDefine(const reflection::Schema & schema,const reflection::Object & rootTable,RawIndexInfos & indexCollect)520 int SchemaObject::FlatBufferSchema::ParseCheckRootTableDefine(const reflection::Schema &schema,
521     const reflection::Object &rootTable, RawIndexInfos &indexCollect)
522 {
523     // Clear schemaDefine_ to recover from a fail parse
524     owner_.schemaDefine_.clear();
525     auto fields = rootTable.fields();
526     if (fields == nullptr || fields->size() == 0) {
527         LOGE("[FBSchema][ParseRootDefine] Empty define.");
528         return -E_SCHEMA_PARSE_FAIL;
529     }
530     for (uint32_t i = 0; i < fields->size(); i++) {
531         auto eachField = (*fields)[i];
532         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachField);
533 
534         auto name = eachField->name();
535         CHECK_NULL_UNLIKELY_RETURN_ERROR(name);
536         int errCode = SchemaUtils::CheckFieldName(name->str());
537         if (errCode != E_OK) {
538             LOGE("[FBSchema][ParseRootDefine] Invalid fieldName, errCode=%d.", errCode);
539             return -E_SCHEMA_PARSE_FAIL;
540         }
541         FieldPath path{name->str()};
542         if (owner_.schemaDefine_[ROOT_DEFINE_DEPTH].count(path) != 0) { // Unlikely
543             LOGE("[FBSchema][ParseRootDefine] FieldPath already exist at root.");
544             return -E_SCHEMA_PARSE_FAIL;
545         }
546 
547         errCode = ParseCheckFieldInfo(schema, *eachField, path, indexCollect);
548         if (errCode != E_OK) {
549             LOGE("[FBSchema][ParseRootDefine] ParseFieldInfo errCode=%d", errCode);
550             return errCode;
551         }
552     }
553     uint32_t fieldPathCount = 0;
554     for (uint32_t depth = ROOT_DEFINE_DEPTH; depth < SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX; depth++) {
555         if (owner_.schemaDefine_.count(depth) != 0) {
556             fieldPathCount += owner_.schemaDefine_[depth].size();
557         }
558     }
559     if (fieldPathCount > SchemaConstant::SCHEMA_FEILD_NAME_COUNT_MAX) {
560         LOGE("[FBSchema][ParseRootDefine] FieldPath count=%" PRIu32 " exceed the limitation.", fieldPathCount);
561         return -E_SCHEMA_PARSE_FAIL;
562     }
563     return E_OK;
564 }
565 
566 namespace {
CheckFieldTypeSupport(const reflection::Type & inType,bool isRootField)567 bool CheckFieldTypeSupport(const reflection::Type &inType, bool isRootField)
568 {
569     auto baseType = inType.base_type();
570     if (isRootField) {
571         if (!IsSupportTypeAtRoot(baseType)) {
572             LOGE("[FBSchema][DecideType] BaseType=%s not support at root.", reflection::EnumNameBaseType(baseType));
573             return false;
574         }
575         if (IsIntegerType(baseType) && (inType.index() != INDEX_OF_NOT_ENUM)) {
576             LOGE("[FBSchema][DecideType] BaseType=%s is enum, not support.", reflection::EnumNameBaseType(baseType));
577             return false;
578         }
579         if (IsVectorType(baseType)) {
580             auto elementType = inType.element();
581             if (!IsIndexableType(elementType)) {
582                 LOGE("[FBSchema][DecideType] ElementType=%s not support for vector.",
583                     reflection::EnumNameBaseType(elementType));
584                 return false;
585             }
586         }
587     } else {
588         // Currently only support nest in Struct, support only scalar and nest-struct
589         if (!IsScalarType(baseType) && !IsObjectType(baseType)) {
590             LOGE("[FBSchema][DecideType] BaseType=%s not support for struct.", reflection::EnumNameBaseType(baseType));
591             return false;
592         }
593     }
594     return true;
595 }
596 }
597 
ParseCheckFieldInfo(const reflection::Schema & schema,const reflection::Field & field,const FieldPath & path,RawIndexInfos & indexCollect)598 int SchemaObject::FlatBufferSchema::ParseCheckFieldInfo(const reflection::Schema &schema,
599     const reflection::Field &field, const FieldPath &path, RawIndexInfos &indexCollect)
600 {
601     if (path.empty() || path.size() > SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX) {
602         LOGE("[FBSchema][ParseField] FieldPath size=%zu invalid.", path.size());
603         return -E_SCHEMA_PARSE_FAIL;
604     }
605     uint32_t depth = path.size() - 1; // Depth count from zero
606     bool isRootField = (depth == ROOT_DEFINE_DEPTH);
607     SchemaAttribute &fieldInfo = owner_.schemaDefine_[depth][path]; // Create new entry in schemaDefine_
608 
609     auto type = field.type();
610     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
611     if (!CheckFieldTypeSupport(*type, isRootField)) {
612         return -E_SCHEMA_PARSE_FAIL;
613     }
614     auto baseType = type->base_type();
615     // Only type and isIndexable of SchemaAttribute is necessary
616     fieldInfo.type = MapFieldType(baseType);
617     fieldInfo.isIndexable = (IsIndexableType(baseType) && isRootField);
618     description_ += (SchemaUtils::FieldPathString(path) + "=" + reflection::EnumNameBaseType(baseType) + ";");
619 
620     if (IsRequiredSupportType(baseType)) {
621         if (IsConflict(field.deprecated(), field.required())) {
622             LOGE("[FBSchema][ParseField] Deprecated conflict with required.");
623             return -E_SCHEMA_PARSE_FAIL;
624         }
625     }
626     if (fieldInfo.isIndexable) {
627         CollectRawIndexInfos(field, indexCollect);
628     }
629     if (IsObjectType(baseType)) {
630         int errCode = ParseCheckStructDefine(schema, field, path);
631         if (errCode != E_OK) {
632             return errCode;
633         }
634     }
635     return E_OK;
636 }
637 
CollectRawIndexInfos(const reflection::Field & field,RawIndexInfos & indexCollect) const638 void SchemaObject::FlatBufferSchema::CollectRawIndexInfos(const reflection::Field &field,
639     RawIndexInfos &indexCollect) const
640 {
641     auto name = field.name();
642     if (name == nullptr) { // Not possible
643         return;
644     }
645     auto fieldAttr = field.attributes();
646     if (fieldAttr == nullptr) {
647         return;
648     }
649     auto indexAttr = fieldAttr->LookupByKey(SchemaConstant::KEYWORD_INDEX.c_str());
650     if (indexAttr == nullptr) {
651         return;
652     }
653     if (indexAttr->value() == nullptr) {
654         indexCollect[name->str()] = ""; // Must be SingleField-Index
655         return;
656     }
657     indexCollect[name->str()] = indexAttr->value()->str(); // May still be empty string
658 }
659 
ParseCheckStructDefine(const reflection::Schema & schema,const reflection::Field & field,const FieldPath & path)660 int SchemaObject::FlatBufferSchema::ParseCheckStructDefine(const reflection::Schema &schema,
661     const reflection::Field &field, const FieldPath &path)
662 {
663     if (path.size() >= SchemaConstant::SCHEMA_FEILD_PATH_DEPTH_MAX) {
664         LOGE("[FBSchema][ParseStruct] Struct define at depth limitation.");
665         return -E_SCHEMA_PARSE_FAIL;
666     }
667     auto objects = schema.objects();
668     CHECK_NULL_UNLIKELY_RETURN_ERROR(objects);
669     auto type = field.type();
670     CHECK_NULL_UNLIKELY_RETURN_ERROR(type);
671     auto objIndex = type->index();
672     if (objIndex < 0 || static_cast<uint32_t>(objIndex) >= objects->size()) { // Unlikely
673         return -E_INTERNAL_ERROR;
674     }
675     auto structObj = (*objects)[objIndex];
676     CHECK_NULL_UNLIKELY_RETURN_ERROR(structObj);
677     auto structName = structObj->name();
678     CHECK_NULL_UNLIKELY_RETURN_ERROR(structName);
679     if (!structObj->is_struct()) {
680         LOGE("[FBSchema][ParseStruct] Nest table=%s not support.", structName->c_str());
681         return -E_SCHEMA_PARSE_FAIL;
682     }
683     description_ += ("StructName=" + SchemaUtils::StripNameSpace(structName->str()) + ";");
684 
685     // Parse fields
686     auto structFields = structObj->fields();
687     CHECK_NULL_UNLIKELY_RETURN_ERROR(structFields);
688     // Flatbuffer guarantee that struct will not be empty size, even if it is empty, we just ignore it
689     for (uint32_t i = 0; i < structFields->size(); i++) {
690         auto eachField = (*structFields)[i];
691         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachField);
692         auto eachName = eachField->name();
693         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachName);
694         int errCode = SchemaUtils::CheckFieldName(eachName->str());
695         if (errCode != E_OK) {
696             LOGE("[FBSchema][ParseStruct] Invalid fieldName, errCode=%d.", errCode);
697             return -E_SCHEMA_PARSE_FAIL;
698         }
699         FieldPath eachPath = path;
700         eachPath.push_back(eachName->str());
701         RawIndexInfos notUsed;
702         errCode = ParseCheckFieldInfo(schema, *eachField, eachPath, notUsed);
703         if (errCode != E_OK) {
704             LOGE("[FBSchema][ParseStruct] ParseFieldInfo errCode=%d.", errCode);
705             return errCode;
706         }
707     }
708     return E_OK;
709 }
710 
711 namespace {
IsNotCompositeIndex(const std::string & indexStr)712 inline bool IsNotCompositeIndex(const std::string &indexStr)
713 {
714     // In fact, test found that attrValue will be "0" if not exist
715     return indexStr.empty() || indexStr == std::string("0");
716 }
717 }
718 
ParseCheckIndexes(const RawIndexInfos & indexCollect)719 int SchemaObject::FlatBufferSchema::ParseCheckIndexes(const RawIndexInfos &indexCollect)
720 {
721     for (const auto &entry : indexCollect) {
722         std::vector<std::string> indexStrArray{entry.first}; // Entry.first is fieldName at root that was checked valid
723         const std::string &rawIndexStr = entry.second;
724         if (IsNotCompositeIndex(rawIndexStr)) {
725             int errCode = owner_.ParseCheckEachIndexFromStringArray(indexStrArray);
726             if (errCode != E_OK) {
727                 LOGE("[FBSchema][ParseIndex] Create single-index fail:%d.", errCode);
728                 return errCode;
729             }
730             description_ += ("INDEX=" + entry.first + ";");
731             continue;
732         }
733         // Parse other indexField
734         for (uint32_t curPos = 0; curPos < rawIndexStr.size();) {
735             uint32_t nextCommaPos = rawIndexStr.find_first_of(',', curPos);
736             std::string eachIndexField = rawIndexStr.substr(curPos, nextCommaPos - curPos);
737             eachIndexField = SchemaUtils::Strip(eachIndexField);
738             if (!eachIndexField.empty()) { // Continuous ',' just ignore
739                 indexStrArray.push_back(eachIndexField);
740             }
741             if (nextCommaPos >= rawIndexStr.size()) { // No ',' anymore
742                 break;
743             }
744             curPos = nextCommaPos + 1;
745         }
746         int errCode = owner_.ParseCheckEachIndexFromStringArray(indexStrArray);
747         if (errCode != E_OK) {
748             LOGE("[FBSchema][ParseIndex] Create composite-index fail:%d.", errCode);
749             return errCode;
750         }
751         description_ += ("INDEX=" + entry.first + ";");
752     }
753     if (owner_.schemaIndexes_.size() > SchemaConstant::SCHEMA_INDEX_COUNT_MAX) {
754         LOGE("[FBSchema][ParseIndex] Index count=%zu exceed limitation.", owner_.schemaIndexes_.size());
755         return -E_SCHEMA_PARSE_FAIL;
756     }
757     return E_OK;
758 }
759 
760 namespace {
IsNotEqualNotCompatible(int errCode)761 inline bool IsNotEqualNotCompatible(int errCode)
762 {
763     return (errCode != -E_SCHEMA_EQUAL_EXACTLY) && (errCode != -E_SCHEMA_UNEQUAL_COMPATIBLE) &&
764         (errCode != -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE);
765 }
766 
CompareFieldCount(bool isRoot,uint32_t selfCount,uint32_t otherCount)767 int CompareFieldCount(bool isRoot, uint32_t selfCount, uint32_t otherCount)
768 {
769     if (isRoot) {
770         if (otherCount < selfCount) {
771             LOGW("[FBSchema][CompareRoot] RootFieldSize: %" PRIu32 " vs %" PRIu32, selfCount, otherCount);
772             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
773         }
774     } else {
775         if (selfCount != otherCount) {
776             LOGW("[FBSchema][CompareRoot] StructFieldSize: %" PRIu32 " vs %" PRIu32, selfCount, otherCount);
777             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
778         }
779     }
780     return (selfCount == otherCount) ? -E_SCHEMA_EQUAL_EXACTLY : -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE;
781 }
782 
CompareFieldInfoBesideType(const reflection::Field & selfField,const reflection::Field & otherField,reflection::BaseType theType)783 int CompareFieldInfoBesideType(const reflection::Field &selfField, const reflection::Field &otherField,
784     reflection::BaseType theType)
785 {
786     // Compare offset
787     if (selfField.offset() != otherField.offset()) {
788         LOGW("[FBSchema][CompareField] Offset diff");
789         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
790     }
791     // Compare default value
792     if (selfField.default_integer() != otherField.default_integer()) {
793         LOGE("[FBSchema][CompareField] DefaultInteger diff");
794         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
795     }
796     // QUEER: for the same default_real value in fbs, flatbuffer will generate different value in binary ???
797     if (!IsDoubleNearlyEqual(selfField.default_real(), otherField.default_real())) {
798         LOGE("[FBSchema][CompareField] DefaultReal diff");
799         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
800     }
801     // Ignore deprecated, Compare required
802     if (IsRequiredSupportType(theType)) {
803         if (selfField.required() != otherField.required()) {
804             LOGE("[FBSchema][CompareField] Require diff");
805             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
806         }
807     }
808     return -E_SCHEMA_EQUAL_EXACTLY;
809 }
810 
CompareFieldInfo(const reflection::Field & selfField,const reflection::Field & otherField,bool & isStruct)811 int CompareFieldInfo(const reflection::Field &selfField, const reflection::Field &otherField, bool &isStruct)
812 {
813     auto selfType = selfField.type();
814     auto otherType = otherField.type();
815     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfType);
816     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherType);
817     // Compare type
818     auto selfBaseType = selfType->base_type();
819     auto otherBaseType = otherType->base_type();
820     if (selfBaseType != otherBaseType) {
821         LOGE("[FBSchema][CompareField] BaseType diff:%s vs %s.", reflection::EnumNameBaseType(selfBaseType),
822             reflection::EnumNameBaseType(otherBaseType));
823         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
824     }
825     if (IsVectorType(selfBaseType)) {
826         auto selfElementType = selfType->element();
827         auto otherElementType = otherType->element();
828         if (selfElementType != otherElementType) {
829             LOGE("[FBSchema][CompareField] ElementType diff:%" PRIu32 " vs %" PRIu32, selfElementType,
830                 otherElementType);
831             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
832         }
833     }
834     if (IsObjectType(selfBaseType)) {
835         isStruct = true;
836     }
837     return CompareFieldInfoBesideType(selfField, otherField, selfBaseType);
838 }
839 
840 // Split from original functions which would be longer than 50 line
CompareExtraField(const PairConstPointer<reflection::Object> & bothObject)841 int CompareExtraField(const PairConstPointer<reflection::Object> &bothObject)
842 {
843     // This is private function, the caller guarantee that inputParameter not nullptr
844     auto selfFields = bothObject.first->fields();
845     auto otherFields = bothObject.second->fields();
846     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfFields);
847     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherFields);
848     // Each field in other not in self, should not be required
849     for (uint32_t i = 0; i < otherFields->size(); i++) {
850         auto eachOtherField = (*otherFields)[i];
851         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachOtherField);
852         auto otherName = eachOtherField->name();
853         CHECK_NULL_UNLIKELY_RETURN_ERROR(otherName);
854         auto correspondSelfField = selfFields->LookupByKey(otherName->c_str());
855         if (correspondSelfField != nullptr) {
856             continue;
857         }
858         if (eachOtherField->required()) {
859             LOGE("[FBSchema][CompareDefine] Extra field should not be required.");
860             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
861         }
862     }
863     return -E_SCHEMA_UNEQUAL_COMPATIBLE_UPGRADE;
864 }
865 }
866 
CompareTableOrStructDefine(const PairConstPointer<reflection::Schema> & bothSchema,const PairConstPointer<reflection::Object> & bothObject,bool isRoot,std::set<std::string> & compared) const867 int SchemaObject::FlatBufferSchema::CompareTableOrStructDefine(const PairConstPointer<reflection::Schema> &bothSchema,
868     const PairConstPointer<reflection::Object> &bothObject, bool isRoot, std::set<std::string> &compared) const
869 {
870     // This is private function, the caller guarantee that inputParameter not nullptr
871     auto selfFields = bothObject.first->fields();
872     auto otherFields = bothObject.second->fields();
873     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfFields);
874     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherFields);
875     int errCode = CompareFieldCount(isRoot, selfFields->size(), otherFields->size());
876     if (errCode == -E_SCHEMA_UNEQUAL_INCOMPATIBLE) {
877         return errCode;
878     }
879     // Each field in self should be in other, and they should be same
880     for (uint32_t i = 0; i < selfFields->size(); i++) {
881         auto eachSelfField = (*selfFields)[i];
882         CHECK_NULL_UNLIKELY_RETURN_ERROR(eachSelfField);
883         auto selfName = eachSelfField->name();
884         CHECK_NULL_UNLIKELY_RETURN_ERROR(selfName);
885         auto correspondOtherField = otherFields->LookupByKey(selfName->c_str());
886         if (correspondOtherField == nullptr) {
887             LOGE("[FBSchema][CompareDefine] SelfField not found in other.");
888             return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
889         }
890         bool isStruct = false;
891         errCode = CompareFieldInfo(*eachSelfField, *correspondOtherField, isStruct);
892         if (IsNotEqualNotCompatible(errCode)) {
893             LOGE("[FBSchema][CompareDefine] Compare info of field fail, errCode=%d.", errCode);
894             return errCode;
895         }
896         if (isStruct) {
897             // Previous parse guarantee that recursion will not be unlimited, don't be afraid.
898             errCode = CompareStruct(bothSchema, {eachSelfField, correspondOtherField}, compared);
899             if (IsNotEqualNotCompatible(errCode)) {
900                 return errCode;
901             }
902         }
903     }
904     if (selfFields->size() == otherFields->size()) {
905         return -E_SCHEMA_EQUAL_EXACTLY;
906     }
907     return CompareExtraField(bothObject);
908 }
909 
CompareStruct(const PairConstPointer<reflection::Schema> & bothSchema,const PairConstPointer<reflection::Field> & bothField,std::set<std::string> & compared) const910 int SchemaObject::FlatBufferSchema::CompareStruct(const PairConstPointer<reflection::Schema> &bothSchema,
911     const PairConstPointer<reflection::Field> &bothField, std::set<std::string> &compared) const
912 {
913     // This is private function, the caller guarantee that inputParameter not nullptr
914     auto selfObjects = bothSchema.first->objects();
915     auto otherObjects = bothSchema.second->objects();
916     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfObjects);
917     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherObjects);
918     auto selfType = bothField.first->type();
919     auto otherType = bothField.second->type();
920     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfType);
921     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherType);
922     auto selfObjIndex = selfType->index();
923     auto otherObjIndex = otherType->index();
924     if (selfObjIndex < 0 || static_cast<uint32_t>(selfObjIndex) >= selfObjects->size()) { // Unlikely
925         return -E_INTERNAL_ERROR;
926     }
927     if (otherObjIndex < 0 || static_cast<uint32_t>(otherObjIndex) >= otherObjects->size()) { // Unlikely
928         return -E_INTERNAL_ERROR;
929     }
930     auto selfStructObj = (*selfObjects)[selfObjIndex];
931     auto otherStructObj = (*otherObjects)[otherObjIndex];
932     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfStructObj);
933     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherStructObj);
934     // Previous parse can guarantee that they are both struct, no need to check again
935     auto selfStructName = selfStructObj->name();
936     auto otherStructName = otherStructObj->name();
937     CHECK_NULL_UNLIKELY_RETURN_ERROR(selfStructName);
938     CHECK_NULL_UNLIKELY_RETURN_ERROR(otherStructName);
939     std::string selfName = SchemaUtils::StripNameSpace(selfStructName->str());
940     std::string otherName = SchemaUtils::StripNameSpace(otherStructName->str());
941     if (selfName != otherName) {
942         LOGE("[FBSchema][CompareStruct] The field is not of same struct type");
943         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
944     }
945     if (compared.count(selfName) != 0) { // This struct-type had already been compared, no need to do recurse again
946         return -E_SCHEMA_EQUAL_EXACTLY;
947     }
948     compared.insert(selfName);
949     // Compare struct detail
950     if (selfStructObj->minalign() != otherStructObj->minalign()) {
951         LOGE("[FBSchema][CompareStruct] The struct minalign differ, self=%d, other=%d.",
952             selfStructObj->minalign(), otherStructObj->minalign());
953         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
954     }
955     if (selfStructObj->bytesize() != otherStructObj->bytesize()) {
956         LOGE("[FBSchema][CompareStruct] The struct bytesize differ, self=%d, other=%d.",
957             selfStructObj->bytesize(), otherStructObj->bytesize());
958         return -E_SCHEMA_UNEQUAL_INCOMPATIBLE;
959     }
960     // Previous parse guarantee that recursion will not be unlimited, don't be afraid.
961     return CompareTableOrStructDefine(bothSchema, {selfStructObj, otherStructObj}, false, compared);
962 }
963 #else // OMIT_FLATBUFFER
IsFlatBufferSchema(const std::string & inOriginal,std::string & outDecoded)964 bool SchemaObject::FlatBufferSchema::IsFlatBufferSchema(const std::string &inOriginal, std::string &outDecoded)
965 {
966     (void)inOriginal;
967     (void)outDecoded;
968     LOGW("FlatBuffer Omit From Compile.");
969     return false;
970 }
971 
ParseFlatBufferSchema(const std::string & inDecoded)972 int SchemaObject::FlatBufferSchema::ParseFlatBufferSchema(const std::string &inDecoded)
973 {
974     (void)inDecoded;
975     owner_.schemaType_ = SchemaType::FLATBUFFER; // For fix compile warning
976     return -E_NOT_PERMIT;
977 }
978 
CompareFlatBufferDefine(const FlatBufferSchema & other) const979 int SchemaObject::FlatBufferSchema::CompareFlatBufferDefine(const FlatBufferSchema &other) const
980 {
981     (void)other;
982     return -E_NOT_PERMIT;
983 }
984 
VerifyFlatBufferValue(const RawValue & inValue,bool tryNoSizePrefix) const985 int SchemaObject::FlatBufferSchema::VerifyFlatBufferValue(const RawValue &inValue, bool tryNoSizePrefix) const
986 {
987     (void)inValue;
988     (void)tryNoSizePrefix;
989     return -E_NOT_PERMIT;
990 }
991 
ExtractFlatBufferValue(RawString inPath,const RawValue & inValue,TypeValue & outExtract,bool tryNoSizePrefix) const992 int SchemaObject::FlatBufferSchema::ExtractFlatBufferValue(RawString inPath, const RawValue &inValue,
993     TypeValue &outExtract, bool tryNoSizePrefix) const
994 {
995     (void)inPath;
996     (void)inValue;
997     (void)outExtract;
998     (void)tryNoSizePrefix;
999     return -E_NOT_PERMIT;
1000 }
1001 #endif // OMIT_FLATBUFFER
1002 } // namespace DistributedDB
1003