• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 
16 #include "medialibrary_rdb_utils.h"
17 
18 #include <functional>
19 #include <iomanip>
20 #include <sstream>
21 #include <string>
22 
23 #include "media_log.h"
24 #include "medialibrary_db_const.h"
25 #include "medialibrary_rdb_transaction.h"
26 #include "medialibrary_tracer.h"
27 #include "photo_album_column.h"
28 #include "photo_map_column.h"
29 #include "result_set.h"
30 #include "userfile_manager_types.h"
31 #include "vision_column.h"
32 
33 namespace OHOS::Media {
34 using namespace std;
35 using namespace NativeRdb;
36 
37 constexpr int32_t E_HAS_DB_ERROR = -222;
38 constexpr int32_t E_SUCCESS = 0;
39 constexpr int32_t ALBUM_UPDATE_THRESHOLD = 10;
40 
41 atomic<bool> MediaLibraryRdbUtils::isNeedRefreshAlbum = false;
42 atomic<bool> MediaLibraryRdbUtils::isInRefreshTask = false;
43 
GetStringValFromColumn(const shared_ptr<ResultSet> & resultSet,const int index)44 static inline string GetStringValFromColumn(const shared_ptr<ResultSet> &resultSet, const int index)
45 {
46     string value;
47     if (resultSet->GetString(index, value)) {
48         return "";
49     }
50     return value;
51 }
52 
GetIntValFromColumn(const shared_ptr<ResultSet> & resultSet,const int index)53 static inline int32_t GetIntValFromColumn(const shared_ptr<ResultSet> &resultSet, const int index)
54 {
55     int32_t value = 0;
56     if (resultSet->GetInt(index, value)) {
57         return 0;
58     }
59     return value;
60 }
61 
GetStringValFromColumn(const shared_ptr<ResultSet> & resultSet,const string & columnName)62 static inline string GetStringValFromColumn(const shared_ptr<ResultSet> &resultSet, const string &columnName)
63 {
64     int32_t index = 0;
65     if (resultSet->GetColumnIndex(columnName, index)) {
66         return "";
67     }
68 
69     return GetStringValFromColumn(resultSet, index);
70 }
71 
GetIntValFromColumn(const shared_ptr<ResultSet> & resultSet,const string & columnName)72 static inline int32_t GetIntValFromColumn(const shared_ptr<ResultSet> &resultSet, const string &columnName)
73 {
74     int32_t index = 0;
75     if (resultSet->GetColumnIndex(columnName, index)) {
76         return 0;
77     }
78 
79     return GetIntValFromColumn(resultSet, index);
80 }
81 
GetUserAlbum(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const vector<string> & userAlbumIds,const vector<string> & columns)82 static inline shared_ptr<ResultSet> GetUserAlbum(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
83     const vector<string> &userAlbumIds, const vector<string> &columns)
84 {
85     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
86     if (userAlbumIds.empty()) {
87         predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
88     } else {
89         predicates.In(PhotoAlbumColumns::ALBUM_ID, userAlbumIds);
90     }
91     if (rdbStore == nullptr) {
92         return nullptr;
93     }
94     return rdbStore->Query(predicates, columns);
95 }
96 
GetAnalysisAlbum(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const vector<string> & analysisAlbumIds,const vector<string> & columns)97 static inline shared_ptr<ResultSet> GetAnalysisAlbum(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
98     const vector<string> &analysisAlbumIds, const vector<string> &columns)
99 {
100     RdbPredicates predicates(ANALYSIS_ALBUM_TABLE);
101     if (!analysisAlbumIds.empty()) {
102         predicates.In(PhotoAlbumColumns::ALBUM_ID, analysisAlbumIds);
103     }
104     if (rdbStore == nullptr) {
105         return nullptr;
106     }
107     return rdbStore->Query(predicates, columns);
108 }
109 
GetSourceAlbum(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const vector<string> & sourceAlbumIds,const vector<string> & columns)110 static inline shared_ptr<ResultSet> GetSourceAlbum(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
111     const vector<string> &sourceAlbumIds, const vector<string> &columns)
112 {
113     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
114     if (!sourceAlbumIds.empty()) {
115         predicates.In(PhotoAlbumColumns::ALBUM_ID, sourceAlbumIds);
116     } else {
117         predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::SOURCE_GENERIC));
118     }
119     if (rdbStore == nullptr) {
120         return nullptr;
121     }
122     return rdbStore->Query(predicates, columns);
123 }
124 
GetQueryFilter(const string & tableName)125 static string GetQueryFilter(const string &tableName)
126 {
127     if (tableName == MEDIALIBRARY_TABLE) {
128         return MEDIALIBRARY_TABLE + "." + MEDIA_DATA_DB_SYNC_STATUS + " = " +
129             to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE));
130     }
131     if (tableName == PhotoColumn::PHOTOS_TABLE) {
132         return PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::PHOTO_SYNC_STATUS + " = " +
133             to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE)) + " AND " +
134             PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::PHOTO_CLEAN_FLAG + " = " +
135             to_string(static_cast<int32_t>(CleanType::TYPE_NOT_CLEAN));
136     }
137     if (tableName == PhotoAlbumColumns::TABLE) {
138         return PhotoAlbumColumns::TABLE + "." + PhotoAlbumColumns::ALBUM_DIRTY + " != " +
139             to_string(static_cast<int32_t>(DirtyTypes::TYPE_DELETED));
140     }
141     if (tableName == PhotoMap::TABLE) {
142         return PhotoMap::TABLE + "." + PhotoMap::DIRTY + " != " + to_string(static_cast<int32_t>(
143             DirtyTypes::TYPE_DELETED));
144     }
145     return "";
146 }
147 
AddQueryFilter(AbsRdbPredicates & predicates)148 void MediaLibraryRdbUtils::AddQueryFilter(AbsRdbPredicates &predicates)
149 {
150     /* build all-table vector */
151     string tableName = predicates.GetTableName();
152     vector<string> joinTables = predicates.GetJoinTableNames();
153     joinTables.push_back(tableName);
154     /* add filters */
155     string filters;
156     for (auto &t : joinTables) {
157         string filter = GetQueryFilter(t);
158         if (filter.empty()) {
159             continue;
160         }
161         if (filters.empty()) {
162             filters += filter;
163         } else {
164             filters += " AND " + filter;
165         }
166     }
167     if (filters.empty()) {
168         return;
169     }
170 
171     /* rebuild */
172     string queryCondition = predicates.GetWhereClause();
173     queryCondition = queryCondition.empty() ? filters : filters + " AND " + queryCondition;
174     predicates.SetWhereClause(queryCondition);
175 }
176 
Query(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const AbsRdbPredicates & predicates,const vector<string> & columns)177 static shared_ptr<AbsSharedResultSet> Query(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
178     const AbsRdbPredicates &predicates, const vector<string> &columns)
179 {
180     MediaLibraryRdbUtils::AddQueryFilter(const_cast<AbsRdbPredicates &>(predicates));
181     if (rdbStore == nullptr) {
182         return nullptr;
183     }
184     return rdbStore->Query(predicates, columns);
185 }
186 
QueryGoToFirst(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const RdbPredicates & predicates,const vector<string> & columns)187 static shared_ptr<ResultSet> QueryGoToFirst(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
188     const RdbPredicates &predicates, const vector<string> &columns)
189 {
190     MediaLibraryTracer tracer;
191     tracer.Start("QueryGoToFirst");
192     auto resultSet = Query(rdbStore, predicates, columns);
193     if (resultSet == nullptr) {
194         return nullptr;
195     }
196 
197     MediaLibraryTracer goToFirst;
198     goToFirst.Start("GoToFirstRow");
199     resultSet->GoToFirstRow();
200     return resultSet;
201 }
202 
ForEachRow(const shared_ptr<RdbStore> & rdbStore,const shared_ptr<ResultSet> & resultSet,const bool hiddenState,const function<int32_t (const shared_ptr<RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,const bool hiddenState)> & func)203 static int32_t ForEachRow(const shared_ptr<RdbStore> &rdbStore, const shared_ptr<ResultSet> &resultSet,
204     const bool hiddenState, const function<int32_t(
205         const shared_ptr<RdbStore> &rdbStore, const shared_ptr<ResultSet> &albumResult, const bool hiddenState)> &func)
206 {
207     TransactionOperations transactionOprn(rdbStore);
208     int32_t err = transactionOprn.Start();
209     if (err != NativeRdb::E_OK) {
210         MEDIA_ERR_LOG("Failed to begin transaction, err: %{public}d", err);
211         return E_HAS_DB_ERROR;
212     }
213     while (resultSet->GoToNextRow() == E_OK) {
214         // Ignore failure here, try to iterate rows as much as possible.
215         func(rdbStore, resultSet, hiddenState);
216     }
217     transactionOprn.Finish();
218     return E_SUCCESS;
219 }
220 
GetFileCount(const shared_ptr<ResultSet> & resultSet)221 static inline int32_t GetFileCount(const shared_ptr<ResultSet> &resultSet)
222 {
223     return GetIntValFromColumn(resultSet, MEDIA_COLUMN_COUNT_1);
224 }
225 
GetPortraitFileCount(const shared_ptr<ResultSet> & resultSet)226 static inline int32_t GetPortraitFileCount(const shared_ptr<ResultSet> &resultSet)
227 {
228     return GetIntValFromColumn(resultSet, MEDIA_COLUMN_COUNT_DISTINCT_FILE_ID);
229 }
230 
GetAlbumCount(const shared_ptr<ResultSet> & resultSet,const string & column)231 static inline int32_t GetAlbumCount(const shared_ptr<ResultSet> &resultSet, const string &column)
232 {
233     return GetIntValFromColumn(resultSet, column);
234 }
235 
GetAlbumCover(const shared_ptr<ResultSet> & resultSet,const string & column)236 static inline string GetAlbumCover(const shared_ptr<ResultSet> &resultSet, const string &column)
237 {
238     return GetStringValFromColumn(resultSet, column);
239 }
240 
GetAlbumId(const shared_ptr<ResultSet> & resultSet)241 static inline int32_t GetAlbumId(const shared_ptr<ResultSet> &resultSet)
242 {
243     return GetIntValFromColumn(resultSet, PhotoAlbumColumns::ALBUM_ID);
244 }
245 
GetAlbumSubType(const shared_ptr<ResultSet> & resultSet)246 static inline int32_t GetAlbumSubType(const shared_ptr<ResultSet> &resultSet)
247 {
248     return GetIntValFromColumn(resultSet, PhotoAlbumColumns::ALBUM_SUBTYPE);
249 }
250 
GetFileName(const string & filePath)251 static string GetFileName(const string &filePath)
252 {
253     string fileName;
254 
255     size_t lastSlash = filePath.rfind('/');
256     if (lastSlash == string::npos) {
257         return fileName;
258     }
259     if (filePath.size() > (lastSlash + 1)) {
260         fileName = filePath.substr(lastSlash + 1);
261     }
262     return fileName;
263 }
264 
GetTitleFromDisplayName(const string & displayName)265 static string GetTitleFromDisplayName(const string &displayName)
266 {
267     auto pos = displayName.find_last_of('.');
268     if (pos == string::npos) {
269         return "";
270     }
271     return displayName.substr(0, pos);
272 }
273 
Encode(const string & uri)274 static string Encode(const string &uri)
275 {
276     const unordered_set<char> uriCompentsSet = {
277         ';', ',', '/', '?', ':', '@', '&',
278         '=', '+', '$', '-', '_', '.', '!',
279         '~', '*', '(', ')', '#', '\''
280     };
281     constexpr int32_t encodeLen = 2;
282     ostringstream outPutStream;
283     outPutStream.fill('0');
284     outPutStream << std::hex;
285 
286     for (unsigned char tmpChar : uri) {
287         if (std::isalnum(tmpChar) || uriCompentsSet.find(tmpChar) != uriCompentsSet.end()) {
288             outPutStream << tmpChar;
289         } else {
290             outPutStream << std::uppercase;
291             outPutStream << '%' << std::setw(encodeLen) << static_cast<unsigned int>(tmpChar);
292             outPutStream << std::nouppercase;
293         }
294     }
295 
296     return outPutStream.str();
297 }
298 
GetExtraUri(const string & displayName,const string & path)299 static string GetExtraUri(const string &displayName, const string &path)
300 {
301     string extraUri = "/" + GetTitleFromDisplayName(GetFileName(path)) + "/" + displayName;
302     return Encode(extraUri);
303 }
304 
GetUriByExtrConditions(const string & prefix,const string & fileId,const string & suffix)305 static string GetUriByExtrConditions(const string &prefix, const string &fileId, const string &suffix)
306 {
307     return prefix + fileId + suffix;
308 }
309 
GetCover(const shared_ptr<ResultSet> & resultSet)310 static inline string GetCover(const shared_ptr<ResultSet> &resultSet)
311 {
312     string coverUri;
313     int32_t fileId = GetIntValFromColumn(resultSet, PhotoColumn::MEDIA_ID);
314     if (fileId <= 0) {
315         return coverUri;
316     }
317 
318     string extrUri = GetExtraUri(GetStringValFromColumn(resultSet, PhotoColumn::MEDIA_NAME),
319         GetStringValFromColumn(resultSet, PhotoColumn::MEDIA_FILE_PATH));
320     return GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(fileId), extrUri);
321 }
322 
SetCount(const shared_ptr<ResultSet> & fileResult,const shared_ptr<ResultSet> & albumResult,ValuesBucket & values,const bool hiddenState,PhotoAlbumSubType subtype)323 static int32_t SetCount(const shared_ptr<ResultSet> &fileResult, const shared_ptr<ResultSet> &albumResult,
324     ValuesBucket &values, const bool hiddenState, PhotoAlbumSubType subtype)
325 {
326     const string &targetColumn = hiddenState ? PhotoAlbumColumns::HIDDEN_COUNT : PhotoAlbumColumns::ALBUM_COUNT;
327     int32_t oldCount = GetAlbumCount(albumResult, targetColumn);
328     int32_t newCount;
329     if (subtype == PORTRAIT) {
330         newCount = GetPortraitFileCount(fileResult);
331     } else {
332         newCount = GetFileCount(fileResult);
333     }
334     if (oldCount != newCount) {
335         MEDIA_INFO_LOG("Update album %{public}s, oldCount: %{public}d, newCount: %{public}d",
336             targetColumn.c_str(), oldCount, newCount);
337         values.PutInt(targetColumn, newCount);
338         if (hiddenState) {
339             MEDIA_INFO_LOG("Update album contains hidden: %{public}d", newCount != 0);
340             values.PutInt(PhotoAlbumColumns::CONTAINS_HIDDEN, newCount != 0);
341         }
342     }
343     return newCount;
344 }
345 
SetCover(const shared_ptr<ResultSet> & fileResult,const shared_ptr<ResultSet> & albumResult,ValuesBucket & values,const bool hiddenState,PhotoAlbumSubType subtype)346 static void SetCover(const shared_ptr<ResultSet> &fileResult, const shared_ptr<ResultSet> &albumResult,
347     ValuesBucket &values, const bool hiddenState, PhotoAlbumSubType subtype)
348 {
349     string newCover;
350     int32_t newCount;
351     if (subtype == PORTRAIT) {
352         newCount = GetPortraitFileCount(fileResult);
353     } else {
354         newCount = GetFileCount(fileResult);
355     }
356     if (newCount != 0) {
357         newCover = GetCover(fileResult);
358     }
359     const string &targetColumn = hiddenState ? PhotoAlbumColumns::HIDDEN_COVER : PhotoAlbumColumns::ALBUM_COVER_URI;
360     string oldCover = GetAlbumCover(albumResult, targetColumn);
361     if (oldCover != newCover) {
362         MEDIA_INFO_LOG("Update album %{public}s. oldCover: %{private}s, newCover: %{private}s",
363             targetColumn.c_str(), oldCover.c_str(), newCover.c_str());
364         values.PutString(targetColumn, newCover);
365     }
366 }
367 
GetAlbumPredicates(PhotoAlbumSubType subtype,const shared_ptr<ResultSet> & albumResult,NativeRdb::RdbPredicates & predicates,const bool hiddenState)368 static void GetAlbumPredicates(PhotoAlbumSubType subtype, const shared_ptr<ResultSet> &albumResult,
369     NativeRdb::RdbPredicates &predicates, const bool hiddenState)
370 {
371     if (!subtype) {
372         PhotoAlbumColumns::GetUserAlbumPredicates(GetAlbumId(albumResult), predicates, hiddenState);
373     } else if (subtype == PhotoAlbumSubType::PORTRAIT) {
374         PhotoAlbumColumns::GetPortraitAlbumPredicates(GetAlbumId(albumResult), predicates, hiddenState);
375     } else if (subtype >= PhotoAlbumSubType::ANALYSIS_START && subtype <= PhotoAlbumSubType::ANALYSIS_END) {
376         PhotoAlbumColumns::GetAnalysisAlbumPredicates(GetAlbumId(albumResult), predicates, hiddenState);
377     } else if (subtype == PhotoAlbumSubType::SOURCE_GENERIC) {
378         PhotoAlbumColumns::GetSourceAlbumPredicates(GetAlbumId(albumResult), predicates, hiddenState);
379     } else {
380         PhotoAlbumColumns::GetSystemAlbumPredicates(subtype, predicates, hiddenState);
381     }
382 }
383 
SetImageVideoCount(int32_t newTotalCount,const shared_ptr<ResultSet> & fileResultVideo,const shared_ptr<ResultSet> & albumResult,ValuesBucket & values)384 static void SetImageVideoCount(int32_t newTotalCount,
385     const shared_ptr<ResultSet> &fileResultVideo, const shared_ptr<ResultSet> &albumResult,
386     ValuesBucket &values)
387 {
388     int32_t oldVideoCount = GetAlbumCount(albumResult, PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
389     int32_t newVideoCount = GetFileCount(fileResultVideo);
390     if (oldVideoCount != newVideoCount) {
391         MEDIA_INFO_LOG("Update album %{public}s, oldCount: %{public}d, newCount: %{public}d",
392             PhotoAlbumColumns::ALBUM_VIDEO_COUNT.c_str(), oldVideoCount, newVideoCount);
393         values.PutInt(PhotoAlbumColumns::ALBUM_VIDEO_COUNT, newVideoCount);
394     }
395     int32_t oldImageCount = GetAlbumCount(albumResult, PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
396     int32_t newImageCount = newTotalCount - newVideoCount;
397     if (oldImageCount != newImageCount) {
398         MEDIA_INFO_LOG("Update album %{public}s, oldCount: %{public}d, newCount: %{public}d",
399             PhotoAlbumColumns::ALBUM_IMAGE_COUNT.c_str(), oldImageCount, newImageCount);
400         values.PutInt(PhotoAlbumColumns::ALBUM_IMAGE_COUNT, newImageCount);
401     }
402 }
403 
QueryAlbumCount(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,PhotoAlbumSubType subtype)404 static int32_t QueryAlbumCount(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
405     const shared_ptr<ResultSet> &albumResult, PhotoAlbumSubType subtype)
406 {
407     const vector<string> columns = { MEDIA_COLUMN_COUNT_1 };
408     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
409     if (subtype == PhotoAlbumSubType::USER_GENERIC) {
410         GetAlbumPredicates(static_cast<PhotoAlbumSubType>(0), albumResult, predicates, false);
411     } else {
412         GetAlbumPredicates(subtype, albumResult, predicates, false);
413     }
414     auto fetchResult = QueryGoToFirst(rdbStore, predicates, columns);
415     if (fetchResult == nullptr) {
416         return E_HAS_DB_ERROR;
417     }
418     return GetFileCount(fetchResult);
419 }
420 
QueryAlbumVideoCount(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,PhotoAlbumSubType subtype)421 static int32_t QueryAlbumVideoCount(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
422     const shared_ptr<ResultSet> &albumResult, PhotoAlbumSubType subtype)
423 {
424     const vector<string> columns = { MEDIA_COLUMN_COUNT_1 };
425     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
426     if (subtype == PhotoAlbumSubType::USER_GENERIC) {
427         GetAlbumPredicates(static_cast<PhotoAlbumSubType>(0), albumResult, predicates, false);
428     } else {
429         GetAlbumPredicates(subtype, albumResult, predicates, false);
430     }
431     predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_MEDIA_TYPE_INDEX);
432     predicates.EqualTo(MediaColumn::MEDIA_TYPE, to_string(MEDIA_TYPE_VIDEO));
433     auto fetchResult = QueryGoToFirst(rdbStore, predicates, columns);
434     if (fetchResult == nullptr) {
435         return E_HAS_DB_ERROR;
436     }
437     return GetFileCount(fetchResult);
438 }
439 
QueryAlbumHiddenCount(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,PhotoAlbumSubType subtype)440 static int32_t QueryAlbumHiddenCount(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
441     const shared_ptr<ResultSet> &albumResult, PhotoAlbumSubType subtype)
442 {
443     const vector<string> columns = { MEDIA_COLUMN_COUNT_1 };
444     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
445     if (subtype == PhotoAlbumSubType::USER_GENERIC) {
446         GetAlbumPredicates(static_cast<PhotoAlbumSubType>(0), albumResult, predicates, true);
447     } else {
448         GetAlbumPredicates(subtype, albumResult, predicates, true);
449     }
450     auto fetchResult = QueryGoToFirst(rdbStore, predicates, columns);
451     if (fetchResult == nullptr) {
452         return E_HAS_DB_ERROR;
453     }
454     return GetFileCount(fetchResult);
455 }
456 
SetAlbumCounts(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,PhotoAlbumSubType subtype,AlbumCounts & albumCounts)457 static int32_t SetAlbumCounts(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
458     const shared_ptr<ResultSet> &albumResult, PhotoAlbumSubType subtype, AlbumCounts &albumCounts)
459 {
460     int ret = QueryAlbumCount(rdbStore, albumResult, subtype);
461     if (ret < E_SUCCESS) {
462         MEDIA_ERR_LOG("Failed to QueryAlbumCount, ret:%{public}d", ret);
463         return ret;
464     }
465     albumCounts.count = ret;
466 
467     ret = QueryAlbumVideoCount(rdbStore, albumResult, subtype);
468     if (ret < E_SUCCESS) {
469         MEDIA_ERR_LOG("Failed to QueryAlbumVideoCount, ret:%{public}d", ret);
470         return ret;
471     }
472     albumCounts.videoCount = ret;
473     albumCounts.imageCount = albumCounts.count - albumCounts.videoCount;
474 
475     ret = QueryAlbumHiddenCount(rdbStore, albumResult, subtype);
476     if (ret < E_SUCCESS) {
477         MEDIA_ERR_LOG("Failed to QueryAlbumCount, ret:%{public}d", ret);
478         return ret;
479     }
480     albumCounts.hiddenCount = ret;
481     return E_SUCCESS;
482 }
483 
SetAlbumCoverUri(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,PhotoAlbumSubType subtype,string & uri)484 static int32_t SetAlbumCoverUri(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
485     const shared_ptr<ResultSet> &albumResult, PhotoAlbumSubType subtype, string &uri)
486 {
487     const vector<string> columns = {
488         PhotoColumn::MEDIA_ID,
489         PhotoColumn::MEDIA_FILE_PATH,
490         PhotoColumn::MEDIA_NAME
491     };
492     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
493     if (subtype == PhotoAlbumSubType::HIDDEN) {
494         GetAlbumPredicates(subtype, albumResult, predicates, true);
495         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_HIDDEN_TIME_INDEX);
496     } else if (subtype == PhotoAlbumSubType::USER_GENERIC) {
497         GetAlbumPredicates(static_cast<PhotoAlbumSubType>(0), albumResult, predicates, false);
498         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_ADDED_INDEX);
499     } else {
500         GetAlbumPredicates(subtype, albumResult, predicates, false);
501         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_ADDED_INDEX);
502     }
503     predicates.Limit(1);
504 
505     auto fetchResult = QueryGoToFirst(rdbStore, predicates, columns);
506     if (fetchResult == nullptr) {
507         MEDIA_ERR_LOG("QueryGoToFirst failed");
508         return E_HAS_DB_ERROR;
509     }
510     uri = GetCover(fetchResult);
511     return E_SUCCESS;
512 }
513 
SetAlbumCoverHiddenUri(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,PhotoAlbumSubType subtype,string & uri)514 static int32_t SetAlbumCoverHiddenUri(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
515     const shared_ptr<ResultSet> &albumResult, PhotoAlbumSubType subtype, string &uri)
516 {
517     const vector<string> columns = {
518         PhotoColumn::MEDIA_ID,
519         PhotoColumn::MEDIA_FILE_PATH,
520         PhotoColumn::MEDIA_NAME
521     };
522     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
523     if (subtype == PhotoAlbumSubType::USER_GENERIC) {
524         GetAlbumPredicates(static_cast<PhotoAlbumSubType>(0), albumResult, predicates, true);
525         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_HIDDEN_TIME_INDEX);
526     } else {
527         GetAlbumPredicates(subtype, albumResult, predicates, true);
528         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_HIDDEN_TIME_INDEX);
529     }
530     predicates.Limit(1);
531     auto fetchResult = QueryGoToFirst(rdbStore, predicates, columns);
532     if (fetchResult == nullptr) {
533         MEDIA_ERR_LOG("QueryGoToFirst failed");
534         return E_HAS_DB_ERROR;
535     }
536     uri = GetCover(fetchResult);
537     return E_SUCCESS;
538 }
539 
FillOneAlbumCountAndCoverUri(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,PhotoAlbumSubType subtype,string & sql)540 static int32_t FillOneAlbumCountAndCoverUri(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
541     const shared_ptr<ResultSet> &albumResult, PhotoAlbumSubType subtype, string &sql)
542 {
543     AlbumCounts albumCounts = { 0, 0, 0, 0 };
544     int32_t ret = SetAlbumCounts(rdbStore, albumResult, subtype, albumCounts);
545     if (ret != E_SUCCESS) {
546         return ret;
547     }
548     string coverUri;
549     ret = SetAlbumCoverUri(rdbStore, albumResult, subtype, coverUri);
550     if (ret != E_SUCCESS) {
551         return ret;
552     }
553     string coverHiddenUri;
554     if (albumCounts.hiddenCount != 0) {
555         ret = SetAlbumCoverHiddenUri(rdbStore, albumResult, subtype, coverHiddenUri);
556         if (ret != E_SUCCESS) {
557             return ret;
558         }
559     }
560 
561     int32_t albumId = GetAlbumId(albumResult);
562     if (albumId < 0) {
563         MEDIA_ERR_LOG("Can not get correct albumId, error albumId is %{public}d", albumId);
564         return E_HAS_DB_ERROR;
565     }
566     string coverUriSql = PhotoAlbumColumns::ALBUM_COVER_URI;
567     if (coverUri.empty()) {
568         coverUriSql += " = NULL";
569     } else {
570         coverUriSql += " = '" + coverUri + "'";
571     }
572     string coverHiddenUriSql = PhotoAlbumColumns::HIDDEN_COVER;
573     if (coverHiddenUri.empty()) {
574         coverHiddenUriSql += " = NULL";
575     } else {
576         coverHiddenUriSql += " = '" + coverHiddenUri + "'";
577     }
578 
579     sql = "UPDATE " + PhotoAlbumColumns::TABLE + " SET " +
580         PhotoAlbumColumns::ALBUM_COUNT + " = " + to_string(albumCounts.count) + ", " +
581         PhotoAlbumColumns::ALBUM_IMAGE_COUNT + " = " +  to_string(albumCounts.imageCount) + ", " +
582         PhotoAlbumColumns::ALBUM_VIDEO_COUNT + " = " + to_string(albumCounts.videoCount) + ", " +
583         PhotoAlbumColumns::HIDDEN_COUNT + " = " + to_string(albumCounts.hiddenCount) + ", " +
584         PhotoAlbumColumns::CONTAINS_HIDDEN + " = " + to_string((albumCounts.hiddenCount == 0) ? 0 : 1) + ", " +
585         coverUriSql + ", " + coverHiddenUriSql + " WHERE " +
586         PhotoAlbumColumns::ALBUM_ID + " = " + to_string(albumId) + ";";
587     return E_SUCCESS;
588 }
589 
RefreshAlbums(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,function<void (PhotoAlbumSubType,int)> refreshProcessHandler)590 static int32_t RefreshAlbums(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
591     const shared_ptr<ResultSet> &albumResult, function<void(PhotoAlbumSubType, int)> refreshProcessHandler)
592 {
593     while (albumResult->GoToNextRow() == NativeRdb::E_OK) {
594         auto subtype = static_cast<PhotoAlbumSubType>(GetAlbumSubType(albumResult));
595         int32_t albumId = GetAlbumId(albumResult);
596         string sql;
597         int32_t ret = FillOneAlbumCountAndCoverUri(rdbStore, albumResult, subtype, sql);
598         if (ret != E_SUCCESS) {
599             return ret;
600         }
601 
602         ret = rdbStore->ExecuteSql(sql);
603         if (ret != NativeRdb::E_OK) {
604             MEDIA_ERR_LOG("Failed to execute sql:%{private}s", sql.c_str());
605             return E_HAS_DB_ERROR;
606         }
607         MEDIA_DEBUG_LOG("Execute sql %{private}s success", sql.c_str());
608         refreshProcessHandler(subtype, albumId);
609     }
610 
611     string updateRefreshTableSql = "DELETE FROM " + ALBUM_REFRESH_TABLE;
612     int32_t ret = rdbStore->ExecuteSql(updateRefreshTableSql);
613     if (ret != NativeRdb::E_OK) {
614         MEDIA_ERR_LOG("Failed to execute sql:%{private}s", updateRefreshTableSql.c_str());
615         return E_HAS_DB_ERROR;
616     }
617     MEDIA_DEBUG_LOG("Delete AlbumRefreshTable success");
618     return E_SUCCESS;
619 }
620 
GetAllRefreshAlbumIds(const shared_ptr<NativeRdb::RdbStore> & rdbStore,vector<string> & albumIds)621 static int32_t GetAllRefreshAlbumIds(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
622     vector<string> &albumIds)
623 {
624     RdbPredicates predicates(ALBUM_REFRESH_TABLE);
625     vector<string> columns = { REFRESHED_ALBUM_ID };
626     auto resultSet = rdbStore->Query(predicates, columns);
627     if (resultSet == nullptr) {
628         MEDIA_ERR_LOG("Can not query ALBUM_REFRESH_TABLE");
629         return E_HAS_DB_ERROR;
630     }
631 
632     int32_t count = 0;
633     int32_t ret = resultSet->GetRowCount(count);
634     if (ret != NativeRdb::E_OK) {
635         MEDIA_ERR_LOG("GetRowCount failed ret:%{public}d", ret);
636         return E_HAS_DB_ERROR;
637     }
638     if (count == 0) {
639         MEDIA_DEBUG_LOG("count is zero, break");
640         return E_SUCCESS;
641     }
642 
643     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
644         int32_t columnIndex = 0;
645         ret = resultSet->GetColumnIndex(REFRESHED_ALBUM_ID, columnIndex);
646         if (ret != NativeRdb::E_OK) {
647             MEDIA_ERR_LOG("GetColumnIndex failed ret:%{public}d", ret);
648             return E_HAS_DB_ERROR;
649         }
650         int32_t refreshAlbumId = 0;
651         ret = resultSet->GetInt(columnIndex, refreshAlbumId);
652         if (ret != NativeRdb::E_OK) {
653             MEDIA_ERR_LOG("GetInt failed ret:%{public}d", ret);
654             return E_HAS_DB_ERROR;
655         }
656         albumIds.push_back(to_string(refreshAlbumId));
657     }
658     return E_SUCCESS;
659 }
660 
QueryAlbumById(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const vector<string> & albumIds)661 shared_ptr<AbsSharedResultSet> QueryAlbumById(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
662     const vector<string> &albumIds)
663 {
664     vector<string> columns = {
665         PhotoAlbumColumns::ALBUM_ID,
666         PhotoAlbumColumns::ALBUM_SUBTYPE
667     };
668     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
669     predicates.In(PhotoAlbumColumns::ALBUM_ID, albumIds);
670     auto resultSet = rdbStore->Query(predicates, columns);
671     if (resultSet == nullptr) {
672         MEDIA_ERR_LOG("Can not Query from rdb");
673         return nullptr;
674     }
675     return resultSet;
676 }
677 
RefreshAllAlbums(const shared_ptr<NativeRdb::RdbStore> & rdbStore,function<void (PhotoAlbumSubType,int)> refreshProcessHandler,function<void ()> refreshCallback)678 int32_t MediaLibraryRdbUtils::RefreshAllAlbums(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
679     function<void(PhotoAlbumSubType, int)> refreshProcessHandler, function<void()> refreshCallback)
680 {
681     isInRefreshTask = true;
682 
683     MediaLibraryTracer tracer;
684     tracer.Start("RefreshAllAlbums");
685 
686     if (rdbStore == nullptr) {
687         MEDIA_ERR_LOG("Can not get rdb");
688         return E_HAS_DB_ERROR;
689     }
690 
691     int ret = E_SUCCESS;
692     bool isRefresh = false;
693     while (IsNeedRefreshAlbum()) {
694         SetNeedRefreshAlbum(false);
695         vector<string> albumIds;
696         ret = GetAllRefreshAlbumIds(rdbStore, albumIds);
697         if (ret != E_SUCCESS) {
698             break;
699         }
700         if (albumIds.empty()) {
701             MEDIA_DEBUG_LOG("albumIds is empty");
702             continue;
703         }
704         auto resultSet = QueryAlbumById(rdbStore, albumIds);
705         if (resultSet == nullptr) {
706             ret = E_HAS_DB_ERROR;
707             break;
708         }
709         ret = RefreshAlbums(rdbStore, resultSet, refreshProcessHandler);
710         if (ret != E_SUCCESS) {
711             break;
712         }
713         isRefresh = true;
714     }
715 
716     if (ret != E_SUCCESS) {
717         // refresh failed and set flag, try to refresh next time
718         SetNeedRefreshAlbum(true);
719     } else {
720         // refresh task is successful
721         SetNeedRefreshAlbum(false);
722     }
723     isInRefreshTask = false;
724     if (isRefresh) {
725         refreshCallback();
726     }
727 
728     return ret;
729 }
730 
IsNeedRefreshByCheckTable(const shared_ptr<NativeRdb::RdbStore> & rdbStore,bool & signal)731 int32_t MediaLibraryRdbUtils::IsNeedRefreshByCheckTable(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
732     bool &signal)
733 {
734     if (rdbStore == nullptr) {
735         MEDIA_ERR_LOG("rdb is nullptr");
736         return E_HAS_DB_ERROR;
737     }
738 
739     RdbPredicates predicates(ALBUM_REFRESH_TABLE);
740     vector<string> columns = { REFRESHED_ALBUM_ID };
741     auto resultSet = rdbStore->Query(predicates, columns);
742     if (resultSet == nullptr) {
743         MEDIA_ERR_LOG("Can not query ALBUM_REFRESH_TABLE");
744         return E_HAS_DB_ERROR;
745     }
746 
747     int32_t count = 0;
748     int32_t ret = resultSet->GetRowCount(count);
749     if (ret != NativeRdb::E_OK) {
750         MEDIA_ERR_LOG("GetRowCount failed ret:%{public}d", ret);
751         return E_HAS_DB_ERROR;
752     }
753     if (count == 0) {
754         MEDIA_DEBUG_LOG("count is zero, should not refresh");
755         signal = false;
756     } else {
757         MEDIA_DEBUG_LOG("count is %{public}d, should refresh", count);
758         signal = true;
759     }
760     return E_SUCCESS;
761 }
762 
IsNeedRefreshAlbum()763 bool MediaLibraryRdbUtils::IsNeedRefreshAlbum()
764 {
765     return isNeedRefreshAlbum.load();
766 }
767 
SetNeedRefreshAlbum(bool isNeedRefresh)768 void MediaLibraryRdbUtils::SetNeedRefreshAlbum(bool isNeedRefresh)
769 {
770     isNeedRefreshAlbum = isNeedRefresh;
771 }
772 
IsInRefreshTask()773 bool MediaLibraryRdbUtils::IsInRefreshTask()
774 {
775     return isInRefreshTask.load();
776 }
777 
SetUpdateValues(const shared_ptr<NativeRdb::RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,ValuesBucket & values,PhotoAlbumSubType subtype,const bool hiddenState)778 static int32_t SetUpdateValues(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
779     const shared_ptr<ResultSet> &albumResult, ValuesBucket &values, PhotoAlbumSubType subtype, const bool hiddenState)
780 {
781     string countColumn = MEDIA_COLUMN_COUNT_1;
782     if (subtype == PORTRAIT) {
783         countColumn = MEDIA_COLUMN_COUNT_DISTINCT_FILE_ID;
784     }
785     const vector<string> columns = {
786         countColumn,
787         PhotoColumn::MEDIA_ID,
788         PhotoColumn::MEDIA_FILE_PATH,
789         PhotoColumn::MEDIA_NAME
790     };
791 
792     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
793     GetAlbumPredicates(subtype, albumResult, predicates, hiddenState);
794     if (subtype == PhotoAlbumSubType::HIDDEN || hiddenState) {
795         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_HIDDEN_TIME_INDEX);
796     } else if (subtype == PhotoAlbumSubType::VIDEO || subtype == PhotoAlbumSubType::IMAGE) {
797         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_MEDIA_TYPE_INDEX);
798     } else if (subtype == PhotoAlbumSubType::FAVORITE) {
799         predicates.IndexedBy(PhotoColumn::PHOTO_FAVORITE_INDEX);
800     } else {
801         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_ADDED_INDEX);
802     }
803     auto fileResult = QueryGoToFirst(rdbStore, predicates, columns);
804     if (fileResult == nullptr) {
805         return E_HAS_DB_ERROR;
806     }
807     int32_t newCount = SetCount(fileResult, albumResult, values, hiddenState, subtype);
808     SetCover(fileResult, albumResult, values, hiddenState, subtype);
809     if (hiddenState == 0 && (subtype < PhotoAlbumSubType::ANALYSIS_START ||
810         subtype > PhotoAlbumSubType::ANALYSIS_END)) {
811         predicates.Clear();
812         GetAlbumPredicates(subtype, albumResult, predicates, hiddenState);
813         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_MEDIA_TYPE_INDEX);
814         predicates.EqualTo(MediaColumn::MEDIA_TYPE, to_string(MEDIA_TYPE_VIDEO));
815         auto fileResultVideo = QueryGoToFirst(rdbStore, predicates, columns);
816         if (fileResultVideo == nullptr) {
817             return E_HAS_DB_ERROR;
818         }
819         SetImageVideoCount(newCount, fileResultVideo, albumResult, values);
820     }
821     return E_SUCCESS;
822 }
823 
GetPhotoId(const std::string & uri)824 static std::string GetPhotoId(const std::string &uri)
825 {
826     if (uri.compare(0, PhotoColumn::PHOTO_URI_PREFIX.size(),
827         PhotoColumn::PHOTO_URI_PREFIX) != 0) {
828         return "";
829     }
830     std::string tmp = uri.substr(PhotoColumn::PHOTO_URI_PREFIX.size());
831     return tmp.substr(0, tmp.find_first_of('/'));
832 }
833 
QueryAlbumId(const shared_ptr<RdbStore> & rdbStore,const RdbPredicates predicates,vector<string> & albumId)834 static void QueryAlbumId(const shared_ptr<RdbStore> &rdbStore, const RdbPredicates predicates,
835     vector<string> &albumId)
836 {
837     const vector<string> columns = {
838         PhotoMap::ALBUM_ID
839     };
840     auto resultSet = rdbStore->Query(predicates, columns);
841     if (resultSet == nullptr) {
842         MEDIA_WARN_LOG("Failed to Query");
843         return;
844     }
845     while (resultSet->GoToNextRow() == E_OK) {
846         albumId.push_back(to_string(GetIntValFromColumn(resultSet, 0)));
847     }
848 }
849 
UpdateUserAlbumIfNeeded(const shared_ptr<RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,const bool hiddenState)850 static int32_t UpdateUserAlbumIfNeeded(const shared_ptr<RdbStore> &rdbStore, const shared_ptr<ResultSet> &albumResult,
851     const bool hiddenState)
852 {
853     MediaLibraryTracer tracer;
854     tracer.Start("UpdateUserAlbumIfNeeded");
855     ValuesBucket values;
856     int err = SetUpdateValues(rdbStore, albumResult, values, static_cast<PhotoAlbumSubType>(0), hiddenState);
857     if (err < 0) {
858         return err;
859     }
860     if (values.IsEmpty()) {
861         return E_SUCCESS;
862     }
863 
864     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
865     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(GetAlbumId(albumResult)));
866     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(PhotoAlbumSubType::USER_GENERIC));
867     int32_t changedRows = 0;
868     err = rdbStore->Update(changedRows, values, predicates);
869     if (err < 0) {
870         MEDIA_WARN_LOG("Failed to update album count and cover! err: %{public}d", err);
871     }
872     return E_SUCCESS;
873 }
874 
UpdateAnalysisAlbumIfNeeded(const shared_ptr<RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,const bool hiddenState)875 static int32_t UpdateAnalysisAlbumIfNeeded(const shared_ptr<RdbStore> &rdbStore,
876     const shared_ptr<ResultSet> &albumResult, const bool hiddenState)
877 {
878     MediaLibraryTracer tracer;
879     tracer.Start("UpdateAnalysisAlbumIfNeeded");
880     ValuesBucket values;
881     auto subtype = static_cast<PhotoAlbumSubType>(GetAlbumSubType(albumResult));
882     int err = SetUpdateValues(rdbStore, albumResult, values, subtype, hiddenState);
883     if (err < 0) {
884         return err;
885     }
886     if (values.IsEmpty()) {
887         return E_SUCCESS;
888     }
889 
890     RdbPredicates predicates(ANALYSIS_ALBUM_TABLE);
891     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(GetAlbumId(albumResult)));
892     int32_t changedRows = 0;
893     err = rdbStore->Update(changedRows, values, predicates);
894     if (err < 0) {
895         MEDIA_WARN_LOG("Failed to update album count and cover! err: %{public}d", err);
896         return err;
897     }
898     return E_SUCCESS;
899 }
900 
UpdateSourceAlbumIfNeeded(const shared_ptr<RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,const bool hiddenState)901 static int32_t UpdateSourceAlbumIfNeeded(const shared_ptr<RdbStore> &rdbStore, const shared_ptr<ResultSet> &albumResult,
902     const bool hiddenState)
903 {
904     MediaLibraryTracer tracer;
905     tracer.Start("UpdateSourceAlbumIfNeeded");
906     ValuesBucket values;
907     auto subtype = static_cast<PhotoAlbumSubType>(GetAlbumSubType(albumResult));
908     int err = SetUpdateValues(rdbStore, albumResult, values, subtype, hiddenState);
909     if (err < 0) {
910         return err;
911     }
912     if (values.IsEmpty()) {
913         return E_SUCCESS;
914     }
915 
916     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
917     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(GetAlbumId(albumResult)));
918     int32_t changedRows = 0;
919     err = rdbStore->Update(changedRows, values, predicates);
920     if (err < 0) {
921         MEDIA_WARN_LOG("Failed to update album count and cover! err: %{public}d", err);
922         return err;
923     }
924     return E_SUCCESS;
925 }
926 
UpdateSysAlbumIfNeeded(const shared_ptr<RdbStore> & rdbStore,const shared_ptr<ResultSet> & albumResult,const bool hiddenState)927 static int32_t UpdateSysAlbumIfNeeded(const shared_ptr<RdbStore> &rdbStore,
928     const shared_ptr<ResultSet> &albumResult, const bool hiddenState)
929 {
930     ValuesBucket values;
931     auto subtype = static_cast<PhotoAlbumSubType>(GetAlbumSubType(albumResult));
932     MediaLibraryTracer tracer;
933     tracer.Start("UpdateSysAlbum: " + to_string(subtype));
934     int err = SetUpdateValues(rdbStore, albumResult, values, subtype, hiddenState);
935     if (err < 0) {
936         return err;
937     }
938     if (values.IsEmpty()) {
939         return E_SUCCESS;
940     }
941 
942     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
943     predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(subtype));
944     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(GetAlbumId(albumResult)));
945     int32_t changedRows = 0;
946     err = rdbStore->Update(changedRows, values, predicates);
947     if (err < 0) {
948         MEDIA_WARN_LOG("Failed to update album count and cover! err: %{public}d", err);
949     }
950     return E_SUCCESS;
951 }
952 
UpdateUserAlbumByUri(const shared_ptr<RdbStore> & rdbStore,const vector<string> & uris)953 void MediaLibraryRdbUtils::UpdateUserAlbumByUri(const shared_ptr<RdbStore> &rdbStore,
954     const vector<string> &uris)
955 {
956     MediaLibraryTracer tracer;
957     tracer.Start("UpdateUserAlbumByUri");
958 
959     if (uris.size() == 0) {
960         UpdateUserAlbumInternal(rdbStore);
961     }
962     vector<string> albumIds;
963     for (const auto &arg : uris) {
964         string fileId = GetPhotoId(arg);
965         if (fileId.size() == 0) {
966             continue;
967         }
968         RdbPredicates predicates(PhotoMap::TABLE);
969         predicates.SetWhereClause(PhotoMap::ASSET_ID + " = ? and " +
970             PhotoMap::ALBUM_ID + " in(select album_id from PhotoAlbum where album_type = " +
971             to_string(PhotoAlbumType::USER) + ")");
972         predicates.SetWhereArgs({fileId});
973         QueryAlbumId(rdbStore, predicates, albumIds);
974     }
975     if (albumIds.size() > 0) {
976         UpdateUserAlbumInternal(rdbStore, albumIds);
977     }
978 }
979 
UpdateUserAlbumInternal(const shared_ptr<RdbStore> & rdbStore,const vector<string> & userAlbumIds)980 void MediaLibraryRdbUtils::UpdateUserAlbumInternal(const shared_ptr<RdbStore> &rdbStore,
981     const vector<string> &userAlbumIds)
982 {
983     MediaLibraryTracer tracer;
984     tracer.Start("UpdateUserAlbumInternal");
985 
986     vector<string> columns = {
987         PhotoAlbumColumns::ALBUM_ID,
988         PhotoAlbumColumns::ALBUM_COVER_URI,
989         PhotoAlbumColumns::ALBUM_COUNT,
990         PhotoAlbumColumns::ALBUM_IMAGE_COUNT,
991         PhotoAlbumColumns::ALBUM_VIDEO_COUNT,
992     };
993     auto albumResult = GetUserAlbum(rdbStore, userAlbumIds, columns);
994     if (albumResult == nullptr) {
995         return;
996     }
997     ForEachRow(rdbStore, albumResult, false, UpdateUserAlbumIfNeeded);
998 }
999 
UpdateAnalysisAlbumByUri(const shared_ptr<RdbStore> & rdbStore,const vector<string> & uris)1000 void MediaLibraryRdbUtils::UpdateAnalysisAlbumByUri(const shared_ptr<RdbStore> &rdbStore,
1001     const vector<string> &uris)
1002 {
1003     MediaLibraryTracer tracer;
1004     tracer.Start("UpdateAnalysisAlbumByUri");
1005 
1006     if (uris.size() == 0) {
1007         UpdateAnalysisAlbumInternal(rdbStore);
1008     }
1009     vector<string> albumIds;
1010     for (const auto &arg : uris) {
1011         string fileId = GetPhotoId(arg);
1012         if (fileId.size() == 0) {
1013             continue;
1014         }
1015         RdbPredicates predicates(ANALYSIS_PHOTO_MAP_TABLE);
1016         predicates.EqualTo(PhotoMap::ASSET_ID, fileId);
1017         QueryAlbumId(rdbStore, predicates, albumIds);
1018     }
1019     if (albumIds.size() > 0) {
1020         UpdateAnalysisAlbumInternal(rdbStore, albumIds);
1021     }
1022 }
1023 
GetAlbumIdsForPortrait(const shared_ptr<NativeRdb::RdbStore> & rdbStore,vector<string> & portraitAlbumIds)1024 int32_t MediaLibraryRdbUtils::GetAlbumIdsForPortrait(const shared_ptr<NativeRdb::RdbStore> &rdbStore,
1025     vector<string> &portraitAlbumIds)
1026 {
1027     std::stringstream labelIds;
1028     unordered_set<string> resultAlbumIds;
1029     for (int i = 0; i < portraitAlbumIds.size(); i++) {
1030         labelIds << portraitAlbumIds[i];
1031         if (i != portraitAlbumIds.size() - 1) {
1032             labelIds << ",";
1033         }
1034         resultAlbumIds.insert(portraitAlbumIds[i]);
1035     }
1036 
1037     RdbPredicates predicates(ANALYSIS_ALBUM_TABLE);
1038     predicates.SetWhereClause(GROUP_TAG + " IN(SELECT " + GROUP_TAG + " FROM " + ANALYSIS_ALBUM_TABLE +
1039         " WHERE " + ALBUM_ID + " IN (" + labelIds.str() + ") AND " + ALBUM_SUBTYPE + " = " + to_string(PORTRAIT) +")");
1040     vector<string> columns = {
1041         ALBUM_ID,
1042     };
1043     auto resultSet = rdbStore->Query(predicates, columns);
1044     if (resultSet == nullptr) {
1045         return E_HAS_DB_ERROR;
1046     }
1047     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1048         string albumId = to_string(GetIntValFromColumn(resultSet, ALBUM_ID));
1049         if (resultAlbumIds.find(albumId) == resultAlbumIds.end()) {
1050             resultAlbumIds.insert(albumId);
1051             portraitAlbumIds.push_back(albumId);
1052         }
1053     }
1054     return E_OK;
1055 }
1056 
UpdateAnalysisAlbumInternal(const shared_ptr<RdbStore> & rdbStore,const vector<string> & anaAlbumAlbumIds)1057 void MediaLibraryRdbUtils::UpdateAnalysisAlbumInternal(const shared_ptr<RdbStore> &rdbStore,
1058     const vector<string> &anaAlbumAlbumIds)
1059 {
1060     MediaLibraryTracer tracer;
1061     tracer.Start("UpdateAnalysisAlbumInternal");
1062     vector<string> columns = {
1063         PhotoAlbumColumns::ALBUM_ID,
1064         PhotoAlbumColumns::ALBUM_SUBTYPE,
1065         PhotoAlbumColumns::ALBUM_COVER_URI,
1066         PhotoAlbumColumns::ALBUM_COUNT,
1067     };
1068     vector<string> tempAlbumId = anaAlbumAlbumIds;
1069     if (tempAlbumId.size() > 0) {
1070         GetAlbumIdsForPortrait(rdbStore, tempAlbumId);
1071     }
1072     auto albumResult = GetAnalysisAlbum(rdbStore, tempAlbumId, columns);
1073     if (albumResult == nullptr) {
1074         return;
1075     }
1076     ForEachRow(rdbStore, albumResult, false, UpdateAnalysisAlbumIfNeeded);
1077 }
1078 
UpdateAnalysisAlbumByFile(const shared_ptr<RdbStore> & rdbStore,const vector<string> & fileIds,const vector<int> & albumTypes)1079 void MediaLibraryRdbUtils::UpdateAnalysisAlbumByFile(const shared_ptr<RdbStore> &rdbStore,
1080     const vector<string> &fileIds, const vector<int> &albumTypes)
1081 {
1082     if (fileIds.empty()) {
1083         MEDIA_ERR_LOG("Failed to UpdateAnalysisAlbumByFile cause fileIds empty");
1084         return;
1085     }
1086     MediaLibraryTracer tracer;
1087     tracer.Start("UpdateAnalysisAlbumByFile");
1088     vector<string> columns = {
1089         PhotoMap::ALBUM_ID,
1090         PhotoMap::ASSET_ID,
1091     };
1092     RdbPredicates predicates(ANALYSIS_PHOTO_MAP_TABLE);
1093     if (!albumTypes.empty()) {
1094         std::string files;
1095         for (std::string fileId : fileIds) {
1096             files.append(fileId).append(",");
1097         }
1098         files = files.substr(0, files.length() - 1);
1099         std::string subTypes;
1100         for (int subtype : albumTypes) {
1101             subTypes.append(to_string(subtype)).append(",");
1102         }
1103         subTypes = subTypes.substr(0, subTypes.length() - 1);
1104         predicates.SetWhereClause(PhotoMap::ASSET_ID + " in(" + files + ") and " + PhotoMap::ALBUM_ID +
1105             " in(select album_id from AnalysisAlbum where album_subtype in(" + subTypes + "))");
1106     } else {
1107         predicates.In(PhotoMap::ASSET_ID, fileIds);
1108     }
1109     shared_ptr<ResultSet> mapResult = rdbStore->Query(predicates, columns);
1110     if (mapResult == nullptr) {
1111         MEDIA_ERR_LOG("Failed query AnalysisAlbum");
1112         return;
1113     }
1114     vector<string> albumIds;
1115     while (mapResult->GoToNextRow() == E_OK) {
1116         albumIds.push_back(to_string(GetIntValFromColumn(mapResult, PhotoMap::ALBUM_ID)));
1117     }
1118     int err = E_HAS_DB_ERROR;
1119     int32_t deletedRows = 0;
1120     err = rdbStore->Delete(deletedRows, predicates);
1121     if (err != E_OK || deletedRows <= 0) {
1122         MEDIA_ERR_LOG("Failed Delete AnalysisPhotoMap");
1123         return;
1124     }
1125     UpdateAnalysisAlbumInternal(rdbStore, albumIds);
1126 }
1127 
UpdateSourceAlbumByUri(const shared_ptr<RdbStore> & rdbStore,const vector<string> & uris)1128 void MediaLibraryRdbUtils::UpdateSourceAlbumByUri(const shared_ptr<RdbStore> &rdbStore,
1129     const vector<string> &uris)
1130 {
1131     MediaLibraryTracer tracer;
1132     tracer.Start("UpdateSourceAlbumByUri");
1133 
1134     if (uris.size() == 0) {
1135         UpdateSourceAlbumInternal(rdbStore);
1136     }
1137     vector<string> albumIds;
1138     for (const auto &arg : uris) {
1139         string fileId = GetPhotoId(arg);
1140         if (fileId.size() == 0) {
1141             continue;
1142         }
1143         RdbPredicates predicates(PhotoMap::TABLE);
1144         predicates.SetWhereClause(PhotoMap::ASSET_ID + " = ? and " +
1145             PhotoMap::ALBUM_ID + " in(select album_id from PhotoAlbum where album_type = " +
1146             to_string(PhotoAlbumType::SOURCE) + ")");
1147         predicates.SetWhereArgs({fileId});
1148         QueryAlbumId(rdbStore, predicates, albumIds);
1149     }
1150     if (albumIds.size() > 0) {
1151         UpdateSourceAlbumInternal(rdbStore, albumIds);
1152     }
1153 }
1154 
UpdateSourceAlbumInternal(const shared_ptr<RdbStore> & rdbStore,const vector<string> & sourceAlbumIds)1155 void MediaLibraryRdbUtils::UpdateSourceAlbumInternal(const shared_ptr<RdbStore> &rdbStore,
1156     const vector<string> &sourceAlbumIds)
1157 {
1158     MediaLibraryTracer tracer;
1159     tracer.Start("UpdateSourceAlbumInternal");
1160 
1161     vector<string> columns = {
1162         PhotoAlbumColumns::ALBUM_ID,
1163         PhotoAlbumColumns::ALBUM_SUBTYPE,
1164         PhotoAlbumColumns::ALBUM_COVER_URI,
1165         PhotoAlbumColumns::ALBUM_COUNT,
1166         PhotoAlbumColumns::ALBUM_IMAGE_COUNT,
1167         PhotoAlbumColumns::ALBUM_VIDEO_COUNT,
1168     };
1169     auto albumResult = GetSourceAlbum(rdbStore, sourceAlbumIds, columns);
1170     if (albumResult == nullptr) {
1171         return;
1172     }
1173 
1174     ForEachRow(rdbStore, albumResult, false, UpdateSourceAlbumIfNeeded);
1175 }
1176 
GetSystemAlbum(const shared_ptr<RdbStore> & rdbStore,const vector<string> & subtypes,const vector<string> & columns)1177 static inline shared_ptr<ResultSet> GetSystemAlbum(const shared_ptr<RdbStore> &rdbStore,
1178     const vector<string> &subtypes, const vector<string> &columns)
1179 {
1180     RdbPredicates predicates(PhotoAlbumColumns::TABLE);
1181     if (subtypes.empty()) {
1182         predicates.In(PhotoAlbumColumns::ALBUM_SUBTYPE, ALL_SYS_PHOTO_ALBUM);
1183     } else {
1184         predicates.In(PhotoAlbumColumns::ALBUM_SUBTYPE, subtypes);
1185     }
1186     return Query(rdbStore, predicates, columns);
1187 }
1188 
UpdateSystemAlbumInternal(const shared_ptr<RdbStore> & rdbStore,const vector<string> & subtypes)1189 void MediaLibraryRdbUtils::UpdateSystemAlbumInternal(const shared_ptr<RdbStore> &rdbStore,
1190     const vector<string> &subtypes)
1191 {
1192     MediaLibraryTracer tracer;
1193     tracer.Start("UpdateSystemAlbumInternal");
1194 
1195     vector<string> columns = {
1196         PhotoAlbumColumns::ALBUM_ID,
1197         PhotoAlbumColumns::ALBUM_SUBTYPE,
1198         PhotoAlbumColumns::ALBUM_COVER_URI,
1199         PhotoAlbumColumns::ALBUM_COUNT,
1200         PhotoAlbumColumns::ALBUM_IMAGE_COUNT,
1201         PhotoAlbumColumns::ALBUM_VIDEO_COUNT,
1202     };
1203     auto albumResult = GetSystemAlbum(rdbStore, subtypes, columns);
1204     if (albumResult == nullptr) {
1205         return;
1206     }
1207 
1208     ForEachRow(rdbStore, albumResult, false, UpdateSysAlbumIfNeeded);
1209 }
1210 
UpdateUserAlbumHiddenState(const shared_ptr<RdbStore> & rdbStore)1211 static void UpdateUserAlbumHiddenState(const shared_ptr<RdbStore> &rdbStore)
1212 {
1213     MediaLibraryTracer tracer;
1214     tracer.Start("UpdateUserAlbumHiddenState");
1215     vector<string> userAlbumIds;
1216 
1217     auto albumResult = GetUserAlbum(rdbStore, userAlbumIds, {
1218         PhotoAlbumColumns::ALBUM_ID,
1219         PhotoAlbumColumns::CONTAINS_HIDDEN,
1220         PhotoAlbumColumns::HIDDEN_COUNT,
1221         PhotoAlbumColumns::HIDDEN_COVER,
1222     });
1223     if (albumResult == nullptr) {
1224         return;
1225     }
1226     ForEachRow(rdbStore, albumResult, true, UpdateUserAlbumIfNeeded);
1227 }
1228 
UpdateSysAlbumHiddenState(const shared_ptr<RdbStore> & rdbStore)1229 static void UpdateSysAlbumHiddenState(const shared_ptr<RdbStore> &rdbStore)
1230 {
1231     MediaLibraryTracer tracer;
1232     tracer.Start("UpdateSysAlbumHiddenState");
1233 
1234     auto albumResult = GetSystemAlbum(rdbStore, {
1235         to_string(PhotoAlbumSubType::IMAGE),
1236         to_string(PhotoAlbumSubType::VIDEO),
1237         to_string(PhotoAlbumSubType::FAVORITE),
1238         to_string(PhotoAlbumSubType::SCREENSHOT),
1239         to_string(PhotoAlbumSubType::CAMERA),
1240     }, {
1241         PhotoAlbumColumns::ALBUM_ID,
1242         PhotoAlbumColumns::ALBUM_SUBTYPE,
1243         PhotoAlbumColumns::CONTAINS_HIDDEN,
1244         PhotoAlbumColumns::HIDDEN_COUNT,
1245         PhotoAlbumColumns::HIDDEN_COVER,
1246     });
1247     if (albumResult == nullptr) {
1248         return;
1249     }
1250     ForEachRow(rdbStore, albumResult, true, UpdateSysAlbumIfNeeded);
1251 }
1252 
UpdateSourceAlbumHiddenState(const shared_ptr<RdbStore> & rdbStore)1253 static void UpdateSourceAlbumHiddenState(const shared_ptr<RdbStore> &rdbStore)
1254 {
1255     MediaLibraryTracer tracer;
1256     tracer.Start("UpdateSourceAlbumHiddenState");
1257     vector<string> sourceAlbumIds;
1258 
1259     auto albumResult = GetSourceAlbum(rdbStore, sourceAlbumIds, {
1260         PhotoAlbumColumns::ALBUM_ID,
1261         PhotoAlbumColumns::CONTAINS_HIDDEN,
1262         PhotoAlbumColumns::HIDDEN_COUNT,
1263         PhotoAlbumColumns::HIDDEN_COVER,
1264     });
1265     if (albumResult == nullptr) {
1266         return;
1267     }
1268     ForEachRow(rdbStore, albumResult, true, UpdateSourceAlbumIfNeeded);
1269 }
1270 
UpdateHiddenAlbumInternal(const shared_ptr<RdbStore> & rdbStore)1271 void MediaLibraryRdbUtils::UpdateHiddenAlbumInternal(const shared_ptr<RdbStore> &rdbStore)
1272 {
1273     MediaLibraryTracer tracer;
1274     tracer.Start("UpdateHiddenAlbumInternal");
1275 
1276     UpdateUserAlbumHiddenState(rdbStore);
1277     UpdateSysAlbumHiddenState(rdbStore);
1278     UpdateSourceAlbumHiddenState(rdbStore);
1279 }
1280 
UpdateAllAlbums(const shared_ptr<RdbStore> & rdbStore,const vector<string> & uris)1281 void MediaLibraryRdbUtils::UpdateAllAlbums(const shared_ptr<RdbStore> &rdbStore, const vector<string> &uris)
1282 {
1283     MediaLibraryTracer tracer;
1284     tracer.Start("UpdateAllAlbums");
1285 
1286     MediaLibraryRdbUtils::UpdateSystemAlbumInternal(rdbStore);
1287     MediaLibraryRdbUtils::UpdateHiddenAlbumInternal(rdbStore);
1288     if (uris.size() > ALBUM_UPDATE_THRESHOLD) {
1289         MediaLibraryRdbUtils::UpdateUserAlbumInternal(rdbStore);
1290         MediaLibraryRdbUtils::UpdateSourceAlbumInternal(rdbStore);
1291         MediaLibraryRdbUtils::UpdateAnalysisAlbumInternal(rdbStore);
1292     } else {
1293         MediaLibraryRdbUtils::UpdateUserAlbumByUri(rdbStore, uris);
1294         MediaLibraryRdbUtils::UpdateSourceAlbumByUri(rdbStore, uris);
1295         MediaLibraryRdbUtils::UpdateAnalysisAlbumByUri(rdbStore, uris);
1296     }
1297 }
1298 
UpdateAlbumReplacedSignal(const shared_ptr<RdbStore> & rdbStore,const vector<string> & albumIdVector)1299 static int32_t UpdateAlbumReplacedSignal(const shared_ptr<RdbStore> &rdbStore,
1300     const vector<string> &albumIdVector)
1301 {
1302     if (albumIdVector.empty()) {
1303         return E_SUCCESS;
1304     }
1305 
1306     ValuesBucket refreshValues;
1307     string insertRefreshTableSql = "INSERT OR IGNORE INTO " + ALBUM_REFRESH_TABLE + " VALUES ";
1308     for (size_t i = 0; i < albumIdVector.size(); ++i) {
1309         if (i != albumIdVector.size() - 1) {
1310             insertRefreshTableSql += "(" + albumIdVector[i] + "), ";
1311         } else {
1312             insertRefreshTableSql += "(" + albumIdVector[i] + ");";
1313         }
1314     }
1315     MEDIA_DEBUG_LOG("output insertRefreshTableSql:%{public}s", insertRefreshTableSql.c_str());
1316 
1317     int32_t ret = rdbStore->ExecuteSql(insertRefreshTableSql);
1318     if (ret != NativeRdb::E_OK) {
1319         MEDIA_ERR_LOG("Can not insert refreshed table, ret:%{public}d", ret);
1320         return E_HAS_DB_ERROR;
1321     }
1322     return E_SUCCESS;
1323 }
1324 
UpdateSystemAlbumCountInternal(const shared_ptr<RdbStore> & rdbStore,const vector<string> & subtypes)1325 void MediaLibraryRdbUtils::UpdateSystemAlbumCountInternal(const shared_ptr<RdbStore> &rdbStore,
1326     const vector<string> &subtypes)
1327 {
1328     // Only use in dfs
1329     MediaLibraryTracer tracer;
1330     tracer.Start("UpdateSystemAlbumCountInternal");
1331 
1332     vector<string> columns = { PhotoAlbumColumns::ALBUM_ID };
1333     auto albumResult = GetSystemAlbum(rdbStore, subtypes, columns);
1334     if (albumResult == nullptr) {
1335         return;
1336     }
1337 
1338     vector<string> replaceSignalAlbumVector;
1339     while (albumResult->GoToNextRow() == NativeRdb::E_OK) {
1340         int32_t ret = GetIntValFromColumn(albumResult, PhotoAlbumColumns::ALBUM_ID);
1341         if (ret <= 0) {
1342             MEDIA_WARN_LOG("Can not get ret:%{public}d", ret);
1343         } else {
1344             replaceSignalAlbumVector.push_back(to_string(ret));
1345         }
1346     }
1347     if (!replaceSignalAlbumVector.empty()) {
1348         int32_t ret = UpdateAlbumReplacedSignal(rdbStore, replaceSignalAlbumVector);
1349         if (ret != E_OK) {
1350             MEDIA_WARN_LOG("Update sysalbum replaced signal failed ret:%{public}d", ret);
1351         }
1352     }
1353     // Do not call SetNeedRefreshAlbum in this function
1354     // This is set by the notification from dfs
1355     // and is set by the media library observer after receiving the notification
1356 }
1357 
UpdateUserAlbumCountInternal(const shared_ptr<RdbStore> & rdbStore,const vector<string> & userAlbumIds)1358 void MediaLibraryRdbUtils::UpdateUserAlbumCountInternal(const shared_ptr<RdbStore> &rdbStore,
1359     const vector<string> &userAlbumIds)
1360 {
1361     // only use in dfs
1362     MediaLibraryTracer tracer;
1363     tracer.Start("UpdateUserAlbumCountInternal");
1364 
1365     vector<string> columns = { PhotoAlbumColumns::ALBUM_ID };
1366     auto albumResult = GetUserAlbum(rdbStore, userAlbumIds, columns);
1367     if (albumResult == nullptr) {
1368         return;
1369     }
1370 
1371     vector<string> replaceSignalAlbumVector;
1372     while (albumResult->GoToNextRow() == NativeRdb::E_OK) {
1373         int32_t ret = GetIntValFromColumn(albumResult, PhotoAlbumColumns::ALBUM_ID);
1374         if (ret <= 0) {
1375             MEDIA_WARN_LOG("Can not get ret:%{public}d", ret);
1376         } else {
1377             replaceSignalAlbumVector.push_back(to_string(ret));
1378         }
1379     }
1380     if (!replaceSignalAlbumVector.empty()) {
1381         int32_t ret = UpdateAlbumReplacedSignal(rdbStore, replaceSignalAlbumVector);
1382         if (ret != E_OK) {
1383             MEDIA_WARN_LOG("Update user album replaced signal failed ret:%{public}d", ret);
1384             return;
1385         }
1386     }
1387     // Do not call SetNeedRefreshAlbum in this function
1388     // This is set by the notification from dfs
1389     // and is set by the media library observer after receiving the notification
1390 }
1391 } // namespace OHOS::Media
1392