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 #ifdef RELATIONAL_STORE
16 #include "relational_schema_object.h"
17 
18 #include <algorithm>
19 
20 #include "db_common.h"
21 #include "json_object.h"
22 #include "schema_constant.h"
23 #include "schema_utils.h"
24 
25 namespace DistributedDB {
IsSchemaValid() const26 bool RelationalSchemaObject::IsSchemaValid() const
27 {
28     return isValid_;
29 }
30 
GetSchemaType() const31 SchemaType RelationalSchemaObject::GetSchemaType() const
32 {
33     return schemaType_;
34 }
35 
ToSchemaString() const36 std::string RelationalSchemaObject::ToSchemaString() const
37 {
38     return schemaString_;
39 }
40 
ParseFromSchemaString(const std::string & inSchemaString)41 int RelationalSchemaObject::ParseFromSchemaString(const std::string &inSchemaString)
42 {
43     if (isValid_) {
44         return -E_NOT_PERMIT;
45     }
46 
47     if (inSchemaString.empty() || inSchemaString.size() > SchemaConstant::SCHEMA_STRING_SIZE_LIMIT) {
48         LOGE("[RelationalSchema][Parse] SchemaSize=%zu is invalid.", inSchemaString.size());
49         return -E_INVALID_ARGS;
50     }
51     JsonObject schemaObj;
52     int errCode = schemaObj.Parse(inSchemaString);
53     if (errCode != E_OK) {
54         LOGE("[RelationalSchema][Parse] Schema json string parse failed: %d.", errCode);
55         return errCode;
56     }
57 
58     errCode = ParseRelationalSchema(schemaObj);
59     if (errCode != E_OK) {
60         LOGE("[RelationalSchema][Parse] Parse to relational schema failed: %d.", errCode);
61         return errCode;
62     }
63 
64     schemaType_ = SchemaType::RELATIVE;
65     schemaString_ = schemaObj.ToString();
66     isValid_ = true;
67     GenerateReachableRef();
68     GenerateTableInfoReferenced();
69     return E_OK;
70 }
71 
GenerateSchemaString()72 void RelationalSchemaObject::GenerateSchemaString()
73 {
74     schemaString_ = {};
75     schemaString_ += "{";
76     schemaString_ += R"("SCHEMA_VERSION":")" + schemaVersion_ + R"(",)";
77     schemaString_ += R"("SCHEMA_TYPE":"RELATIVE",)";
78     if (schemaVersion_ == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2_1) {
79         std::string modeString = tableMode_ == DistributedTableMode::COLLABORATION ?
80             SchemaConstant::KEYWORD_TABLE_COLLABORATION : SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE;
81         schemaString_ += R"("TABLE_MODE":")" + modeString + R"(",)";
82     }
83     schemaString_ += R"("TABLES":[)";
84     for (auto it = tables_.begin(); it != tables_.end(); it++) {
85         if (it != tables_.begin()) {
86             schemaString_ += ",";
87         }
88         schemaString_ += it->second.ToTableInfoString(schemaVersion_);
89     }
90     schemaString_ += R"(])";
91     schemaString_ += GetReferencePropertyString();
92     schemaString_ += "}";
93 }
94 
AddRelationalTable(const TableInfo & table)95 void RelationalSchemaObject::AddRelationalTable(const TableInfo &table)
96 {
97     tables_[table.GetTableName()] = table;
98     isValid_ = true;
99     if (table.GetPrimaryKey().size() > 1 && table.GetTableSyncType() != CLOUD_COOPERATION) {
100         // Table with composite primary keys
101         // Composite primary keys are supported since version 2.1
102         schemaVersion_ = SchemaConstant::SCHEMA_CURRENT_VERSION;
103     }
104     GenerateSchemaString();
105 }
106 
RemoveRelationalTable(const std::string & tableName)107 void RelationalSchemaObject::RemoveRelationalTable(const std::string &tableName)
108 {
109     tables_.erase(tableName);
110     GenerateSchemaString();
111 }
112 
GetTables() const113 const TableInfoMap &RelationalSchemaObject::GetTables() const
114 {
115     return tables_;
116 }
117 
GetTableNames() const118 std::vector<std::string> RelationalSchemaObject::GetTableNames() const
119 {
120     std::vector<std::string> tableNames;
121     for (const auto &it : tables_) {
122         tableNames.emplace_back(it.first);
123     }
124     return tableNames;
125 }
126 
GetTable(const std::string & tableName) const127 TableInfo RelationalSchemaObject::GetTable(const std::string &tableName) const
128 {
129     auto it = tables_.find(tableName);
130     if (it != tables_.end()) {
131         return it->second;
132     }
133     return {};
134 }
135 
GetSchemaVersion() const136 std::string RelationalSchemaObject::GetSchemaVersion() const
137 {
138     return schemaVersion_;
139 }
140 
GetTableMode() const141 DistributedTableMode RelationalSchemaObject::GetTableMode() const
142 {
143     return tableMode_;
144 }
145 
SetTableMode(DistributedTableMode mode)146 void RelationalSchemaObject::SetTableMode(DistributedTableMode mode)
147 {
148     tableMode_ = mode;
149     if (tableMode_ == DistributedTableMode::COLLABORATION) {
150         schemaVersion_ = SchemaConstant::SCHEMA_CURRENT_VERSION;
151     }
152     GenerateSchemaString();
153 }
154 
InsertTrackerSchema(const TrackerSchema & schema)155 void RelationalSchemaObject::InsertTrackerSchema(const TrackerSchema &schema)
156 {
157     TrackerTable table;
158     table.Init(schema);
159     trackerTables_[schema.tableName].SetTrackerTable(table);
160     GenerateTrackerSchemaString();
161 }
162 
RemoveTrackerSchema(const TrackerSchema & schema)163 void RelationalSchemaObject::RemoveTrackerSchema(const TrackerSchema &schema)
164 {
165     trackerTables_.erase(schema.tableName);
166     GenerateTrackerSchemaString();
167 }
168 
GenerateTrackerSchemaString()169 void RelationalSchemaObject::GenerateTrackerSchemaString()
170 {
171     schemaString_ = {};
172     schemaString_ += "{";
173     schemaString_ += R"("SCHEMA_TYPE":"TRACKER",)";
174     schemaString_ += R"("TABLES":[)";
175     for (auto it = trackerTables_.begin(); it != trackerTables_.end(); it++) {
176         if (it != trackerTables_.begin()) {
177             schemaString_ += ",";
178         }
179         schemaString_ += it->second.GetTrackerTable().ToString();
180     }
181     schemaString_ += R"(])";
182     schemaString_ += "}";
183 }
184 
GetReferencePropertyString()185 std::string RelationalSchemaObject::GetReferencePropertyString()
186 {
187     std::string res;
188     if (!referenceProperty_.empty()) {
189         res += R"(,"REFERENCE_PROPERTY":[)";
190         for (const auto &reference : referenceProperty_) {
191             res += GetOneReferenceString(reference) + ",";
192         }
193         res.pop_back();
194         res += R"(])";
195     }
196     return res;
197 }
198 
GetOneReferenceString(const TableReferenceProperty & reference)199 std::string RelationalSchemaObject::GetOneReferenceString(const TableReferenceProperty &reference)
200 {
201     std::string res = R"({"SOURCE_TABLE_NAME":")";
202     res += reference.sourceTableName;
203     res += R"(","TARGET_TABLE_NAME":")";
204     res += reference.targetTableName;
205     res += R"(","COLUMNS":[)";
206     for (const auto &item : reference.columns) {
207         res += R"({"SOURCE_COL":")";
208         res += item.first;
209         res += R"(","TARGET_COL":")";
210         res += item.second;
211         res += R"("},)";
212     }
213     res.pop_back();
214     res += R"(]})";
215     return res;
216 }
217 
ColumnsCompare(const std::map<std::string,std::string> & left,const std::map<std::string,std::string> & right)218 static bool ColumnsCompare(const std::map<std::string, std::string> &left,
219     const std::map<std::string, std::string> &right)
220 {
221     if (left.size() != right.size()) {
222         LOGE("[ColumnsCompare] column size not equal");
223         return false;
224     }
225     std::map<std::string, std::string>::const_iterator leftIt = left.begin();
226     std::map<std::string, std::string>::const_iterator rightIt = right.begin();
227     for (; leftIt != left.end() && rightIt != right.end(); leftIt++, rightIt++) {
228         if (strcasecmp(leftIt->first.c_str(), rightIt->first.c_str()) != 0 ||
229             strcasecmp(leftIt->second.c_str(), rightIt->second.c_str()) != 0) {
230             LOGE("[ColumnsCompare] column not equal");
231             return false;
232         }
233     }
234     return true;
235 }
236 
ReferenceCompare(const TableReferenceProperty & left,const TableReferenceProperty & right)237 static bool ReferenceCompare(const TableReferenceProperty &left, const TableReferenceProperty &right)
238 {
239     if (strcasecmp(left.sourceTableName.c_str(), right.sourceTableName.c_str()) == 0 &&
240         strcasecmp(left.targetTableName.c_str(), right.targetTableName.c_str()) == 0 &&
241         ColumnsCompare(left.columns, right.columns)) {
242         return true;
243     }
244     return false;
245 }
246 
PropertyCompare(const std::vector<TableReferenceProperty> & left,const std::vector<TableReferenceProperty> & right,std::set<std::string> & changeTables)247 static void PropertyCompare(const std::vector<TableReferenceProperty> &left,
248     const std::vector<TableReferenceProperty> &right, std::set<std::string> &changeTables)
249 {
250     for (const auto &reference : left) {
251         bool found = false;
252         for (const auto &otherRef : right) {
253             if (ReferenceCompare(reference, otherRef)) {
254                 found = true;
255                 break;
256             }
257         }
258         if (!found) {
259             changeTables.insert(reference.sourceTableName);
260             changeTables.insert(reference.targetTableName);
261         }
262     }
263 }
264 
GetSharedTableForChangeTable(std::set<std::string> & changeTables) const265 std::set<std::string> RelationalSchemaObject::GetSharedTableForChangeTable(std::set<std::string> &changeTables) const
266 {
267     std::set<std::string> res;
268     TableInfoMap tableInfos = GetTables();
269     for (const auto &changeName : changeTables) {
270         for (const auto &item : tableInfos) {
271             if (item.second.GetSharedTableMark() &&
272                 (strcasecmp(item.second.GetOriginTableName().c_str(), changeName.c_str()) == 0)) {
273                 res.insert(item.second.GetTableName()); // get shared table name
274             }
275         }
276     }
277     return res;
278 }
279 
CompareReferenceProperty(const std::vector<TableReferenceProperty> & others) const280 std::set<std::string> RelationalSchemaObject::CompareReferenceProperty(
281     const std::vector<TableReferenceProperty> &others) const
282 {
283     std::set<std::string> changeTables;
284     PropertyCompare(referenceProperty_, others, changeTables);
285     PropertyCompare(others, referenceProperty_, changeTables);
286     if (!changeTables.empty()) { // get shared tables
287         std::set<std::string> sharedTables = GetSharedTableForChangeTable(changeTables);
288         changeTables.insert(sharedTables.begin(), sharedTables.end());
289     }
290     LOGI("[CompareReferenceProperty] changeTables size = %zu", changeTables.size());
291     return changeTables;
292 }
293 
GetReachableRef()294 std::map<std::string, std::map<std::string, bool>> RelationalSchemaObject::GetReachableRef()
295 {
296     return reachableReference_;
297 }
298 
GetTableWeight()299 std::map<std::string, int> RelationalSchemaObject::GetTableWeight()
300 {
301     return tableWeight_;
302 }
303 
GetTrackerTable(const std::string & tableName) const304 TrackerTable RelationalSchemaObject::GetTrackerTable(const std::string &tableName) const
305 {
306     auto it = trackerTables_.find(tableName);
307     if (it != trackerTables_.end()) {
308         return it->second.GetTrackerTable();
309     }
310     return {};
311 }
312 
ParseFromTrackerSchemaString(const std::string & inSchemaString)313 int RelationalSchemaObject::ParseFromTrackerSchemaString(const std::string &inSchemaString)
314 {
315     JsonObject schemaObj;
316     int errCode = schemaObj.Parse(inSchemaString);
317     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
318         LOGE("[RelationalSchema][Parse] Schema json string parse failed: %d.", errCode);
319         return errCode;
320     }
321 
322     errCode = ParseTrackerSchema(schemaObj);
323     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
324         LOGE("[RelationalSchema][Parse] Parse to tracker schema failed: %d.", errCode);
325         return errCode;
326     }
327 
328     schemaString_ = schemaObj.ToString();
329     return E_OK;
330 }
331 
GetTrackerTables() const332 const TableInfoMap &RelationalSchemaObject::GetTrackerTables() const
333 {
334     return trackerTables_;
335 }
336 
SetReferenceProperty(const std::vector<TableReferenceProperty> & referenceProperty)337 void RelationalSchemaObject::SetReferenceProperty(const std::vector<TableReferenceProperty> &referenceProperty)
338 {
339     referenceProperty_ = referenceProperty;
340     GenerateSchemaString();
341     GenerateReachableRef();
342     GenerateTableInfoReferenced();
343 }
344 
GetReferenceProperty() const345 const std::vector<TableReferenceProperty> &RelationalSchemaObject::GetReferenceProperty() const
346 {
347     return referenceProperty_;
348 }
349 
CompareAgainstSchemaObject(const std::string & inSchemaString,std::map<std::string,int> & cmpRst) const350 int RelationalSchemaObject::CompareAgainstSchemaObject(const std::string &inSchemaString,
351     std::map<std::string, int> &cmpRst) const
352 {
353     return E_OK;
354 }
355 
CompareAgainstSchemaObject(const RelationalSchemaObject & inSchemaObject,std::map<std::string,int> & cmpRst) const356 int RelationalSchemaObject::CompareAgainstSchemaObject(const RelationalSchemaObject &inSchemaObject,
357     std::map<std::string, int> &cmpRst) const
358 {
359     return E_OK;
360 }
361 
362 namespace {
GetMemberFromJsonObject(const JsonObject & inJsonObject,const std::string & fieldName,FieldType expectType,bool isNecessary,FieldValue & fieldValue)363 int GetMemberFromJsonObject(const JsonObject &inJsonObject, const std::string &fieldName, FieldType expectType,
364     bool isNecessary, FieldValue &fieldValue)
365 {
366     if (!inJsonObject.IsFieldPathExist(FieldPath {fieldName})) {
367         if (isNecessary) {
368             LOGE("[RelationalSchema][Parse] Get schema %s not exist. isNecessary: %d", fieldName.c_str(), isNecessary);
369             return -E_SCHEMA_PARSE_FAIL;
370         }
371         return -E_NOT_FOUND;
372     }
373 
374     FieldType fieldType;
375     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {fieldName}, fieldType);
376     if (errCode != E_OK) {
377         LOGE("[RelationalSchema][Parse] Get schema %s fieldType failed: %d.", fieldName.c_str(), errCode);
378         return -E_SCHEMA_PARSE_FAIL;
379     }
380 
381     if (fieldType != expectType) {
382         LOGE("[RelationalSchema][Parse] Expect %s fieldType %d but: %d.", fieldName.c_str(),
383             static_cast<int>(expectType), static_cast<int>(fieldType));
384         return -E_SCHEMA_PARSE_FAIL;
385     }
386 
387     errCode = inJsonObject.GetFieldValueByFieldPath(FieldPath {fieldName}, fieldValue);
388     if (errCode != E_OK) {
389         LOGE("[RelationalSchema][Parse] Get schema %s value failed: %d.", fieldName.c_str(), errCode);
390         return -E_SCHEMA_PARSE_FAIL;
391     }
392     return E_OK;
393 }
394 }
395 
ParseTrackerSchema(const JsonObject & inJsonObject)396 int RelationalSchemaObject::ParseTrackerSchema(const JsonObject &inJsonObject)
397 {
398     FieldType fieldType;
399     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, fieldType);
400     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
401         LOGE("[RelationalSchema][Parse] Get tracker schema TABLES fieldType failed: %d.", errCode);
402         return -E_SCHEMA_PARSE_FAIL;
403     }
404     if (FieldType::LEAF_FIELD_ARRAY != fieldType) { // LCOV_EXCL_BR_LINE
405         LOGE("[RelationalSchema][Parse] Expect tracker TABLES fieldType ARRAY but %s.",
406              SchemaUtils::FieldTypeString(fieldType).c_str());
407         return -E_SCHEMA_PARSE_FAIL;
408     }
409     std::vector<JsonObject> tables;
410     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, tables);
411     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
412         LOGE("[RelationalSchema][Parse] Get tracker schema TABLES value failed: %d.", errCode);
413         return -E_SCHEMA_PARSE_FAIL;
414     }
415     for (const JsonObject &table : tables) {
416         errCode = ParseCheckTrackerTable(table);
417         if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
418             LOGE("[RelationalSchema][Parse] Parse schema TABLES failed: %d.", errCode);
419             return -E_SCHEMA_PARSE_FAIL;
420         }
421     }
422     return E_OK;
423 }
424 
ParseCheckTrackerTable(const JsonObject & inJsonObject)425 int RelationalSchemaObject::ParseCheckTrackerTable(const JsonObject &inJsonObject)
426 {
427     TrackerTable table;
428     int errCode = ParseCheckTrackerTableName(inJsonObject, table);
429     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
430         return errCode;
431     }
432     errCode = ParseCheckTrackerExtendName(inJsonObject, table);
433     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
434         return errCode;
435     }
436     errCode = ParseCheckTrackerName(inJsonObject, table);
437     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
438         return errCode;
439     }
440     trackerTables_[table.GetTableName()].SetTrackerTable(table);
441     return E_OK;
442 }
443 
ParseCheckTrackerTableName(const JsonObject & inJsonObject,TrackerTable & resultTable)444 int RelationalSchemaObject::ParseCheckTrackerTableName(const JsonObject &inJsonObject, TrackerTable &resultTable)
445 {
446     FieldValue fieldValue;
447     int errCode = GetMemberFromJsonObject(inJsonObject, "NAME", FieldType::LEAF_FIELD_STRING,
448         true, fieldValue);
449     if (errCode == E_OK) { // LCOV_EXCL_BR_LINE
450         if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) { // LCOV_EXCL_BR_LINE
451             LOGE("[RelationalSchema][Parse] Invalid characters in table name, err=%d.", errCode);
452             return -E_SCHEMA_PARSE_FAIL;
453         }
454         resultTable.SetTableName(fieldValue.stringValue);
455     }
456     return errCode;
457 }
458 
ParseCheckTrackerExtendName(const JsonObject & inJsonObject,TrackerTable & resultTable)459 int RelationalSchemaObject::ParseCheckTrackerExtendName(const JsonObject &inJsonObject, TrackerTable &resultTable)
460 {
461     FieldValue fieldValue;
462     int errCode = GetMemberFromJsonObject(inJsonObject, "EXTEND_NAME", FieldType::LEAF_FIELD_STRING,
463         true, fieldValue);
464     if (errCode == E_OK) { // LCOV_EXCL_BR_LINE
465         if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) { // LCOV_EXCL_BR_LINE
466             LOGE("[RelationalSchema][Parse] Invalid characters in extend name, err=%d.", errCode);
467             return -E_SCHEMA_PARSE_FAIL;
468         }
469         resultTable.SetExtendName(fieldValue.stringValue);
470     }
471     return errCode;
472 }
473 
ParseCheckTrackerName(const JsonObject & inJsonObject,TrackerTable & resultTable)474 int RelationalSchemaObject::ParseCheckTrackerName(const JsonObject &inJsonObject, TrackerTable &resultTable)
475 {
476     FieldType fieldType;
477     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {"TRACKER_NAMES"}, fieldType);
478     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
479         LOGE("[RelationalSchema][Parse] Get tracker col names fieldType failed: %d.", errCode);
480         return -E_SCHEMA_PARSE_FAIL;
481     }
482     if (FieldType::LEAF_FIELD_ARRAY != fieldType) { // LCOV_EXCL_BR_LINE
483         LOGE("[RelationalSchema][Parse] Expect tracker TABLES fieldType ARRAY but %s.",
484             SchemaUtils::FieldTypeString(fieldType).c_str());
485         return -E_SCHEMA_PARSE_FAIL;
486     }
487     std::vector<JsonObject> fieldValues;
488     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath{"TRACKER_NAMES"}, fieldValues);
489     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
490         LOGE("[RelationalSchema][Parse] Get tracker col names value failed: %d.", errCode);
491         return -E_SCHEMA_PARSE_FAIL;
492     }
493     std::set<std::string> colNames;
494     for (const JsonObject &value : fieldValues) {
495         FieldValue fieldValue;
496         errCode = value.GetFieldValueByFieldPath(FieldPath {}, fieldValue);
497         if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
498             LOGE("[RelationalSchema][Parse] Parse tracker col name failed: %d.", errCode);
499             return -E_SCHEMA_PARSE_FAIL;
500         }
501         colNames.insert(fieldValue.stringValue);
502     }
503     resultTable.SetTrackerNames(colNames);
504     return errCode;
505 }
506 
ParseRelationalSchema(const JsonObject & inJsonObject)507 int RelationalSchemaObject::ParseRelationalSchema(const JsonObject &inJsonObject)
508 {
509     int errCode = ParseCheckSchemaVersion(inJsonObject);
510     if (errCode != E_OK) {
511         return errCode;
512     }
513     errCode = ParseCheckSchemaType(inJsonObject);
514     if (errCode != E_OK) {
515         return errCode;
516     }
517     errCode = ParseCheckTableMode(inJsonObject);
518     if (errCode != E_OK) {
519         return errCode;
520     }
521     errCode = ParseCheckSchemaTableDefine(inJsonObject);
522     if (errCode != E_OK) {
523         return errCode;
524     }
525     return ParseCheckReferenceProperty(inJsonObject);
526 }
527 
528 namespace {
IsSchemaVersionValid(const std::string & version)529 inline bool IsSchemaVersionValid(const std::string &version)
530 {
531     std::string stripedVersion = SchemaUtils::Strip(version);
532     return stripedVersion == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2 ||
533         stripedVersion == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2_1;
534 }
535 }
536 
ParseCheckSchemaVersion(const JsonObject & inJsonObject)537 int RelationalSchemaObject::ParseCheckSchemaVersion(const JsonObject &inJsonObject)
538 {
539     FieldValue fieldValue;
540     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_SCHEMA_VERSION,
541         FieldType::LEAF_FIELD_STRING, true, fieldValue);
542     if (errCode != E_OK) {
543         return errCode;
544     }
545 
546     if (IsSchemaVersionValid(fieldValue.stringValue)) {
547         schemaVersion_ = fieldValue.stringValue;
548         return E_OK;
549     }
550 
551     LOGE("[RelationalSchema][Parse] Unexpected SCHEMA_VERSION=%s.", fieldValue.stringValue.c_str());
552     return -E_SCHEMA_PARSE_FAIL;
553 }
554 
ParseCheckSchemaType(const JsonObject & inJsonObject)555 int RelationalSchemaObject::ParseCheckSchemaType(const JsonObject &inJsonObject)
556 {
557     FieldValue fieldValue;
558     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_SCHEMA_TYPE,
559         FieldType::LEAF_FIELD_STRING, true, fieldValue);
560     if (errCode != E_OK) {
561         return errCode;
562     }
563 
564     if (SchemaUtils::Strip(fieldValue.stringValue) != SchemaConstant::KEYWORD_TYPE_RELATIVE) {
565         LOGE("[RelationalSchema][Parse] Unexpected SCHEMA_TYPE=%s.", fieldValue.stringValue.c_str());
566         return -E_SCHEMA_PARSE_FAIL;
567     }
568     schemaType_ = SchemaType::RELATIVE;
569     return E_OK;
570 }
571 
572 namespace {
IsTableModeValid(const std::string & mode)573 inline bool IsTableModeValid(const std::string &mode)
574 {
575     std::string stripedMode = SchemaUtils::Strip(mode);
576     return stripedMode == SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE ||
577         stripedMode == SchemaConstant::KEYWORD_TABLE_COLLABORATION;
578 }
579 }
580 
ParseCheckTableMode(const JsonObject & inJsonObject)581 int RelationalSchemaObject::ParseCheckTableMode(const JsonObject &inJsonObject)
582 {
583     if (schemaVersion_ == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2) {
584         return E_OK; // version 2 has no table mode, no parsing required
585     }
586 
587     FieldValue fieldValue;
588     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_TABLE_MODE,
589         FieldType::LEAF_FIELD_STRING, true, fieldValue);
590     if (errCode != E_OK) {
591         return errCode;
592     }
593 
594     if (!IsTableModeValid(fieldValue.stringValue)) {
595         LOGE("[RelationalSchema][Parse] Unexpected TABLE_MODE=%s.", fieldValue.stringValue.c_str());
596         return -E_SCHEMA_PARSE_FAIL;
597     }
598 
599     tableMode_ = SchemaUtils::Strip(fieldValue.stringValue) == SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE ?
600         DistributedDB::SPLIT_BY_DEVICE : DistributedTableMode::COLLABORATION;
601     return E_OK;
602 }
603 
ParseCheckSchemaTableDefine(const JsonObject & inJsonObject)604 int RelationalSchemaObject::ParseCheckSchemaTableDefine(const JsonObject &inJsonObject)
605 {
606     FieldType fieldType;
607     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, fieldType);
608     if (errCode != E_OK) {
609         LOGE("[RelationalSchema][Parse] Get schema TABLES fieldType failed: %d.", errCode);
610         return -E_SCHEMA_PARSE_FAIL;
611     }
612     if (FieldType::LEAF_FIELD_ARRAY != fieldType) {
613         LOGE("[RelationalSchema][Parse] Expect TABLES fieldType ARRAY but %s.",
614             SchemaUtils::FieldTypeString(fieldType).c_str());
615         return -E_SCHEMA_PARSE_FAIL;
616     }
617     std::vector<JsonObject> tables;
618     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, tables);
619     if (errCode != E_OK) {
620         LOGE("[RelationalSchema][Parse] Get schema TABLES value failed: %d.", errCode);
621         return -E_SCHEMA_PARSE_FAIL;
622     }
623     for (const JsonObject &table : tables) {
624         errCode = ParseCheckTableInfo(table);
625         if (errCode != E_OK) {
626             LOGE("[RelationalSchema][Parse] Parse schema TABLES failed: %d.", errCode);
627             return -E_SCHEMA_PARSE_FAIL;
628         }
629     }
630     return E_OK;
631 }
632 
ParseCheckTableInfo(const JsonObject & inJsonObject)633 int RelationalSchemaObject::ParseCheckTableInfo(const JsonObject &inJsonObject)
634 {
635     TableInfo resultTable;
636     int errCode = ParseCheckTableName(inJsonObject, resultTable);
637     if (errCode != E_OK) {
638         return errCode;
639     }
640     errCode = ParseCheckTableDefine(inJsonObject, resultTable);
641     if (errCode != E_OK) {
642         return errCode;
643     }
644     errCode = ParseCheckOriginTableName(inJsonObject, resultTable);
645     if (errCode != E_OK) {
646         return errCode;
647     }
648     errCode = ParseCheckTableAutoInc(inJsonObject, resultTable);
649     if (errCode != E_OK) {
650         return errCode;
651     }
652     errCode = ParseCheckSharedTableMark(inJsonObject, resultTable);
653     if (errCode != E_OK) {
654         return errCode;
655     }
656     errCode = ParseCheckTablePrimaryKey(inJsonObject, resultTable);
657     if (errCode != E_OK) {
658         return errCode;
659     }
660 
661     errCode = ParseCheckTableSyncType(inJsonObject, resultTable);
662     if (errCode != E_OK) {
663         return errCode;
664     }
665     errCode = ParseCheckTableIndex(inJsonObject, resultTable);
666     if (errCode != E_OK) {
667         return errCode;
668     }
669     errCode = ParseCheckTableUnique(inJsonObject, resultTable);
670     if (errCode != E_OK) {
671         return errCode;
672     }
673     tables_[resultTable.GetTableName()] = resultTable;
674     return E_OK;
675 }
676 
ParseCheckTableName(const JsonObject & inJsonObject,TableInfo & resultTable)677 int RelationalSchemaObject::ParseCheckTableName(const JsonObject &inJsonObject, TableInfo &resultTable)
678 {
679     FieldValue fieldValue;
680     int errCode = GetMemberFromJsonObject(inJsonObject, "NAME", FieldType::LEAF_FIELD_STRING,
681         true, fieldValue);
682     if (errCode == E_OK) {
683         if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
684             LOGE("[RelationalSchema][Parse] Invalid characters in table name, err=%d.", errCode);
685             return -E_SCHEMA_PARSE_FAIL;
686         }
687         resultTable.SetTableName(fieldValue.stringValue);
688     }
689     return errCode;
690 }
691 
ParseCheckTableDefine(const JsonObject & inJsonObject,TableInfo & resultTable)692 int RelationalSchemaObject::ParseCheckTableDefine(const JsonObject &inJsonObject, TableInfo &resultTable)
693 {
694     std::map<FieldPath, FieldType> tableFields;
695     int errCode = inJsonObject.GetSubFieldPathAndType(FieldPath {"DEFINE"}, tableFields);
696     if (errCode != E_OK) {
697         LOGE("[RelationalSchema][Parse] Get schema TABLES DEFINE failed: %d.", errCode);
698         return -E_SCHEMA_PARSE_FAIL;
699     }
700 
701     for (const auto &field : tableFields) {
702         if (field.second != FieldType::INTERNAL_FIELD_OBJECT) {
703             LOGE("[RelationalSchema][Parse] Expect schema TABLES DEFINE fieldType INTERNAL OBJECT but : %s.",
704                 SchemaUtils::FieldTypeString(field.second).c_str());
705             return -E_SCHEMA_PARSE_FAIL;
706         }
707 
708         JsonObject fieldObj;
709         errCode = inJsonObject.GetObjectByFieldPath(field.first, fieldObj);
710         if (errCode != E_OK) {
711             LOGE("[RelationalSchema][Parse] Get table field object failed. %d", errCode);
712             return errCode;
713         }
714 
715         if (!DBCommon::CheckIsAlnumOrUnderscore(field.first[1])) {
716             LOGE("[RelationalSchema][Parse] Invalid characters in field name, err=%d.", errCode);
717             return -E_SCHEMA_PARSE_FAIL;
718         }
719 
720         FieldInfo fieldInfo;
721         fieldInfo.SetFieldName(field.first[1]); // 1 : table name element in path
722         errCode = ParseCheckTableFieldInfo(fieldObj, field.first, fieldInfo);
723         if (errCode != E_OK) {
724             LOGE("[RelationalSchema][Parse] Parse table field info failed. %d", errCode);
725             return -E_SCHEMA_PARSE_FAIL;
726         }
727         resultTable.AddField(fieldInfo);
728     }
729     return E_OK;
730 }
731 
ParseCheckTableFieldInfo(const JsonObject & inJsonObject,const FieldPath & path,FieldInfo & field)732 int RelationalSchemaObject::ParseCheckTableFieldInfo(const JsonObject &inJsonObject, const FieldPath &path,
733     FieldInfo &field)
734 {
735     FieldValue fieldValue;
736     int errCode = GetMemberFromJsonObject(inJsonObject, "COLUMN_ID", FieldType::LEAF_FIELD_INTEGER, true, fieldValue);
737     if (errCode != E_OK) {
738         return errCode;
739     }
740     field.SetColumnId(fieldValue.integerValue);
741 
742     errCode = GetMemberFromJsonObject(inJsonObject, "TYPE", FieldType::LEAF_FIELD_STRING, true, fieldValue);
743     if (errCode != E_OK) {
744         return errCode;
745     }
746     field.SetDataType(fieldValue.stringValue);
747 
748     errCode = GetMemberFromJsonObject(inJsonObject, "NOT_NULL", FieldType::LEAF_FIELD_BOOL, true, fieldValue);
749     if (errCode != E_OK) {
750         return errCode;
751     }
752     field.SetNotNull(fieldValue.boolValue);
753 
754     errCode = GetMemberFromJsonObject(inJsonObject, "DEFAULT", FieldType::LEAF_FIELD_STRING, false, fieldValue);
755     if (errCode == E_OK) {
756         field.SetDefaultValue(fieldValue.stringValue);
757     } else if (errCode != -E_NOT_FOUND) {
758         return errCode;
759     }
760 
761     return E_OK;
762 }
763 
ParseCheckOriginTableName(const JsonObject & inJsonObject,TableInfo & resultTable)764 int RelationalSchemaObject::ParseCheckOriginTableName(const JsonObject &inJsonObject, TableInfo &resultTable)
765 {
766     FieldValue fieldValue;
767     int errCode = GetMemberFromJsonObject(inJsonObject, "ORIGINTABLENAME", FieldType::LEAF_FIELD_STRING,
768         false, fieldValue);
769     if (errCode == E_OK) {
770         if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
771             LOGE("[RelationalSchema][Parse] Invalid characters in origin table name, err=%d.", errCode);
772             return -E_SCHEMA_PARSE_FAIL;
773         }
774         resultTable.SetOriginTableName(fieldValue.stringValue);
775     } else if (errCode != -E_NOT_FOUND) {
776         LOGE("[RelationalSchema][Parse] Get schema orgin table name failed: %d", errCode);
777         return errCode;
778     }
779     return E_OK;
780 }
781 
ParseCheckTableAutoInc(const JsonObject & inJsonObject,TableInfo & resultTable)782 int RelationalSchemaObject::ParseCheckTableAutoInc(const JsonObject &inJsonObject, TableInfo &resultTable)
783 {
784     FieldValue fieldValue;
785     int errCode = GetMemberFromJsonObject(inJsonObject, "AUTOINCREMENT", FieldType::LEAF_FIELD_BOOL, false, fieldValue);
786     if (errCode == E_OK) {
787         resultTable.SetAutoIncrement(fieldValue.boolValue);
788     } else if (errCode != -E_NOT_FOUND) {
789         return errCode;
790     }
791     return E_OK;
792 }
793 
ParseCheckSharedTableMark(const JsonObject & inJsonObject,TableInfo & resultTable)794 int RelationalSchemaObject::ParseCheckSharedTableMark(const JsonObject &inJsonObject, TableInfo &resultTable)
795 {
796     FieldValue fieldValue;
797     int errCode = GetMemberFromJsonObject(inJsonObject, "SHAREDTABLEMARK", FieldType::LEAF_FIELD_BOOL, false,
798         fieldValue);
799     if (errCode == E_OK) {
800         resultTable.SetSharedTableMark(fieldValue.boolValue);
801     } else if (errCode != -E_NOT_FOUND) {
802         return errCode;
803     }
804     return E_OK;
805 }
806 
ParseCheckTablePrimaryKey(const JsonObject & inJsonObject,TableInfo & resultTable)807 int RelationalSchemaObject::ParseCheckTablePrimaryKey(const JsonObject &inJsonObject, TableInfo &resultTable)
808 {
809     if (!inJsonObject.IsFieldPathExist(FieldPath {"PRIMARY_KEY"})) {
810         return E_OK;
811     }
812 
813     FieldType type;
814     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {"PRIMARY_KEY"}, type);
815     if (errCode != E_OK) {
816         return errCode;
817     }
818 
819     if (type == FieldType::LEAF_FIELD_STRING) { // Compatible with schema 2.0
820         FieldValue fieldValue;
821         errCode = GetMemberFromJsonObject(inJsonObject, "PRIMARY_KEY", FieldType::LEAF_FIELD_STRING, false, fieldValue);
822         if (errCode == E_OK) {
823             resultTable.SetPrimaryKey(fieldValue.stringValue, 1);
824         }
825     } else if (type == FieldType::LEAF_FIELD_ARRAY) {
826         CompositeFields multiPrimaryKey;
827         errCode = inJsonObject.GetStringArrayByFieldPath(FieldPath {"PRIMARY_KEY"}, multiPrimaryKey);
828         if (errCode == E_OK) {
829             int index = 1; // primary key index
830             for (const auto &item : multiPrimaryKey) {
831                 resultTable.SetPrimaryKey(item, index++);
832             }
833         }
834     } else {
835         errCode = -E_SCHEMA_PARSE_FAIL;
836     }
837     return errCode;
838 }
839 
ParseCheckReferenceProperty(const JsonObject & inJsonObject)840 int RelationalSchemaObject::ParseCheckReferenceProperty(const JsonObject &inJsonObject)
841 {
842     if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::REFERENCE_PROPERTY})) {
843         return E_OK;
844     }
845 
846     FieldType fieldType;
847     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::REFERENCE_PROPERTY}, fieldType);
848     if (errCode != E_OK) {
849         LOGE("[RelationalSchema][Parse] Get schema REFERENCE_PROPERTY fieldType failed: %d.", errCode);
850         return -E_SCHEMA_PARSE_FAIL;
851     }
852     if (FieldType::LEAF_FIELD_ARRAY != fieldType) {
853         LOGE("[RelationalSchema][Parse] Expect TABLES REFERENCE_PROPERTY ARRAY but %s.",
854              SchemaUtils::FieldTypeString(fieldType).c_str());
855         return -E_SCHEMA_PARSE_FAIL;
856     }
857     std::vector<JsonObject> references;
858     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath{SchemaConstant::REFERENCE_PROPERTY}, references);
859     if (errCode != E_OK) {
860         LOGE("[RelationalSchema][Parse] Get schema REFERENCE_PROPERTY value failed: %d.", errCode);
861         return -E_SCHEMA_PARSE_FAIL;
862     }
863     for (const JsonObject &reference : references) {
864         errCode = ParseCheckReference(reference);
865         if (errCode != E_OK) {
866             LOGE("[RelationalSchema][Parse] Parse schema reference failed: %d.", errCode);
867             return -E_SCHEMA_PARSE_FAIL;
868         }
869     }
870     return E_OK;
871 }
872 
ParseCheckReference(const JsonObject & inJsonObject)873 int RelationalSchemaObject::ParseCheckReference(const JsonObject &inJsonObject)
874 {
875     FieldValue fieldValue;
876     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::SOURCE_TABLE_NAME, FieldType::LEAF_FIELD_STRING,
877         true, fieldValue);
878     if (errCode != E_OK) {
879         LOGE("[RelationalSchema][Parse] Get source table name failed, errCode = %d", errCode);
880         return errCode;
881     }
882     if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
883         LOGE("[RelationalSchema][Parse] Invalid characters in source table name.");
884         return -E_SCHEMA_PARSE_FAIL;
885     }
886 
887     TableReferenceProperty referenceProperty;
888     referenceProperty.sourceTableName = fieldValue.stringValue;
889     errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::TARGET_TABLE_NAME, FieldType::LEAF_FIELD_STRING,
890         true, fieldValue);
891     if (errCode != E_OK) {
892         LOGE("[RelationalSchema][Parse] Get target table name failed, errCode = %d", errCode);
893         return errCode;
894     }
895     if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
896         LOGE("[RelationalSchema][Parse] Invalid characters in target table name.");
897         return -E_SCHEMA_PARSE_FAIL;
898     }
899 
900     referenceProperty.targetTableName = fieldValue.stringValue;
901     errCode = ParseCheckReferenceColumns(inJsonObject, referenceProperty);
902     if (errCode != E_OK) {
903         LOGE("[RelationalSchema][Parse] Parse reference columns failed, errCode = %d", errCode);
904         return errCode;
905     }
906     referenceProperty_.emplace_back(referenceProperty);
907     tables_[referenceProperty.targetTableName].AddTableReferenceProperty(referenceProperty);
908     return E_OK;
909 }
910 
ParseCheckReferenceColumns(const JsonObject & inJsonObject,TableReferenceProperty & tableReferenceProperty)911 int RelationalSchemaObject::ParseCheckReferenceColumns(const JsonObject &inJsonObject,
912     TableReferenceProperty &tableReferenceProperty)
913 {
914     // parse columns
915     FieldType fieldType;
916     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::COLUMNS}, fieldType);
917     if (errCode != E_OK) {
918         LOGE("[RelationalSchema][Parse] Get schema reference COLUMNS fieldType failed: %d.", errCode);
919         return -E_SCHEMA_PARSE_FAIL;
920     }
921     if (FieldType::LEAF_FIELD_ARRAY != fieldType) {
922         LOGE("[RelationalSchema][Parse] Expect reference COLUMNS ARRAY but %s.",
923              SchemaUtils::FieldTypeString(fieldType).c_str());
924         return -E_SCHEMA_PARSE_FAIL;
925     }
926     std::vector<JsonObject> columns;
927     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath{SchemaConstant::COLUMNS}, columns);
928     if (errCode != E_OK) {
929         LOGE("[RelationalSchema][Parse] Get schema reference COLUMNS value failed: %d.", errCode);
930         return -E_SCHEMA_PARSE_FAIL;
931     }
932 
933     for (const JsonObject &column : columns) {
934         errCode = ParseCheckReferenceColumn(column, tableReferenceProperty);
935         if (errCode != E_OK) {
936             LOGE("[RelationalSchema][Parse] Parse reference one COLUMN failed: %d.", errCode);
937             return -E_SCHEMA_PARSE_FAIL;
938         }
939     }
940     return E_OK;
941 }
942 
ParseCheckReferenceColumn(const JsonObject & inJsonObject,TableReferenceProperty & tableReferenceProperty)943 int RelationalSchemaObject::ParseCheckReferenceColumn(const JsonObject &inJsonObject,
944     TableReferenceProperty &tableReferenceProperty)
945 {
946     FieldValue fieldValue;
947     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::SOURCE_COL, FieldType::LEAF_FIELD_STRING,
948         true, fieldValue);
949     if (errCode != E_OK) {
950         LOGE("[RelationalSchema][Parse] Get source col failed, errCode = %d", errCode);
951         return errCode;
952     }
953     if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
954         LOGE("[RelationalSchema][Parse] Invalid characters in source col name.");
955         return -E_SCHEMA_PARSE_FAIL;
956     }
957 
958     std::string sourceCol = fieldValue.stringValue;
959     errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::TARGET_COL, FieldType::LEAF_FIELD_STRING,
960         true, fieldValue);
961     if (errCode != E_OK) {
962         LOGE("[RelationalSchema][Parse] Get target col failed, errCode = %d", errCode);
963         return errCode;
964     }
965     if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
966         LOGE("[RelationalSchema][Parse] Invalid characters in target col name.");
967         return -E_SCHEMA_PARSE_FAIL;
968     }
969     std::string targetCol = fieldValue.stringValue;
970     tableReferenceProperty.columns[sourceCol] = targetCol;
971     return E_OK;
972 }
973 
ParseCheckTableSyncType(const JsonObject & inJsonObject,TableInfo & resultTable)974 int RelationalSchemaObject::ParseCheckTableSyncType(const JsonObject &inJsonObject, TableInfo &resultTable)
975 {
976     FieldValue fieldValue;
977     int errCode = GetMemberFromJsonObject(inJsonObject, "TABLE_SYNC_TYPE", FieldType::LEAF_FIELD_INTEGER,
978         false, fieldValue);
979     if (errCode == E_OK) {
980         resultTable.SetTableSyncType(static_cast<TableSyncType>(fieldValue.integerValue));
981     } else if (errCode != -E_NOT_FOUND) {
982         return errCode;
983     }
984     return E_OK; // if there is no "TABLE_SYNC_TYPE" filed, the table_sync_type is DEVICE_COOPERATION
985 }
986 
ParseCheckTableIndex(const JsonObject & inJsonObject,TableInfo & resultTable)987 int RelationalSchemaObject::ParseCheckTableIndex(const JsonObject &inJsonObject, TableInfo &resultTable)
988 {
989     if (!inJsonObject.IsFieldPathExist(FieldPath {"INDEX"})) { // INDEX is not necessary
990         return E_OK;
991     }
992     std::map<FieldPath, FieldType> tableFields;
993     int errCode = inJsonObject.GetSubFieldPathAndType(FieldPath {"INDEX"}, tableFields);
994     if (errCode != E_OK) {
995         LOGE("[RelationalSchema][Parse] Get schema TABLES INDEX failed: %d.", errCode);
996         return -E_SCHEMA_PARSE_FAIL;
997     }
998 
999     for (const auto &field : tableFields) {
1000         if (field.second != FieldType::LEAF_FIELD_ARRAY) {
1001             LOGE("[RelationalSchema][Parse] Expect schema TABLES INDEX fieldType ARRAY but : %s.",
1002                 SchemaUtils::FieldTypeString(field.second).c_str());
1003             return -E_SCHEMA_PARSE_FAIL;
1004         }
1005         CompositeFields indexDefine;
1006         errCode = inJsonObject.GetStringArrayByFieldPath(field.first, indexDefine);
1007         if (errCode != E_OK) {
1008             LOGE("[RelationalSchema][Parse] Get schema TABLES INDEX field value failed: %d.", errCode);
1009             return -E_SCHEMA_PARSE_FAIL;
1010         }
1011         resultTable.AddIndexDefine(field.first[1], indexDefine); // 1 : second element in path
1012     }
1013     return E_OK;
1014 }
1015 
ParseCheckTableUnique(const JsonObject & inJsonObject,TableInfo & resultTable)1016 int RelationalSchemaObject::ParseCheckTableUnique(const JsonObject &inJsonObject, TableInfo &resultTable)
1017 {
1018     if (!inJsonObject.IsFieldPathExist(FieldPath {"UNIQUE"})) { // UNIQUE is not necessary
1019         return E_OK;
1020     }
1021 
1022     std::vector<CompositeFields> uniques;
1023     int errCode = inJsonObject.GetArrayContentOfStringOrStringArray(FieldPath {"UNIQUE"}, uniques);
1024     if (errCode != E_OK) {
1025         LOGE("[RelationalSchema][Parse] Get schema TABLES UNIQUE failed: %d.", errCode);
1026         return -E_SCHEMA_PARSE_FAIL;
1027     }
1028     resultTable.SetUniqueDefine(uniques);
1029     return E_OK;
1030 }
1031 
GenerateReachableRef()1032 void RelationalSchemaObject::GenerateReachableRef()
1033 {
1034     reachableReference_.clear();
1035     tableWeight_.clear();
1036     std::set<std::string> startNodes; // such as {a->b->c,d->e}, record {a,d}
1037     std::map<std::string, std::set<std::string>> nextNodes; // such as {a->b->c}, record {{a,{b}}, {b, {c}}}
1038     // we need to record all table reachable reference here
1039     for (const auto &tableRef : referenceProperty_) {
1040         // they also can reach target
1041         RefreshReachableRef(tableRef);
1042         startNodes.insert(tableRef.sourceTableName);
1043         startNodes.erase(tableRef.targetTableName);
1044         nextNodes[tableRef.sourceTableName].insert(tableRef.targetTableName);
1045     }
1046     CalculateTableWeight(startNodes, nextNodes);
1047 }
1048 
GenerateTableInfoReferenced()1049 void RelationalSchemaObject::GenerateTableInfoReferenced()
1050 {
1051     for (auto &table : tables_) {
1052         table.second.SetSourceTableReference({});
1053     }
1054     for (const auto &reference : referenceProperty_) {
1055         tables_[reference.targetTableName].AddTableReferenceProperty(reference);
1056     }
1057 }
1058 
RefreshReachableRef(const TableReferenceProperty & referenceProperty)1059 void RelationalSchemaObject::RefreshReachableRef(const TableReferenceProperty &referenceProperty)
1060 {
1061     // such as source:A target:B
1062     std::set<std::string> recordSources;
1063     // find all node which can reach source as collection recordSources
1064     for (const auto &[start, end] : reachableReference_) {
1065         auto node = end.find(referenceProperty.sourceTableName);
1066         // find the node and it can reach
1067         if (node != end.end() && node->second) {
1068             recordSources.insert(start);
1069         }
1070     }
1071     recordSources.insert(referenceProperty.sourceTableName);
1072     // find all node which start with target as collection recordTargets
1073     std::set<std::string> recordTargets;
1074     for (auto &[entry, reach] : reachableReference_[referenceProperty.targetTableName]) {
1075         if (reach) {
1076             recordTargets.insert(entry);
1077         }
1078     }
1079     recordTargets.insert(referenceProperty.targetTableName);
1080     for (const auto &source : recordSources) {
1081         for (const auto &target : recordTargets) {
1082             reachableReference_[source][target] = true;
1083         }
1084     }
1085 }
1086 
CalculateTableWeight(const std::set<std::string> & startNodes,const std::map<std::string,std::set<std::string>> & nextNodes)1087 void RelationalSchemaObject::CalculateTableWeight(const std::set<std::string> &startNodes,
1088     const std::map<std::string, std::set<std::string>> &nextNodes)
1089 {
1090     // record the max long path as table weight
1091     for (const auto &start : startNodes) {
1092         std::map<std::string, int> tmpTableWeight;
1093         tmpTableWeight[start] = 1;
1094         if (nextNodes.find(start) == nextNodes.end()) {
1095             continue;
1096         }
1097         std::list<std::string> queue;
1098         for (const auto &target : nextNodes.at(start)) {
1099             queue.push_back(target);
1100             tmpTableWeight[target] = 2; // this path contain 2 nodes
1101         }
1102         // bfs all the path which start from startNodes
1103         while (!queue.empty()) {
1104             auto node = queue.front();
1105             queue.pop_front();
1106             if (nextNodes.find(node) == nextNodes.end()) {
1107                 continue;
1108             }
1109             for (const auto &item : nextNodes.at(node)) {
1110                 queue.push_back(item);
1111                 tmpTableWeight[item] = std::max(tmpTableWeight[item], tmpTableWeight[node] + 1);
1112             }
1113         }
1114         for (const auto &[table, weight] : tmpTableWeight) {
1115             tableWeight_[table] = std::max(tableWeight_[table], weight);
1116         }
1117     }
1118 }
1119 }
1120 #endif