• 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 
31 using namespace std;
32 using namespace OHOS::NativeRdb;
33 using namespace OHOS::RdbDataShareAdapter;
34 
35 namespace OHOS {
36 namespace Media {
37 static const int32_t MAX_UPDATE_RETRY_TIMES = 5;
38 const size_t UPDATE_BATCH_SIZE = 200;
39 
Query(MediaLibraryCommand & cmd,RdbPredicates & servicePredicates,const vector<string> & columns)40 std::shared_ptr<ResultSet> EnhancementDatabaseOperations::Query(MediaLibraryCommand &cmd,
41     RdbPredicates &servicePredicates, const vector<string> &columns)
42 {
43     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
44     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
45     string uri = whereUriArgs.front();
46     if (!MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
47         MEDIA_ERR_LOG("invalid URI: %{private}s", uri.c_str());
48         return nullptr;
49     }
50     string fileId = MediaFileUri::GetPhotoId(uri);
51     servicePredicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
52     return MediaLibraryRdbStore::QueryWithFilter(servicePredicates, columns);
53 }
54 
BatchQuery(MediaLibraryCommand & cmd,const vector<string> & columns,unordered_map<int32_t,string> & fileId2Uri)55 std::shared_ptr<ResultSet> EnhancementDatabaseOperations::BatchQuery(MediaLibraryCommand &cmd,
56     const vector<string> &columns, unordered_map<int32_t, string> &fileId2Uri)
57 {
58     RdbPredicates servicePredicates(PhotoColumn::PHOTOS_TABLE);
59     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
60     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
61     vector<string> whereIdArgs;
62     whereIdArgs.reserve(whereUriArgs.size());
63     for (const auto &arg : whereUriArgs) {
64         if (!MediaFileUtils::StartsWith(arg, PhotoColumn::PHOTO_URI_PREFIX)) {
65             MEDIA_ERR_LOG("invalid URI: %{private}s", arg.c_str());
66             continue;
67         }
68         string fileId = MediaFileUri::GetPhotoId(arg);
69         fileId2Uri.emplace(stoi(fileId), arg);
70         whereIdArgs.push_back(fileId);
71     }
72     if (fileId2Uri.empty()) {
73         MEDIA_ERR_LOG("submit tasks are invalid");
74         return nullptr;
75     }
76     servicePredicates.In(MediaColumn::MEDIA_ID, whereIdArgs);
77     return MediaLibraryRdbStore::QueryWithFilter(servicePredicates, columns);
78 }
79 
Update(ValuesBucket & rdbValues,AbsRdbPredicates & predicates)80 int32_t EnhancementDatabaseOperations::Update(ValuesBucket &rdbValues, AbsRdbPredicates &predicates)
81 {
82     int32_t changedRows = -1;
83     for (int32_t i = 0; i < MAX_UPDATE_RETRY_TIMES; i++) {
84         changedRows = MediaLibraryRdbStore::UpdateWithDateTime(rdbValues, predicates);
85         if (changedRows >= 0) {
86             break;
87         }
88         MEDIA_ERR_LOG("Update DB failed! changedRows: %{public}d times: %{public}d", changedRows, i);
89     }
90     if (changedRows <= 0) {
91         MEDIA_INFO_LOG("Update DB failed! changedRows: %{public}d", changedRows);
92         return E_HAS_DB_ERROR;
93     }
94     return E_OK;
95 }
96 
HandleDateAdded(const int64_t dateAdded,const MediaType type,ValuesBucket & outValues)97 static void HandleDateAdded(const int64_t dateAdded, const MediaType type, ValuesBucket &outValues)
98 {
99     outValues.PutLong(MediaColumn::MEDIA_DATE_ADDED, dateAdded);
100     if (type != MEDIA_TYPE_PHOTO) {
101         return;
102     }
103     outValues.PutString(PhotoColumn::PHOTO_DATE_YEAR,
104         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_YEAR_FORMAT, dateAdded));
105     outValues.PutString(PhotoColumn::PHOTO_DATE_MONTH,
106         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_MONTH_FORMAT, dateAdded));
107     outValues.PutString(PhotoColumn::PHOTO_DATE_DAY,
108         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_DAY_FORMAT, dateAdded));
109     outValues.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateAdded);
110 }
111 
SetOwnerAlbumId(ValuesBucket & assetInfo,shared_ptr<NativeRdb::ResultSet> resultSet)112 static void SetOwnerAlbumId(ValuesBucket &assetInfo, shared_ptr<NativeRdb::ResultSet> resultSet)
113 {
114     int32_t albumId = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
115     string ownerPackage = GetStringVal(MediaColumn::MEDIA_OWNER_PACKAGE, resultSet);
116     string ownerAppId = GetStringVal(MediaColumn::MEDIA_OWNER_APPID, resultSet);
117     string packageName = GetStringVal(MediaColumn::MEDIA_PACKAGE_NAME, resultSet);
118     assetInfo.PutInt(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
119     assetInfo.PutString(MediaColumn::MEDIA_OWNER_PACKAGE, ownerPackage);
120     assetInfo.PutString(MediaColumn::MEDIA_OWNER_APPID, ownerAppId);
121     assetInfo.PutString(MediaColumn::MEDIA_PACKAGE_NAME, packageName);
122 }
123 
SetSupportedWatermarkType(int32_t sourceFileId,ValuesBucket & assetInfo,shared_ptr<NativeRdb::ResultSet> resultSet)124 static void SetSupportedWatermarkType(int32_t sourceFileId, ValuesBucket &assetInfo,
125     shared_ptr<NativeRdb::ResultSet> resultSet)
126 {
127     int32_t supportedWatermarkType = GetInt32Val(PhotoColumn::SUPPORTED_WATERMARK_TYPE, resultSet);
128     assetInfo.PutInt(PhotoColumn::SUPPORTED_WATERMARK_TYPE, supportedWatermarkType);
129 }
130 
InsertCloudEnhancementImageInDb(MediaLibraryCommand & cmd,const FileAsset & fileAsset,int32_t sourceFileId,shared_ptr<CloudEnhancementFileInfo> info,shared_ptr<NativeRdb::ResultSet> resultSet,std::shared_ptr<TransactionOperations> trans)131 int32_t EnhancementDatabaseOperations::InsertCloudEnhancementImageInDb(MediaLibraryCommand &cmd,
132     const FileAsset &fileAsset, int32_t sourceFileId, shared_ptr<CloudEnhancementFileInfo> info,
133     shared_ptr<NativeRdb::ResultSet> resultSet, std::shared_ptr<TransactionOperations> trans)
134 {
135     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
136     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "get rdb store failed");
137     CHECK_AND_RETURN_RET_LOG(fileAsset.GetPath().empty() || !MediaFileUtils::IsFileExists(fileAsset.GetPath()),
138         E_FILE_EXIST, "file %{private}s exists now", fileAsset.GetPath().c_str());
139     const string& displayName = fileAsset.GetDisplayName();
140     int64_t nowTime = MediaFileUtils::UTCTimeMilliSeconds();
141     ValuesBucket assetInfo;
142     assetInfo.PutInt(MediaColumn::MEDIA_TYPE, fileAsset.GetMediaType());
143     string extension = ScannerUtils::GetFileExtension(displayName);
144     assetInfo.PutString(MediaColumn::MEDIA_MIME_TYPE,
145         MimeTypeUtils::GetMimeTypeFromExtension(extension));
146     assetInfo.PutString(MediaColumn::MEDIA_FILE_PATH, fileAsset.GetPath());
147     assetInfo.PutLong(MediaColumn::MEDIA_TIME_PENDING, fileAsset.GetTimePending());
148     assetInfo.PutString(MediaColumn::MEDIA_NAME, displayName);
149     assetInfo.PutString(MediaColumn::MEDIA_TITLE, MediaFileUtils::GetTitleFromDisplayName(displayName));
150     assetInfo.PutString(MediaColumn::MEDIA_DEVICE_NAME, cmd.GetDeviceName());
151     HandleDateAdded(nowTime, MEDIA_TYPE_PHOTO, assetInfo);
152     // Set subtype if source image is moving photo
153     assetInfo.PutInt(MediaColumn::MEDIA_HIDDEN, info->hidden);
154     if (info->subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
155         assetInfo.PutInt(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::MOVING_PHOTO));
156         int32_t dirty = GetInt32Val(PhotoColumn::PHOTO_DIRTY, resultSet);
157         if (dirty < 0) {
158             assetInfo.PutInt(PhotoColumn::PHOTO_DIRTY, dirty);
159         }
160     }
161     assetInfo.PutInt(PhotoColumn::PHOTO_CE_AVAILABLE,
162         static_cast<int32_t>(CloudEnhancementAvailableType::FINISH));
163     assetInfo.PutInt(PhotoColumn::PHOTO_STRONG_ASSOCIATION,
164         static_cast<int32_t>(StrongAssociationType::CLOUD_ENHANCEMENT));
165     assetInfo.PutInt(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, sourceFileId);
166     SetOwnerAlbumId(assetInfo, resultSet);
167     SetSupportedWatermarkType(sourceFileId, assetInfo, resultSet);
168     cmd.SetValueBucket(assetInfo);
169     cmd.SetTableName(PhotoColumn::PHOTOS_TABLE);
170     int64_t outRowId = -1;
171     int32_t errCode;
172     if (trans == nullptr) {
173         errCode = rdbStore->Insert(cmd, outRowId);
174     } else {
175         errCode = trans->Insert(cmd, outRowId);
176     }
177     CHECK_AND_RETURN_RET_LOG(errCode == NativeRdb::E_OK, E_HAS_DB_ERROR,
178         "Insert into db failed, errCode = %{public}d", errCode);
179     MEDIA_INFO_LOG("insert success, rowId = %{public}d", (int)outRowId);
180     return static_cast<int32_t>(outRowId);
181 }
182 
IsEditedTrashedHidden(const std::shared_ptr<NativeRdb::ResultSet> & ret)183 bool IsEditedTrashedHidden(const std::shared_ptr<NativeRdb::ResultSet> &ret)
184 {
185     if (ret == nullptr) {
186         MEDIA_ERR_LOG("resultset is null");
187         return false;
188     }
189     if (ret->GoToFirstRow() != NativeRdb::E_OK) {
190         MEDIA_ERR_LOG("go to first row failed");
191         return false;
192     }
193     int32_t colIndex = -1;
194     double editTime = -1;
195     double trashedTime = -1;
196     double hiddenTime = -1;
197     MEDIA_INFO_LOG("coIndex1 is %{public}d, editTime is %{public}d", colIndex, static_cast<int>(editTime));
198     ret->GetColumnIndex(PhotoColumn::PHOTO_EDIT_TIME, colIndex);
199     if (ret->GetDouble(colIndex, editTime) != NativeRdb::E_OK) {
200         MEDIA_ERR_LOG("Fail to query DB ");
201         MEDIA_INFO_LOG("coIndex2 is %{public}d, editTime is %{public}d", colIndex, static_cast<int>(editTime));
202         return false;
203     }
204     ret->GetColumnIndex(MediaColumn::MEDIA_DATE_TRASHED, colIndex);
205     if (ret->GetDouble(colIndex, trashedTime) != NativeRdb::E_OK) {
206         MEDIA_ERR_LOG("Fail to query DB ");
207         MEDIA_INFO_LOG("coIndex2 is %{public}d, trashedTime is %{public}d", colIndex, static_cast<int>(trashedTime));
208         return false;
209     }
210     ret->GetColumnIndex(PhotoColumn::PHOTO_HIDDEN_TIME, colIndex);
211     if (ret->GetDouble(colIndex, hiddenTime) != NativeRdb::E_OK) {
212         MEDIA_ERR_LOG("Fail to query DB ");
213         MEDIA_INFO_LOG("coIndex2 is %{public}d, hiddenTime is %{public}d", colIndex, static_cast<int>(hiddenTime));
214         return false;
215     }
216     MEDIA_INFO_LOG("editTime is %{public}d, trashedTime is %{public}d, hiddenTime is %{public}d",
217         static_cast<int>(editTime), static_cast<int>(trashedTime), static_cast<int>(hiddenTime));
218     return (editTime == 0 && trashedTime == 0 && hiddenTime == 0) ? true : false;
219 }
220 
GetPair(MediaLibraryCommand & cmd)221 std::shared_ptr<NativeRdb::ResultSet> EnhancementDatabaseOperations::GetPair(MediaLibraryCommand &cmd)
222 {
223     RdbPredicates firstServicePredicates(PhotoColumn::PHOTOS_TABLE);
224     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
225     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
226     string UriArg = whereUriArgs.front();
227     if (!MediaFileUtils::StartsWith(UriArg, PhotoColumn::PHOTO_URI_PREFIX)) {
228         return nullptr;
229     }
230     string fileId = MediaFileUri::GetPhotoId(UriArg);
231     MEDIA_INFO_LOG("GetPair_build fileId: %{public}s", fileId.c_str());
232     vector<string> queryColumns = {PhotoColumn::PHOTO_EDIT_TIME, MediaColumn::MEDIA_DATE_TRASHED,
233         PhotoColumn::PHOTO_HIDDEN_TIME};
234     firstServicePredicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
235     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(firstServicePredicates, queryColumns);
236     if (IsEditedTrashedHidden(resultSet)) {
237         MEDIA_INFO_LOG("success into query stage after IsEditedTrashedHidden");
238         RdbPredicates secondServicePredicates(PhotoColumn::PHOTOS_TABLE);
239         secondServicePredicates.EqualTo(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, fileId);
240         vector<string> columns = {};
241         MEDIA_INFO_LOG("start query");
242         auto resultSetCallback = MediaLibraryRdbStore::QueryWithFilter(secondServicePredicates, columns);
243         if (IsEditedTrashedHidden(resultSetCallback)) {
244             return resultSetCallback;
245         }
246     }
247     MEDIA_INFO_LOG("PhotoAsset is edited or trashed or hidden");
248     return nullptr;
249 }
250 
QueryAndUpdatePhotos(const std::vector<std::string> & photoIds)251 int32_t EnhancementDatabaseOperations::QueryAndUpdatePhotos(const std::vector<std::string> &photoIds)
252 {
253     CHECK_AND_RETURN_RET_LOG(photoIds.size() > 0, NativeRdb::E_OK, "photoIds is emtpy");
254     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
255     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "rdbStore is nullptr");
256 
257     std::string photoIdList =
258         accumulate(photoIds.begin() + 1, photoIds.end(), photoIds[0], [](const string &a, const string &b) {
259             return a + ", " + b;
260         });
261     std::string querySql = "SELECT file_id FROM Photos WHERE (ce_available = 0 AND photo_id IN (" + photoIdList +
262                            ")) OR (ce_available = 1 AND photo_id NOT IN (" + photoIdList + "));";
263 
264     auto resultSet = rdbStore->QueryByStep(querySql);
265     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, NativeRdb::E_ERROR, "query by step failed");
266 
267     std::vector<std::string> needUpdateFileIds;
268     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
269         needUpdateFileIds.push_back(GetStringVal(PhotoColumn::MEDIA_ID, resultSet));
270     }
271     resultSet->Close();
272     auto needChange = needUpdateFileIds.size();
273     CHECK_AND_RETURN_RET_LOG(needChange > 0, NativeRdb::E_OK, "needUpdateFileIds is emtpy");
274 
275     int32_t ret = NativeRdb::E_OK;
276     int64_t totalChanged = 0;
277     for (size_t start = 0; start < needChange; start += UPDATE_BATCH_SIZE) {
278         size_t end = std::min(start + UPDATE_BATCH_SIZE, needChange);
279         std::stringstream updateSql;
280         updateSql << "UPDATE Photos SET ce_available = NOT ( ce_available ) WHERE file_id IN ( ";
281         for (size_t i = start; i < end; ++i) {
282             if (i != start) {
283                 updateSql << ", ";
284             }
285             updateSql << needUpdateFileIds[i];
286         }
287         updateSql << " );";
288         int64_t changedRowCount = 0;
289         auto errCode = rdbStore->ExecuteForChangedRowCount(changedRowCount, updateSql.str());
290         if (errCode != NativeRdb::E_OK) {
291             ret = errCode;
292             MEDIA_ERR_LOG("execute for changed row count failed, errCode: %{public}d", errCode);
293         } else {
294             totalChanged += changedRowCount;
295             MEDIA_INFO_LOG("changed row count: %{public}" PRId64, changedRowCount);
296         }
297     }
298 
299     MEDIA_INFO_LOG("need change: %{public}zu, total changed: %{public}" PRId64, needChange, totalChanged);
300     return ret;
301 }
302 } // namespace Media
303 } // namespace OHOS