• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "table_info.h"
16 
17 #include <algorithm>
18 
19 #include "db_common.h"
20 #include "db_errno.h"
21 #include "log_print.h"
22 
23 namespace DistributedDB {
GetFieldName() const24 const std::string &FieldInfo::GetFieldName() const
25 {
26     return fieldName_;
27 }
28 
SetFieldName(const std::string & fileName)29 void FieldInfo::SetFieldName(const std::string &fileName)
30 {
31     fieldName_ = fileName;
32 }
33 
GetDataType() const34 const std::string &FieldInfo::GetDataType() const
35 {
36     return dataType_;
37 }
38 
39 namespace {
AffinityPatternHex(const std::string & ss)40 inline uint32_t AffinityPatternHex(const std::string &ss)
41 {
42     uint32_t res = 0;
43     for (const auto &c : ss) {
44         res = (res << 8) + c; // 8: shift length
45     }
46     return res;
47 }
48 
49 static uint32_t affinityTable[] = {
50     AffinityPatternHex("char"), AffinityPatternHex("clob"), AffinityPatternHex("text"),
51     AffinityPatternHex("blob"), AffinityPatternHex("real"), AffinityPatternHex("floa"),
52     AffinityPatternHex("doub"), AffinityPatternHex("int")
53 };
54 
55 enum AffinityPattern : uint32_t {
56     AFFINITY_CHAR,
57     AFFINITY_CLOB,
58     AFFINITY_TEXT,
59     AFFINITY_BLOB,
60     AFFINITY_REAL,
61     AFFINITY_FLOA,
62     AFFINITY_DOUB,
63     AFFINITY_INT,
64 };
65 }
66 
AffinityType(const std::string & dataType)67 static StorageType AffinityType(const std::string &dataType)
68 {
69     StorageType type = StorageType::STORAGE_TYPE_NULL;
70     uint32_t hex = 0;
71     for (uint32_t i = 0; i < dataType.length(); i++) {
72         hex = (hex << 8) + (std::tolower(dataType[i])); // 8: shift length
73         if (hex == affinityTable[AFFINITY_CHAR]) {
74             type = StorageType::STORAGE_TYPE_TEXT;
75         } else if (hex == affinityTable[AFFINITY_CLOB]) {
76             type = StorageType::STORAGE_TYPE_TEXT;
77         } else if (hex == affinityTable[AFFINITY_TEXT]) {
78             type = StorageType::STORAGE_TYPE_TEXT;
79         } else if (hex == affinityTable[AFFINITY_BLOB] && (type == StorageType::STORAGE_TYPE_NULL ||
80             type == StorageType::STORAGE_TYPE_REAL)) {
81             type = StorageType::STORAGE_TYPE_BLOB;
82         } else if (hex == affinityTable[AFFINITY_REAL] && type == StorageType::STORAGE_TYPE_NULL) {
83             type = StorageType::STORAGE_TYPE_REAL;
84         } else if (hex == affinityTable[AFFINITY_FLOA] && type == StorageType::STORAGE_TYPE_NULL) {
85             type = StorageType::STORAGE_TYPE_REAL;
86         } else if (hex == affinityTable[AFFINITY_DOUB] && type == StorageType::STORAGE_TYPE_NULL) {
87             type = StorageType::STORAGE_TYPE_REAL;
88         } else if ((hex & 0x00ffffff) == affinityTable[AFFINITY_INT]) { // 0x00ffffff: mask for 3 byte
89             type = StorageType::STORAGE_TYPE_INTEGER;
90         }
91     }
92     return type;
93 }
94 
SetDataType(const std::string & dataType)95 void FieldInfo::SetDataType(const std::string &dataType)
96 {
97     dataType_ = dataType;
98     std::transform(dataType_.begin(), dataType_.end(), dataType_.begin(), ::tolower);
99     storageType_ = AffinityType(dataType_);
100 }
101 
IsNotNull() const102 bool FieldInfo::IsNotNull() const
103 {
104     return isNotNull_;
105 }
106 
SetNotNull(bool isNotNull)107 void FieldInfo::SetNotNull(bool isNotNull)
108 {
109     isNotNull_ = isNotNull;
110 }
111 
HasDefaultValue() const112 bool FieldInfo::HasDefaultValue() const
113 {
114     return hasDefaultValue_;
115 }
116 
GetDefaultValue() const117 const std::string &FieldInfo::GetDefaultValue() const
118 {
119     return defaultValue_;
120 }
121 
SetDefaultValue(const std::string & value)122 void FieldInfo::SetDefaultValue(const std::string &value)
123 {
124     hasDefaultValue_ = true;
125     defaultValue_ = value;
126 }
127 
128 // convert to StorageType according "Determination Of Column Affinity"
GetStorageType() const129 StorageType FieldInfo::GetStorageType() const
130 {
131     return storageType_;
132 }
133 
SetStorageType(StorageType storageType)134 void FieldInfo::SetStorageType(StorageType storageType)
135 {
136     storageType_ = storageType;
137 }
138 
GetColumnId() const139 int FieldInfo::GetColumnId() const
140 {
141     return cid_;
142 }
143 
SetColumnId(int cid)144 void FieldInfo::SetColumnId(int cid)
145 {
146     cid_ = cid;
147 }
148 
ToAttributeString() const149 std::string FieldInfo::ToAttributeString() const
150 {
151     std::string attrStr = "\"" + fieldName_ + "\": {";
152     attrStr += "\"COLUMN_ID\":" + std::to_string(cid_) + ",";
153     attrStr += "\"TYPE\":\"" + dataType_ + "\",";
154     attrStr += "\"NOT_NULL\":" + std::string(isNotNull_ ? "true" : "false");
155     if (hasDefaultValue_) {
156         attrStr += ",";
157         attrStr += "\"DEFAULT\":\"" + defaultValue_ + "\"";
158     }
159     attrStr += "}";
160     return attrStr;
161 }
162 
CompareWithField(const FieldInfo & inField,bool isLite) const163 int FieldInfo::CompareWithField(const FieldInfo &inField, bool isLite) const
164 {
165     if (fieldName_ != inField.GetFieldName() || isNotNull_ != inField.IsNotNull()) {
166         return false;
167     }
168     if (isLite) {
169         if (storageType_ != inField.GetStorageType()) {
170             return false;
171         }
172     } else {
173         if (dataType_ != inField.GetDataType()) {
174             return false;
175         }
176     }
177     if (hasDefaultValue_ && inField.HasDefaultValue()) {
178         // lite schema only uses NULL as default value
179         return (isLite && defaultValue_ == "NULL") || defaultValue_ == inField.GetDefaultValue();
180     }
181     return hasDefaultValue_ == inField.HasDefaultValue();
182 }
183 
Empty() const184 bool FieldInfo::Empty() const
185 {
186     return fieldName_.empty();
187 }
188 
GetTableName() const189 const std::string &TableInfo::GetTableName() const
190 {
191     return tableName_;
192 }
193 
SetTableName(const std::string & tableName)194 void TableInfo::SetTableName(const std::string &tableName)
195 {
196     tableName_ = tableName;
197 }
198 
SetAutoIncrement(bool autoInc)199 void TableInfo::SetAutoIncrement(bool autoInc)
200 {
201     autoInc_ = autoInc;
202 }
203 
GetAutoIncrement() const204 bool TableInfo::GetAutoIncrement() const
205 {
206     return autoInc_;
207 }
208 
GetCreateTableSql() const209 const std::string &TableInfo::GetCreateTableSql() const
210 {
211     return sql_;
212 }
213 
SetCreateTableSql(const std::string & sql)214 void TableInfo::SetCreateTableSql(const std::string &sql)
215 {
216     sql_ = sql;
217     for (auto &c : sql_) {
218         c = static_cast<char>(std::toupper(c));
219     }
220     if (DBCommon::HasConstraint(DBCommon::TrimSpace(sql_), "AUTOINCREMENT", " ", " ,)")) {
221         autoInc_ = true;
222     }
223 }
224 
GetFields() const225 const std::map<std::string, FieldInfo> &TableInfo::GetFields() const
226 {
227     return fields_;
228 }
229 
GetFieldInfos() const230 const std::vector<FieldInfo> &TableInfo::GetFieldInfos() const
231 {
232     if (!fieldInfos_.empty() && fieldInfos_.size() == fields_.size()) {
233         return fieldInfos_;
234     }
235     fieldInfos_.resize(fields_.size());
236     if (fieldInfos_.size() != fields_.size()) {
237         LOGE("GetField error, alloc memory failed.");
238         return fieldInfos_;
239     }
240     for (const auto &entry : fields_) {
241         if (static_cast<size_t>(entry.second.GetColumnId()) >= fieldInfos_.size()) {
242             LOGE("Cid is over field size.");
243             fieldInfos_.clear();
244             return fieldInfos_;
245         }
246         fieldInfos_.at(entry.second.GetColumnId()) = entry.second;
247     }
248     return fieldInfos_;
249 }
250 
GetFieldName(uint32_t cid) const251 std::string TableInfo::GetFieldName(uint32_t cid) const
252 {
253     if (cid >= fields_.size() || GetFieldInfos().empty()) {
254         return {};
255     }
256     return GetFieldInfos().at(cid).GetFieldName();
257 }
258 
IsValid() const259 bool TableInfo::IsValid() const
260 {
261     return !tableName_.empty();
262 }
263 
AddField(const FieldInfo & field)264 void TableInfo::AddField(const FieldInfo &field)
265 {
266     fields_[field.GetFieldName()] = field;
267 }
268 
GetIndexDefine() const269 const std::map<std::string, CompositeFields> &TableInfo::GetIndexDefine() const
270 {
271     return indexDefines_;
272 }
273 
GetUniqueDefine() const274 const std::vector<CompositeFields> &TableInfo::GetUniqueDefine() const
275 {
276     return uniqueDefines_;
277 }
278 
AddIndexDefine(const std::string & indexName,const CompositeFields & indexDefine)279 void TableInfo::AddIndexDefine(const std::string &indexName, const CompositeFields &indexDefine)
280 {
281     indexDefines_[indexName] = indexDefine;
282 }
283 
SetUniqueDefine(const std::vector<CompositeFields> & uniqueDefine)284 void TableInfo::SetUniqueDefine(const std::vector<CompositeFields> &uniqueDefine)
285 {
286     uniqueDefines_ = uniqueDefine;
287     std::sort(uniqueDefines_.begin(), uniqueDefines_.end());
288 }
289 
GetPrimaryKey() const290 const std::map<int, FieldName> &TableInfo::GetPrimaryKey() const
291 {
292     return primaryKey_;
293 }
294 
GetIdentifyKey() const295 CompositeFields TableInfo::GetIdentifyKey() const
296 {
297     if (primaryKey_.size() == 1 && primaryKey_.at(0) == "rowid") {
298         if (!uniqueDefines_.empty()) {
299             return uniqueDefines_.at(0);
300         }
301     }
302     CompositeFields key;
303     for (const auto &it : primaryKey_) {
304         key.emplace_back(it.second);
305     }
306     return key;
307 }
308 
SetPrimaryKey(const std::map<int,FieldName> & key)309 void TableInfo::SetPrimaryKey(const std::map<int, FieldName> &key)
310 {
311     primaryKey_ = key;
312 }
313 
SetPrimaryKey(const FieldName & fieldName,int keyIndex)314 void TableInfo::SetPrimaryKey(const FieldName &fieldName, int keyIndex)
315 {
316     if (keyIndex <= 0) {
317         LOGW("Set primary key index %d less than or equal to 0", keyIndex);
318         return;
319     }
320 
321     primaryKey_[keyIndex - 1] = fieldName;
322 }
323 
AddFieldDefineString(std::string & attrStr) const324 void TableInfo::AddFieldDefineString(std::string &attrStr) const
325 {
326     if (fields_.empty()) {
327         return;
328     }
329     attrStr += R"("DEFINE": {)";
330     for (auto itField = fields_.begin(); itField != fields_.end(); ++itField) {
331         attrStr += itField->second.ToAttributeString();
332         if (itField != std::prev(fields_.end(), 1)) {
333             attrStr += ",";
334         }
335     }
336     attrStr += "},";
337 }
338 
AddIndexDefineString(std::string & attrStr) const339 void TableInfo::AddIndexDefineString(std::string &attrStr) const
340 {
341     if (indexDefines_.empty()) {
342         return;
343     }
344     attrStr += R"(,"INDEX": {)";
345     for (auto itIndexDefine = indexDefines_.begin(); itIndexDefine != indexDefines_.end(); ++itIndexDefine) {
346         attrStr += "\"" + (*itIndexDefine).first + "\": [\"";
347         for (auto itField = itIndexDefine->second.begin(); itField != itIndexDefine->second.end(); ++itField) {
348             attrStr += *itField;
349             if (itField != itIndexDefine->second.end() - 1) {
350                 attrStr += "\",\"";
351             }
352         }
353         attrStr += "\"]";
354         if (itIndexDefine != std::prev(indexDefines_.end(), 1)) {
355             attrStr += ",";
356         }
357     }
358     attrStr += "}";
359 }
360 
AddUniqueDefineString(std::string & attrStr) const361 void TableInfo::AddUniqueDefineString(std::string &attrStr) const
362 {
363     if (uniqueDefines_.empty()) {
364         return;
365     }
366 
367     attrStr += R"("UNIQUE":[)";
368     for (const auto &unique : uniqueDefines_) {
369         attrStr += "[";
370         for (const auto &it : unique) {
371             attrStr += "\"" + it + "\",";
372         }
373         attrStr.pop_back();
374         attrStr += "],";
375     }
376     attrStr.pop_back();
377     attrStr += "],";
378 }
379 
CompareWithTable(const TableInfo & inTableInfo,const std::string & schemaVersion) const380 int TableInfo::CompareWithTable(const TableInfo &inTableInfo, const std::string &schemaVersion) const
381 {
382     if (tableName_ != inTableInfo.GetTableName()) {
383         LOGW("[Relational][Compare] Table name is not same");
384         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
385     }
386 
387     if (primaryKey_ != inTableInfo.GetPrimaryKey()) {
388         LOGW("[Relational][Compare] Table primary key is not same");
389         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
390     }
391 
392     int fieldCompareResult = CompareWithTableFields(inTableInfo.GetFields());
393     if (fieldCompareResult == -E_RELATIONAL_TABLE_INCOMPATIBLE) {
394         LOGW("[Relational][Compare] Compare table fields with in table, %d", fieldCompareResult);
395         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
396     }
397 
398     if (schemaVersion == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2_1) {
399         int uniqueCompareResult = CompareWithTableUnique(inTableInfo.GetUniqueDefine());
400         if (uniqueCompareResult == -E_RELATIONAL_TABLE_INCOMPATIBLE) {
401             LOGW("[Relational][Compare] Compare table unique with in table, %d", fieldCompareResult);
402             return -E_RELATIONAL_TABLE_INCOMPATIBLE;
403         }
404 
405         if (autoInc_ != inTableInfo.GetAutoIncrement()) {
406             LOGW("[Relational][Compare] Compare table auto increment with in table");
407             return -E_RELATIONAL_TABLE_INCOMPATIBLE;
408         }
409     }
410 
411     int indexCompareResult = CompareWithTableIndex(inTableInfo.GetIndexDefine());
412     return (fieldCompareResult == -E_RELATIONAL_TABLE_EQUAL) ? indexCompareResult : fieldCompareResult;
413 }
414 
CompareWithTableFields(const std::map<std::string,FieldInfo> & inTableFields,bool isLite) const415 int TableInfo::CompareWithTableFields(const std::map<std::string, FieldInfo> &inTableFields, bool isLite) const
416 {
417     auto itLocal = fields_.begin();
418     auto itInTable = inTableFields.begin();
419     int errCode = -E_RELATIONAL_TABLE_EQUAL;
420     while (itLocal != fields_.end() && itInTable != inTableFields.end()) {
421         LOGD("--> field name %s", itLocal->first.c_str());
422         if (itLocal->first == itInTable->first) { // Same field
423             if (!itLocal->second.CompareWithField(itInTable->second, isLite)) { // Compare field
424                 LOGW("[Relational][Compare] Table field is incompatible"); // not compatible
425                 return -E_RELATIONAL_TABLE_INCOMPATIBLE;
426             }
427             itLocal++; // Compare next field
428         } else { // Assume local table fields is a subset of in table
429             if (itInTable->second.IsNotNull() && !itInTable->second.HasDefaultValue()) { // Upgrade field not compatible
430                 LOGW("[Relational][Compare] Table upgrade field should allowed to be empty or have default value.");
431                 return -E_RELATIONAL_TABLE_INCOMPATIBLE;
432             }
433             errCode = -E_RELATIONAL_TABLE_COMPATIBLE_UPGRADE;
434         }
435         itInTable++; // Next in table field
436     }
437 
438     if (itLocal != fields_.end()) {
439         LOGW("[Relational][Compare] Table field is missing");
440         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
441     }
442 
443     if (itInTable == inTableFields.end()) {
444         return errCode;
445     }
446 
447     while (itInTable != inTableFields.end()) {
448         if (itInTable->second.IsNotNull() && !itInTable->second.HasDefaultValue()) {
449             LOGW("[Relational][Compare] Table upgrade field should allowed to be empty or have default value.");
450             return -E_RELATIONAL_TABLE_INCOMPATIBLE;
451         }
452         itInTable++;
453     }
454     return -E_RELATIONAL_TABLE_COMPATIBLE_UPGRADE;
455 }
456 
CompareWithTableUnique(const std::vector<CompositeFields> & inTableUnique) const457 int TableInfo::CompareWithTableUnique(const std::vector<CompositeFields> &inTableUnique) const
458 {
459     if (uniqueDefines_.size() != inTableUnique.size()) {
460         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
461     }
462 
463     auto itLocal = uniqueDefines_.begin();
464     auto itInTable = inTableUnique.begin();
465     while (itLocal != uniqueDefines_.end()) {
466         if (*itLocal != *itInTable) {
467             return -E_RELATIONAL_TABLE_INCOMPATIBLE;
468         }
469         itLocal++;
470         itInTable++;
471     }
472     return -E_RELATIONAL_TABLE_EQUAL;
473 }
474 
CompareWithTableIndex(const std::map<std::string,CompositeFields> & inTableIndex) const475 int TableInfo::CompareWithTableIndex(const std::map<std::string, CompositeFields> &inTableIndex) const
476 {
477     // Index comparison results do not affect synchronization decisions
478     auto itLocal = indexDefines_.begin();
479     auto itInTable = inTableIndex.begin();
480     while (itLocal != indexDefines_.end() && itInTable != inTableIndex.end()) {
481         if (itLocal->first != itInTable->first || itLocal->second != itInTable->second) {
482             return -E_RELATIONAL_TABLE_COMPATIBLE;
483         }
484         itLocal++;
485         itInTable++;
486     }
487     return (itLocal == indexDefines_.end() && itInTable == inTableIndex.end()) ? -E_RELATIONAL_TABLE_EQUAL :
488         -E_RELATIONAL_TABLE_COMPATIBLE;
489 }
490 
491 
492 namespace {
Difference(const std::map<std::string,FieldInfo> & first,const std::map<std::string,FieldInfo> & second,std::map<std::string,FieldInfo> & orphanFst,std::map<std::string,FieldInfo> & orphanSnd,std::map<std::string,FieldInfo> & bothAppear)493 void Difference(const std::map<std::string, FieldInfo> &first, const std::map<std::string, FieldInfo> &second,
494     std::map<std::string, FieldInfo> &orphanFst, std::map<std::string, FieldInfo> &orphanSnd,
495     std::map<std::string, FieldInfo> &bothAppear)
496 {
497     auto itFirst = first.begin();
498     auto itSecond = second.begin();
499     while (itFirst != first.end()) {
500         if (itSecond == second.end()) {
501             break;
502         }
503         if (itFirst->first == itSecond->first) {
504             bothAppear.insert(*itFirst);
505             itFirst++;
506             itSecond++;
507             continue;
508         } else if (itFirst->first < itSecond->first) {
509             orphanFst.insert(*itFirst++);
510         } else {
511             orphanSnd.insert(*itSecond++);
512         }
513     }
514 
515     while (itFirst != first.end()) {
516         orphanFst.insert(*itFirst++);
517     }
518 
519     while (itSecond != second.end()) {
520         orphanSnd.insert(*itSecond++);
521     }
522 }
523 }
524 
CompareWithLiteTableFields(const std::map<std::string,FieldInfo> & liteTableFields) const525 int TableInfo::CompareWithLiteTableFields(const std::map<std::string, FieldInfo> &liteTableFields) const
526 {
527     std::map<std::string, FieldInfo> orphanLocal;
528     std::map<std::string, FieldInfo> orphanLite;
529     std::map<std::string, FieldInfo> bothAppear;
530     Difference(fields_, liteTableFields, orphanLocal, orphanLite, bothAppear);
531 
532     if (!orphanLocal.empty() && !orphanLite.empty()) {
533         LOGE("[Relational][Compare] Only one side should have upgrade fields");
534         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
535     }
536 
537     for (const auto &it : bothAppear) {
538         if (!it.second.CompareWithField(liteTableFields.at(it.first), true)) {
539             LOGE("[Relational][Compare] field is incompatible");
540             return -E_RELATIONAL_TABLE_INCOMPATIBLE;
541         }
542     }
543 
544     for (const auto &it : orphanLocal) {
545         if (it.second.IsNotNull() && !it.second.HasDefaultValue()) {
546             LOGE("[Relational][Compare] field is upgrade incompatible");
547             return -E_RELATIONAL_TABLE_INCOMPATIBLE;
548         }
549     }
550 
551     for (const auto &it : orphanLite) {
552         if (it.second.IsNotNull() && !it.second.HasDefaultValue()) {
553             LOGE("[Relational][Compare] field is upgrade incompatible");
554             return -E_RELATIONAL_TABLE_INCOMPATIBLE;
555         }
556     }
557 
558     return E_OK;
559 }
560 
CompareWithLiteSchemaTable(const TableInfo & liteTableInfo) const561 int TableInfo::CompareWithLiteSchemaTable(const TableInfo &liteTableInfo) const
562 {
563     LOGE("--> check table primary key, %d %d %d", primaryKey_.empty(), liteTableInfo.GetPrimaryKey().empty(), autoInc_);
564 
565     if (!liteTableInfo.GetPrimaryKey().empty() && (primaryKey_.at(0) != "rowid") &&
566         liteTableInfo.GetPrimaryKey() != primaryKey_) {
567         LOGE("[Relational][Compare] Table primary key is not same");
568         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
569     }
570     if (!liteTableInfo.GetPrimaryKey().empty() && (primaryKey_.at(0) == "rowid")) {
571         LOGE("[Relational][Compare] Table primary key is not same");
572         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
573     }
574     if ((liteTableInfo.GetPrimaryKey().empty() && (primaryKey_.at(0) != "rowid") && !autoInc_)) {
575         LOGE("[Relational][Compare] Table primary key is not same");
576         return -E_RELATIONAL_TABLE_INCOMPATIBLE;
577     }
578 
579     return CompareWithLiteTableFields(liteTableInfo.GetFields());
580 }
581 
ToTableInfoString(const std::string & schemaVersion) const582 std::string TableInfo::ToTableInfoString(const std::string &schemaVersion) const
583 {
584     std::string attrStr;
585     attrStr += "{";
586     attrStr += R"("NAME": ")" + tableName_ + "\",";
587     AddFieldDefineString(attrStr);
588     attrStr += R"("AUTOINCREMENT": )";
589     if (autoInc_) {
590         attrStr += "true,";
591     } else {
592         attrStr += "false,";
593     }
594     AddUniqueDefineString(attrStr);
595     if (primaryKey_.size() == 1 && schemaVersion == SchemaConstant::SCHEMA_SUPPORT_VERSION_V2) {
596         attrStr += R"("PRIMARY_KEY": ")" + primaryKey_.at(0) + "\"";
597     } else {
598         if (!primaryKey_.empty()) {
599             std::string primaryKey;
600             for (const auto &item : primaryKey_) {
601                 primaryKey += "\"" + item.second + "\",";
602             }
603             primaryKey.pop_back(); // remove the last comma
604             attrStr += R"("PRIMARY_KEY": [)" + primaryKey + "]";
605         }
606     }
607     AddIndexDefineString(attrStr);
608     attrStr += "}";
609     return attrStr;
610 }
611 
GetSchemaDefine() const612 std::map<FieldPath, SchemaAttribute> TableInfo::GetSchemaDefine() const
613 {
614     std::map<FieldPath, SchemaAttribute> schemaDefine;
615     for (const auto &[fieldName, fieldInfo] : GetFields()) {
616         FieldValue defaultValue;
617         defaultValue.stringValue = fieldInfo.GetDefaultValue();
618         schemaDefine[std::vector { fieldName }] = SchemaAttribute {
619             .type = FieldType::LEAF_FIELD_NULL,     // For relational schema, the json field type is unimportant.
620             .isIndexable = true,                    // For relational schema, all field is indexable.
621             .hasNotNullConstraint = fieldInfo.IsNotNull(),
622             .hasDefaultValue = fieldInfo.HasDefaultValue(),
623             .defaultValue = defaultValue,
624             .customFieldType = {}
625         };
626     }
627     return schemaDefine;
628 }
629 
SetTableId(int id)630 void TableInfo::SetTableId(int id)
631 {
632     id_ = id;
633 }
634 
GetTableId() const635 int TableInfo::GetTableId() const
636 {
637     return id_;
638 }
639 
Empty() const640 bool TableInfo::Empty() const
641 {
642     return tableName_.empty() || fields_.empty();
643 }
644 } // namespace DistributeDB