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