• 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 
47 const std::vector<uint32_t> HEX_MAX = { 0xff, 0xffff, 0xffffff, 0xffffffff };
48 static SafeMap<int32_t, int32_t> fileIdOld2NewForCloudEnhancement;
49 
InitDb(std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & dbName,const std::string & dbPath,const std::string & bundleName,bool isMediaLibrary,int32_t area)50 int32_t BackupDatabaseUtils::InitDb(std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &dbName,
51     const std::string &dbPath, const std::string &bundleName, bool isMediaLibrary, int32_t area)
52 {
53     NativeRdb::RdbStoreConfig config(dbName);
54     config.SetPath(dbPath);
55     config.SetBundleName(bundleName);
56     config.SetReadConSize(CONNECT_SIZE);
57     config.SetSecurityLevel(NativeRdb::SecurityLevel::S3);
58     config.SetHaMode(NativeRdb::HAMode::MANUAL_TRIGGER);
59     config.SetAllowRebuild(true);
60     if (area != DEFAULT_AREA_VERSION) {
61         config.SetArea(area);
62     }
63     if (isMediaLibrary) {
64         config.SetScalarFunction("cloud_sync_func", 0, CloudSyncTriggerFunc);
65         config.SetScalarFunction("is_caller_self_func", 0, IsCallerSelfFunc);
66         config.SetScalarFunction("photo_album_notify_func", 1, PhotoAlbumNotifyFunc);
67         config.SetScalarFunction("begin_generate_highlight_thumbnail", STAMP_PARAM, BeginGenerateHighlightThumbnail);
68     }
69     int32_t err;
70     RdbCallback cb;
71     rdbStore = NativeRdb::RdbHelper::GetRdbStore(config, MEDIA_RDB_VERSION, cb, err);
72     return err;
73 }
74 
InitReadOnlyRdb(std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & dbName,const std::string & dbPath,const std::string & bundleName)75 int32_t BackupDatabaseUtils::InitReadOnlyRdb(std::shared_ptr<NativeRdb::RdbStore> &rdbStore,
76     const std::string &dbName, const std::string &dbPath, const std::string &bundleName)
77 {
78     NativeRdb::RdbStoreConfig config(dbName);
79     config.SetPath(dbPath);
80     config.SetBundleName(bundleName);
81     config.SetReadConSize(CONNECT_SIZE);
82     int32_t err;
83     RdbCallback cb;
84     rdbStore = NativeRdb::RdbHelper::GetRdbStore(config, MEDIA_RDB_VERSION, cb, err);
85     return err;
86 }
87 
CloudSyncTriggerFunc(const std::vector<std::string> & args)88 std::string BackupDatabaseUtils::CloudSyncTriggerFunc(const std::vector<std::string> &args)
89 {
90     return "";
91 }
92 
IsCallerSelfFunc(const std::vector<std::string> & args)93 std::string BackupDatabaseUtils::IsCallerSelfFunc(const std::vector<std::string> &args)
94 {
95     return "false";
96 }
97 
PhotoAlbumNotifyFunc(const std::vector<std::string> & args)98 std::string BackupDatabaseUtils::PhotoAlbumNotifyFunc(const std::vector<std::string> &args)
99 {
100     return "";
101 }
102 
BeginGenerateHighlightThumbnail(const std::vector<std::string> & args)103 std::string BackupDatabaseUtils::BeginGenerateHighlightThumbnail(const std::vector<std::string> &args)
104 {
105     return "";
106 }
107 
ExecSqlWithRetry(std::function<int32_t ()> execSql)108 static int32_t ExecSqlWithRetry(std::function<int32_t()> execSql)
109 {
110     int32_t currentTime = 0;
111     int32_t err = NativeRdb::E_OK;
112     while (currentTime <= MAX_TRY_TIMES) {
113         err = execSql();
114         if (err == NativeRdb::E_OK) {
115             break;
116         } else if (err == NativeRdb::E_SQLITE_LOCKED || err == NativeRdb::E_DATABASE_BUSY ||
117             err == NativeRdb::E_SQLITE_BUSY) {
118             std::this_thread::sleep_for(std::chrono::milliseconds(TRANSACTION_WAIT_INTERVAL));
119             currentTime++;
120             MEDIA_ERR_LOG("execSql busy, err: %{public}d, currentTime: %{public}d", err, currentTime);
121         } else {
122             MEDIA_ERR_LOG("execSql failed, err: %{public}d, currentTime: %{public}d", err, currentTime);
123             break;
124         }
125     }
126     return err;
127 }
128 
QueryInt(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & sql,const std::string & column,const std::vector<NativeRdb::ValueObject> & args)129 int32_t BackupDatabaseUtils::QueryInt(std::shared_ptr<NativeRdb::RdbStore> rdbStore, const std::string &sql,
130     const std::string &column, const std::vector<NativeRdb::ValueObject> &args)
131 {
132     if (rdbStore == nullptr) {
133         MEDIA_ERR_LOG("rdb_ is nullptr, Maybe init failed.");
134         return 0;
135     }
136     auto resultSet = rdbStore->QuerySql(sql, args);
137     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
138         return 0;
139     }
140     int32_t result = GetInt32Val(column, resultSet);
141     return result;
142 }
143 
Update(std::shared_ptr<NativeRdb::RdbStore> & rdbStore,int32_t & changeRows,NativeRdb::ValuesBucket & valuesBucket,std::unique_ptr<NativeRdb::AbsRdbPredicates> & predicates)144 int32_t BackupDatabaseUtils::Update(std::shared_ptr<NativeRdb::RdbStore> &rdbStore, int32_t &changeRows,
145     NativeRdb::ValuesBucket &valuesBucket, std::unique_ptr<NativeRdb::AbsRdbPredicates> &predicates)
146 {
147     if (rdbStore == nullptr) {
148         MEDIA_ERR_LOG("rdb_ is nullptr, Maybe init failed.");
149         return E_FAIL;
150     }
151     return ExecSqlWithRetry([&]() { return rdbStore->Update(changeRows, valuesBucket, *predicates); });
152 }
153 
Delete(NativeRdb::AbsRdbPredicates & predicates,int32_t & changeRows,std::shared_ptr<NativeRdb::RdbStore> & rdbStore)154 int32_t BackupDatabaseUtils::Delete(NativeRdb::AbsRdbPredicates &predicates, int32_t &changeRows,
155     std::shared_ptr<NativeRdb::RdbStore> &rdbStore)
156 {
157     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_FAIL, "rdb is nullptr");
158     return ExecSqlWithRetry([&]() { return rdbStore->Delete(changeRows, predicates); });
159 }
160 
InitGarbageAlbum(std::shared_ptr<NativeRdb::RdbStore> galleryRdb,std::set<std::string> & cacheSet,std::unordered_map<std::string,std::string> & nickMap)161 int32_t BackupDatabaseUtils::InitGarbageAlbum(std::shared_ptr<NativeRdb::RdbStore> galleryRdb,
162     std::set<std::string> &cacheSet, std::unordered_map<std::string, std::string> &nickMap)
163 {
164     if (galleryRdb == nullptr) {
165         MEDIA_ERR_LOG("Pointer rdb_ is nullptr, Maybe init failed.");
166         return E_FAIL;
167     }
168 
169     const string querySql = "SELECT nick_dir, nick_name FROM garbage_album where type = 0";
170     auto resultSet = galleryRdb->QuerySql(QUERY_GARBAGE_ALBUM);
171     if (resultSet == nullptr) {
172         return E_HAS_DB_ERROR;
173     }
174     int32_t count = -1;
175     int32_t err = resultSet->GetRowCount(count);
176     if (err != E_OK) {
177         MEDIA_ERR_LOG("Failed to get count, err: %{public}d", err);
178         return E_FAIL;
179     }
180     MEDIA_INFO_LOG("garbageCount: %{public}d", count);
181     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
182         int32_t type;
183         resultSet->GetInt(INDEX_TYPE, type);
184         if (type == NICK) {
185             string nickName;
186             string nickDir;
187             resultSet->GetString(INDEX_NICK_DIR, nickDir);
188             resultSet->GetString(INDEX_NICK_NAME, nickName);
189             nickMap[nickDir] = nickName;
190         } else {
191             string cacheDir;
192             resultSet->GetString(INDEX_CACHE_DIR, cacheDir);
193             cacheSet.insert(cacheDir);
194         }
195     }
196     MEDIA_INFO_LOG("add map success!");
197     resultSet->Close();
198     return E_OK;
199 }
200 
QueryGalleryCloneCount(std::shared_ptr<NativeRdb::RdbStore> galleryRdb)201 int32_t BackupDatabaseUtils::QueryGalleryCloneCount(std::shared_ptr<NativeRdb::RdbStore> galleryRdb)
202 {
203     static string QUERY_GALLERY_CLONE_COUNT =
204         string("SELECT count(1) AS count FROM gallery_media WHERE local_media_id = -3 AND _size > 0 ") +
205         "AND (storage_id IN (0, 65537)) AND relative_bucket_id NOT IN ( " +
206         "SELECT DISTINCT relative_bucket_id FROM garbage_album WHERE type = 1)";
207     return QueryInt(galleryRdb, QUERY_GALLERY_CLONE_COUNT, CUSTOM_COUNT);
208 }
209 
QueryGalleryDuplicateDataCount(std::shared_ptr<NativeRdb::RdbStore> galleryRdb,int32_t & count,int32_t & total)210 void BackupDatabaseUtils::QueryGalleryDuplicateDataCount(std::shared_ptr<NativeRdb::RdbStore> galleryRdb,
211     int32_t &count, int32_t &total)
212 {
213     static string QUERY_GALLERY_DUPLICATE_DATA_COUNT = "SELECT count(DISTINCT _data) as count, count(1) as total"
214         " FROM gallery_media WHERE _data IN (SELECT _data FROM gallery_media GROUP BY _data HAVING count(1) > 1)";
215     auto resultSet = GetQueryResultSet(galleryRdb, QUERY_GALLERY_DUPLICATE_DATA_COUNT);
216     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
217         return;
218     }
219     count = GetInt32Val("count", resultSet);
220     total = GetInt32Val("total", resultSet);
221 }
222 
GetQueryResultSet(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & querySql,const std::vector<std::string> & sqlArgs)223 std::shared_ptr<NativeRdb::ResultSet> BackupDatabaseUtils::GetQueryResultSet(
224     const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &querySql,
225     const std::vector<std::string> &sqlArgs)
226 {
227     if (rdbStore == nullptr) {
228         MEDIA_ERR_LOG("rdbStore is nullptr");
229         return nullptr;
230     }
231     return rdbStore->QuerySql(querySql, sqlArgs);
232 }
233 
GetColumnInfoMap(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & tableName)234 std::unordered_map<std::string, std::string> BackupDatabaseUtils::GetColumnInfoMap(
235     const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &tableName)
236 {
237     std::unordered_map<std::string, std::string> columnInfoMap;
238     std::string querySql = "SELECT name, type FROM pragma_table_info('" + tableName + "')";
239     auto resultSet = GetQueryResultSet(rdbStore, querySql);
240     if (resultSet == nullptr) {
241         MEDIA_ERR_LOG("resultSet is nullptr");
242         return columnInfoMap;
243     }
244     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
245         std::string columnName = GetStringVal(PRAGMA_TABLE_NAME, resultSet);
246         std::string columnType = GetStringVal(PRAGMA_TABLE_TYPE, resultSet);
247         if (columnName.empty() || columnType.empty()) {
248             MEDIA_ERR_LOG("Empty column name or type: %{public}s, %{public}s", columnName.c_str(), columnType.c_str());
249             continue;
250         }
251         columnInfoMap[columnName] = columnType;
252     }
253     return columnInfoMap;
254 }
255 
UpdateUniqueNumber(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,int32_t number,const std::string & type)256 void BackupDatabaseUtils::UpdateUniqueNumber(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, int32_t number,
257     const std::string &type)
258 {
259     const string updateSql =
260         "UPDATE UniqueNumber SET unique_number = " + to_string(number) + " WHERE media_type = '" + type + "'";
261     int32_t erroCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
262     CHECK_AND_PRINT_LOG(erroCode >= 0, "execute update unique number failed, ret=%{public}d", erroCode);
263 }
264 
QueryUniqueNumber(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & type)265 int32_t BackupDatabaseUtils::QueryUniqueNumber(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore,
266     const std::string &type)
267 {
268     const string querySql = "SELECT unique_number FROM UniqueNumber WHERE media_type = '" + type + "'";
269     return QueryInt(rdbStore, querySql, UNIQUE_NUMBER);
270 }
271 
GarbleInfoName(const string & infoName)272 std::string BackupDatabaseUtils::GarbleInfoName(const string &infoName)
273 {
274     std::string garbledInfoName = infoName;
275     if (infoName.size() <= MIN_GARBLE_SIZE) {
276         return garbledInfoName;
277     }
278     size_t garbledSize = infoName.size() - MIN_GARBLE_SIZE;
279     garbledInfoName.replace(GARBLE_START, garbledSize, GARBLE);
280     return garbledInfoName;
281 }
282 
UpdateSelection(std::string & selection,const std::string & selectionToAdd,bool needWrap)283 void BackupDatabaseUtils::UpdateSelection(std::string &selection, const std::string &selectionToAdd, bool needWrap)
284 {
285     if (selectionToAdd.empty()) {
286         return;
287     }
288     std::string wrappedSelectionToAdd = needWrap ? "'" + selectionToAdd + "'" : selectionToAdd;
289     selection += selection.empty() ? wrappedSelectionToAdd : ", " + wrappedSelectionToAdd;
290 }
291 
UpdateSdWhereClause(std::string & querySql,bool shouldIncludeSd)292 void BackupDatabaseUtils::UpdateSdWhereClause(std::string &querySql, bool shouldIncludeSd)
293 {
294     if (shouldIncludeSd) {
295         return;
296     }
297     querySql += " AND " + EXCLUDE_SD;
298 }
299 
QueryThumbImage(NativeRdb::RdbStore & rdbStore,const std::string & keyValue,std::vector<uint8_t> & blob)300 bool BackupDatabaseUtils::QueryThumbImage(NativeRdb::RdbStore &rdbStore,
301     const std::string &keyValue, std::vector<uint8_t> &blob)
302 {
303     std::string query = "SELECT v FROM general_kv where k = " + SQL_QUOTES + keyValue + SQL_QUOTES +";";
304     auto resultSet = rdbStore.QueryByStep(query);
305     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, false, "Failed to QueryByStep");
306     int32_t count = -1;
307     int err = resultSet->GetRowCount(count);
308     CHECK_AND_RETURN_RET_LOG(err == E_OK, false,
309         "Failed to get count, err: %{public}d, %{public}s", err, query.c_str());
310     if (count != 1) {
311         MEDIA_ERR_LOG("Failed to get count: %{public}d,", count);
312         resultSet->Close();
313         return false;
314     }
315     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
316         resultSet->GetBlob(0, blob);
317     }
318     resultSet->Close();
319     return true;
320 }
321 
GetBlob(const std::string & columnName,std::shared_ptr<NativeRdb::ResultSet> resultSet,std::vector<uint8_t> & blobVal)322 int32_t BackupDatabaseUtils::GetBlob(const std::string &columnName, std::shared_ptr<NativeRdb::ResultSet> resultSet,
323     std::vector<uint8_t> &blobVal)
324 {
325     int32_t columnIndex = 0;
326     int32_t errCode = resultSet->GetColumnIndex(columnName, columnIndex);
327     CHECK_AND_RETURN_RET_LOG(!errCode, E_FAIL, "Get column index errCode: %{public}d", errCode);
328     CHECK_AND_RETURN_RET(resultSet->GetBlob(columnIndex, blobVal) == NativeRdb::E_OK, E_FAIL);
329     return E_OK;
330 }
331 
GetUint32ValFromBytes(const std::vector<uint8_t> & bytes,size_t start)332 uint32_t BackupDatabaseUtils::GetUint32ValFromBytes(const std::vector<uint8_t> &bytes, size_t start)
333 {
334     uint32_t uint32Val = 0;
335     for (size_t index = 0; index < BYTE_LEN; index++) {
336         uint32Val |= static_cast<uint32_t>(bytes[start + index]) << (index * BYTE_BASE_OFFSET);
337         uint32Val &= HEX_MAX[index];
338     }
339     return uint32Val;
340 }
341 
UpdateAnalysisTotalStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)342 void BackupDatabaseUtils::UpdateAnalysisTotalStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
343 {
344     std::string updateSql = "UPDATE tab_analysis_total SET face = CASE WHEN EXISTS \
345         (SELECT 1 FROM tab_analysis_image_face WHERE tab_analysis_image_face.file_id = tab_analysis_total.file_id \
346         AND tag_id = '-1') THEN 2 ELSE 3 END WHERE EXISTS (SELECT 1 FROM tab_analysis_image_face WHERE \
347         tab_analysis_image_face.file_id = tab_analysis_total.file_id)";
348     int32_t errCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
349     CHECK_AND_PRINT_LOG(errCode >= 0, "execute update analysis total failed, ret=%{public}d", errCode);
350 }
351 
UpdateAnalysisFaceTagStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)352 void BackupDatabaseUtils::UpdateAnalysisFaceTagStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
353 {
354     std::string updateSql = "UPDATE tab_analysis_face_tag SET count = (SELECT count(1) from tab_analysis_image_face \
355         WHERE tab_analysis_image_face.tag_id = tab_analysis_face_tag.tag_id)";
356     int32_t errCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
357     if (errCode < 0) {
358         MEDIA_ERR_LOG("execute update analysis face tag count failed, ret=%{public}d", errCode);
359     }
360 }
361 
UpdateAnalysisTotalTblStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::vector<FileIdPair> & fileIdPair)362 void BackupDatabaseUtils::UpdateAnalysisTotalTblStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
363     const std::vector<FileIdPair>& fileIdPair)
364 {
365     auto [oldFileIds, newFileIds] = BackupDatabaseUtils::UnzipFileIdPairs(fileIdPair);
366     std::string fileIdNewFilterClause = "(" + BackupDatabaseUtils::JoinValues<int>(newFileIds, ", ") + ")";
367 
368     std::string updateSql =
369         "UPDATE tab_analysis_total "
370         "SET face = CASE "
371             "WHEN EXISTS (SELECT 1 FROM tab_analysis_image_face "
372                          "WHERE tab_analysis_image_face.file_id = tab_analysis_total.file_id "
373                          "AND tag_id = '-1') THEN 2 "
374             "WHEN EXISTS (SELECT 1 FROM tab_analysis_image_face "
375                          "WHERE tab_analysis_image_face.file_id = tab_analysis_total.file_id "
376                          "AND tag_id = '-2') THEN 4 "
377             "ELSE 3 "
378         "END "
379         "WHERE EXISTS (SELECT 1 FROM tab_analysis_image_face "
380                       "WHERE tab_analysis_image_face.file_id = tab_analysis_total.file_id "
381                       "AND " + IMAGE_FACE_COL_FILE_ID + " IN " + fileIdNewFilterClause + ")";
382 
383     int32_t errCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
384     CHECK_AND_PRINT_LOG(errCode >= 0, "execute update analysis total failed, ret=%{public}d", errCode);
385 }
386 
UpdateFaceAnalysisTblStatus(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)387 void BackupDatabaseUtils::UpdateFaceAnalysisTblStatus(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
388 {
389     BackupDatabaseUtils::UpdateAnalysisFaceTagStatus(mediaLibraryRdb);
390 }
391 
SetTagIdNew(PortraitAlbumInfo & portraitAlbumInfo,std::unordered_map<std::string,std::string> & tagIdMap)392 bool BackupDatabaseUtils::SetTagIdNew(PortraitAlbumInfo &portraitAlbumInfo,
393     std::unordered_map<std::string, std::string> &tagIdMap)
394 {
395     portraitAlbumInfo.tagIdNew = TAG_ID_PREFIX + std::to_string(MediaFileUtils::UTCTimeNanoSeconds());
396     tagIdMap[portraitAlbumInfo.tagIdOld] = portraitAlbumInfo.tagIdNew;
397     return true;
398 }
399 
SetFileIdNew(FaceInfo & faceInfo,const std::unordered_map<std::string,FileInfo> & fileInfoMap)400 bool BackupDatabaseUtils::SetFileIdNew(FaceInfo &faceInfo, const std::unordered_map<std::string, FileInfo> &fileInfoMap)
401 {
402     if (faceInfo.hash.empty() || fileInfoMap.count(faceInfo.hash) == 0) {
403         MEDIA_ERR_LOG("Set new file_id for face %{public}s failed, no such file hash", faceInfo.faceId.c_str());
404         return false;
405     }
406     faceInfo.fileIdNew = fileInfoMap.at(faceInfo.hash).fileIdNew;
407     CHECK_AND_RETURN_RET_LOG(faceInfo.fileIdNew > 0, false,
408         "Set new file_id for face %{public}s failed, file_id %{public}d <= 0", faceInfo.faceId.c_str(),
409         faceInfo.fileIdNew);
410     return true;
411 }
412 
SetTagIdNew(FaceInfo & faceInfo,const std::unordered_map<std::string,std::string> & tagIdMap)413 bool BackupDatabaseUtils::SetTagIdNew(FaceInfo &faceInfo, const std::unordered_map<std::string, std::string> &tagIdMap)
414 {
415     CHECK_AND_RETURN_RET_LOG(!faceInfo.tagIdOld.empty(), false,
416         "Set new tag_id for face %{public}s failed, empty tag_id", faceInfo.faceId.c_str());
417     if (tagIdMap.count(faceInfo.tagIdOld) == 0) {
418         faceInfo.tagIdNew = TAG_ID_UNPROCESSED;
419         return true;
420     }
421     faceInfo.tagIdNew = tagIdMap.at(faceInfo.tagIdOld);
422     if (faceInfo.tagIdNew.empty() || !MediaFileUtils::StartsWith(faceInfo.tagIdNew, TAG_ID_PREFIX)) {
423         MEDIA_ERR_LOG("Set new tag_id for face %{public}s failed, new tag_id %{public}s empty or invalid",
424             faceInfo.tagIdNew.c_str(), faceInfo.faceId.c_str());
425         return false;
426     }
427     return true;
428 }
429 
SetAlbumIdNew(FaceInfo & faceInfo,const std::unordered_map<std::string,int32_t> & albumIdMap)430 bool BackupDatabaseUtils::SetAlbumIdNew(FaceInfo &faceInfo, const std::unordered_map<std::string, int32_t> &albumIdMap)
431 {
432     CHECK_AND_RETURN_RET(faceInfo.tagIdNew != TAG_ID_UNPROCESSED, true);
433     CHECK_AND_RETURN_RET_LOG(albumIdMap.count(faceInfo.tagIdNew) != 0, false,
434         "Set new album_id for face %{public}s failed, no such tag_id", faceInfo.faceId.c_str());
435 
436     faceInfo.albumIdNew = albumIdMap.at(faceInfo.tagIdNew);
437     CHECK_AND_RETURN_RET_LOG(faceInfo.albumIdNew > 0, false,
438         "Set new album_id for face %{public}s failed, album_id %{public}d <= 0", faceInfo.faceId.c_str(),
439         faceInfo.albumIdNew);
440     return true;
441 }
442 
PrintErrorLog(const std::string & errorLog,int64_t start)443 void BackupDatabaseUtils::PrintErrorLog(const std::string &errorLog, int64_t start)
444 {
445     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
446     MEDIA_INFO_LOG("%{public}s, cost %{public}ld", errorLog.c_str(), (long)(end - start));
447 }
448 
GetLandmarksScale(int32_t width,int32_t height)449 float BackupDatabaseUtils::GetLandmarksScale(int32_t width, int32_t height)
450 {
451     float scale = 1;
452     int32_t minWidthHeight = width <= height ? width : height;
453     if (minWidthHeight >= SCALE_MIN_SIZE * SCALE_FACTOR) {
454         minWidthHeight = static_cast<int32_t>(minWidthHeight * SCALE_DEFAULT);
455         scale = SCALE_DEFAULT;
456         if (minWidthHeight < SCALE_MIN_SIZE) {
457             minWidthHeight *= SCALE_FACTOR;
458             scale *= SCALE_FACTOR;
459         }
460         if (minWidthHeight < SCALE_MIN_SIZE) {
461             scale = 1;
462         }
463     }
464     width = static_cast<int32_t>(width * scale);
465     height = static_cast<int32_t>(height * scale);
466     int32_t maxWidthHeight = width >= height ? width : height;
467     scale *= maxWidthHeight >= SCALE_MAX_SIZE ? static_cast<float>(SCALE_MAX_SIZE) / maxWidthHeight : 1;
468     return scale;
469 }
470 
IsLandmarkValid(const FaceInfo & faceInfo,float landmarkX,float landmarkY)471 bool BackupDatabaseUtils::IsLandmarkValid(const FaceInfo &faceInfo, float landmarkX, float landmarkY)
472 {
473     return IsValInBound(landmarkX, faceInfo.scaleX, faceInfo.scaleX + faceInfo.scaleWidth) &&
474         IsValInBound(landmarkY, faceInfo.scaleY, faceInfo.scaleY + faceInfo.scaleHeight);
475 }
476 
IsValInBound(float val,float minVal,float maxVal)477 bool BackupDatabaseUtils::IsValInBound(float val, float minVal, float maxVal)
478 {
479     return val >= minVal && val <= maxVal;
480 }
481 
GetColumnInfoPairs(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & tableName)482 std::vector<std::pair<std::string, std::string>> BackupDatabaseUtils::GetColumnInfoPairs(
483     const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &tableName)
484 {
485     std::vector<std::pair<std::string, std::string>> columnInfoPairs;
486     std::string querySql = "SELECT name, type FROM pragma_table_info('" + tableName + "')";
487     auto resultSet = GetQueryResultSet(rdbStore, querySql);
488     if (resultSet == nullptr) {
489         MEDIA_ERR_LOG("resultSet is nullptr");
490         return columnInfoPairs;
491     }
492     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
493         std::string columnName = GetStringVal(PRAGMA_TABLE_NAME, resultSet);
494         std::string columnType = GetStringVal(PRAGMA_TABLE_TYPE, resultSet);
495         if (columnName.empty() || columnType.empty()) {
496             MEDIA_ERR_LOG("Empty column name or type: %{public}s, %{public}s", columnName.c_str(), columnType.c_str());
497             continue;
498         }
499         columnInfoPairs.emplace_back(columnName, columnType);
500     }
501 
502     return columnInfoPairs;
503 }
504 
GetCommonColumnInfos(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,std::string tableName)505 std::vector<std::string> BackupDatabaseUtils::GetCommonColumnInfos(std::shared_ptr<NativeRdb::RdbStore> mediaRdb,
506     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb, std::string tableName)
507 {
508     std::vector<std::string> commonColumns;
509     auto mediaRdbColumnInfoPairs = BackupDatabaseUtils::GetColumnInfoPairs(mediaRdb, tableName);
510     auto mediaLibraryRdbColumnInfoPairs = BackupDatabaseUtils::GetColumnInfoPairs(mediaLibraryRdb, tableName);
511 
512     for (const auto &pair : mediaRdbColumnInfoPairs) {
513         auto it = std::find_if(mediaLibraryRdbColumnInfoPairs.begin(), mediaLibraryRdbColumnInfoPairs.end(),
514             [&](const std::pair<std::string, std::string> &p) {
515                 return p.first == pair.first && p.second == pair.second;
516             });
517         if (it != mediaLibraryRdbColumnInfoPairs.end()) {
518             commonColumns.emplace_back(pair.first);
519         }
520     }
521 
522     return commonColumns;
523 }
524 
filterColumns(const std::vector<std::string> & allColumns,const std::vector<std::string> & excludedColumns)525 std::vector<std::string> BackupDatabaseUtils::filterColumns(const std::vector<std::string>& allColumns,
526     const std::vector<std::string>& excludedColumns)
527 {
528     std::vector<std::string> filteredColumns;
529     std::copy_if(allColumns.begin(), allColumns.end(), std::back_inserter(filteredColumns),
530         [&excludedColumns](const std::string& column) {
531             return std::find(excludedColumns.begin(), excludedColumns.end(), column) == excludedColumns.end();
532         });
533     return filteredColumns;
534 }
535 
UpdateAnalysisPhotoMapStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)536 void BackupDatabaseUtils::UpdateAnalysisPhotoMapStatus(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
537 {
538     std::string insertSql =
539         "INSERT OR REPLACE INTO AnalysisPhotoMap (map_album, map_asset) "
540         "SELECT AnalysisAlbum.album_id, tab_analysis_image_face.file_id "
541         "FROM AnalysisAlbum "
542         "INNER JOIN tab_analysis_image_face ON AnalysisAlbum.tag_id = tab_analysis_image_face.tag_id";
543 
544     int32_t ret = BackupDatabaseUtils::ExecuteSQL(rdbStore, insertSql);
545     CHECK_AND_PRINT_LOG(ret >= 0, "execute update AnalysisPhotoMap failed, ret=%{public}d", ret);
546 }
547 
CollectFileIdPairs(const std::vector<FileInfo> & fileInfos)548 std::vector<FileIdPair> BackupDatabaseUtils::CollectFileIdPairs(const std::vector<FileInfo>& fileInfos)
549 {
550     std::set<FileIdPair> uniquePairs;
551 
552     for (const auto& fileInfo : fileInfos) {
553         uniquePairs.emplace(fileInfo.fileIdOld, fileInfo.fileIdNew);
554     }
555 
556     return std::vector<FileIdPair>(uniquePairs.begin(), uniquePairs.end());
557 }
558 
UnzipFileIdPairs(const std::vector<FileIdPair> & pairs)559 std::pair<std::vector<int32_t>, std::vector<int32_t>> BackupDatabaseUtils::UnzipFileIdPairs(
560     const std::vector<FileIdPair>& pairs)
561 {
562     std::vector<int32_t> oldFileIds;
563     std::vector<int32_t> newFileIds;
564 
565     for (const auto& pair : pairs) {
566         oldFileIds.push_back(pair.first);
567         newFileIds.push_back(pair.second);
568     }
569 
570     return {oldFileIds, newFileIds};
571 }
572 
SplitString(const std::string & str,char delimiter)573 std::vector<std::string> BackupDatabaseUtils::SplitString(const std::string& str, char delimiter)
574 {
575     std::vector<std::string> elements;
576     std::stringstream ss(str);
577     std::string item;
578     while (std::getline(ss, item, delimiter)) {
579         if (!item.empty()) {
580             elements.emplace_back(item);
581         }
582     }
583     return elements;
584 }
585 
PrintQuerySql(const std::string & querySql)586 void BackupDatabaseUtils::PrintQuerySql(const std::string& querySql)
587 {
588     MEDIA_INFO_LOG("Generated SQL Query:");
589     MEDIA_INFO_LOG("--------------------");
590     MEDIA_INFO_LOG("%{public}s", querySql.c_str());
591     MEDIA_INFO_LOG("--------------------");
592 }
593 
DeleteDuplicatePortraitAlbum(const std::vector<std::string> & albumNames,const std::vector<std::string> tagIds,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)594 bool BackupDatabaseUtils::DeleteDuplicatePortraitAlbum(const std::vector<std::string> &albumNames,
595     const std::vector<std::string> tagIds, std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
596 {
597     std::set<std::string> uniqueAlbums(albumNames.begin(), albumNames.end());
598     std::vector<std::string> uniqueAlbumNames(uniqueAlbums.begin(), uniqueAlbums.end());
599     MEDIA_INFO_LOG("unique AlbumName %{public}zu", uniqueAlbumNames.size());
600 
601     std::string inClause = BackupDatabaseUtils::JoinSQLValues<string>(uniqueAlbumNames, ", ");
602     std::string tagIdClause;
603     if (!tagIds.empty()) {
604         tagIdClause = "(" + BackupDatabaseUtils::JoinSQLValues<string>(tagIds, ", ") + ")";
605     }
606     // 删除 VisionFaceTag 表中的记录
607     std::string deleteFaceTagSql = "DELETE FROM " + VISION_FACE_TAG_TABLE +
608                                    " WHERE tag_id IN (SELECT A.tag_id FROM " + ANALYSIS_ALBUM_TABLE + " AS A, " +
609                                    VISION_FACE_TAG_TABLE + " AS B WHERE A.tag_id = B.tag_id AND " +
610                                    ANALYSIS_COL_ALBUM_NAME + " IN (" + inClause + "))";
611     ExecuteSQL(mediaLibraryRdb, deleteFaceTagSql);
612 
613     std::string imageFaceClause = "tag_id IN (SELECT A.tag_id FROM " + ANALYSIS_ALBUM_TABLE + " AS A, " +
614         VISION_IMAGE_FACE_TABLE + " AS B WHERE A.tag_id = B.tag_id AND " +
615         ANALYSIS_COL_ALBUM_NAME + " IN (" + inClause + "))";
616 
617     std::unique_ptr<NativeRdb::AbsRdbPredicates> updatePredicates =
618             make_unique<NativeRdb::AbsRdbPredicates>(VISION_IMAGE_FACE_TABLE);
619     updatePredicates->SetWhereClause(imageFaceClause);
620     int32_t deletedRows = 0;
621     NativeRdb::ValuesBucket valuesBucket;
622     valuesBucket.PutString(FACE_TAG_COL_TAG_ID, std::string("-1"));
623 
624     int32_t ret = BackupDatabaseUtils::Update(mediaLibraryRdb, deletedRows, valuesBucket, updatePredicates);
625     if (deletedRows < 0 || ret < 0) {
626         MEDIA_ERR_LOG("Failed to update tag_id colum value");
627         return false;
628     }
629 
630     /* 删除 AnalysisAlbum 表中的记录 */
631     std::string deleteAnalysisSql = "DELETE FROM " + ANALYSIS_ALBUM_TABLE +
632                                     " WHERE " + ANALYSIS_COL_ALBUM_NAME + " IN (" + inClause + ")";
633     if (!tagIds.empty()) {
634         deleteAnalysisSql += " OR ";
635         deleteAnalysisSql += "(" + ANALYSIS_COL_TAG_ID + " IN " + tagIdClause + ")";
636     }
637     ExecuteSQL(mediaLibraryRdb, deleteAnalysisSql);
638 
639     return true;
640 }
641 
ExecuteSQL(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & sql,const std::vector<NativeRdb::ValueObject> & args)642 int BackupDatabaseUtils::ExecuteSQL(std::shared_ptr<NativeRdb::RdbStore> rdbStore, const std::string& sql,
643     const std::vector<NativeRdb::ValueObject> &args)
644 {
645     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_FAIL, "rdbStore is nullptr");
646     return ExecSqlWithRetry([&]() { return rdbStore->ExecuteSql(sql, args); });
647 }
648 
BatchInsert(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & value,int64_t & rowNum)649 int32_t BackupDatabaseUtils::BatchInsert(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
650     const std::string &tableName, std::vector<NativeRdb::ValuesBucket> &value, int64_t &rowNum)
651 {
652     if (rdbStore == nullptr) {
653         MEDIA_ERR_LOG("rdbStore is nullptr");
654         return E_FAIL;
655     }
656     return ExecSqlWithRetry([&]() { return rdbStore->BatchInsert(rowNum, tableName, value); });
657 }
658 
DeleteExistingImageFaceData(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::vector<FileIdPair> & fileIdPair)659 void BackupDatabaseUtils::DeleteExistingImageFaceData(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
660     const std::vector<FileIdPair>& fileIdPair)
661 {
662     auto [oldFileIds, newFileIds] = BackupDatabaseUtils::UnzipFileIdPairs(fileIdPair);
663     std::string fileIdNewFilterClause = "(" + BackupDatabaseUtils::JoinValues<int>(newFileIds, ", ") + ")";
664 
665     std::string deleteAnalysisPhotoMapSql =
666         "DELETE FROM AnalysisPhotoMap WHERE map_asset IN ("
667         "SELECT " + IMAGE_FACE_COL_FILE_ID + " FROM " + VISION_IMAGE_FACE_TABLE +
668         " WHERE " + IMAGE_FACE_COL_FILE_ID + " IN " + fileIdNewFilterClause +
669         ") AND map_album IN (SELECT album_id FROM AnalysisAlbum WHERE album_type = 4096 AND album_subtype = 4102)";
670 
671     // 删除 AnalysisPhotoMap 表中的重复记录
672     BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb, deleteAnalysisPhotoMapSql);
673 
674     std::string deleteFaceSql = "DELETE FROM " + VISION_IMAGE_FACE_TABLE +
675         " WHERE " + IMAGE_FACE_COL_FILE_ID + " IN " + fileIdNewFilterClause;
676     BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb, deleteFaceSql);
677 }
678 
ParseFaceTagResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,TagPairOpt & tagPair)679 void BackupDatabaseUtils::ParseFaceTagResultSet(const std::shared_ptr<NativeRdb::ResultSet>& resultSet,
680     TagPairOpt& tagPair)
681 {
682     tagPair.first = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_TAG_ID);
683     tagPair.second = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_GROUP_TAG);
684 }
685 
QueryTagInfo(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)686 std::vector<TagPairOpt> BackupDatabaseUtils::QueryTagInfo(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
687 {
688     std::vector<TagPairOpt> result;
689     std::string querySql = "SELECT " + ANALYSIS_COL_TAG_ID + ", " +
690         ANALYSIS_COL_GROUP_TAG +
691         " FROM " + ANALYSIS_ALBUM_TABLE +
692         " WHERE " + ANALYSIS_COL_TAG_ID + " IS NOT NULL AND " +
693         ANALYSIS_COL_TAG_ID + " != ''";
694 
695     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb, querySql);
696     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, result, "Query resultSet is null.");
697 
698     while (resultSet->GoToNextRow () == NativeRdb::E_OK) {
699         TagPairOpt tagPair;
700         ParseFaceTagResultSet(resultSet, tagPair);
701         result.emplace_back(tagPair);
702     }
703     return result;
704 }
705 
UpdateGroupTagColumn(const std::vector<TagPairOpt> & updatedPairs,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)706 void BackupDatabaseUtils::UpdateGroupTagColumn(const std::vector<TagPairOpt>& updatedPairs,
707     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
708 {
709     for (const auto& pair : updatedPairs) {
710         if (pair.first.has_value() && pair.second.has_value()) {
711             std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
712                 std::make_unique<NativeRdb::AbsRdbPredicates>(ANALYSIS_ALBUM_TABLE);
713             std::string whereClause = ANALYSIS_COL_TAG_ID + " = '" + pair.first.value() + "'";
714             predicates->SetWhereClause(whereClause);
715 
716             int32_t updatedRows = 0;
717             NativeRdb::ValuesBucket valuesBucket;
718             valuesBucket.PutString(ANALYSIS_COL_GROUP_TAG, pair.second.value());
719 
720             int32_t ret = BackupDatabaseUtils::Update(mediaLibraryRdb, updatedRows, valuesBucket, predicates);
721             if (updatedRows <= 0 || ret < 0) {
722                 MEDIA_ERR_LOG("Failed to update group_tag for tag_id: %s", pair.first.value().c_str());
723             }
724         }
725     }
726 }
727 
UpdateFaceGroupTagsUnion(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)728 void BackupDatabaseUtils::UpdateFaceGroupTagsUnion(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
729 {
730     std::vector<TagPairOpt> tagPairs = QueryTagInfo(mediaLibraryRdb);
731     std::vector<TagPairOpt> updatedPairs;
732     std::vector<std::string> allTagIds;
733     for (const auto& pair : tagPairs) {
734         if (pair.first.has_value()) {
735             allTagIds.emplace_back(pair.first.value());
736         }
737     }
738     MEDIA_INFO_LOG("get all TagId  %{public}zu", allTagIds.size());
739     for (const auto& pair : tagPairs) {
740         if (pair.second.has_value()) {
741             std::vector<std::string> groupTags = BackupDatabaseUtils::SplitString(pair.second.value(), '|');
742             MEDIA_INFO_LOG("TagId: %{public}s, old GroupTags is: %{public}s",
743                            pair.first.value_or(std::string("-1")).c_str(), pair.second.value().c_str());
744             groupTags.erase(std::remove_if(groupTags.begin(), groupTags.end(),
745                 [&allTagIds](const std::string& tagId) {
746                 return std::find(allTagIds.begin(), allTagIds.end(), tagId) == allTagIds.end();
747                 }),
748                 groupTags.end());
749 
750             std::string newGroupTag = BackupDatabaseUtils::JoinValues<std::string>(groupTags, "|");
751             if (newGroupTag != pair.second.value()) {
752                 updatedPairs.emplace_back(pair.first, newGroupTag);
753                 MEDIA_INFO_LOG("TagId: %{public}s  GroupTags updated", pair.first.value().c_str());
754             }
755         }
756     }
757 
758     UpdateGroupTagColumn(updatedPairs, mediaLibraryRdb);
759 }
760 
UpdateTagPairs(std::vector<TagPairOpt> & updatedPairs,const std::string & newGroupTag,const std::vector<std::string> & tagIds)761 void BackupDatabaseUtils::UpdateTagPairs(std::vector<TagPairOpt>& updatedPairs, const std::string& newGroupTag,
762     const std::vector<std::string>& tagIds)
763 {
764     for (const auto& tagId : tagIds) {
765         updatedPairs.emplace_back(tagId, newGroupTag);
766     }
767 }
768 
UpdateGroupTags(std::vector<TagPairOpt> & updatedPairs,const std::unordered_map<std::string,std::vector<std::string>> & groupTagMap)769 void BackupDatabaseUtils::UpdateGroupTags(std::vector<TagPairOpt>& updatedPairs,
770     const std::unordered_map<std::string, std::vector<std::string>>& groupTagMap)
771 {
772     for (auto &[groupTag, tagIds] : groupTagMap) {
773         if (tagIds.empty()) {
774             continue;
775         }
776 
777         const std::string newGroupTag =
778             (tagIds.size() > 1) ? BackupDatabaseUtils::JoinValues(tagIds, "|") : tagIds.front();
779         if (newGroupTag != groupTag) {
780             UpdateTagPairs(updatedPairs, newGroupTag, tagIds);
781         }
782     }
783 }
784 
785     /* 双框架的group_id是合并相册之一的某一 tag_id */
UpdateFaceGroupTagOfDualFrame(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)786 void BackupDatabaseUtils::UpdateFaceGroupTagOfDualFrame(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
787 {
788     std::vector<TagPairOpt> tagPairs = QueryTagInfo(mediaLibraryRdb);
789     std::vector<TagPairOpt> updatedPairs;
790     std::unordered_map<std::string, std::vector<std::string>> groupTagMap;
791 
792     for (const auto& pair : tagPairs) {
793         if (pair.first.has_value() && pair.second.has_value()) {
794             groupTagMap[pair.second.value()].push_back(pair.first.value());
795         } else {
796             MEDIA_INFO_LOG("Found tag_id without group_tag: %{public}s", pair.first.value().c_str());
797         }
798     }
799 
800     UpdateGroupTags(updatedPairs, groupTagMap);
801     UpdateGroupTagColumn(updatedPairs, mediaLibraryRdb);
802 }
803 
UpdateAssociateFileId(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::vector<FileInfo> & fileInfos)804 void BackupDatabaseUtils::UpdateAssociateFileId(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
805     const std::vector<FileInfo> &fileInfos)
806 {
807     for (const FileInfo &fileInfo : fileInfos) {
808         if (fileInfo.associateFileId <= 0 || fileInfo.fileIdOld <= 0 || fileInfo.fileIdNew <= 0) {
809             continue;
810         }
811         int32_t updateAssociateId = -1;
812         bool ret = fileIdOld2NewForCloudEnhancement.Find(fileInfo.associateFileId, updateAssociateId);
813         if (!ret) {
814             fileIdOld2NewForCloudEnhancement.Insert(fileInfo.fileIdOld, fileInfo.fileIdNew);
815             continue;
816         }
817         int32_t changeRows = 0;
818         NativeRdb::ValuesBucket updatePostBucket;
819         updatePostBucket.Put(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, updateAssociateId);
820         std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
821             make_unique<NativeRdb::AbsRdbPredicates>(PhotoColumn::PHOTOS_TABLE);
822         predicates->SetWhereClause("file_id=?");
823         predicates->SetWhereArgs({ to_string(fileInfo.fileIdNew) });
824         BackupDatabaseUtils::Update(rdbStore, changeRows, updatePostBucket, predicates);
825         if (changeRows > 0) {
826             MEDIA_INFO_LOG("update, old:%{public}d, new:%{public}d, old_associate:%{public}d, new_associate:%{public}d",
827                 fileInfo.fileIdOld, fileInfo.fileIdNew, fileInfo.associateFileId, updateAssociateId);
828         }
829 
830         NativeRdb::ValuesBucket updatePreBucket;
831         updatePreBucket.Put(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, fileInfo.fileIdNew);
832         predicates->SetWhereArgs({ to_string(updateAssociateId) });
833         BackupDatabaseUtils::Update(rdbStore, changeRows, updatePreBucket, predicates);
834         if (changeRows > 0) {
835             MEDIA_INFO_LOG("update, old:%{public}d, new:%{public}d, new_associate:%{public}d",
836                 fileInfo.associateFileId, updateAssociateId, fileInfo.fileIdNew);
837         }
838         fileIdOld2NewForCloudEnhancement.Erase(fileInfo.associateFileId);
839     }
840 }
841 
BatchUpdatePhotosToLocal(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::vector<std::string> & inColumn)842 void BackupDatabaseUtils::BatchUpdatePhotosToLocal(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
843     const std::vector<std::string> &inColumn)
844 {
845     CHECK_AND_RETURN(!inColumn.empty());
846 
847     int32_t changeRows = 0;
848     std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
849         make_unique<NativeRdb::AbsRdbPredicates>(PhotoColumn::PHOTOS_TABLE);
850     predicates->In(MediaColumn::MEDIA_ID, inColumn);
851     NativeRdb::ValuesBucket updatePostBucket;
852     updatePostBucket.Put(PhotoColumn::PHOTO_CLEAN_FLAG, 0);
853     updatePostBucket.Put(PhotoColumn::PHOTO_POSITION, static_cast<int32_t>(PhotoPositionType::LOCAL));
854     updatePostBucket.PutNull(PhotoColumn::PHOTO_CLOUD_ID);
855     updatePostBucket.PutNull(PhotoColumn::PHOTO_CLOUD_VERSION);
856     updatePostBucket.Put(PhotoColumn::PHOTO_THUMBNAIL_READY, 0);
857     updatePostBucket.Put(PhotoColumn::PHOTO_THUMB_STATUS, static_cast<int32_t>(PhotoThumbStatusType::NOT_DOWNLOADED));
858     updatePostBucket.Put(PhotoColumn::PHOTO_LCD_VISIT_TIME, 0);
859     updatePostBucket.Put(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, 0);
860 
861     BackupDatabaseUtils::Update(mediaLibraryRdb, changeRows, updatePostBucket, predicates);
862     if (changeRows != static_cast<int32_t>(inColumn.size())) {
863         MEDIA_ERR_LOG("update failed, UpdatePhotoToLocal, expected count %{public}d, but got %{public}d",
864             static_cast<int32_t>(inColumn.size()), changeRows);
865     }
866 }
867 
CheckDbIntegrity(std::shared_ptr<NativeRdb::RdbStore> rdbStore,int32_t sceneCode,const std::string & dbTag)868 std::string BackupDatabaseUtils::CheckDbIntegrity(std::shared_ptr<NativeRdb::RdbStore> rdbStore, int32_t sceneCode,
869     const std::string &dbTag)
870 {
871     const std::string querySql = "PRAGMA " + COLUMN_INTEGRITY_CHECK;
872     auto resultSet = GetQueryResultSet(rdbStore, querySql);
873     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
874         MEDIA_ERR_LOG ("Query resultSet is null or GoToFirstRow failed.");
875         return "";
876     }
877     std::string result = GetStringVal(COLUMN_INTEGRITY_CHECK, resultSet);
878     MEDIA_INFO_LOG("Check db integrity: %{public}d, %{public}s, %{public}s", sceneCode, dbTag.c_str(), result.c_str());
879     return result;
880 }
881 
QueryLocalNoAstcCount(std::shared_ptr<NativeRdb::RdbStore> rdbStore)882 int32_t BackupDatabaseUtils::QueryLocalNoAstcCount(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
883 {
884     const std::string QUERY_LOCAL_NO_ASTC_COUNT = "SELECT count(1) AS count FROM Photos "
885         "WHERE " + PhotoColumn::PHOTO_POSITION + " = 1 AND " + PhotoColumn::PHOTO_THUMBNAIL_VISIBLE + " = 0 " +
886         "AND " + MediaColumn::MEDIA_DATE_TRASHED + " = 0 AND " + MediaColumn::MEDIA_TIME_PENDING +  "= 0 " +
887         "AND " + MediaColumn::MEDIA_HIDDEN + " = 0 AND " + PhotoColumn::PHOTO_IS_TEMP + " = 0 " +
888         "AND " + PhotoColumn::PHOTO_BURST_COVER_LEVEL + " = 1 AND " + PhotoColumn::PHOTO_CLEAN_FLAG + " = 0 " +
889         "AND " + PhotoColumn::PHOTO_SYNC_STATUS + " = 0";
890     return QueryInt(rdbStore, QUERY_LOCAL_NO_ASTC_COUNT, CUSTOM_COUNT);
891 }
892 
QueryReadyAstcCount(std::shared_ptr<NativeRdb::RdbStore> rdbStore)893 int32_t BackupDatabaseUtils::QueryReadyAstcCount(std::shared_ptr<NativeRdb::RdbStore> rdbStore)
894 {
895     const std::string QUERY_READY_ASTC_COUNT = "SELECT count(1) AS count FROM Photos WHERE " +
896         PhotoColumn::PHOTO_THUMBNAIL_VISIBLE + " = 1";
897     return QueryInt(rdbStore, QUERY_READY_ASTC_COUNT, CUSTOM_COUNT);
898 }
899 
QueryMediaTypeCount(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & querySql)900 std::unordered_map<int32_t, int32_t> BackupDatabaseUtils::QueryMediaTypeCount(
901     const std::shared_ptr<NativeRdb::RdbStore>& rdbStore, const std::string& querySql)
902 {
903     std::unordered_map<int32_t, int32_t> mediaTypeCountMap;
904     auto resultSet = GetQueryResultSet(rdbStore, querySql);
905     if (resultSet == nullptr) {
906         MEDIA_ERR_LOG("resultSet is nullptr");
907         return mediaTypeCountMap;
908     }
909     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
910         int32_t mediaType = GetInt32Val(EXTERNAL_MEDIA_TYPE, resultSet);
911         int32_t count = GetInt32Val(CUSTOM_COUNT, resultSet);
912         mediaTypeCountMap[mediaType] = count;
913     }
914     return mediaTypeCountMap;
915 }
916 
QuerySql(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::string & querySql,const std::vector<NativeRdb::ValueObject> & params)917 std::shared_ptr<NativeRdb::ResultSet> BackupDatabaseUtils::QuerySql(
918     std::shared_ptr<NativeRdb::RdbStore> rdbStore, const std::string &querySql,
919     const std::vector<NativeRdb::ValueObject> &params)
920 {
921     if (rdbStore == nullptr) {
922         MEDIA_ERR_LOG("rdbStore is nullptr");
923         return nullptr;
924     }
925     return rdbStore->QuerySql(querySql, params);
926 }
927 
UpdateBurstPhotos(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore)928 void BackupDatabaseUtils::UpdateBurstPhotos(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore)
929 {
930     const string updateSql =
931         "UPDATE " + PhotoColumn::PHOTOS_TABLE + " SET " + PhotoColumn::PHOTO_BURST_COVER_LEVEL + " = 1," +
932         PhotoColumn::PHOTO_BURST_KEY + " = NULL WHERE " + SQL_SELECT_ERROR_BURST_PHOTOS +
933         "AND file_id IN (" + SQL_SELECT_CLONE_FILE_IDS + ")";
934     int32_t erroCode = BackupDatabaseUtils::ExecuteSQL(rdbStore, updateSql);
935     CHECK_AND_PRINT_LOG(erroCode >= 0, "execute update continuous shooting photos, ret=%{public}d", erroCode);
936 }
937 } // namespace Media
938 } // namespace OHOS