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