• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2022 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 "directory_ex.h"
20 #include "media_file_utils.h"
21 #include "media_log.h"
22 #include "medialibrary_data_manager_utils.h"
23 #include "medialibrary_db_const.h"
24 #include "medialibrary_errno.h"
25 #include "medialibrary_notify.h"
26 #include "medialibrary_object_utils.h"
27 #include "medialibrary_rdbstore.h"
28 #include "medialibrary_tracer.h"
29 #include "medialibrary_unistore_manager.h"
30 #include "photo_album_column.h"
31 #include "photo_map_column.h"
32 
33 #include "result_set_utils.h"
34 #include "values_bucket.h"
35 
36 using namespace std;
37 using namespace OHOS::NativeRdb;
38 using namespace OHOS::DataShare;
39 using namespace OHOS::RdbDataShareAdapter;
40 
41 namespace OHOS::Media {
42 using ChangeType = AAFwk::ChangeInfo::ChangeType;
43 constexpr int32_t AFTER_AGR_SIZE = 2;
44 constexpr int32_t THAN_AGR_SIZE = 1;
CreateAlbumOperation(MediaLibraryCommand & cmd)45 int32_t MediaLibraryAlbumOperations::CreateAlbumOperation(MediaLibraryCommand &cmd)
46 {
47     int64_t outRow = -1;
48     int32_t errCode = MediaLibraryObjectUtils::CreateDirObj(cmd, outRow);
49     if (errCode == E_SUCCESS) {
50         return outRow;
51     }
52     return errCode;
53 }
54 
55 // only support modify in the same parent folder, like: a/b/c --> a/b/d
ModifyAlbumOperation(MediaLibraryCommand & cmd)56 int32_t MediaLibraryAlbumOperations::ModifyAlbumOperation(MediaLibraryCommand &cmd)
57 {
58     string strId = cmd.GetOprnFileId();
59     string srcDirPath = MediaLibraryObjectUtils::GetPathByIdFromDb(strId);
60     if (srcDirPath.empty()) {
61         MEDIA_ERR_LOG("Get path of id %{private}s from database file!", strId.c_str());
62         return E_INVALID_PATH;
63     }
64 
65     auto values = cmd.GetValueBucket();
66     string dstDirName;
67     ValueObject valueObject;
68     if (values.GetObject(MEDIA_DATA_DB_NAME, valueObject)) {
69         valueObject.GetString(dstDirName);
70     }
71     int ret;
72     if (dstDirName.empty() && !values.IsEmpty()) {
73         ret = MediaLibraryObjectUtils::ModifyInfoByIdInDb(cmd);
74     } else {
75         string dstDirPath = MediaFileUtils::GetParentPath(srcDirPath) + "/" + dstDirName;
76         ret = MediaLibraryObjectUtils::RenameDirObj(cmd, srcDirPath, dstDirPath);
77     }
78     return ret;
79 }
80 
GetDistributedAlbumSql(const string & strQueryCondition,const string & tableName)81 string MediaLibraryAlbumOperations::GetDistributedAlbumSql(const string &strQueryCondition, const string &tableName)
82 {
83     string distributedAlbumSql = "SELECT * FROM ( " + DISTRIBUTED_ALBUM_COLUMNS + " FROM " + tableName + " " +
84         FILE_TABLE + ", " + tableName + " " + ALBUM_TABLE +
85         DISTRIBUTED_ALBUM_WHERE_AND_GROUPBY + " )";
86     if (!strQueryCondition.empty()) {
87         distributedAlbumSql += " WHERE " + strQueryCondition;
88     }
89     MEDIA_DEBUG_LOG("GetDistributedAlbumSql distributedAlbumSql = %{private}s", distributedAlbumSql.c_str());
90     return distributedAlbumSql;
91 }
92 
93 #ifdef MEDIALIBRARY_COMPATIBILITY
ReplaceRelativePath(string & selection,vector<string> & selectionArgs)94 static void ReplaceRelativePath(string &selection, vector<string> &selectionArgs)
95 {
96     for (size_t pos = 0; pos != string::npos;) {
97         pos = selection.find(MEDIA_DATA_DB_RELATIVE_PATH, pos);
98         if (pos == string::npos) {
99             break;
100         }
101         size_t argPos = selection.find('?', pos);
102         if (argPos == string::npos) {
103             break;
104         }
105         size_t argIndex = 0;
106         for (size_t i = 0; i < argPos; i++) {
107             if (selection[i] == '?') {
108                 argIndex++;
109             }
110         }
111         if (argIndex > selectionArgs.size() - 1) {
112             MEDIA_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
113                 selection.c_str());
114             break;
115         }
116         const string &arg = selectionArgs[argIndex];
117         if (!arg.empty()) {
118             MEDIA_WARN_LOG("No empty args in ReplaceRelativePath");
119             return;
120         }
121         selection.replace(argPos, 1, "? OR 1=1)");
122         selection.replace(pos, MEDIA_DATA_DB_RELATIVE_PATH.length(), "(" + PhotoAlbumColumns::ALBUM_ID);
123 
124         selectionArgs[argIndex] = "1";
125         pos = argPos + 1;
126     }
127 }
128 
ReplaceMediaType(string & selection,vector<string> & selectionArgs)129 static void ReplaceMediaType(string &selection, vector<string> &selectionArgs)
130 {
131     for (size_t pos = 0; pos != string::npos;) {
132         pos = selection.find(MEDIA_DATA_DB_MEDIA_TYPE, pos);
133         if (pos == string::npos) {
134             break;
135         }
136         size_t argPos = selection.find('?', pos);
137         if (argPos == string::npos) {
138             break;
139         }
140         size_t argIndex = 0;
141         for (size_t i = 0; i < argPos; i++) {
142             if (selection[i] == '?') {
143                 argIndex++;
144             }
145         }
146         if (argIndex > selectionArgs.size() - 1) {
147             MEDIA_WARN_LOG("SelectionArgs size is not valid, selection format maybe incorrect: %{private}s",
148                 selection.c_str());
149             break;
150         }
151         selection.replace(argPos, 1, "? OR 1=1)");
152         selection.replace(pos, MEDIA_DATA_DB_MEDIA_TYPE.length(), "(" + PhotoAlbumColumns::ALBUM_ID);
153 
154         selectionArgs[argIndex] = "1";
155         pos = argPos + 1;
156     }
157 }
158 
GetSqlArgs(MediaLibraryCommand & cmd,string & sql,vector<string> & selectionArgs,const vector<string> & columns)159 static void GetSqlArgs(MediaLibraryCommand &cmd, string &sql, vector<string> &selectionArgs,
160     const vector<string> &columns)
161 {
162     string clause = cmd.GetAbsRdbPredicates()->GetWhereClause();
163     selectionArgs = cmd.GetAbsRdbPredicates()->GetWhereArgs();
164     sql = "SELECT ";
165     for (size_t i = 0; i < columns.size(); i++) {
166         if (i != columns.size() - 1) {
167             sql += columns[i] + ",";
168         } else {
169             sql += columns[i];
170         }
171     }
172     sql += " FROM " + cmd.GetAbsRdbPredicates()->GetTableName();
173     sql += " WHERE ";
174     ReplaceRelativePath(clause, selectionArgs);
175     ReplaceMediaType(clause, selectionArgs);
176     sql += clause;
177 }
178 
QueryAlbumDebug(MediaLibraryCommand & cmd,const vector<string> & columns,const shared_ptr<MediaLibraryUnistore> & store)179 static void QueryAlbumDebug(MediaLibraryCommand &cmd, const vector<string> &columns,
180     const shared_ptr<MediaLibraryUnistore> &store)
181 {
182     MEDIA_DEBUG_LOG("Querying album, table: %{public}s selections: %{public}s",
183         cmd.GetAbsRdbPredicates()->GetTableName().c_str(), cmd.GetAbsRdbPredicates()->GetWhereClause().c_str());
184     for (const auto &arg : cmd.GetAbsRdbPredicates()->GetWhereArgs()) {
185         MEDIA_DEBUG_LOG("Querying album, arg: %{public}s", arg.c_str());
186     }
187     for (const auto &col : columns) {
188         MEDIA_DEBUG_LOG("Querying album, col: %{public}s", col.c_str());
189     }
190 
191     auto resultSet = store->Query(cmd, columns);
192     if (resultSet == nullptr) {
193         MEDIA_ERR_LOG("Failed to query file!");
194         return;
195     }
196     int32_t count = -1;
197     int32_t err = resultSet->GetRowCount(count);
198     if (err != E_OK) {
199         MEDIA_ERR_LOG("Failed to get count, err: %{public}d", err);
200         return;
201     }
202     MEDIA_DEBUG_LOG("Querying album, count: %{public}d", count);
203 }
204 
QuerySqlDebug(const string & sql,const vector<string> & selectionArgs,const vector<string> & columns,const shared_ptr<MediaLibraryUnistore> & store)205 static void QuerySqlDebug(const string &sql, const vector<string> &selectionArgs, const vector<string> &columns,
206     const shared_ptr<MediaLibraryUnistore> &store)
207 {
208     constexpr int32_t printMax = 512;
209     for (size_t pos = 0; pos < sql.size(); pos += printMax) {
210         MEDIA_DEBUG_LOG("Quering album sql: %{public}s", sql.substr(pos, printMax).c_str());
211     }
212     for (const auto &arg : selectionArgs) {
213         MEDIA_DEBUG_LOG("Quering album, arg: %{public}s", arg.c_str());
214     }
215     for (const auto &col : columns) {
216         MEDIA_DEBUG_LOG("Quering album, col: %{public}s", col.c_str());
217     }
218     auto resultSet = store->QuerySql(sql, selectionArgs);
219     if (resultSet == nullptr) {
220         MEDIA_ERR_LOG("Failed to query album!");
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("Quering album, count: %{public}d", count);
230 }
231 #endif
232 
QueryAlbumOperation(MediaLibraryCommand & cmd,const vector<string> & columns)233 shared_ptr<ResultSet> MediaLibraryAlbumOperations::QueryAlbumOperation(
234     MediaLibraryCommand &cmd, const vector<string> &columns)
235 {
236     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
237     if (uniStore == nullptr) {
238         MEDIA_ERR_LOG("uniStore is nullptr!");
239         return nullptr;
240     }
241 
242     if (cmd.GetOprnObject() == OperationObject::MEDIA_VOLUME) {
243         MEDIA_DEBUG_LOG("QUERY_MEDIA_VOLUME = %{public}s", QUERY_MEDIA_VOLUME.c_str());
244         return uniStore->QuerySql(QUERY_MEDIA_VOLUME + " UNION " + PhotoColumn::QUERY_MEDIA_VOLUME + " UNION " +
245             AudioColumn::QUERY_MEDIA_VOLUME);
246     }
247 
248 #ifdef MEDIALIBRARY_COMPATIBILITY
249     string whereClause = cmd.GetAbsRdbPredicates()->GetWhereClause();
250     if (whereClause.find(MEDIA_DATA_DB_RELATIVE_PATH) != string::npos ||
251         whereClause.find(MEDIA_DATA_DB_MEDIA_TYPE) != string::npos) {
252         string sql;
253         vector<string> selectionArgs;
254         GetSqlArgs(cmd, sql, selectionArgs, columns);
255         QuerySqlDebug(sql, selectionArgs, columns, uniStore);
256         return uniStore->QuerySql(sql, selectionArgs);
257     }
258 
259     QueryAlbumDebug(cmd, columns, uniStore);
260     return uniStore->Query(cmd, columns);
261 #else
262     string strQueryCondition = cmd.GetAbsRdbPredicates()->GetWhereClause();
263     strQueryCondition += " GROUP BY " + MEDIA_DATA_DB_BUCKET_ID;
264     cmd.GetAbsRdbPredicates()->SetWhereClause(strQueryCondition);
265     string networkId = cmd.GetOprnDevice();
266     if (!networkId.empty()) {
267         string tableName = cmd.GetTableName();
268         MEDIA_INFO_LOG("tableName is %{private}s", tableName.c_str());
269         if (!strQueryCondition.empty()) {
270             strQueryCondition = MediaLibraryDataManagerUtils::ObtionCondition(strQueryCondition,
271                 cmd.GetAbsRdbPredicates()->GetWhereArgs());
272         }
273         string distributedAlbumSql = GetDistributedAlbumSql(strQueryCondition, tableName);
274         return uniStore->QuerySql(distributedAlbumSql);
275     }
276 
277     if (!strQueryCondition.empty()) {
278         return uniStore->Query(cmd, columns);
279     }
280     string querySql = "SELECT * FROM " + cmd.GetTableName();
281     return uniStore->QuerySql(querySql);
282 #endif
283 }
284 
GetStringObject(const ValuesBucket & values,const string & key,string & value)285 inline int32_t GetStringObject(const ValuesBucket &values, const string &key, string &value)
286 {
287     value = "";
288     ValueObject valueObject;
289     if (values.GetObject(key, valueObject)) {
290         valueObject.GetString(value);
291     } else {
292         return -EINVAL;
293     }
294     return E_OK;
295 }
296 
PrepareUserAlbum(const string & albumName,const string & relativePath,ValuesBucket & values)297 inline void PrepareUserAlbum(const string &albumName, const string &relativePath, ValuesBucket &values)
298 {
299     values.PutString(PhotoAlbumColumns::ALBUM_NAME, albumName);
300     values.PutInt(PhotoAlbumColumns::ALBUM_TYPE, PhotoAlbumType::USER);
301     values.PutInt(PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumSubType::USER_GENERIC);
302     values.PutLong(PhotoAlbumColumns::ALBUM_DATE_MODIFIED, MediaFileUtils::UTCTimeSeconds());
303 
304     if (!relativePath.empty()) {
305         values.PutString(PhotoAlbumColumns::ALBUM_RELATIVE_PATH, relativePath);
306     }
307 }
308 
PrepareWhere(const string & albumName,const string & relativePath,RdbPredicates & predicates)309 inline void PrepareWhere(const string &albumName, const string &relativePath, RdbPredicates &predicates)
310 {
311     predicates.EqualTo(PhotoAlbumColumns::ALBUM_NAME, albumName);
312     predicates.EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::USER));
313     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
314     if (relativePath.empty()) {
315         predicates.IsNull(PhotoAlbumColumns::ALBUM_RELATIVE_PATH);
316     } else {
317         predicates.EqualTo(PhotoAlbumColumns::ALBUM_RELATIVE_PATH, relativePath);
318     }
319 }
320 
321 // Caller is responsible for checking @albumName AND @relativePath
DoCreatePhotoAlbum(const string & albumName,const string & relativePath)322 int DoCreatePhotoAlbum(const string &albumName, const string &relativePath)
323 {
324     // Build insert sql
325     string sql;
326     vector<ValueObject> bindArgs;
327     sql.append("INSERT").append(" OR ROLLBACK").append(" INTO ").append(PhotoAlbumColumns::TABLE).append(" ");
328 
329     ValuesBucket albumValues;
330     PrepareUserAlbum(albumName, relativePath, albumValues);
331     MediaLibraryRdbStore::BuildValuesSql(albumValues, bindArgs, sql);
332 
333     RdbPredicates wherePredicates(PhotoAlbumColumns::TABLE);
334     PrepareWhere(albumName, relativePath, wherePredicates);
335     sql.append(" WHERE NOT EXISTS (");
336     MediaLibraryRdbStore::BuildQuerySql(wherePredicates, { PhotoAlbumColumns::ALBUM_ID }, bindArgs, sql);
337     sql.append(");");
338     MEDIA_DEBUG_LOG("DoCreatePhotoAlbum InsertSql: %{private}s", sql.c_str());
339 
340     return MediaLibraryRdbStore::ExecuteForLastInsertedRowId(sql, bindArgs);
341 }
342 
CreatePhotoAlbum(const string & albumName)343 inline int CreatePhotoAlbum(const string &albumName)
344 {
345     int32_t err = MediaFileUtils::CheckAlbumName(albumName);
346     if (err < 0) {
347         return err;
348     }
349 
350     return DoCreatePhotoAlbum(albumName, "");
351 }
352 
CreatePhotoAlbum(MediaLibraryCommand & cmd)353 int CreatePhotoAlbum(MediaLibraryCommand &cmd)
354 {
355     string albumName;
356     int err = GetStringObject(cmd.GetValueBucket(), PhotoAlbumColumns::ALBUM_NAME, albumName);
357     if (err < 0) {
358         return err;
359     }
360     int rowId = CreatePhotoAlbum(albumName);
361     auto watch = MediaLibraryNotify::GetInstance();
362     if (rowId > 0) {
363         watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX, to_string(rowId)),
364             NotifyType::NOTIFY_ADD);
365     }
366     return rowId;
367 }
368 
DeletePhotoAlbum(RdbPredicates & predicates)369 int32_t MediaLibraryAlbumOperations::DeletePhotoAlbum(RdbPredicates &predicates)
370 {
371     // Only user generic albums can be deleted
372     predicates.And()->BeginWrap()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::USER));
373     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
374     predicates.EndWrap();
375 
376     int deleteRow = MediaLibraryRdbStore::Delete(predicates);
377     auto watch = MediaLibraryNotify::GetInstance();
378     for (size_t i = 0; i < predicates.GetWhereArgs().size() - AFTER_AGR_SIZE; i++) {
379         if (deleteRow > 0) {
380             watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX,
381                 predicates.GetWhereArgs()[i]), NotifyType::NOTIFY_REMOVE);
382         }
383     }
384     return deleteRow;
385 }
386 
QueryPhotoAlbum(MediaLibraryCommand & cmd,const vector<string> & columns)387 shared_ptr<ResultSet> MediaLibraryAlbumOperations::QueryPhotoAlbum(MediaLibraryCommand &cmd,
388     const vector<string> &columns)
389 {
390     return MediaLibraryRdbStore::Query(*(cmd.GetAbsRdbPredicates()), columns);
391 }
392 
PrepareUpdateValues(const ValuesBucket & values,ValuesBucket & updateValues)393 int32_t PrepareUpdateValues(const ValuesBucket &values, ValuesBucket &updateValues)
394 {
395     // Collect albumName if exists and check
396     string albumName;
397     if (GetStringObject(values, PhotoAlbumColumns::ALBUM_NAME, albumName) == E_OK) {
398         int32_t err = MediaFileUtils::CheckAlbumName(albumName);
399         if (err < 0) {
400             return err;
401         }
402         updateValues.PutString(PhotoAlbumColumns::ALBUM_NAME, albumName);
403     }
404 
405     // Collect coverUri if exists
406     string coverUri;
407     if (GetStringObject(values, PhotoAlbumColumns::ALBUM_COVER_URI, coverUri) == E_OK) {
408         updateValues.PutString(PhotoAlbumColumns::ALBUM_COVER_URI, coverUri);
409     }
410 
411     if (updateValues.IsEmpty()) {
412         return -EINVAL;
413     }
414     updateValues.PutLong(PhotoAlbumColumns::ALBUM_DATE_MODIFIED, MediaFileUtils::UTCTimeSeconds());
415     return E_OK;
416 }
417 
UpdatePhotoAlbum(const ValuesBucket & values,const DataSharePredicates & predicates)418 int32_t UpdatePhotoAlbum(const ValuesBucket &values, const DataSharePredicates &predicates)
419 {
420     ValuesBucket rdbValues;
421     int32_t err = PrepareUpdateValues(values, rdbValues);
422     if (err < 0) {
423         return err;
424     }
425 
426     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoAlbumColumns::TABLE);
427     // Only user generic albums can be updated
428     rdbPredicates.And()->BeginWrap()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::USER));
429     rdbPredicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
430     rdbPredicates.EndWrap();
431 
432     int32_t changedRows = MediaLibraryRdbStore::Update(rdbValues, rdbPredicates);
433     auto watch = MediaLibraryNotify::GetInstance();
434     if (changedRows > 0) {
435         for (size_t i = 0; i < rdbPredicates.GetWhereArgs().size() - AFTER_AGR_SIZE; i++) {
436             watch->Notify(MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX,
437                 rdbPredicates.GetWhereArgs()[i]), NotifyType::NOTIFY_UPDATE);
438         }
439     }
440     return changedRows;
441 }
442 
QueryGoToFirst(const RdbPredicates & predicates,const vector<string> & columns)443 static inline shared_ptr<ResultSet> QueryGoToFirst(const RdbPredicates &predicates, const vector<string> &columns)
444 {
445     auto resultSet = MediaLibraryRdbStore::Query(predicates, columns);
446     if (resultSet == nullptr) {
447         return nullptr;
448     }
449     int32_t count = 0;
450     int32_t err = resultSet->GetRowCount(count);
451     if (err != NativeRdb::E_OK) {
452         return nullptr;
453     }
454     if (count > 0) {
455         err = resultSet->GoToFirstRow();
456         if (err != E_OK) {
457             return nullptr;
458         }
459     }
460 
461     return resultSet;
462 }
463 
QueryAlbumAssets(RdbPredicates & predicates,const vector<string> & columns)464 static inline shared_ptr<ResultSet> QueryAlbumAssets(RdbPredicates &predicates,
465     const vector<string> &columns)
466 {
467     return QueryGoToFirst(predicates, columns);
468 }
469 
ForEachRow(const shared_ptr<ResultSet> & resultSet,const function<int32_t (const shared_ptr<ResultSet> & albumResult)> & func,const bool ignoreFailure)470 static int32_t ForEachRow(const shared_ptr<ResultSet> &resultSet,
471     const function<int32_t(const shared_ptr<ResultSet> &albumResult)> &func, const bool ignoreFailure)
472 {
473     int32_t count = 0;
474     int32_t err = resultSet->GetRowCount(count);
475     if (err != E_OK) {
476         return E_HAS_DB_ERROR;
477     }
478     if (count <= 0) {
479         MEDIA_WARN_LOG("No rows to iterate: %{public}d", count);
480         return E_SUCCESS;
481     }
482     err = resultSet->GoToFirstRow();
483     if (err != E_OK) {
484         return E_HAS_DB_ERROR;
485     }
486     do {
487         err = func(resultSet);
488         if (err < 0) {
489             if (ignoreFailure) {
490                 MEDIA_WARN_LOG("Ignore failure for resultSet operation: %{public}d", err);
491             } else {
492                 return err;
493             }
494         }
495         count--;
496         if (count > 0) {
497             err = resultSet->GoToNextRow();
498             if (err < 0) {
499                 return E_HAS_DB_ERROR;
500             }
501         }
502     } while (count > 0);
503     return E_SUCCESS;
504 }
505 
GetInt(const shared_ptr<ResultSet> & resultSet,const string & column)506 static inline int32_t GetInt(const shared_ptr<ResultSet> &resultSet, const string &column)
507 {
508     return get<int32_t>(ResultSetUtils::GetValFromColumn(column, resultSet, TYPE_INT32));
509 }
510 
GetString(const shared_ptr<ResultSet> & resultSet,const string & column)511 static inline string GetString(const shared_ptr<ResultSet> &resultSet, const string &column)
512 {
513     return get<string>(ResultSetUtils::GetValFromColumn(column, resultSet, TYPE_STRING));
514 }
515 
GetFileCount(const shared_ptr<ResultSet> & resultSet)516 static inline int32_t GetFileCount(const shared_ptr<ResultSet> &resultSet)
517 {
518     int32_t count = 0;
519     int32_t err = resultSet->GetRowCount(count);
520     if (err != E_OK) {
521         return 0;
522     }
523     return count;
524 }
525 
GetAlbumCount(const shared_ptr<ResultSet> & resultSet)526 static inline int32_t GetAlbumCount(const shared_ptr<ResultSet> &resultSet)
527 {
528     return GetInt(resultSet, PhotoAlbumColumns::ALBUM_COUNT);
529 }
530 
GetAlbumCover(const shared_ptr<ResultSet> & resultSet)531 static inline string GetAlbumCover(const shared_ptr<ResultSet> &resultSet)
532 {
533     return GetString(resultSet, PhotoAlbumColumns::ALBUM_COVER_URI);
534 }
535 
GetAlbumId(const shared_ptr<ResultSet> & resultSet)536 static inline int32_t GetAlbumId(const shared_ptr<ResultSet> &resultSet)
537 {
538     return GetInt(resultSet, PhotoAlbumColumns::ALBUM_ID);
539 }
540 
GetAlbumSubType(const shared_ptr<ResultSet> & resultSet)541 static inline int32_t GetAlbumSubType(const shared_ptr<ResultSet> &resultSet)
542 {
543     return GetInt(resultSet, PhotoAlbumColumns::ALBUM_SUBTYPE);
544 }
545 
GetCover(const shared_ptr<ResultSet> & resultSet)546 static inline string GetCover(const shared_ptr<ResultSet> &resultSet)
547 {
548     string coverUri;
549     int32_t fileId = GetInt(resultSet, PhotoColumn::MEDIA_ID);
550     if (fileId <= 0) {
551         return coverUri;
552     }
553 
554     string extrUri = MediaFileUtils::GetExtraUri(GetString(resultSet, PhotoColumn::MEDIA_NAME),
555         GetString(resultSet, PhotoColumn::MEDIA_FILE_PATH));
556     return MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(fileId), extrUri);
557 }
558 
SetCount(const shared_ptr<ResultSet> & fileResult,const shared_ptr<ResultSet> & albumResult,ValuesBucket & values)559 static void SetCount(const shared_ptr<ResultSet> &fileResult, const shared_ptr<ResultSet> &albumResult,
560     ValuesBucket &values)
561 {
562     int32_t oldCount = GetAlbumCount(albumResult);
563     int32_t newCount = GetFileCount(fileResult);
564     if (oldCount != newCount) {
565         MEDIA_INFO_LOG("Update album count. oldCount: %{public}d, newCount: %{public}d", oldCount, newCount);
566         values.PutInt(PhotoAlbumColumns::ALBUM_COUNT, newCount);
567     }
568 }
569 
SetCover(const shared_ptr<ResultSet> & fileResult,const shared_ptr<ResultSet> & albumResult,ValuesBucket & values)570 static void SetCover(const shared_ptr<ResultSet> &fileResult, const shared_ptr<ResultSet> &albumResult,
571     ValuesBucket &values)
572 {
573     string newCover;
574     int32_t newCount = GetFileCount(fileResult);
575     if (newCount != 0) {
576         newCover = GetCover(fileResult);
577     }
578     string oldCover = GetAlbumCover(albumResult);
579     if (oldCover != newCover) {
580         MEDIA_INFO_LOG("Update album cover. oldCover: %{public}s, newCover: %{public}s",
581             oldCover.c_str(), newCover.c_str());
582         values.PutString(PhotoAlbumColumns::ALBUM_COVER_URI, newCover);
583     }
584 }
585 
SetUpdateValues(const shared_ptr<ResultSet> & albumResult,ValuesBucket & values,PhotoAlbumSubType subtype)586 static int32_t SetUpdateValues(const shared_ptr<ResultSet> &albumResult, ValuesBucket &values,
587     PhotoAlbumSubType subtype)
588 {
589     const vector<string> columns = {
590         PhotoColumn::MEDIA_ID,
591         PhotoColumn::MEDIA_FILE_PATH,
592         PhotoColumn::MEDIA_NAME
593     };
594 
595     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
596     if (subtype) {
597         PhotoAlbumColumns::GetSystemAlbumPredicates(subtype, predicates);
598     } else {
599         PhotoAlbumColumns::GetUserAlbumPredicates(GetAlbumId(albumResult), predicates);
600     }
601     predicates.OrderByDesc(PhotoColumn::MEDIA_DATE_ADDED);
602     auto fileResult = QueryAlbumAssets(predicates, columns);
603     if (fileResult == nullptr) {
604         return E_HAS_DB_ERROR;
605     }
606 
607     SetCount(fileResult, albumResult, values);
608     SetCover(fileResult, albumResult, values);
609     return E_SUCCESS;
610 }
611 
UpdateUserAlbumIfNeeded(const shared_ptr<ResultSet> & albumResult)612 static int32_t UpdateUserAlbumIfNeeded(const shared_ptr<ResultSet> &albumResult)
613 {
614     TransactionOperations transactionOprn;
615     int32_t err = transactionOprn.Start();
616     if (err != NativeRdb::E_OK) {
617         MEDIA_ERR_LOG("Failed to begin transaction, err: %{public}d", err);
618         return E_HAS_DB_ERROR;
619     }
620     ValuesBucket values;
621     err = SetUpdateValues(albumResult, values, static_cast<PhotoAlbumSubType>(0));
622     if (err < 0) {
623         MEDIA_ERR_LOG("Failed to collect update values, err: %{public}d", err);
624         return err;
625     }
626     if (values.IsEmpty()) {
627         MEDIA_DEBUG_LOG("No need to post-update album.");
628         return E_SUCCESS;
629     }
630 
631     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
632     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(GetAlbumId(albumResult)));
633     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
634     int32_t changedRows = MediaLibraryRdbStore::Update(values, predicates);
635     if (changedRows < 0) {
636         MEDIA_ERR_LOG("Failed to update album in db, err: %{public}d", changedRows);
637         return changedRows;
638     }
639     transactionOprn.Finish();
640     return E_SUCCESS;
641 }
642 
UpdateSysAlbumIfNeeded(const shared_ptr<ResultSet> & albumResult)643 static int32_t UpdateSysAlbumIfNeeded(const shared_ptr<ResultSet> &albumResult)
644 {
645     ValuesBucket values;
646     auto subtype = static_cast<PhotoAlbumSubType>(GetAlbumSubType(albumResult));
647     TransactionOperations transactionOprn;
648     int32_t err = transactionOprn.Start();
649     if (err != NativeRdb::E_OK) {
650         return E_HAS_DB_ERROR;
651     }
652     err = SetUpdateValues(albumResult, values, subtype);
653     if (err < 0) {
654         return err;
655     }
656     if (values.IsEmpty()) {
657         return E_SUCCESS;
658     }
659 
660     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
661     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(subtype));
662     int32_t changedRows = MediaLibraryRdbStore::Update(values, predicates);
663     if (changedRows < 0) {
664         return changedRows;
665     }
666     transactionOprn.Finish();
667     return E_SUCCESS;
668 }
669 
GetUserAlbum(const vector<string> & userAlbumIds,const vector<string> & columns)670 static inline shared_ptr<ResultSet> GetUserAlbum(const vector<string> &userAlbumIds, const vector<string> &columns)
671 {
672     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
673     if (userAlbumIds.empty()) {
674         predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
675     } else {
676         predicates.In(PhotoAlbumColumns::ALBUM_ID, userAlbumIds);
677     }
678     return MediaLibraryRdbStore::Query(predicates, columns);
679 }
680 
GetSystemAlbum(const vector<string> & subtypes,const vector<string> & columns)681 static inline shared_ptr<ResultSet> GetSystemAlbum(const vector<string> &subtypes, const vector<string> &columns)
682 {
683     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
684     if (subtypes.empty()) {
685         predicates.In(PhotoAlbumColumns::ALBUM_SUBTYPE, ALL_SYS_PHOTO_ALBUM);
686     } else {
687         predicates.In(PhotoAlbumColumns::ALBUM_SUBTYPE, subtypes);
688     }
689     return MediaLibraryRdbStore::Query(predicates, columns);
690 }
691 
UpdateUserAlbumInternal(const vector<string> & userAlbumIds)692 void MediaLibraryAlbumOperations::UpdateUserAlbumInternal(const vector<string> &userAlbumIds)
693 {
694     MediaLibraryTracer tracer;
695     tracer.Start("PostUpdateAlbum UpdateUserAlbumInternal");
696 
697     vector<string> columns = {
698         PhotoAlbumColumns::ALBUM_ID,
699         PhotoAlbumColumns::ALBUM_COVER_URI,
700         PhotoAlbumColumns::ALBUM_COUNT,
701     };
702     auto albumResult = GetUserAlbum(userAlbumIds, columns);
703     if (albumResult == nullptr) {
704         MEDIA_WARN_LOG("Ignore failure on post updating user album!");
705         return;
706     }
707     ForEachRow(albumResult, UpdateUserAlbumIfNeeded, true);
708 }
709 
UpdateSystemAlbumInternal(const vector<string> & subtypes)710 void MediaLibraryAlbumOperations::UpdateSystemAlbumInternal(const vector<string> &subtypes)
711 {
712     MediaLibraryTracer tracer;
713     tracer.Start("PostUpdateAlbum MediaLibraryAlbumOperations::UpdateUserAlbumInternal");
714 
715     vector<string> columns = {
716         PhotoAlbumColumns::ALBUM_ID,
717         PhotoAlbumColumns::ALBUM_SUBTYPE,
718         PhotoAlbumColumns::ALBUM_COVER_URI,
719         PhotoAlbumColumns::ALBUM_COUNT,
720     };
721     auto albumResult = GetSystemAlbum(subtypes, columns);
722     if (albumResult == nullptr) {
723         MEDIA_WARN_LOG("Ignore failure on post updating system album!");
724         return;
725     }
726 
727     ForEachRow(albumResult, UpdateSysAlbumIfNeeded, true);
728 }
729 
RecoverPhotoAssets(const DataSharePredicates & predicates)730 int32_t RecoverPhotoAssets(const DataSharePredicates &predicates)
731 {
732     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoColumn::PHOTOS_TABLE);
733     rdbPredicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
734     vector<string> whereArgs = rdbPredicates.GetWhereArgs();
735     MediaLibraryRdbStore::ReplacePredicatesUriToId(rdbPredicates);
736 
737     ValuesBucket rdbValues;
738     rdbValues.PutInt(MediaColumn::MEDIA_DATE_TRASHED, 0);
739 
740     int32_t changedRows = MediaLibraryRdbStore::Update(rdbValues, rdbPredicates);
741     if (changedRows < 0) {
742         return changedRows;
743     }
744     MediaLibraryAlbumOperations::UpdateUserAlbumInternal();
745     MediaLibraryAlbumOperations::UpdateSystemAlbumInternal();
746 
747     auto watch = MediaLibraryNotify::GetInstance();
748     size_t count = whereArgs.size() - THAN_AGR_SIZE;
749     for (size_t i = 0; i < count; i++) {
750         string notifyUri = MediaFileUtils::Encode(whereArgs[i]);
751         watch->Notify(notifyUri, NotifyType::NOTIFY_ADD);
752         watch->Notify(notifyUri, NotifyType::NOTIFY_ALBUM_ADD_ASSERT);
753     }
754     int trashAlbumId = watch->GetAlbumIdBySubType(PhotoAlbumSubType::TRASH);
755     if (trashAlbumId > 0) {
756         for (size_t i = 0; i < count; i++) {
757             watch->Notify(MediaFileUtils::Encode(whereArgs[i]), NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, trashAlbumId);
758         }
759     }
760     return changedRows;
761 }
762 
DeletePhotoAssets(const DataSharePredicates & predicates,bool isAging)763 int32_t DeletePhotoAssets(const DataSharePredicates &predicates, bool isAging)
764 {
765     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoColumn::PHOTOS_TABLE);
766     rdbPredicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
767     vector<string> whereArgs = rdbPredicates.GetWhereArgs();
768     MediaLibraryRdbStore::ReplacePredicatesUriToId(rdbPredicates);
769     vector<string> agingNotifyUris;
770 
771     // Query asset uris for notify before delete.
772     if (isAging) {
773         MediaLibraryNotify::GetNotifyUris(rdbPredicates, agingNotifyUris);
774     }
775     int32_t deletedRows = MediaLibraryRdbStore::DeleteFromDisk(rdbPredicates);
776     MediaLibraryAlbumOperations::UpdateSystemAlbumInternal({ to_string(PhotoAlbumSubType::TRASH) });
777 
778     auto watch = MediaLibraryNotify::GetInstance();
779     int trashAlbumId = watch->GetAlbumIdBySubType(PhotoAlbumSubType::TRASH);
780     if (trashAlbumId <= 0) {
781         return deletedRows;
782     }
783 
784     // Send notify of trash album in aging case.
785     if (isAging) {
786         for (const auto &notifyUri : agingNotifyUris) {
787             watch->Notify(MediaFileUtils::Encode(notifyUri), NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, trashAlbumId);
788         }
789         return deletedRows;
790     }
791 
792     size_t count = whereArgs.size() - THAN_AGR_SIZE;
793     for (size_t i = 0; i < count; i++) {
794         watch->Notify(MediaFileUtils::Encode(whereArgs[i]), NotifyType::NOTIFY_ALBUM_REMOVE_ASSET, trashAlbumId);
795     }
796     return deletedRows;
797 }
798 
AgingPhotoAssets()799 int32_t AgingPhotoAssets()
800 {
801     auto time = MediaFileUtils::UTCTimeSeconds();
802     DataSharePredicates predicates;
803     predicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(0));
804     predicates.And()->LessThanOrEqualTo(MediaColumn::MEDIA_DATE_TRASHED, to_string(time - AGING_TIME));
805     int32_t err = DeletePhotoAssets(predicates, true);
806     if (err < 0) {
807         return err;
808     }
809     return E_OK;
810 }
811 
HandlePhotoAlbum(const OperationType & opType,const ValuesBucket & values,const DataSharePredicates & predicates)812 int32_t MediaLibraryAlbumOperations::HandlePhotoAlbum(const OperationType &opType, const ValuesBucket &values,
813     const DataSharePredicates &predicates)
814 {
815     switch (opType) {
816         case OperationType::UPDATE:
817             return UpdatePhotoAlbum(values, predicates);
818         case OperationType::ALBUM_RECOVER_ASSETS:
819             return RecoverPhotoAssets(predicates);
820         case OperationType::ALBUM_DELETE_ASSETS:
821             return DeletePhotoAssets(predicates, false);
822         case OperationType::AGING:
823             return AgingPhotoAssets();
824         default:
825             MEDIA_ERR_LOG("Unknown operation type: %{public}d", opType);
826             return E_ERR;
827     }
828 }
829 
HandlePhotoAlbumOperations(MediaLibraryCommand & cmd)830 int MediaLibraryAlbumOperations::HandlePhotoAlbumOperations(MediaLibraryCommand &cmd)
831 {
832     switch (cmd.GetOprnType()) {
833         case OperationType::CREATE:
834             return CreatePhotoAlbum(cmd);
835         default:
836             MEDIA_ERR_LOG("Unknown operation type: %{public}d", cmd.GetOprnType());
837             return E_ERR;
838     }
839 }
840 } // namespace OHOS::Media
841