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 ¬ifyUri : 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