• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define MLOG_TAG "EnhancementDatabaseOperations"
17 
18 #include "enhancement_database_operations.h"
19 
20 #include "enhancement_manager.h"
21 #include "medialibrary_unistore_manager.h"
22 #include "media_file_uri.h"
23 #include "media_file_utils.h"
24 #include "media_log.h"
25 #include "scanner_utils.h"
26 #include "mimetype_utils.h"
27 #include "result_set_utils.h"
28 #include "rdb_utils.h"
29 #include "photo_album_column.h"
30 #include "media_app_uri_permission_column.h"
31 #include "media_library_extend_manager.h"
32 #include "moving_photo_file_utils.h"
33 
34 using namespace std;
35 using namespace OHOS::NativeRdb;
36 using namespace OHOS::RdbDataShareAdapter;
37 
38 namespace OHOS {
39 namespace Media {
40 static const int32_t MAX_UPDATE_RETRY_TIMES = 5;
41 const size_t UPDATE_BATCH_SIZE = 200;
42 
Query(MediaLibraryCommand & cmd,RdbPredicates & servicePredicates,const vector<string> & columns)43 std::shared_ptr<NativeRdb::ResultSet> EnhancementDatabaseOperations::Query(MediaLibraryCommand &cmd,
44     RdbPredicates &servicePredicates, const vector<string> &columns)
45 {
46     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
47     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
48     string uri = whereUriArgs.front();
49     if (!MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
50         MEDIA_ERR_LOG("invalid URI: %{private}s", uri.c_str());
51         return nullptr;
52     }
53     string fileId = MediaFileUri::GetPhotoId(uri);
54     servicePredicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
55     return MediaLibraryRdbStore::QueryWithFilter(servicePredicates, columns);
56 }
57 
BatchQuery(MediaLibraryCommand & cmd,const vector<string> & columns,unordered_map<int32_t,string> & fileId2Uri)58 std::shared_ptr<NativeRdb::ResultSet> EnhancementDatabaseOperations::BatchQuery(MediaLibraryCommand &cmd,
59     const vector<string> &columns, unordered_map<int32_t, string> &fileId2Uri)
60 {
61     RdbPredicates servicePredicates(PhotoColumn::PHOTOS_TABLE);
62     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
63     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
64     vector<string> whereIdArgs;
65     whereIdArgs.reserve(whereUriArgs.size());
66     for (const auto &arg : whereUriArgs) {
67         if (!MediaFileUtils::StartsWith(arg, PhotoColumn::PHOTO_URI_PREFIX)) {
68             MEDIA_ERR_LOG("invalid URI: %{private}s", arg.c_str());
69             continue;
70         }
71         string fileId = MediaFileUri::GetPhotoId(arg);
72         fileId2Uri.emplace(stoi(fileId), arg);
73         whereIdArgs.push_back(fileId);
74     }
75     if (fileId2Uri.empty()) {
76         MEDIA_ERR_LOG("submit tasks are invalid");
77         return nullptr;
78     }
79     servicePredicates.In(MediaColumn::MEDIA_ID, whereIdArgs);
80     return MediaLibraryRdbStore::QueryWithFilter(servicePredicates, columns);
81 }
82 
Update(ValuesBucket & rdbValues,AbsRdbPredicates & predicates,shared_ptr<AccurateRefresh::AssetAccurateRefresh> assetRefresh)83 int32_t EnhancementDatabaseOperations::Update(ValuesBucket &rdbValues, AbsRdbPredicates &predicates,
84     shared_ptr<AccurateRefresh::AssetAccurateRefresh> assetRefresh)
85 {
86     int32_t changedRows = -1;
87     for (int32_t i = 0; i < MAX_UPDATE_RETRY_TIMES; i++) {
88         if (assetRefresh != nullptr) {
89             changedRows = assetRefresh->UpdateWithDateTime(rdbValues, predicates);
90         } else {
91             changedRows = MediaLibraryRdbStore::UpdateWithDateTime(rdbValues, predicates);
92         }
93         if (changedRows >= 0) {
94             break;
95         }
96         MEDIA_ERR_LOG("Update DB failed! changedRows: %{public}d times: %{public}d", changedRows, i);
97     }
98     if (changedRows <= 0) {
99         MEDIA_INFO_LOG("Update DB failed! changedRows: %{public}d", changedRows);
100         return E_HAS_DB_ERROR;
101     }
102     return E_OK;
103 }
104 
HandleDateAdded(const MediaType type,ValuesBucket & outValues,shared_ptr<NativeRdb::ResultSet> resultSet)105 static void HandleDateAdded(const MediaType type, ValuesBucket &outValues,
106     shared_ptr<NativeRdb::ResultSet> resultSet)
107 {
108     int64_t dateAdded = GetInt64Val(PhotoColumn::MEDIA_DATE_ADDED, resultSet);
109     int64_t dateTaken = GetInt64Val(PhotoColumn::MEDIA_DATE_TAKEN, resultSet);
110     outValues.PutLong(MediaColumn::MEDIA_DATE_ADDED, dateAdded);
111     if (type != MEDIA_TYPE_PHOTO) {
112         return;
113     }
114     outValues.PutString(PhotoColumn::PHOTO_DATE_YEAR,
115         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_YEAR_FORMAT, dateTaken));
116     outValues.PutString(PhotoColumn::PHOTO_DATE_MONTH,
117         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_MONTH_FORMAT, dateTaken));
118     outValues.PutString(PhotoColumn::PHOTO_DATE_DAY,
119         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_DAY_FORMAT, dateTaken));
120     outValues.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateTaken);
121 }
122 
SetOwnerAlbumId(ValuesBucket & assetInfo,shared_ptr<NativeRdb::ResultSet> resultSet)123 static void SetOwnerAlbumId(ValuesBucket &assetInfo, shared_ptr<NativeRdb::ResultSet> resultSet)
124 {
125     int32_t albumId = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
126     string ownerPackage = GetStringVal(MediaColumn::MEDIA_OWNER_PACKAGE, resultSet);
127     string ownerAppId = GetStringVal(MediaColumn::MEDIA_OWNER_APPID, resultSet);
128     string packageName = GetStringVal(MediaColumn::MEDIA_PACKAGE_NAME, resultSet);
129     assetInfo.PutInt(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
130     assetInfo.PutString(MediaColumn::MEDIA_OWNER_PACKAGE, ownerPackage);
131     assetInfo.PutString(MediaColumn::MEDIA_OWNER_APPID, ownerAppId);
132     assetInfo.PutString(MediaColumn::MEDIA_PACKAGE_NAME, packageName);
133 }
134 
SetSupportedWatermarkType(int32_t sourceFileId,ValuesBucket & assetInfo,shared_ptr<NativeRdb::ResultSet> resultSet)135 static void SetSupportedWatermarkType(int32_t sourceFileId, ValuesBucket &assetInfo,
136     shared_ptr<NativeRdb::ResultSet> resultSet)
137 {
138     int32_t supportedWatermarkType = GetInt32Val(PhotoColumn::SUPPORTED_WATERMARK_TYPE, resultSet);
139     assetInfo.PutInt(PhotoColumn::SUPPORTED_WATERMARK_TYPE, supportedWatermarkType);
140 }
141 
SetBasicAttributes(MediaLibraryCommand & cmd,const FileAsset & fileAsset,ValuesBucket & assetInfo,shared_ptr<NativeRdb::ResultSet> resultSet)142 static void SetBasicAttributes(MediaLibraryCommand &cmd, const FileAsset &fileAsset,
143     ValuesBucket &assetInfo, shared_ptr<NativeRdb::ResultSet> resultSet)
144 {
145     const string& displayName = fileAsset.GetDisplayName();
146     assetInfo.PutInt(MediaColumn::MEDIA_TYPE, fileAsset.GetMediaType());
147     string extension = ScannerUtils::GetFileExtension(displayName);
148     assetInfo.PutString(MediaColumn::MEDIA_MIME_TYPE,
149         MimeTypeUtils::GetMimeTypeFromExtension(extension));
150     assetInfo.PutString(PhotoColumn::PHOTO_MEDIA_SUFFIX, extension);
151     assetInfo.PutString(MediaColumn::MEDIA_FILE_PATH, fileAsset.GetPath());
152     assetInfo.PutLong(MediaColumn::MEDIA_TIME_PENDING, fileAsset.GetTimePending());
153     assetInfo.PutString(MediaColumn::MEDIA_NAME, displayName);
154     assetInfo.PutString(MediaColumn::MEDIA_TITLE, MediaFileUtils::GetTitleFromDisplayName(displayName));
155     assetInfo.PutString(MediaColumn::MEDIA_DEVICE_NAME, cmd.GetDeviceName());
156 }
157 
SetCloudEnhancementAttributes(int32_t sourceFileId,ValuesBucket & assetInfo)158 static void SetCloudEnhancementAttributes(int32_t sourceFileId, ValuesBucket &assetInfo)
159 {
160     assetInfo.PutInt(PhotoColumn::PHOTO_CE_AVAILABLE,
161         static_cast<int32_t>(CloudEnhancementAvailableType::FINISH));
162     assetInfo.PutInt(PhotoColumn::PHOTO_STRONG_ASSOCIATION,
163         static_cast<int32_t>(StrongAssociationType::CLOUD_ENHANCEMENT));
164     assetInfo.PutInt(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, sourceFileId);
165 }
166 
SetSpecialAttributes(ValuesBucket & assetInfo,shared_ptr<CloudEnhancementFileInfo> info,shared_ptr<NativeRdb::ResultSet> resultSet)167 static void SetSpecialAttributes(ValuesBucket &assetInfo, shared_ptr<CloudEnhancementFileInfo> info,
168     shared_ptr<NativeRdb::ResultSet> resultSet)
169 {
170     // Set hidden
171     assetInfo.PutInt(MediaColumn::MEDIA_HIDDEN, info->hidden);
172     // Set subtype if source image is moving photo
173     int32_t effectMode = GetInt32Val(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, resultSet);
174     int32_t originalSubtype = GetInt32Val(PhotoColumn::PHOTO_ORIGINAL_SUBTYPE, resultSet);
175     if (MovingPhotoFileUtils::IsMovingPhoto(info->subtype, effectMode, originalSubtype)) {
176         assetInfo.PutInt(PhotoColumn::PHOTO_SUBTYPE, info->subtype);
177         assetInfo.PutInt(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, effectMode);
178         assetInfo.PutInt(PhotoColumn::PHOTO_ORIGINAL_SUBTYPE, originalSubtype);
179         MEDIA_INFO_LOG("subtype:%{public}d, moving_photo_effect_mode:%{public}d, original_subtype:%{public}d",
180             info->subtype, effectMode, originalSubtype);
181         int32_t dirty = GetInt32Val(PhotoColumn::PHOTO_DIRTY, resultSet);
182         if (dirty < 0) {
183             assetInfo.PutInt(PhotoColumn::PHOTO_DIRTY, dirty);
184         }
185     }
186 }
187 
InsertCloudEnhancementImageInDb(MediaLibraryCommand & cmd,const FileAsset & fileAsset,int32_t sourceFileId,shared_ptr<CloudEnhancementFileInfo> info,shared_ptr<NativeRdb::ResultSet> resultSet,std::shared_ptr<TransactionOperations> trans)188 int32_t EnhancementDatabaseOperations::InsertCloudEnhancementImageInDb(MediaLibraryCommand &cmd,
189     const FileAsset &fileAsset, int32_t sourceFileId, shared_ptr<CloudEnhancementFileInfo> info,
190     shared_ptr<NativeRdb::ResultSet> resultSet, std::shared_ptr<TransactionOperations> trans)
191 {
192     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
193     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "get rdb store failed");
194     CHECK_AND_RETURN_RET_LOG(fileAsset.GetPath().empty() || !MediaFileUtils::IsFileExists(fileAsset.GetPath()),
195         E_FILE_EXIST, "file %{private}s exists now", fileAsset.GetPath().c_str());
196     ValuesBucket assetInfo;
197     SetBasicAttributes(cmd, fileAsset, assetInfo, resultSet);
198     HandleDateAdded(MEDIA_TYPE_PHOTO, assetInfo, resultSet);
199     SetSpecialAttributes(assetInfo, info, resultSet);
200     SetCloudEnhancementAttributes(sourceFileId, assetInfo);
201     SetOwnerAlbumId(assetInfo, resultSet);
202     SetSupportedWatermarkType(sourceFileId, assetInfo, resultSet);
203     cmd.SetValueBucket(assetInfo);
204     cmd.SetTableName(PhotoColumn::PHOTOS_TABLE);
205     int64_t outRowId = -1;
206     int32_t errCode;
207     if (trans == nullptr) {
208         errCode = rdbStore->Insert(cmd, outRowId);
209     } else {
210         errCode = trans->Insert(cmd, outRowId);
211     }
212     CHECK_AND_RETURN_RET_LOG(errCode == NativeRdb::E_OK, E_HAS_DB_ERROR,
213         "Insert into db failed, errCode = %{public}d", errCode);
214     MEDIA_INFO_LOG("insert success, rowId = %{public}d", (int)outRowId);
215     return static_cast<int32_t>(outRowId);
216 }
217 
InsertCloudEnhancementPerm(int32_t sourceFileId,int32_t targetFileId)218 int64_t EnhancementDatabaseOperations::InsertCloudEnhancementPerm(int32_t sourceFileId,
219     int32_t targetFileId)
220 {
221     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
222     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "get rdb store failed");
223     RdbPredicates queryPredicates(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
224     queryPredicates.EqualTo(AppUriPermissionColumn::FILE_ID, sourceFileId);
225     queryPredicates.And();
226     queryPredicates.EqualTo(AppUriPermissionColumn::PERMISSION_TYPE,
227         static_cast<int32_t>(PhotoPermissionType::PERSIST_READWRITE_IMAGEVIDEO));
228     vector<string> columns = { AppUriPermissionColumn::APP_ID,
229         AppUriPermissionColumn::URI_TYPE, AppUriPermissionColumn::DATE_MODIFIED,
230         AppUriPermissionColumn::SOURCE_TOKENID, AppUriPermissionColumn::TARGET_TOKENID };
231     auto resultSet = MediaLibraryRdbStore::StepQueryWithoutCheck(queryPredicates, columns);
232     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr && resultSet->GoToFirstRow() == NativeRdb::E_OK,
233         E_HAS_DB_ERROR, "cannot get permission from origin photo: %{public}d", sourceFileId);
234     string appId = GetStringVal(AppUriPermissionColumn::APP_ID, resultSet);
235     int32_t uriType = GetInt32Val(AppUriPermissionColumn::URI_TYPE, resultSet);
236     int64_t dateModified = GetInt64Val(AppUriPermissionColumn::DATE_MODIFIED, resultSet);
237     int64_t sourceTokenId = GetInt64Val(AppUriPermissionColumn::SOURCE_TOKENID, resultSet);
238     int64_t targetTokenId = GetInt64Val(AppUriPermissionColumn::TARGET_TOKENID, resultSet);
239     resultSet->Close();
240 
241     int64_t outRowId = -1;
242     RdbPredicates checkPredicates(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
243     checkPredicates.EqualTo(AppUriPermissionColumn::FILE_ID, targetFileId);
244     checkPredicates.EqualTo(AppUriPermissionColumn::URI_TYPE, uriType);
245     checkPredicates.EqualTo(AppUriPermissionColumn::PERMISSION_TYPE,
246         static_cast<int32_t>(PhotoPermissionType::PERSIST_READWRITE_IMAGEVIDEO));
247     checkPredicates.EqualTo(AppUriPermissionColumn::DATE_MODIFIED, dateModified);
248     checkPredicates.EqualTo(AppUriPermissionColumn::SOURCE_TOKENID, sourceTokenId);
249     checkPredicates.EqualTo(AppUriPermissionColumn::TARGET_TOKENID, targetTokenId);
250     resultSet = MediaLibraryRdbStore::StepQueryWithoutCheck(checkPredicates, columns);
251     if (resultSet != nullptr && resultSet->GoToFirstRow() == NativeRdb::E_OK) {
252         MEDIA_INFO_LOG("cloud enhancement permission record has already exists: %{public}d", targetFileId);
253         return outRowId;
254     }
255 
256     ValuesBucket valueBucket;
257     valueBucket.PutString(AppUriPermissionColumn::APP_ID, appId);
258     valueBucket.PutInt(AppUriPermissionColumn::FILE_ID, targetFileId);
259     valueBucket.PutInt(AppUriPermissionColumn::URI_TYPE, uriType);
260     valueBucket.PutInt(AppUriPermissionColumn::PERMISSION_TYPE,
261         static_cast<int32_t>(PhotoPermissionType::PERSIST_READWRITE_IMAGEVIDEO));
262     valueBucket.PutLong(AppUriPermissionColumn::DATE_MODIFIED, dateModified);
263     valueBucket.PutLong(AppUriPermissionColumn::SOURCE_TOKENID, sourceTokenId);
264     valueBucket.PutLong(AppUriPermissionColumn::TARGET_TOKENID, targetTokenId);
265 
266     int32_t errCode = MediaLibraryRdbStore::InsertInternal(outRowId,
267         AppUriPermissionColumn::APP_URI_PERMISSION_TABLE, valueBucket);
268     CHECK_AND_PRINT_LOG(errCode == E_OK, "insert permission failed: %{public}d", errCode);
269     MEDIA_INFO_LOG("Add permission for cloud enhancement photo success: %{public}d", targetFileId);
270     return outRowId;
271 }
272 
IsEditedTrashedHidden(const std::shared_ptr<NativeRdb::ResultSet> & ret)273 bool IsEditedTrashedHidden(const std::shared_ptr<NativeRdb::ResultSet> &ret)
274 {
275     if (ret == nullptr) {
276         MEDIA_ERR_LOG("resultset is null");
277         return false;
278     }
279     if (ret->GoToFirstRow() != NativeRdb::E_OK) {
280         MEDIA_ERR_LOG("go to first row failed");
281         return false;
282     }
283     int32_t colIndex = -1;
284     double editTime = -1;
285     double trashedTime = -1;
286     double hiddenTime = -1;
287     MEDIA_INFO_LOG("coIndex1 is %{public}d, editTime is %{public}d", colIndex, static_cast<int>(editTime));
288     ret->GetColumnIndex(PhotoColumn::PHOTO_EDIT_TIME, colIndex);
289     if (ret->GetDouble(colIndex, editTime) != NativeRdb::E_OK) {
290         MEDIA_ERR_LOG("Fail to query DB ");
291         MEDIA_INFO_LOG("coIndex2 is %{public}d, editTime is %{public}d", colIndex, static_cast<int>(editTime));
292         return false;
293     }
294     ret->GetColumnIndex(MediaColumn::MEDIA_DATE_TRASHED, colIndex);
295     if (ret->GetDouble(colIndex, trashedTime) != NativeRdb::E_OK) {
296         MEDIA_ERR_LOG("Fail to query DB ");
297         MEDIA_INFO_LOG("coIndex2 is %{public}d, trashedTime is %{public}d", colIndex, static_cast<int>(trashedTime));
298         return false;
299     }
300     ret->GetColumnIndex(PhotoColumn::PHOTO_HIDDEN_TIME, colIndex);
301     if (ret->GetDouble(colIndex, hiddenTime) != NativeRdb::E_OK) {
302         MEDIA_ERR_LOG("Fail to query DB ");
303         MEDIA_INFO_LOG("coIndex2 is %{public}d, hiddenTime is %{public}d", colIndex, static_cast<int>(hiddenTime));
304         return false;
305     }
306     MEDIA_INFO_LOG("editTime is %{public}d, trashedTime is %{public}d, hiddenTime is %{public}d",
307         static_cast<int>(editTime), static_cast<int>(trashedTime), static_cast<int>(hiddenTime));
308     return (editTime == 0 && trashedTime == 0 && hiddenTime == 0) ? true : false;
309 }
310 
GetPair(MediaLibraryCommand & cmd)311 std::shared_ptr<NativeRdb::ResultSet> EnhancementDatabaseOperations::GetPair(MediaLibraryCommand &cmd)
312 {
313     RdbPredicates firstServicePredicates(PhotoColumn::PHOTOS_TABLE);
314     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
315     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
316     string UriArg = whereUriArgs.front();
317     if (!MediaFileUtils::StartsWith(UriArg, PhotoColumn::PHOTO_URI_PREFIX)) {
318         return nullptr;
319     }
320     string fileId = MediaFileUri::GetPhotoId(UriArg);
321     MEDIA_INFO_LOG("GetPair_build fileId: %{public}s", fileId.c_str());
322     vector<string> queryColumns = {PhotoColumn::PHOTO_EDIT_TIME, MediaColumn::MEDIA_DATE_TRASHED,
323         PhotoColumn::PHOTO_HIDDEN_TIME};
324     firstServicePredicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
325     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(firstServicePredicates, queryColumns);
326     if (IsEditedTrashedHidden(resultSet)) {
327         MEDIA_INFO_LOG("success into query stage after IsEditedTrashedHidden");
328         RdbPredicates secondServicePredicates(PhotoColumn::PHOTOS_TABLE);
329         secondServicePredicates.EqualTo(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, fileId);
330         vector<string> columns = {};
331         MEDIA_INFO_LOG("start query");
332         auto resultSetCallback = MediaLibraryRdbStore::QueryWithFilter(secondServicePredicates, columns);
333         if (IsEditedTrashedHidden(resultSetCallback)) {
334             return resultSetCallback;
335         }
336     }
337     MEDIA_INFO_LOG("PhotoAsset is edited or trashed or hidden");
338     return nullptr;
339 }
340 
QueryAndUpdatePhotos(const std::vector<std::string> & photoIds)341 int32_t EnhancementDatabaseOperations::QueryAndUpdatePhotos(const std::vector<std::string> &photoIds)
342 {
343     CHECK_AND_RETURN_RET_LOG(photoIds.size() > 0, NativeRdb::E_OK, "photoIds is emtpy");
344     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
345     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "rdbStore is nullptr");
346 
347     std::string photoIdList =
348         accumulate(photoIds.begin() + 1, photoIds.end(), photoIds[0], [](const string &a, const string &b) {
349             return a + ", " + b;
350         });
351     std::string querySql = "SELECT file_id FROM Photos WHERE (ce_available = 0 AND photo_id IN (" + photoIdList +
352                            ")) OR (ce_available = 1 AND photo_id NOT IN (" + photoIdList + "));";
353 
354     auto resultSet = rdbStore->QueryByStep(querySql);
355     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, NativeRdb::E_ERROR, "query by step failed");
356 
357     std::vector<std::string> needUpdateFileIds;
358     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
359         needUpdateFileIds.push_back(GetStringVal(PhotoColumn::MEDIA_ID, resultSet));
360     }
361     resultSet->Close();
362     auto needChange = needUpdateFileIds.size();
363     CHECK_AND_RETURN_RET_LOG(needChange > 0, NativeRdb::E_OK, "needUpdateFileIds is emtpy");
364 
365     int32_t ret = NativeRdb::E_OK;
366     int64_t totalChanged = 0;
367     for (size_t start = 0; start < needChange; start += UPDATE_BATCH_SIZE) {
368         size_t end = std::min(start + UPDATE_BATCH_SIZE, needChange);
369         std::stringstream updateSql;
370         updateSql << "UPDATE Photos SET ce_available = NOT ( ce_available ) WHERE file_id IN ( ";
371         for (size_t i = start; i < end; ++i) {
372             if (i != start) {
373                 updateSql << ", ";
374             }
375             updateSql << needUpdateFileIds[i];
376         }
377         updateSql << " );";
378         int64_t changedRowCount = 0;
379         auto errCode = rdbStore->ExecuteForChangedRowCount(changedRowCount, updateSql.str());
380         if (errCode != NativeRdb::E_OK) {
381             ret = errCode;
382             MEDIA_ERR_LOG("execute for changed row count failed, errCode: %{public}d", errCode);
383         } else {
384             totalChanged += changedRowCount;
385             MEDIA_INFO_LOG("changed row count: %{public}" PRId64, changedRowCount);
386         }
387     }
388 
389     MEDIA_INFO_LOG("need change: %{public}zu, total changed: %{public}" PRId64, needChange, totalChanged);
390     return ret;
391 }
392 } // namespace Media
393 } // namespace OHOS