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 return E_OK;
68 }
69
GenerateSchemaString()70 void RelationalSchemaObject::GenerateSchemaString()
71 {
72 schemaString_ = {};
73 schemaString_ += "{";
74 schemaString_ += R"("SCHEMA_VERSION":")" + schemaVersion_ + R"(",)";
75 schemaString_ += R"("SCHEMA_TYPE":"RELATIVE",)";
76 if (schemaVersion_ == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2_1) {
77 std::string modeString = tableMode_ == DistributedTableMode::COLLABORATION ?
78 SchemaConstant::KEYWORD_TABLE_COLLABORATION : SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE;
79 schemaString_ += R"("TABLE_MODE":")" + modeString + R"(",)";
80 }
81 schemaString_ += R"("TABLES":[)";
82 for (auto it = tables_.begin(); it != tables_.end(); it++) {
83 if (it != tables_.begin()) {
84 schemaString_ += ",";
85 }
86 schemaString_ += it->second.ToTableInfoString(schemaVersion_);
87 }
88 schemaString_ += R"(])";
89 schemaString_ += "}";
90 }
91
AddRelationalTable(const TableInfo & tb)92 void RelationalSchemaObject::AddRelationalTable(const TableInfo &tb)
93 {
94 tables_[tb.GetTableName()] = tb;
95 isValid_ = true;
96 if (tb.GetPrimaryKey().size() > 1) { // Table with composite primary keys
97 // Composite primary keys are supported since version 2.1
98 schemaVersion_ = SchemaConstant::SCHEMA_CURRENT_VERSION;
99 }
100 GenerateSchemaString();
101 }
102
RemoveRelationalTable(const std::string & tableName)103 void RelationalSchemaObject::RemoveRelationalTable(const std::string &tableName)
104 {
105 tables_.erase(tableName);
106 GenerateSchemaString();
107 }
108
GetTables() const109 const std::map<std::string, TableInfo> &RelationalSchemaObject::GetTables() const
110 {
111 return tables_;
112 }
113
GetTableNames() const114 std::vector<std::string> RelationalSchemaObject::GetTableNames() const
115 {
116 std::vector<std::string> tableNames;
117 for (const auto &it : tables_) {
118 tableNames.emplace_back(it.first);
119 }
120 return tableNames;
121 }
122
GetTable(const std::string & tableName) const123 TableInfo RelationalSchemaObject::GetTable(const std::string &tableName) const
124 {
125 auto it = tables_.find(tableName);
126 if (it != tables_.end()) {
127 return it->second;
128 }
129 return {};
130 }
131
GetSchemaVersion() const132 std::string RelationalSchemaObject::GetSchemaVersion() const
133 {
134 return schemaVersion_;
135 }
136
GetTableMode() const137 DistributedTableMode RelationalSchemaObject::GetTableMode() const
138 {
139 return tableMode_;
140 }
141
SetTableMode(DistributedTableMode mode)142 void RelationalSchemaObject::SetTableMode(DistributedTableMode mode)
143 {
144 tableMode_ = mode;
145 if (tableMode_ == DistributedTableMode::COLLABORATION) {
146 schemaVersion_ = SchemaConstant::SCHEMA_CURRENT_VERSION;
147 }
148 GenerateSchemaString();
149 }
150
CompareAgainstSchemaObject(const std::string & inSchemaString,std::map<std::string,int> & cmpRst) const151 int RelationalSchemaObject::CompareAgainstSchemaObject(const std::string &inSchemaString,
152 std::map<std::string, int> &cmpRst) const
153 {
154 return E_OK;
155 }
156
CompareAgainstSchemaObject(const RelationalSchemaObject & inSchemaObject,std::map<std::string,int> & cmpRst) const157 int RelationalSchemaObject::CompareAgainstSchemaObject(const RelationalSchemaObject &inSchemaObject,
158 std::map<std::string, int> &cmpRst) const
159 {
160 return E_OK;
161 }
162
163 namespace {
GetMemberFromJsonObject(const JsonObject & inJsonObject,const std::string & fieldName,FieldType expectType,bool isNecessary,FieldValue & fieldValue)164 int GetMemberFromJsonObject(const JsonObject &inJsonObject, const std::string &fieldName, FieldType expectType,
165 bool isNecessary, FieldValue &fieldValue)
166 {
167 if (!inJsonObject.IsFieldPathExist(FieldPath {fieldName})) {
168 if (isNecessary) {
169 LOGE("[RelationalSchema][Parse] Get schema %s not exist. isNecessary: %d", fieldName.c_str(), isNecessary);
170 return -E_SCHEMA_PARSE_FAIL;
171 }
172 return -E_NOT_FOUND;
173 }
174
175 FieldType fieldType;
176 int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {fieldName}, fieldType);
177 if (errCode != E_OK) {
178 LOGE("[RelationalSchema][Parse] Get schema %s fieldType failed: %d.", fieldName.c_str(), errCode);
179 return -E_SCHEMA_PARSE_FAIL;
180 }
181
182 if (fieldType != expectType) {
183 LOGE("[RelationalSchema][Parse] Expect %s fieldType %d but: %d.", fieldName.c_str(),
184 static_cast<int>(expectType), static_cast<int>(fieldType));
185 return -E_SCHEMA_PARSE_FAIL;
186 }
187
188 errCode = inJsonObject.GetFieldValueByFieldPath(FieldPath {fieldName}, fieldValue);
189 if (errCode != E_OK) {
190 LOGE("[RelationalSchema][Parse] Get schema %s value failed: %d.", fieldName.c_str(), errCode);
191 return -E_SCHEMA_PARSE_FAIL;
192 }
193 return E_OK;
194 }
195 }
196
ParseRelationalSchema(const JsonObject & inJsonObject)197 int RelationalSchemaObject::ParseRelationalSchema(const JsonObject &inJsonObject)
198 {
199 int errCode = ParseCheckSchemaVersion(inJsonObject);
200 if (errCode != E_OK) {
201 return errCode;
202 }
203 errCode = ParseCheckSchemaType(inJsonObject);
204 if (errCode != E_OK) {
205 return errCode;
206 }
207 errCode = ParseCheckTableMode(inJsonObject);
208 if (errCode != E_OK) {
209 return errCode;
210 }
211 return ParseCheckSchemaTableDefine(inJsonObject);
212 }
213
214 namespace {
IsSchemaVersionValid(const std::string & version)215 inline bool IsSchemaVersionValid(const std::string &version)
216 {
217 std::string stripedVersion = SchemaUtils::Strip(version);
218 return stripedVersion == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2 ||
219 stripedVersion == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2_1;
220 }
221 }
222
ParseCheckSchemaVersion(const JsonObject & inJsonObject)223 int RelationalSchemaObject::ParseCheckSchemaVersion(const JsonObject &inJsonObject)
224 {
225 FieldValue fieldValue;
226 int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_SCHEMA_VERSION,
227 FieldType::LEAF_FIELD_STRING, true, fieldValue);
228 if (errCode != E_OK) {
229 return errCode;
230 }
231
232 if (IsSchemaVersionValid(fieldValue.stringValue)) {
233 schemaVersion_ = fieldValue.stringValue;
234 return E_OK;
235 }
236
237 LOGE("[RelationalSchema][Parse] Unexpected SCHEMA_VERSION=%s.", fieldValue.stringValue.c_str());
238 return -E_SCHEMA_PARSE_FAIL;
239 }
240
ParseCheckSchemaType(const JsonObject & inJsonObject)241 int RelationalSchemaObject::ParseCheckSchemaType(const JsonObject &inJsonObject)
242 {
243 FieldValue fieldValue;
244 int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_SCHEMA_TYPE,
245 FieldType::LEAF_FIELD_STRING, true, fieldValue);
246 if (errCode != E_OK) {
247 return errCode;
248 }
249
250 if (SchemaUtils::Strip(fieldValue.stringValue) != SchemaConstant::KEYWORD_TYPE_RELATIVE) {
251 LOGE("[RelationalSchema][Parse] Unexpected SCHEMA_TYPE=%s.", fieldValue.stringValue.c_str());
252 return -E_SCHEMA_PARSE_FAIL;
253 }
254 schemaType_ = SchemaType::RELATIVE;
255 return E_OK;
256 }
257
258 namespace {
IsTableModeValid(const std::string & mode)259 inline bool IsTableModeValid(const std::string &mode)
260 {
261 std::string stripedMode = SchemaUtils::Strip(mode);
262 return stripedMode == SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE ||
263 stripedMode == SchemaConstant::KEYWORD_TABLE_COLLABORATION;
264 }
265 }
266
ParseCheckTableMode(const JsonObject & inJsonObject)267 int RelationalSchemaObject::ParseCheckTableMode(const JsonObject &inJsonObject)
268 {
269 if (schemaVersion_ == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2) {
270 return E_OK; // version 2 has no table mode, no parsing required
271 }
272
273 FieldValue fieldValue;
274 int errCode = GetMemberFromJsonObject(inJsonObject, SchemaConstant::KEYWORD_TABLE_MODE,
275 FieldType::LEAF_FIELD_STRING, true, fieldValue);
276 if (errCode != E_OK) {
277 return errCode;
278 }
279
280 if (!IsTableModeValid(fieldValue.stringValue)) {
281 LOGE("[RelationalSchema][Parse] Unexpected TABLE_MODE=%s.", fieldValue.stringValue.c_str());
282 return -E_SCHEMA_PARSE_FAIL;
283 }
284
285 tableMode_ = SchemaUtils::Strip(fieldValue.stringValue) == SchemaConstant::KEYWORD_TABLE_SPLIT_DEVICE ?
286 DistributedDB::SPLIT_BY_DEVICE : DistributedTableMode::COLLABORATION;
287 return E_OK;
288 }
289
ParseCheckSchemaTableDefine(const JsonObject & inJsonObject)290 int RelationalSchemaObject::ParseCheckSchemaTableDefine(const JsonObject &inJsonObject)
291 {
292 FieldType fieldType;
293 int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {SchemaConstant::KEYWORD_SCHEMA_TABLE}, fieldType);
294 if (errCode != E_OK) {
295 LOGE("[RelationalSchema][Parse] Get schema TABLES fieldType failed: %d.", errCode);
296 return -E_SCHEMA_PARSE_FAIL;
297 }
298 if (FieldType::LEAF_FIELD_ARRAY != fieldType) {
299 LOGE("[RelationalSchema][Parse] Expect TABLES fieldType ARRAY but %s.",
300 SchemaUtils::FieldTypeString(fieldType).c_str());
301 return -E_SCHEMA_PARSE_FAIL;
302 }
303 std::vector<JsonObject> tables;
304 errCode = inJsonObject.GetObjectArrayByFieldPath(FieldPath{SchemaConstant::KEYWORD_SCHEMA_TABLE}, tables);
305 if (errCode != E_OK) {
306 LOGE("[RelationalSchema][Parse] Get schema TABLES value failed: %d.", errCode);
307 return -E_SCHEMA_PARSE_FAIL;
308 }
309 for (const JsonObject &table : tables) {
310 errCode = ParseCheckTableInfo(table);
311 if (errCode != E_OK) {
312 LOGE("[RelationalSchema][Parse] Parse schema TABLES failed: %d.", errCode);
313 return -E_SCHEMA_PARSE_FAIL;
314 }
315 }
316 return E_OK;
317 }
318
ParseCheckTableInfo(const JsonObject & inJsonObject)319 int RelationalSchemaObject::ParseCheckTableInfo(const JsonObject &inJsonObject)
320 {
321 TableInfo resultTable;
322 int errCode = ParseCheckTableName(inJsonObject, resultTable);
323 if (errCode != E_OK) {
324 return errCode;
325 }
326 errCode = ParseCheckTableDefine(inJsonObject, resultTable);
327 if (errCode != E_OK) {
328 return errCode;
329 }
330 errCode = ParseCheckTableAutoInc(inJsonObject, resultTable);
331 if (errCode != E_OK) {
332 return errCode;
333 }
334 errCode = ParseCheckTablePrimaryKey(inJsonObject, resultTable);
335 if (errCode != E_OK) {
336 return errCode;
337 }
338 errCode = ParseCheckTableIndex(inJsonObject, resultTable);
339 if (errCode != E_OK) {
340 return errCode;
341 }
342 errCode = ParseCheckTableUnique(inJsonObject, resultTable);
343 if (errCode != E_OK) {
344 return errCode;
345 }
346 tables_[resultTable.GetTableName()] = resultTable;
347 return E_OK;
348 }
349
ParseCheckTableName(const JsonObject & inJsonObject,TableInfo & resultTable)350 int RelationalSchemaObject::ParseCheckTableName(const JsonObject &inJsonObject, TableInfo &resultTable)
351 {
352 FieldValue fieldValue;
353 int errCode = GetMemberFromJsonObject(inJsonObject, "NAME", FieldType::LEAF_FIELD_STRING,
354 true, fieldValue);
355 if (errCode == E_OK) {
356 if (!DBCommon::CheckIsAlnumAndUnderscore(fieldValue.stringValue)) {
357 LOGE("[RelationalSchema][Parse] Invalid characters in table name, err=%d.", errCode);
358 return -E_SCHEMA_PARSE_FAIL;
359 }
360 resultTable.SetTableName(fieldValue.stringValue);
361 }
362 return errCode;
363 }
364
ParseCheckTableDefine(const JsonObject & inJsonObject,TableInfo & resultTable)365 int RelationalSchemaObject::ParseCheckTableDefine(const JsonObject &inJsonObject, TableInfo &resultTable)
366 {
367 std::map<FieldPath, FieldType> tableFields;
368 int errCode = inJsonObject.GetSubFieldPathAndType(FieldPath {"DEFINE"}, tableFields);
369 if (errCode != E_OK) {
370 LOGE("[RelationalSchema][Parse] Get schema TABLES DEFINE failed: %d.", errCode);
371 return -E_SCHEMA_PARSE_FAIL;
372 }
373
374 for (const auto &field : tableFields) {
375 if (field.second != FieldType::INTERNAL_FIELD_OBJECT) {
376 LOGE("[RelationalSchema][Parse] Expect schema TABLES DEFINE fieldType INTERNAL OBJECT but : %s.",
377 SchemaUtils::FieldTypeString(field.second).c_str());
378 return -E_SCHEMA_PARSE_FAIL;
379 }
380
381 JsonObject fieldObj;
382 errCode = inJsonObject.GetObjectByFieldPath(field.first, fieldObj);
383 if (errCode != E_OK) {
384 LOGE("[RelationalSchema][Parse] Get table field object failed. %d", errCode);
385 return errCode;
386 }
387
388 if (!DBCommon::CheckIsAlnumAndUnderscore(field.first[1])) {
389 LOGE("[RelationalSchema][Parse] Invalid characters in field name, err=%d.", errCode);
390 return -E_SCHEMA_PARSE_FAIL;
391 }
392
393 FieldInfo fieldInfo;
394 fieldInfo.SetFieldName(field.first[1]); // 1 : table name element in path
395 errCode = ParseCheckTableFieldInfo(fieldObj, field.first, fieldInfo);
396 if (errCode != E_OK) {
397 LOGE("[RelationalSchema][Parse] Parse table field info failed. %d", errCode);
398 return -E_SCHEMA_PARSE_FAIL;
399 }
400 resultTable.AddField(fieldInfo);
401 }
402 return E_OK;
403 }
404
ParseCheckTableFieldInfo(const JsonObject & inJsonObject,const FieldPath & path,FieldInfo & field)405 int RelationalSchemaObject::ParseCheckTableFieldInfo(const JsonObject &inJsonObject, const FieldPath &path,
406 FieldInfo &field)
407 {
408 FieldValue fieldValue;
409 int errCode = GetMemberFromJsonObject(inJsonObject, "COLUMN_ID", FieldType::LEAF_FIELD_INTEGER, true, fieldValue);
410 if (errCode != E_OK) {
411 return errCode;
412 }
413 field.SetColumnId(fieldValue.integerValue);
414
415 errCode = GetMemberFromJsonObject(inJsonObject, "TYPE", FieldType::LEAF_FIELD_STRING, true, fieldValue);
416 if (errCode != E_OK) {
417 return errCode;
418 }
419 field.SetDataType(fieldValue.stringValue);
420
421 errCode = GetMemberFromJsonObject(inJsonObject, "NOT_NULL", FieldType::LEAF_FIELD_BOOL, true, fieldValue);
422 if (errCode != E_OK) {
423 return errCode;
424 }
425 field.SetNotNull(fieldValue.boolValue);
426
427 errCode = GetMemberFromJsonObject(inJsonObject, "DEFAULT", FieldType::LEAF_FIELD_STRING, false, fieldValue);
428 if (errCode == E_OK) {
429 field.SetDefaultValue(fieldValue.stringValue);
430 } else if (errCode != -E_NOT_FOUND) {
431 return errCode;
432 }
433
434 return E_OK;
435 }
436
ParseCheckTableAutoInc(const JsonObject & inJsonObject,TableInfo & resultTable)437 int RelationalSchemaObject::ParseCheckTableAutoInc(const JsonObject &inJsonObject, TableInfo &resultTable)
438 {
439 FieldValue fieldValue;
440 int errCode = GetMemberFromJsonObject(inJsonObject, "AUTOINCREMENT", FieldType::LEAF_FIELD_BOOL, false, fieldValue);
441 if (errCode == E_OK) {
442 resultTable.SetAutoIncrement(fieldValue.boolValue);
443 } else if (errCode != -E_NOT_FOUND) {
444 return errCode;
445 }
446 return E_OK;
447 }
448
ParseCheckTablePrimaryKey(const JsonObject & inJsonObject,TableInfo & resultTable)449 int RelationalSchemaObject::ParseCheckTablePrimaryKey(const JsonObject &inJsonObject, TableInfo &resultTable)
450 {
451 if (!inJsonObject.IsFieldPathExist(FieldPath {"PRIMARY_KEY"})) {
452 return E_OK;
453 }
454
455 FieldType type;
456 int errCode = inJsonObject.GetFieldTypeByFieldPath(FieldPath {"PRIMARY_KEY"}, type);
457 if (errCode != E_OK) {
458 return errCode;
459 }
460
461 if (type == FieldType::LEAF_FIELD_STRING) { // Compatible with schema 2.0
462 FieldValue fieldValue;
463 errCode = GetMemberFromJsonObject(inJsonObject, "PRIMARY_KEY", FieldType::LEAF_FIELD_STRING, false, fieldValue);
464 if (errCode == E_OK) {
465 resultTable.SetPrimaryKey(fieldValue.stringValue, 1);
466 }
467 } else if (type == FieldType::LEAF_FIELD_ARRAY) {
468 CompositeFields multiPrimaryKey;
469 errCode = inJsonObject.GetStringArrayByFieldPath(FieldPath {"PRIMARY_KEY"}, multiPrimaryKey);
470 if (errCode == E_OK) {
471 int index = 1; // primary key index
472 for (const auto &item : multiPrimaryKey) {
473 resultTable.SetPrimaryKey(item, index++);
474 }
475 }
476 } else {
477 errCode = -E_SCHEMA_PARSE_FAIL;
478 }
479 return errCode;
480 }
481
ParseCheckTableIndex(const JsonObject & inJsonObject,TableInfo & resultTable)482 int RelationalSchemaObject::ParseCheckTableIndex(const JsonObject &inJsonObject, TableInfo &resultTable)
483 {
484 if (!inJsonObject.IsFieldPathExist(FieldPath {"INDEX"})) { // INDEX is not necessary
485 return E_OK;
486 }
487 std::map<FieldPath, FieldType> tableFields;
488 int errCode = inJsonObject.GetSubFieldPathAndType(FieldPath {"INDEX"}, tableFields);
489 if (errCode != E_OK) {
490 LOGE("[RelationalSchema][Parse] Get schema TABLES INDEX failed: %d.", errCode);
491 return -E_SCHEMA_PARSE_FAIL;
492 }
493
494 for (const auto &field : tableFields) {
495 if (field.second != FieldType::LEAF_FIELD_ARRAY) {
496 LOGE("[RelationalSchema][Parse] Expect schema TABLES INDEX fieldType ARRAY but : %s.",
497 SchemaUtils::FieldTypeString(field.second).c_str());
498 return -E_SCHEMA_PARSE_FAIL;
499 }
500 CompositeFields indexDefine;
501 errCode = inJsonObject.GetStringArrayByFieldPath(field.first, indexDefine);
502 if (errCode != E_OK) {
503 LOGE("[RelationalSchema][Parse] Get schema TABLES INDEX field value failed: %d.", errCode);
504 return -E_SCHEMA_PARSE_FAIL;
505 }
506 resultTable.AddIndexDefine(field.first[1], indexDefine); // 1 : second element in path
507 }
508 return E_OK;
509 }
510
ParseCheckTableUnique(const JsonObject & inJsonObject,TableInfo & resultTable)511 int RelationalSchemaObject::ParseCheckTableUnique(const JsonObject &inJsonObject, TableInfo &resultTable)
512 {
513 if (!inJsonObject.IsFieldPathExist(FieldPath {"UNIQUE"})) { // UNIQUE is not necessary
514 return E_OK;
515 }
516
517 std::vector<CompositeFields> uniques;
518 int errCode = inJsonObject.GetArrayContentOfStringOrStringArray(FieldPath {"UNIQUE"}, uniques);
519 if (errCode != E_OK) {
520 LOGE("[RelationalSchema][Parse] Get schema TABLES UNIQUE failed: %d.", errCode);
521 return -E_SCHEMA_PARSE_FAIL;
522 }
523 resultTable.SetUniqueDefine(uniques);
524 return E_OK;
525 }
526 }
527 #endif