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