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