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