1 /*
2  * Copyright (c) 2022 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 
16 #include "sqlite_relational_database_upgrader.h"
17 
18 #include "cloud/cloud_storage_utils.h"
19 #include "db_common.h"
20 #include "db_constant.h"
21 #include "db_errno.h"
22 #include "log_table_manager_factory.h"
23 #include "relational_schema_object.h"
24 #include "simple_tracker_log_table_manager.h"
25 #include "sqlite_relational_utils.h"
26 
27 namespace DistributedDB {
SqliteRelationalDatabaseUpgrader(sqlite3 * db)28 SqliteRelationalDatabaseUpgrader::SqliteRelationalDatabaseUpgrader(sqlite3 *db)
29     : db_(db)
30 {}
31 
~SqliteRelationalDatabaseUpgrader()32 SqliteRelationalDatabaseUpgrader::~SqliteRelationalDatabaseUpgrader() {}
33 
Upgrade()34 int SqliteRelationalDatabaseUpgrader::Upgrade()
35 {
36     // read version first, if not newest, start transaction
37     std::string logTableVersion;
38     int errCode = SQLiteUtils::GetLogTableVersion(db_, logTableVersion);
39     if (errCode != E_OK) {
40         LOGW("[Relational][Upgrade] Get log table version return. %d", errCode);
41         return (errCode == -E_NOT_FOUND) ? E_OK : errCode;
42     }
43     if (IsNewestVersion(logTableVersion)) {
44         return E_OK;
45     }
46 
47     errCode = BeginUpgrade();
48     if (errCode != E_OK) {
49         LOGE("[Relational][Upgrade] Begin upgrade failed. err=%d", errCode);
50         return errCode;
51     }
52 
53     errCode = ExecuteUpgrade();
54     if (errCode != E_OK) {
55         LOGE("[Relational][Upgrade] Execute upgrade failed. err=%d", errCode);
56         (void)EndUpgrade(false);
57         return errCode;
58     }
59 
60     errCode = EndUpgrade(true);
61     if (errCode != E_OK) {
62         LOGE("[Relational][Upgrade] End upgrade failed. err=%d", errCode);
63     }
64     return errCode;
65 }
66 
BeginUpgrade()67 int SqliteRelationalDatabaseUpgrader::BeginUpgrade()
68 {
69     return SQLiteUtils::BeginTransaction(db_, TransactType::IMMEDIATE);
70 }
71 
ExecuteUpgrade()72 int SqliteRelationalDatabaseUpgrader::ExecuteUpgrade()
73 {
74     std::string logTableVersion;
75     int errCode = SQLiteUtils::GetLogTableVersion(db_, logTableVersion);
76     if (errCode != E_OK) {
77         LOGW("[Relational][Upgrade] Get log table version return %d", errCode);
78         return (errCode == -E_NOT_FOUND) ? E_OK : errCode;
79     }
80 
81     if (IsNewestVersion(logTableVersion)) {
82         LOGD("[Relational][UpgradeTrigger] No need upgrade.");
83         return E_OK;
84     }
85 
86     RelationalSchemaObject schemaObj;
87     RelationalSchemaObject trackerSchemaObj;
88     errCode = GetParseSchema(schemaObj, trackerSchemaObj);
89     if (errCode != E_OK) {
90         return errCode;
91     }
92 
93     errCode = UpgradeLogTable(logTableVersion, schemaObj, trackerSchemaObj);
94     if (errCode != E_OK) {
95         LOGE("[Relational][Upgrade] Upgrade log table failed, err = %d.", errCode);
96         return errCode;
97     }
98 
99     return UpgradeTrigger(logTableVersion, schemaObj, trackerSchemaObj);
100 }
101 
EndUpgrade(bool isSuccess)102 int SqliteRelationalDatabaseUpgrader::EndUpgrade(bool isSuccess)
103 {
104     if (isSuccess) {
105         return SQLiteUtils::CommitTransaction(db_);
106     }
107 
108     return SQLiteUtils::RollbackTransaction(db_);
109 }
110 
IsNewestVersion(const std::string & logTableVersion)111 bool SqliteRelationalDatabaseUpgrader::IsNewestVersion(const std::string &logTableVersion)
112 {
113     return logTableVersion == DBConstant::LOG_TABLE_VERSION_CURRENT;
114 }
115 
UpgradeTrigger(const std::string & logTableVersion,const RelationalSchemaObject & schemaObj,const RelationalSchemaObject & trackerSchemaObj)116 int SqliteRelationalDatabaseUpgrader::UpgradeTrigger(const std::string &logTableVersion,
117     const RelationalSchemaObject &schemaObj, const RelationalSchemaObject &trackerSchemaObj)
118 {
119     DistributedTableMode mode = schemaObj.GetTableMode();
120     TableInfoMap trackerTables = trackerSchemaObj.GetTrackerTables();
121     for (const auto &table : schemaObj.GetTables()) {
122         bool isExists = false;
123         int errCode = SQLiteUtils::CheckTableExists(db_, table.first, isExists);
124         if (errCode == E_OK && !isExists) {
125             LOGI("[Relational][UpgradeLogTable] table may has been deleted, skip upgrade distributed trigger.");
126             continue;
127         }
128         TableInfo tableInfo = table.second;
129         tableInfo.SetTrackerTable(trackerSchemaObj.GetTrackerTable(table.first));
130         auto manager = LogTableManagerFactory::GetTableManager(mode, tableInfo.GetTableSyncType());
131         errCode = manager->AddRelationalLogTableTrigger(db_, tableInfo, "");
132         if (errCode != E_OK) {
133             LOGE("[Relational][Upgrade] recreate distributed trigger failed. err:%d", errCode);
134             return errCode;
135         }
136         trackerTables.erase(table.first);
137     }
138     // Need to upgrade non-distributed trigger
139     auto manager = std::make_unique<SimpleTrackerLogTableManager>();
140     for (const auto &table: trackerTables) {
141         TableInfo tableInfo;
142         int ret = SQLiteRelationalUtils::AnalysisTrackerTable(db_, table.second.GetTrackerTable(), tableInfo);
143         if (ret == -E_NOT_FOUND) {
144             LOGI("[Relational][Upgrade] table may has been deleted, skip upgrade tracker trigger.");
145             continue;
146         }
147         if (ret != E_OK) {
148             LOGE("[Relational][Upgrade] analysis tracker table schema failed %d.", ret);
149             return ret;
150         }
151         ret = manager->AddRelationalLogTableTrigger(db_, tableInfo, "");
152         if (ret != E_OK) {
153             LOGE("[Relational][Upgrade] recreate trigger failed. err:%d", ret);
154             return ret;
155         }
156     }
157     LOGI("[Relational][UpgradeLogTable] recreate trigger success, ver:%s to ver:%s", logTableVersion.c_str(),
158         DBConstant::LOG_TABLE_VERSION_CURRENT);
159     return E_OK;
160 }
161 
UpgradeLogTable(const std::string & logTableVersion,const RelationalSchemaObject & schemaObj,const RelationalSchemaObject & trackerSchemaObj)162 int SqliteRelationalDatabaseUpgrader::UpgradeLogTable(const std::string &logTableVersion,
163     const RelationalSchemaObject &schemaObj, const RelationalSchemaObject &trackerSchemaObj)
164 {
165     TableInfoMap trackerTables = trackerSchemaObj.GetTrackerTables();
166     for (const auto &table : schemaObj.GetTables()) {
167         int errCode = UpgradeLogBaseOnVersion(logTableVersion, table.first);
168         if (errCode != E_OK) {
169             LOGE("[Relational][UpgradeLogTable] upgrade distributed log table failed. err:%d", errCode);
170             return errCode;
171         }
172         trackerTables.erase(table.first);
173     }
174     // Need to upgrade non-distributed log table
175     for (const auto &table: trackerTables) {
176         int errCode = UpgradeLogBaseOnVersion(logTableVersion, table.first);
177         if (errCode != E_OK) {
178             LOGE("[Relational][UpgradeLogTable] upgrade tracker log table failed. err:%d", errCode);
179             return errCode;
180         }
181     }
182     LOGI("[Relational][UpgradeLogTable] success, ver:%s to ver:%s", logTableVersion.c_str(),
183         DBConstant::LOG_TABLE_VERSION_CURRENT);
184     return E_OK;
185 }
186 
UpgradeLogBaseOnVersion(const std::string & oldVersion,const std::string & tableName)187 int SqliteRelationalDatabaseUpgrader::UpgradeLogBaseOnVersion(const std::string &oldVersion,
188     const std::string &tableName)
189 {
190     std::string logName = DBCommon::GetLogTableName(tableName);
191     TableInfo tableInfo;
192     tableInfo.SetTableName(logName);
193     int errCode = SQLiteUtils::AnalysisSchemaFieldDefine(db_, logName, tableInfo);
194     if (errCode == E_OK && tableInfo.Empty()) {
195         LOGI("[Relational][UpgradeLogTable] table may has been deleted, skip upgrade log table.");
196         return E_OK;
197     }
198     if (errCode != E_OK) {
199         return errCode;
200     }
201     std::vector<std::string> addColSqlVec;
202     if (oldVersion < DBConstant::LOG_TABLE_VERSION_3) {
203         SQLiteRelationalUtils::AddUpgradeSqlToList(tableInfo, { { "cloud_gid", "text" } }, addColSqlVec);
204     }
205     if (oldVersion < DBConstant::LOG_TABLE_VERSION_5_1) {
206         SQLiteRelationalUtils::AddUpgradeSqlToList(tableInfo, { { "extend_field", "blob" },
207             { "cursor", "int" }, { "version", "text" } }, addColSqlVec);
208     }
209     if (oldVersion < DBConstant::LOG_TABLE_VERSION_5_3) {
210         SQLiteRelationalUtils::AddUpgradeSqlToList(tableInfo, { { "sharing_resource", "text" } }, addColSqlVec);
211     }
212     if (oldVersion < DBConstant::LOG_TABLE_VERSION_5_5) {
213         SQLiteRelationalUtils::AddUpgradeSqlToList(tableInfo, { { "status", "int default 0" } }, addColSqlVec);
214     }
215     if (oldVersion < DBConstant::LOG_TABLE_VERSION_5_8) {
216         addColSqlVec.push_back(CloudStorageUtils::GetCursorUpgradeSql(tableName));
217     }
218     for (size_t i = 0; i < addColSqlVec.size(); ++i) {
219         errCode = SQLiteUtils::ExecuteRawSQL(db_, addColSqlVec[i]);
220         if (errCode != E_OK) {
221             LOGE("[Relational][UpgradeLogTable] add column failed. err:%d, index:%zu, curVer:%s, maxVer:%s", errCode,
222                  i, oldVersion.c_str(), DBConstant::LOG_TABLE_VERSION_CURRENT);
223             return errCode;
224         }
225     }
226     return errCode;
227 }
228 
GetParseSchema(RelationalSchemaObject & schemaObj,RelationalSchemaObject & trackerSchemaObj)229 int SqliteRelationalDatabaseUpgrader::GetParseSchema(RelationalSchemaObject &schemaObj,
230     RelationalSchemaObject &trackerSchemaObj)
231 {
232     // get schema from meta
233     std::string schemaDefine;
234     int errCode = SQLiteUtils::GetRelationalSchema(db_, schemaDefine);
235     if (errCode != E_OK && errCode != -E_NOT_FOUND) {
236         LOGE("[Relational][UpgradeTrigger] Get relational schema from meta return. err:%d", errCode);
237         return errCode;
238     }
239     if (errCode == -E_NOT_FOUND || schemaDefine.empty()) {
240         LOGI("[Relational][UpgradeTrigger] relational schema is empty:%d.", errCode);
241     } else {
242         errCode = schemaObj.ParseFromSchemaString(schemaDefine);
243         if (errCode != E_OK) {
244             LOGE("[Relational][UpgradeTrigger] Parse to relational schema failed. err:%d", errCode);
245             return errCode;
246         }
247     }
248 
249     std::string trackerSchemaDefine;
250     errCode = SQLiteUtils::GetRelationalSchema(db_, trackerSchemaDefine, DBConstant::RELATIONAL_TRACKER_SCHEMA_KEY);
251     if (errCode != E_OK && errCode != -E_NOT_FOUND) {
252         LOGE("[Relational][UpgradeTrigger] Get tracker schema from meta return. err:%d", errCode);
253         return errCode;
254     }
255     if (errCode == -E_NOT_FOUND || trackerSchemaDefine.empty()) {
256         LOGI("[Relational][UpgradeTrigger] tracker schema is empty:%d", errCode);
257     } else {
258         errCode = trackerSchemaObj.ParseFromTrackerSchemaString(trackerSchemaDefine);
259         if (errCode != E_OK) {
260             LOGE("[Relational][UpgradeTrigger] Parse to tracker schema failed. err:%d", errCode);
261             return errCode;
262         }
263     }
264     return E_OK;
265 }
266 } // namespace DistributedDB
267