• 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 
16 #include "sqlite_single_ver_database_upgrader.h"
17 #include "db_errno.h"
18 #include "log_print.h"
19 #include "version.h"
20 #include "db_constant.h"
21 #include "platform_specific.h"
22 #include "param_check_utils.h"
23 #include "res_finalizer.h"
24 #include "runtime_context.h"
25 #include "sqlite_single_ver_storage_executor_sql.h"
26 
27 namespace DistributedDB {
28 namespace {
29     const constexpr char *CREATE_LOCAL_TABLE_SQL =
30         "CREATE TABLE IF NOT EXISTS local_data(" \
31             "key BLOB PRIMARY KEY," \
32             "value BLOB," \
33             "timestamp INT," \
34             "hash_key BLOB);";
35 
36     const constexpr char *CREATE_SYNC_TABLE_SQL =
37         "CREATE TABLE IF NOT EXISTS sync_data(" \
38             "key         BLOB NOT NULL," \
39             "value       BLOB," \
40             "timestamp   INT  NOT NULL," \
41             "flag        INT  NOT NULL," \
42             "device      BLOB," \
43             "ori_device  BLOB," \
44             "hash_key    BLOB PRIMARY KEY NOT NULL," \
45             "w_timestamp INT," \
46             "modify_time INT DEFAULT 0," \
47             "create_time INT DEFAULT 0" \
48             ");";
49 
50     const constexpr char *CREATE_META_TABLE_SQL =
51         "CREATE TABLE IF NOT EXISTS meta_data("  \
52             "key    BLOB PRIMARY KEY  NOT NULL," \
53             "value  BLOB);";
54 
55     const constexpr char *CREATE_SINGLE_META_TABLE_SQL =
56         "CREATE TABLE IF NOT EXISTS meta.meta_data("  \
57             "key    BLOB PRIMARY KEY  NOT NULL," \
58             "value  BLOB);";
59 
60     const constexpr char *CREATE_SYNC_TABLE_INDEX_SQL_KEY_INDEX =
61         "CREATE INDEX IF NOT EXISTS key_index ON sync_data (key, flag);";
62 
63     const constexpr char *CREATE_SYNC_TABLE_INDEX_SQL_TIME_INDEX =
64         "CREATE INDEX IF NOT EXISTS time_index ON sync_data (timestamp);";
65 
66     const constexpr char *CREATE_SYNC_TABLE_INDEX_SQL_DEV_INDEX =
67         "CREATE INDEX IF NOT EXISTS dev_index ON sync_data (device);";
68 
69     const constexpr char *CREATE_SYNC_TABLE_INDEX_SQL_LOCAL_HASHKEY_INDEX =
70         "CREATE INDEX IF NOT EXISTS local_hashkey_index ON local_data (hash_key);";
71 
72     const constexpr char *DROP_META_TABLE_SQL = "DROP TABLE IF EXISTS main.meta_data;";
73     const constexpr char *COPY_META_TABLE_SQL = "INSERT OR REPLACE INTO meta.meta_data SELECT * FROM meta_data "
74         "where (SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='main.meta_data') > 0;";
75 }
76 
SQLiteSingleVerDatabaseUpgrader(sqlite3 * db,const SecurityOption & secopt,bool isMemDb)77 SQLiteSingleVerDatabaseUpgrader::SQLiteSingleVerDatabaseUpgrader(sqlite3 *db,
78     const SecurityOption &secopt, bool isMemDb)
79     : db_(db),
80       secOpt_(secopt),
81       isMemDB_(isMemDb),
82       isMetaUpgrade_(false)
83 {
84 }
85 
~SQLiteSingleVerDatabaseUpgrader()86 SQLiteSingleVerDatabaseUpgrader::~SQLiteSingleVerDatabaseUpgrader()
87 {
88     db_ = nullptr;
89 }
90 
TransferDatabasePath(const std::string & parentDir,const OpenDbProperties & option)91 int SQLiteSingleVerDatabaseUpgrader::TransferDatabasePath(const std::string &parentDir,
92     const OpenDbProperties &option)
93 {
94     std::string dbFilePath = parentDir + "/" + DBConstant::SINGLE_VER_DATA_STORE + DBConstant::DB_EXTENSION;
95     std::string upgradeLockFile = parentDir + "/" + DBConstant::UPGRADE_POSTFIX;
96 
97     if (OS::CheckPathExistence(upgradeLockFile)) {
98         return MoveDatabaseToNewDir(parentDir, upgradeLockFile);
99     }
100     if (OS::CheckPathExistence(dbFilePath)) {
101         int currentVersion = 0;
102         int errCode = GetDbVersion(dbFilePath, option, currentVersion);
103         if (errCode != E_OK) {
104             LOGE("[SQLiteSinVerUp] Get version of old database failed");
105             return errCode;
106         }
107         if (currentVersion == 0) {
108             LOGI("The database file has not been initialized, maybe invalid database");
109             if (OS::RemoveFile(dbFilePath) != E_OK) {
110                 LOGE("[SQLiteSinVerUp] Remove the uninitialized database failed, errno[%d]", errno);
111                 return -E_SYSTEM_API_FAIL;
112             }
113         }
114         if (currentVersion >= SINGLE_VER_STORE_VERSION_V1 && currentVersion <= SINGLE_VER_STORE_VERSION_V2) {
115             LOGI("[SQLiteSinVerUp] Old version[%d] database exists.", currentVersion);
116             if (OS::CreateFileByFileName(upgradeLockFile) != E_OK) {
117                 return -E_SYSTEM_API_FAIL;
118             }
119             return MoveDatabaseToNewDir(parentDir, upgradeLockFile);
120         }
121     }
122     return E_OK;
123 }
124 
BeginUpgrade()125 int SQLiteSingleVerDatabaseUpgrader::BeginUpgrade()
126 {
127     return SQLiteUtils::BeginTransaction(db_, TransactType::IMMEDIATE);
128 }
129 
EndUpgrade(bool isSuccess)130 int SQLiteSingleVerDatabaseUpgrader::EndUpgrade(bool isSuccess)
131 {
132     if (isSuccess) {
133         return SQLiteUtils::CommitTransaction(db_);
134     } else {
135         int errCode = SQLiteUtils::RollbackTransaction(db_);
136         std::string secOptUpgradeFile = subDir_ + "/" + DBConstant::SET_SECOPT_POSTFIX;
137         if (errCode == E_OK && OS::CheckPathExistence(secOptUpgradeFile) &&
138             (OS::RemoveFile(secOptUpgradeFile) != E_OK)) {
139             LOGW("[EndUpgrade] Delete secure upgrade file failed");
140             return -E_SYSTEM_API_FAIL;
141         }
142         return errCode;
143     }
144 }
145 
GetDatabaseVersion(int & version) const146 int SQLiteSingleVerDatabaseUpgrader::GetDatabaseVersion(int &version) const
147 {
148     return SQLiteUtils::GetVersion(db_, version);
149 }
150 
SetDatabaseVersion(int version)151 int SQLiteSingleVerDatabaseUpgrader::SetDatabaseVersion(int version)
152 {
153     return SQLiteUtils::SetUserVer(db_, version);
154 }
155 
SetUpgradeSqls(int version,std::vector<std::string> & sqls,bool & isCreateUpgradeFile) const156 void SQLiteSingleVerDatabaseUpgrader::SetUpgradeSqls(int version, std::vector<std::string> &sqls,
157     bool &isCreateUpgradeFile) const
158 {
159     if (version == 0) { // no write version.
160         if ((!isMemDB_) && ParamCheckUtils::IsS3SECEOpt(secOpt_)) {
161             sqls = {
162                 CREATE_LOCAL_TABLE_SQL,
163                 CREATE_SINGLE_META_TABLE_SQL,
164                 CREATE_SYNC_TABLE_SQL,
165                 CREATE_SYNC_TABLE_INDEX_SQL_KEY_INDEX,
166                 CREATE_SYNC_TABLE_INDEX_SQL_TIME_INDEX,
167                 CREATE_SYNC_TABLE_INDEX_SQL_DEV_INDEX,
168                 CREATE_SYNC_TABLE_INDEX_SQL_LOCAL_HASHKEY_INDEX
169             };
170         } else {
171             sqls = {
172                 CREATE_LOCAL_TABLE_SQL,
173                 CREATE_META_TABLE_SQL,
174                 CREATE_SYNC_TABLE_SQL,
175                 CREATE_SYNC_TABLE_INDEX_SQL_KEY_INDEX,
176                 CREATE_SYNC_TABLE_INDEX_SQL_TIME_INDEX,
177                 CREATE_SYNC_TABLE_INDEX_SQL_DEV_INDEX,
178                 CREATE_SYNC_TABLE_INDEX_SQL_LOCAL_HASHKEY_INDEX
179             };
180         }
181     } else {
182         if (version <= SINGLE_VER_STORE_VERSION_V1) {
183             sqls = {
184                 "DROP INDEX key_index;",
185                 "CREATE INDEX IF NOT EXISTS key_index ON sync_data (key, flag);",
186                 "ALTER TABLE sync_data ADD w_timestamp INT;",
187                 "UPDATE sync_data SET w_timestamp=timestamp;",
188                 "ALTER TABLE local_data ADD timestamp INT;",
189                 "ALTER TABLE local_data ADD hash_key BLOB;",
190                 "UPDATE local_data SET hash_key=calc_hash_key(key), timestamp=0;",
191                 "CREATE INDEX IF NOT EXISTS local_hashkey_index ON local_data (hash_key);"
192             };
193         }
194         if ((version <= SINGLE_VER_STORE_VERSION_V2 && ParamCheckUtils::IsS3SECEOpt(secOpt_)) ||
195             (version >= SINGLE_VER_STORE_VERSION_V3 && isMetaUpgrade_ == true)) {
196             sqls.emplace_back(CREATE_SINGLE_META_TABLE_SQL);
197             sqls.emplace_back(COPY_META_TABLE_SQL);
198             sqls.emplace_back(DROP_META_TABLE_SQL);
199             isCreateUpgradeFile = true;
200         }
201         if (version < SINGLE_VER_STORE_VERSION_V4) {
202             sqls.emplace_back("ALTER TABLE sync_data ADD modify_time INT DEFAULT 0");
203             sqls.emplace_back("ALTER TABLE sync_data ADD create_time INT DEFAULT 0");
204         }
205     }
206 }
207 
UpgradeFromDatabaseVersion(int version)208 int SQLiteSingleVerDatabaseUpgrader::UpgradeFromDatabaseVersion(int version)
209 {
210     std::vector<std::string> sqls;
211     bool isCreateUpgradeFile = false;
212     LOGI("[SqlSingleUp] metaSplit[%d], secLabel[%d], secFlag[%d], version[%d]",
213         isMetaUpgrade_, secOpt_.securityLabel, secOpt_.securityFlag, version);
214     SetUpgradeSqls(version, sqls, isCreateUpgradeFile);
215     for (const auto &item : sqls) {
216         int errCode = SQLiteUtils::ExecuteRawSQL(db_, item);
217         if (errCode != E_OK) {
218             LOGE("[SqlSingleUp][UpFrom] Execute upgrade sql failed:%d", errCode);
219             return errCode;
220         }
221     }
222     InitTimeForUpgrade(version);
223     if (isCreateUpgradeFile) {
224         std::string secOptUpgradeFile = subDir_ + "/" + DBConstant::SET_SECOPT_POSTFIX;
225         if (!OS::CheckPathExistence(secOptUpgradeFile) && (OS::CreateFileByFileName(secOptUpgradeFile) != E_OK)) {
226             LOGE("[SqlSingleUp][UpFrom] Create s3sece flag file failed");
227             return -E_SYSTEM_API_FAIL;
228         }
229         LOGD("[SqlSingleUp][UpFrom] Create s3sece mark file success");
230     }
231     return E_OK;
232 }
233 
GetDbVersion(const std::string & dbPath,const OpenDbProperties & option,int & version)234 int SQLiteSingleVerDatabaseUpgrader::GetDbVersion(const std::string &dbPath, const OpenDbProperties &option,
235     int &version)
236 {
237     OpenDbProperties optionTmp(option);
238     optionTmp.uri = dbPath;
239     sqlite3 *db = nullptr;
240     int errCode = SQLiteUtils::OpenDatabase(optionTmp, db);
241     if (errCode != E_OK) {
242         return errCode;
243     }
244     errCode = SQLiteUtils::GetVersion(db, version);
245     (void)sqlite3_close_v2(db);
246     db = nullptr;
247     return errCode;
248 }
249 
SetMetaUpgrade(const SecurityOption & currentOpt,const SecurityOption & expectOpt,const std::string & subDir)250 void SQLiteSingleVerDatabaseUpgrader::SetMetaUpgrade(const SecurityOption &currentOpt,
251     const SecurityOption &expectOpt, const std::string &subDir)
252 {
253     std::string secOptUpgradeFile = subDir + "/" + DBConstant::SET_SECOPT_POSTFIX;
254     // the same version should upgrade while user open db with s3sece.
255     if ((!OS::CheckPathExistence(secOptUpgradeFile)) && currentOpt.securityLabel == SecurityLabel::NOT_SET &&
256         ParamCheckUtils::IsS3SECEOpt(expectOpt)) {
257         isMetaUpgrade_ = true;
258     } else {
259         isMetaUpgrade_ = false;
260     }
261 }
262 
SetSubdir(const std::string & subDir)263 void SQLiteSingleVerDatabaseUpgrader::SetSubdir(const std::string &subDir)
264 {
265     subDir_ = subDir;
266 }
267 
SetPathSecOptWithCheck(const std::string & path,const SecurityOption & secOption,const std::string & dbStore,bool isWithChecked)268 int SQLiteSingleVerDatabaseUpgrader::SetPathSecOptWithCheck(const std::string &path, const SecurityOption &secOption,
269     const std::string &dbStore, bool isWithChecked)
270 {
271     SecurityOption dbOpt;
272     std::vector<std::string> dbFilePathVec {DBConstant::DB_EXTENSION};
273     std::string dbFilePath = path + "/" + dbStore + DBConstant::DB_EXTENSION;
274     if (OS::CheckPathExistence(dbFilePath) && isWithChecked) {
275         int errCode = RuntimeContext::GetInstance()->GetSecurityOption(dbFilePath, dbOpt);
276         if (errCode != E_OK) {
277             LOGE("[SetPathSecOptWithCheck] GetSecurityOption failed:%d", errCode);
278             if (errCode == -E_NOT_SUPPORT) {
279                 dbOpt = SecurityOption();
280             } else {
281                 return errCode;
282             }
283         }
284     }
285 
286     for (const auto &item : dbFilePathVec) {
287         std::string dbItemFilePath = path + "/" + dbStore + item;
288         if (!OS::CheckPathExistence(dbItemFilePath)) {
289             continue;
290         }
291         int errCode = RuntimeContext::GetInstance()->SetSecurityOption(dbItemFilePath, secOption);
292         if (errCode != E_OK) {
293             LOGE("[SetPathSecOptWithCheck] SetSecurityOption failed.");
294             return errCode;
295         }
296     }
297     return E_OK;
298 }
299 
SetSecOption(const std::string & path,const SecurityOption & secOption,bool isWithChecked)300 int SQLiteSingleVerDatabaseUpgrader::SetSecOption(const std::string &path, const SecurityOption &secOption,
301     bool isWithChecked)
302 {
303     if (!ParamCheckUtils::CheckSecOption(secOption)) {
304         return -E_INVALID_ARGS;
305     }
306     if (secOption.securityLabel == NOT_SET) {
307         return E_OK;
308     }
309     std::string secOptUpgradeFile = path + "/" + DBConstant::SET_SECOPT_POSTFIX;
310     if (OS::CheckPathExistence(secOptUpgradeFile) && !ParamCheckUtils::IsS3SECEOpt(secOption)) {
311         LOGE("[SingleVerUp][SetSec] Security option is invalid");
312         return -E_INVALID_ARGS;
313     }
314     int errCode = E_OK;
315     if (secOption.securityLabel != NOT_SET) {
316         std::string mainDbPath = path + "/" + DBConstant::MAINDB_DIR;
317         std::string cacheDbPath = path + "/" + DBConstant::CACHEDB_DIR;
318         std::string metaDbPath = path + "/" + DBConstant::METADB_DIR;
319         errCode = SetPathSecOptWithCheck(mainDbPath, secOption, DBConstant::SINGLE_VER_DATA_STORE, isWithChecked);
320         if (errCode != E_OK) {
321             return errCode;
322         }
323         errCode = SetPathSecOptWithCheck(cacheDbPath, secOption, DBConstant::SINGLE_VER_CACHE_STORE, isWithChecked);
324         if (errCode != E_OK) {
325             LOGE("[SQLiteSingleVerDatabaseUpgrader] cacheDb SetSecurityOption failed.");
326             return errCode;
327         }
328         SecurityOption metaSecOpt;
329         metaSecOpt.securityLabel = ((secOption.securityLabel >= SecurityLabel::S2) ?
330             SecurityLabel::S2 : secOption.securityLabel);
331         errCode = SetPathSecOptWithCheck(metaDbPath, metaSecOpt, DBConstant::SINGLE_VER_META_STORE, false);
332         if (errCode != E_OK) {
333             LOGE("[SQLiteSingleVerDatabaseUpgrader] metaDb SetSecurityOption failed.");
334             return errCode;
335         }
336     }
337     if (OS::CheckPathExistence(secOptUpgradeFile) && (OS::RemoveFile(secOptUpgradeFile) != E_OK)) {
338         return -E_SYSTEM_API_FAIL;
339     }
340 
341     return errCode;
342 }
343 
MoveDatabaseToNewDir(const std::string & parentDir,const std::string & upgradeLockFile)344 int SQLiteSingleVerDatabaseUpgrader::MoveDatabaseToNewDir(const std::string &parentDir,
345     const std::string &upgradeLockFile)
346 {
347     std::vector<std::string> dbFilePathVec {DBConstant::DB_EXTENSION, ".db-wal", ".db-shm"};
348     for (const auto &item : dbFilePathVec) {
349         std::string oldDbPath = parentDir + "/" + DBConstant::SINGLE_VER_DATA_STORE + item;
350         std::string currentDbPath = parentDir + "/" + DBConstant::MAINDB_DIR + "/" +
351             DBConstant::SINGLE_VER_DATA_STORE + item;
352         if (OS::CheckPathExistence(oldDbPath)) {
353             if (OS::RenameFilePath(oldDbPath, currentDbPath) != E_OK) {
354                 LOGE("[SQLiteSinVerUp] Move database file to the new directory failed, errno:%d", errno);
355                 return -E_SYSTEM_API_FAIL;
356             }
357         }
358     }
359     int errCode = OS::RemoveFile(upgradeLockFile);
360     if (errCode != E_OK) {
361         LOGE("[SQLiteSinVerUp] Remove upgrade flag file failed, errno:%d", errno);
362     }
363     return errCode;
364 }
365 
IsValueNeedUpgrade() const366 bool SQLiteSingleVerDatabaseUpgrader::IsValueNeedUpgrade() const
367 {
368     return valueNeedUpgrade_;
369 }
370 
InitTimeForUpgrade(int version)371 void SQLiteSingleVerDatabaseUpgrader::InitTimeForUpgrade(int version)
372 {
373     if (version >= SINGLE_VER_STORE_VERSION_V4) {
374         return;
375     }
376     auto [errCode, offset] = GetLocalTimeOffset();
377     if (errCode != E_OK) {
378         // init time failed should not block upgrade
379         return;
380     }
381     UpgradeTime(offset);
382 }
383 
GetLocalTimeOffset()384 std::pair<int, TimeOffset> SQLiteSingleVerDatabaseUpgrader::GetLocalTimeOffset()
385 {
386     std::pair<int, TimeOffset> res;
387     auto &[errCode, offset] = res;
388     sqlite3_stmt *stmt = nullptr;
389     errCode = SQLiteUtils::GetStatement(db_, SELECT_META_VALUE_SQL, stmt);
390     if (errCode != E_OK) {
391         LOGW("[SQLiteSinVerUp] Prepare get meta data failed %d", errCode);
392         return res;
393     }
394     ResFinalizer finalizer([stmt]() {
395         int ret = E_OK;
396         sqlite3_stmt *sqlite3Stmt = stmt;
397         SQLiteUtils::ResetStatement(sqlite3Stmt, true, ret);
398         if (ret != E_OK) {
399             LOGW("[SQLiteSinVerUp] Finalize select stmt failed %d", ret);
400         }
401     });
402     const std::string_view localTimeOffset = DBConstant::LOCALTIME_OFFSET_KEY;
403     Key key(localTimeOffset.begin(), localTimeOffset.end());
404     errCode = SQLiteUtils::BindBlobToStatement(stmt, 1, key); // 1 is time offset
405     if (errCode != E_OK) {
406         LOGW("[SQLiteSinVerUp] Bind localTimeOffset failed %d", errCode);
407         return res;
408     }
409     errCode = SQLiteUtils::StepWithRetry(stmt, isMemDB_);
410     if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
411         errCode = -E_NOT_FOUND;
412     } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
413         LOGW("[SQLiteSinVerUp] Get meta data failed %d", errCode);
414         return res;
415     }
416     Value value;
417     errCode = SQLiteUtils::GetColumnBlobValue(stmt, 0, value);
418     if (errCode != E_OK) {
419         LOGW("[SQLiteSinVerUp] Get blob local offset failed %d", errCode);
420         return res;
421     }
422     offset = std::strtoll(std::string(value.begin(), value.end()).c_str(), nullptr, DBConstant::STR_TO_LL_BY_DEVALUE);
423     return res;
424 }
425 
UpgradeTime(TimeOffset offset)426 void SQLiteSingleVerDatabaseUpgrader::UpgradeTime(TimeOffset offset)
427 {
428     std::string addOffset;
429     if (offset < 0) {
430         addOffset = "+";
431     } else {
432         addOffset = "-";
433     }
434     addOffset += std::to_string(std::abs(offset));
435     std::string updateSQL = "UPDATE sync_data SET modify_time=timestamp" + addOffset + ", create_time=w_timestamp" +
436         addOffset + " WHERE modify_time = 0";
437     int errCode = SQLiteUtils::ExecuteRawSQL(db_, updateSQL);
438     if (errCode != E_OK) {
439         LOGE("[SQLiteSinVerUp] Upgrade time failed %d", errCode);
440     }
441 }
442 } // namespace DistributedDB
443