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