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