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