• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-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 "AlbumOperation"
16 
17 #include "medialibrary_album_operations.h"
18 
19 #include <cstddef>
20 #include <cstdio>
21 #include <cstring>
22 
23 #include "album_plugin_config.h"
24 #include "dfx_utils.h"
25 #include "directory_ex.h"
26 #include "media_analysis_helper.h"
27 #include "media_file_utils.h"
28 #include "media_log.h"
29 #include "medialibrary_album_fusion_utils.h"
30 #include "medialibrary_analysis_album_operations.h"
31 #include "medialibrary_asset_operations.h"
32 #include "medialibrary_album_refresh.h"
33 #include "medialibrary_db_const.h"
34 #include "medialibrary_errno.h"
35 #include "medialibrary_notify.h"
36 #include "medialibrary_object_utils.h"
37 #include "medialibrary_rdb_utils.h"
38 #include "medialibrary_rdbstore.h"
39 #include "medialibrary_tracer.h"
40 #include "medialibrary_unistore_manager.h"
41 #ifdef MEDIALIBRARY_FEATURE_CLOUD_ENHANCEMENT
42 #include "enhancement_manager.h"
43 #endif
44 #include "multistages_capture_manager.h"
45 #include "photo_album_column.h"
46 #include "photo_map_column.h"
47 
48 #include "result_set_utils.h"
49 #include "story_album_column.h"
50 #include "story_cover_info_column.h"
51 #include "values_bucket.h"
52 #include "medialibrary_formmap_operations.h"
53 #include "media_file_uri.h"
54 #include "media_file_utils.h"
55 #include "vision_album_column.h"
56 #include "vision_column.h"
57 #include "vision_face_tag_column.h"
58 #include "vision_photo_map_column.h"
59 #include "vision_total_column.h"
60 #include "photo_owner_album_id_operation.h"
61 
62 using namespace std;
63 using namespace OHOS::NativeRdb;
64 using namespace OHOS::DataShare;
65 using namespace OHOS::RdbDataShareAdapter;
66 
67 namespace OHOS::Media {
68 using ChangeType = AAFwk::ChangeInfo::ChangeType;
69 constexpr int32_t AFTER_AGR_SIZE = 2;
70 constexpr int32_t THAN_AGR_SIZE = 1;
71 constexpr int32_t MERGE_ALBUM_COUNT = 2;
72 constexpr int32_t E_INDEX = -1;
73 constexpr int32_t PORTRAIT_FIRST_PAGE_MIN_COUNT = 50;
74 constexpr int32_t PORTRAIT_FIRST_PAGE_MIN_COUNT_RELATED_ME = 20;
75 constexpr int32_t PORTRAIT_SECOND_PAGE_MIN_PICTURES_COUNT = 10;
76 constexpr int32_t SUPPORT_QUERY_ISME_MIN_COUNT = 80;
77 constexpr int32_t PERCENTAGE_FOR_SUPPORT_QUERY_ISME = 100;
78 constexpr int32_t QUERY_PROB_IS_ME_VALUE = 1;
79 constexpr int32_t QUERY_IS_ME_VALUE = 2;
80 constexpr int32_t FACE_ANALYSISED_STATE = 3;
81 constexpr int32_t FACE_NO_NEED_ANALYSIS_STATE = -2;
82 constexpr int32_t ALBUM_NAME_NOT_NULL_ENABLED = 1;
83 constexpr int32_t ALBUM_PRIORITY_DEFAULT = 1;
84 constexpr int32_t ALBUM_SETNAME_OK = 1;
85 constexpr int32_t HIGHLIGHT_DELETED = -2;
86 constexpr int32_t HIGHLIGHT_COVER_STATUS_TITLE = 2;
87 constexpr int32_t HIGHLIGHT_COVER_STATUS_COVER = 1;
88 const std::string ALBUM_LPATH_PREFIX = "/Pictures/Users/";
89 const std::string SOURCE_PATH_PREFIX = "/storage/emulated/0";
90 
CreateAlbumOperation(MediaLibraryCommand & cmd)91 int32_t MediaLibraryAlbumOperations::CreateAlbumOperation(MediaLibraryCommand &cmd)
92 {
93     int64_t outRow = -1;
94     int32_t errCode = MediaLibraryObjectUtils::CreateDirObj(cmd, outRow);
95     if (errCode == E_SUCCESS) {
96         return outRow;
97     }
98     return errCode;
99 }
100 
101 // only support modify in the same parent folder, like: a/b/c --> a/b/d
ModifyAlbumOperation(MediaLibraryCommand & cmd)102 int32_t MediaLibraryAlbumOperations::ModifyAlbumOperation(MediaLibraryCommand &cmd)
103 {
104     string strId = cmd.GetOprnFileId();
105     string srcDirPath = MediaLibraryObjectUtils::GetPathByIdFromDb(strId);
106     if (srcDirPath.empty()) {
107         MEDIA_ERR_LOG("Get path of id %{private}s from database file!", strId.c_str());
108         return E_INVALID_PATH;
109     }
110 
111     auto values = cmd.GetValueBucket();
112     string dstDirName;
113     ValueObject valueObject;
114     if (values.GetObject(MEDIA_DATA_DB_NAME, valueObject)) {
115         valueObject.GetString(dstDirName);
116     }
117     int ret;
118     if (dstDirName.empty() && !values.IsEmpty()) {
119         ret = MediaLibraryObjectUtils::ModifyInfoByIdInDb(cmd);
120     } else {
121         string dstDirPath = MediaFileUtils::GetParentPath(srcDirPath) + "/" + dstDirName;
122         ret = MediaLibraryObjectUtils::RenameDirObj(cmd, srcDirPath, dstDirPath);
123     }
124     return ret;
125 }
126 
127 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceRelativePath(string & selection,vector<string> & selectionArgs)128 static void ReplaceRelativePath(string &selection, vector<string> &selectionArgs)
129 {
130     for (size_t pos = 0; pos != string::npos;) {
131         pos = selection.find(MEDIA_DATA_DB_RELATIVE_PATH, pos);
132         if (pos == string::npos) {
133             break;
134         }
135         size_t argPos = selection.find('?', pos);
136         if (argPos == string::npos) {
137             break;
138         }
139         size_t argIndex = 0;
140         for (size_t i = 0; i < argPos; i++) {
141             if (selection[i] == '?') {
142                 argIndex++;
143             }
144         }
145         if (argIndex > selectionArgs.size() - 1) {
146             MEDIA_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
147                 selection.c_str());
148             break;
149         }
150         const string &arg = selectionArgs[argIndex];
151         if (!arg.empty()) {
152             MEDIA_WARN_LOG("No empty args in ReplaceRelativePath");
153             return;
154         }
155         selection.replace(argPos, 1, "? OR 1=1)");
156         selection.replace(pos, MEDIA_DATA_DB_RELATIVE_PATH.length(), "(" + PhotoAlbumColumns::ALBUM_ID);
157 
158         selectionArgs[argIndex] = "1";
159         pos = argPos + 1;
160     }
161 }
162 
ReplaceMediaType(string & selection,vector<string> & selectionArgs)163 static void ReplaceMediaType(string &selection, vector<string> &selectionArgs)
164 {
165     for (size_t pos = 0; pos != string::npos;) {
166         pos = selection.find(MEDIA_DATA_DB_MEDIA_TYPE, pos);
167         if (pos == string::npos) {
168             break;
169         }
170         size_t argPos = selection.find('?', pos);
171         if (argPos == string::npos) {
172             break;
173         }
174         size_t argIndex = 0;
175         for (size_t i = 0; i < argPos; i++) {
176             if (selection[i] == '?') {
177                 argIndex++;
178             }
179         }
180         if (argIndex > selectionArgs.size() - 1) {
181             MEDIA_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
182                 selection.c_str());
183             break;
184         }
185         selection.replace(argPos, 1, "? OR 1=1)");
186         selection.replace(pos, MEDIA_DATA_DB_MEDIA_TYPE.length(), "(" + PhotoAlbumColumns::ALBUM_ID);
187 
188         selectionArgs[argIndex] = "1";
189         pos = argPos + 1;
190     }
191 }
192 
GetSqlArgs(MediaLibraryCommand & cmd,string & sql,vector<string> & selectionArgs,const vector<string> & columns)193 static void GetSqlArgs(MediaLibraryCommand &cmd, string &sql, vector<string> &selectionArgs,
194     const vector<string> &columns)
195 {
196     string clause = cmd.GetAbsRdbPredicates()->GetWhereClause();
197     selectionArgs = cmd.GetAbsRdbPredicates()->GetWhereArgs();
198     sql = "SELECT ";
199     for (size_t i = 0; i < columns.size(); i++) {
200         if (i != columns.size() - 1) {
201             sql += columns[i] + ",";
202         } else {
203             sql += columns[i];
204         }
205     }
206     sql += " FROM " + cmd.GetAbsRdbPredicates()->GetTableName();
207     sql += " WHERE ";
208     ReplaceRelativePath(clause, selectionArgs);
209     ReplaceMediaType(clause, selectionArgs);
210     sql += clause;
211 }
212 
QueryAlbumDebug(MediaLibraryCommand & cmd,const vector<string> & columns,const shared_ptr<MediaLibraryRdbStore> store)213 static void QueryAlbumDebug(MediaLibraryCommand &cmd, const vector<string> &columns,
214     const shared_ptr<MediaLibraryRdbStore> store)
215 {
216     MEDIA_DEBUG_LOG("Querying album, table: %{private}s selections: %{private}s",
217         cmd.GetAbsRdbPredicates()->GetTableName().c_str(), cmd.GetAbsRdbPredicates()->GetWhereClause().c_str());
218     for (const auto &arg : cmd.GetAbsRdbPredicates()->GetWhereArgs()) {
219         MEDIA_DEBUG_LOG("Querying album, arg: %{private}s", arg.c_str());
220     }
221     for (const auto &col : columns) {
222         MEDIA_DEBUG_LOG("Querying album, col: %{private}s", col.c_str());
223     }
224 
225     auto resultSet = store->Query(cmd, columns);
226     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Failed to query file!");
227     int32_t count = -1;
228     int32_t err = resultSet->GetRowCount(count);
229     CHECK_AND_RETURN_LOG(err == E_OK, "Failed to get count, err: %{public}d", err);
230     MEDIA_DEBUG_LOG("Querying album, count: %{public}d", count);
231 }
232 
QuerySqlDebug(const string & sql,const vector<string> & selectionArgs,const vector<string> & columns,const shared_ptr<MediaLibraryRdbStore> store)233 static void QuerySqlDebug(const string &sql, const vector<string> &selectionArgs, const vector<string> &columns,
234     const shared_ptr<MediaLibraryRdbStore> store)
235 {
236     constexpr int32_t printMax = 512;
237     for (size_t pos = 0; pos < sql.size(); pos += printMax) {
238         MEDIA_DEBUG_LOG("Quering album sql: %{private}s", sql.substr(pos, printMax).c_str());
239     }
240     for (const auto &arg : selectionArgs) {
241         MEDIA_DEBUG_LOG("Quering album, arg: %{private}s", arg.c_str());
242     }
243     for (const auto &col : columns) {
244         MEDIA_DEBUG_LOG("Quering album, col: %{private}s", col.c_str());
245     }
246     auto resultSet = store->QuerySql(sql, selectionArgs);
247     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Failed to query album!");
248 
249     int32_t count = -1;
250     int32_t err = resultSet->GetRowCount(count);
251     CHECK_AND_RETURN_LOG(err == E_OK, "Failed to get count, err: %{public}d", err);
252     MEDIA_DEBUG_LOG("Quering album, count: %{public}d", count);
253 }
254 #endif
255 
QueryPhotoThumbnailVolumn(shared_ptr<MediaLibraryRdbStore> uniStore)256 static size_t QueryPhotoThumbnailVolumn(shared_ptr<MediaLibraryRdbStore> uniStore)
257 {
258     const string sql = "SELECT SUM(" + PhotoExtColumn::THUMBNAIL_SIZE + ")" + " as " + MEDIA_DATA_DB_SIZE +
259         " FROM " + PhotoExtColumn::PHOTOS_EXT_TABLE;
260     auto resultSet = uniStore->QuerySql(sql);
261     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, 0, "resultSet is null!");
262     CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK, 0, "go to first row failed");
263 
264     int64_t size = get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_SIZE,
265         resultSet, TYPE_INT64));
266     if (size < 0) {
267         MEDIA_ERR_LOG("Invalid size retrieved from database: %{public}" PRId64, size);
268         return 0;
269     }
270     return static_cast<size_t>(size);
271 }
272 
QueryAlbumOperation(MediaLibraryCommand & cmd,const vector<string> & columns)273 shared_ptr<ResultSet> MediaLibraryAlbumOperations::QueryAlbumOperation(
274     MediaLibraryCommand &cmd, const vector<string> &columns)
275 {
276     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
277     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, nullptr, "uniStore is nullptr!");
278 
279     if (cmd.GetOprnObject() == OperationObject::MEDIA_VOLUME) {
280         size_t photoThumbnailVolumn = QueryPhotoThumbnailVolumn(uniStore);
281         string queryThumbnailSql = "SELECT cast(" + to_string(photoThumbnailVolumn) +
282             " as bigint) as " + MEDIA_DATA_DB_SIZE + ", -1 as " + MediaColumn::MEDIA_TYPE;
283         string mediaVolumeQuery = PhotoColumn::QUERY_MEDIA_VOLUME + " UNION " + AudioColumn::QUERY_MEDIA_VOLUME
284             + " UNION " + queryThumbnailSql;
285         MEDIA_INFO_LOG("Thumbnail size is %{public}zu", photoThumbnailVolumn);
286         return uniStore->QuerySql(mediaVolumeQuery);
287     }
288 
289     string whereClause = cmd.GetAbsRdbPredicates()->GetWhereClause();
290     if (whereClause.find(MEDIA_DATA_DB_RELATIVE_PATH) != string::npos ||
291         whereClause.find(MEDIA_DATA_DB_MEDIA_TYPE) != string::npos) {
292         string sql;
293         vector<string> selectionArgs;
294         GetSqlArgs(cmd, sql, selectionArgs, columns);
295         QuerySqlDebug(sql, selectionArgs, columns, uniStore);
296         return uniStore->QuerySql(sql, selectionArgs);
297     }
298 
299     QueryAlbumDebug(cmd, columns, uniStore);
300     return uniStore->Query(cmd, columns);
301 }
302 
GetStringObject(const ValuesBucket & values,const string & key,string & value)303 inline int32_t GetStringObject(const ValuesBucket &values, const string &key, string &value)
304 {
305     value = "";
306     ValueObject valueObject;
307     if (values.GetObject(key, valueObject)) {
308         valueObject.GetString(value);
309     } else {
310         return -EINVAL;
311     }
312     return E_OK;
313 }
314 
GetIntVal(const ValuesBucket & values,const string & key,int32_t & value)315 inline int32_t GetIntVal(const ValuesBucket &values, const string &key, int32_t &value)
316 {
317     value = 0;
318     ValueObject valueObject;
319     if (values.GetObject(key, valueObject)) {
320         valueObject.GetInt(value);
321     } else {
322         return -EINVAL;
323     }
324     return E_OK;
325 }
326 
ObtainMaxAlbumOrder(int32_t & maxAlbumOrder)327 static int32_t ObtainMaxAlbumOrder(int32_t &maxAlbumOrder)
328 {
329     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
330     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, -E_HAS_DB_ERROR, "uniStore is nullptr! failed query album order");
331     std::string queryMaxOrderSql = "SELECT Max(album_order) FROM " + PhotoAlbumColumns::TABLE;
332     auto resultSet = uniStore->QuerySql(queryMaxOrderSql);
333     bool cond = (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK);
334     CHECK_AND_RETURN_RET_LOG(!cond, -E_HAS_DB_ERROR, "Failed to query album!");
335     return resultSet->GetInt(0, maxAlbumOrder);
336 }
337 
PrepareUserAlbum(const string & albumName,ValuesBucket & values)338 static void PrepareUserAlbum(const string &albumName, ValuesBucket &values)
339 {
340     values.PutString(PhotoAlbumColumns::ALBUM_NAME, albumName);
341     values.PutInt(PhotoAlbumColumns::ALBUM_TYPE, PhotoAlbumType::USER);
342     values.PutInt(PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumSubType::USER_GENERIC);
343     values.PutLong(PhotoAlbumColumns::ALBUM_DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
344     values.PutInt(PhotoAlbumColumns::ALBUM_IS_LOCAL, 1); // local album is 1.
345     values.PutInt(PhotoAlbumColumns::ALBUM_PRIORITY, ALBUM_PRIORITY_DEFAULT);
346     values.PutString(PhotoAlbumColumns::ALBUM_LPATH, ALBUM_LPATH_PREFIX + albumName);
347     values.PutLong(PhotoAlbumColumns::ALBUM_DATE_ADDED, MediaFileUtils::UTCTimeMilliSeconds());
348 }
349 
PrepareWhere(const string & albumName,const string & relativePath,RdbPredicates & predicates)350 inline void PrepareWhere(const string &albumName, const string &relativePath, RdbPredicates &predicates)
351 {
352     predicates.EqualTo(PhotoAlbumColumns::ALBUM_NAME, albumName);
353     predicates.EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::USER));
354     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
355     if (relativePath.empty()) {
356         predicates.IsNull(PhotoAlbumColumns::ALBUM_RELATIVE_PATH);
357     } else {
358         predicates.EqualTo(PhotoAlbumColumns::ALBUM_RELATIVE_PATH, relativePath);
359     }
360     predicates.NotEqualTo(PhotoAlbumColumns::ALBUM_DIRTY,
361         to_string(static_cast<int32_t>(DirtyTypes::TYPE_DELETED)));
362 }
363 
364 // Caller is responsible for checking @albumName AND @relativePath
DoCreatePhotoAlbum(const string & albumName,const string & relativePath,const ValuesBucket & albumValues)365 int DoCreatePhotoAlbum(const string &albumName, const string &relativePath, const ValuesBucket& albumValues)
366 {
367     // Build insert sql
368     string sql;
369     vector<ValueObject> bindArgs;
370     sql.append("INSERT").append(" OR ROLLBACK").append(" INTO ").append(PhotoAlbumColumns::TABLE).append(" ");
371 
372     MediaLibraryRdbStore::BuildValuesSql(albumValues, bindArgs, sql);
373 
374     RdbPredicates wherePredicates(PhotoAlbumColumns::TABLE);
375     PrepareWhere(albumName, relativePath, wherePredicates);
376     sql.append(" WHERE NOT EXISTS (");
377     MediaLibraryRdbStore::BuildQuerySql(wherePredicates, { PhotoAlbumColumns::ALBUM_ID }, bindArgs, sql);
378     sql.append(");");
379     MEDIA_DEBUG_LOG("DoCreatePhotoAlbum InsertSql: %{private}s", sql.c_str());
380 
381     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
382     int64_t lastInsertRowId = 0;
383     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, lastInsertRowId, "RdbStore is nullptr!");
384     lastInsertRowId = rdbStore->ExecuteForLastInsertedRowId(sql, bindArgs);
385     CHECK_AND_RETURN_RET_LOG(lastInsertRowId >= 0, lastInsertRowId, "insert fail and rollback");
386     MEDIA_INFO_LOG("Create photo album success, id: %{public}" PRId64, lastInsertRowId);
387     return lastInsertRowId;
388 }
389 
QueryExistingAlbumByLpath(const string & albumName,bool & isDeleted,bool & isSameName)390 static int32_t QueryExistingAlbumByLpath(const string& albumName, bool& isDeleted, bool& isSameName)
391 {
392     const string lpath = ALBUM_LPATH_PREFIX + albumName;
393     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
394     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_FAIL, "fail to get rdbstore, lpath is: %{public}s", lpath.c_str());
395 
396     const string sql = "SELECT album_id, album_name, dirty FROM " + PhotoAlbumColumns::TABLE +
397         " WHERE LOWER(lpath) = LOWER(?)";
398     const vector<ValueObject> bindArgs { lpath };
399     auto resultSet = rdbStore->QueryByStep(sql, bindArgs);
400     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_FAIL, "Query failed, lpath is: %{public}s", lpath.c_str());
401 
402     int32_t rowCount;
403     CHECK_AND_RETURN_RET_LOG(resultSet->GetRowCount(rowCount) == NativeRdb::E_OK, E_FAIL,
404         "Failed to get row count, lpath is: %{public}s", lpath.c_str());
405     if (rowCount == 0) {
406         // No existing album with same lpath is found
407         return E_OK;
408     }
409     CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK, E_FAIL,
410         "Failed to go to first row, lpath is: %{public}s", lpath.c_str());
411     isDeleted =
412         GetInt32Val(PhotoAlbumColumns::ALBUM_DIRTY, resultSet) == static_cast<int32_t>(DirtyTypes::TYPE_DELETED);
413     string existingName = GetStringVal(PhotoAlbumColumns::ALBUM_NAME, resultSet);
414     isSameName = existingName == albumName;
415     return GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
416 }
417 
UseDefaultCreateValue(const string & columnName,const pair<bool,string> & defaultValue,string & sql,vector<ValueObject> & bindArgs,int32_t albumId)418 static void UseDefaultCreateValue(const string& columnName, const pair<bool, string>& defaultValue,
419     string& sql, vector<ValueObject>& bindArgs, int32_t albumId)
420 {
421     // needs to set album order to the max value + 1
422     if (columnName == PhotoAlbumColumns::ALBUM_ORDER) {
423         sql.append("( SELECT COALESCE(MAX(album_order), 0) + 1 FROM PhotoAlbum WHERE album_id <> ?)");
424         bindArgs.push_back(ValueObject {albumId});
425     // otherwise, set the default value
426     } else if (defaultValue.first) {
427         sql.append("NULL");
428     } else {
429         sql.append(defaultValue.second);
430     }
431 }
432 
BuildReuseSql(int32_t id,const ValuesBucket & albumValues,const unordered_map<string,pair<bool,string>> & photoAlbumSchema,vector<ValueObject> & bindArgs)433 static string BuildReuseSql(int32_t id, const ValuesBucket& albumValues,
434     const unordered_map<string, pair<bool, string>>& photoAlbumSchema, vector<ValueObject>& bindArgs)
435 {
436     map<string, ValueObject> createUserValuesMap;
437     albumValues.GetAll(createUserValuesMap);
438     string sql;
439     sql.append("UPDATE PhotoAlbum SET ");
440     for (auto schemaIter = photoAlbumSchema.begin(); schemaIter != photoAlbumSchema.end(); schemaIter++) {
441         sql.append(schemaIter->first); // columnName
442         sql.append(" = ");
443         auto userValueIter = createUserValuesMap.find(schemaIter->first);
444         if (userValueIter != createUserValuesMap.end()) {
445             // Use the value from createUserValuesMap
446             sql.append("?");
447             bindArgs.push_back(userValueIter->second);
448         } else {
449             UseDefaultCreateValue(schemaIter->first, schemaIter->second, sql, bindArgs, id);
450         }
451         if (std::next(schemaIter) != photoAlbumSchema.end()) {
452             sql.append(", ");
453         }
454     }
455     sql.append(" WHERE album_id = ?");
456     bindArgs.push_back(ValueObject {id});
457     return sql;
458 }
459 
QueryPhotoAlbumSchema()460 static unordered_map<string, pair<bool, string>> QueryPhotoAlbumSchema()
461 {
462     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
463     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, {}, "fail to get rdbstore");
464     const string queryScheme = "PRAGMA table_info([PhotoAlbum])";
465     auto resultSet = rdbStore->QueryByStep(queryScheme);
466     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, {}, "Query failed");
467 
468     unordered_map<string, pair<bool, string>> photoAlbumSchema;
469     while (resultSet->GoToNextRow() == E_OK) {
470         bool isPk = GetInt32Val("pk", resultSet) == 1;
471         if (!isPk) {
472             string colName = GetStringVal("name", resultSet);
473             string defaultValue = GetStringVal("dflt_value", resultSet);
474             bool isNull;
475             int32_t dfltIdx;
476             resultSet->GetColumnIndex("dflt_value", dfltIdx);
477             resultSet->IsColumnNull(dfltIdx, isNull);
478             photoAlbumSchema[colName] = make_pair(isNull, defaultValue);
479         }
480     }
481     return photoAlbumSchema;
482 }
483 
RenewDeletedPhotoAlbum(int32_t id,const ValuesBucket & albumValues,std::shared_ptr<TransactionOperations> trans)484 int32_t MediaLibraryAlbumOperations::RenewDeletedPhotoAlbum(int32_t id, const ValuesBucket& albumValues,
485     std::shared_ptr<TransactionOperations> trans)
486 {
487     MEDIA_INFO_LOG("Renew deleted PhotoAlbum start, album id: %{public}d", id);
488     unordered_map<string, pair<bool, string>> photoAlbumSchema = QueryPhotoAlbumSchema();
489     vector<NativeRdb::ValueObject> bindArgs;
490     string sql = BuildReuseSql(id, albumValues, photoAlbumSchema, bindArgs);
491     int32_t ret {};
492     if (trans) {
493         ret = trans->ExecuteSql(sql, bindArgs);
494     } else {
495         auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
496         CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR,
497             "Renew deleted PhotoAlbum execute sql failed, RdbStore is nullptr");
498         ret = rdbStore->ExecuteSql(sql, bindArgs);
499     }
500     CHECK_AND_RETURN_RET_LOG(ret == NativeRdb::E_OK, E_HAS_DB_ERROR,
501         "Renew deleted PhotoAlbum execute sql failed, id is: %{public}d", id);
502     return E_OK;
503 }
504 
CreatePhotoAlbum(const string & albumName)505 int CreatePhotoAlbum(const string &albumName)
506 {
507     int32_t err = MediaFileUtils::CheckAlbumName(albumName);
508     if (err < 0) {
509         MEDIA_ERR_LOG("Check album name failed, album name: %{private}s", albumName.c_str());
510         return err;
511     }
512 
513     ValuesBucket albumValues;
514     PrepareUserAlbum(albumName, albumValues);
515 
516     // try to reuse existing record with same lpath first
517     int32_t id = -1;
518     bool isDeleted = false;
519     bool isSameName = false;
520     std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
521     std::function<int(void)> tryReuseDeleted = [&]()->int {
522         id = QueryExistingAlbumByLpath(albumName, isDeleted, isSameName);
523         if (id <= 0) {
524             // id < 0 means error has occurred, id == 0 means no existing record.
525             // needs to return in either case.
526             return id;
527         }
528         MEDIA_INFO_LOG("%{public}s photo album with the same lpath exists, reuse the record id %{public}d.",
529             isDeleted ? "Deleted" : "Existing", id);
530         if (isDeleted) {
531             int32_t ret = MediaLibraryAlbumOperations::RenewDeletedPhotoAlbum(id, albumValues, trans);
532             CHECK_AND_PRINT_LOG(ret == E_OK, "Failed to update deleted album: %{public}s", albumName.c_str());
533             return ret;
534         }
535         return E_OK;
536     };
537     int ret = trans->RetryTrans(tryReuseDeleted);
538     CHECK_AND_RETURN_RET_LOG(ret == E_OK, E_HAS_DB_ERROR, "Try trans fail!, ret: %{public}d", ret);
539     if (id > 0 && (!isSameName || isDeleted)) {
540         return id;
541     }
542 
543     // no existing record available, create a new one
544     return DoCreatePhotoAlbum(albumName, "", albumValues);
545 }
546 
CreatePhotoAlbum(MediaLibraryCommand & cmd)547 int CreatePhotoAlbum(MediaLibraryCommand &cmd)
548 {
549     string albumName;
550     string subtype;
551     int err = GetStringObject(cmd.GetValueBucket(), PhotoAlbumColumns::ALBUM_NAME, albumName);
552     GetStringObject(cmd.GetValueBucket(), PhotoAlbumColumns::ALBUM_SUBTYPE, subtype);
553     if (err < 0 && subtype != to_string(PORTRAIT) && subtype != to_string(GROUP_PHOTO)) {
554         return err;
555     }
556     int rowId;
557     if (OperationObject::ANALYSIS_PHOTO_ALBUM == cmd.GetOprnObject()) {
558         auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
559         CHECK_AND_RETURN_RET(rdbStore != nullptr, E_HAS_DB_ERROR);
560         int64_t outRowId = 0;
561         auto ret = rdbStore->Insert(cmd, outRowId);
562         CHECK_AND_RETURN_RET_LOG(ret == E_OK, outRowId, "insert fail, ret: %{public}d", ret);
563         rowId = outRowId;
564     } else {
565         rowId = CreatePhotoAlbum(albumName);
566     }
567     auto watch = MediaLibraryNotify::GetInstance();
568     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
569     if (rowId > 0) {
570         watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX, to_string(rowId)),
571             NotifyType::NOTIFY_ADD);
572     }
573     return rowId;
574 }
575 
DeletePhotoAlbum(RdbPredicates & predicates)576 int32_t MediaLibraryAlbumOperations::DeletePhotoAlbum(RdbPredicates &predicates)
577 {
578     // Only user generic albums can be deleted
579     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
580     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "DeletePhotoAlbum failed. rdbStore is null");
581     MEDIA_INFO_LOG("Delete user generic albums start");
582     if (MediaLibraryRdbUtils::UpdateTrashedAssetOnAlbum(rdbStore, predicates) <= 0) {
583         MEDIA_ERR_LOG("Update trashed asset failed");
584         return E_HAS_DB_ERROR;
585     }
586     predicates.And()->BeginWrap()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::USER));
587     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
588     predicates.EndWrap();
589 
590     int deleteRow = MediaLibraryRdbStore::Delete(predicates);
591     auto watch = MediaLibraryNotify::GetInstance();
592     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
593     const vector<string> &notifyUris = predicates.GetWhereArgs();
594     size_t count = notifyUris.size() - AFTER_AGR_SIZE;
595     for (size_t i = 0; i < count; i++) {
596         if (deleteRow > 0) {
597             watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX,
598                 notifyUris[i]), NotifyType::NOTIFY_REMOVE);
599         }
600     }
601     return deleteRow;
602 }
603 
DeleteHighlightAlbums(RdbPredicates & predicates)604 int32_t MediaLibraryAlbumOperations::DeleteHighlightAlbums(RdbPredicates &predicates)
605 {
606     // Only Highlight albums can be deleted by this way
607     MEDIA_INFO_LOG("Delete highlight albums");
608     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
609     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "DeleteHighlightAlbum failed. rdbStore is null");
610 
611     ValuesBucket values;
612     values.PutInt(HIGHLIGHT_STATUS, HIGHLIGHT_DELETED);
613     int32_t changedRows = 0;
614     int32_t result = rdbStore->Update(changedRows, values, predicates);
615     CHECK_AND_RETURN_RET_LOG(result == NativeRdb::E_OK, E_HAS_DB_ERROR,
616         "Delete highlight album failed, result is %{private}d", result);
617     auto watch = MediaLibraryNotify::GetInstance();
618     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
619 
620     const vector<string> &notifyUris = predicates.GetWhereArgs();
621     if (changedRows > 0) {
622         for (size_t i = 0; i < notifyUris.size(); ++i) {
623             watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX,
624                 notifyUris[i]), NotifyType::NOTIFY_REMOVE);
625         }
626     }
627     return changedRows;
628 }
629 
NotifyPortraitAlbum(const vector<int32_t> & changedAlbumIds)630 static void NotifyPortraitAlbum(const vector<int32_t> &changedAlbumIds)
631 {
632     if (changedAlbumIds.size() <= 0) {
633         return;
634     }
635     auto watch = MediaLibraryNotify::GetInstance();
636     CHECK_AND_RETURN_LOG(watch != nullptr, "Can not get MediaLibraryNotify Instance");
637     for (int32_t albumId : changedAlbumIds) {
638         watch->Notify(MediaFileUtils::GetUriByExtrConditions(
639             PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX, to_string(albumId)), NotifyType::NOTIFY_UPDATE);
640     }
641 }
642 
NotifyHighlightAlbum(const vector<int32_t> & changedAlbumIds)643 static void NotifyHighlightAlbum(const vector<int32_t> &changedAlbumIds)
644 {
645     if (changedAlbumIds.size() <= 0) {
646         return;
647     }
648     auto watch = MediaLibraryNotify::GetInstance();
649     for (int32_t albumId : changedAlbumIds) {
650         watch->Notify(MediaFileUtils::GetUriByExtrConditions(
651             PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX, to_string(albumId)), NotifyType::NOTIFY_UPDATE);
652     }
653 }
654 
GetIntValueFromResultSet(shared_ptr<ResultSet> resultSet,const string & column,int & value)655 int32_t GetIntValueFromResultSet(shared_ptr<ResultSet> resultSet, const string &column, int &value)
656 {
657     int index = E_INDEX;
658     resultSet->GetColumnIndex(column, index);
659     if (index == E_INDEX) {
660         return E_HAS_DB_ERROR;
661     }
662     if (resultSet->GetInt(index, value) != NativeRdb::E_OK) {
663         return E_HAS_DB_ERROR;
664     }
665     return E_OK;
666 }
667 
GetStringValueFromResultSet(shared_ptr<ResultSet> resultSet,const string & column,string & value)668 int32_t GetStringValueFromResultSet(shared_ptr<ResultSet> resultSet, const string &column, string &value)
669 {
670     if (resultSet == nullptr) {
671         return E_HAS_DB_ERROR;
672     }
673     int index = E_INDEX;
674     resultSet->GetColumnIndex(column, index);
675     if (index == E_INDEX) {
676         return E_HAS_DB_ERROR;
677     }
678     if (resultSet->GetString(index, value) != NativeRdb::E_OK) {
679         return E_HAS_DB_ERROR;
680     }
681     return E_OK;
682 }
683 
GetDisplayLevelAlbumPredicates(const int32_t value,DataShare::DataSharePredicates & predicates)684 void GetDisplayLevelAlbumPredicates(const int32_t value, DataShare::DataSharePredicates &predicates)
685 {
686     string whereClause;
687     string whereClauseRelatedMe = "(SELECT " + MAP_ALBUM + " FROM " + ANALYSIS_PHOTO_MAP_TABLE +
688             " WHERE " + MAP_ASSET + " IN ( SELECT " + MediaColumn::MEDIA_ID + " FROM " + PhotoColumn::PHOTOS_TABLE +
689             " WHERE " + MediaColumn::MEDIA_ID + " IN (SELECT " + MAP_ASSET + " FROM " + ANALYSIS_PHOTO_MAP_TABLE +
690             " WHERE " + MAP_ASSET + " IN (SELECT " + MAP_ASSET + " FROM " + ANALYSIS_PHOTO_MAP_TABLE + " WHERE " +
691             MAP_ALBUM + " IN(SELECT " + ALBUM_ID + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + IS_ME + " = 1))" +
692             " GROUP BY " + MAP_ASSET + " HAVING count(" + MAP_ASSET + ") > 1) AND " + MediaColumn::MEDIA_DATE_TRASHED +
693             " = 0) AND " + MAP_ALBUM + " NOT IN (SELECT " + ALBUM_ID + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " +
694             IS_ME + " = 1)" + " GROUP BY " + MAP_ALBUM + " HAVING count(" + MAP_ALBUM + ") >= " +
695             to_string(PORTRAIT_FIRST_PAGE_MIN_COUNT_RELATED_ME) + ")";
696     std::string whereClauseAlbumName = ALBUM_NAME + " IS NOT NULL AND " + ALBUM_NAME + " != ''";
697 
698     if (value == FIRST_PAGE) {
699         string relatedMeFirstPage = ALBUM_ID + " IN " + whereClauseRelatedMe;
700         string whereClauseDisplay = USER_DISPLAY_LEVEL + " = 1";
701         string whereClauseSatifyCount = COUNT + " >= " + to_string(PORTRAIT_FIRST_PAGE_MIN_COUNT) + " AND (" +
702             USER_DISPLAY_LEVEL + " != 2 OR " + USER_DISPLAY_LEVEL + " IS NULL)";
703         whereClause = ALBUM_SUBTYPE + " = " + to_string(PORTRAIT) + " AND (((" + USER_DISPLAY_LEVEL + " != 3 AND " +
704             USER_DISPLAY_LEVEL + " !=2) OR " + USER_DISPLAY_LEVEL + " IS NULL) AND ((" +
705             whereClauseDisplay + ") OR (" + relatedMeFirstPage + ") OR (" + whereClauseSatifyCount + ") OR (" +
706             whereClauseAlbumName + "))) GROUP BY " + GROUP_TAG +
707             " ORDER BY CASE WHEN " + IS_ME + " != 0 THEN 0 ELSE 1 END, CASE WHEN " +
708             RENAME_OPERATION + " != 0 THEN 0 ELSE 1 END, " + COUNT + " DESC";
709     } else if (value == SECOND_PAGE) {
710         whereClause = ALBUM_SUBTYPE + " = " + to_string(PORTRAIT) + " AND (" + USER_DISPLAY_LEVEL + " = 2 OR (" +
711             COUNT + " < " + to_string(PORTRAIT_FIRST_PAGE_MIN_COUNT) + " AND " + COUNT + " >= " +
712             to_string(PORTRAIT_SECOND_PAGE_MIN_PICTURES_COUNT) + " AND (" + USER_DISPLAY_LEVEL + " != 1 OR " +
713             USER_DISPLAY_LEVEL + " IS NULL) AND (" + USER_DISPLAY_LEVEL + " != 3 OR " + USER_DISPLAY_LEVEL +
714             " IS NULL) " + " AND NOT (" + whereClauseAlbumName + ") AND (" +
715             ALBUM_ID + " NOT IN " + whereClauseRelatedMe + ")))" +
716             " GROUP BY " + GROUP_TAG +
717             " ORDER BY CASE WHEN " + IS_ME + " != 0 THEN 0 ELSE 1 END, CASE WHEN " +
718             RENAME_OPERATION + " != 0 THEN 0 ELSE 1 END, " + COUNT + " DESC";
719     } else if (value == FAVORITE_PAGE) {
720         whereClause = ALBUM_SUBTYPE + " = " + to_string(PORTRAIT) + " AND (" + USER_DISPLAY_LEVEL + " = 3 )GROUP BY " +
721             GROUP_TAG + " ORDER BY CASE WHEN " + IS_ME + " != 0 THEN 0 ELSE 1 END, CASE WHEN " +
722             RENAME_OPERATION + " != 0 THEN 0 ELSE 1 END, " + COUNT + " DESC, " + RANK;
723     } else {
724         MEDIA_ERR_LOG("The display level is invalid");
725         whereClause = "";
726     }
727     predicates.SetWhereClause(whereClause);
728 }
729 
GetPortraitSubtype(const string & subtypeName,const string & whereClause,const vector<string> & whereArgs)730 int32_t GetPortraitSubtype(const string &subtypeName, const string &whereClause, const vector<string> &whereArgs)
731 {
732     size_t pos = whereClause.find(subtypeName);
733     if (pos == string::npos) {
734         MEDIA_ERR_LOG("whereClause is invalid");
735         return E_INDEX;
736     }
737     size_t argsIndex = 0;
738     for (size_t i = 0; i < pos; i++) {
739         if (whereClause[i] == '?') {
740             argsIndex++;
741         }
742     }
743     if (argsIndex > whereArgs.size() - 1) {
744         MEDIA_ERR_LOG("whereArgs is invalid");
745         return E_INDEX;
746     }
747     return atoi(whereArgs[argsIndex].c_str());
748 }
749 
IsSupportQueryIsMe()750 bool IsSupportQueryIsMe()
751 {
752     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
753     if (uniStore == nullptr) {
754         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
755         return false;
756     }
757     const std::string queryAnalyzedPic = "SELECT " + MEDIA_COLUMN_COUNT_1 + " FROM " + VISION_TOTAL_TABLE + " WHERE " +
758         FACE + " = " + to_string(FACE_ANALYSISED_STATE) + " OR " +
759         FACE + " = " + to_string(FACE_NO_NEED_ANALYSIS_STATE);
760     auto resultSetAnalyzed = uniStore->QuerySql(queryAnalyzedPic);
761     bool cond = (resultSetAnalyzed == nullptr || resultSetAnalyzed->GoToFirstRow() != NativeRdb::E_OK);
762     CHECK_AND_RETURN_RET(!cond, false);
763 
764     int analyzedCount;
765     if (GetIntValueFromResultSet(resultSetAnalyzed, MEDIA_COLUMN_COUNT_1, analyzedCount) != NativeRdb::E_OK) {
766         return false;
767     }
768     if (analyzedCount <= 0) {
769         return false;
770     }
771 
772     const std::string queryAllPic = "SELECT " + MEDIA_COLUMN_COUNT_1 + " FROM " + VISION_TOTAL_TABLE;
773     auto resultSetTotal = uniStore->QuerySql(queryAnalyzedPic);
774     cond = (resultSetTotal == nullptr || resultSetTotal->GoToFirstRow() != NativeRdb::E_OK);
775     CHECK_AND_RETURN_RET(!cond, false);
776     int totleCount;
777     if (GetIntValueFromResultSet(resultSetTotal, MEDIA_COLUMN_COUNT_1, totleCount) != NativeRdb::E_OK) {
778         return false;
779     }
780     if (totleCount == 0 ||
781         (analyzedCount * PERCENTAGE_FOR_SUPPORT_QUERY_ISME / totleCount <= SUPPORT_QUERY_ISME_MIN_COUNT)) {
782         MEDIA_INFO_LOG("Analyzed proportion less than 80");
783         return false;
784     }
785     return true;
786 }
787 
GetIsMeAlbumPredicates(const int32_t value,DataShare::DataSharePredicates & predicates)788 void GetIsMeAlbumPredicates(const int32_t value, DataShare::DataSharePredicates &predicates)
789 {
790     string selection;
791     if (value == QUERY_PROB_IS_ME_VALUE) {
792         if (!IsSupportQueryIsMe()) {
793             MEDIA_ERR_LOG("Not support to query isMe");
794             return;
795         }
796         selection = ANALYSIS_ALBUM_TABLE + "." + ALBUM_SUBTYPE + " = " + to_string(PORTRAIT) +
797             " GROUP BY " + ANALYSIS_ALBUM_TABLE + "." + ALBUM_ID + " HAVING SUM(CASE WHEN " +
798             PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::PHOTO_FRONT_CAMERA + " = 1 THEN 1 ELSE " +
799             " 0 END) > 0 " + " ORDER BY SUM(CASE WHEN " + PhotoColumn::PHOTOS_TABLE + "." +
800             PhotoColumn::PHOTO_FRONT_CAMERA + " = 1 THEN 1 ELSE 0 END) DESC ";
801     } else if (value == QUERY_IS_ME_VALUE) {
802         selection = ALBUM_SUBTYPE + " = " + to_string(PORTRAIT) + " AND " + IS_ME + " = 1 GROUP BY " + GROUP_TAG;
803     } else {
804         MEDIA_ERR_LOG("The value is not support for query is me");
805         return;
806     }
807     predicates.SetWhereClause(selection);
808 }
809 
GetAlbumNameNotNullPredicates(int32_t value,DataShare::DataSharePredicates & predicates)810 void GetAlbumNameNotNullPredicates(int32_t value, DataShare::DataSharePredicates &predicates)
811 {
812     if (value != ALBUM_NAME_NOT_NULL_ENABLED) {
813         MEDIA_ERR_LOG("The value is not support for query not null");
814         return;
815     }
816     string selection = ALBUM_SUBTYPE + " = " + to_string(PORTRAIT) + " AND " + PhotoAlbumColumns::ALBUM_NAME +
817         " IS NOT NULL GROUP BY " + GROUP_TAG;
818     predicates.SetWhereClause(selection);
819 }
820 
GetIsMeLeftJoinPredicates(RdbPredicates & rdbPredicates)821 void GetIsMeLeftJoinPredicates(RdbPredicates &rdbPredicates)
822 {
823     std::string onClause = ANALYSIS_ALBUM_TABLE + "." + ALBUM_ID + " = " +
824         ANALYSIS_PHOTO_MAP_TABLE + "." + MAP_ALBUM;
825     rdbPredicates.LeftOuterJoin(ANALYSIS_PHOTO_MAP_TABLE)->On({ onClause });
826     onClause = ANALYSIS_PHOTO_MAP_TABLE + "." + MAP_ASSET + " = " +
827         PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID;
828     rdbPredicates.LeftOuterJoin(PhotoColumn::PHOTOS_TABLE)->On({ onClause });
829 }
830 
QueryPortraitAlbum(MediaLibraryCommand & cmd,const std::vector<std::string> & columns)831 std::shared_ptr<NativeRdb::ResultSet> MediaLibraryAlbumOperations::QueryPortraitAlbum(MediaLibraryCommand &cmd,
832     const std::vector<std::string> &columns)
833 {
834     auto predicates = cmd.GetAbsRdbPredicates();
835     auto whereClause = predicates->GetWhereClause();
836     auto whereArgs = predicates->GetWhereArgs();
837     DataShare::DataSharePredicates predicatesPortrait;
838     if (whereClause.find(USER_DISPLAY_LEVEL) != string::npos) {
839         int32_t value = GetPortraitSubtype(USER_DISPLAY_LEVEL, whereClause, whereArgs);
840         if (value == E_INDEX) {
841             return nullptr;
842         }
843         GetDisplayLevelAlbumPredicates(value, predicatesPortrait);
844     } else if (whereClause.find(IS_ME) != string::npos) {
845         int32_t value = GetPortraitSubtype(IS_ME, whereClause, whereArgs);
846         bool cond = (value == E_INDEX || (value != QUERY_PROB_IS_ME_VALUE && value != QUERY_IS_ME_VALUE));
847         CHECK_AND_RETURN_RET(!cond, nullptr);
848         GetIsMeAlbumPredicates(value, predicatesPortrait);
849     } else if (whereClause.find(ALBUM_NAME_NOT_NULL) != string::npos) {
850         int32_t value = GetPortraitSubtype(ALBUM_NAME_NOT_NULL, whereClause, whereArgs);
851         bool cond = (value == E_INDEX || value != ALBUM_NAME_NOT_NULL_ENABLED);
852         CHECK_AND_RETURN_RET(!cond, nullptr);
853         GetAlbumNameNotNullPredicates(value, predicatesPortrait);
854     } else {
855         MEDIA_INFO_LOG("QueryPortraitAlbum whereClause is error");
856         return nullptr;
857     }
858     if (predicatesPortrait.GetWhereClause().empty()) {
859         return nullptr;
860     }
861     auto rdbPredicates = RdbUtils::ToPredicates(predicatesPortrait, ANALYSIS_ALBUM_TABLE);
862     if (whereClause.find(IS_ME) != string::npos &&
863         GetPortraitSubtype(IS_ME, whereClause, whereArgs) == QUERY_PROB_IS_ME_VALUE) {
864         GetIsMeLeftJoinPredicates(rdbPredicates);
865         std::vector<std::string> ismeColumns;
866         for (auto &item : columns) {
867             if (item.find(PhotoAlbumColumns::ALBUM_DATE_MODIFIED, 0) == string::npos) {
868                 ismeColumns.push_back(item);
869             }
870         }
871         ismeColumns.push_back(ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_DATE_MODIFIED);
872         ismeColumns.push_back("CAST(" + ANALYSIS_ALBUM_TABLE + "." + PhotoAlbumColumns::ALBUM_DATE_MODIFIED +
873             " / 1000 AS BIGINT) AS date_modified_s");
874         MEDIA_INFO_LOG("start query prob is me!!!");
875         return MediaLibraryRdbStore::QueryWithFilter(rdbPredicates, ismeColumns);
876     }
877     return MediaLibraryRdbStore::QueryWithFilter(rdbPredicates, columns);
878 }
879 
QueryPhotoAlbum(MediaLibraryCommand & cmd,const vector<string> & columns)880 shared_ptr<ResultSet> MediaLibraryAlbumOperations::QueryPhotoAlbum(MediaLibraryCommand &cmd,
881     const vector<string> &columns)
882 {
883     if (cmd.GetAbsRdbPredicates()->GetOrder().empty()) {
884         cmd.GetAbsRdbPredicates()->OrderByAsc(PhotoAlbumColumns::ALBUM_ORDER);
885     }
886     return MediaLibraryRdbStore::QueryWithFilter(*(cmd.GetAbsRdbPredicates()), columns);
887 }
888 
889 /*
890  * Check for conflicts with existing albums when setting album name
891  * returns:
892  *     - positive integer album id if needs to combine with an deleted album of same lpath
893  *     - 0 if no conflicts is found and new name album can be created
894  *     - negative integer if a conflict is found or error occurs and needs to abort
895  */
CheckConflictsWithExistingAlbum(const string & newAlbumName,const shared_ptr<MediaLibraryRdbStore> & rdbStore)896 static int32_t CheckConflictsWithExistingAlbum(const string &newAlbumName,
897     const shared_ptr<MediaLibraryRdbStore>& rdbStore)
898 {
899     const std::string newLPath = ALBUM_LPATH_PREFIX + newAlbumName;
900 
901     // Check if non-deleted album with same name exists
902     std::string sql = "SELECT * FROM PhotoAlbum WHERE album_name = ? AND dirty <> ?";
903     shared_ptr<NativeRdb::ResultSet> resultSetAlbum =
904         rdbStore->QueryByStep(sql, { newAlbumName, static_cast<int32_t>(DirtyTypes::TYPE_DELETED) });
905     CHECK_AND_RETURN_RET_LOG(resultSetAlbum != nullptr, E_ERR, "Query non-deleted album with same name failed");
906     int32_t rowCount = 0;
907     CHECK_AND_RETURN_RET_LOG(resultSetAlbum->GetRowCount(rowCount) == NativeRdb::E_OK, E_ERR,
908         "Get non-deleted album with same name row count failed");
909     CHECK_AND_RETURN_RET_LOG(rowCount <= 0, E_ERR, "Non-deleted album with same name exists");
910 
911     // Check albums with same lpath
912     sql = "SELECT * FROM PhotoAlbum WHERE lpath = ?";
913     resultSetAlbum = rdbStore->QueryByStep(sql, { newLPath });
914     CHECK_AND_RETURN_RET_LOG(resultSetAlbum != nullptr, E_ERR, "Query albums with same lpath failed");
915     CHECK_AND_RETURN_RET_LOG(resultSetAlbum->GetRowCount(rowCount) == NativeRdb::E_OK, E_ERR,
916         "Get albums with same lpath row count failed");
917     if (rowCount > 0) {
918         CHECK_AND_RETURN_RET_LOG(resultSetAlbum->GoToFirstRow() == NativeRdb::E_OK, E_ERR,
919             "Albums with same lpath go to first row failed, row count is %{public}d", rowCount);
920         bool isDeleted = GetInt32Val(PhotoAlbumColumns::ALBUM_DIRTY, resultSetAlbum) ==
921             static_cast<int32_t>(DirtyTypes::TYPE_DELETED);
922         if (isDeleted) {
923             int32_t albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSetAlbum);
924             MEDIA_INFO_LOG("Found deleted album %{public}d with same lpath", albumId);
925             return albumId;
926         } else {
927             MEDIA_ERR_LOG("Non-deleted album with same lpath exists");
928             return E_ERR;
929         }
930     }
931     return E_OK;
932 }
933 
BuildNewNameValuesBucket(const shared_ptr<MediaLibraryRdbStore> & rdbStore,int32_t albumId,NativeRdb::ValuesBucket & newNameValues,const string & newAlbumName,bool & isCloudAlbum)934 static bool BuildNewNameValuesBucket(const shared_ptr<MediaLibraryRdbStore>& rdbStore, int32_t albumId,
935     NativeRdb::ValuesBucket& newNameValues, const string& newAlbumName, bool& isCloudAlbum)
936 {
937     const std::string QUERY_OLD_ALBUM_INFO =
938         "SELECT * FROM PhotoAlbum WHERE " + PhotoAlbumColumns::ALBUM_ID + " = " + to_string(albumId) +
939         " AND " + PhotoAlbumColumns::ALBUM_TYPE + " = " + to_string(PhotoAlbumType::USER);
940     shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->QuerySql(QUERY_OLD_ALBUM_INFO);
941     CHECK_AND_RETURN_RET_LOG(TryToGoToFirstRow(resultSet), false,
942         "Rename user album failed. Query old album info failed");
943     MediaLibraryAlbumFusionUtils::BuildAlbumInsertValuesSetName(rdbStore, newNameValues, resultSet, newAlbumName);
944     const string albumCloudId = GetStringVal(PhotoAlbumColumns::ALBUM_CLOUD_ID, resultSet);
945     isCloudAlbum = !albumCloudId.empty();
946     return true;
947 }
948 
SetNewNameExecute(const shared_ptr<MediaLibraryRdbStore> & rdbStore,int32_t oldAlbumId,int64_t & newAlbumId,NativeRdb::ValuesBucket & newNameValues,bool isCloudAlbum)949 static bool SetNewNameExecute(const shared_ptr<MediaLibraryRdbStore>& rdbStore, int32_t oldAlbumId, int64_t& newAlbumId,
950     NativeRdb::ValuesBucket& newNameValues, bool isCloudAlbum)
951 {
952     if (newAlbumId > 0) {
953         // Deleted album with same lpath exists
954         int changeRows = 0;
955         newNameValues.PutInt(PhotoAlbumColumns::ALBUM_DIRTY, static_cast<int32_t>(DirtyTypes::TYPE_MDIRTY));
956         RdbPredicates rdbPredicatesNew(PhotoAlbumColumns::TABLE);
957         rdbPredicatesNew.EqualTo(PhotoAlbumColumns::ALBUM_ID, newAlbumId);
958         CHECK_AND_RETURN_RET_LOG(rdbStore->Update(changeRows, newNameValues, rdbPredicatesNew) == NativeRdb::E_OK,
959             false, "Failed to update deleted album with same name");
960         CHECK_AND_RETURN_RET_LOG(MediaLibraryAlbumFusionUtils::DeleteAlbumAndUpdateRelationship(rdbStore, oldAlbumId,
961             newAlbumId, false) == E_OK, false, "Failed to merge old name album with new name album");
962         MEDIA_INFO_LOG("Set photo album name: update deleted album with same name success,"
963             "old album id: %{public}d, new album id: %{public}" PRId64, oldAlbumId, newAlbumId);
964     } else {
965         newNameValues.PutInt(PhotoAlbumColumns::ALBUM_DIRTY, static_cast<int32_t>(DirtyTypes::TYPE_NEW));
966         CHECK_AND_RETURN_RET_LOG(
967             rdbStore->Insert(newAlbumId, PhotoAlbumColumns::TABLE, newNameValues) == NativeRdb::E_OK,
968             false, "Failed to insert new name album");
969         CHECK_AND_RETURN_RET_LOG(MediaLibraryAlbumFusionUtils::DeleteAlbumAndUpdateRelationship(rdbStore, oldAlbumId,
970             newAlbumId, isCloudAlbum) == E_OK, false, "Failed to merge old name album with new name album");
971         MEDIA_INFO_LOG("Set photo album name: insert new name album success,"
972             "old album id: %{public}d, new album id: %{public}" PRId64, oldAlbumId, newAlbumId);
973     }
974     return true;
975 }
976 
UpdateAnalysisIndexAfterRename(const vector<string> & fileIdsToUpdateIndex)977 static void UpdateAnalysisIndexAfterRename(const vector<string>& fileIdsToUpdateIndex)
978 {
979     MEDIA_INFO_LOG("update index fileIdsToUpdateIndex size: %{public}zu", fileIdsToUpdateIndex.size());
980     if (fileIdsToUpdateIndex.size() > 0) {
981         MediaAnalysisHelper::AsyncStartMediaAnalysisService(
982             static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_UPDATE_INDEX),
983             fileIdsToUpdateIndex);
984     }
985 }
986 
GetAssetIdsFromOldAlbum(const shared_ptr<MediaLibraryRdbStore> & rdbStore,int32_t oldAlbumId)987 static vector<string> GetAssetIdsFromOldAlbum(const shared_ptr<MediaLibraryRdbStore>& rdbStore,
988     int32_t oldAlbumId)
989 {
990     const std::string  QUERY_FILEID_TO_UPDATE_INDEX =
991         "SELECT file_id FROM Photos WHERE dirty != '4' AND owner_album_id = " + to_string(oldAlbumId);
992     vector<string> fileIds;
993     shared_ptr<NativeRdb::ResultSet> queryIdsResultSet = rdbStore->QuerySql(QUERY_FILEID_TO_UPDATE_INDEX);
994     CHECK_AND_PRINT_LOG(queryIdsResultSet != nullptr, "Query file id to update index failed");
995     while (queryIdsResultSet != nullptr && queryIdsResultSet->GoToNextRow() == NativeRdb::E_OK) {
996         fileIds.push_back(to_string(GetInt32Val("file_id", queryIdsResultSet)));
997     }
998     return fileIds;
999 }
1000 
1001 // Set album name: delete old and build a new one
RenameUserAlbum(int32_t oldAlbumId,const string & newAlbumName)1002 static int32_t RenameUserAlbum(int32_t oldAlbumId, const string &newAlbumName)
1003 {
1004     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1005     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "Rename user album failed. RdbStore is null");
1006     CHECK_AND_RETURN_RET_LOG(oldAlbumId > 0, E_INVALID_ARGS, "Rename user album failed. Invalid album id: %{public}d",
1007         oldAlbumId);
1008     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CheckAlbumName(newAlbumName) == E_OK, E_INVALID_ARGS,
1009         "Check album name failed");
1010     MEDIA_INFO_LOG("Start to set user album name of id %{public}d", oldAlbumId);
1011 
1012     vector<string> fileIdsToUpdateIndex = GetAssetIdsFromOldAlbum(rdbStore, oldAlbumId);
1013 
1014     bool argInvalid { false };
1015     std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
1016     int64_t newAlbumId = -1;
1017     std::function<int(void)> trySetUserAlbumName = [&]()->int {
1018         newAlbumId = -1;
1019         int32_t ret = CheckConflictsWithExistingAlbum(newAlbumName, rdbStore);
1020         if (ret < 0) {
1021             MEDIA_ERR_LOG("New name conflicts with existing album");
1022             argInvalid = true;
1023             return E_OK;
1024         } else if (ret > 0) {
1025             newAlbumId = ret;
1026         }
1027         NativeRdb::ValuesBucket newNameValues {};
1028         bool isCloudAlbum {};
1029         if (!BuildNewNameValuesBucket(rdbStore, oldAlbumId, newNameValues, newAlbumName, isCloudAlbum)) {
1030             MEDIA_ERR_LOG("Build new name values bucket failed");
1031             argInvalid = true;
1032             return E_OK;
1033         }
1034         CHECK_AND_RETURN_RET_LOG(SetNewNameExecute(rdbStore, oldAlbumId, newAlbumId, newNameValues, isCloudAlbum),
1035             E_HAS_DB_ERROR, "Set new name execute failed");
1036         return E_OK;
1037     };
1038     int ret = trans->RetryTrans(trySetUserAlbumName);
1039     if (argInvalid) {
1040         return E_INVALID_ARGS;
1041     }
1042     if (ret != E_OK) {
1043         MEDIA_ERR_LOG("Try trans fail!, ret: %{public}d", ret);
1044         return E_HAS_DB_ERROR;
1045     }
1046 
1047     UpdateAnalysisIndexAfterRename(fileIdsToUpdateIndex);
1048 
1049     auto watch = MediaLibraryNotify::GetInstance();
1050     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
1051     watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX,
1052         to_string(newAlbumId)), NotifyType::NOTIFY_UPDATE);
1053     return ALBUM_SETNAME_OK;
1054 }
1055 
PrepareUpdateValues(const ValuesBucket & values,ValuesBucket & updateValues)1056 int32_t PrepareUpdateValues(const ValuesBucket &values, ValuesBucket &updateValues)
1057 {
1058     // Collect coverUri if exists
1059     string coverUri;
1060     if (GetStringObject(values, PhotoAlbumColumns::ALBUM_COVER_URI, coverUri) == E_OK) {
1061         updateValues.PutString(PhotoAlbumColumns::ALBUM_COVER_URI, coverUri);
1062     }
1063 
1064     if (updateValues.IsEmpty()) {
1065         return -EINVAL;
1066     }
1067     updateValues.PutLong(PhotoAlbumColumns::ALBUM_DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
1068     return E_OK;
1069 }
1070 
GetOldAlbumName(int32_t albumId,string & oldAlbumName)1071 static bool GetOldAlbumName(int32_t albumId, string &oldAlbumName)
1072 {
1073     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1074     if (rdbStore == nullptr) {
1075         MEDIA_ERR_LOG("Get old album name failed. RdbStore is null");
1076         return false;
1077     }
1078     const std::string QUERY_ALBUM_INFO =
1079         "SELECT * FROM PhotoAlbum WHERE " + PhotoAlbumColumns::ALBUM_ID + " = " + to_string(albumId);
1080     shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->QuerySql(QUERY_ALBUM_INFO);
1081     if (resultSet == nullptr) {
1082         MEDIA_ERR_LOG("Get old album name failed. Query album info failed");
1083         return false;
1084     }
1085     if (resultSet->GoToNextRow() != NativeRdb::E_OK) {
1086         MEDIA_ERR_LOG("Get old album name failed. Go to next row failed");
1087         return false;
1088     }
1089     GetStringValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_NAME, oldAlbumName);
1090     return true;
1091 }
1092 
UpdatePhotoAlbum(const ValuesBucket & values,const DataSharePredicates & predicates)1093 int32_t UpdatePhotoAlbum(const ValuesBucket &values, const DataSharePredicates &predicates)
1094 {
1095     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoAlbumColumns::TABLE);
1096     CHECK_AND_RETURN_RET_LOG(!rdbPredicates.GetWhereArgs().empty(), E_INVALID_ARGS,
1097         "Update photo album failed. Predicates empty");
1098     int32_t albumId = atoi(rdbPredicates.GetWhereArgs()[0].c_str());
1099     CHECK_AND_RETURN_RET_LOG(albumId > 0, E_INVALID_ARGS,
1100         "Invalid album id: %{public}s", rdbPredicates.GetWhereArgs()[0].c_str());
1101 
1102     MEDIA_INFO_LOG("Start to update album %{public}d", albumId);
1103 
1104     string newAlbumName {};
1105     string oldAlbumName {};
1106     bool needRename = false;
1107     if (GetStringObject(values, PhotoAlbumColumns::ALBUM_NAME, newAlbumName) == E_OK &&
1108         GetOldAlbumName(albumId, oldAlbumName) && oldAlbumName != newAlbumName) {
1109         // if album name is changed, start user album renaming process
1110         // Rename process changes the album id, so put the rename process at the end
1111         needRename = true;
1112     };
1113 
1114     ValuesBucket rdbValues;
1115     int32_t err = PrepareUpdateValues(values, rdbValues);
1116     if (err < 0 && !needRename) {
1117         MEDIA_ERR_LOG("No values to update");
1118         return err;
1119     }
1120     // Only user generic albums can be updated
1121     rdbPredicates.And()->BeginWrap()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::USER));
1122     rdbPredicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
1123     rdbPredicates.Or()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SMART));
1124     rdbPredicates.EndWrap();
1125 
1126     int32_t changedRows = MediaLibraryRdbStore::UpdateWithDateTime(rdbValues, rdbPredicates);
1127     CHECK_AND_PRINT_LOG(changedRows >= 0, "Update photo album failed: %{public}d", changedRows);
1128 
1129     auto watch = MediaLibraryNotify::GetInstance();
1130     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
1131     if (changedRows > 0 && !needRename) { // No need to notify if album is to be renamed. Rename process will notify
1132         const vector<string> &notifyIds = rdbPredicates.GetWhereArgs();
1133         constexpr int32_t notIdArgs = 3;
1134         size_t count = notifyIds.size() - notIdArgs;
1135         for (size_t i = 0; i < count; i++) {
1136             watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX,
1137                 notifyIds[i]), NotifyType::NOTIFY_UPDATE);
1138         }
1139     }
1140 
1141     if (needRename) {
1142         int32_t ret = RenameUserAlbum(albumId, newAlbumName);
1143         CHECK_AND_RETURN_RET_LOG(ret >= 0, ret, "Rename user album failed");
1144     }
1145 
1146     return changedRows;
1147 }
1148 
GetLPathFromSourcePath(const string & sourcePath,string & lPath,int32_t mediaType)1149 int32_t MediaLibraryAlbumOperations::GetLPathFromSourcePath(const string& sourcePath, string& lPath,
1150                                                             int32_t mediaType)
1151 {
1152     size_t pos1 = SOURCE_PATH_PREFIX.length();
1153     size_t pos2 = sourcePath.find_last_of("/");
1154     CHECK_AND_RETURN_RET_LOG(
1155         sourcePath.find(SOURCE_PATH_PREFIX) != std::string::npos && pos2 != string::npos && pos1 < pos2,
1156         E_INDEX,
1157         "get no valid source path: %{public}s", sourcePath.c_str());
1158     lPath = sourcePath.substr(pos1, pos2 - pos1);
1159     /*
1160         if lPath from source path is /Pictures/Screenshots,
1161         it should be converted to /Pictures/Screenrecords if the asset is a video
1162     */
1163     if (lPath == AlbumPlugin::LPATH_SCREEN_SHOTS && mediaType == MEDIA_TYPE_VIDEO) {
1164         lPath = AlbumPlugin::LPATH_SCREEN_RECORDS;
1165     }
1166     return E_OK;
1167 }
1168 
HasSameLpath(const string & lPath,const string & assetId)1169 static bool HasSameLpath(const string &lPath, const string &assetId)
1170 {
1171     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1172     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, false, "Failed to get rdbStore.");
1173     const std::string QUERY_LPATH = "SELECT * FROM PhotoAlbum WHERE lpath = '" + lPath + "'";
1174     shared_ptr<NativeRdb::ResultSet> albumResultSet = rdbStore->QuerySql(QUERY_LPATH);
1175     if (albumResultSet == nullptr || albumResultSet->GoToFirstRow() != NativeRdb::E_OK) {
1176         return false;
1177     } else {
1178         int albumIdIndex;
1179         int32_t albumId;
1180         albumResultSet->GetColumnIndex(PhotoAlbumColumns::ALBUM_ID, albumIdIndex);
1181         if (albumResultSet->GetInt(albumIdIndex, albumId) != NativeRdb::E_OK) {
1182             return false;
1183         }
1184         const std::string UPDATE_ALBUM_ID_IN_PHOTOS = "UPDATE Photos Set owner_album_id = " +
1185             to_string(albumId) + " WHERE file_id = " + assetId;
1186         int ret = rdbStore->ExecuteSql(UPDATE_ALBUM_ID_IN_PHOTOS);
1187         if (ret != NativeRdb::E_OK) {
1188             MEDIA_ERR_LOG("Update new album is fails");
1189             return false;
1190         }
1191     }
1192     return true;
1193 }
1194 
RecoverAlbum(const string & assetId,const string & lPath,bool & isUserAlbum,int64_t & newAlbumId)1195 void MediaLibraryAlbumOperations::RecoverAlbum(const string& assetId, const string& lPath,
1196                                                bool& isUserAlbum, int64_t& newAlbumId)
1197 {
1198     CHECK_AND_RETURN_LOG(!lPath.empty(), "lPath empty, cannot recover album");
1199     CHECK_AND_RETURN_LOG(!HasSameLpath(lPath, assetId), "Has same lpath, no need to build new one");
1200     const string userAlbumMark = "/Users/";
1201     if (lPath.find(userAlbumMark) != string::npos) {
1202         isUserAlbum = true;
1203     }
1204     MEDIA_INFO_LOG("new album need to build, lpath is %{public}s", lPath.c_str());
1205     string albumName;
1206     string bundleName = "";
1207     auto albumType = PhotoAlbumType::SOURCE;
1208     auto albumSubType = PhotoAlbumSubType::SOURCE_GENERIC;
1209     string queryExpiredAlbumInfo = "SELECT * FROM album_plugin WHERE lpath = '" +
1210         lPath + "' AND priority = '1'";
1211     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1212     CHECK_AND_RETURN_LOG(rdbStore != nullptr, "Failed to get rdbStore.");
1213     shared_ptr<NativeRdb::ResultSet> albumPluginResultSet = rdbStore->QuerySql(queryExpiredAlbumInfo);
1214     if (albumPluginResultSet == nullptr || albumPluginResultSet->GoToFirstRow() != NativeRdb::E_OK) {
1215         size_t pos = lPath.find_last_of("/");
1216         CHECK_AND_RETURN_LOG(
1217             pos != string::npos && pos + 1 < lPath.length(),
1218             "get album name fail, lpath is %{public}s", lPath.c_str());
1219         albumName = lPath.substr(pos + 1);
1220         if (isUserAlbum) {
1221             albumType = PhotoAlbumType::USER;
1222             albumSubType = PhotoAlbumSubType::USER_GENERIC;
1223         }
1224     } else {
1225         GetStringValueFromResultSet(albumPluginResultSet, PhotoAlbumColumns::ALBUM_BUNDLE_NAME, bundleName);
1226         GetStringValueFromResultSet(albumPluginResultSet, PhotoAlbumColumns::ALBUM_NAME, albumName);
1227     }
1228 
1229     NativeRdb::ValuesBucket values;
1230     values.PutInt(PhotoAlbumColumns::ALBUM_PRIORITY, 1);
1231     values.PutInt(PhotoAlbumColumns::ALBUM_TYPE, albumType);
1232     values.PutInt(PhotoAlbumColumns::ALBUM_SUBTYPE, albumSubType);
1233     values.PutString(PhotoAlbumColumns::ALBUM_LPATH, lPath);
1234     values.PutString(PhotoAlbumColumns::ALBUM_NAME, albumName);
1235     values.PutString(PhotoAlbumColumns::ALBUM_BUNDLE_NAME, bundleName);
1236     values.PutLong(PhotoAlbumColumns::ALBUM_DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
1237     values.PutLong(PhotoAlbumColumns::ALBUM_DATE_ADDED, MediaFileUtils::UTCTimeMilliSeconds());
1238     int32_t ret = rdbStore->Insert(newAlbumId, PhotoAlbumColumns::TABLE, values);
1239 
1240     CHECK_AND_RETURN_LOG(ret == NativeRdb::E_OK, "Insert album failed on recover assets");
1241     const std::string UPDATE_NEW_ALBUM_ID_IN_PHOTOS = "UPDATE Photos SET owner_album_id = " +
1242         to_string(newAlbumId) + " WHERE file_id = " + assetId;
1243     ret = rdbStore->ExecuteSql(UPDATE_NEW_ALBUM_ID_IN_PHOTOS);
1244     CHECK_AND_RETURN_LOG(ret == NativeRdb::E_OK, "Update new album is fails");
1245 }
1246 
DealwithNoAlbumAssets(const vector<string> & whereArgs)1247 void MediaLibraryAlbumOperations::DealwithNoAlbumAssets(const vector<string> &whereArgs)
1248 {
1249     MediaLibraryTracer tracer;
1250     tracer.Start("MediaLibraryAlbumOperations::DealwithNoAlbumAssets");
1251     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1252     if (uniStore == nullptr) {
1253         MEDIA_ERR_LOG("get uniStore fail");
1254         return;
1255     }
1256     int32_t ret = PhotoOwnerAlbumIdOperation().SetRdbStore(uniStore).SetFileIds(whereArgs).FixPhotoRelation();
1257     CHECK_AND_RETURN_LOG(ret == E_OK, "Fix photo relation failed");
1258 }
1259 
isRecoverToHiddenAlbum(const string & uri)1260 static bool isRecoverToHiddenAlbum(const string& uri)
1261 {
1262     string fileId = MediaFileUtils::GetIdFromUri(uri);
1263     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
1264     predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
1265     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1266     if (uniStore == nullptr) {
1267         MEDIA_ERR_LOG("get uniStore fail");
1268         return false;
1269     }
1270     vector<string> columns = { MediaColumn::MEDIA_HIDDEN };
1271     auto resultSet = uniStore->Query(predicates, columns);
1272     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1273         MEDIA_ERR_LOG("fail to query file on photo");
1274         return false;
1275     }
1276     int isHiddenIndex = -1;
1277     int32_t isHidden = 0;
1278     resultSet->GetColumnIndex(MediaColumn::MEDIA_HIDDEN, isHiddenIndex);
1279     if (resultSet->GetInt(isHiddenIndex, isHidden) != NativeRdb::E_OK) {
1280         return false;
1281     }
1282     return isHidden == 1;
1283 }
1284 
RecoverPhotoAssets(const DataSharePredicates & predicates)1285 int32_t RecoverPhotoAssets(const DataSharePredicates &predicates)
1286 {
1287     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoColumn::PHOTOS_TABLE);
1288     rdbPredicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
1289     vector<string> whereArgs = rdbPredicates.GetWhereArgs();
1290     MediaLibraryRdbStore::ReplacePredicatesUriToId(rdbPredicates);
1291 
1292     MediaLibraryAlbumOperations::DealwithNoAlbumAssets(rdbPredicates.GetWhereArgs());
1293     // notify deferred processing session to restore image
1294     MultiStagesCaptureManager::RestorePhotos(rdbPredicates);
1295 
1296     ValuesBucket rdbValues;
1297     rdbValues.PutInt(MediaColumn::MEDIA_DATE_TRASHED, 0);
1298 
1299     int32_t changedRows = MediaLibraryRdbStore::UpdateWithDateTime(rdbValues, rdbPredicates);
1300     if (changedRows < 0) {
1301         return changedRows;
1302     }
1303     // set cloud enhancement to available
1304 #ifdef MEDIALIBRARY_FEATURE_CLOUD_ENHANCEMENT
1305     EnhancementManager::GetInstance().RecoverTrashUpdateInternal(rdbPredicates.GetWhereArgs());
1306 #endif
1307     MediaAnalysisHelper::StartMediaAnalysisServiceAsync(
1308         static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_UPDATE_INDEX), whereArgs);
1309     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1310     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "Failed to get rdbStore.");
1311     MediaLibraryRdbUtils::UpdateAllAlbums(rdbStore, whereArgs, NotifyAlbumType::SYS_ALBUM, false,
1312         AlbumOperationType::RECOVER_PHOTO);
1313 
1314     auto watch = MediaLibraryNotify::GetInstance();
1315     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
1316     size_t count = whereArgs.size() - THAN_AGR_SIZE;
1317     for (size_t i = 0; i < count; i++) {
1318         string notifyUri = MediaFileUtils::Encode(whereArgs[i]);
1319         if (isRecoverToHiddenAlbum(notifyUri)) {
1320             watch->Notify(notifyUri, NotifyType::NOTIFY_UPDATE);
1321         } else {
1322             watch->Notify(notifyUri, NotifyType::NOTIFY_ADD);
1323             watch->Notify(notifyUri, NotifyType::NOTIFY_THUMB_ADD);
1324         }
1325         watch->Notify(notifyUri, NotifyType::NOTIFY_ALBUM_ADD_ASSET);
1326     }
1327     int trashAlbumId = watch->GetAlbumIdBySubType(PhotoAlbumSubType::TRASH);
1328     if (trashAlbumId > 0) {
1329         for (size_t i = 0; i < count; i++) {
1330             watch->Notify(MediaFileUtils::Encode(whereArgs[i]), NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, trashAlbumId);
1331         }
1332     }
1333     return changedRows;
1334 }
1335 
DealWithHighlightSdTable(const DataSharePredicates & predicates)1336 void DealWithHighlightSdTable(const DataSharePredicates &predicates)
1337 {
1338     RdbPredicates assetMapPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_ASSET_MAP_TABLE);
1339     const vector<string> &whereUriArgs = assetMapPredicates.GetWhereArgs();
1340     vector<string> whereIdArgs;
1341     whereIdArgs.reserve(whereUriArgs.size());
1342     for (const auto &arg : whereUriArgs) {
1343         if (!MediaFileUtils::StartsWith(arg, PhotoColumn::PHOTO_URI_PREFIX)) {
1344             continue;
1345         }
1346         whereIdArgs.push_back(MediaFileUri::GetPhotoId(arg));
1347     }
1348     assetMapPredicates.SetWhereArgs(whereIdArgs);
1349 
1350     RdbPredicates predicatesSdMap(ANALYSIS_ASSET_SD_MAP_TABLE);
1351     predicatesSdMap.And()->In(MAP_ASSET_SOURCE, assetMapPredicates.GetWhereArgs());
1352     vector<string> columns = { MAP_ASSET_SOURCE, MAP_ASSET_DESTINATION };
1353     auto resultSetQuery = MediaLibraryRdbStore::QueryWithFilter(predicatesSdMap, columns);
1354     if (resultSetQuery == nullptr) {
1355         MEDIA_ERR_LOG("get highlight video failed");
1356         return;
1357     }
1358 
1359     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1360     if (rdbStore == nullptr) {
1361         MEDIA_ERR_LOG("Can not get rdbstore");
1362         return;
1363     }
1364     while (resultSetQuery->GoToNextRow() == NativeRdb::E_OK) {
1365         string assetId = to_string(GetInt32Val(MAP_ASSET_SOURCE, resultSetQuery));
1366         int32_t mapAssetDestination = GetInt32Val(MAP_ASSET_DESTINATION, resultSetQuery);
1367 
1368         string highlightVideoPath = "/storage/cloud/files/highlight/video/" + to_string(mapAssetDestination);
1369         MediaFileUtils::DeleteDir(highlightVideoPath);
1370         MEDIA_INFO_LOG("Delete highlight video path is: %{public}s", highlightVideoPath.c_str());
1371 
1372         const std::string DELETE_ITEM_FROM_SD_MAP =
1373             "DELETE FROM tab_analysis_asset_sd_map WHERE map_asset_source = " + assetId;
1374         int32_t ret = rdbStore->ExecuteSql(DELETE_ITEM_FROM_SD_MAP);
1375         if (ret != NativeRdb::E_OK) {
1376             MEDIA_ERR_LOG("DELETE highlight video failed, id is: %{public}s", assetId.c_str());
1377             continue;
1378         }
1379         const std::string DELETE_ITEM_FROM_ALBUM_MAP =
1380             "DELETE FROM tab_analysis_album_asset_map WHERE map_asset = " + assetId;
1381         ret = rdbStore->ExecuteSql(DELETE_ITEM_FROM_ALBUM_MAP);
1382         if (ret != NativeRdb::E_OK) {
1383             MEDIA_ERR_LOG("DELETE highlight video failed, id is: %{public}s", assetId.c_str());
1384             continue;
1385         }
1386     }
1387     MEDIA_INFO_LOG("Deal with highlight video finished");
1388 }
1389 
DeletePhotoAssets(const DataSharePredicates & predicates,const bool isAging,const bool compatible)1390 static inline int32_t DeletePhotoAssets(const DataSharePredicates &predicates,
1391     const bool isAging, const bool compatible)
1392 {
1393     DealWithHighlightSdTable(predicates);
1394     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoColumn::PHOTOS_TABLE);
1395     int32_t deletedRows = MediaLibraryAssetOperations::DeleteFromDisk(rdbPredicates, isAging, compatible);
1396     if (!isAging) {
1397         MediaAnalysisHelper::StartMediaAnalysisServiceAsync(
1398             static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_DELETE_INDEX));
1399     }
1400     return deletedRows;
1401 }
1402 
DeletePhotoAssetsCompleted(const DataSharePredicates & predicates,const bool isAging)1403 static inline int32_t DeletePhotoAssetsCompleted(const DataSharePredicates &predicates,
1404     const bool isAging)
1405 {
1406     MEDIA_DEBUG_LOG("DeletePhotoAssetsCompleted start.");
1407     DealWithHighlightSdTable(predicates);
1408     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoColumn::PHOTOS_TABLE);
1409     int32_t deletedRows = MediaLibraryAssetOperations::DeletePermanently(rdbPredicates, isAging);
1410     if (!isAging) {
1411         MediaAnalysisHelper::StartMediaAnalysisServiceAsync(
1412             static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_DELETE_INDEX));
1413     }
1414     return deletedRows;
1415 }
1416 
AgingPhotoAssets(shared_ptr<int> countPtr)1417 int32_t AgingPhotoAssets(shared_ptr<int> countPtr)
1418 {
1419     auto time = MediaFileUtils::UTCTimeMilliSeconds();
1420     DataSharePredicates predicates;
1421     predicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
1422     predicates.And()->LessThanOrEqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(time - AGING_TIME));
1423     int32_t ret = DeletePhotoAssets(predicates, true, false);
1424     if (ret < 0) {
1425         return ret;
1426     }
1427     if (countPtr != nullptr) {
1428         *countPtr = ret;
1429     }
1430     return E_OK;
1431 }
1432 
ObtainAlbumOrders(const int32_t & currentAlbumId,const int32_t referenceAlbumId,int32_t & currentAlbumOrder,int32_t & referenceAlbumOrder)1433 static int32_t ObtainAlbumOrders(const int32_t &currentAlbumId, const int32_t referenceAlbumId,
1434     int32_t &currentAlbumOrder, int32_t &referenceAlbumOrder)
1435 {
1436     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1437     if (uniStore == nullptr) {
1438         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1439         return E_HAS_DB_ERROR;
1440     }
1441     const std::string queryCurrentAlbumOrder = "SELECT " + PhotoAlbumColumns::ALBUM_ORDER + " FROM " +
1442         PhotoAlbumColumns::TABLE + " WHERE " + PhotoAlbumColumns::ALBUM_ID + " = " + to_string(currentAlbumId);
1443     const std::string queryReferenceAlbumOrder = "SELECT " + PhotoAlbumColumns::ALBUM_ORDER + " FROM " +
1444         PhotoAlbumColumns::TABLE + " WHERE " + PhotoAlbumColumns::ALBUM_ID + " = " + to_string(referenceAlbumId);
1445     auto resultSet = uniStore->QuerySql(queryCurrentAlbumOrder);
1446     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1447         return E_HAS_DB_ERROR;
1448     }
1449     int colIndex = -1;
1450     resultSet->GetColumnIndex(PhotoAlbumColumns::ALBUM_ORDER, colIndex);
1451     if (resultSet->GetInt(colIndex, currentAlbumOrder) != NativeRdb::E_OK) {
1452         return E_HAS_DB_ERROR;
1453     }
1454     resultSet = uniStore->QuerySql(queryReferenceAlbumOrder);
1455     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK
1456         || resultSet->GetInt(colIndex, referenceAlbumOrder) != NativeRdb::E_OK) {
1457         return E_HAS_DB_ERROR;
1458     }
1459     return E_OK;
1460 }
1461 
ExecSqls(const vector<string> & sqls,const shared_ptr<MediaLibraryRdbStore> store)1462 static int32_t ExecSqls(const vector<string> &sqls, const shared_ptr<MediaLibraryRdbStore> store)
1463 {
1464     int32_t err = NativeRdb::E_OK;
1465     for (const auto &sql : sqls) {
1466         err = store->ExecuteSql(sql);
1467         if (err != NativeRdb::E_OK) {
1468             MEDIA_ERR_LOG("Failed to exec: %{private}s", sql.c_str());
1469             break;
1470         }
1471     }
1472     return NativeRdb::E_OK;
1473 }
1474 
ObtainNotifyAlbumIds(int32_t & currentAlbumOrder,int32_t referenceAlbumOrder,vector<int32_t> & changedAlbumIds)1475 static int32_t ObtainNotifyAlbumIds(int32_t &currentAlbumOrder, int32_t referenceAlbumOrder,
1476     vector<int32_t> &changedAlbumIds)
1477 {
1478     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1479     if (uniStore == nullptr) {
1480         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1481         return E_DB_FAIL;
1482     }
1483     std::string queryAlbumIds = "";
1484     if (currentAlbumOrder < referenceAlbumOrder) {
1485         queryAlbumIds = "SELECT " + PhotoAlbumColumns::ALBUM_ID + " FROM " +
1486             PhotoAlbumColumns::TABLE + " WHERE " + PhotoAlbumColumns::ALBUM_ORDER + " >= " +
1487             to_string(currentAlbumOrder) + " AND " + PhotoAlbumColumns::ALBUM_ORDER +
1488             " < " + to_string(referenceAlbumOrder);
1489     } else {
1490         queryAlbumIds = "SELECT " + PhotoAlbumColumns::ALBUM_ID + " FROM " +
1491             PhotoAlbumColumns::TABLE + " WHERE " + PhotoAlbumColumns::ALBUM_ORDER + " >= " +
1492             to_string(referenceAlbumOrder) + " AND " + PhotoAlbumColumns::ALBUM_ORDER +
1493             " <= " + to_string(currentAlbumOrder);
1494     }
1495     auto resultSet = uniStore->QuerySql(queryAlbumIds);
1496     if (resultSet == nullptr) {
1497         return E_DB_FAIL;
1498     }
1499     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1500         changedAlbumIds.push_back(GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet));
1501     }
1502     return E_OK;
1503 }
1504 
NotifyOrderChange(vector<int32_t> & changedAlbumIds)1505 static void NotifyOrderChange(vector<int32_t> &changedAlbumIds)
1506 {
1507     if (changedAlbumIds.size() <= 0) {
1508         return;
1509     }
1510     auto watch = MediaLibraryNotify::GetInstance();
1511     CHECK_AND_RETURN_LOG(watch != nullptr, "Can not get MediaLibraryNotify Instance");
1512     for (int32_t &albumId : changedAlbumIds) {
1513         watch->Notify(MediaFileUtils::GetUriByExtrConditions(
1514             PhotoAlbumColumns::ALBUM_URI_PREFIX, to_string(albumId)), NotifyType::NOTIFY_UPDATE);
1515     }
1516 }
1517 
UpdateSortedOrder(const int32_t & currentAlbumId,const int32_t referenceAlbumId,int32_t & currentAlbumOrder,int32_t & referenceAlbumOrder)1518 static int32_t UpdateSortedOrder(const int32_t &currentAlbumId, const int32_t referenceAlbumId,
1519     int32_t &currentAlbumOrder, int32_t &referenceAlbumOrder)
1520 {
1521     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1522     if (uniStore == nullptr) {
1523         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1524         return E_DB_FAIL;
1525     }
1526     std::string updateOtherAlbumOrder = "";
1527     std::string updateCurrentAlbumOrder = "";
1528     if (currentAlbumOrder < referenceAlbumOrder) {
1529         updateOtherAlbumOrder = "UPDATE " + PhotoAlbumColumns::TABLE +
1530             " SET " + PhotoAlbumColumns::ALBUM_ORDER + " = " +
1531             PhotoAlbumColumns::ALBUM_ORDER + " -1 WHERE " + PhotoAlbumColumns::ALBUM_ORDER +
1532             " > " + to_string(currentAlbumOrder) +
1533             " and " + PhotoAlbumColumns::ALBUM_ORDER + " < " + to_string(referenceAlbumOrder);
1534         updateCurrentAlbumOrder = "UPDATE " + PhotoAlbumColumns::TABLE + " SET " + PhotoAlbumColumns::ALBUM_ORDER +
1535             " = " + to_string(referenceAlbumOrder) + " -1 WHERE " +
1536             PhotoAlbumColumns::ALBUM_ID + " = " + to_string(currentAlbumId);
1537     } else {
1538         updateOtherAlbumOrder = "UPDATE " + PhotoAlbumColumns::TABLE +
1539             " SET " + PhotoAlbumColumns::ALBUM_ORDER + " = " +
1540             PhotoAlbumColumns::ALBUM_ORDER + " +1 WHERE " + PhotoAlbumColumns::ALBUM_ORDER + " >= " +
1541             to_string(referenceAlbumOrder) + " AND " + PhotoAlbumColumns::ALBUM_ORDER +
1542             " < " + to_string(currentAlbumOrder);
1543         updateCurrentAlbumOrder = "UPDATE " + PhotoAlbumColumns::TABLE +
1544             " SET " + PhotoAlbumColumns::ALBUM_ORDER + " = " +
1545             to_string(referenceAlbumOrder) + " WHERE " +
1546             PhotoAlbumColumns::ALBUM_ID + " = " + to_string(currentAlbumId);
1547     }
1548     vector<string> updateSortedAlbumsSqls = { updateOtherAlbumOrder, updateCurrentAlbumOrder};
1549     return ExecSqls(updateSortedAlbumsSqls, uniStore);
1550 }
1551 
ObtainCurrentAlbumOrder(const int32_t & albumId,int32_t & albumOrder)1552 static int32_t ObtainCurrentAlbumOrder(const int32_t &albumId, int32_t &albumOrder)
1553 {
1554     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1555     if (uniStore == nullptr) {
1556         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1557         return E_HAS_DB_ERROR;
1558     }
1559     const std::string queryAlbumOrder = "SELECT " + PhotoAlbumColumns::ALBUM_ORDER + " FROM " +
1560         PhotoAlbumColumns::TABLE + " WHERE " + PhotoAlbumColumns::ALBUM_ID + " = " + to_string(albumId);
1561     auto resultSet = uniStore->QuerySql(queryAlbumOrder);
1562     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1563         return E_HAS_DB_ERROR;
1564     }
1565     int colIndex = -1;
1566     resultSet->GetColumnIndex(PhotoAlbumColumns::ALBUM_ORDER, colIndex);
1567     if (resultSet->GetInt(colIndex, albumOrder) != NativeRdb::E_OK) {
1568         return E_HAS_DB_ERROR;
1569     }
1570     return E_OK;
1571 }
1572 
UpdateNullReferenceOrder(const int32_t & currentAlbumId,const int32_t & currentAlbumOrder,const int32_t & maxAlbumOrder)1573 static int32_t UpdateNullReferenceOrder(const int32_t &currentAlbumId,
1574     const int32_t &currentAlbumOrder, const int32_t &maxAlbumOrder)
1575 {
1576     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1577     if (uniStore == nullptr) {
1578         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1579         return E_DB_FAIL;
1580     }
1581     std::string updateOtherAlbumOrder = "UPDATE " + PhotoAlbumColumns::TABLE + " SET " +
1582         PhotoAlbumColumns::ALBUM_ORDER + " = " + PhotoAlbumColumns::ALBUM_ORDER + " -1 WHERE " +
1583         PhotoAlbumColumns::ALBUM_ORDER + " > " + to_string(currentAlbumOrder) + " and " +
1584         PhotoAlbumColumns::ALBUM_ORDER + " <= " + to_string(maxAlbumOrder);
1585     std::string updateCurrentAlbumOrder = "UPDATE " + PhotoAlbumColumns::TABLE +
1586         " SET " + PhotoAlbumColumns::ALBUM_ORDER + " = " + to_string(maxAlbumOrder) +
1587         " WHERE " + PhotoAlbumColumns::ALBUM_ID + " = " + to_string(currentAlbumId);
1588     vector<string> updateSortedAlbumsSqls = { updateOtherAlbumOrder, updateCurrentAlbumOrder};
1589     return ExecSqls(updateSortedAlbumsSqls, uniStore);
1590 }
1591 
HandleNullReferenceCondition(const int32_t & currentAlbumId)1592 static int32_t HandleNullReferenceCondition(const int32_t &currentAlbumId)
1593 {
1594     int32_t maxAlbumOrder = 0;
1595     int err = ObtainMaxAlbumOrder(maxAlbumOrder);
1596     if (err != E_OK) {
1597         return E_HAS_DB_ERROR;
1598     }
1599     int32_t currentAlbumOrder = -1;
1600     err = ObtainCurrentAlbumOrder(currentAlbumId, currentAlbumOrder);
1601     if (err != E_OK) {
1602         return err;
1603     }
1604     vector<int32_t> changedAlbumIds;
1605     ObtainNotifyAlbumIds(currentAlbumOrder, maxAlbumOrder + 1, changedAlbumIds); // 1: move order curosr to the end
1606     err = UpdateNullReferenceOrder(currentAlbumId, currentAlbumOrder, maxAlbumOrder);
1607     if (err == E_OK) {
1608         NotifyOrderChange(changedAlbumIds);
1609     }
1610     return err;
1611 }
1612 
UpdatePortraitNullReferenceOrder(const int32_t currentAlbumId,const int32_t currentAlbumOrder,const int32_t maxAlbumOrder)1613 static int32_t UpdatePortraitNullReferenceOrder(const int32_t currentAlbumId,
1614     const int32_t currentAlbumOrder, const int32_t maxAlbumOrder)
1615 {
1616     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1617     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_DB_FAIL, "uniStore is nullptr! failed query album order");
1618     std::string updateOtherAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " +
1619         RANK + " = " + RANK + " -1 WHERE " +
1620         RANK + " > " + to_string(currentAlbumOrder) + " and " +
1621         RANK + " <= " + to_string(maxAlbumOrder);
1622     std::string updateCurrentAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE +
1623         " SET " + RANK + " = " + to_string(maxAlbumOrder) +
1624         " WHERE " + GROUP_TAG + " IN (SELECT " + GROUP_TAG + " FROM " + ANALYSIS_ALBUM_TABLE +
1625         " WHERE " + ALBUM_ID + " = " + to_string(currentAlbumId) + ")";
1626     vector<string> updateSortedAlbumsSqls = { updateOtherAlbumOrder, updateCurrentAlbumOrder };
1627     return ExecSqls(updateSortedAlbumsSqls, uniStore);
1628 }
1629 
ObtainNotifyPortraitAlbumIds(const int32_t currentAlbumOrder,const int32_t referenceAlbumOrder,vector<int32_t> & changedAlbumIds)1630 static int32_t ObtainNotifyPortraitAlbumIds(const int32_t currentAlbumOrder, const int32_t referenceAlbumOrder,
1631     vector<int32_t> &changedAlbumIds)
1632 {
1633     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1634     if (uniStore == nullptr) {
1635         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1636         return E_DB_FAIL;
1637     }
1638     std::string queryAlbumIds = "";
1639     if (currentAlbumOrder < referenceAlbumOrder) {
1640         queryAlbumIds = "SELECT " + ALBUM_ID + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + RANK + " >= " +
1641             to_string(currentAlbumOrder) + " AND " + RANK + " < " + to_string(referenceAlbumOrder);
1642     } else {
1643         queryAlbumIds = "SELECT " + ALBUM_ID + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + RANK + " >= " +
1644             to_string(referenceAlbumOrder) + " AND " + RANK + " <= " + to_string(currentAlbumOrder);
1645     }
1646     auto resultSet = uniStore->QuerySql(queryAlbumIds);
1647     if (resultSet == nullptr) {
1648         return E_DB_FAIL;
1649     }
1650     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1651         changedAlbumIds.push_back(GetInt32Val(ALBUM_ID, resultSet));
1652     }
1653     return E_OK;
1654 }
1655 
ObtainCurrentPortraitAlbumOrder(const int32_t albumId,int32_t & albumOrder)1656 static int32_t ObtainCurrentPortraitAlbumOrder(const int32_t albumId, int32_t &albumOrder)
1657 {
1658     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1659     if (uniStore == nullptr) {
1660         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1661         return E_HAS_DB_ERROR;
1662     }
1663     const std::string queryAlbumOrder = "SELECT " + RANK + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " +
1664         PhotoAlbumColumns::ALBUM_ID + " = " + to_string(albumId);
1665     auto resultSet = uniStore->QuerySql(queryAlbumOrder);
1666     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1667         return E_HAS_DB_ERROR;
1668     }
1669     return GetIntValueFromResultSet(resultSet, RANK, albumOrder);
1670 }
1671 
ObtainMaxPortraitAlbumOrder(int32_t & maxAlbumOrder)1672 static int32_t ObtainMaxPortraitAlbumOrder(int32_t &maxAlbumOrder)
1673 {
1674     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1675     if (uniStore == nullptr) {
1676         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1677         return -E_HAS_DB_ERROR;
1678     }
1679     std::string queryMaxOrderSql = "SELECT Max(rank) FROM " + ANALYSIS_ALBUM_TABLE;
1680     auto resultSet = uniStore->QuerySql(queryMaxOrderSql);
1681     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1682         MEDIA_ERR_LOG("Failed to query album!");
1683         return -E_HAS_DB_ERROR;
1684     }
1685 
1686     return resultSet->GetInt(0, maxAlbumOrder);
1687 }
1688 
HandlePortraitNullReferenceCondition(const int32_t currentAlbumId)1689 static int32_t HandlePortraitNullReferenceCondition(const int32_t currentAlbumId)
1690 {
1691     int32_t maxAlbumOrder = 0;
1692     int err = ObtainMaxPortraitAlbumOrder(maxAlbumOrder);
1693     CHECK_AND_RETURN_RET(err == E_OK, E_HAS_DB_ERROR);
1694     int32_t currentAlbumOrder = -1;
1695     err = ObtainCurrentPortraitAlbumOrder(currentAlbumId, currentAlbumOrder);
1696     CHECK_AND_RETURN_RET(err == E_OK, err);
1697 
1698     vector<int32_t> changedAlbumIds;
1699      // move order curosr to the end
1700     ObtainNotifyPortraitAlbumIds(currentAlbumOrder, maxAlbumOrder + 1, changedAlbumIds);
1701     err = UpdatePortraitNullReferenceOrder(currentAlbumId, currentAlbumOrder, maxAlbumOrder);
1702     if (err == E_OK) {
1703         NotifyPortraitAlbum(changedAlbumIds);
1704     }
1705     return err;
1706 }
1707 
ObtainPortraitAlbumOrders(const int32_t currentAlbumId,const int32_t referenceAlbumId,int32_t & currentAlbumOrder,int32_t & referenceAlbumOrder)1708 static int32_t ObtainPortraitAlbumOrders(const int32_t currentAlbumId, const int32_t referenceAlbumId,
1709     int32_t &currentAlbumOrder, int32_t &referenceAlbumOrder)
1710 {
1711     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1712     if (uniStore == nullptr) {
1713         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1714         return E_HAS_DB_ERROR;
1715     }
1716     const std::string queryCurrentAlbumOrder = "SELECT " + RANK + " FROM " +
1717         ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID + " = " + to_string(currentAlbumId);
1718     auto resultSet = uniStore->QuerySql(queryCurrentAlbumOrder);
1719     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1720         return E_HAS_DB_ERROR;
1721     }
1722     if (GetIntValueFromResultSet(resultSet, RANK, currentAlbumOrder) != NativeRdb::E_OK) {
1723         return E_HAS_DB_ERROR;
1724     }
1725 
1726     const std::string queryReferenceAlbumOrder = "SELECT " + RANK + " FROM " +
1727         ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID + " = " + to_string(referenceAlbumId);
1728     resultSet = uniStore->QuerySql(queryReferenceAlbumOrder);
1729     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1730         return E_HAS_DB_ERROR;
1731     }
1732     if (GetIntValueFromResultSet(resultSet, RANK, referenceAlbumOrder) != NativeRdb::E_OK) {
1733         return E_HAS_DB_ERROR;
1734     }
1735     return E_OK;
1736 }
1737 
UpdatePortraitSortedOrder(const int32_t currentAlbumId,const int32_t referenceAlbumId,const int32_t currentAlbumOrder,const int32_t referenceAlbumOrder)1738 static int32_t UpdatePortraitSortedOrder(const int32_t currentAlbumId, const int32_t referenceAlbumId,
1739     const int32_t currentAlbumOrder, const int32_t referenceAlbumOrder)
1740 {
1741     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1742     if (uniStore == nullptr) {
1743         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1744         return E_DB_FAIL;
1745     }
1746     std::string updateOtherAlbumOrder = "";
1747     std::string updateCurrentAlbumOrder = "";
1748     if (currentAlbumOrder < referenceAlbumOrder) {
1749         updateOtherAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + RANK + " = " + RANK + " -1 WHERE " +
1750             RANK + " > " + to_string(currentAlbumOrder) + " and " + RANK + " < " + to_string(referenceAlbumOrder);
1751         updateCurrentAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + RANK + " = " +
1752             to_string(referenceAlbumOrder) + " -1 WHERE " + GROUP_TAG + " IN (SELECT " + GROUP_TAG + " FROM " +
1753             ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID + " = " + to_string(currentAlbumId) + ")";
1754     } else {
1755         updateOtherAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + RANK + " = " + RANK + " +1 WHERE " +
1756             RANK + " >= " + to_string(referenceAlbumOrder) + " AND " + RANK + " < " + to_string(currentAlbumOrder);
1757         updateCurrentAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + RANK + " = " +
1758             to_string(referenceAlbumOrder) + " WHERE " + GROUP_TAG + " IN (SELECT " + GROUP_TAG + " FROM " +
1759             ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID + " = " + to_string(currentAlbumId) + ")";
1760     }
1761     vector<string> updateSortedAlbumsSqls = { updateOtherAlbumOrder, updateCurrentAlbumOrder};
1762     return ExecSqls(updateSortedAlbumsSqls, uniStore);
1763 }
1764 
CheckIsFavoritePortraitAlbum(const int32_t currentAlbumId,const int32_t referenceAlbumId)1765 bool CheckIsFavoritePortraitAlbum(const int32_t currentAlbumId, const int32_t referenceAlbumId)
1766 {
1767     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1768     if (uniStore == nullptr) {
1769         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1770         return false;
1771     }
1772     std::string queryDisplayLevel = "SELECT " + USER_DISPLAY_LEVEL + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " +
1773         ALBUM_ID + " IN (" + to_string(currentAlbumId) + "," + to_string(referenceAlbumId) + ")";
1774     auto resultSet = uniStore->QuerySql(queryDisplayLevel);
1775     if (resultSet == nullptr) {
1776         MEDIA_ERR_LOG("Failed to query display level!");
1777         return false;
1778     }
1779     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1780         int32_t displayLevel;
1781         if (GetIntValueFromResultSet(resultSet, USER_DISPLAY_LEVEL, displayLevel) != E_OK) {
1782             MEDIA_ERR_LOG("Get display level fail");
1783             return false;
1784         }
1785         if (displayLevel != FAVORITE_PAGE) {
1786             MEDIA_ERR_LOG("this album is not favorite portrait album");
1787             return false;
1788         }
1789     }
1790     return true;
1791 }
1792 
OrderPortraitFavoriteAlbum(const int32_t currentAlbumId,const int32_t referenceAlbumId)1793 int32_t OrderPortraitFavoriteAlbum(const int32_t currentAlbumId, const int32_t referenceAlbumId)
1794 {
1795     if (!CheckIsFavoritePortraitAlbum(currentAlbumId, referenceAlbumId)) {
1796         return E_INVALID_VALUES;
1797     }
1798     if (referenceAlbumId == NULL_REFERENCE_ALBUM_ID) {
1799         return HandlePortraitNullReferenceCondition(currentAlbumId);
1800     }
1801 
1802     int32_t currentAlbumOrder = -1; // -1: default invalid value
1803     int32_t referenceAlbumOrder = -1; // -1: default invalid value
1804     int err = ObtainPortraitAlbumOrders(currentAlbumId, referenceAlbumId, currentAlbumOrder, referenceAlbumOrder);
1805     if (err != E_OK) {
1806         MEDIA_ERR_LOG("obtains album order error");
1807         return err;
1808     }
1809     vector<int32_t> changedAlbumIds;
1810     ObtainNotifyPortraitAlbumIds(currentAlbumOrder, referenceAlbumOrder, changedAlbumIds);
1811     err = UpdatePortraitSortedOrder(currentAlbumId, referenceAlbumId, currentAlbumOrder, referenceAlbumOrder);
1812     if (err == E_OK) {
1813         NotifyPortraitAlbum(changedAlbumIds);
1814     }
1815     return E_OK;
1816 }
1817 
1818 /**
1819  * Place the current album before the reference album
1820  * @param values contains current and reference album_id
1821  */
OrderSingleAlbum(const ValuesBucket & values)1822 int32_t OrderSingleAlbum(const ValuesBucket &values)
1823 {
1824     int32_t currentAlbumId;
1825     int32_t referenceAlbumId;
1826     int err = GetIntVal(values, PhotoAlbumColumns::ALBUM_ID, currentAlbumId);
1827     if (err < 0 || currentAlbumId <= 0) {
1828         MEDIA_ERR_LOG("invalid album id");
1829         return E_INVALID_VALUES;
1830     }
1831     err = GetIntVal(values, PhotoAlbumColumns::REFERENCE_ALBUM_ID, referenceAlbumId);
1832     if (err < 0 || referenceAlbumId == 0 || referenceAlbumId < NULL_REFERENCE_ALBUM_ID) {
1833         MEDIA_ERR_LOG("invalid reference album id");
1834         return E_INVALID_VALUES;
1835     }
1836     if (currentAlbumId == referenceAlbumId) { // same album, no need to order
1837         return E_OK;
1838     }
1839 
1840     int32_t albumType;
1841     int32_t albumSubtype;
1842     err = GetIntVal(values, PhotoAlbumColumns::ALBUM_TYPE, albumType);
1843     int errorSubtype = GetIntVal(values, PhotoAlbumColumns::ALBUM_SUBTYPE, albumSubtype);
1844     if (err == E_OK && errorSubtype == E_OK && (albumType == PhotoAlbumType::SMART && albumSubtype == PORTRAIT)) {
1845         return OrderPortraitFavoriteAlbum(currentAlbumId, referenceAlbumId);
1846     }
1847     if (referenceAlbumId == NULL_REFERENCE_ALBUM_ID) {
1848         return HandleNullReferenceCondition(currentAlbumId);
1849     }
1850     int32_t currentAlbumOrder = -1; // -1: default invalid value
1851     int32_t referenceAlbumOrder = -1;
1852     err = ObtainAlbumOrders(currentAlbumId, referenceAlbumId, currentAlbumOrder, referenceAlbumOrder);
1853     if (err != E_OK) {
1854         MEDIA_ERR_LOG("obtains album order error");
1855         return err;
1856     }
1857     vector<int32_t> changedAlbumIds;
1858     ObtainNotifyAlbumIds(currentAlbumOrder, referenceAlbumOrder, changedAlbumIds);
1859     err = UpdateSortedOrder(currentAlbumId, referenceAlbumId, currentAlbumOrder, referenceAlbumOrder);
1860     if (err == E_OK) {
1861         NotifyOrderChange(changedAlbumIds);
1862     }
1863     return E_OK;
1864 }
1865 
GetStringVal(const ValuesBucket & values,const string & key,string & value)1866 inline int32_t GetStringVal(const ValuesBucket &values, const string &key, string &value)
1867 {
1868     value = "";
1869     ValueObject valueObject;
1870     if (values.GetObject(key, valueObject)) {
1871         valueObject.GetString(value);
1872     } else {
1873         return -EINVAL;
1874     }
1875     return E_OK;
1876 }
1877 
GetMergeAlbumCount(const int32_t currentAlbumId,const int32_t targetAlbumId)1878 int GetMergeAlbumCount(const int32_t currentAlbumId, const int32_t targetAlbumId)
1879 {
1880     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1881     if (uniStore == nullptr) {
1882         MEDIA_ERR_LOG("uniStore is nullptr! failed query merge album info");
1883         return E_DB_FAIL;
1884     }
1885 
1886     string queryCount = "SELECT COUNT(DISTINCT file_id) FROM " + PhotoColumn::PHOTOS_TABLE + " p INNER JOIN " +
1887         ANALYSIS_PHOTO_MAP_TABLE + " apm ON p." + PhotoColumn::MEDIA_ID + " = apm." + MAP_ASSET + " INNER JOIN " +
1888         ANALYSIS_ALBUM_TABLE + " aa ON aa." + ALBUM_ID + " = apm." + MAP_ALBUM + " INNER JOIN (SELECT " + GROUP_TAG +
1889         " FROM "+ ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID + " IN (" + to_string(currentAlbumId) + "," +
1890         to_string(targetAlbumId) + ")) ag ON ag." + GROUP_TAG + " = " + " aa." + GROUP_TAG + " WHERE " +
1891         PhotoColumn::MEDIA_DATE_TRASHED + " = 0 AND " + PhotoColumn::MEDIA_TIME_PENDING + " = 0 AND " +
1892         PhotoColumn::MEDIA_HIDDEN + " = 0";
1893     auto resultSet = uniStore->QuerySql(queryCount);
1894     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1895         MEDIA_ERR_LOG("Failed to query album!");
1896         return E_HAS_DB_ERROR;
1897     }
1898     int count;
1899     if (resultSet->GetInt(0, count) != E_OK) {
1900         return E_HAS_DB_ERROR;
1901     }
1902     return count;
1903 }
1904 
ParseFileIdFromCoverUri(const string & uri)1905 string ParseFileIdFromCoverUri(const string &uri)
1906 {
1907     if (PhotoColumn::PHOTO_URI_PREFIX.size() >= uri.size()) {
1908         return "";
1909     }
1910     string midStr = uri.substr(PhotoColumn::PHOTO_URI_PREFIX.size());
1911     string delimiter = "/";
1912     size_t pos = midStr.find(delimiter);
1913     if (pos == string::npos) {
1914         MEDIA_ERR_LOG("ParseFileIdFromCoverUri fail");
1915         return "";
1916     }
1917     return midStr.substr(0, pos);
1918 }
1919 
UpdateForReduceOneOrder(const int32_t referenceOrder)1920 static int32_t UpdateForReduceOneOrder(const int32_t referenceOrder)
1921 {
1922     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1923     if (uniStore == nullptr) {
1924         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
1925         return E_DB_FAIL;
1926     }
1927     std::string updateOtherAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + RANK + " = " + RANK +
1928         " -1 WHERE " + RANK + " > " + to_string(referenceOrder);
1929     vector<string> updateSortedAlbumsSqls = { updateOtherAlbumOrder};
1930     return ExecSqls(updateSortedAlbumsSqls, uniStore);
1931 }
1932 
UpdateForMergeAlbums(const MergeAlbumInfo & updateAlbumInfo,const int32_t currentAlbumId,const int32_t targetAlbumId)1933 int32_t UpdateForMergeAlbums(const MergeAlbumInfo &updateAlbumInfo, const int32_t currentAlbumId,
1934     const int32_t targetAlbumId)
1935 {
1936     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1937     if (uniStore == nullptr) {
1938         MEDIA_ERR_LOG("uniStore is nullptr! failed update for merge albums");
1939         return E_DB_FAIL;
1940     }
1941 
1942     std::string updateForMergeAlbums = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + GROUP_TAG + " = " +
1943         updateAlbumInfo.groupTag + "," + COUNT + " = " + to_string(updateAlbumInfo.count) + "," + IS_ME + " = " +
1944         to_string(updateAlbumInfo.isMe) + "," + COVER_URI + " = '" + updateAlbumInfo.coverUri + "'," +
1945         USER_DISPLAY_LEVEL + " = " + to_string(updateAlbumInfo.userDisplayLevel) + "," + RANK + " = " +
1946         to_string(updateAlbumInfo.rank) + "," + USER_OPERATION + " = " + to_string(updateAlbumInfo.userOperation) +
1947         "," + RENAME_OPERATION + " = " + to_string(updateAlbumInfo.renameOperation) + "," + ALBUM_NAME + " = '" +
1948         updateAlbumInfo.albumName + "'," + IS_COVER_SATISFIED + " = " + to_string(updateAlbumInfo.isCoverSatisfied) +
1949         " WHERE " + GROUP_TAG + " IN(SELECT " + GROUP_TAG + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID +
1950         " = " + to_string(currentAlbumId) + " OR " + ALBUM_ID + " = " + to_string(targetAlbumId) + ")";
1951     vector<string> updateSqls = { updateForMergeAlbums};
1952     return ExecSqls(updateSqls, uniStore);
1953 }
1954 
GetMergeAlbumsInfo(vector<MergeAlbumInfo> & mergeAlbumInfo,const int32_t currentAlbumId,const int32_t targetAlbumId)1955 int32_t GetMergeAlbumsInfo(vector<MergeAlbumInfo> &mergeAlbumInfo, const int32_t currentAlbumId,
1956     const int32_t targetAlbumId)
1957 {
1958     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1959     if (uniStore == nullptr) {
1960         MEDIA_ERR_LOG("uniStore is nullptr! failed query merge album info");
1961         return E_DB_FAIL;
1962     }
1963     const std::string queryAlbumInfo = "SELECT " + ALBUM_ID + "," + GROUP_TAG + "," + COUNT + "," + IS_ME + "," +
1964         COVER_URI + "," + USER_DISPLAY_LEVEL + "," + RANK + "," + USER_OPERATION + "," + RENAME_OPERATION + "," +
1965         ALBUM_NAME + "," + IS_COVER_SATISFIED + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID + " = " +
1966         to_string(currentAlbumId) + " OR " + ALBUM_ID + " = " + to_string(targetAlbumId);
1967 
1968     auto resultSet = uniStore->QuerySql(queryAlbumInfo);
1969     if (resultSet == nullptr) {
1970         MEDIA_ERR_LOG("Database query failed");
1971         return E_HAS_DB_ERROR;
1972     }
1973     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1974         MergeAlbumInfo albumInfo;
1975         int isCoverSatisfied = 0;
1976         if (GetIntValueFromResultSet(resultSet, ALBUM_ID, albumInfo.albumId) != E_OK ||
1977             GetStringValueFromResultSet(resultSet, GROUP_TAG, albumInfo.groupTag) != E_OK ||
1978             GetIntValueFromResultSet(resultSet, COUNT, albumInfo.count) != E_OK ||
1979             GetIntValueFromResultSet(resultSet, IS_ME, albumInfo.isMe) != E_OK ||
1980             GetStringValueFromResultSet(resultSet, GROUP_TAG, albumInfo.groupTag) != E_OK ||
1981             GetStringValueFromResultSet(resultSet, COVER_URI, albumInfo.coverUri) != E_OK ||
1982             GetIntValueFromResultSet(resultSet, USER_DISPLAY_LEVEL, albumInfo.userDisplayLevel) != E_OK ||
1983             GetIntValueFromResultSet(resultSet, RANK, albumInfo.rank) != E_OK ||
1984             GetIntValueFromResultSet(resultSet, RENAME_OPERATION, albumInfo.renameOperation) != E_OK ||
1985             GetStringValueFromResultSet(resultSet, ALBUM_NAME, albumInfo.albumName) != E_OK ||
1986             GetIntValueFromResultSet(resultSet, IS_COVER_SATISFIED, isCoverSatisfied) != E_OK) {
1987                 MEDIA_ERR_LOG("Failed to get values from result set");
1988                 return E_HAS_DB_ERROR;
1989             }
1990         albumInfo.isCoverSatisfied = static_cast<uint8_t>(isCoverSatisfied);
1991         mergeAlbumInfo.push_back(albumInfo);
1992     }
1993     return E_OK;
1994 }
1995 
JoinCandidateIds(const vector<string> & candidateIds)1996 inline string JoinCandidateIds(const vector<string> &candidateIds)
1997 {
1998     return accumulate(candidateIds.begin() + 1, candidateIds.end(), candidateIds[0],
1999         [](const string &a, const string &b) { return a + ", " + b; });
2000 }
2001 
GetCandidateIdsAndSetCoverSatisfied(MergeAlbumInfo & updateAlbumInfo,const MergeAlbumInfo & currentAlbum,const MergeAlbumInfo & targetAlbum,const string & currentFileId,const string & targetFileId)2002 string GetCandidateIdsAndSetCoverSatisfied(MergeAlbumInfo &updateAlbumInfo, const MergeAlbumInfo &currentAlbum,
2003     const MergeAlbumInfo &targetAlbum, const string &currentFileId, const string &targetFileId)
2004 {
2005     vector<string> candidateIds;
2006     if (currentAlbum.isCoverSatisfied & static_cast<uint8_t>(CoverSatisfiedType::USER_SETTING)) {
2007         candidateIds.push_back(currentFileId);
2008     }
2009     if (targetAlbum.isCoverSatisfied & static_cast<uint8_t>(CoverSatisfiedType::USER_SETTING)) {
2010         candidateIds.push_back(targetFileId);
2011     }
2012     if (!candidateIds.empty()) {
2013         updateAlbumInfo.isCoverSatisfied = static_cast<uint8_t>(CoverSatisfiedType::USER_SETTING_EDITE);
2014         return JoinCandidateIds(candidateIds);
2015     }
2016 
2017     if (currentAlbum.isCoverSatisfied & static_cast<uint8_t>(CoverSatisfiedType::BEAUTY_SETTING)) {
2018         candidateIds.push_back(currentFileId);
2019     }
2020     if (targetAlbum.isCoverSatisfied & static_cast<uint8_t>(CoverSatisfiedType::BEAUTY_SETTING)) {
2021         candidateIds.push_back(targetFileId);
2022     }
2023     if (!candidateIds.empty()) {
2024         updateAlbumInfo.isCoverSatisfied = static_cast<uint8_t>(CoverSatisfiedType::BEAUTY_SETTING_EDITE);
2025         return JoinCandidateIds(candidateIds);
2026     }
2027 
2028     if (currentAlbum.isCoverSatisfied & static_cast<uint8_t>(CoverSatisfiedType::DEFAULT_SETTING)) {
2029         candidateIds.push_back(currentFileId);
2030     }
2031     if (targetAlbum.isCoverSatisfied & static_cast<uint8_t>(CoverSatisfiedType::DEFAULT_SETTING)) {
2032         candidateIds.push_back(targetFileId);
2033     }
2034     if (!candidateIds.empty()) {
2035         updateAlbumInfo.isCoverSatisfied = static_cast<uint8_t>(CoverSatisfiedType::DEFAULT_SETTING);
2036         return JoinCandidateIds(candidateIds);
2037     }
2038 
2039     updateAlbumInfo.isCoverSatisfied = static_cast<uint8_t>(CoverSatisfiedType::DEFAULT_SETTING);
2040     return currentFileId + ", " + targetFileId;
2041 }
2042 
GetMergeAlbumCoverUriAndSatisfied(MergeAlbumInfo & updateAlbumInfo,const MergeAlbumInfo & currentAlbum,const MergeAlbumInfo & targetAlbum)2043 int32_t GetMergeAlbumCoverUriAndSatisfied(MergeAlbumInfo &updateAlbumInfo, const MergeAlbumInfo &currentAlbum,
2044     const MergeAlbumInfo &targetAlbum)
2045 {
2046     string currentFileId = ParseFileIdFromCoverUri(currentAlbum.coverUri);
2047     string targetFileId = ParseFileIdFromCoverUri(targetAlbum.coverUri);
2048     if (currentFileId.empty() || targetFileId.empty()) {
2049         return E_DB_FAIL;
2050     }
2051     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2052     if (uniStore == nullptr) {
2053         MEDIA_ERR_LOG("uniStore is nullptr! failed query get merge album cover uri");
2054         return E_DB_FAIL;
2055     }
2056     string candidateIds =
2057         GetCandidateIdsAndSetCoverSatisfied(updateAlbumInfo, currentAlbum, targetAlbum, currentFileId, targetFileId);
2058 
2059     const std::string queryAlbumInfo = "SELECT " + MediaColumn::MEDIA_ID + "," + MediaColumn::MEDIA_TITLE + "," +
2060         MediaColumn::MEDIA_NAME + ", MAX(" + MediaColumn::MEDIA_DATE_ADDED + ") FROM " + PhotoColumn::PHOTOS_TABLE +
2061         " WHERE " + MediaColumn::MEDIA_ID + " IN (" + candidateIds + " )";
2062 
2063     auto resultSet = uniStore->QuerySql(queryAlbumInfo);
2064     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
2065         MEDIA_ERR_LOG("resultSet is nullptr! failed query get merge album cover uri");
2066         return E_HAS_DB_ERROR;
2067     }
2068     int mergeFileId;
2069     if (GetIntValueFromResultSet(resultSet, MediaColumn::MEDIA_ID, mergeFileId) != NativeRdb::E_OK) {
2070         MEDIA_ERR_LOG("resultSet is error! failed query get merge album cover uri");
2071         return E_HAS_DB_ERROR;
2072     }
2073 
2074     string mergeTitle;
2075     if (GetStringValueFromResultSet(resultSet, MediaColumn::MEDIA_TITLE, mergeTitle) != NativeRdb::E_OK) {
2076         MEDIA_ERR_LOG("resultSet is error! failed query get merge album cover uri");
2077         return E_HAS_DB_ERROR;
2078     }
2079 
2080     string mergeDisplayName;
2081     if (GetStringValueFromResultSet(resultSet, MediaColumn::MEDIA_NAME, mergeDisplayName) != NativeRdb::E_OK) {
2082         MEDIA_ERR_LOG("resultSet is error! failed query get merge album cover uri");
2083         return E_HAS_DB_ERROR;
2084     }
2085     updateAlbumInfo.coverUri = "file://media/Photo/" + to_string(mergeFileId) + "/" + mergeTitle + "/" +
2086         mergeDisplayName;
2087     return E_OK;
2088 }
2089 
MergeAlbumInfoToString(const MergeAlbumInfo & mergeAlbumInfo)2090 static string MergeAlbumInfoToString(const MergeAlbumInfo& mergeAlbumInfo)
2091 {
2092     string info = "album " + to_string(mergeAlbumInfo.albumId) + ", groupTag " + mergeAlbumInfo.groupTag + ", count " +
2093         to_string(mergeAlbumInfo.count) + ", isMe " + to_string(mergeAlbumInfo.isMe) + ", coverUri " +
2094         DfxUtils::GetSafeUri(mergeAlbumInfo.coverUri) + ", userDisplayLevel " +
2095         to_string(mergeAlbumInfo.userDisplayLevel) + ", rank " +
2096         to_string(mergeAlbumInfo.rank) + ", userOperation " + to_string(mergeAlbumInfo.userOperation) +
2097         ", renameOperation " + to_string(mergeAlbumInfo.renameOperation) + ", albumName " +
2098         DfxUtils::GetSafeAlbumName(mergeAlbumInfo.albumName) +
2099         ", isCoverSatisfied " + to_string(mergeAlbumInfo.isCoverSatisfied);
2100     return info;
2101 }
2102 
UpdateMergeAlbumsInfo(const vector<MergeAlbumInfo> & mergeAlbumInfo,int32_t currentAlbumId)2103 static int32_t UpdateMergeAlbumsInfo(const vector<MergeAlbumInfo> &mergeAlbumInfo, int32_t currentAlbumId)
2104 {
2105     MergeAlbumInfo updateAlbumInfo;
2106     if (GetMergeAlbumCoverUriAndSatisfied(updateAlbumInfo, mergeAlbumInfo[0], mergeAlbumInfo[1]) != E_OK) {
2107         return E_HAS_DB_ERROR;
2108     }
2109     updateAlbumInfo.count = GetMergeAlbumCount(mergeAlbumInfo[0].albumId, mergeAlbumInfo[1].albumId);
2110     updateAlbumInfo.groupTag = "'" + mergeAlbumInfo[0].groupTag + "|" + mergeAlbumInfo[1].groupTag + "'";
2111     updateAlbumInfo.isMe = (mergeAlbumInfo[0].isMe == 1 || mergeAlbumInfo[1].isMe == 1) ? 1 : 0;
2112     updateAlbumInfo.userOperation = 1;
2113     updateAlbumInfo.albumName =
2114         mergeAlbumInfo[0].albumId == currentAlbumId ? mergeAlbumInfo[0].albumName : mergeAlbumInfo[1].albumName;
2115     if (updateAlbumInfo.albumName == "") {
2116         updateAlbumInfo.albumName =
2117             mergeAlbumInfo[0].albumId != currentAlbumId ? mergeAlbumInfo[0].albumName : mergeAlbumInfo[1].albumName;
2118     }
2119     updateAlbumInfo.renameOperation =
2120         (mergeAlbumInfo[0].albumName != "" || mergeAlbumInfo[1].albumName != "") ? 1 : 0;
2121     int currentLevel = mergeAlbumInfo[0].userDisplayLevel;
2122     int targetLevel = mergeAlbumInfo[1].userDisplayLevel;
2123     if ((currentLevel == targetLevel) && (currentLevel == FIRST_PAGE || currentLevel == SECOND_PAGE ||
2124         currentLevel == UNFAVORITE_PAGE)) {
2125         updateAlbumInfo.userDisplayLevel = currentLevel;
2126         updateAlbumInfo.rank = 0;
2127     } else if ((currentLevel == targetLevel) && (currentLevel == FAVORITE_PAGE)) {
2128         updateAlbumInfo.userDisplayLevel = currentLevel;
2129         updateAlbumInfo.rank = min(mergeAlbumInfo[0].rank, mergeAlbumInfo[1].rank);
2130         if (UpdateForReduceOneOrder(max(mergeAlbumInfo[0].rank, mergeAlbumInfo[1].rank)) != E_OK) {
2131             return E_HAS_DB_ERROR;
2132         }
2133     } else if (currentLevel == FAVORITE_PAGE || targetLevel == FAVORITE_PAGE) {
2134         updateAlbumInfo.userDisplayLevel = FAVORITE_PAGE;
2135         updateAlbumInfo.rank = max(mergeAlbumInfo[0].rank, mergeAlbumInfo[1].rank);
2136     } else if (currentLevel == FIRST_PAGE || targetLevel == FIRST_PAGE) {
2137         updateAlbumInfo.userDisplayLevel = FIRST_PAGE;
2138         updateAlbumInfo.rank = 0;
2139     } else {
2140         updateAlbumInfo.userDisplayLevel = SECOND_PAGE;
2141         updateAlbumInfo.rank = 0;
2142     }
2143     MEDIA_INFO_LOG("After merge: %{public}s", MergeAlbumInfoToString(updateAlbumInfo).c_str());
2144     return UpdateForMergeAlbums(updateAlbumInfo, mergeAlbumInfo[0].albumId, mergeAlbumInfo[1].albumId);
2145 }
2146 
2147 /**
2148  * Merge album
2149  * @param values contains current and target album_id
2150  */
MergePortraitAlbums(const ValuesBucket & values)2151 static int32_t MergePortraitAlbums(const ValuesBucket &values)
2152 {
2153     int32_t currentAlbumId;
2154     int32_t targetAlbumId;
2155     int err = GetIntVal(values, ALBUM_ID, currentAlbumId);
2156     if (err < 0 || currentAlbumId <= 0) {
2157         MEDIA_ERR_LOG("invalid album id");
2158         return E_INVALID_VALUES;
2159     }
2160     err = GetIntVal(values, TARGET_ALBUM_ID, targetAlbumId);
2161     if (err < 0 || targetAlbumId <= 0) {
2162         MEDIA_ERR_LOG("invalid target album id");
2163         return E_INVALID_VALUES;
2164     }
2165     if (currentAlbumId == targetAlbumId) { // same album, no need to merge
2166         MEDIA_WARN_LOG("Ignore invalid portrait album merge request, "
2167             "current album id and target album id are the same");
2168         return E_OK;
2169     }
2170     MEDIA_INFO_LOG("Start merge portrait albums, current album id: %{public}d, target album id: %{public}d",
2171         currentAlbumId, targetAlbumId);
2172     vector<MergeAlbumInfo> mergeAlbumInfo;
2173     if (GetMergeAlbumsInfo(mergeAlbumInfo, currentAlbumId, targetAlbumId)) {
2174         MEDIA_ERR_LOG("Get merge albums info fail");
2175         return E_HAS_DB_ERROR;
2176     }
2177     if (mergeAlbumInfo.size() != MERGE_ALBUM_COUNT) { // merge album count
2178         MEDIA_ERR_LOG("invalid mergeAlbumInfo size");
2179         return E_INVALID_VALUES;
2180     }
2181     MEDIA_INFO_LOG("Before merge: %{public}s", MergeAlbumInfoToString(mergeAlbumInfo[0]).c_str());
2182     MEDIA_INFO_LOG("Before merge: %{public}s", MergeAlbumInfoToString(mergeAlbumInfo[1]).c_str());
2183     err = UpdateMergeAlbumsInfo(mergeAlbumInfo, currentAlbumId);
2184     if (err != E_OK) {
2185         MEDIA_ERR_LOG("MergeAlbum failed");
2186         return err;
2187     }
2188     err = MediaLibraryAnalysisAlbumOperations::UpdateMergeGroupAlbumsInfo(mergeAlbumInfo);
2189     if (err != E_OK) {
2190         MEDIA_ERR_LOG("MergeGroupAlbum failed");
2191         return err;
2192     }
2193     vector<int32_t> changeAlbumIds = { currentAlbumId };
2194     NotifyPortraitAlbum(changeAlbumIds);
2195     return err;
2196 }
2197 
UpdateDisplayLevel(const int32_t value,const int32_t albumId)2198 static int32_t UpdateDisplayLevel(const int32_t value, const int32_t albumId)
2199 {
2200     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2201     if (uniStore == nullptr) {
2202         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
2203         return E_DB_FAIL;
2204     }
2205     std::string updateDisplayLevel = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + USER_DISPLAY_LEVEL + " = " +
2206         to_string(value) + " WHERE " + GROUP_TAG + " IN (SELECT " + GROUP_TAG + " FROM " + ANALYSIS_ALBUM_TABLE +
2207         " WHERE " + ALBUM_ID + " = " + to_string(albumId) + ")";
2208     vector<string> updateDisplayLevelAlbumsSqls = { updateDisplayLevel };
2209     return ExecSqls(updateDisplayLevelAlbumsSqls, uniStore);
2210 }
2211 
UpdateFavoritesOrder(const int32_t value,const int32_t currentAlbumId)2212 static int32_t UpdateFavoritesOrder(const int32_t value, const int32_t currentAlbumId)
2213 {
2214     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2215     if (uniStore == nullptr) {
2216         MEDIA_ERR_LOG("uniStore is nullptr! failed query album order");
2217         return E_DB_FAIL;
2218     }
2219     std::string updateOtherAlbumOrder;
2220     std::string updateCurrentAlbumOrder;
2221     vector<string> updateSortedAlbumsSqls;
2222     if (value == FAVORITE_PAGE) {
2223         int maxAlbumOrder;
2224         ObtainMaxPortraitAlbumOrder(maxAlbumOrder);
2225         updateCurrentAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + RANK + " = " + to_string(maxAlbumOrder) +
2226             " +1 WHERE " + GROUP_TAG + " IN (SELECT " + GROUP_TAG + " FROM " + ANALYSIS_ALBUM_TABLE +
2227             " WHERE " + ALBUM_ID + " = " + to_string(currentAlbumId) + ")";
2228         updateSortedAlbumsSqls.push_back(updateCurrentAlbumOrder);
2229     } else {
2230         int rank;
2231         int err = ObtainCurrentPortraitAlbumOrder(currentAlbumId, rank);
2232         if (err != E_OK) {
2233             return err;
2234         }
2235         updateOtherAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + RANK + " = " + RANK + " -1 WHERE " +
2236             USER_DISPLAY_LEVEL + " = " + to_string(FAVORITE_PAGE) + " AND " + RANK + ">" + to_string(rank);
2237         updateCurrentAlbumOrder = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + RANK + " = 0" +
2238             " WHERE " + GROUP_TAG + " IN (SELECT " + GROUP_TAG + " FROM " + ANALYSIS_ALBUM_TABLE +
2239             " WHERE " + ALBUM_ID + " = " + to_string(currentAlbumId) + ")";
2240         updateSortedAlbumsSqls.push_back(updateOtherAlbumOrder);
2241         updateSortedAlbumsSqls.push_back(updateCurrentAlbumOrder);
2242     }
2243     return ExecSqls(updateSortedAlbumsSqls, uniStore);
2244 }
2245 
UpdateFavorites(int32_t value,const int32_t albumId)2246 static int32_t UpdateFavorites(int32_t value, const int32_t albumId)
2247 {
2248     int err = UpdateFavoritesOrder(value, albumId);
2249     if (err != E_OK) {
2250         MEDIA_ERR_LOG("UpdateFavoritesOrder fail");
2251         return E_DB_FAIL;
2252     }
2253     if (value == UNFAVORITE_PAGE) {
2254         value = FIRST_PAGE;
2255     }
2256     return UpdateDisplayLevel(value, albumId);
2257 }
2258 
SetDisplayLevel(const ValuesBucket & values,const DataSharePredicates & predicates)2259 int32_t SetDisplayLevel(const ValuesBucket &values, const DataSharePredicates &predicates)
2260 {
2261     int32_t displayLevelValue;
2262     int err = GetIntVal(values, USER_DISPLAY_LEVEL, displayLevelValue);
2263     if (err < 0 || !MediaFileUtils::CheckDisplayLevel(displayLevelValue)) {
2264         MEDIA_ERR_LOG("invalid display level");
2265         return E_INVALID_VALUES;
2266     }
2267 
2268     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
2269     auto whereArgs = rdbPredicates.GetWhereArgs();
2270     if (whereArgs.size() == 0) {
2271         MEDIA_ERR_LOG("no target album id");
2272         return E_INVALID_VALUES;
2273     }
2274     int32_t albumId = atoi(whereArgs[0].c_str());
2275     if (albumId <= 0) {
2276         MEDIA_ERR_LOG("invalid album id");
2277         return E_INVALID_VALUES;
2278     }
2279 
2280     vector<int32_t> changedAlbumIds;
2281     if (displayLevelValue == FIRST_PAGE || displayLevelValue == SECOND_PAGE) {
2282         err = UpdateDisplayLevel(displayLevelValue, albumId);
2283         changedAlbumIds.push_back(albumId);
2284     } else {
2285         err = UpdateFavorites(displayLevelValue, albumId);
2286         changedAlbumIds.push_back(albumId);
2287     }
2288     if (err == E_OK) {
2289         NotifyPortraitAlbum(changedAlbumIds);
2290     }
2291     return err;
2292 }
2293 
SetMyOldAlbum(vector<string> & updateSqls,shared_ptr<MediaLibraryRdbStore> uniStore)2294 void SetMyOldAlbum(vector<string>& updateSqls, shared_ptr<MediaLibraryRdbStore> uniStore)
2295 {
2296     std::string queryIsMe = "SELECT COUNT(DISTINCT album_id)," + ALBUM_NAME + "," + USER_DISPLAY_LEVEL +
2297         " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + IS_ME + " = 1 ";
2298     auto resultSet = uniStore->QuerySql(queryIsMe);
2299     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
2300         MEDIA_ERR_LOG("Failed to query isMe!");
2301         return;
2302     }
2303     int count;
2304     if (resultSet->GetInt(0, count) != E_OK) {
2305         return;
2306     }
2307     std::string clearIsMeAlbum = "";
2308     if (count > 0) {
2309         string albumName = "";
2310         int userDisplayLevel = 0;
2311         GetStringValueFromResultSet(resultSet, ALBUM_NAME, albumName);
2312         GetIntValueFromResultSet(resultSet, USER_DISPLAY_LEVEL, userDisplayLevel);
2313         int renameOperation = albumName != "" ? 1 : 0;
2314         int updateDisplayLevel = (userDisplayLevel != FAVORITE_PAGE &&
2315             userDisplayLevel != FIRST_PAGE) ? 0 : userDisplayLevel;
2316         clearIsMeAlbum= "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + IS_ME + " = 0, " + RENAME_OPERATION +
2317             " = " + to_string(renameOperation) + ", " + USER_DISPLAY_LEVEL + " = " + to_string(updateDisplayLevel) +
2318             " WHERE " + IS_ME + " = 1";
2319         updateSqls.push_back(clearIsMeAlbum);
2320     }
2321 }
2322 
GetHighlightCoverStatus(const string & albumId,int32_t & currentCoverStatus)2323 static void GetHighlightCoverStatus(const string &albumId, int32_t &currentCoverStatus)
2324 {
2325     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2326     if (rdbStore == nullptr) {
2327         MEDIA_ERR_LOG("rdbStore is nullptr! failed update index");
2328         return;
2329     }
2330     const std::string queryCoverStatus =
2331         "SELECT status FROM " + HIGHLIGHT_COVER_INFO_TABLE + " WHERE album_id = "
2332         "(SELECT id FROM tab_highlight_album WHERE album_id = " + albumId + " LIMIT 1)";
2333     shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->QuerySql(queryCoverStatus);
2334     if (resultSet == nullptr) {
2335         MEDIA_ERR_LOG("resultSet is nullptr! failed update index");
2336         return;
2337     }
2338     if (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2339         currentCoverStatus = GetInt32Val(COVER_STATUS, resultSet);
2340     }
2341 }
2342 
SetHighlightCoverUri(const ValuesBucket & values,const DataSharePredicates & predicates)2343 int32_t SetHighlightCoverUri(const ValuesBucket &values, const DataSharePredicates &predicates)
2344 {
2345     MEDIA_INFO_LOG("Start set highlight cover uri");
2346     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
2347     auto whereArgs = rdbPredicates.GetWhereArgs();
2348     if (whereArgs.size() == 0) {
2349         MEDIA_ERR_LOG("no target album id");
2350         return E_INVALID_VALUES;
2351     }
2352     string targetAlbumId = whereArgs[0];
2353     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2354     if (uniStore == nullptr) {
2355         MEDIA_ERR_LOG("uniStore is nullptr! failed update for set highlight cover uri");
2356         return E_DB_FAIL;
2357     }
2358     string coverUri;
2359     int err = GetStringVal(values, COVER_URI, coverUri);
2360     if (err < 0 || coverUri.empty()) {
2361         MEDIA_ERR_LOG("invalid album cover uri");
2362         return E_INVALID_VALUES;
2363     }
2364 
2365     int32_t currentCoverStatus = 0;
2366     GetHighlightCoverStatus(targetAlbumId, currentCoverStatus);
2367     int32_t newCoverStatus = static_cast<uint32_t>(currentCoverStatus) | HIGHLIGHT_COVER_STATUS_COVER;
2368     std::string updateAnalysisAlbum = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + COVER_URI + " = '" + coverUri +
2369         "' WHERE " + ALBUM_ID + " = " + targetAlbumId;
2370     std::string updateCoverInfoTable = "UPDATE " + HIGHLIGHT_COVER_INFO_TABLE +
2371         " SET " + COVER_STATUS + " = " + to_string(newCoverStatus) +
2372         " WHERE " + ALBUM_ID + " = (SELECT id FROM tab_highlight_album WHERE album_id = " + targetAlbumId + " LIMIT 1)";
2373     vector<string> updateSqls = { updateAnalysisAlbum, updateCoverInfoTable };
2374     err = ExecSqls(updateSqls, uniStore);
2375     if (err == E_OK) {
2376         vector<int32_t> changeAlbumIds = { atoi(targetAlbumId.c_str()) };
2377         NotifyHighlightAlbum(changeAlbumIds);
2378     }
2379     return err;
2380 }
2381 
SetHighlightAlbumName(const ValuesBucket & values,const DataSharePredicates & predicates)2382 int32_t SetHighlightAlbumName(const ValuesBucket &values, const DataSharePredicates &predicates)
2383 {
2384     MEDIA_INFO_LOG("Start set highlight album name");
2385     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
2386     auto whereArgs = rdbPredicates.GetWhereArgs();
2387     if (whereArgs.size() == 0) {
2388         MEDIA_ERR_LOG("no target highlight album id");
2389         return E_INVALID_VALUES;
2390     }
2391     string highlightAlbumId = whereArgs[0];
2392     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2393     if (uniStore == nullptr) {
2394         MEDIA_ERR_LOG("uniStore is nullptr! failed update for set highlight album name");
2395         return E_DB_FAIL;
2396     }
2397     string albumName;
2398     int err = GetStringVal(values, ALBUM_NAME, albumName);
2399     if (err < 0 || albumName.empty()) {
2400         MEDIA_ERR_LOG("invalid album name");
2401         return E_INVALID_VALUES;
2402     }
2403 
2404     int32_t currentCoverStatus = 0;
2405     GetHighlightCoverStatus(highlightAlbumId, currentCoverStatus);
2406     int32_t newCoverStatus = static_cast<uint32_t>(currentCoverStatus) | HIGHLIGHT_COVER_STATUS_TITLE;
2407     std::string updateAlbumName = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + ALBUM_NAME + " = '" + albumName +
2408         "' WHERE " + ALBUM_ID + " = " + highlightAlbumId;
2409     std::string updateCoverInfoTable = "UPDATE " + HIGHLIGHT_COVER_INFO_TABLE + " SET " +
2410         COVER_STATUS + " = " + to_string(newCoverStatus) + " WHERE " +
2411         ALBUM_ID + " = (SELECT id FROM tab_highlight_album WHERE album_id = " + highlightAlbumId + " LIMIT 1)";
2412     vector<string> updateSqls = { updateAlbumName, updateCoverInfoTable };
2413     err = ExecSqls(updateSqls, uniStore);
2414     if (err == E_OK) {
2415         vector<int32_t> changeAlbumIds = { atoi(highlightAlbumId.c_str()) };
2416         NotifyHighlightAlbum(changeAlbumIds);
2417     }
2418     return err;
2419 }
2420 
SetHighlightSubtitle(const ValuesBucket & values,const DataSharePredicates & predicates)2421 int32_t SetHighlightSubtitle(const ValuesBucket &values, const DataSharePredicates &predicates)
2422 {
2423     MEDIA_INFO_LOG("Start set highlight subtitle");
2424     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
2425     auto whereArgs = rdbPredicates.GetWhereArgs();
2426     if (whereArgs.size() == 0) {
2427         MEDIA_ERR_LOG("no target highlight album id");
2428         return E_INVALID_VALUES;
2429     }
2430     string highlightAlbumId = whereArgs[0];
2431     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2432     if (uniStore == nullptr) {
2433         MEDIA_ERR_LOG("uniStore is nullptr! failed update for set highlight album name");
2434         return E_DB_FAIL;
2435     }
2436     string albumSubtitle;
2437     int err = GetStringVal(values, SUB_TITLE, albumSubtitle);
2438     if (err < 0) {
2439         MEDIA_ERR_LOG("invalid album name");
2440         return E_INVALID_VALUES;
2441     }
2442 
2443     MEDIA_INFO_LOG("New highlight subtitle is: %{public}s, album id is %{public}s",
2444         albumSubtitle.c_str(), highlightAlbumId.c_str());
2445     int32_t currentCoverStatus = 0;
2446     GetHighlightCoverStatus(highlightAlbumId, currentCoverStatus);
2447     int32_t newCoverStatus = static_cast<uint32_t>(currentCoverStatus) | HIGHLIGHT_COVER_STATUS_TITLE;
2448     std::string updateAlbumName = "UPDATE " + HIGHLIGHT_ALBUM_TABLE + " SET " + SUB_TITLE + " = '" + albumSubtitle +
2449         "', " + HIGHLIGHT_USE_SUBTITLE + " = 1" + " WHERE " + ALBUM_ID + " = " + highlightAlbumId;
2450     std::string updateCoverInfoTable = "UPDATE " + HIGHLIGHT_COVER_INFO_TABLE + " SET " +
2451         COVER_STATUS + " = " + to_string(newCoverStatus) + " WHERE " +
2452         ALBUM_ID + " = (SELECT id FROM tab_highlight_album WHERE album_id = " + highlightAlbumId + " LIMIT 1)";
2453     vector<string> updateSqls = { updateAlbumName, updateCoverInfoTable };
2454     err = ExecSqls(updateSqls, uniStore);
2455     if (err == E_OK) {
2456         vector<int32_t> changeAlbumIds = { atoi(highlightAlbumId.c_str()) };
2457         NotifyHighlightAlbum(changeAlbumIds);
2458     }
2459     return err;
2460 }
2461 
2462 /**
2463  * set target album is me
2464  * @param values is_me
2465  * @param predicates target album
2466  */
SetIsMe(const ValuesBucket & values,const DataSharePredicates & predicates)2467 int32_t SetIsMe(const ValuesBucket &values, const DataSharePredicates &predicates)
2468 {
2469     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
2470     auto whereArgs = rdbPredicates.GetWhereArgs();
2471     if (whereArgs.size() == 0) {
2472         MEDIA_ERR_LOG("no target album id");
2473         return E_INVALID_VALUES;
2474     }
2475     string targetAlbumId = whereArgs[0];
2476     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2477     if (uniStore == nullptr) {
2478         MEDIA_ERR_LOG("uniStore is nullptr! failed update for merge albums");
2479         return E_DB_FAIL;
2480     }
2481     vector<string> updateSqls;
2482     SetMyOldAlbum(updateSqls, uniStore);
2483     std::string queryTargetIsMe = "SELECT " + USER_DISPLAY_LEVEL + " FROM " + ANALYSIS_ALBUM_TABLE +
2484         " WHERE " + ALBUM_ID + " = " + targetAlbumId;
2485     auto tartGetResultSet = uniStore->QuerySql(queryTargetIsMe);
2486     if (tartGetResultSet == nullptr || tartGetResultSet->GoToFirstRow() != NativeRdb::E_OK) {
2487         MEDIA_ERR_LOG("Failed to query isMe!");
2488         return -E_HAS_DB_ERROR;
2489     }
2490     int tartgetUserDisplayLevel;
2491     GetIntValueFromResultSet(tartGetResultSet, USER_DISPLAY_LEVEL, tartgetUserDisplayLevel);
2492     int updateTargetDisplayLevel = (tartgetUserDisplayLevel != FAVORITE_PAGE) ? 1 : tartgetUserDisplayLevel;
2493 
2494     std::string updateForSetIsMe = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + IS_ME + " = 1, " + RENAME_OPERATION +
2495         " = 1, " + USER_DISPLAY_LEVEL + " = " + to_string(updateTargetDisplayLevel) + " WHERE " + GROUP_TAG +
2496         " IN(SELECT " + GROUP_TAG + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID +
2497         " = " + targetAlbumId + ")";
2498     updateSqls.push_back(updateForSetIsMe);
2499     int32_t err = ExecSqls(updateSqls, uniStore);
2500     if (err == E_OK) {
2501         vector<int32_t> changeAlbumIds = { atoi(targetAlbumId.c_str()) };
2502         NotifyPortraitAlbum(changeAlbumIds);
2503     }
2504     return err;
2505 }
2506 
2507 /**
2508  * set target album name
2509  * @param values album_name
2510  * @param predicates target album
2511  */
SetAlbumName(const ValuesBucket & values,const DataSharePredicates & predicates)2512 int32_t SetAlbumName(const ValuesBucket &values, const DataSharePredicates &predicates)
2513 {
2514     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
2515     auto whereArgs = rdbPredicates.GetWhereArgs();
2516     if (whereArgs.size() == 0) {
2517         MEDIA_ERR_LOG("no target album id");
2518         return E_INVALID_VALUES;
2519     }
2520     string targetAlbumId = whereArgs[0];
2521     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2522     if (uniStore == nullptr) {
2523         MEDIA_ERR_LOG("uniStore is nullptr! failed update for set album name");
2524         return E_DB_FAIL;
2525     }
2526     string albumName;
2527     int err = GetStringVal(values, ALBUM_NAME, albumName);
2528     if (err < 0 || albumName.empty()) {
2529         MEDIA_ERR_LOG("invalid album name");
2530         return E_INVALID_VALUES;
2531     }
2532     std::string updateForSetAlbumName = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + ALBUM_NAME + " = '" + albumName +
2533         "' , " + RENAME_OPERATION + " = 1 WHERE " + GROUP_TAG + " IN(SELECT " + GROUP_TAG + " FROM " +
2534         ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID + " = " + targetAlbumId + ")";
2535     vector<string> updateSqls = { updateForSetAlbumName};
2536     err = ExecSqls(updateSqls, uniStore);
2537     if (err == E_OK) {
2538         vector<int32_t> changeAlbumIds = { atoi(targetAlbumId.c_str()) };
2539         NotifyPortraitAlbum(changeAlbumIds);
2540     }
2541 
2542     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2543     if (rdbStore == nullptr) {
2544         MEDIA_ERR_LOG("rdbStore is nullptr! failed update index");
2545         return err;
2546     }
2547     const std::string  QUERY_MAP_ASSET_TO_UPDATE_INDEX =
2548         "SELECT map_asset FROM AnalysisPhotoMap WHERE map_album = " + targetAlbumId;
2549     vector<string> mapAssets;
2550     shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->QuerySql(QUERY_MAP_ASSET_TO_UPDATE_INDEX);
2551     if (resultSet == nullptr) {
2552         MEDIA_ERR_LOG("resultSet is nullptr! failed update index");
2553         return err;
2554     }
2555     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2556         mapAssets.push_back(to_string(GetInt32Val("map_asset", resultSet)));
2557     }
2558     MEDIA_INFO_LOG("update index map_asset size: %{public}zu", mapAssets.size());
2559     MediaAnalysisHelper::AsyncStartMediaAnalysisService(
2560         static_cast<int32_t>(MediaAnalysisProxy::ActivateServiceType::START_UPDATE_INDEX), mapAssets);
2561 
2562     return err;
2563 }
2564 
2565 /**
2566  * set target album uri
2567  * @param values cover_uri
2568  * @param predicates target album
2569  */
SetCoverUri(const ValuesBucket & values,const DataSharePredicates & predicates)2570 int32_t SetCoverUri(const ValuesBucket &values, const DataSharePredicates &predicates)
2571 {
2572     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, ANALYSIS_ALBUM_TABLE);
2573     auto whereArgs = rdbPredicates.GetWhereArgs();
2574     if (whereArgs.size() == 0) {
2575         MEDIA_ERR_LOG("no target album id");
2576         return E_INVALID_VALUES;
2577     }
2578     string targetAlbumId = whereArgs[0];
2579     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
2580     if (uniStore == nullptr) {
2581         MEDIA_ERR_LOG("uniStore is nullptr! failed update for set album cover uri");
2582         return E_DB_FAIL;
2583     }
2584     string coverUri;
2585     int err = GetStringVal(values, COVER_URI, coverUri);
2586     if (err < 0 || coverUri.empty()) {
2587         MEDIA_ERR_LOG("invalid album cover uri");
2588         return E_INVALID_VALUES;
2589     }
2590     std::string updateForSetCoverUri = "UPDATE " + ANALYSIS_ALBUM_TABLE + " SET " + COVER_URI + " = '" + coverUri +
2591         "', " + IS_COVER_SATISFIED + " = " + to_string(static_cast<uint8_t>(CoverSatisfiedType::USER_SETTING)) +
2592         " WHERE " + GROUP_TAG + " IN(SELECT " + GROUP_TAG + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " + ALBUM_ID +
2593         " = " + targetAlbumId + ")";
2594     vector<string> updateSqls = { updateForSetCoverUri };
2595     err = ExecSqls(updateSqls, uniStore);
2596     if (err == E_OK) {
2597         vector<int32_t> changeAlbumIds = { atoi(targetAlbumId.c_str()) };
2598         NotifyPortraitAlbum(changeAlbumIds);
2599     }
2600     return err;
2601 }
2602 
GetArgsSetUserAlbumName(const ValuesBucket & values,const DataSharePredicates & predicates,int32_t & oldAlbumId,string & newAlbumName)2603 static bool GetArgsSetUserAlbumName(const ValuesBucket& values,
2604     const DataSharePredicates& predicates, int32_t& oldAlbumId, string& newAlbumName)
2605 {
2606     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoAlbumColumns::TABLE);
2607     CHECK_AND_RETURN_RET_LOG(!rdbPredicates.GetWhereArgs().empty(), false,
2608         "Rename user album failed. Args is empty");
2609     oldAlbumId = atoi(rdbPredicates.GetWhereArgs()[0].c_str());
2610     CHECK_AND_RETURN_RET_LOG(oldAlbumId > 0, false, "Rename user album failed. Invalid album id: %{public}s",
2611         rdbPredicates.GetWhereArgs()[0].c_str());
2612     CHECK_AND_RETURN_RET_LOG(GetStringObject(values, PhotoAlbumColumns::ALBUM_NAME, newAlbumName) == E_OK, false,
2613         "Rename user album failed. Get new album name failed");
2614     return true;
2615 }
2616 
HandleSetAlbumNameRequest(const ValuesBucket & values,const DataSharePredicates & predicates)2617 static int32_t HandleSetAlbumNameRequest(const ValuesBucket &values, const DataSharePredicates &predicates)
2618 {
2619     int32_t oldAlbumId {};
2620     string newAlbumName {};
2621     CHECK_AND_RETURN_RET_LOG(GetArgsSetUserAlbumName(values, predicates, oldAlbumId, newAlbumName),
2622         E_INVALID_ARGS, "Set album name args invalid");
2623     return RenameUserAlbum(oldAlbumId, newAlbumName);
2624 }
2625 
HandleAnalysisPhotoAlbum(const OperationType & opType,const NativeRdb::ValuesBucket & values,const DataShare::DataSharePredicates & predicates,std::shared_ptr<int> countPtr)2626 int32_t MediaLibraryAlbumOperations::HandleAnalysisPhotoAlbum(const OperationType &opType,
2627     const NativeRdb::ValuesBucket &values, const DataShare::DataSharePredicates &predicates,
2628     std::shared_ptr<int> countPtr)
2629 {
2630     switch (opType) {
2631         case OperationType::PORTRAIT_DISPLAY_LEVEL:
2632             return SetDisplayLevel(values, predicates);
2633         case OperationType::PORTRAIT_MERGE_ALBUM:
2634             return MergePortraitAlbums(values);
2635         case OperationType::PORTRAIT_IS_ME:
2636             return SetIsMe(values, predicates);
2637         case OperationType::PORTRAIT_ALBUM_NAME:
2638             return SetAlbumName(values, predicates);
2639         case OperationType::PORTRAIT_COVER_URI:
2640             return SetCoverUri(values, predicates);
2641         case OperationType::HIGHLIGHT_ALBUM_NAME:
2642             return SetHighlightAlbumName(values, predicates);
2643         case OperationType::HIGHLIGHT_COVER_URI:
2644             return SetHighlightCoverUri(values, predicates);
2645         case OperationType::HIGHLIGHT_SUBTITLE:
2646             return SetHighlightSubtitle(values, predicates);
2647         case OperationType::DISMISS:
2648         case OperationType::GROUP_ALBUM_NAME:
2649         case OperationType::GROUP_COVER_URI:
2650             return MediaLibraryAnalysisAlbumOperations::HandleGroupPhotoAlbum(opType, values, predicates);
2651         default:
2652             MEDIA_ERR_LOG("Unknown operation type: %{public}d", opType);
2653             return E_ERR;
2654     }
2655 }
2656 
HandlePhotoAlbum(const OperationType & opType,const ValuesBucket & values,const DataSharePredicates & predicates,shared_ptr<int> countPtr)2657 int32_t MediaLibraryAlbumOperations::HandlePhotoAlbum(const OperationType &opType, const ValuesBucket &values,
2658     const DataSharePredicates &predicates, shared_ptr<int> countPtr)
2659 {
2660     switch (opType) {
2661         case OperationType::UPDATE:
2662             return UpdatePhotoAlbum(values, predicates);
2663         case OperationType::ALBUM_RECOVER_ASSETS:
2664             return RecoverPhotoAssets(predicates);
2665         case OperationType::ALBUM_DELETE_ASSETS:
2666             return DeletePhotoAssets(predicates, false, false);
2667         case OperationType::COMPAT_ALBUM_DELETE_ASSETS:
2668             return DeletePhotoAssets(predicates, false, true);
2669         case OperationType::DELETE_LOCAL_ASSETS_PERMANENTLY:
2670             return DeletePhotoAssetsCompleted(predicates, false);
2671         case OperationType::AGING:
2672             return AgingPhotoAssets(countPtr);
2673         case OperationType::ALBUM_ORDER:
2674             return OrderSingleAlbum(values);
2675         case OperationType::ALBUM_SET_NAME:
2676             return HandleSetAlbumNameRequest(values, predicates);
2677         default:
2678             MEDIA_ERR_LOG("Unknown operation type: %{public}d", opType);
2679             return E_ERR;
2680     }
2681 }
2682 
HandlePhotoAlbumOperations(MediaLibraryCommand & cmd)2683 int MediaLibraryAlbumOperations::HandlePhotoAlbumOperations(MediaLibraryCommand &cmd)
2684 {
2685     switch (cmd.GetOprnType()) {
2686         case OperationType::CREATE:
2687             return CreatePhotoAlbum(cmd);
2688         default:
2689             MEDIA_ERR_LOG("Unknown operation type: %{public}d", cmd.GetOprnType());
2690             return E_ERR;
2691     }
2692 }
2693 } // namespace OHOS::Media
2694