• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #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_ += GetDistributedSchemaString();
93     schemaString_ += "}";
94 }
95 
AddRelationalTable(const TableInfo & table)96 void RelationalSchemaObject::AddRelationalTable(const TableInfo &table)
97 {
98     tables_[table.GetTableName()] = table;
99     isValid_ = true;
100     if (table.GetPrimaryKey().size() > 1 && table.GetTableSyncType() != CLOUD_COOPERATION) {
101         // Table with composite primary keys
102         // Composite primary keys are supported since version 2.1
103         schemaVersion_ = SchemaConstant::SCHEMA_CURRENT_VERSION;
104     }
105     GenerateSchemaString();
106 }
107 
RemoveRelationalTable(const std::string & tableName)108 void RelationalSchemaObject::RemoveRelationalTable(const std::string &tableName)
109 {
110     tables_.erase(tableName);
111     GenerateSchemaString();
112 }
113 
GetTables() const114 const TableInfoMap &RelationalSchemaObject::GetTables() const
115 {
116     return tables_;
117 }
118 
GetTableNames() const119 std::vector<std::string> RelationalSchemaObject::GetTableNames() const
120 {
121     std::vector<std::string> tableNames;
122     for (const auto &it : tables_) {
123         tableNames.emplace_back(it.first);
124     }
125     return tableNames;
126 }
127 
GetTable(const std::string & tableName) const128 TableInfo RelationalSchemaObject::GetTable(const std::string &tableName) const
129 {
130     auto it = tables_.find(tableName);
131     if (it != tables_.end()) {
132         return it->second;
133     }
134     return {};
135 }
136 
GetSchemaVersion() const137 std::string RelationalSchemaObject::GetSchemaVersion() const
138 {
139     return schemaVersion_;
140 }
141 
GetTableMode() const142 DistributedTableMode RelationalSchemaObject::GetTableMode() const
143 {
144     return tableMode_;
145 }
146 
SetTableMode(DistributedTableMode mode)147 void RelationalSchemaObject::SetTableMode(DistributedTableMode mode)
148 {
149     tableMode_ = mode;
150     if (tableMode_ == DistributedTableMode::COLLABORATION) {
151         schemaVersion_ = SchemaConstant::SCHEMA_CURRENT_VERSION;
152     }
153     GenerateSchemaString();
154 }
155 
InsertTrackerSchema(const TrackerSchema & schema)156 void RelationalSchemaObject::InsertTrackerSchema(const TrackerSchema &schema)
157 {
158     TrackerTable table;
159     table.Init(schema);
160     trackerTables_[schema.tableName].SetTrackerTable(table);
161     GenerateTrackerSchemaString();
162 }
163 
RemoveTrackerSchema(const TrackerSchema & schema)164 void RelationalSchemaObject::RemoveTrackerSchema(const TrackerSchema &schema)
165 {
166     trackerTables_.erase(schema.tableName);
167     GenerateTrackerSchemaString();
168 }
169 
GenerateTrackerSchemaString()170 void RelationalSchemaObject::GenerateTrackerSchemaString()
171 {
172     schemaString_ = {};
173     schemaString_ += "{";
174     schemaString_ += R"("SCHEMA_TYPE":"TRACKER",)";
175     schemaString_ += R"("TABLES":[)";
176     for (auto it = trackerTables_.begin(); it != trackerTables_.end(); it++) {
177         if (it != trackerTables_.begin()) {
178             schemaString_ += ",";
179         }
180         schemaString_ += it->second.GetTrackerTable().ToString();
181     }
182     schemaString_ += R"(])";
183     schemaString_ += "}";
184 }
185 
GetReferencePropertyString()186 std::string RelationalSchemaObject::GetReferencePropertyString()
187 {
188     std::string res;
189     if (!referenceProperty_.empty()) {
190         res += R"(,"REFERENCE_PROPERTY":[)";
191         for (const auto &reference : referenceProperty_) {
192             res += GetOneReferenceString(reference) + ",";
193         }
194         res.pop_back();
195         res += R"(])";
196     }
197     return res;
198 }
199 
GetOneReferenceString(const TableReferenceProperty & reference)200 std::string RelationalSchemaObject::GetOneReferenceString(const TableReferenceProperty &reference)
201 {
202     std::string res = R"({"SOURCE_TABLE_NAME":")";
203     res += reference.sourceTableName;
204     res += R"(","TARGET_TABLE_NAME":")";
205     res += reference.targetTableName;
206     res += R"(","COLUMNS":[)";
207     for (const auto &item : reference.columns) {
208         res += R"({"SOURCE_COL":")";
209         res += item.first;
210         res += R"(","TARGET_COL":")";
211         res += item.second;
212         res += R"("},)";
213     }
214     res.pop_back();
215     res += R"(]})";
216     return res;
217 }
218 
ColumnsCompare(const std::map<std::string,std::string> & left,const std::map<std::string,std::string> & right)219 static bool ColumnsCompare(const std::map<std::string, std::string> &left,
220     const std::map<std::string, std::string> &right)
221 {
222     if (left.size() != right.size()) {
223         LOGE("[ColumnsCompare] column size not equal");
224         return false;
225     }
226     std::map<std::string, std::string>::const_iterator leftIt = left.begin();
227     std::map<std::string, std::string>::const_iterator rightIt = right.begin();
228     for (; leftIt != left.end() && rightIt != right.end(); leftIt++, rightIt++) {
229         if (strcasecmp(leftIt->first.c_str(), rightIt->first.c_str()) != 0 ||
230             strcasecmp(leftIt->second.c_str(), rightIt->second.c_str()) != 0) {
231             LOGE("[ColumnsCompare] column not equal");
232             return false;
233         }
234     }
235     return true;
236 }
237 
ReferenceCompare(const TableReferenceProperty & left,const TableReferenceProperty & right)238 static bool ReferenceCompare(const TableReferenceProperty &left, const TableReferenceProperty &right)
239 {
240     if (strcasecmp(left.sourceTableName.c_str(), right.sourceTableName.c_str()) == 0 &&
241         strcasecmp(left.targetTableName.c_str(), right.targetTableName.c_str()) == 0 &&
242         ColumnsCompare(left.columns, right.columns)) {
243         return true;
244     }
245     return false;
246 }
247 
PropertyCompare(const std::vector<TableReferenceProperty> & left,const std::vector<TableReferenceProperty> & right,std::set<std::string> & changeTables)248 static void PropertyCompare(const std::vector<TableReferenceProperty> &left,
249     const std::vector<TableReferenceProperty> &right, std::set<std::string> &changeTables)
250 {
251     for (const auto &reference : left) {
252         bool found = false;
253         for (const auto &otherRef : right) {
254             if (ReferenceCompare(reference, otherRef)) {
255                 found = true;
256                 break;
257             }
258         }
259         if (!found) {
260             changeTables.insert(reference.sourceTableName);
261             changeTables.insert(reference.targetTableName);
262         }
263     }
264 }
265 
GetSharedTableForChangeTable(std::set<std::string> & changeTables) const266 std::set<std::string> RelationalSchemaObject::GetSharedTableForChangeTable(std::set<std::string> &changeTables) const
267 {
268     std::set<std::string> res;
269     TableInfoMap tableInfos = GetTables();
270     for (const auto &changeName : changeTables) {
271         for (const auto &item : tableInfos) {
272             if (item.second.GetSharedTableMark() &&
273                 (strcasecmp(item.second.GetOriginTableName().c_str(), changeName.c_str()) == 0)) {
274                 res.insert(item.second.GetTableName()); // get shared table name
275             }
276         }
277     }
278     return res;
279 }
280 
CompareReferenceProperty(const std::vector<TableReferenceProperty> & others,bool & isRefNotSet) const281 std::set<std::string> RelationalSchemaObject::CompareReferenceProperty(
282     const std::vector<TableReferenceProperty> &others, bool &isRefNotSet) const
283 {
284     std::set<std::string> changeTables;
285     isRefNotSet = referenceProperty_.empty();
286     PropertyCompare(referenceProperty_, others, changeTables);
287     PropertyCompare(others, referenceProperty_, changeTables);
288     if (!changeTables.empty()) { // get shared tables
289         std::set<std::string> sharedTables = GetSharedTableForChangeTable(changeTables);
290         changeTables.insert(sharedTables.begin(), sharedTables.end());
291     }
292     LOGI("[CompareReferenceProperty] size = %zu", changeTables.size());
293     return changeTables;
294 }
295 
GetReachableRef()296 std::map<std::string, std::map<std::string, bool>> RelationalSchemaObject::GetReachableRef()
297 {
298     return reachableReference_;
299 }
300 
GetTableWeight()301 std::map<std::string, int> RelationalSchemaObject::GetTableWeight()
302 {
303     return tableWeight_;
304 }
305 
GetTrackerTable(const std::string & tableName) const306 TrackerTable RelationalSchemaObject::GetTrackerTable(const std::string &tableName) const
307 {
308     auto it = trackerTables_.find(tableName);
309     if (it != trackerTables_.end()) {
310         return it->second.GetTrackerTable();
311     }
312     return {};
313 }
314 
ParseFromTrackerSchemaString(const std::string & inSchemaString)315 int RelationalSchemaObject::ParseFromTrackerSchemaString(const std::string &inSchemaString)
316 {
317     JsonObject schemaObj;
318     int errCode = schemaObj.Parse(inSchemaString);
319     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
320         LOGE("[RelationalSchema][Parse] Schema json string parse failed: %d.", errCode);
321         return errCode;
322     }
323 
324     errCode = ParseTrackerSchema(schemaObj);
325     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
326         LOGE("[RelationalSchema][Parse] Parse to tracker schema failed: %d.", errCode);
327         return errCode;
328     }
329 
330     schemaString_ = schemaObj.ToString();
331     return E_OK;
332 }
333 
GetTrackerTables() const334 const TableInfoMap &RelationalSchemaObject::GetTrackerTables() const
335 {
336     return trackerTables_;
337 }
338 
SetReferenceProperty(const std::vector<TableReferenceProperty> & referenceProperty)339 void RelationalSchemaObject::SetReferenceProperty(const std::vector<TableReferenceProperty> &referenceProperty)
340 {
341     referenceProperty_ = referenceProperty;
342     GenerateSchemaString();
343     GenerateReachableRef();
344     GenerateTableInfoReferenced();
345 }
346 
GetReferenceProperty() const347 const std::vector<TableReferenceProperty> &RelationalSchemaObject::GetReferenceProperty() const
348 {
349     return referenceProperty_;
350 }
351 
CompareAgainstSchemaObject(const std::string & inSchemaString,std::map<std::string,int> & cmpRst) const352 int RelationalSchemaObject::CompareAgainstSchemaObject(const std::string &inSchemaString,
353     std::map<std::string, int> &cmpRst) const
354 {
355     return E_OK;
356 }
357 
CompareAgainstSchemaObject(const RelationalSchemaObject & inSchemaObject,std::map<std::string,int> & cmpRst) const358 int RelationalSchemaObject::CompareAgainstSchemaObject(const RelationalSchemaObject &inSchemaObject,
359     std::map<std::string, int> &cmpRst) const
360 {
361     return E_OK;
362 }
363 
364 namespace {
GetMemberFromJsonObject(const JsonObject & inJsonObject,const std::string & fieldName,FieldType expectType,bool isNecessary,FieldValue & fieldValue)365 int GetMemberFromJsonObject(const JsonObject &inJsonObject, const std::string &fieldName, FieldType expectType,
366     bool isNecessary, FieldValue &fieldValue)
367 {
368     if (!inJsonObject.IsFieldPathExist(FieldPath {fieldName})) {
369         if (isNecessary) {
370             LOGE("[RelationalSchema][Parse] Get schema not exist. isNecessary: %d", isNecessary);
371             return -E_SCHEMA_PARSE_FAIL;
372         }
373         return -E_NOT_FOUND;
374     }
375 
376     FieldType fieldType;
377     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {fieldName}, fieldType);
378     if (errCode != E_OK) {
379         LOGE("[RelationalSchema][Parse] Get schema fieldType failed: %d.", errCode);
380         return -E_SCHEMA_PARSE_FAIL;
381     }
382 
383     if (fieldType != expectType) {
384         LOGE("[RelationalSchema][Parse] Expect fieldType %d but: %d.",
385             static_cast<int>(expectType), static_cast<int>(fieldType));
386         return -E_SCHEMA_PARSE_FAIL;
387     }
388 
389     errCode = inJsonObject.GetFieldValueByFieldPath(FieldPath {fieldName}, fieldValue);
390     if (errCode != E_OK) {
391         LOGE("[RelationalSchema][Parse] Get schema value failed: %d.", errCode);
392         return -E_SCHEMA_PARSE_FAIL;
393     }
394     return E_OK;
395 }
396 }
397 
ParseTrackerSchema(const JsonObject & inJsonObject)398 int RelationalSchemaObject::ParseTrackerSchema(const JsonObject &inJsonObject)
399 {
400     FieldType fieldType;
401     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, fieldType);
402     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
403         LOGE("[RelationalSchema][Parse] Get tracker schema TABLES fieldType failed: %d.", errCode);
404         return -E_SCHEMA_PARSE_FAIL;
405     }
406     if (FieldType::LEAF_FIELD_ARRAY != fieldType) { // LCOV_EXCL_BR_LINE
407         LOGE("[RelationalSchema][Parse] Expect tracker TABLES fieldType ARRAY but %s.",
408              SchemaUtils::FieldTypeString(fieldType).c_str());
409         return -E_SCHEMA_PARSE_FAIL;
410     }
411     std::vector<JsonObject> tables;
412     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, tables);
413     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
414         LOGE("[RelationalSchema][Parse] Get tracker schema TABLES value failed: %d.", errCode);
415         return -E_SCHEMA_PARSE_FAIL;
416     }
417     for (const JsonObject &table : tables) {
418         errCode = ParseCheckTrackerTable(table);
419         if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
420             LOGE("[RelationalSchema][Parse] Parse schema TABLES failed: %d.", errCode);
421             return -E_SCHEMA_PARSE_FAIL;
422         }
423     }
424     return E_OK;
425 }
426 
ParseCheckTrackerTable(const JsonObject & inJsonObject)427 int RelationalSchemaObject::ParseCheckTrackerTable(const JsonObject &inJsonObject)
428 {
429     TrackerTable table;
430     int errCode = ParseCheckTrackerTableName(inJsonObject, table);
431     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
432         return errCode;
433     }
434     errCode = ParseCheckTrackerExtendName(inJsonObject, table);
435     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
436         return errCode;
437     }
438     errCode = ParseCheckTrackerName(inJsonObject, table);
439     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
440         return errCode;
441     }
442     errCode = ParseCheckTrackerAction(inJsonObject, table);
443     if (errCode != E_OK) {
444         return errCode;
445     }
446     trackerTables_[table.GetTableName()].SetTrackerTable(table);
447     return E_OK;
448 }
449 
ParseCheckTrackerTableName(const JsonObject & inJsonObject,TrackerTable & resultTable)450 int RelationalSchemaObject::ParseCheckTrackerTableName(const JsonObject &inJsonObject, TrackerTable &resultTable)
451 {
452     FieldValue fieldValue;
453     int errCode = GetMemberFromJsonObject(inJsonObject, "NAME", FieldType::LEAF_FIELD_STRING,
454         true, fieldValue);
455     if (errCode == E_OK) { // LCOV_EXCL_BR_LINE
456         if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) { // LCOV_EXCL_BR_LINE
457             LOGE("[RelationalSchema][Parse] Invalid characters in table name, err=%d.", errCode);
458             return -E_SCHEMA_PARSE_FAIL;
459         }
460         resultTable.SetTableName(fieldValue.stringValue);
461     }
462     return errCode;
463 }
464 
ParseCheckTrackerExtendName(const JsonObject & inJsonObject,TrackerTable & resultTable)465 int RelationalSchemaObject::ParseCheckTrackerExtendName(const JsonObject &inJsonObject, TrackerTable &resultTable)
466 {
467     FieldType fieldType;
468     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {"EXTEND_NAMES"}, fieldType);
469     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
470         FieldValue fieldValue;
471         errCode = GetMemberFromJsonObject(inJsonObject, "EXTEND_NAME", FieldType::LEAF_FIELD_STRING,
472             true, fieldValue);
473         if (errCode == E_OK) { // LCOV_EXCL_BR_LINE
474             if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) { // LCOV_EXCL_BR_LINE
475                 LOGE("[RelationalSchema][Parse] Invalid characters in extend name, err=%d.", errCode);
476                 return -E_SCHEMA_PARSE_FAIL;
477             } else if (!fieldValue.stringValue.empty()) {
478                 resultTable.SetExtendName(fieldValue.stringValue);
479                 resultTable.SetExtendNames({fieldValue.stringValue});
480             }
481             return E_OK;
482         }
483         LOGE("[RelationalSchema][Parse] Get extend col names fieldType failed: %d.", errCode);
484         return -E_SCHEMA_PARSE_FAIL;
485     }
486     if (FieldType::LEAF_FIELD_ARRAY != fieldType) { // LCOV_EXCL_BR_LINE
487         LOGE("[RelationalSchema][Parse] Expect extend cols fieldType ARRAY but %s.",
488              SchemaUtils::FieldTypeString(fieldType).c_str());
489         return -E_SCHEMA_PARSE_FAIL;
490     }
491     std::vector<JsonObject> fieldValues;
492     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath{"EXTEND_NAMES"}, fieldValues);
493     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
494         LOGE("[RelationalSchema][Parse] Get extend col names value failed: %d.", errCode);
495         return -E_SCHEMA_PARSE_FAIL;
496     }
497     std::set<std::string> colNames;
498     for (const JsonObject &value : fieldValues) {
499         FieldValue fieldValue;
500         errCode = value.GetFieldValueByFieldPath(FieldPath {}, fieldValue);
501         if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
502             LOGE("[RelationalSchema][Parse] Parse extend col name failed: %d.", errCode);
503             return -E_SCHEMA_PARSE_FAIL;
504         }
505         colNames.insert(fieldValue.stringValue);
506     }
507     resultTable.SetExtendNames(colNames);
508     return errCode;
509 }
510 
ParseCheckTrackerName(const JsonObject & inJsonObject,TrackerTable & resultTable)511 int RelationalSchemaObject::ParseCheckTrackerName(const JsonObject &inJsonObject, TrackerTable &resultTable)
512 {
513     FieldType fieldType;
514     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {"TRACKER_NAMES"}, fieldType);
515     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
516         LOGE("[RelationalSchema][Parse] Get tracker col names fieldType failed: %d.", errCode);
517         return -E_SCHEMA_PARSE_FAIL;
518     }
519     if (FieldType::LEAF_FIELD_ARRAY != fieldType) { // LCOV_EXCL_BR_LINE
520         LOGE("[RelationalSchema][Parse] Expect tracker TABLES fieldType ARRAY but %s.",
521             SchemaUtils::FieldTypeString(fieldType).c_str());
522         return -E_SCHEMA_PARSE_FAIL;
523     }
524     std::vector<JsonObject> fieldValues;
525     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath{"TRACKER_NAMES"}, fieldValues);
526     if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
527         LOGE("[RelationalSchema][Parse] Get tracker col names value failed: %d.", errCode);
528         return -E_SCHEMA_PARSE_FAIL;
529     }
530     std::set<std::string> colNames;
531     for (const JsonObject &value : fieldValues) {
532         FieldValue fieldValue;
533         errCode = value.GetFieldValueByFieldPath(FieldPath {}, fieldValue);
534         if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
535             LOGE("[RelationalSchema][Parse] Parse tracker col name failed: %d.", errCode);
536             return -E_SCHEMA_PARSE_FAIL;
537         }
538         colNames.insert(fieldValue.stringValue);
539     }
540     resultTable.SetTrackerNames(colNames);
541     return errCode;
542 }
543 
ParseRelationalSchema(const JsonObject & inJsonObject)544 int RelationalSchemaObject::ParseRelationalSchema(const JsonObject &inJsonObject)
545 {
546     int errCode = ParseCheckSchemaVersion(inJsonObject);
547     if (errCode != E_OK) {
548         return errCode;
549     }
550     errCode = ParseCheckSchemaType(inJsonObject);
551     if (errCode != E_OK) {
552         return errCode;
553     }
554     errCode = ParseCheckTableMode(inJsonObject);
555     if (errCode != E_OK) {
556         return errCode;
557     }
558     errCode = ParseCheckSchemaTableDefine(inJsonObject);
559     if (errCode != E_OK) {
560         return errCode;
561     }
562     errCode = ParseCheckReferenceProperty(inJsonObject);
563     if (errCode != E_OK) {
564         return errCode;
565     }
566     return ParseDistributedSchema(inJsonObject);
567 }
568 
569 namespace {
IsSchemaVersionValid(const std::string & version)570 inline bool IsSchemaVersionValid(const std::string &version)
571 {
572     std::string stripedVersion = SchemaUtils::Strip(version);
573     return stripedVersion == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2 ||
574         stripedVersion == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2_1;
575 }
576 }
577 
ParseCheckSchemaVersion(const JsonObject & inJsonObject)578 int RelationalSchemaObject::ParseCheckSchemaVersion(const JsonObject &inJsonObject)
579 {
580     FieldValue fieldValue;
581     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_SCHEMA_VERSION,
582         FieldType::LEAF_FIELD_STRING, true, fieldValue);
583     if (errCode != E_OK) {
584         return errCode;
585     }
586 
587     if (IsSchemaVersionValid(fieldValue.stringValue)) {
588         schemaVersion_ = fieldValue.stringValue;
589         return E_OK;
590     }
591 
592     LOGE("[RelationalSchema][Parse] Unexpected SCHEMA_VERSION=%s.", fieldValue.stringValue.c_str());
593     return -E_SCHEMA_PARSE_FAIL;
594 }
595 
ParseCheckSchemaType(const JsonObject & inJsonObject)596 int RelationalSchemaObject::ParseCheckSchemaType(const JsonObject &inJsonObject)
597 {
598     FieldValue fieldValue;
599     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_SCHEMA_TYPE,
600         FieldType::LEAF_FIELD_STRING, true, fieldValue);
601     if (errCode != E_OK) {
602         return errCode;
603     }
604 
605     if (SchemaUtils::Strip(fieldValue.stringValue) != SchemaConstant::KEYWORD_TYPE_RELATIVE) {
606         LOGE("[RelationalSchema][Parse] Unexpected SCHEMA_TYPE=%s.", fieldValue.stringValue.c_str());
607         return -E_SCHEMA_PARSE_FAIL;
608     }
609     schemaType_ = SchemaType::RELATIVE;
610     return E_OK;
611 }
612 
613 namespace {
IsTableModeValid(const std::string & mode)614 inline bool IsTableModeValid(const std::string &mode)
615 {
616     std::string stripedMode = SchemaUtils::Strip(mode);
617     return stripedMode == SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE ||
618         stripedMode == SchemaConstant::KEYWORD_TABLE_COLLABORATION;
619 }
620 }
621 
ParseCheckTableMode(const JsonObject & inJsonObject)622 int RelationalSchemaObject::ParseCheckTableMode(const JsonObject &inJsonObject)
623 {
624     if (schemaVersion_ == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2) {
625         return E_OK; // version 2 has no table mode, no parsing required
626     }
627 
628     FieldValue fieldValue;
629     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_TABLE_MODE,
630         FieldType::LEAF_FIELD_STRING, true, fieldValue);
631     if (errCode != E_OK) {
632         return errCode;
633     }
634 
635     if (!IsTableModeValid(fieldValue.stringValue)) {
636         LOGE("[RelationalSchema][Parse] Unexpected TABLE_MODE=%s.", fieldValue.stringValue.c_str());
637         return -E_SCHEMA_PARSE_FAIL;
638     }
639 
640     tableMode_ = SchemaUtils::Strip(fieldValue.stringValue) == SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE ?
641         DistributedTableMode::SPLIT_BY_DEVICE : DistributedTableMode::COLLABORATION;
642     return E_OK;
643 }
644 
ParseCheckSchemaTableDefine(const JsonObject & inJsonObject)645 int RelationalSchemaObject::ParseCheckSchemaTableDefine(const JsonObject &inJsonObject)
646 {
647     FieldType fieldType;
648     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, fieldType);
649     if (errCode != E_OK) {
650         LOGE("[RelationalSchema][Parse] Get schema TABLES fieldType failed: %d.", errCode);
651         return -E_SCHEMA_PARSE_FAIL;
652     }
653     if (FieldType::LEAF_FIELD_ARRAY != fieldType) {
654         LOGE("[RelationalSchema][Parse] Expect TABLES fieldType ARRAY but %s.",
655             SchemaUtils::FieldTypeString(fieldType).c_str());
656         return -E_SCHEMA_PARSE_FAIL;
657     }
658     std::vector<JsonObject> tables;
659     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, tables);
660     if (errCode != E_OK) {
661         LOGE("[RelationalSchema][Parse] Get schema TABLES value failed: %d.", errCode);
662         return -E_SCHEMA_PARSE_FAIL;
663     }
664     for (const JsonObject &table : tables) {
665         errCode = ParseCheckTableInfo(table);
666         if (errCode != E_OK) {
667             LOGE("[RelationalSchema][Parse] Parse schema TABLES failed: %d.", errCode);
668             return -E_SCHEMA_PARSE_FAIL;
669         }
670     }
671     return E_OK;
672 }
673 
ParseCheckTableInfo(const JsonObject & inJsonObject)674 int RelationalSchemaObject::ParseCheckTableInfo(const JsonObject &inJsonObject)
675 {
676     TableInfo resultTable;
677     int errCode = ParseCheckTableName(inJsonObject, resultTable);
678     if (errCode != E_OK) {
679         return errCode;
680     }
681     errCode = ParseCheckTableDefine(inJsonObject, resultTable);
682     if (errCode != E_OK) {
683         return errCode;
684     }
685     errCode = ParseCheckOriginTableName(inJsonObject, resultTable);
686     if (errCode != E_OK) {
687         return errCode;
688     }
689     errCode = ParseCheckTableAutoInc(inJsonObject, resultTable);
690     if (errCode != E_OK) {
691         return errCode;
692     }
693     errCode = ParseCheckSharedTableMark(inJsonObject, resultTable);
694     if (errCode != E_OK) {
695         return errCode;
696     }
697     errCode = ParseCheckTablePrimaryKey(inJsonObject, resultTable);
698     if (errCode != E_OK) {
699         return errCode;
700     }
701 
702     errCode = ParseCheckTableSyncType(inJsonObject, resultTable);
703     if (errCode != E_OK) {
704         return errCode;
705     }
706     errCode = ParseCheckTableIndex(inJsonObject, resultTable);
707     if (errCode != E_OK) {
708         return errCode;
709     }
710     errCode = ParseCheckTableUnique(inJsonObject, resultTable);
711     if (errCode != E_OK) {
712         return errCode;
713     }
714     tables_[resultTable.GetTableName()] = resultTable;
715     return E_OK;
716 }
717 
ParseCheckTableName(const JsonObject & inJsonObject,TableInfo & resultTable)718 int RelationalSchemaObject::ParseCheckTableName(const JsonObject &inJsonObject, TableInfo &resultTable)
719 {
720     FieldValue fieldValue;
721     int errCode = GetMemberFromJsonObject(inJsonObject, "NAME", FieldType::LEAF_FIELD_STRING,
722         true, fieldValue);
723     if (errCode == E_OK) {
724         if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
725             LOGE("[RelationalSchema][Parse] Invalid characters in table name, err=%d.", errCode);
726             return -E_SCHEMA_PARSE_FAIL;
727         }
728         resultTable.SetTableName(fieldValue.stringValue);
729     }
730     return errCode;
731 }
732 
ParseCheckTableDefine(const JsonObject & inJsonObject,TableInfo & resultTable)733 int RelationalSchemaObject::ParseCheckTableDefine(const JsonObject &inJsonObject, TableInfo &resultTable)
734 {
735     std::map<FieldPath, FieldType> tableFields;
736     int errCode = inJsonObject.GetSubFieldPathAndType(FieldPath {"DEFINE"}, tableFields);
737     if (errCode != E_OK) {
738         LOGE("[RelationalSchema][Parse] Get schema TABLES DEFINE failed: %d.", errCode);
739         return -E_SCHEMA_PARSE_FAIL;
740     }
741 
742     for (const auto &field : tableFields) {
743         if (field.second != FieldType::INTERNAL_FIELD_OBJECT) {
744             LOGE("[RelationalSchema][Parse] Expect schema TABLES DEFINE fieldType INTERNAL OBJECT but : %s.",
745                 SchemaUtils::FieldTypeString(field.second).c_str());
746             return -E_SCHEMA_PARSE_FAIL;
747         }
748 
749         JsonObject fieldObj;
750         errCode = inJsonObject.GetObjectByFieldPath(field.first, fieldObj);
751         if (errCode != E_OK) {
752             LOGE("[RelationalSchema][Parse] Get table field object failed. %d", errCode);
753             return errCode;
754         }
755 
756         if (!DBCommon::CheckIsAlnumOrUnderscore(field.first[1])) {
757             LOGE("[RelationalSchema][Parse] Invalid characters in field name, err=%d.", errCode);
758             return -E_SCHEMA_PARSE_FAIL;
759         }
760 
761         FieldInfo fieldInfo;
762         fieldInfo.SetFieldName(field.first[1]); // 1 : table name element in path
763         errCode = ParseCheckTableFieldInfo(fieldObj, field.first, fieldInfo);
764         if (errCode != E_OK) {
765             LOGE("[RelationalSchema][Parse] Parse table field info failed. %d", errCode);
766             return -E_SCHEMA_PARSE_FAIL;
767         }
768         resultTable.AddField(fieldInfo);
769     }
770     return E_OK;
771 }
772 
ParseCheckTableFieldInfo(const JsonObject & inJsonObject,const FieldPath & path,FieldInfo & field)773 int RelationalSchemaObject::ParseCheckTableFieldInfo(const JsonObject &inJsonObject, const FieldPath &path,
774     FieldInfo &field)
775 {
776     FieldValue fieldValue;
777     int errCode = GetMemberFromJsonObject(inJsonObject, "COLUMN_ID", FieldType::LEAF_FIELD_INTEGER, true, fieldValue);
778     if (errCode != E_OK) {
779         return errCode;
780     }
781     field.SetColumnId(fieldValue.integerValue);
782 
783     errCode = GetMemberFromJsonObject(inJsonObject, "TYPE", FieldType::LEAF_FIELD_STRING, true, fieldValue);
784     if (errCode != E_OK) {
785         return errCode;
786     }
787     field.SetDataType(fieldValue.stringValue);
788 
789     errCode = GetMemberFromJsonObject(inJsonObject, "NOT_NULL", FieldType::LEAF_FIELD_BOOL, true, fieldValue);
790     if (errCode != E_OK) {
791         return errCode;
792     }
793     field.SetNotNull(fieldValue.boolValue);
794 
795     errCode = GetMemberFromJsonObject(inJsonObject, "DEFAULT", FieldType::LEAF_FIELD_STRING, false, fieldValue);
796     if (errCode == E_OK) {
797         field.SetDefaultValue(fieldValue.stringValue);
798     } else if (errCode != -E_NOT_FOUND) {
799         return errCode;
800     }
801 
802     return E_OK;
803 }
804 
ParseCheckOriginTableName(const JsonObject & inJsonObject,TableInfo & resultTable)805 int RelationalSchemaObject::ParseCheckOriginTableName(const JsonObject &inJsonObject, TableInfo &resultTable)
806 {
807     FieldValue fieldValue;
808     int errCode = GetMemberFromJsonObject(inJsonObject, "ORIGINTABLENAME", FieldType::LEAF_FIELD_STRING,
809         false, fieldValue);
810     if (errCode == E_OK) {
811         if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
812             LOGE("[RelationalSchema][Parse] Invalid characters in origin table name, err=%d.", errCode);
813             return -E_SCHEMA_PARSE_FAIL;
814         }
815         resultTable.SetOriginTableName(fieldValue.stringValue);
816     } else if (errCode != -E_NOT_FOUND) {
817         LOGE("[RelationalSchema][Parse] Get schema orgin table name failed: %d", errCode);
818         return errCode;
819     }
820     return E_OK;
821 }
822 
ParseCheckTableAutoInc(const JsonObject & inJsonObject,TableInfo & resultTable)823 int RelationalSchemaObject::ParseCheckTableAutoInc(const JsonObject &inJsonObject, TableInfo &resultTable)
824 {
825     FieldValue fieldValue;
826     int errCode = GetMemberFromJsonObject(inJsonObject, "AUTOINCREMENT", FieldType::LEAF_FIELD_BOOL, false, fieldValue);
827     if (errCode == E_OK) {
828         resultTable.SetAutoIncrement(fieldValue.boolValue);
829     } else if (errCode != -E_NOT_FOUND) {
830         return errCode;
831     }
832     return E_OK;
833 }
834 
ParseCheckSharedTableMark(const JsonObject & inJsonObject,TableInfo & resultTable)835 int RelationalSchemaObject::ParseCheckSharedTableMark(const JsonObject &inJsonObject, TableInfo &resultTable)
836 {
837     FieldValue fieldValue;
838     int errCode = GetMemberFromJsonObject(inJsonObject, "SHAREDTABLEMARK", FieldType::LEAF_FIELD_BOOL, false,
839         fieldValue);
840     if (errCode == E_OK) {
841         resultTable.SetSharedTableMark(fieldValue.boolValue);
842     } else if (errCode != -E_NOT_FOUND) {
843         return errCode;
844     }
845     return E_OK;
846 }
847 
ParseCheckTablePrimaryKey(const JsonObject & inJsonObject,TableInfo & resultTable)848 int RelationalSchemaObject::ParseCheckTablePrimaryKey(const JsonObject &inJsonObject, TableInfo &resultTable)
849 {
850     if (!inJsonObject.IsFieldPathExist(FieldPath {"PRIMARY_KEY"})) {
851         return E_OK;
852     }
853 
854     FieldType type;
855     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {"PRIMARY_KEY"}, type);
856     if (errCode != E_OK) {
857         return errCode;
858     }
859 
860     if (type == FieldType::LEAF_FIELD_STRING) { // Compatible with schema 2.0
861         FieldValue fieldValue;
862         errCode = GetMemberFromJsonObject(inJsonObject, "PRIMARY_KEY", FieldType::LEAF_FIELD_STRING, false, fieldValue);
863         if (errCode == E_OK) {
864             resultTable.SetPrimaryKey(fieldValue.stringValue, 1);
865         }
866     } else if (type == FieldType::LEAF_FIELD_ARRAY) {
867         CompositeFields multiPrimaryKey;
868         errCode = inJsonObject.GetStringArrayByFieldPath(FieldPath {"PRIMARY_KEY"}, multiPrimaryKey);
869         if (errCode == E_OK) {
870             int index = 1; // primary key index
871             for (const auto &item : multiPrimaryKey) {
872                 resultTable.SetPrimaryKey(item, index++);
873             }
874         }
875     } else {
876         errCode = -E_SCHEMA_PARSE_FAIL;
877     }
878     return errCode;
879 }
880 
ParseCheckReferenceProperty(const JsonObject & inJsonObject)881 int RelationalSchemaObject::ParseCheckReferenceProperty(const JsonObject &inJsonObject)
882 {
883     if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::REFERENCE_PROPERTY})) {
884         return E_OK;
885     }
886 
887     FieldType fieldType;
888     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::REFERENCE_PROPERTY}, fieldType);
889     if (errCode != E_OK) {
890         LOGE("[RelationalSchema][Parse] Get schema REFERENCE_PROPERTY fieldType failed: %d.", errCode);
891         return -E_SCHEMA_PARSE_FAIL;
892     }
893     if (FieldType::LEAF_FIELD_ARRAY != fieldType) {
894         LOGE("[RelationalSchema][Parse] Expect TABLES REFERENCE_PROPERTY ARRAY but %s.",
895              SchemaUtils::FieldTypeString(fieldType).c_str());
896         return -E_SCHEMA_PARSE_FAIL;
897     }
898     std::vector<JsonObject> references;
899     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath{SchemaConstant::REFERENCE_PROPERTY}, references);
900     if (errCode != E_OK) {
901         LOGE("[RelationalSchema][Parse] Get schema REFERENCE_PROPERTY value failed: %d.", errCode);
902         return -E_SCHEMA_PARSE_FAIL;
903     }
904     for (const JsonObject &reference : references) {
905         errCode = ParseCheckReference(reference);
906         if (errCode != E_OK) {
907             LOGE("[RelationalSchema][Parse] Parse schema reference failed: %d.", errCode);
908             return -E_SCHEMA_PARSE_FAIL;
909         }
910     }
911     return E_OK;
912 }
913 
ParseCheckReference(const JsonObject & inJsonObject)914 int RelationalSchemaObject::ParseCheckReference(const JsonObject &inJsonObject)
915 {
916     FieldValue fieldValue;
917     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::SOURCE_TABLE_NAME, FieldType::LEAF_FIELD_STRING,
918         true, fieldValue);
919     if (errCode != E_OK) {
920         LOGE("[RelationalSchema][Parse] Get source table name failed, errCode = %d", errCode);
921         return errCode;
922     }
923     if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
924         LOGE("[RelationalSchema][Parse] Invalid characters in source table name.");
925         return -E_SCHEMA_PARSE_FAIL;
926     }
927 
928     TableReferenceProperty referenceProperty;
929     referenceProperty.sourceTableName = fieldValue.stringValue;
930     errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::TARGET_TABLE_NAME, FieldType::LEAF_FIELD_STRING,
931         true, fieldValue);
932     if (errCode != E_OK) {
933         LOGE("[RelationalSchema][Parse] Get target table name failed, errCode = %d", errCode);
934         return errCode;
935     }
936     if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
937         LOGE("[RelationalSchema][Parse] Invalid characters in target table name.");
938         return -E_SCHEMA_PARSE_FAIL;
939     }
940 
941     referenceProperty.targetTableName = fieldValue.stringValue;
942     errCode = ParseCheckReferenceColumns(inJsonObject, referenceProperty);
943     if (errCode != E_OK) {
944         LOGE("[RelationalSchema][Parse] Parse reference columns failed, errCode = %d", errCode);
945         return errCode;
946     }
947     referenceProperty_.emplace_back(referenceProperty);
948     tables_[referenceProperty.targetTableName].AddTableReferenceProperty(referenceProperty);
949     return E_OK;
950 }
951 
ParseCheckReferenceColumns(const JsonObject & inJsonObject,TableReferenceProperty & tableReferenceProperty)952 int RelationalSchemaObject::ParseCheckReferenceColumns(const JsonObject &inJsonObject,
953     TableReferenceProperty &tableReferenceProperty)
954 {
955     // parse columns
956     FieldType fieldType;
957     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::COLUMNS}, fieldType);
958     if (errCode != E_OK) {
959         LOGE("[RelationalSchema][Parse] Get schema reference COLUMNS fieldType failed: %d.", errCode);
960         return -E_SCHEMA_PARSE_FAIL;
961     }
962     if (FieldType::LEAF_FIELD_ARRAY != fieldType) {
963         LOGE("[RelationalSchema][Parse] Expect reference COLUMNS ARRAY but %s.",
964              SchemaUtils::FieldTypeString(fieldType).c_str());
965         return -E_SCHEMA_PARSE_FAIL;
966     }
967     std::vector<JsonObject> columns;
968     errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath{SchemaConstant::COLUMNS}, columns);
969     if (errCode != E_OK) {
970         LOGE("[RelationalSchema][Parse] Get schema reference COLUMNS value failed: %d.", errCode);
971         return -E_SCHEMA_PARSE_FAIL;
972     }
973 
974     for (const JsonObject &column : columns) {
975         errCode = ParseCheckReferenceColumn(column, tableReferenceProperty);
976         if (errCode != E_OK) {
977             LOGE("[RelationalSchema][Parse] Parse reference one COLUMN failed: %d.", errCode);
978             return -E_SCHEMA_PARSE_FAIL;
979         }
980     }
981     return E_OK;
982 }
983 
ParseCheckReferenceColumn(const JsonObject & inJsonObject,TableReferenceProperty & tableReferenceProperty)984 int RelationalSchemaObject::ParseCheckReferenceColumn(const JsonObject &inJsonObject,
985     TableReferenceProperty &tableReferenceProperty)
986 {
987     FieldValue fieldValue;
988     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::SOURCE_COL, FieldType::LEAF_FIELD_STRING,
989         true, fieldValue);
990     if (errCode != E_OK) {
991         LOGE("[RelationalSchema][Parse] Get source col failed, errCode = %d", errCode);
992         return errCode;
993     }
994     if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
995         LOGE("[RelationalSchema][Parse] Invalid characters in source col name.");
996         return -E_SCHEMA_PARSE_FAIL;
997     }
998 
999     std::string sourceCol = fieldValue.stringValue;
1000     errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::TARGET_COL, FieldType::LEAF_FIELD_STRING,
1001         true, fieldValue);
1002     if (errCode != E_OK) {
1003         LOGE("[RelationalSchema][Parse] Get target col failed, errCode = %d", errCode);
1004         return errCode;
1005     }
1006     if (!DBCommon::CheckIsAlnumOrUnderscore(fieldValue.stringValue)) {
1007         LOGE("[RelationalSchema][Parse] Invalid characters in target col name.");
1008         return -E_SCHEMA_PARSE_FAIL;
1009     }
1010     std::string targetCol = fieldValue.stringValue;
1011     tableReferenceProperty.columns[sourceCol] = targetCol;
1012     return E_OK;
1013 }
1014 
ParseCheckTableSyncType(const JsonObject & inJsonObject,TableInfo & resultTable)1015 int RelationalSchemaObject::ParseCheckTableSyncType(const JsonObject &inJsonObject, TableInfo &resultTable)
1016 {
1017     FieldValue fieldValue;
1018     int errCode = GetMemberFromJsonObject(inJsonObject, "TABLE_SYNC_TYPE", FieldType::LEAF_FIELD_INTEGER,
1019         false, fieldValue);
1020     if (errCode == E_OK) {
1021         resultTable.SetTableSyncType(static_cast<TableSyncType>(fieldValue.integerValue));
1022     } else if (errCode != -E_NOT_FOUND) {
1023         return errCode;
1024     }
1025     return E_OK; // if there is no "TABLE_SYNC_TYPE" filed, the table_sync_type is DEVICE_COOPERATION
1026 }
1027 
ParseCheckTableIndex(const JsonObject & inJsonObject,TableInfo & resultTable)1028 int RelationalSchemaObject::ParseCheckTableIndex(const JsonObject &inJsonObject, TableInfo &resultTable)
1029 {
1030     if (!inJsonObject.IsFieldPathExist(FieldPath {"INDEX"})) { // INDEX is not necessary
1031         return E_OK;
1032     }
1033     std::map<FieldPath, FieldType> tableFields;
1034     int errCode = inJsonObject.GetSubFieldPathAndType(FieldPath {"INDEX"}, tableFields);
1035     if (errCode != E_OK) {
1036         LOGE("[RelationalSchema][Parse] Get schema TABLES INDEX failed: %d.", errCode);
1037         return -E_SCHEMA_PARSE_FAIL;
1038     }
1039 
1040     for (const auto &field : tableFields) {
1041         if (field.second != FieldType::LEAF_FIELD_ARRAY) {
1042             LOGE("[RelationalSchema][Parse] Expect schema TABLES INDEX fieldType ARRAY but : %s.",
1043                 SchemaUtils::FieldTypeString(field.second).c_str());
1044             return -E_SCHEMA_PARSE_FAIL;
1045         }
1046         CompositeFields indexDefine;
1047         errCode = inJsonObject.GetStringArrayByFieldPath(field.first, indexDefine);
1048         if (errCode != E_OK) {
1049             LOGE("[RelationalSchema][Parse] Get schema TABLES INDEX field value failed: %d.", errCode);
1050             return -E_SCHEMA_PARSE_FAIL;
1051         }
1052         resultTable.AddIndexDefine(field.first[1], indexDefine); // 1 : second element in path
1053     }
1054     return E_OK;
1055 }
1056 
ParseCheckTableUnique(const JsonObject & inJsonObject,TableInfo & resultTable)1057 int RelationalSchemaObject::ParseCheckTableUnique(const JsonObject &inJsonObject, TableInfo &resultTable)
1058 {
1059     if (!inJsonObject.IsFieldPathExist(FieldPath {"UNIQUE"})) { // UNIQUE is not necessary
1060         return E_OK;
1061     }
1062 
1063     std::vector<CompositeFields> uniques;
1064     int errCode = inJsonObject.GetArrayContentOfStringOrStringArray(FieldPath {"UNIQUE"}, uniques);
1065     if (errCode != E_OK) {
1066         LOGE("[RelationalSchema][Parse] Get schema TABLES UNIQUE failed: %d.", errCode);
1067         return -E_SCHEMA_PARSE_FAIL;
1068     }
1069     resultTable.SetUniqueDefine(uniques);
1070     return E_OK;
1071 }
1072 
GenerateReachableRef()1073 void RelationalSchemaObject::GenerateReachableRef()
1074 {
1075     reachableReference_.clear();
1076     tableWeight_.clear();
1077     std::set<std::string> startNodes; // such as {a->b->c,d->e}, record {a,d}
1078     std::map<std::string, std::set<std::string>> nextNodes; // such as {a->b->c}, record {{a,{b}}, {b, {c}}}
1079     // we need to record all table reachable reference here
1080     for (const auto &tableRef : referenceProperty_) {
1081         // they also can reach target
1082         RefreshReachableRef(tableRef);
1083         startNodes.insert(tableRef.sourceTableName);
1084         startNodes.erase(tableRef.targetTableName);
1085         nextNodes[tableRef.sourceTableName].insert(tableRef.targetTableName);
1086     }
1087     CalculateTableWeight(startNodes, nextNodes);
1088 }
1089 
GenerateTableInfoReferenced()1090 void RelationalSchemaObject::GenerateTableInfoReferenced()
1091 {
1092     for (auto &table : tables_) {
1093         table.second.SetSourceTableReference({});
1094     }
1095     for (const auto &reference : referenceProperty_) {
1096         tables_[reference.targetTableName].AddTableReferenceProperty(reference);
1097     }
1098 }
1099 
RefreshReachableRef(const TableReferenceProperty & referenceProperty)1100 void RelationalSchemaObject::RefreshReachableRef(const TableReferenceProperty &referenceProperty)
1101 {
1102     // such as source:A target:B
1103     std::set<std::string> recordSources;
1104     // find all node which can reach source as collection recordSources
1105     for (const auto &[start, end] : reachableReference_) {
1106         auto node = end.find(referenceProperty.sourceTableName);
1107         // find the node and it can reach
1108         if (node != end.end() && node->second) {
1109             recordSources.insert(start);
1110         }
1111     }
1112     recordSources.insert(referenceProperty.sourceTableName);
1113     // find all node which start with target as collection recordTargets
1114     std::set<std::string> recordTargets;
1115     for (auto &[entry, reach] : reachableReference_[referenceProperty.targetTableName]) {
1116         if (reach) {
1117             recordTargets.insert(entry);
1118         }
1119     }
1120     recordTargets.insert(referenceProperty.targetTableName);
1121     for (const auto &source : recordSources) {
1122         for (const auto &target : recordTargets) {
1123             reachableReference_[source][target] = true;
1124         }
1125     }
1126 }
1127 
CalculateTableWeight(const std::set<std::string> & startNodes,const std::map<std::string,std::set<std::string>> & nextNodes)1128 void RelationalSchemaObject::CalculateTableWeight(const std::set<std::string> &startNodes,
1129     const std::map<std::string, std::set<std::string>> &nextNodes)
1130 {
1131     // record the max long path as table weight
1132     for (const auto &start : startNodes) {
1133         std::map<std::string, int> tmpTableWeight;
1134         tmpTableWeight[start] = 1;
1135         if (nextNodes.find(start) == nextNodes.end()) {
1136             continue;
1137         }
1138         std::list<std::string> queue;
1139         for (const auto &target : nextNodes.at(start)) {
1140             queue.push_back(target);
1141             tmpTableWeight[target] = 2; // this path contain 2 nodes
1142         }
1143         // bfs all the path which start from startNodes
1144         while (!queue.empty()) {
1145             auto node = queue.front();
1146             queue.pop_front();
1147             if (nextNodes.find(node) == nextNodes.end()) {
1148                 continue;
1149             }
1150             for (const auto &item : nextNodes.at(node)) {
1151                 queue.push_back(item);
1152                 tmpTableWeight[item] = std::max(tmpTableWeight[item], tmpTableWeight[node] + 1);
1153             }
1154         }
1155         for (const auto &[table, weight] : tmpTableWeight) {
1156             tableWeight_[table] = std::max(tableWeight_[table], weight);
1157         }
1158     }
1159 }
1160 
ParseCheckTrackerAction(const JsonObject & inJsonObject,TrackerTable & resultTable)1161 int RelationalSchemaObject::ParseCheckTrackerAction(const JsonObject &inJsonObject, TrackerTable &resultTable)
1162 {
1163     FieldValue fieldValue;
1164     int errCode = GetMemberFromJsonObject(inJsonObject, "TRACKER_ACTION", FieldType::LEAF_FIELD_BOOL,
1165         false, fieldValue);
1166     if (errCode == E_OK) { // LCOV_EXCL_BR_LINE
1167         resultTable.SetTrackerAction(fieldValue.boolValue);
1168     } else if (errCode == -E_NOT_FOUND) {
1169         fieldValue.boolValue = false;
1170         errCode = E_OK;
1171     } else {
1172         LOGE("[RelationalSchema][Parse] get TRACKER_ACTION failed %d", errCode);
1173     }
1174     return errCode;
1175 }
1176 
CheckDistributedSchemaChange(const DistributedSchema & schema)1177 bool RelationalSchemaObject::CheckDistributedSchemaChange(const DistributedSchema &schema)
1178 {
1179     if (schema.version != dbSchema_.version) {
1180         return true;
1181     }
1182     std::map<std::string, std::vector<DistributedField>, CaseInsensitiveComparator> tableSchema;
1183     for (const auto &table : dbSchema_.tables) {
1184         tableSchema[table.tableName] = table.fields;
1185     }
1186     if (tableSchema.size() != schema.tables.size()) {
1187         return true;
1188     }
1189     for (const auto &table : schema.tables) {
1190         if (tableSchema.find(table.tableName) == tableSchema.end()) {
1191             return true;
1192         }
1193         if (CheckDistributedFieldChange(tableSchema[table.tableName], table.fields)) {
1194             return true;
1195         }
1196     }
1197     return false;
1198 }
1199 
CheckDistributedFieldChange(const std::vector<DistributedField> & source,const std::vector<DistributedField> & target)1200 bool RelationalSchemaObject::CheckDistributedFieldChange(const std::vector<DistributedField> &source,
1201     const std::vector<DistributedField> &target)
1202 {
1203     std::map<std::string, DistributedField, CaseInsensitiveComparator> fields;
1204     for (const auto &field : source) {
1205         fields[field.colName] = field;
1206     }
1207     if (fields.size() != target.size()) {
1208         return true;
1209     }
1210     for (const auto &field : target) {
1211         if (fields.find(field.colName) == fields.end()) {
1212             return true;
1213         }
1214         if (fields[field.colName].isP2pSync != field.isP2pSync) {
1215             return true;
1216         }
1217         if (fields[field.colName].isSpecified != field.isSpecified) {
1218             return true;
1219         }
1220     }
1221     return false;
1222 }
1223 
SetDistributedSchema(const DistributedSchema & schema)1224 void RelationalSchemaObject::SetDistributedSchema(const DistributedSchema &schema)
1225 {
1226     dbSchema_ = schema;
1227     for (const auto &table : schema.tables) {
1228         if (tables_.find(table.tableName) == tables_.end()) {
1229             continue;
1230         }
1231         tables_.at(table.tableName).SetDistributedTable(table);
1232     }
1233     GenerateSchemaString();
1234 }
1235 
GetDistributedSchema() const1236 DistributedSchema RelationalSchemaObject::GetDistributedSchema() const
1237 {
1238     return dbSchema_;
1239 }
1240 
GetDistributedSchemaString()1241 std::string RelationalSchemaObject::GetDistributedSchemaString()
1242 {
1243     std::string res;
1244     res += R"(,")";
1245     res += SchemaConstant::KEYWORD_DISTRIBUTED_SCHEMA;
1246     res += R"(":{)";
1247     res += R"(")";
1248     res += SchemaConstant::KEYWORD_DISTRIBUTED_VERSION;
1249     res += R"(":)";
1250     res += std::to_string(dbSchema_.version);
1251     res += R"(,")";
1252     res += SchemaConstant::KEYWORD_DISTRIBUTED_TABLE;
1253     res += R"(":[)";
1254     for (const auto &table : dbSchema_.tables) {
1255         res += GetOneDistributedTableString(table) + ",";
1256     }
1257     if (!dbSchema_.tables.empty()) {
1258         res.pop_back();
1259     }
1260     res += R"(]})";
1261     return res;
1262 }
1263 
GetOneDistributedTableString(const DistributedTable & table)1264 std::string RelationalSchemaObject::GetOneDistributedTableString(const DistributedTable &table)
1265 {
1266     std::string res;
1267     res += R"({")";
1268     res += SchemaConstant::KEYWORD_DISTRIBUTED_TABLE_NAME;
1269     res += R"(":")";
1270     res += table.tableName;
1271     res += R"(", ")";
1272     res += SchemaConstant::KEYWORD_DISTRIBUTED_FIELD;
1273     res += R"(":[)";
1274     for (const auto &field : table.fields) {
1275         res += R"({")";
1276         res += SchemaConstant::KEYWORD_DISTRIBUTED_COL_NAME;
1277         res += R"(":")";
1278         res += field.colName;
1279         res += R"(", ")";
1280         res += SchemaConstant::KEYWORD_DISTRIBUTED_IS_P2P_SYNC;
1281         res += R"(":)";
1282         if (field.isP2pSync) {
1283             res += "true";
1284         } else {
1285             res += "false";
1286         }
1287         res += R"(, ")";
1288         res += SchemaConstant::KEYWORD_DISTRIBUTED_IS_SPECIFIED;
1289         res += R"(":)";
1290         if (field.isSpecified) {
1291             res += "true";
1292         } else {
1293             res += "false";
1294         }
1295         res += R"(},)";
1296     }
1297     if (!table.fields.empty()) {
1298         res.pop_back();
1299     }
1300     res += R"(]})";
1301     return res;
1302 }
1303 
ParseDistributedSchema(const JsonObject & inJsonObject)1304 int RelationalSchemaObject::ParseDistributedSchema(const JsonObject &inJsonObject)
1305 {
1306     if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::KEYWORD_DISTRIBUTED_SCHEMA})) {
1307         return E_OK;
1308     }
1309 
1310     JsonObject schemaObj;
1311     int errCode = SchemaUtils::ExtractJsonObj(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_SCHEMA, schemaObj);
1312     if (errCode != E_OK) {
1313         return errCode;
1314     }
1315 
1316     errCode = ParseDistributedVersion(schemaObj);
1317     if (errCode != E_OK) {
1318         return errCode;
1319     }
1320     return ParseDistributedTables(schemaObj);
1321 }
1322 
ParseDistributedVersion(const JsonObject & inJsonObject)1323 int RelationalSchemaObject::ParseDistributedVersion(const JsonObject &inJsonObject)
1324 {
1325     const std::string fieldName = SchemaConstant::KEYWORD_DISTRIBUTED_VERSION;
1326     if (!inJsonObject.IsFieldPathExist(FieldPath {fieldName})) {
1327         LOGE("[RelationalSchema][ParseDistributedVersion] Distributed schema has no version");
1328         return -E_SCHEMA_PARSE_FAIL;
1329     }
1330 
1331     FieldType fieldType;
1332     int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {fieldName}, fieldType);
1333     if (errCode != E_OK) {
1334         LOGE("[RelationalSchema][ParseDistributedVersion] Get fieldType of version failed: %d.", errCode);
1335         return -E_SCHEMA_PARSE_FAIL;
1336     }
1337     if (fieldType != FieldType::LEAF_FIELD_INTEGER && fieldType != FieldType::LEAF_FIELD_LONG) {
1338         LOGE("[RelationalSchema][ParseDistributedVersion] Get fieldType of version failed. Found type: %d.", fieldType);
1339         return -E_SCHEMA_PARSE_FAIL;
1340     }
1341 
1342     FieldValue fieldValue;
1343     errCode = inJsonObject.GetFieldValueByFieldPath(FieldPath {fieldName}, fieldValue);
1344     if (errCode != E_OK) {
1345         LOGE("[RelationalSchema][ParseDistributedVersion] Get version value failed: %d.", errCode);
1346         return -E_SCHEMA_PARSE_FAIL;
1347     }
1348 
1349     int64_t versionValue = fieldType == FieldType::LEAF_FIELD_INTEGER ?
1350         static_cast<int64_t>(fieldValue.integerValue) : fieldValue.longValue;
1351     if (versionValue < 0 || versionValue > UINT32_MAX) {
1352         LOGE("[RelationalSchema][ParseDistributedVersion] Version value out of range, value is: %" PRId64,
1353             versionValue);
1354         return -E_SCHEMA_PARSE_FAIL;
1355     }
1356     dbSchema_.version = static_cast<uint32_t>(versionValue);
1357     return E_OK;
1358 }
1359 
ParseDistributedTables(const JsonObject & inJsonObject)1360 int RelationalSchemaObject::ParseDistributedTables(const JsonObject &inJsonObject)
1361 {
1362     if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::KEYWORD_DISTRIBUTED_TABLE})) {
1363         return E_OK;
1364     }
1365 
1366     std::vector<JsonObject> tablesObj;
1367     int errCode = SchemaUtils::ExtractJsonObjArray(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_TABLE, tablesObj);
1368     if (errCode != E_OK) {
1369         return errCode;
1370     }
1371 
1372     for (const auto &tableObj : tablesObj) {
1373         errCode = ParseDistributedTable(tableObj);
1374         if (errCode != E_OK) {
1375             return errCode;
1376         }
1377     }
1378     return E_OK;
1379 }
1380 
ParseDistributedTable(const JsonObject & inJsonObject)1381 int RelationalSchemaObject::ParseDistributedTable(const JsonObject &inJsonObject)
1382 {
1383     if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::KEYWORD_DISTRIBUTED_TABLE_NAME})) {
1384         return E_OK;
1385     }
1386 
1387     FieldValue fieldValue;
1388     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_TABLE_NAME,
1389         FieldType::LEAF_FIELD_STRING, true, fieldValue);
1390     if (errCode != E_OK) {
1391         return errCode;
1392     }
1393     DistributedTable table;
1394     table.tableName = fieldValue.stringValue;
1395     errCode = ParseDistributedFields(inJsonObject, table.fields);
1396     if (errCode != E_OK) {
1397         return errCode;
1398     }
1399     dbSchema_.tables.push_back(std::move(table));
1400     return E_OK;
1401 }
1402 
ParseDistributedFields(const JsonObject & inJsonObject,std::vector<DistributedField> & fields)1403 int RelationalSchemaObject::ParseDistributedFields(const JsonObject &inJsonObject,
1404     std::vector<DistributedField> &fields)
1405 {
1406     if (!inJsonObject.IsFieldPathExist(FieldPath {SchemaConstant::KEYWORD_DISTRIBUTED_FIELD})) {
1407         return E_OK;
1408     }
1409 
1410     std::vector<JsonObject> fieldsObj;
1411     int errCode = SchemaUtils::ExtractJsonObjArray(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_FIELD, fieldsObj);
1412     if (errCode != E_OK) {
1413         return errCode;
1414     }
1415 
1416     for (const auto &fieldObj : fieldsObj) {
1417         DistributedField field;
1418         errCode = ParseDistributedField(fieldObj, field);
1419         if (errCode != E_OK) {
1420             return errCode;
1421         }
1422         fields.push_back(std::move(field));
1423     }
1424     return E_OK;
1425 }
1426 
ParseDistributedField(const JsonObject & inJsonObject,DistributedField & field)1427 int RelationalSchemaObject::ParseDistributedField(const JsonObject &inJsonObject, DistributedField &field)
1428 {
1429     FieldValue fieldValue;
1430     int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_COL_NAME,
1431         FieldType::LEAF_FIELD_STRING, true, fieldValue);
1432     if (errCode != E_OK) {
1433         return errCode;
1434     }
1435     field.colName = fieldValue.stringValue;
1436     errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_IS_P2P_SYNC,
1437         FieldType::LEAF_FIELD_BOOL, true, fieldValue);
1438     if (errCode != E_OK) {
1439         return errCode;
1440     }
1441     field.isP2pSync = fieldValue.boolValue;
1442     errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_DISTRIBUTED_IS_SPECIFIED,
1443         FieldType::LEAF_FIELD_BOOL, true, fieldValue);
1444     if (errCode != E_OK) {
1445         return errCode;
1446     }
1447     field.isSpecified = fieldValue.boolValue;
1448     return E_OK;
1449 }
1450 
IsNeedSkipSyncField(const FieldInfo & fieldInfo,const std::string & tableName,bool ignoreTableNonExist) const1451 bool RelationalSchemaObject::IsNeedSkipSyncField(const FieldInfo &fieldInfo, const std::string &tableName,
1452     bool ignoreTableNonExist) const
1453 {
1454     bool splitByDevice = tableMode_ == DistributedTableMode::SPLIT_BY_DEVICE;
1455     if (splitByDevice) {
1456         return false;
1457     }
1458     auto it = tables_.find(tableName);
1459     if (it == tables_.end()) {
1460         LOGW("[RelationalSchemaObject][IsNeedSkipSyncField] Unknown table %s size %zu",
1461             DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size());
1462         return false;
1463     }
1464     auto match = std::find_if(dbSchema_.tables.begin(), dbSchema_.tables.end(),
1465         [&tableName](const DistributedTable &distributedTable) {
1466         return DBCommon::CaseInsensitiveCompare(distributedTable.tableName, tableName);
1467     });
1468     if (match == dbSchema_.tables.end()) {
1469         return !ignoreTableNonExist;
1470     }
1471     bool existDistributedPk = false;
1472     for (const auto &item : match->fields) {
1473         if (item.isSpecified && item.isP2pSync) {
1474             existDistributedPk = true;
1475             break;
1476         }
1477     }
1478     if (!existDistributedPk) {
1479         auto pks = it->second.GetPrimaryKey();
1480         for (const auto &pk : pks) {
1481             if (DBCommon::CaseInsensitiveCompare(fieldInfo.GetFieldName(), pk.second)) {
1482                 return false;
1483             }
1484         }
1485     }
1486     auto matchField = std::find_if(match->fields.begin(), match->fields.end(),
1487         [&fieldInfo](const DistributedField &distributedField) {
1488         return distributedField.isP2pSync &&
1489             DBCommon::CaseInsensitiveCompare(distributedField.colName, fieldInfo.GetFieldName());
1490     });
1491     return matchField == match->fields.end();
1492 }
1493 
GetSyncFieldInfo(const std::string & tableName,bool ignoreTableNonExist) const1494 std::vector<FieldInfo> RelationalSchemaObject::GetSyncFieldInfo(const std::string &tableName,
1495     bool ignoreTableNonExist) const
1496 {
1497     std::vector<FieldInfo> res;
1498     auto it = tables_.find(tableName);
1499     if (it == tables_.end()) {
1500         LOGW("[RelationalSchemaObject][GetSyncFieldInfo] Unknown table %s size %zu",
1501             DBCommon::StringMiddleMasking(tableName).c_str(), tableName.size());
1502         return res;
1503     }
1504     for (const auto &fieldInfo : it->second.GetFieldInfos()) {
1505         if (IsNeedSkipSyncField(fieldInfo, tableName, ignoreTableNonExist)) {
1506             continue;
1507         }
1508         res.push_back(fieldInfo);
1509     }
1510     return res;
1511 }
1512 
GetDistributedTable(const std::string & table) const1513 DistributedTable RelationalSchemaObject::GetDistributedTable(const std::string &table) const
1514 {
1515     auto match = std::find_if(dbSchema_.tables.begin(), dbSchema_.tables.end(),
1516         [&table](const DistributedTable &distributedTable) {
1517         return DBCommon::CaseInsensitiveCompare(distributedTable.tableName, table);
1518     });
1519     if (match == dbSchema_.tables.end()) {
1520         return {};
1521     }
1522     return *match;
1523 }
1524 
GetTableChangeStatus(const DistributedSchema & schema)1525 std::map<std::string, bool> RelationalSchemaObject::GetTableChangeStatus(const DistributedSchema &schema)
1526 {
1527     std::map<std::string, bool> res;
1528     std::map<std::string, std::vector<DistributedField>, CaseInsensitiveComparator> tableSchema;
1529     for (const auto &table : dbSchema_.tables) {
1530         tableSchema[table.tableName] = table.fields;
1531     }
1532     for (const auto &table : schema.tables) {
1533         if (tableSchema.find(table.tableName) == tableSchema.end()) {
1534             res[table.tableName] = true;
1535             continue;
1536         }
1537         if (CheckDistributedFieldChange(tableSchema[table.tableName], table.fields)) {
1538             res[table.tableName] = true;
1539             continue;
1540         }
1541     }
1542     return res;
1543 }
1544 }
1545 #endif