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