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