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