1 /*
2  * Copyright (C) 2024-2024 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 #define MLOG_TAG "AnalysisAlbumOperation"
16 
17 #include "medialibrary_analysis_album_operations.h"
18 
19 #include <cstddef>
20 #include <cstdio>
21 #include <cstring>
22 #include <algorithm>
23 
24 #include "media_log.h"
25 #include "medialibrary_db_const.h"
26 #include "medialibrary_errno.h"
27 #include "medialibrary_notify.h"
28 #include "medialibrary_object_utils.h"
29 #include "medialibrary_unistore_manager.h"
30 #include "medialibrary_data_manager.h"
31 #include "medialibrary_rdb_transaction.h"
32 #include "media_file_uri.h"
33 #include "media_file_utils.h"
34 #include "result_set_utils.h"
35 #include "values_bucket.h"
36 #include "photo_album_column.h"
37 #include "photo_map_column.h"
38 #include "vision_album_column.h"
39 #include "vision_face_tag_column.h"
40 #include "vision_image_face_column.h"
41 #include "vision_photo_map_column.h"
42 #include "vision_total_column.h"
43 
44 using namespace std;
45 using namespace OHOS::NativeRdb;
46 using namespace OHOS::DataShare;
47 using namespace OHOS::RdbDataShareAdapter;
48 
49 namespace OHOS::Media {
50 constexpr int32_t E_INDEX = -1;
51 constexpr int32_t ALBUM_IS_ME = 1;
52 constexpr int32_t ALBUM_IS_NOT_ME = 0;
53 constexpr int32_t ALBUM_IS_REMOVED = 1;
54 constexpr int32_t SINGLE_FACE = 1;
55 constexpr int32_t LOCAL_ALBUM = 1;
56 constexpr int32_t ALBUM_NOT_FOUND = 0;
57 constexpr int32_t QUERY_GROUP_PHOTO_ALBUM_RELATED_TO_ME = 1;
58 const string GROUP_PHOTO_TAG = "group_photo_tag";
59 const string GROUP_PHOTO_IS_ME = "group_photo_is_me";
60 const string GROUP_PHOTO_ALBUM_NAME = "album_name";
61 static std::mutex updateGroupPhotoAlbumMutex;
62 
ExecSqls(const vector<string> & sqls,const shared_ptr<MediaLibraryUnistore> & store)63 static int32_t ExecSqls(const vector<string> &sqls, const shared_ptr<MediaLibraryUnistore> &store)
64 {
65     int32_t err = NativeRdb::E_OK;
66     for (const auto &sql : sqls) {
67         err = store->ExecuteSql(sql);
68         if (err != NativeRdb::E_OK) {
69             MEDIA_ERR_LOG("Failed to exec: %{private}s", sql.c_str());
70             break;
71         }
72     }
73     return err;
74 }
75 
GetArgsValueByName(const string & valueName,const string & whereClause,const vector<string> & whereArgs)76 static int32_t GetArgsValueByName(const string &valueName, const string &whereClause, const vector<string> &whereArgs)
77 {
78     size_t pos = whereClause.find(valueName);
79     if (pos == string::npos) {
80         MEDIA_ERR_LOG("whereClause is invalid");
81         return E_INDEX;
82     }
83     size_t argsIndex = 0;
84     for (size_t i = 0; i < pos; i++) {
85         if (whereClause[i] == '?') {
86             argsIndex++;
87         }
88     }
89     if (argsIndex > whereArgs.size() - 1) {
90         MEDIA_ERR_LOG("whereArgs is invalid");
91         return E_INDEX;
92     }
93     return atoi(whereArgs[argsIndex].c_str());
94 }
95 
GetAlbumId(const string & whereClause,const vector<string> & whereArgs)96 static int32_t GetAlbumId(const string &whereClause, const vector<string> &whereArgs)
97 {
98     size_t pos = whereClause.find(PhotoAlbumColumns::ALBUM_ID);
99     if (pos == string::npos) {
100         MEDIA_ERR_LOG("whereClause is invalid");
101         return E_INDEX;
102     }
103     size_t argsIndex = 0;
104     for (size_t i = 0; i < pos; i++) {
105         if (whereClause[i] == '?') {
106             argsIndex++;
107         }
108     }
109     if (argsIndex > whereArgs.size() - 1) {
110         MEDIA_ERR_LOG("whereArgs is invalid");
111         return E_INDEX;
112     }
113     auto albumId = whereArgs[argsIndex];
114     if (MediaLibraryDataManagerUtils::IsNumber(albumId)) {
115         return atoi(albumId.c_str());
116     }
117     return E_INDEX;
118 }
119 
GetIntValueFromResultSet(shared_ptr<NativeRdb::ResultSet> resultSet,const string & column,int & value)120 static int32_t GetIntValueFromResultSet(shared_ptr<NativeRdb::ResultSet> resultSet, const string &column, int &value)
121 {
122     int index = E_INDEX;
123     resultSet->GetColumnIndex(column, index);
124     if (index == E_INDEX) {
125         return E_HAS_DB_ERROR;
126     }
127     if (resultSet->GetInt(index, value) != NativeRdb::E_OK) {
128         return E_HAS_DB_ERROR;
129     }
130     return E_OK;
131 }
132 
GetStringValueFromResultSet(shared_ptr<NativeRdb::ResultSet> resultSet,const string & column,string & value)133 static int32_t GetStringValueFromResultSet(shared_ptr<NativeRdb::ResultSet> resultSet, const string &column,
134     string &value)
135 {
136     if (resultSet == nullptr) {
137         return E_HAS_DB_ERROR;
138     }
139     int index = E_INDEX;
140     resultSet->GetColumnIndex(column, index);
141     if (index == E_INDEX) {
142         return E_HAS_DB_ERROR;
143     }
144     if (resultSet->GetString(index, value) != NativeRdb::E_OK) {
145         return E_HAS_DB_ERROR;
146     }
147     return E_OK;
148 }
149 
GetCoverUri(int32_t fileId,const string & path,const string & displayName)150 static string GetCoverUri(int32_t fileId, const string &path, const string &displayName)
151 {
152     string fileName;
153     size_t lastSlash = path.find_last_of('/');
154     if (lastSlash != string::npos && path.size() > (lastSlash + 1)) {
155         fileName = path.substr(lastSlash + 1);
156     }
157     string fileTitle = fileName;
158     size_t lastDot = fileName.find_last_of('.');
159     if (lastDot != string::npos) {
160         fileTitle = fileName.substr(0, lastDot);
161     }
162     return PhotoColumn::PHOTO_URI_PREFIX + to_string(fileId) + "/" + fileTitle + "/" + displayName;
163 }
164 
GetStringObject(const ValuesBucket & values,const string & key,string & value)165 inline int32_t GetStringObject(const ValuesBucket &values, const string &key, string &value)
166 {
167     value = "";
168     ValueObject valueObject;
169     if (values.GetObject(key, valueObject)) {
170         valueObject.GetString(value);
171     } else {
172         return -EINVAL;
173     }
174     return E_OK;
175 }
176 
NotifyGroupAlbum(const vector<int32_t> & changedAlbumIds)177 static void NotifyGroupAlbum(const vector<int32_t> &changedAlbumIds)
178 {
179     if (changedAlbumIds.size() <= 0) {
180         return;
181     }
182     auto watch = MediaLibraryNotify::GetInstance();
183     for (int32_t albumId : changedAlbumIds) {
184         watch->Notify(MediaFileUtils::GetUriByExtrConditions(
185             PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX, to_string(albumId)), NotifyType::NOTIFY_UPDATE);
186     }
187 }
188 
ClearEmptyGroupPhotoAlbumInfo(const vector<GroupPhotoAlbumInfo> & clearAlbums)189 static void ClearEmptyGroupPhotoAlbumInfo(const vector<GroupPhotoAlbumInfo> &clearAlbums)
190 {
191     if (clearAlbums.empty()) {
192         return;
193     }
194     ValuesBucket values;
195     values.PutInt(PhotoAlbumColumns::ALBUM_COUNT, 0);
196     values.PutString(PhotoAlbumColumns::ALBUM_COVER_URI, "");
197     values.PutInt(IS_COVER_SATISFIED, static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING));
198     values.PutInt(IS_ME, ALBUM_IS_NOT_ME);
199 
200     RdbPredicates rdbPredicates(ANALYSIS_ALBUM_TABLE);
201     stringstream ss;
202     for (size_t i = 0; i < clearAlbums.size(); i++) {
203         ss << clearAlbums[i].albumId;
204         if (i != clearAlbums.size() - 1) {
205             ss << ", ";
206         }
207     }
208     string clause = PhotoAlbumColumns::ALBUM_ID + " IN (" + ss.str() + ") AND ";
209     rdbPredicates.SetWhereClause(clause);
210     rdbPredicates.EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SMART));
211     rdbPredicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::GROUP_PHOTO));
212     auto ret = MediaLibraryRdbStore::UpdateWithDateTime(values, rdbPredicates);
213     if (ret != NativeRdb::E_OK) {
214         MEDIA_ERR_LOG("Clear empty group photo album info failed! Error: %{public}d", ret);
215     }
216 }
217 
BuildUpdateGroupPhotoAlbumSql(const GroupPhotoAlbumInfo & albumInfo)218 static string BuildUpdateGroupPhotoAlbumSql(const GroupPhotoAlbumInfo &albumInfo)
219 {
220     string withSql;
221     string coverUriValueSql;
222     string isCoverSatisfiedValueSql;
223     if (albumInfo.isCoverSatisfied == static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING)) {
224         coverUriValueSql = "'" + albumInfo.candidateUri + "'";
225         isCoverSatisfiedValueSql = to_string(static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING));
226     } else {
227         string oldCoverId = MediaFileUri::GetPhotoId(albumInfo.coverUri);
228         if (!oldCoverId.empty() && MediaLibraryDataManagerUtils::IsNumber(oldCoverId)) {
229             withSql = "WITH temp_table AS (SELECT COUNT(1) > 0 AS is_cover_exist FROM " + ANALYSIS_ALBUM_TABLE +
230                 " INNER JOIN " + ANALYSIS_PHOTO_MAP_TABLE + " ON " +
231                 MAP_ALBUM + " = " + ALBUM_ID + " AND INSTR('" + albumInfo.tagId + "', " + GROUP_TAG + ") > 0" +
232                 " INNER JOIN " + VISION_IMAGE_FACE_TABLE + " F ON " +
233                 MAP_ASSET + " = F." + MediaColumn::MEDIA_ID +
234                 " INNER JOIN " + PhotoColumn::PHOTOS_TABLE + " P ON " +
235                 MAP_ASSET + " = P." + MediaColumn::MEDIA_ID + " AND " +
236                 MediaColumn::MEDIA_DATE_TRASHED + " = 0 AND " +
237                 MediaColumn::MEDIA_HIDDEN + " = 0 AND " +
238                 MediaColumn::MEDIA_TIME_PENDING + " = 0 AND P." +
239                 MediaColumn::MEDIA_ID + " = " + oldCoverId + ")";
240             coverUriValueSql = "CASE (SELECT is_cover_exist FROM temp_table) WHEN 1 THEN '" + albumInfo.coverUri +
241                 "' ELSE '" + albumInfo.candidateUri + "' END";
242             isCoverSatisfiedValueSql = "CASE (SELECT is_cover_exist FROM temp_table) WHEN 1 THEN " +
243                 to_string(albumInfo.isCoverSatisfied) + " ELSE " +
244                 to_string(static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING)) + " END";
245         } else {
246             coverUriValueSql = "'" + albumInfo.candidateUri + "'";
247             isCoverSatisfiedValueSql = to_string(static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING));
248         }
249     }
250     string albumNameArg = "";
251     if (!albumInfo.albumName.empty()) {
252         albumNameArg = ", " + GROUP_PHOTO_ALBUM_NAME + " = '" + albumInfo.albumName + "'";
253     }
254     string updateSql = withSql + " UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " +
255         PhotoAlbumColumns::ALBUM_COUNT + " = " + to_string(albumInfo.count) + ", " +
256         IS_ME + " = " + to_string(albumInfo.isMe) + ", " +
257         PhotoAlbumColumns::ALBUM_COVER_URI + " = " + coverUriValueSql + ", " +
258         IS_REMOVED + " = " + to_string(albumInfo.isRemoved) + ", " +
259         RENAME_OPERATION + " = " + to_string(albumInfo.renameOperation) + ", " +
260         IS_COVER_SATISFIED + " = " + isCoverSatisfiedValueSql + albumNameArg +
261         " WHERE " + PhotoAlbumColumns::ALBUM_ID + " = " + to_string(albumInfo.albumId) + ";";
262     return updateSql;
263 }
264 
UpdateGroupPhotoAlbumInfo(const vector<GroupPhotoAlbumInfo> & updateAlbums)265 static void UpdateGroupPhotoAlbumInfo(const vector<GroupPhotoAlbumInfo> &updateAlbums)
266 {
267     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
268     if (rdbStore == nullptr) {
269         MEDIA_ERR_LOG("Update group photo album info failed. rdbStore is null");
270         return;
271     }
272     auto rdbStorePtr = rdbStore;
273     if (rdbStorePtr == nullptr) {
274         MEDIA_ERR_LOG("Update group photo album info failed. rdbStorePtr is null");
275         return;
276     }
277     for (auto album : updateAlbums) {
278         string sql = BuildUpdateGroupPhotoAlbumSql(album);
279         auto ret = rdbStorePtr->ExecuteSql(sql);
280         if (ret != NativeRdb::E_OK) {
281             MEDIA_ERR_LOG("Update group photo album failed! Error: %{public}d", ret);
282         }
283     }
284 }
285 
InsertGroupPhotoAlbumInfo(const vector<GroupPhotoAlbumInfo> & insertAlbums,vector<int32_t> & insertAlbumsId)286 static void InsertGroupPhotoAlbumInfo(const vector<GroupPhotoAlbumInfo> &insertAlbums, vector<int32_t> &insertAlbumsId)
287 {
288     if (insertAlbums.empty()) {
289         return;
290     }
291     vector<DataShare::DataShareValuesBucket> insertValues;
292     for (auto album : insertAlbums) {
293         DataShare::DataShareValuesBucket values;
294         values.Put(PhotoAlbumColumns::ALBUM_TYPE, PhotoAlbumType::SMART);
295         values.Put(PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumSubType::GROUP_PHOTO);
296         values.Put(PhotoAlbumColumns::ALBUM_COVER_URI, album.candidateUri);
297         values.Put(PhotoAlbumColumns::ALBUM_COUNT, album.count);
298         values.Put(TAG_ID, album.tagId);
299         values.Put(GROUP_TAG, album.tagId);
300         values.Put(IS_ME, album.isMe);
301         values.Put(IS_LOCAL, LOCAL_ALBUM);
302         values.Put(IS_COVER_SATISFIED, static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING));
303         insertValues.push_back(values);
304     }
305     Uri uri(PAH_INSERT_ANA_PHOTO_ALBUM);
306     MediaLibraryCommand cmd(uri);
307     auto ret = MediaLibraryDataManager::GetInstance()->BatchInsert(cmd, insertValues);
308     if (ret >= 0) {
309         MEDIA_INFO_LOG("Insert %{public}d group photo album info.", ret);
310         RdbPredicates rdbPredicates(ANALYSIS_ALBUM_TABLE);
311         rdbPredicates.SetWhereClause(PhotoAlbumColumns::ALBUM_SUBTYPE + " = ?");
312         rdbPredicates.SetWhereArgs({ to_string(PhotoAlbumSubType::GROUP_PHOTO) });
313         rdbPredicates.OrderByDesc(PhotoAlbumColumns::ALBUM_ID);
314         std::vector<std::string> columns = { PhotoAlbumColumns::ALBUM_ID };
315         auto resultSet = MediaLibraryRdbStore::QueryWithFilter(rdbPredicates, columns);
316         if (resultSet == nullptr) {
317             return;
318         }
319         for (auto i = 0; i < ret; i++) {
320             resultSet->GoTo(i);
321             insertAlbumsId.push_back(GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet));
322         }
323     } else {
324         MEDIA_ERR_LOG("Insert group photo album info failed! Error: %{public}d.", ret);
325     }
326 }
327 
GetGroupPhotoAlbumSql()328 static string GetGroupPhotoAlbumSql()
329 {
330     string innerJoinAnalysisAlbum = "INNER JOIN " + ANALYSIS_ALBUM_TABLE + " AA ON F." +
331         TAG_ID + " = AA." + TAG_ID + " AND " + TOTAL_FACES + " > " + to_string(SINGLE_FACE) +
332         " AND (" + ALBUM_NAME + " IS NOT NULL OR " + IS_ME + " = " + to_string(ALBUM_IS_ME) + ")";
333     string innerJoinAnalysisPhotoMap = "INNER JOIN " + ANALYSIS_PHOTO_MAP_TABLE + " ON " +
334         MAP_ALBUM + " = AA." + PhotoAlbumColumns::ALBUM_ID + " AND " +
335         MAP_ASSET + " = F." + MediaColumn::MEDIA_ID;
336     string innerJoinPhotos = "INNER JOIN " + PhotoColumn::PHOTOS_TABLE + " P ON F." +
337         MediaColumn::MEDIA_ID + " = P." + MediaColumn::MEDIA_ID + " AND " +
338         MediaColumn::MEDIA_DATE_TRASHED + " = 0 AND " +
339         MediaColumn::MEDIA_HIDDEN + " = 0 AND " +
340         MediaColumn::MEDIA_TIME_PENDING + " = 0";
341     string innerSql = "SELECT F." + MediaColumn::MEDIA_ID + ", " + MediaColumn::MEDIA_FILE_PATH + ", " +
342         MediaColumn::MEDIA_NAME + ", " + MediaColumn::MEDIA_DATE_ADDED + ", " +
343         TOTAL_FACES + ", " + GROUP_TAG + ", " + IS_ME + " FROM " + VISION_IMAGE_FACE_TABLE + " F " +
344         innerJoinAnalysisAlbum + " " + innerJoinAnalysisPhotoMap + " " + innerJoinPhotos +
345         " ORDER BY F." + MediaColumn::MEDIA_ID + ", " + GROUP_TAG;
346     string queryGroupPhotoIsMe = "CASE WHEN MAX(" + IS_ME + ") = " + to_string(ALBUM_IS_ME) + " THEN " +
347         to_string(ALBUM_IS_ME) + " ELSE " + to_string(ALBUM_IS_NOT_ME) + " END AS " + GROUP_PHOTO_IS_ME;
348     string groupPhotoTagSql = "SELECT " + MediaColumn::MEDIA_ID + ", " + MediaColumn::MEDIA_FILE_PATH + ", " +
349         MediaColumn::MEDIA_NAME + ", " + MediaColumn::MEDIA_DATE_ADDED + ", " + queryGroupPhotoIsMe +
350         ", GROUP_CONCAT(DISTINCT " + GROUP_TAG + ") AS " + GROUP_PHOTO_TAG +
351         " FROM (" + innerSql + ") GROUP BY " + MediaColumn::MEDIA_ID +
352         " HAVING COUNT(" + GROUP_TAG +") = " + TOTAL_FACES + " AND COUNT(DISTINCT " + GROUP_TAG + ") > " +
353         to_string(SINGLE_FACE);
354     string leftJoinAnalysisAlbum = "LEFT JOIN " + ANALYSIS_ALBUM_TABLE + " AA ON " +
355         GROUP_PHOTO_TAG + " = AA." + TAG_ID + " AND AA." + ALBUM_SUBTYPE + " = " +
356         to_string(PhotoAlbumSubType::GROUP_PHOTO);
357     string fullSql = "SELECT " + GROUP_PHOTO_TAG + ", " + PhotoAlbumColumns::ALBUM_ID + ", " +
358         PhotoAlbumColumns::ALBUM_COVER_URI + ", " + IS_COVER_SATISFIED + ", " +
359         MediaColumn::MEDIA_ID + ", " + MediaColumn::MEDIA_FILE_PATH + ", " + MediaColumn::MEDIA_NAME + ", " +
360         GROUP_PHOTO_ALBUM_NAME + ", " + IS_REMOVED + ", " + RENAME_OPERATION + ", " +
361         "COUNT (DISTINCT " + MediaColumn::MEDIA_ID + ") AS " + PhotoAlbumColumns::ALBUM_COUNT + ", " +
362         GROUP_PHOTO_IS_ME + ", " + "MAX(" + MediaColumn::MEDIA_DATE_ADDED + ") FROM (" + groupPhotoTagSql + ") " +
363         leftJoinAnalysisAlbum + " GROUP BY " + GROUP_PHOTO_TAG + ";";
364     return fullSql;
365 }
366 
CheckGroupPhotoAlbumInfo(const GroupPhotoAlbumInfo & info,const GroupPhotoAlbumInfo & lastInfo)367 static bool CheckGroupPhotoAlbumInfo(const GroupPhotoAlbumInfo &info, const GroupPhotoAlbumInfo &lastInfo)
368 {
369     bool hasUpdated = ((info.albumName.compare(lastInfo.albumName) != 0) ||
370         (info.coverUri.compare(lastInfo.coverUri) != 0) ||
371         (info.count != lastInfo.count) ||
372         (info.isMe != lastInfo.isMe) ||
373         (info.isRemoved != lastInfo.isRemoved) ||
374         (info.renameOperation != lastInfo.renameOperation) ||
375         (info.isCoverSatisfied != lastInfo.isCoverSatisfied));
376     return hasUpdated;
377 }
378 
AssemblyInfo(shared_ptr<NativeRdb::ResultSet> resultSet)379 static GroupPhotoAlbumInfo AssemblyInfo(shared_ptr<NativeRdb::ResultSet> resultSet)
380 {
381     string tagId = GetStringVal(GROUP_PHOTO_TAG, resultSet);
382     int32_t isCoverSatisfied = GetInt32Val(IS_COVER_SATISFIED, resultSet);
383     int32_t count = GetInt32Val(PhotoAlbumColumns::ALBUM_COUNT, resultSet);
384     int32_t isMe = GetInt32Val(GROUP_PHOTO_IS_ME, resultSet);
385     int32_t albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
386     string coverUri = GetStringVal(PhotoAlbumColumns::ALBUM_COVER_URI, resultSet);
387     int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
388     string path = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
389     string displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
390     string candidateUri = GetCoverUri(fileId, path, displayName);
391     string albumName = GetStringVal(GROUP_PHOTO_ALBUM_NAME, resultSet);
392     int32_t isRemoved = GetInt32Val(IS_REMOVED, resultSet);
393     int32_t renameOperation = GetInt32Val(RENAME_OPERATION, resultSet);
394     GroupPhotoAlbumInfo info {albumId, tagId, coverUri, isCoverSatisfied, count, fileId, candidateUri, isMe,
395         albumName, isRemoved, renameOperation};
396     return info;
397 }
398 
GetAnalysisAlbumInfo()399 static std::map<int32_t, GroupPhotoAlbumInfo> GetAnalysisAlbumInfo()
400 {
401     std::map<int32_t, GroupPhotoAlbumInfo> lastResultMap;
402     const string queryAnalysisAlbumSql = "SELECT * FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " +
403         PhotoAlbumColumns::ALBUM_TYPE + " = " + to_string(PhotoAlbumType::SMART) + " AND " +
404         PhotoAlbumColumns::ALBUM_SUBTYPE + " = " + to_string(PhotoAlbumSubType::GROUP_PHOTO);
405     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
406     if (rdbStore == nullptr) {
407         MEDIA_ERR_LOG("Get AnalysisAlbum failed. rdbStore is null");
408         return lastResultMap;
409     }
410     auto rdbStorePtr = rdbStore;
411     if (rdbStorePtr == nullptr) {
412         MEDIA_ERR_LOG("Get AnalysisAlbum failed. rdbStorePtr is null");
413         return lastResultMap;
414     }
415     auto resultSet = rdbStorePtr->QuerySql(queryAnalysisAlbumSql);
416     if (resultSet == nullptr) {
417         MEDIA_ERR_LOG("Get AnalysisAlbum failed, query resultSet is null.");
418         return lastResultMap;
419     }
420     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
421         int32_t albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
422         lastResultMap[albumId].albumId = albumId;
423         lastResultMap[albumId].albumName = GetStringVal(GROUP_PHOTO_ALBUM_NAME, resultSet);
424         lastResultMap[albumId].coverUri = GetStringVal(PhotoAlbumColumns::ALBUM_COVER_URI, resultSet);
425         lastResultMap[albumId].count = GetInt32Val(PhotoAlbumColumns::ALBUM_COUNT, resultSet);
426         lastResultMap[albumId].isMe = GetInt32Val(IS_ME, resultSet);
427         lastResultMap[albumId].isRemoved = GetInt32Val(IS_REMOVED, resultSet);
428         lastResultMap[albumId].renameOperation = GetInt32Val(RENAME_OPERATION, resultSet);
429         lastResultMap[albumId].isCoverSatisfied = GetInt32Val(IS_COVER_SATISFIED, resultSet);
430     }
431     return lastResultMap;
432 }
433 
UpdateGroupPhotoAlbum(vector<GroupPhotoAlbumInfo> & updateAlbums,vector<GroupPhotoAlbumInfo> & insertAlbums,vector<GroupPhotoAlbumInfo> & clearAlbums,vector<int32_t> & insertAlbumsId)434 static bool UpdateGroupPhotoAlbum(vector<GroupPhotoAlbumInfo> &updateAlbums, vector<GroupPhotoAlbumInfo> &insertAlbums,
435     vector<GroupPhotoAlbumInfo> &clearAlbums, vector<int32_t> &insertAlbumsId)
436 {
437     auto lastResultMap = GetAnalysisAlbumInfo();
438     const string querySql = GetGroupPhotoAlbumSql();
439     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
440     if (rdbStore == nullptr) {
441         MEDIA_ERR_LOG("Update group photo album failed. rdbStore is null");
442         return false;
443     }
444     auto rdbStorePtr = rdbStore;
445     if (rdbStorePtr == nullptr) {
446         MEDIA_ERR_LOG("Update group photo album failed. rdbStorePtr is null");
447         return false;
448     }
449     auto resultSet = rdbStorePtr->QuerySql(querySql);
450     if (resultSet == nullptr) {
451         MEDIA_ERR_LOG("Update group photo album failed, query resultSet is null.");
452         return false;
453     }
454 
455     bool hasUpdated = false;
456     while (resultSet->GoToNextRow() == E_OK) {
457         int32_t albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
458         auto info = AssemblyInfo(resultSet);
459         if (albumId == ALBUM_NOT_FOUND) {
460             insertAlbums.push_back(info);
461             hasUpdated = true;
462         } else {
463             if (CheckGroupPhotoAlbumInfo(info, lastResultMap[albumId])) {
464                 hasUpdated = true;
465                 updateAlbums.push_back(info);
466             }
467             lastResultMap.erase(albumId);
468         }
469     }
470 
471     UpdateGroupPhotoAlbumInfo(updateAlbums);
472     InsertGroupPhotoAlbumInfo(insertAlbums, insertAlbumsId);
473     if (lastResultMap.size() > 0) {
474         hasUpdated = true;
475         for (auto iter = lastResultMap.begin(); iter != lastResultMap.end(); ++iter) {
476             clearAlbums.push_back(iter->second);
477         }
478         ClearEmptyGroupPhotoAlbumInfo(clearAlbums);
479     }
480     return hasUpdated;
481 }
482 
UpdateGroupPhotoAlbumAsync(AsyncTaskData * data)483 static void UpdateGroupPhotoAlbumAsync(AsyncTaskData *data)
484 {
485     lock_guard<mutex> lock(updateGroupPhotoAlbumMutex);
486     vector<GroupPhotoAlbumInfo> updateAlbums;
487     vector<GroupPhotoAlbumInfo> insertAlbums;
488     vector<GroupPhotoAlbumInfo> clearAlbums;
489     vector<int32_t> insertAlbumsId;
490     bool hasUpdated = UpdateGroupPhotoAlbum(updateAlbums, insertAlbums, clearAlbums, insertAlbumsId);
491     if (hasUpdated) {
492         vector<int32_t> changeAlbumIds {};
493         for (auto info : updateAlbums) {
494             changeAlbumIds.push_back(info.albumId);
495         }
496         for (auto albumId : insertAlbumsId) {
497             changeAlbumIds.push_back(albumId);
498         }
499         for (auto info : clearAlbums) {
500             changeAlbumIds.push_back(info.albumId);
501         }
502         NotifyGroupAlbum(changeAlbumIds);
503     }
504 }
505 
QueryGroupPhotoAlbum(MediaLibraryCommand & cmd,const std::vector<std::string> & columns)506 std::shared_ptr<NativeRdb::ResultSet> MediaLibraryAnalysisAlbumOperations::QueryGroupPhotoAlbum(
507     MediaLibraryCommand &cmd, const std::vector<std::string> &columns)
508 {
509     auto whereClause = cmd.GetAbsRdbPredicates()->GetWhereClause();
510     auto whereArgs = cmd.GetAbsRdbPredicates()->GetWhereArgs();
511     RdbPredicates rdbPredicates(ANALYSIS_ALBUM_TABLE);
512     auto albumId = GetAlbumId(whereClause, whereArgs);
513 
514     string clause = "";
515     if (albumId != E_INDEX) {
516         clause = PhotoAlbumColumns::ALBUM_TYPE + " = " + to_string(PhotoAlbumType::SMART) + " AND " +
517             PhotoAlbumColumns::ALBUM_SUBTYPE + " = " + to_string(PhotoAlbumSubType::GROUP_PHOTO) + " AND " +
518             PhotoAlbumColumns::ALBUM_ID + " = " + to_string(albumId) + " AND " +
519             IS_REMOVED + " IS NOT " + to_string(ALBUM_IS_REMOVED);
520     } else {
521         clause = PhotoAlbumColumns::ALBUM_TYPE + " = " + to_string(PhotoAlbumType::SMART) + " AND " +
522             PhotoAlbumColumns::ALBUM_SUBTYPE + " = " + to_string(PhotoAlbumSubType::GROUP_PHOTO) + " AND " +
523             IS_REMOVED + " IS NOT " + to_string(ALBUM_IS_REMOVED);
524         if (whereClause.find(IS_ME) != string::npos) {
525             int32_t value = GetArgsValueByName(IS_ME, whereClause, whereArgs);
526             if (value == QUERY_GROUP_PHOTO_ALBUM_RELATED_TO_ME) {
527                 clause += " AND " + IS_ME + " = " + to_string(ALBUM_IS_ME);
528             }
529         }
530     }
531 
532     rdbPredicates.SetWhereClause(clause);
533     rdbPredicates.OrderByDesc(RENAME_OPERATION);
534     rdbPredicates.OrderByDesc("(SELECT LENGTH(" + TAG_ID + ") - LENGTH([REPLACE](" + TAG_ID + ", ',', '')))");
535     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(rdbPredicates, columns);
536     if (albumId != E_INDEX) {
537         return resultSet;
538     }
539 
540     auto asyncWorker = MediaLibraryAsyncWorker::GetInstance();
541     if (asyncWorker != nullptr) {
542         auto updateGroupTask = make_shared<MediaLibraryAsyncTask>(UpdateGroupPhotoAlbumAsync, nullptr);
543         if (updateGroupTask != nullptr) {
544             asyncWorker->AddTask(updateGroupTask, true);
545         } else {
546             MEDIA_ERR_LOG("Failed to create async task for query group photo album.");
547         }
548     } else {
549         MEDIA_ERR_LOG("Can not get asyncWorker");
550     }
551     return resultSet;
552 }
553 
GetMergeAlbumCoverUri(MergeAlbumInfo & updateAlbumInfo,const MergeAlbumInfo & currentAlbum,const MergeAlbumInfo & targetAlbum)554 static int32_t GetMergeAlbumCoverUri(MergeAlbumInfo &updateAlbumInfo, const MergeAlbumInfo &currentAlbum,
555     const MergeAlbumInfo &targetAlbum)
556 {
557     string currentFileId = MediaFileUri::GetPhotoId(currentAlbum.coverUri);
558     string targetFileId = MediaFileUri::GetPhotoId(targetAlbum.coverUri);
559     if (currentFileId.empty() || targetFileId.empty()) {
560         return E_DB_FAIL;
561     }
562     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
563     if (uniStore == nullptr) {
564         MEDIA_ERR_LOG("uniStore is nullptr! failed query get merge album cover uri");
565         return E_DB_FAIL;
566     }
567     string candidateIds;
568     if (currentAlbum.isCoverSatisfied == targetAlbum.isCoverSatisfied) {
569         candidateIds = currentFileId + ", " + targetFileId;
570     } else {
571         candidateIds = currentAlbum.isCoverSatisfied != static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING) ?
572             currentFileId :
573             targetFileId;
574     }
575     const std::string queryAlbumInfo = "SELECT " + MediaColumn::MEDIA_ID + "," + MediaColumn::MEDIA_TITLE + "," +
576         MediaColumn::MEDIA_NAME + ", MAX(" + MediaColumn::MEDIA_DATE_ADDED + ") FROM " + PhotoColumn::PHOTOS_TABLE +
577         " WHERE " + MediaColumn::MEDIA_ID + " IN (" + candidateIds + " )";
578 
579     auto resultSet = uniStore->QuerySql(queryAlbumInfo);
580     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
581         MEDIA_ERR_LOG("Failed to query merge album cover uri");
582         return E_HAS_DB_ERROR;
583     }
584     int mergeFileId;
585     if (GetIntValueFromResultSet(resultSet, MediaColumn::MEDIA_ID, mergeFileId) != NativeRdb::E_OK) {
586         MEDIA_ERR_LOG("Failed to get file id of merge album cover uri.");
587         return E_HAS_DB_ERROR;
588     }
589 
590     string mergeTitle;
591     if (GetStringValueFromResultSet(resultSet, MediaColumn::MEDIA_TITLE, mergeTitle) != NativeRdb::E_OK) {
592         MEDIA_ERR_LOG("Failed to get title of merge album cover uri.");
593         return E_HAS_DB_ERROR;
594     }
595 
596     string mergeDisplayName;
597     if (GetStringValueFromResultSet(resultSet, MediaColumn::MEDIA_NAME, mergeDisplayName) != NativeRdb::E_OK) {
598         MEDIA_ERR_LOG("Failed to get display name of merge album cover uri.");
599         return E_HAS_DB_ERROR;
600     }
601     updateAlbumInfo.coverUri = "file://media/Photo/" + to_string(mergeFileId) + "/" + mergeTitle + "/" +
602         mergeDisplayName;
603     return E_OK;
604 }
605 
UpdateForMergeGroupAlbums(const shared_ptr<MediaLibraryRdbStore> store,const vector<int> & deleteId,const std::unordered_map<string,MergeAlbumInfo> updateMap)606 static int32_t UpdateForMergeGroupAlbums(const shared_ptr<MediaLibraryRdbStore> store, const vector<int> &deleteId,
607     const std::unordered_map<string, MergeAlbumInfo> updateMap)
608 {
609     for (auto it : deleteId) {
610         RdbPredicates rdbPredicates(ANALYSIS_ALBUM_TABLE);
611         rdbPredicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(it));
612         MediaLibraryRdbStore::Delete(rdbPredicates);
613     }
614     vector<string> updateSqls;
615     for (auto it : updateMap) {
616         string sql = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + TAG_ID + " = '" + it.first + "', " +
617             GROUP_TAG + " = '" + it.first + "', " + COVER_URI + " = '" + it.second.coverUri + "', " +
618             IS_REMOVED + " = 0, " + IS_COVER_SATISFIED  + " = " + to_string(it.second.isCoverSatisfied) +
619             " WHERE " + ALBUM_ID + " = " + to_string(it.second.albumId);
620         updateSqls.push_back(sql);
621     }
622     return ExecSqls(updateSqls, store);
623 }
624 
ReorderTagId(string target,const vector<MergeAlbumInfo> & mergeAlbumInfo)625 static string ReorderTagId(string target, const vector<MergeAlbumInfo> &mergeAlbumInfo)
626 {
627     string reordererTagId;
628     vector<string> splitResult;
629     if (target.empty()) {
630         return reordererTagId;
631     }
632     string pattern = ",";
633     string strs = target + pattern;
634     size_t pos = strs.find(pattern);
635     while (pos != strs.npos) {
636         string groupTag = strs.substr(0, pos);
637         strs = strs.substr(pos + 1, strs.size());
638         pos = strs.find(pattern);
639         if (groupTag.compare(mergeAlbumInfo[0].groupTag) != 0 && groupTag.compare(mergeAlbumInfo[1].groupTag) != 0) {
640             splitResult.push_back(groupTag);
641         }
642     }
643     if (splitResult.empty()) {
644         return reordererTagId;
645     }
646     string newTagId = mergeAlbumInfo[0].groupTag + "|" + mergeAlbumInfo[1].groupTag;
647     splitResult.push_back(newTagId);
648     std::sort(splitResult.begin(), splitResult.end());
649     for (auto tagId : splitResult) {
650         reordererTagId += (tagId + ",");
651     }
652     reordererTagId = reordererTagId.substr(0, reordererTagId.size() - 1);
653     return reordererTagId;
654 }
655 
GetMergeAlbumInfo(shared_ptr<NativeRdb::ResultSet> resultSet,MergeAlbumInfo & info)656 int32_t GetMergeAlbumInfo(shared_ptr<NativeRdb::ResultSet> resultSet, MergeAlbumInfo &info)
657 {
658     int isCoverSatisfied = 0;
659     if (GetIntValueFromResultSet(resultSet, ALBUM_ID, info.albumId) != E_OK ||
660         GetStringValueFromResultSet(resultSet, TAG_ID, info.tagId) != E_OK ||
661         GetStringValueFromResultSet(resultSet, COVER_URI, info.coverUri) != E_OK ||
662         GetIntValueFromResultSet(resultSet, IS_COVER_SATISFIED, isCoverSatisfied) != E_OK) {
663         return E_HAS_DB_ERROR;
664     }
665     info.isCoverSatisfied = static_cast<uint8_t>(isCoverSatisfied);
666     return E_OK;
667 }
668 
UpdateMergeGroupAlbumsInfo(const vector<MergeAlbumInfo> & mergeAlbumInfo)669 int32_t MediaLibraryAnalysisAlbumOperations::UpdateMergeGroupAlbumsInfo(const vector<MergeAlbumInfo> &mergeAlbumInfo)
670 {
671     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
672     if (uniStore == nullptr) {
673         MEDIA_ERR_LOG("UniStore is nullptr! Query album order failed.");
674         return E_DB_FAIL;
675     }
676     string queryTagId = "SELECT " + ALBUM_ID + ", " + COVER_URI + ", " + IS_COVER_SATISFIED + ", " + TAG_ID +
677         " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_SUBTYPE + " = " + to_string(GROUP_PHOTO) +
678         " AND (INSTR(" + TAG_ID + ", '" + mergeAlbumInfo[0].groupTag + "') > 0 OR INSTR(" + TAG_ID + ", '" +
679         mergeAlbumInfo[1].groupTag + "') > 0)";
680     auto resultSet = uniStore->QuerySql(queryTagId);
681     if (resultSet == nullptr) {
682         return E_HAS_DB_ERROR;
683     }
684 
685     std::vector<int> deleteId;
686     std::unordered_map<string, MergeAlbumInfo> updateMap;
687     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
688         MergeAlbumInfo info;
689         if (GetMergeAlbumInfo(resultSet, info) != E_OK) {
690             return E_HAS_DB_ERROR;
691         }
692         string reorderedTagId = ReorderTagId(info.tagId, mergeAlbumInfo);
693         auto it = updateMap.find(reorderedTagId);
694         if (reorderedTagId.empty()) {
695             deleteId.push_back(info.albumId);
696         } else if (it == updateMap.end()) {
697             updateMap.insert(std::make_pair(reorderedTagId, info));
698         } else {
699             MergeAlbumInfo newInfo;
700             if (it->second.coverUri.empty()) {
701                 updateMap[reorderedTagId].coverUri = info.coverUri;
702                 updateMap[reorderedTagId].isCoverSatisfied = info.isCoverSatisfied;
703                 deleteId.push_back(info.albumId);
704                 continue;
705             } else if (info.coverUri.empty()) {
706                 deleteId.push_back(info.albumId);
707                 continue;
708             } else if (GetMergeAlbumCoverUri(newInfo, info, it->second) != E_OK) {
709                 return E_HAS_DB_ERROR;
710             }
711             if (info.isCoverSatisfied != static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING) ||
712                 it->second.isCoverSatisfied != static_cast<uint8_t>(CoverSatisfiedType::NO_SETTING)) {
713                 updateMap[reorderedTagId].isCoverSatisfied = static_cast<uint8_t>(CoverSatisfiedType::DEFAULT_SETTING);
714             }
715             updateMap[reorderedTagId].coverUri = newInfo.coverUri;
716             deleteId.push_back(info.albumId);
717         }
718     }
719     return UpdateForMergeGroupAlbums(uniStore, deleteId, updateMap);
720 }
721 
SetGroupAlbumName(const ValuesBucket & values,const DataSharePredicates & predicates)722 static int32_t SetGroupAlbumName(const ValuesBucket &values, const DataSharePredicates &predicates)
723 {
724     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
725     auto whereArgs = rdbPredicates.GetWhereArgs();
726     if (whereArgs.size() == 0) {
727         MEDIA_ERR_LOG("no target album id");
728         return E_INVALID_VALUES;
729     }
730     string targetAlbumId = whereArgs[0];
731     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
732     if (uniStore == nullptr) {
733         MEDIA_ERR_LOG("uniStore is nullptr! failed update for set album name");
734         return E_DB_FAIL;
735     }
736     string albumName;
737     int err = GetStringObject(values, ALBUM_NAME, albumName);
738     if (err < 0 || albumName.empty()) {
739         MEDIA_ERR_LOG("invalid album name");
740         return E_INVALID_VALUES;
741     }
742     std::string updateForSetAlbumName = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + ALBUM_NAME + " = '" + albumName +
743         "' , " + RENAME_OPERATION + " = 1 WHERE " + ALBUM_ID + " = " + targetAlbumId;
744     vector<string> updateSqls = { updateForSetAlbumName };
745     err = ExecSqls(updateSqls, uniStore);
746     if (err == E_OK) {
747         vector<int32_t> changeAlbumIds = { atoi(targetAlbumId.c_str()) };
748         NotifyGroupAlbum(changeAlbumIds);
749     }
750     return err;
751 }
752 
SetGroupCoverUri(const ValuesBucket & values,const DataSharePredicates & predicates)753 static int32_t SetGroupCoverUri(const ValuesBucket &values, const DataSharePredicates &predicates)
754 {
755     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
756     auto whereArgs = rdbPredicates.GetWhereArgs();
757     if (whereArgs.size() == 0) {
758         MEDIA_ERR_LOG("no target album id");
759         return E_INVALID_VALUES;
760     }
761     string targetAlbumId = whereArgs[0];
762     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
763     if (uniStore == nullptr) {
764         MEDIA_ERR_LOG("uniStore is nullptr! failed update for set album cover uri");
765         return E_DB_FAIL;
766     }
767     string coverUri;
768     int err = GetStringObject(values, COVER_URI, coverUri);
769     if (err < 0 || coverUri.empty()) {
770         MEDIA_ERR_LOG("invalid album cover uri");
771         return E_INVALID_VALUES;
772     }
773     std::string updateForSetCoverUri = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + COVER_URI + " = '" + coverUri +
774         "', " + IS_COVER_SATISFIED + " = " + to_string(static_cast<uint8_t>(CoverSatisfiedType::DEFAULT_SETTING)) +
775         " WHERE " + ALBUM_ID + " = " + targetAlbumId;
776     vector<string> updateSqls = { updateForSetCoverUri };
777     err = ExecSqls(updateSqls, uniStore);
778     if (err == E_OK) {
779         vector<int32_t> changeAlbumIds = { atoi(targetAlbumId.c_str()) };
780         NotifyGroupAlbum(changeAlbumIds);
781     }
782     return err;
783 }
784 
DismissGroupPhotoAlbum(const ValuesBucket & values,const DataSharePredicates & predicates)785 static int32_t DismissGroupPhotoAlbum(const ValuesBucket &values, const DataSharePredicates &predicates)
786 {
787     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
788     auto whereArgs = rdbPredicates.GetWhereArgs();
789     if (whereArgs.size() == 0) {
790         MEDIA_ERR_LOG("no target album id");
791         return E_INVALID_VALUES;
792     }
793     string targetAlbumId = whereArgs[0];
794     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
795     if (uniStore == nullptr) {
796         MEDIA_ERR_LOG("uniStore is nullptr! failed update for set album cover uri");
797         return E_DB_FAIL;
798     }
799     std::string updateForDeleteGroupAlbum = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + IS_REMOVED + " = 1 WHERE " +
800         ALBUM_ID + " = " + targetAlbumId;
801     vector<string> updateSqls = { updateForDeleteGroupAlbum };
802     int err = ExecSqls(updateSqls, uniStore);
803     if (err == E_OK) {
804         vector<int32_t> changeAlbumIds = { atoi(targetAlbumId.c_str()) };
805         NotifyGroupAlbum(changeAlbumIds);
806     }
807     return err;
808 }
809 
HandleGroupPhotoAlbum(const OperationType & opType,const NativeRdb::ValuesBucket & values,const DataShare::DataSharePredicates & predicates)810 int32_t MediaLibraryAnalysisAlbumOperations::HandleGroupPhotoAlbum(const OperationType &opType,
811     const NativeRdb::ValuesBucket &values, const DataShare::DataSharePredicates &predicates)
812 {
813     switch (opType) {
814         case OperationType::DISMISS:
815             return DismissGroupPhotoAlbum(values, predicates);
816         case OperationType::GROUP_ALBUM_NAME:
817             return SetGroupAlbumName(values, predicates);
818         case OperationType::GROUP_COVER_URI:
819             return SetGroupCoverUri(values, predicates);
820         default:
821             MEDIA_ERR_LOG("Unknown operation type: %{public}d", opType);
822             return E_ERR;
823     }
824 }
825 
UpdateGroupPhotoAlbumById(int32_t albumId)826 void MediaLibraryAnalysisAlbumOperations::UpdateGroupPhotoAlbumById(int32_t albumId)
827 {
828     const string &querySql = GetGroupPhotoAlbumSql();
829     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
830     if (rdbStore == nullptr) {
831         MEDIA_ERR_LOG("Update group photo album by id: %{public}d failed, rdbStore is null.", albumId);
832         return;
833     }
834     auto rdbStorePtr = rdbStore;
835     if (rdbStorePtr == nullptr) {
836         MEDIA_ERR_LOG("Update group photo album by id: %{public}d failed, rdbStorePtr is null.", albumId);
837         return;
838     }
839     auto resultSet = rdbStorePtr->QuerySql(querySql);
840     if (resultSet == nullptr) {
841         MEDIA_ERR_LOG("Update group photo album by id: %{public}d failed, query resultSet is null.", albumId);
842         return;
843     }
844 
845     vector<GroupPhotoAlbumInfo> updateAlbums;
846     while (resultSet->GoToNextRow() == E_OK) {
847         int32_t id = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
848         if (id == albumId) {
849             auto info = AssemblyInfo(resultSet);
850             updateAlbums.push_back(info);
851             break;
852         }
853     }
854     UpdateGroupPhotoAlbumInfo(updateAlbums);
855 }
856 
UpdatePortraitAlbumCoverSatisfied(int32_t fileId)857 void MediaLibraryAnalysisAlbumOperations::UpdatePortraitAlbumCoverSatisfied(int32_t fileId)
858 {
859     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
860     if (rdbStore == nullptr) {
861         MEDIA_ERR_LOG("UpdatePortraitAlbumCoverSatisfied failed, fileId: %{public}d, rdbStore is null.", fileId);
862         return;
863     }
864     const string coverUriPrefix = "'" + PhotoColumn::PHOTO_URI_PREFIX + to_string(fileId) + "/%'";
865 
866     const string updateSql = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + IS_COVER_SATISFIED + " = " +
867         IS_COVER_SATISFIED + " | " + to_string(static_cast<uint8_t>(CoverSatisfiedType::DEFAULT_SETTING)) + " WHERE " +
868         PhotoAlbumColumns::ALBUM_SUBTYPE + " = " + to_string(static_cast<int32_t>(PhotoAlbumSubType::PORTRAIT)) +
869         " AND " + PhotoAlbumColumns::ALBUM_COVER_URI + " LIKE " + coverUriPrefix;
870 
871     int32_t ret = rdbStore->ExecuteSql(updateSql);
872     if (ret != E_OK) {
873         MEDIA_ERR_LOG("ExecuteSql error, fileId: %{public}d, ret: %{public}d.", fileId, ret);
874         return;
875     }
876 }
877 } // namespace OHOS::Media
878