• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023-2025 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 #define MLOG_TAG "MediaLibraryBackupUtils"
17 
18 #include "backup_database_utils.h"
19 
20 #include <fcntl.h>
21 #include <nlohmann/json.hpp>
22 #include <safe_map.h>
23 
24 #include "backup_const_column.h"
25 #include "media_file_utils.h"
26 #include "media_log.h"
27 
28 namespace OHOS {
29 namespace Media {
30 const int32_t SCALE_FACTOR = 2;
31 const int32_t SCALE_MIN_SIZE = 1080;
32 const int32_t SCALE_MAX_SIZE = 2560;
33 const int32_t UPDATE_COUNT = 200;
34 const int32_t STAMP_PARAM = 4;
35 const float SCALE_DEFAULT = 0.25;
36 const size_t MIN_GARBLE_SIZE = 2;
37 const size_t GARBLE_START = 1;
38 const size_t XY_DIMENSION = 2;
39 const size_t BYTE_LEN = 4;
40 const size_t BYTE_BASE_OFFSET = 8;
41 const size_t LANDMARKS_SIZE = 5;
42 const std::string LANDMARK_X = "x";
43 const std::string LANDMARK_Y = "y";
44 const std::string COLUMN_INTEGRITY_CHECK = "quick_check";
45 const std::string SQL_QUOTES = "\"";
46 const int32_t ARG_COUNT = 2;
47 
48 const std::vector<uint32_t> HEX_MAX = { 0xff, 0xffff, 0xffffff, 0xffffffff };
49 static SafeMap<int32_t, int32_t> fileIdOld2NewForCloudEnhancement;
50 
InitDb(std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & dbName,const std::string & dbPath,const std::string & bundleName,bool isMediaLibrary,int32_t area)51 int32_t BackupDatabaseUtils::InitDb(std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &dbName,
52     const std::string &dbPath, const std::string &bundleName, bool isMediaLibrary, int32_t area)
53 {
54     NativeRdb::RdbStoreConfig config(dbName);
55     config.SetPath(dbPath);
56     config.SetBundleName(bundleName);
57     config.SetReadConSize(CONNECT_SIZE);
58     config.SetSecurityLevel(NativeRdb::SecurityLevel::S3);
59     config.SetHaMode(NativeRdb::HAMode::MANUAL_TRIGGER);
60     config.SetAllowRebuild(true);
61     config.SetWalLimitSize(WAL_LIMIT_SIZE);
62     if (area != DEFAULT_AREA_VERSION) {
63         config.SetArea(area);
64     }
65     if (isMediaLibrary) {
66         config.SetScalarFunction("cloud_sync_func", 0, CloudSyncTriggerFunc);
67         config.SetScalarFunction("is_caller_self_func", 0, IsCallerSelfFunc);
68         config.SetScalarFunction("photo_album_notify_func", ARG_COUNT, PhotoAlbumNotifyFunc);
69         config.SetScalarFunction("begin_generate_highlight_thumbnail", STAMP_PARAM, BeginGenerateHighlightThumbnail);
70     }
71     int32_t err;
72     RdbCallback cb;
73     rdbStore = NativeRdb::RdbHelper::GetRdbStore(config, MEDIA_RDB_VERSION, cb, err);
74     return err;
75 }
76 
InitReadOnlyRdb(std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & dbName,const std::string & dbPath,const std::string & bundleName)77 int32_t BackupDatabaseUtils::InitReadOnlyRdb(std::shared_ptr<NativeRdb::RdbStore> &rdbStore,
78     const std::string &dbName, const std::string &dbPath, const std::string &bundleName)
79 {
80     NativeRdb::RdbStoreConfig config(dbName);
81     config.SetPath(dbPath);
82     config.SetBundleName(bundleName);
83     config.SetReadConSize(CONNECT_SIZE);
84     int32_t err;
85     RdbCallback cb;
86     rdbStore = NativeRdb::RdbHelper::GetRdbStore(config, MEDIA_RDB_VERSION, cb, err);
87     return err;
88 }
89 
CloudSyncTriggerFunc(const std::vector<std::string> & args)90 std::string BackupDatabaseUtils::CloudSyncTriggerFunc(const std::vector<std::string> &args)
91 {
92     return "";
93 }
94 
IsCallerSelfFunc(const std::vector<std::string> & args)95 std::string BackupDatabaseUtils::IsCallerSelfFunc(const std::vector<std::string> &args)
96 {
97     return "false";
98 }
99 
PhotoAlbumNotifyFunc(const std::vector<std::string> & args)100 std::string BackupDatabaseUtils::PhotoAlbumNotifyFunc(const std::vector<std::string> &args)
101 {
102     return "";
103 }
104 
BeginGenerateHighlightThumbnail(const std::vector<std::string> & args)105 std::string BackupDatabaseUtils::BeginGenerateHighlightThumbnail(const std::vector<std::string> &args)
106 {
107     return "";
108 }
109 
ExecSqlWithRetry(std::function<int32_t ()> execSql)110 static int32_t ExecSqlWithRetry(std::function<int32_t()> execSql)
111 {
112     int32_t currentTime = 0;
113     int32_t err = NativeRdb::E_OK;
114     while (currentTime <= MAX_TRY_TIMES) {
115         err = execSql();
116         if (err == NativeRdb::E_OK) {
117             break;
118         } else if (err == NativeRdb::E_SQLITE_LOCKED || err == NativeRdb::E_DATABASE_BUSY ||
119             err == NativeRdb::E_SQLITE_BUSY) {
120             std::this_thread::sleep_for(std::chrono::milliseconds(TRANSACTION_WAIT_INTERVAL));
121             currentTime++;
122             MEDIA_ERR_LOG("execSql busy, err: %{public}d, currentTime: %{public}d", err, currentTime);
123         } else {
124             MEDIA_ERR_LOG("execSql failed, err: %{public}d, currentTime: %{public}d", err, currentTime);
125             break;
126         }
127     }
128     return err;
129 }
130 
QueryInt(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & sql,const std::string & column,const std::vector<NativeRdb::ValueObject> & args)131 int32_t BackupDatabaseUtils::QueryInt(std::shared_ptr<NativeRdb::RdbStore> rdbStore, const std::string &sql,
132     const std::string &column, const std::vector<NativeRdb::ValueObject> &args)
133 {
134     if (rdbStore == nullptr) {
135         MEDIA_ERR_LOG("rdb_ is nullptr, Maybe init failed.");
136         return 0;
137     }
138     auto resultSet = rdbStore->QuerySql(sql, args);
139     if (resultSet == nullptr) {
140         return 0;
141     }
142     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
143         resultSet->Close();
144         return 0;
145     }
146     int32_t result = GetInt32Val(column, resultSet);
147     resultSet->Close();
148     return result;
149 }
150 
Update(std::shared_ptr<NativeRdb::RdbStore> & rdbStore,int32_t & changeRows,NativeRdb::ValuesBucket & valuesBucket,std::unique_ptr<NativeRdb::AbsRdbPredicates> & predicates)151 int32_t BackupDatabaseUtils::Update(std::shared_ptr<NativeRdb::RdbStore> &rdbStore, int32_t &changeRows,
152     NativeRdb::ValuesBucket &valuesBucket, std::unique_ptr<NativeRdb::AbsRdbPredicates> &predicates)
153 {
154     if (rdbStore == nullptr) {
155         MEDIA_ERR_LOG("rdb_ is nullptr, Maybe init failed.");
156         return E_FAIL;
157     }
158     return ExecSqlWithRetry([&]() { return rdbStore->Update(changeRows, valuesBucket, *predicates); });
159 }
160 
Delete(NativeRdb::AbsRdbPredicates & predicates,int32_t & changeRows,std::shared_ptr<NativeRdb::RdbStore> & rdbStore)161 int32_t BackupDatabaseUtils::Delete(NativeRdb::AbsRdbPredicates &predicates, int32_t &changeRows,
162     std::shared_ptr<NativeRdb::RdbStore> &rdbStore)
163 {
164     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_FAIL, "rdb is nullptr");
165     return ExecSqlWithRetry([&]() { return rdbStore->Delete(changeRows, predicates); });
166 }
167 
InitGarbageAlbum(std::shared_ptr<NativeRdb::RdbStore> galleryRdb,std::set<std::string> & cacheSet,std::unordered_map<std::string,std::string> & nickMap)168 int32_t BackupDatabaseUtils::InitGarbageAlbum(std::shared_ptr<NativeRdb::RdbStore> galleryRdb,
169     std::set<std::string> &cacheSet, std::unordered_map<std::string, std::string> &nickMap)
170 {
171     CHECK_AND_RETURN_RET_LOG(galleryRdb != nullptr, E_FAIL, "Pointer rdb_ is nullptr, Maybe init failed.");
172     const string querySql = "SELECT nick_dir, nick_name FROM garbage_album where type = 0";
173     auto resultSet = galleryRdb->QuerySql(QUERY_GARBAGE_ALBUM);
174     CHECK_AND_RETURN_RET(resultSet != nullptr, E_HAS_DB_ERROR);
175     int32_t count = -1;
176     int32_t err = resultSet->GetRowCount(count);
177     CHECK_AND_RETURN_RET_LOG(err == E_OK, E_FAIL, "Failed to get count, err: %{public}d", err);
178     MEDIA_INFO_LOG("garbageCount: %{public}d", count);
179     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
180         int32_t type;
181         resultSet->GetInt(INDEX_TYPE, type);
182         if (type == NICK) {
183             string nickName;
184             string nickDir;
185             resultSet->GetString(INDEX_NICK_DIR, nickDir);
186             resultSet->GetString(INDEX_NICK_NAME, nickName);
187             nickMap[nickDir] = nickName;
188         } else {
189             string cacheDir;
190             resultSet->GetString(INDEX_CACHE_DIR, cacheDir);
191             cacheSet.insert(cacheDir);
192         }
193     }
194     MEDIA_INFO_LOG("add map success!");
195     resultSet->Close();
196     return E_OK;
197 }
198 
QueryGalleryDuplicateDataCount(std::shared_ptr<NativeRdb::RdbStore> galleryRdb,int32_t & count,int32_t & total)199 void BackupDatabaseUtils::QueryGalleryDuplicateDataCount(std::shared_ptr<NativeRdb::RdbStore> galleryRdb,
200     int32_t &count, int32_t &total)
201 {
202     static string QUERY_GALLERY_DUPLICATE_DATA_COUNT = "SELECT count(DISTINCT _data) as count, count(1) as total"
203         " FROM gallery_media WHERE _data IN (SELECT _data FROM gallery_media GROUP BY _data HAVING count(1) > 1)";
204     auto resultSet = GetQueryResultSet(galleryRdb, QUERY_GALLERY_DUPLICATE_DATA_COUNT);
205     bool cond = (resultSet == nullptr);
206     CHECK_AND_RETURN(!cond);
207     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
208         resultSet->Close();
209         return;
210     }
211     count = GetInt32Val("count", resultSet);
212     total = GetInt32Val("total", resultSet);
213     resultSet->Close();
214 }
215 
GetQueryResultSet(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & querySql,const std::vector<std::string> & sqlArgs)216 std::shared_ptr<NativeRdb::ResultSet> BackupDatabaseUtils::GetQueryResultSet(
217     const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &querySql,
218     const std::vector<std::string> &sqlArgs)
219 {
220     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, nullptr, "rdbStore is nullptr");
221     return rdbStore->QuerySql(querySql, sqlArgs);
222 }
223 
GetColumnInfoMap(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & tableName)224 std::unordered_map<std::string, std::string> BackupDatabaseUtils::GetColumnInfoMap(
225     const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &tableName)
226 {
227     std::unordered_map<std::string, std::string> columnInfoMap;
228     std::string querySql = "SELECT name, type FROM pragma_table_info('" + tableName + "')";
229     auto resultSet = GetQueryResultSet(rdbStore, querySql);
230     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, columnInfoMap, "resultSet is nullptr");
231     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
232         std::string columnName = GetStringVal(PRAGMA_TABLE_NAME, resultSet);
233         std::string columnType = GetStringVal(PRAGMA_TABLE_TYPE, resultSet);
234         if (columnName.empty() || columnType.empty()) {
235             MEDIA_ERR_LOG("Empty column name or type: %{public}s, %{public}s", columnName.c_str(), columnType.c_str());
236             continue;
237         }
238         columnInfoMap[columnName] = columnType;
239     }
240     resultSet->Close();
241     return columnInfoMap;
242 }
243 
UpdateUniqueNumber(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,int32_t number,const std::string & type)244 void BackupDatabaseUtils::UpdateUniqueNumber(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, int32_t number,
245     const std::string &type)
246 {
247     const string updateSql =
248         "UPDATE UniqueNumber SET unique_number = " + to_string(number) + " WHERE media_type = '" + type + "'";
249     int32_t erroCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
250     CHECK_AND_PRINT_LOG(erroCode >= 0, "execute update unique number failed, ret=%{public}d", erroCode);
251 }
252 
QueryUniqueNumber(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & type)253 int32_t BackupDatabaseUtils::QueryUniqueNumber(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore,
254     const std::string &type)
255 {
256     const string querySql = "SELECT unique_number FROM UniqueNumber WHERE media_type = '" + type + "'";
257     return QueryInt(rdbStore, querySql, UNIQUE_NUMBER);
258 }
259 
GarbleInfoName(const string & infoName)260 std::string BackupDatabaseUtils::GarbleInfoName(const string &infoName)
261 {
262     std::string garbledInfoName = infoName;
263     if (infoName.size() <= MIN_GARBLE_SIZE) {
264         return garbledInfoName;
265     }
266     size_t garbledSize = infoName.size() - MIN_GARBLE_SIZE;
267     garbledInfoName.replace(GARBLE_START, garbledSize, GARBLE);
268     return garbledInfoName;
269 }
270 
UpdateSelection(std::string & selection,const std::string & selectionToAdd,bool needWrap)271 void BackupDatabaseUtils::UpdateSelection(std::string &selection, const std::string &selectionToAdd, bool needWrap)
272 {
273     CHECK_AND_RETURN(!selectionToAdd.empty());
274     std::string wrappedSelectionToAdd = needWrap ? "'" + selectionToAdd + "'" : selectionToAdd;
275     selection += selection.empty() ? wrappedSelectionToAdd : ", " + wrappedSelectionToAdd;
276 }
277 
UpdateSdWhereClause(std::string & querySql,bool shouldIncludeSd)278 void BackupDatabaseUtils::UpdateSdWhereClause(std::string &querySql, bool shouldIncludeSd)
279 {
280     if (shouldIncludeSd) {
281         return;
282     }
283     querySql += " AND " + EXCLUDE_SD;
284 }
285 
QueryThumbImage(NativeRdb::RdbStore & rdbStore,const std::string & keyValue,std::vector<uint8_t> & blob)286 bool BackupDatabaseUtils::QueryThumbImage(NativeRdb::RdbStore &rdbStore,
287     const std::string &keyValue, std::vector<uint8_t> &blob)
288 {
289     std::string query = "SELECT v FROM general_kv where k = " + SQL_QUOTES + keyValue + SQL_QUOTES +";";
290     auto resultSet = rdbStore.QueryByStep(query);
291     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, false, "Failed to QueryByStep");
292     int32_t count = -1;
293     int err = resultSet->GetRowCount(count);
294     CHECK_AND_RETURN_RET_LOG(err == E_OK, false,
295         "Failed to get count, err: %{public}d, %{public}s", err, query.c_str());
296     if (count != 1) {
297         MEDIA_ERR_LOG("Failed to get count: %{public}d,", count);
298         resultSet->Close();
299         return false;
300     }
301     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
302         resultSet->GetBlob(0, blob);
303     }
304     resultSet->Close();
305     return true;
306 }
307 
GetBlob(const std::string & columnName,std::shared_ptr<NativeRdb::ResultSet> resultSet,std::vector<uint8_t> & blobVal)308 int32_t BackupDatabaseUtils::GetBlob(const std::string &columnName, std::shared_ptr<NativeRdb::ResultSet> resultSet,
309     std::vector<uint8_t> &blobVal)
310 {
311     int32_t columnIndex = 0;
312     int32_t errCode = resultSet->GetColumnIndex(columnName, columnIndex);
313     CHECK_AND_RETURN_RET_LOG(!errCode, E_FAIL, "Get column index errCode: %{public}d", errCode);
314     CHECK_AND_RETURN_RET(resultSet->GetBlob(columnIndex, blobVal) == NativeRdb::E_OK, E_FAIL);
315     return E_OK;
316 }
317 
GetUint32ValFromBytes(const std::vector<uint8_t> & bytes,size_t start)318 uint32_t BackupDatabaseUtils::GetUint32ValFromBytes(const std::vector<uint8_t> &bytes, size_t start)
319 {
320     uint32_t uint32Val = 0;
321     for (size_t index = 0; index < BYTE_LEN; index++) {
322         uint32Val |= static_cast<uint32_t>(bytes[start + index]) << (index * BYTE_BASE_OFFSET);
323         uint32Val &= HEX_MAX[index];
324     }
325     return uint32Val;
326 }
327 
UpdateAnalysisTotalStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)328 void BackupDatabaseUtils::UpdateAnalysisTotalStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
329 {
330     std::string updateSql = "UPDATE tab_analysis_total SET face = CASE WHEN EXISTS \
331         (SELECT 1 FROM tab_analysis_image_face WHERE tab_analysis_image_face.file_id = tab_analysis_total.file_id \
332         AND tag_id = '-1') THEN 2 ELSE 3 END WHERE EXISTS (SELECT 1 FROM tab_analysis_image_face WHERE \
333         tab_analysis_image_face.file_id = tab_analysis_total.file_id)";
334     int32_t errCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
335     CHECK_AND_PRINT_LOG(errCode >= 0, "execute update analysis total failed, ret=%{public}d", errCode);
336 }
337 
UpdateAnalysisFaceTagStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)338 void BackupDatabaseUtils::UpdateAnalysisFaceTagStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
339 {
340     std::string updateSql = "UPDATE tab_analysis_face_tag SET count = (SELECT count(1) from tab_analysis_image_face \
341         WHERE tab_analysis_image_face.tag_id = tab_analysis_face_tag.tag_id \
342         AND tab_analysis_image_face.tag_id LIKE 'ser%')";
343     int32_t errCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
344     CHECK_AND_PRINT_LOG(errCode >= 0, "execute update analysis face tag count failed, ret=%{public}d", errCode);
345 }
346 
UpdateAnalysisTotalTblStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::vector<FileIdPair> & fileIdPair)347 void BackupDatabaseUtils::UpdateAnalysisTotalTblStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
348     const std::vector<FileIdPair>& fileIdPair)
349 {
350     auto [oldFileIds, newFileIds] = BackupDatabaseUtils::UnzipFileIdPairs(fileIdPair);
351     std::string fileIdNewFilterClause = "(" + BackupDatabaseUtils::JoinValues<int>(newFileIds, ", ") + ")";
352 
353     std::string updateSql =
354         "UPDATE tab_analysis_total "
355         "SET face = CASE "
356             "WHEN EXISTS (SELECT 1 FROM tab_analysis_image_face "
357                          "WHERE tab_analysis_image_face.file_id = tab_analysis_total.file_id "
358                          "AND tag_id = '-1') THEN 2 "
359             "WHEN EXISTS (SELECT 1 FROM tab_analysis_image_face "
360                          "WHERE tab_analysis_image_face.file_id = tab_analysis_total.file_id "
361                          "AND tag_id = '-2') THEN 4 "
362             "ELSE 3 "
363         "END "
364         "WHERE EXISTS (SELECT 1 FROM tab_analysis_image_face "
365                       "WHERE tab_analysis_image_face.file_id = tab_analysis_total.file_id) "
366         "AND " + IMAGE_FACE_COL_FILE_ID + " IN " + fileIdNewFilterClause;
367 
368     int32_t errCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
369     CHECK_AND_PRINT_LOG(errCode >= 0, "execute update analysis total failed, ret=%{public}d", errCode);
370 }
371 
UpdateFaceAnalysisTblStatus(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)372 void BackupDatabaseUtils::UpdateFaceAnalysisTblStatus(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
373 {
374     BackupDatabaseUtils::UpdateAnalysisFaceTagStatus(mediaLibraryRdb);
375 }
376 
SetTagIdNew(PortraitAlbumInfo & portraitAlbumInfo,std::unordered_map<std::string,std::string> & tagIdMap)377 bool BackupDatabaseUtils::SetTagIdNew(PortraitAlbumInfo &portraitAlbumInfo,
378     std::unordered_map<std::string, std::string> &tagIdMap)
379 {
380     portraitAlbumInfo.tagIdNew = TAG_ID_PREFIX + std::to_string(MediaFileUtils::UTCTimeNanoSeconds());
381     tagIdMap[portraitAlbumInfo.tagIdOld] = portraitAlbumInfo.tagIdNew;
382     return true;
383 }
384 
SetFileIdNew(FaceInfo & faceInfo,const std::unordered_map<std::string,FileInfo> & fileInfoMap)385 bool BackupDatabaseUtils::SetFileIdNew(FaceInfo &faceInfo, const std::unordered_map<std::string, FileInfo> &fileInfoMap)
386 {
387     bool cond = (faceInfo.hash.empty() || fileInfoMap.count(faceInfo.hash) == 0);
388     CHECK_AND_RETURN_RET_LOG(!cond, false,
389         "Set new file_id for face %{public}s failed, no such file hash", faceInfo.faceId.c_str());
390     faceInfo.fileIdNew = fileInfoMap.at(faceInfo.hash).fileIdNew;
391     CHECK_AND_RETURN_RET_LOG(faceInfo.fileIdNew > 0, false,
392         "Set new file_id for face %{public}s failed, file_id %{public}d <= 0", faceInfo.faceId.c_str(),
393         faceInfo.fileIdNew);
394     return true;
395 }
396 
SetTagIdNew(FaceInfo & faceInfo,const std::unordered_map<std::string,std::string> & tagIdMap)397 bool BackupDatabaseUtils::SetTagIdNew(FaceInfo &faceInfo, const std::unordered_map<std::string, std::string> &tagIdMap)
398 {
399     CHECK_AND_RETURN_RET_LOG(!faceInfo.tagIdOld.empty(), false,
400         "Set new tag_id for face %{public}s failed, empty tag_id", faceInfo.faceId.c_str());
401     if (tagIdMap.count(faceInfo.tagIdOld) == 0) {
402         faceInfo.tagIdNew = TAG_ID_UNPROCESSED;
403         return true;
404     }
405     faceInfo.tagIdNew = tagIdMap.at(faceInfo.tagIdOld);
406     bool cond = (faceInfo.tagIdNew.empty() || !MediaFileUtils::StartsWith(faceInfo.tagIdNew, TAG_ID_PREFIX));
407     CHECK_AND_RETURN_RET_LOG(!cond, false,
408         "Set new tag_id for face %{public}s failed, new tag_id %{public}s empty or invalid",
409         faceInfo.tagIdNew.c_str(), faceInfo.faceId.c_str());
410     return true;
411 }
412 
SetAlbumIdNew(FaceInfo & faceInfo,const std::unordered_map<std::string,int32_t> & albumIdMap)413 bool BackupDatabaseUtils::SetAlbumIdNew(FaceInfo &faceInfo, const std::unordered_map<std::string, int32_t> &albumIdMap)
414 {
415     CHECK_AND_RETURN_RET(faceInfo.tagIdNew != TAG_ID_UNPROCESSED, true);
416     CHECK_AND_RETURN_RET_LOG(albumIdMap.count(faceInfo.tagIdNew) != 0, false,
417         "Set new album_id for face %{public}s failed, no such tag_id", faceInfo.faceId.c_str());
418 
419     faceInfo.albumIdNew = albumIdMap.at(faceInfo.tagIdNew);
420     CHECK_AND_RETURN_RET_LOG(faceInfo.albumIdNew > 0, false,
421         "Set new album_id for face %{public}s failed, album_id %{public}d <= 0", faceInfo.faceId.c_str(),
422         faceInfo.albumIdNew);
423     return true;
424 }
425 
PrintErrorLog(const std::string & errorLog,int64_t start)426 void BackupDatabaseUtils::PrintErrorLog(const std::string &errorLog, int64_t start)
427 {
428     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
429     MEDIA_INFO_LOG("%{public}s, cost %{public}ld", errorLog.c_str(), (long)(end - start));
430 }
431 
GetLandmarksScale(int32_t width,int32_t height)432 float BackupDatabaseUtils::GetLandmarksScale(int32_t width, int32_t height)
433 {
434     float scale = 1;
435     int32_t minWidthHeight = width <= height ? width : height;
436     if (minWidthHeight >= SCALE_MIN_SIZE * SCALE_FACTOR) {
437         minWidthHeight = static_cast<int32_t>(minWidthHeight * SCALE_DEFAULT);
438         scale = SCALE_DEFAULT;
439         if (minWidthHeight < SCALE_MIN_SIZE) {
440             minWidthHeight *= SCALE_FACTOR;
441             scale *= SCALE_FACTOR;
442         }
443         if (minWidthHeight < SCALE_MIN_SIZE) {
444             scale = 1;
445         }
446     }
447     width = static_cast<int32_t>(width * scale);
448     height = static_cast<int32_t>(height * scale);
449     int32_t maxWidthHeight = width >= height ? width : height;
450     scale *= maxWidthHeight >= SCALE_MAX_SIZE ? static_cast<float>(SCALE_MAX_SIZE) / maxWidthHeight : 1;
451     return scale;
452 }
453 
IsLandmarkValid(const FaceInfo & faceInfo,float landmarkX,float landmarkY)454 bool BackupDatabaseUtils::IsLandmarkValid(const FaceInfo &faceInfo, float landmarkX, float landmarkY)
455 {
456     return IsValInBound(landmarkX, faceInfo.scaleX, faceInfo.scaleX + faceInfo.scaleWidth) &&
457         IsValInBound(landmarkY, faceInfo.scaleY, faceInfo.scaleY + faceInfo.scaleHeight);
458 }
459 
IsValInBound(float val,float minVal,float maxVal)460 bool BackupDatabaseUtils::IsValInBound(float val, float minVal, float maxVal)
461 {
462     return val >= minVal && val <= maxVal;
463 }
464 
GetColumnInfoPairs(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & tableName)465 std::vector<std::pair<std::string, std::string>> BackupDatabaseUtils::GetColumnInfoPairs(
466     const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &tableName)
467 {
468     std::vector<std::pair<std::string, std::string>> columnInfoPairs;
469     std::string querySql = "SELECT name, type FROM pragma_table_info('" + tableName + "')";
470     auto resultSet = GetQueryResultSet(rdbStore, querySql);
471     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, columnInfoPairs, "resultSet is nullptr");
472     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
473         std::string columnName = GetStringVal(PRAGMA_TABLE_NAME, resultSet);
474         std::string columnType = GetStringVal(PRAGMA_TABLE_TYPE, resultSet);
475         if (columnName.empty() || columnType.empty()) {
476             MEDIA_ERR_LOG("Empty column name or type: %{public}s, %{public}s", columnName.c_str(), columnType.c_str());
477             continue;
478         }
479         columnInfoPairs.emplace_back(columnName, columnType);
480     }
481 
482     resultSet->Close();
483     return columnInfoPairs;
484 }
485 
GetCommonColumnInfos(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,std::string tableName)486 std::vector<std::string> BackupDatabaseUtils::GetCommonColumnInfos(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,
487     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb, std::string tableName)
488 {
489     std::vector<std::string> commonColumns;
490     auto mediaRdbColumnInfoPairs = BackupDatabaseUtils::GetColumnInfoPairs(mediaRdb, tableName);
491     auto mediaLibraryRdbColumnInfoPairs = BackupDatabaseUtils::GetColumnInfoPairs(mediaLibraryRdb, tableName);
492 
493     for (const auto &pair : mediaRdbColumnInfoPairs) {
494         auto it = std::find_if(mediaLibraryRdbColumnInfoPairs.begin(), mediaLibraryRdbColumnInfoPairs.end(),
495             [&](const std::pair<std::string, std::string> &p) {
496                 return p.first == pair.first && p.second == pair.second;
497             });
498         if (it != mediaLibraryRdbColumnInfoPairs.end()) {
499             commonColumns.emplace_back(pair.first);
500         }
501     }
502 
503     return commonColumns;
504 }
505 
filterColumns(const std::vector<std::string> & allColumns,const std::vector<std::string> & excludedColumns)506 std::vector<std::string> BackupDatabaseUtils::filterColumns(const std::vector<std::string>& allColumns,
507     const std::vector<std::string>& excludedColumns)
508 {
509     std::vector<std::string> filteredColumns;
510     std::copy_if(allColumns.begin(), allColumns.end(), std::back_inserter(filteredColumns),
511         [&excludedColumns](const std::string& column) {
512             return std::find(excludedColumns.begin(), excludedColumns.end(), column) == excludedColumns.end();
513         });
514     return filteredColumns;
515 }
516 
UpdateAnalysisPhotoMapStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)517 void BackupDatabaseUtils::UpdateAnalysisPhotoMapStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
518 {
519     std::string insertSql =
520         "INSERT OR REPLACE INTO AnalysisPhotoMap (map_album, map_asset) "
521         "SELECT AnalysisAlbum.album_id, tab_analysis_image_face.file_id "
522         "FROM AnalysisAlbum "
523         "INNER JOIN tab_analysis_image_face ON AnalysisAlbum.tag_id = tab_analysis_image_face.tag_id";
524 
525     int32_t ret = BackupDatabaseUtils::ExecuteSQL(rdbStore, insertSql);
526     CHECK_AND_PRINT_LOG(ret >= 0, "execute update AnalysisPhotoMap failed, ret=%{public}d", ret);
527 }
528 
CollectFileIdPairs(const std::vector<FileInfo> & fileInfos)529 std::vector<FileIdPair> BackupDatabaseUtils::CollectFileIdPairs(const std::vector<FileInfo>& fileInfos)
530 {
531     std::set<FileIdPair> uniquePairs;
532 
533     for (const auto& fileInfo : fileInfos) {
534         uniquePairs.emplace(fileInfo.fileIdOld, fileInfo.fileIdNew);
535     }
536 
537     return std::vector<FileIdPair>(uniquePairs.begin(), uniquePairs.end());
538 }
539 
UnzipFileIdPairs(const std::vector<FileIdPair> & pairs)540 std::pair<std::vector<int32_t>, std::vector<int32_t>> BackupDatabaseUtils::UnzipFileIdPairs(
541     const std::vector<FileIdPair>& pairs)
542 {
543     std::vector<int32_t> oldFileIds;
544     std::vector<int32_t> newFileIds;
545 
546     for (const auto& pair : pairs) {
547         oldFileIds.push_back(pair.first);
548         newFileIds.push_back(pair.second);
549     }
550 
551     return {oldFileIds, newFileIds};
552 }
553 
SplitString(const std::string & str,char delimiter)554 std::vector<std::string> BackupDatabaseUtils::SplitString(const std::string& str, char delimiter)
555 {
556     std::vector<std::string> elements;
557     std::stringstream ss(str);
558     std::string item;
559     while (std::getline(ss, item, delimiter)) {
560         if (!item.empty()) {
561             elements.emplace_back(item);
562         }
563     }
564     return elements;
565 }
566 
PrintQuerySql(const std::string & querySql)567 void BackupDatabaseUtils::PrintQuerySql(const std::string& querySql)
568 {
569     MEDIA_INFO_LOG("Generated SQL Query:");
570     MEDIA_INFO_LOG("--------------------");
571     MEDIA_INFO_LOG("%{public}s", querySql.c_str());
572     MEDIA_INFO_LOG("--------------------");
573 }
574 
QueryLong(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & sql,const std::string & columnName,const std::vector<NativeRdb::ValueObject> & args)575 int64_t BackupDatabaseUtils::QueryLong(std::shared_ptr<NativeRdb::RdbStore> rdbStore, const std::string &sql,
576     const std::string &columnName, const std::vector<NativeRdb::ValueObject> &args)
577 {
578     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, 0, "RdbStore is null.");
579     auto resultSet = rdbStore->QuerySql(sql, args);
580     CHECK_AND_RETURN_RET(resultSet != nullptr, 0);
581     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
582         resultSet->Close();
583         return 0;
584     }
585 
586     int64_t resultValue = GetInt64Val(columnName, resultSet);
587     resultSet->Close();
588     return resultValue;
589 }
590 
QueryMaxId(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & tableName,const std::string & idColumnName)591 int64_t BackupDatabaseUtils::QueryMaxId(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
592     const std::string& tableName, const std::string& idColumnName)
593 {
594     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, 0, "RdbStore is null.");
595 
596     std::string querySql = "SELECT MAX(" + idColumnName + ") AS max_id FROM " + tableName;
597     int64_t maxId = BackupDatabaseUtils::QueryLong(rdbStore, querySql, "max_id");
598     MEDIA_INFO_LOG("QueryMaxId on table '%{public}s' column '%{public}s' return %{public}" PRId64,
599         tableName.c_str(), idColumnName.c_str(), maxId);
600 
601     return maxId;
602 }
603 
DeleteDuplicateVisionFaceTags(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::string & selectTagIdsToDeleteSql)604 static bool DeleteDuplicateVisionFaceTags(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
605     const std::string& selectTagIdsToDeleteSql)
606 {
607     CHECK_AND_RETURN_RET_LOG(!selectTagIdsToDeleteSql.empty(), true, "No tag IDs to delete.");
608 
609     std::string deleteFaceTagSql = "DELETE FROM " + VISION_FACE_TAG_TABLE +
610         " WHERE " + ANALYSIS_COL_TAG_ID + " IN (" + selectTagIdsToDeleteSql + ")";
611 
612     BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb, deleteFaceTagSql);
613     return true;
614 }
615 
UpdateVisionTotalFaceStatus(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::vector<std::string> & affectedFileIds)616 static bool UpdateVisionTotalFaceStatus(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
617     const std::vector<std::string>& affectedFileIds)
618 {
619     CHECK_AND_RETURN_RET_LOG(mediaLibraryRdb != nullptr, false, "RdbStore is null.");
620 
621     auto totalPredicates = std::make_unique<NativeRdb::AbsRdbPredicates>(VISION_TOTAL_TABLE);
622     totalPredicates->In(IMAGE_FACE_COL_FILE_ID, affectedFileIds);
623 
624     NativeRdb::ValuesBucket values;
625     values.PutInt("face", TOTAL_TBL_FACE_ANALYSED);
626     int32_t updatedRows = 0;
627     int32_t ret = BackupDatabaseUtils::Update(mediaLibraryRdb, updatedRows, values, totalPredicates);
628     if (ret < 0 || updatedRows < 0) {
629         MEDIA_ERR_LOG("Update failed on VISION_TOTAL_TABLE, ret:%{public}d", ret);
630         return false;
631     }
632 
633     return true;
634 }
635 
UpdateDuplicateVisionImageFaces(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::string & selectTagIdsToDeleteSql)636 static bool UpdateDuplicateVisionImageFaces(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
637     const std::string& selectTagIdsToDeleteSql)
638 {
639     CHECK_AND_RETURN_RET_LOG(mediaLibraryRdb != nullptr, false, "RdbStore is null.");
640     CHECK_AND_RETURN_RET_LOG(!selectTagIdsToDeleteSql.empty(), true, "No tag IDs to update.");
641 
642     std::string selectFileIdsSql = "SELECT DISTINCT " + IMAGE_FACE_COL_FILE_ID + " FROM " + VISION_IMAGE_FACE_TABLE +
643                                    " WHERE " + FACE_TAG_COL_TAG_ID + " IN (" + selectTagIdsToDeleteSql + ")";
644 
645     std::vector<std::string> affectedFileIds;
646     std::shared_ptr<NativeRdb::ResultSet> resultSet = mediaLibraryRdb->QuerySql(selectFileIdsSql);
647     if (resultSet != nullptr) {
648         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
649             std::string fileId;
650             int32_t columnIndex;
651             if (resultSet->GetColumnIndex(IMAGE_FACE_COL_FILE_ID, columnIndex) == NativeRdb::E_OK) {
652                 resultSet->GetString(columnIndex, fileId);
653                 affectedFileIds.push_back(fileId);
654             }
655         }
656     }
657 
658     std::string imageFaceUpdateWhereClause = FACE_TAG_COL_TAG_ID + " IN (" + selectTagIdsToDeleteSql + ")";
659     std::unique_ptr<NativeRdb::AbsRdbPredicates> imageFacePredicates =
660         std::make_unique<NativeRdb::AbsRdbPredicates>(VISION_IMAGE_FACE_TABLE);
661     imageFacePredicates->SetWhereClause(imageFaceUpdateWhereClause);
662 
663     NativeRdb::ValuesBucket imageFaceValues;
664     imageFaceValues.PutString(FACE_TAG_COL_TAG_ID, "-1");
665 
666     int32_t imageFaceUpdatedRows = 0;
667     int32_t ret = BackupDatabaseUtils::Update(mediaLibraryRdb,
668         imageFaceUpdatedRows, imageFaceValues, imageFacePredicates);
669     bool imageFaceUpdateFailed = (imageFaceUpdatedRows < 0 || ret < 0);
670     CHECK_AND_RETURN_RET_LOG(!imageFaceUpdateFailed, false, "Failed to update VISION_IMAGE_FACE_TABLE");
671 
672     if (!affectedFileIds.empty()) {
673         if (!UpdateVisionTotalFaceStatus(mediaLibraryRdb, affectedFileIds)) {
674             MEDIA_ERR_LOG("VISION_TOTAL_TABLE update failed");
675             return false;
676         }
677     }
678 
679     return true;
680 }
681 
DeleteDuplicateAnalysisAlbums(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::string & finalWhereClause)682 static bool DeleteDuplicateAnalysisAlbums(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
683     const std::string& finalWhereClause)
684 {
685     CHECK_AND_RETURN_RET_LOG(!finalWhereClause.empty(), false, "finalWhereClause is empty, cannot delete.");
686 
687     std::string deleteAnalysisSql = "DELETE FROM " + ANALYSIS_ALBUM_TABLE +
688         " WHERE " + finalWhereClause;
689 
690     BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb, deleteAnalysisSql);
691     return true;
692 }
693 
DeleteDuplicatePortraitAlbum(int64_t maxAlbumId,const std::vector<std::string> & albumNames,const std::vector<std::string> & tagIds,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)694 bool BackupDatabaseUtils::DeleteDuplicatePortraitAlbum(int64_t maxAlbumId, const std::vector<std::string> &albumNames,
695     const std::vector<std::string> &tagIds, std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
696 {
697     std::set<std::string> uniqueAlbums(albumNames.begin(), albumNames.end());
698     std::vector<std::string> uniqueAlbumNames(uniqueAlbums.begin(), uniqueAlbums.end());
699     MEDIA_INFO_LOG("DeleteDuplicatePortraitAlbum: Unique names %{public}zu", uniqueAlbumNames.size());
700     std::string albumNameInClause;
701     if (!uniqueAlbumNames.empty()) {
702         albumNameInClause = ANALYSIS_COL_ALBUM_NAME + " IN (" +
703             BackupDatabaseUtils::JoinSQLValues<string>(uniqueAlbumNames, ", ") + ")";
704     }
705     std::string tagIdInClause;
706     if (!tagIds.empty()) {
707         tagIdInClause = ANALYSIS_COL_TAG_ID + " IN (" +
708             BackupDatabaseUtils::JoinSQLValues<string>(tagIds, ", ") + ")";
709     }
710 
711     std::string analysisAlbumWhereClause;
712     if (!albumNameInClause.empty() && !tagIdInClause.empty()) {
713         analysisAlbumWhereClause = "(" + albumNameInClause + " OR " + tagIdInClause + ")";
714     } else {
715         analysisAlbumWhereClause = !albumNameInClause.empty() ? albumNameInClause : tagIdInClause;
716     }
717     if (analysisAlbumWhereClause.empty()) {
718         MEDIA_INFO_LOG("DeleteDuplicatePortraitAlbum: Effective criteria empty.");
719         return true;
720     }
721 
722     std::string albumIdCondition = ANALYSIS_COL_ALBUM_ID + " <= " + std::to_string(maxAlbumId);
723     std::string finalWhereClause = albumIdCondition + " AND (" + analysisAlbumWhereClause + ")";
724     finalWhereClause += " AND (album_type = 4096 AND album_subtype = 4102)";
725 
726     std::string selectTagIdsToDeleteSql = "SELECT A." + ANALYSIS_COL_TAG_ID +
727         " FROM " + ANALYSIS_ALBUM_TABLE + " AS A " + " WHERE " + finalWhereClause;
728 
729     bool success = true;
730     success &= DeleteDuplicateVisionFaceTags(mediaLibraryRdb, selectTagIdsToDeleteSql);
731     if (!success) {
732         MEDIA_ERR_LOG("Failed during DeleteDuplicateVisionFaceTags step.");
733     }
734 
735     success &= UpdateDuplicateVisionImageFaces(mediaLibraryRdb, selectTagIdsToDeleteSql);
736     if (!success) {
737         MEDIA_ERR_LOG("Failed during UpdateDuplicateVisionImageFaces step.");
738     }
739 
740     success &= DeleteDuplicateAnalysisAlbums(mediaLibraryRdb, finalWhereClause);
741     if (!success) {
742         MEDIA_ERR_LOG("Failed during DeleteDuplicateAnalysisAlbums step.");
743     }
744     return success;
745 }
746 
ExecuteSQL(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & sql,const std::vector<NativeRdb::ValueObject> & args)747 int BackupDatabaseUtils::ExecuteSQL(std::shared_ptr<NativeRdb::RdbStore> rdbStore, const std::string& sql,
748     const std::vector<NativeRdb::ValueObject> &args)
749 {
750     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_FAIL, "rdbStore is nullptr");
751     return ExecSqlWithRetry([&]() { return rdbStore->ExecuteSql(sql, args); });
752 }
753 
BatchInsert(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & value,int64_t & rowNum)754 int32_t BackupDatabaseUtils::BatchInsert(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
755     const std::string &tableName, std::vector<NativeRdb::ValuesBucket> &value, int64_t &rowNum)
756 {
757     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_FAIL, "rdbStore is nullptr");
758     return ExecSqlWithRetry([&]() { return rdbStore->BatchInsert(rowNum, tableName, value); });
759 }
760 
DeleteExistingImageFaceData(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::vector<FileIdPair> & fileIdPair)761 void BackupDatabaseUtils::DeleteExistingImageFaceData(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
762     const std::vector<FileIdPair>& fileIdPair)
763 {
764     auto [oldFileIds, newFileIds] = BackupDatabaseUtils::UnzipFileIdPairs(fileIdPair);
765     std::vector<int> realNewFileIds;
766     for (auto fileId: newFileIds) {
767         CHECK_AND_EXECUTE(fileId == -1, realNewFileIds.emplace_back(fileId));
768     }
769 
770     std::string fileIdNewFilterClause = "(" + BackupDatabaseUtils::JoinValues<int>(realNewFileIds, ", ") + ")";
771 
772     std::string deleteAnalysisPhotoMapSql =
773         "DELETE FROM AnalysisPhotoMap WHERE "
774         "map_album IN (SELECT album_id FROM AnalysisAlbum WHERE album_type = 4096 AND album_subtype = 4102) "
775         "AND map_asset IN ("
776         "SELECT " + IMAGE_FACE_COL_FILE_ID + " FROM " + VISION_IMAGE_FACE_TABLE +
777         " WHERE " + IMAGE_FACE_COL_FILE_ID + " IN " + fileIdNewFilterClause +
778         ") ";
779     BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb, deleteAnalysisPhotoMapSql);
780 
781     std::string deleteFaceSql = "DELETE FROM " + VISION_IMAGE_FACE_TABLE +
782         " WHERE " + IMAGE_FACE_COL_FILE_ID + " IN " + fileIdNewFilterClause;
783     BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb, deleteFaceSql);
784 
785     std::unique_ptr<NativeRdb::AbsRdbPredicates> totalTablePredicates =
786         std::make_unique<NativeRdb::AbsRdbPredicates>(VISION_TOTAL_TABLE);
787 
788     std::string fileIdCondition = IMAGE_FACE_COL_FILE_ID + " IN " + fileIdNewFilterClause;
789     totalTablePredicates->SetWhereClause(fileIdCondition);
790 
791     NativeRdb::ValuesBucket totalValues;
792     totalValues.PutInt("face", 0);
793 
794     int32_t totalUpdatedRows = 0;
795     int32_t totalRet = BackupDatabaseUtils::Update(mediaLibraryRdb,
796         totalUpdatedRows, totalValues, totalTablePredicates);
797 
798     bool totalUpdateFailed = (totalUpdatedRows < 0 || totalRet < 0);
799     CHECK_AND_RETURN_LOG(!totalUpdateFailed, "Failed to update VISION_TOTAL_TABLE face field to 0");
800 }
801 
ParseFaceTagResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,TagPairOpt & tagPair)802 void BackupDatabaseUtils::ParseFaceTagResultSet(const std::shared_ptr<NativeRdb::ResultSet>& resultSet,
803     TagPairOpt& tagPair)
804 {
805     tagPair.first = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_TAG_ID);
806     tagPair.second = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_GROUP_TAG);
807 }
808 
QueryTagInfo(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)809 std::vector<TagPairOpt> BackupDatabaseUtils::QueryTagInfo(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
810 {
811     std::vector<TagPairOpt> result;
812     std::string querySql = "SELECT " + ANALYSIS_COL_TAG_ID + ", " +
813         ANALYSIS_COL_GROUP_TAG +
814         " FROM " + ANALYSIS_ALBUM_TABLE +
815         " WHERE " + ANALYSIS_COL_TAG_ID + " IS NOT NULL AND " +
816         ANALYSIS_COL_TAG_ID + " != ''";
817 
818     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb, querySql);
819     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, result, "Query resultSet is null.");
820 
821     while (resultSet->GoToNextRow () == NativeRdb::E_OK) {
822         TagPairOpt tagPair;
823         ParseFaceTagResultSet(resultSet, tagPair);
824         result.emplace_back(tagPair);
825     }
826     resultSet->Close();
827     return result;
828 }
829 
UpdateGroupTagColumn(const std::vector<TagPairOpt> & updatedPairs,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)830 void BackupDatabaseUtils::UpdateGroupTagColumn(const std::vector<TagPairOpt>& updatedPairs,
831     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
832 {
833     for (const auto& pair : updatedPairs) {
834         if (pair.first.has_value() && pair.second.has_value()) {
835             std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
836                 std::make_unique<NativeRdb::AbsRdbPredicates>(ANALYSIS_ALBUM_TABLE);
837             std::string whereClause = ANALYSIS_COL_TAG_ID + " = '" + pair.first.value() + "'";
838             predicates->SetWhereClause(whereClause);
839 
840             int32_t updatedRows = 0;
841             NativeRdb::ValuesBucket valuesBucket;
842             valuesBucket.PutString(ANALYSIS_COL_GROUP_TAG, pair.second.value());
843 
844             int32_t ret = BackupDatabaseUtils::Update(mediaLibraryRdb, updatedRows, valuesBucket, predicates);
845             bool cond = (updatedRows <= 0 || ret < 0);
846             CHECK_AND_PRINT_LOG(!cond, "Failed to update group_tag for tag_id: %s", pair.first.value().c_str());
847         }
848     }
849 }
850 
UpdateFaceGroupTagsUnion(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)851 void BackupDatabaseUtils::UpdateFaceGroupTagsUnion(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
852 {
853     std::vector<TagPairOpt> tagPairs = QueryTagInfo(mediaLibraryRdb);
854     std::vector<TagPairOpt> updatedPairs;
855     std::vector<std::string> allTagIds;
856     for (const auto& pair : tagPairs) {
857         CHECK_AND_EXECUTE(!pair.first.has_value(), allTagIds.emplace_back(pair.first.value()));
858     }
859     MEDIA_INFO_LOG("get all TagId  %{public}zu", allTagIds.size());
860     for (const auto& pair : tagPairs) {
861         if (pair.second.has_value()) {
862             std::vector<std::string> groupTags = BackupDatabaseUtils::SplitString(pair.second.value(), '|');
863             MEDIA_INFO_LOG("TagId: %{public}s, old GroupTags is: %{public}s",
864                            pair.first.value_or(std::string("-1")).c_str(), pair.second.value().c_str());
865             groupTags.erase(std::remove_if(groupTags.begin(), groupTags.end(),
866                 [&allTagIds](const std::string& tagId) {
867                 return std::find(allTagIds.begin(), allTagIds.end(), tagId) == allTagIds.end();
868                 }),
869                 groupTags.end());
870 
871             std::string newGroupTag = BackupDatabaseUtils::JoinValues<std::string>(groupTags, "|");
872             if (newGroupTag != pair.second.value()) {
873                 updatedPairs.emplace_back(pair.first, newGroupTag);
874                 MEDIA_INFO_LOG("TagId: %{public}s  GroupTags updated", pair.first.value().c_str());
875             }
876         }
877     }
878 
879     UpdateGroupTagColumn(updatedPairs, mediaLibraryRdb);
880 }
881 
UpdateTagPairs(std::vector<TagPairOpt> & updatedPairs,const std::string & newGroupTag,const std::vector<std::string> & tagIds)882 void BackupDatabaseUtils::UpdateTagPairs(std::vector<TagPairOpt>& updatedPairs, const std::string& newGroupTag,
883     const std::vector<std::string>& tagIds)
884 {
885     for (const auto& tagId : tagIds) {
886         updatedPairs.emplace_back(tagId, newGroupTag);
887     }
888 }
889 
UpdateGroupTags(std::vector<TagPairOpt> & updatedPairs,const std::unordered_map<std::string,std::vector<std::string>> & groupTagMap)890 void BackupDatabaseUtils::UpdateGroupTags(std::vector<TagPairOpt>& updatedPairs,
891     const std::unordered_map<std::string, std::vector<std::string>>& groupTagMap)
892 {
893     for (auto &[groupTag, tagIds] : groupTagMap) {
894         CHECK_AND_CONTINUE(!tagIds.empty());
895         const std::string newGroupTag =
896             (tagIds.size() > 1) ? BackupDatabaseUtils::JoinValues(tagIds, "|") : tagIds.front();
897         CHECK_AND_EXECUTE(newGroupTag == groupTag, UpdateTagPairs(updatedPairs, newGroupTag, tagIds));
898     }
899 }
900 
UpdateFaceGroupTagOfGallery(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)901 void BackupDatabaseUtils::UpdateFaceGroupTagOfGallery(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
902 {
903     std::vector<TagPairOpt> tagPairs = QueryTagInfo(mediaLibraryRdb);
904     std::vector<TagPairOpt> updatedPairs;
905     std::unordered_map<std::string, std::vector<std::string>> groupTagMap;
906 
907     for (const auto& pair : tagPairs) {
908         if (pair.first.has_value() && pair.second.has_value()) {
909             groupTagMap[pair.second.value()].push_back(pair.first.value());
910         } else {
911             MEDIA_INFO_LOG("Found tag_id without group_tag: %{public}s", pair.first.value().c_str());
912         }
913     }
914 
915     UpdateGroupTags(updatedPairs, groupTagMap);
916     UpdateGroupTagColumn(updatedPairs, mediaLibraryRdb);
917 }
918 
UpdateAssociateFileId(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::vector<FileInfo> & fileInfos)919 void BackupDatabaseUtils::UpdateAssociateFileId(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
920     const std::vector<FileInfo> &fileInfos)
921 {
922     for (const FileInfo &fileInfo : fileInfos) {
923         bool cond = (fileInfo.associateFileId <= 0 || fileInfo.fileIdOld <= 0 || fileInfo.fileIdNew <= 0);
924         CHECK_AND_CONTINUE(!cond);
925         int32_t updateAssociateId = -1;
926         bool ret = fileIdOld2NewForCloudEnhancement.Find(fileInfo.associateFileId, updateAssociateId);
927         if (!ret) {
928             fileIdOld2NewForCloudEnhancement.Insert(fileInfo.fileIdOld, fileInfo.fileIdNew);
929             continue;
930         }
931 
932         int32_t changeRows = 0;
933         NativeRdb::ValuesBucket updatePostBucket;
934         updatePostBucket.Put(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, updateAssociateId);
935         std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
936             make_unique<NativeRdb::AbsRdbPredicates>(PhotoColumn::PHOTOS_TABLE);
937         predicates->SetWhereClause("file_id=?");
938         predicates->SetWhereArgs({ to_string(fileInfo.fileIdNew) });
939         BackupDatabaseUtils::Update(rdbStore, changeRows, updatePostBucket, predicates);
940         if (changeRows > 0) {
941             MEDIA_INFO_LOG("update, old:%{public}d, new:%{public}d, old_associate:%{public}d, new_associate:%{public}d",
942                 fileInfo.fileIdOld, fileInfo.fileIdNew, fileInfo.associateFileId, updateAssociateId);
943         }
944 
945         NativeRdb::ValuesBucket updatePreBucket;
946         updatePreBucket.Put(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, fileInfo.fileIdNew);
947         predicates->SetWhereArgs({ to_string(updateAssociateId) });
948         BackupDatabaseUtils::Update(rdbStore, changeRows, updatePreBucket, predicates);
949         if (changeRows > 0) {
950             MEDIA_INFO_LOG("update, old:%{public}d, new:%{public}d, new_associate:%{public}d",
951                 fileInfo.associateFileId, updateAssociateId, fileInfo.fileIdNew);
952         }
953         fileIdOld2NewForCloudEnhancement.Erase(fileInfo.associateFileId);
954     }
955 }
956 
BatchUpdatePhotosToLocal(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::vector<std::string> & inColumn)957 void BackupDatabaseUtils::BatchUpdatePhotosToLocal(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
958     const std::vector<std::string> &inColumn)
959 {
960     CHECK_AND_RETURN(!inColumn.empty());
961 
962     int32_t changeRows = 0;
963     std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
964         make_unique<NativeRdb::AbsRdbPredicates>(PhotoColumn::PHOTOS_TABLE);
965     predicates->In(MediaColumn::MEDIA_ID, inColumn);
966     NativeRdb::ValuesBucket updatePostBucket;
967     updatePostBucket.Put(PhotoColumn::PHOTO_CLEAN_FLAG, 0);
968     updatePostBucket.Put(PhotoColumn::PHOTO_POSITION, static_cast<int32_t>(PhotoPositionType::LOCAL));
969     updatePostBucket.PutNull(PhotoColumn::PHOTO_CLOUD_ID);
970     updatePostBucket.PutNull(PhotoColumn::PHOTO_CLOUD_VERSION);
971     updatePostBucket.Put(PhotoColumn::PHOTO_THUMBNAIL_READY, 0);
972     updatePostBucket.Put(PhotoColumn::PHOTO_THUMB_STATUS, static_cast<int32_t>(PhotoThumbStatusType::NOT_DOWNLOADED));
973     updatePostBucket.Put(PhotoColumn::PHOTO_LCD_VISIT_TIME, 0);
974     updatePostBucket.Put(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, 0);
975 
976     BackupDatabaseUtils::Update(mediaLibraryRdb, changeRows, updatePostBucket, predicates);
977     if (changeRows != static_cast<int32_t>(inColumn.size())) {
978         MEDIA_ERR_LOG("update failed, UpdatePhotoToLocal, expected count %{public}d, but got %{public}d",
979             static_cast<int32_t>(inColumn.size()), changeRows);
980     }
981 }
982 
CheckDbIntegrity(std::shared_ptr<NativeRdb::RdbStore> rdbStore,int32_t sceneCode,const std::string & dbTag)983 std::string BackupDatabaseUtils::CheckDbIntegrity(std::shared_ptr<NativeRdb::RdbStore> rdbStore, int32_t sceneCode,
984     const std::string &dbTag)
985 {
986     const std::string querySql = "PRAGMA " + COLUMN_INTEGRITY_CHECK;
987     auto resultSet = GetQueryResultSet(rdbStore, querySql);
988     if (resultSet == nullptr) {
989         MEDIA_ERR_LOG ("Query resultSet is null or GoToFirstRow failed.");
990         return "";
991     }
992     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
993         resultSet->Close();
994         return "";
995     }
996     std::string result = GetStringVal(COLUMN_INTEGRITY_CHECK, resultSet);
997     MEDIA_INFO_LOG("Check db integrity: %{public}d, %{public}s, %{public}s", sceneCode, dbTag.c_str(), result.c_str());
998     resultSet->Close();
999     return result;
1000 }
1001 
QueryLocalNoAstcCount(std::shared_ptr<NativeRdb::RdbStore> rdbStore)1002 int32_t BackupDatabaseUtils::QueryLocalNoAstcCount(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
1003 {
1004     const std::string QUERY_LOCAL_NO_ASTC_COUNT = "SELECT count(1) AS count FROM Photos "
1005         "WHERE " + PhotoColumn::PHOTO_POSITION + " = 1 AND " + PhotoColumn::PHOTO_THUMBNAIL_VISIBLE + " = 0 " +
1006         "AND " + MediaColumn::MEDIA_DATE_TRASHED + " = 0 AND " + MediaColumn::MEDIA_TIME_PENDING +  "= 0 " +
1007         "AND " + MediaColumn::MEDIA_HIDDEN + " = 0 AND " + PhotoColumn::PHOTO_IS_TEMP + " = 0 " +
1008         "AND " + PhotoColumn::PHOTO_BURST_COVER_LEVEL + " = 1 AND " + PhotoColumn::PHOTO_CLEAN_FLAG + " = 0 " +
1009         "AND " + PhotoColumn::PHOTO_SYNC_STATUS + " = 0";
1010     return QueryInt(rdbStore, QUERY_LOCAL_NO_ASTC_COUNT, CUSTOM_COUNT);
1011 }
1012 
QueryReadyAstcCount(std::shared_ptr<NativeRdb::RdbStore> rdbStore)1013 int32_t BackupDatabaseUtils::QueryReadyAstcCount(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
1014 {
1015     const std::string QUERY_READY_ASTC_COUNT = "SELECT count(1) AS count FROM Photos WHERE " +
1016         PhotoColumn::PHOTO_THUMBNAIL_VISIBLE + " = 1";
1017     return QueryInt(rdbStore, QUERY_READY_ASTC_COUNT, CUSTOM_COUNT);
1018 }
1019 
QueryMediaTypeCount(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & querySql)1020 std::unordered_map<int32_t, int32_t> BackupDatabaseUtils::QueryMediaTypeCount(
1021     const std::shared_ptr<NativeRdb::RdbStore>& rdbStore, const std::string& querySql)
1022 {
1023     std::unordered_map<int32_t, int32_t> mediaTypeCountMap;
1024     auto resultSet = GetQueryResultSet(rdbStore, querySql);
1025     if (resultSet == nullptr) {
1026         MEDIA_ERR_LOG("resultSet is nullptr");
1027         return mediaTypeCountMap;
1028     }
1029     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1030         int32_t mediaType = GetInt32Val(EXTERNAL_MEDIA_TYPE, resultSet);
1031         int32_t count = GetInt32Val(CUSTOM_COUNT, resultSet);
1032         mediaTypeCountMap[mediaType] = count;
1033     }
1034     resultSet->Close();
1035     return mediaTypeCountMap;
1036 }
1037 
QuerySql(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & querySql,const std::vector<NativeRdb::ValueObject> & params)1038 std::shared_ptr<NativeRdb::ResultSet> BackupDatabaseUtils::QuerySql(
1039     std::shared_ptr<NativeRdb::RdbStore> rdbStore, const std::string &querySql,
1040     const std::vector<NativeRdb::ValueObject> &params)
1041 {
1042     if (rdbStore == nullptr) {
1043         MEDIA_ERR_LOG("rdbStore is nullptr");
1044         return nullptr;
1045     }
1046     return rdbStore->QuerySql(querySql, params);
1047 }
1048 
UpdateBurstPhotos(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore)1049 void BackupDatabaseUtils::UpdateBurstPhotos(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore)
1050 {
1051     const string updateSql =
1052         "UPDATE " + PhotoColumn::PHOTOS_TABLE + " SET " +
1053         PhotoColumn::PHOTO_BURST_COVER_LEVEL + " = " + to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)) +
1054         "," + PhotoColumn::PHOTO_BURST_KEY + " = NULL," +
1055         PhotoColumn::PHOTO_SUBTYPE + " = " + to_string(static_cast<int32_t>(PhotoSubType::DEFAULT)) +
1056         " WHERE " + SQL_SELECT_ERROR_BURST_PHOTOS +
1057         "AND file_id IN (" + SQL_SELECT_CLONE_FILE_IDS + ")";
1058     int32_t erroCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
1059     CHECK_AND_PRINT_LOG(erroCode >= 0, "execute update continuous shooting photos, ret=%{public}d", erroCode);
1060 }
1061 
QueryIntVec(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & sql,const std::string & columnName)1062 std::vector<int32_t> BackupDatabaseUtils::QueryIntVec(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
1063     const std::string& sql, const std::string& columnName)
1064 {
1065     std::vector<int32_t> results;
1066     if (rdbStore == nullptr) {
1067         return results;
1068     }
1069 
1070     auto resultSet = rdbStore->QuerySql(sql);
1071     if (resultSet == nullptr) {
1072         MEDIA_ERR_LOG("Failed to query SQL or resultSet is null");
1073         return results;
1074     }
1075 
1076     int32_t columnIndex = -1;
1077     if (resultSet->GetColumnIndex(columnName, columnIndex) != NativeRdb::E_OK) {
1078         MEDIA_ERR_LOG("Get column index error");
1079         resultSet->Close();
1080         return results;
1081     }
1082 
1083     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1084         int32_t value;
1085         if (resultSet->GetInt(columnIndex, value) == NativeRdb::E_OK) {
1086             results.push_back(value);
1087         }
1088     }
1089     resultSet->Close();
1090     return results;
1091 }
1092 
UpdateAnalysisTotalTblNoFaceStatus(std::shared_ptr<NativeRdb::RdbStore> newRdbStore,std::shared_ptr<NativeRdb::RdbStore> oldRdbStore,const std::vector<FileIdPair> & fileIdPair)1093 void BackupDatabaseUtils::UpdateAnalysisTotalTblNoFaceStatus(std::shared_ptr<NativeRdb::RdbStore> newRdbStore,
1094     std::shared_ptr<NativeRdb::RdbStore> oldRdbStore, const std::vector<FileIdPair>& fileIdPair)
1095 {
1096     auto [oldFileIds, newFileIds] = BackupDatabaseUtils::UnzipFileIdPairs(fileIdPair);
1097 
1098     if (oldFileIds.empty()) {
1099         MEDIA_ERR_LOG("No old file IDs to process for no face status update.");
1100         return;
1101     }
1102 
1103     std::string fileIdOldInClause = "(" + BackupDatabaseUtils::JoinValues<int>(oldFileIds, ", ") + ")";
1104     std::string queryOldNoFaceSql =
1105         "SELECT file_id FROM tab_analysis_total "
1106         "WHERE face = -2 AND file_id IN " + fileIdOldInClause;
1107 
1108     std::vector<int32_t> oldNoFaceFileIds = QueryIntVec(oldRdbStore, queryOldNoFaceSql, "file_id");
1109 
1110     if (oldNoFaceFileIds.empty()) {
1111         MEDIA_ERR_LOG("No old files found with face = -2 status to migrate.");
1112         return;
1113     }
1114 
1115     std::vector<int32_t> newNoFaceFileIds;
1116     std::map<int32_t, int32_t> oldToNewIdMap;
1117     for (const auto& pair : fileIdPair) {
1118         oldToNewIdMap[pair.first] = pair.second;
1119     }
1120 
1121     for (int32_t oldId : oldNoFaceFileIds) {
1122         auto it = oldToNewIdMap.find(oldId);
1123         if (it != oldToNewIdMap.end()) {
1124             newNoFaceFileIds.push_back(it->second);
1125         }
1126     }
1127 
1128     if (newNoFaceFileIds.empty()) {
1129         MEDIA_ERR_LOG("No corresponding new file IDs found for old files with face = -2 status.");
1130         return;
1131     }
1132 
1133     std::string fileIdNewFilterClause = "(" + BackupDatabaseUtils::JoinValues<int>(newNoFaceFileIds, ", ") + ")";
1134     std::string updateSql =
1135         "UPDATE tab_analysis_total "
1136         "SET face = -2 "
1137         "WHERE file_id IN " + fileIdNewFilterClause;
1138 
1139     int32_t errCode = BackupDatabaseUtils::ExecuteSQL(newRdbStore, updateSql);
1140     CHECK_AND_PRINT_LOG(errCode >= 0, "execute update analysis total for no face failed, ret=%{public}d", errCode);
1141 }
1142 } // namespace Media
1143 } // namespace OHOS