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 
Query(MediaLibraryCommand & cmd,RdbPredicates & servicePredicates,const vector<string> & columns)39 std::shared_ptr<ResultSet> EnhancementDatabaseOperations::Query(MediaLibraryCommand &cmd,
40     RdbPredicates &servicePredicates, const vector<string> &columns)
41 {
42     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
43     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
44     string uri = whereUriArgs.front();
45     if (!MediaFileUtils::StartsWith(uri, PhotoColumn::PHOTO_URI_PREFIX)) {
46         MEDIA_ERR_LOG("invalid URI: %{private}s", uri.c_str());
47         return nullptr;
48     }
49     string fileId = MediaFileUri::GetPhotoId(uri);
50     servicePredicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
51     return MediaLibraryRdbStore::QueryWithFilter(servicePredicates, columns);
52 }
53 
BatchQuery(MediaLibraryCommand & cmd,const vector<string> & columns,unordered_map<int32_t,string> & fileId2Uri)54 std::shared_ptr<ResultSet> EnhancementDatabaseOperations::BatchQuery(MediaLibraryCommand &cmd,
55     const vector<string> &columns, unordered_map<int32_t, string> &fileId2Uri)
56 {
57     RdbPredicates servicePredicates(PhotoColumn::PHOTOS_TABLE);
58     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
59     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
60     vector<string> whereIdArgs;
61     whereIdArgs.reserve(whereUriArgs.size());
62     for (const auto &arg : whereUriArgs) {
63         if (!MediaFileUtils::StartsWith(arg, PhotoColumn::PHOTO_URI_PREFIX)) {
64             MEDIA_ERR_LOG("invalid URI: %{private}s", arg.c_str());
65             continue;
66         }
67         string fileId = MediaFileUri::GetPhotoId(arg);
68         fileId2Uri.emplace(stoi(fileId), arg);
69         whereIdArgs.push_back(fileId);
70     }
71     if (fileId2Uri.empty()) {
72         MEDIA_ERR_LOG("submit tasks are invalid");
73         return nullptr;
74     }
75     servicePredicates.In(MediaColumn::MEDIA_ID, whereIdArgs);
76     return MediaLibraryRdbStore::QueryWithFilter(servicePredicates, columns);
77 }
78 
Update(ValuesBucket & rdbValues,AbsRdbPredicates & predicates)79 int32_t EnhancementDatabaseOperations::Update(ValuesBucket &rdbValues, AbsRdbPredicates &predicates)
80 {
81     int32_t changedRows = -1;
82     for (int32_t i = 0; i < MAX_UPDATE_RETRY_TIMES; i++) {
83         changedRows = MediaLibraryRdbStore::UpdateWithDateTime(rdbValues, predicates);
84         if (changedRows >= 0) {
85             break;
86         }
87         MEDIA_ERR_LOG("Update DB failed! changedRows: %{public}d times: %{public}d", changedRows, i);
88     }
89     if (changedRows <= 0) {
90         MEDIA_INFO_LOG("Update DB failed! changedRows: %{public}d", changedRows);
91         return E_HAS_DB_ERROR;
92     }
93     return E_OK;
94 }
95 
HandleDateAdded(const int64_t dateAdded,const MediaType type,ValuesBucket & outValues)96 static void HandleDateAdded(const int64_t dateAdded, const MediaType type, ValuesBucket &outValues)
97 {
98     outValues.PutLong(MediaColumn::MEDIA_DATE_ADDED, dateAdded);
99     if (type != MEDIA_TYPE_PHOTO) {
100         return;
101     }
102     outValues.PutString(PhotoColumn::PHOTO_DATE_YEAR,
103         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_YEAR_FORMAT, dateAdded));
104     outValues.PutString(PhotoColumn::PHOTO_DATE_MONTH,
105         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_MONTH_FORMAT, dateAdded));
106     outValues.PutString(PhotoColumn::PHOTO_DATE_DAY,
107         MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_DAY_FORMAT, dateAdded));
108     outValues.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateAdded);
109 }
110 
SetOwnerAlbumId(ValuesBucket & assetInfo,shared_ptr<NativeRdb::ResultSet> resultSet)111 static void SetOwnerAlbumId(ValuesBucket &assetInfo, shared_ptr<NativeRdb::ResultSet> resultSet)
112 {
113     int32_t albumId = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
114     string ownerPackage = GetStringVal(MediaColumn::MEDIA_OWNER_PACKAGE, resultSet);
115     string ownerAppId = GetStringVal(MediaColumn::MEDIA_OWNER_APPID, resultSet);
116     string packageName = GetStringVal(MediaColumn::MEDIA_PACKAGE_NAME, resultSet);
117     assetInfo.PutInt(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
118     assetInfo.PutString(MediaColumn::MEDIA_OWNER_PACKAGE, ownerPackage);
119     assetInfo.PutString(MediaColumn::MEDIA_OWNER_APPID, ownerAppId);
120     assetInfo.PutString(MediaColumn::MEDIA_PACKAGE_NAME, packageName);
121 }
122 
SetSupportedWatermarkType(int32_t sourceFileId,ValuesBucket & assetInfo,shared_ptr<NativeRdb::ResultSet> resultSet)123 static void SetSupportedWatermarkType(int32_t sourceFileId, ValuesBucket &assetInfo,
124     shared_ptr<NativeRdb::ResultSet> resultSet)
125 {
126     int32_t supportedWatermarkType = GetInt32Val(PhotoColumn::SUPPORTED_WATERMARK_TYPE, resultSet);
127     assetInfo.PutInt(PhotoColumn::SUPPORTED_WATERMARK_TYPE, supportedWatermarkType);
128 }
129 
InsertCloudEnhancementImageInDb(MediaLibraryCommand & cmd,const FileAsset & fileAsset,int32_t sourceFileId,shared_ptr<CloudEnhancementFileInfo> info,shared_ptr<NativeRdb::ResultSet> resultSet,std::shared_ptr<TransactionOperations> trans)130 int32_t EnhancementDatabaseOperations::InsertCloudEnhancementImageInDb(MediaLibraryCommand &cmd,
131     const FileAsset &fileAsset, int32_t sourceFileId, shared_ptr<CloudEnhancementFileInfo> info,
132     shared_ptr<NativeRdb::ResultSet> resultSet, std::shared_ptr<TransactionOperations> trans)
133 {
134     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
135     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "get rdb store failed");
136     CHECK_AND_RETURN_RET_LOG(fileAsset.GetPath().empty() || !MediaFileUtils::IsFileExists(fileAsset.GetPath()),
137         E_FILE_EXIST, "file %{private}s exists now", fileAsset.GetPath().c_str());
138     const string& displayName = fileAsset.GetDisplayName();
139     int64_t nowTime = MediaFileUtils::UTCTimeMilliSeconds();
140     ValuesBucket assetInfo;
141     assetInfo.PutInt(MediaColumn::MEDIA_TYPE, fileAsset.GetMediaType());
142     string extension = ScannerUtils::GetFileExtension(displayName);
143     assetInfo.PutString(MediaColumn::MEDIA_MIME_TYPE,
144         MimeTypeUtils::GetMimeTypeFromExtension(extension));
145     assetInfo.PutString(MediaColumn::MEDIA_FILE_PATH, fileAsset.GetPath());
146     assetInfo.PutLong(MediaColumn::MEDIA_TIME_PENDING, fileAsset.GetTimePending());
147     assetInfo.PutString(MediaColumn::MEDIA_NAME, displayName);
148     assetInfo.PutString(MediaColumn::MEDIA_TITLE, MediaFileUtils::GetTitleFromDisplayName(displayName));
149     assetInfo.PutString(MediaColumn::MEDIA_DEVICE_NAME, cmd.GetDeviceName());
150     HandleDateAdded(nowTime, MEDIA_TYPE_PHOTO, assetInfo);
151     // Set subtype if source image is moving photo
152     assetInfo.PutInt(MediaColumn::MEDIA_HIDDEN, info->hidden);
153     if (info->subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
154         assetInfo.PutInt(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::MOVING_PHOTO));
155         int32_t dirty = GetInt32Val(PhotoColumn::PHOTO_DIRTY, resultSet);
156         if (dirty < 0) {
157             assetInfo.PutInt(PhotoColumn::PHOTO_DIRTY, dirty);
158         }
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     SetOwnerAlbumId(assetInfo, resultSet);
166     SetSupportedWatermarkType(sourceFileId, assetInfo, resultSet);
167     cmd.SetValueBucket(assetInfo);
168     cmd.SetTableName(PhotoColumn::PHOTOS_TABLE);
169     int64_t outRowId = -1;
170     int32_t errCode;
171     if (trans == nullptr) {
172         errCode = rdbStore->Insert(cmd, outRowId);
173     } else {
174         errCode = trans->Insert(cmd, outRowId);
175     }
176     CHECK_AND_RETURN_RET_LOG(errCode == NativeRdb::E_OK, E_HAS_DB_ERROR,
177         "Insert into db failed, errCode = %{public}d", errCode);
178     MEDIA_INFO_LOG("insert success, rowId = %{public}d", (int)outRowId);
179     return static_cast<int32_t>(outRowId);
180 }
181 
IsEditedTrashedHidden(const std::shared_ptr<NativeRdb::ResultSet> & ret)182 bool IsEditedTrashedHidden(const std::shared_ptr<NativeRdb::ResultSet> &ret)
183 {
184     if (ret == nullptr) {
185         MEDIA_ERR_LOG("resultset is null");
186         return false;
187     }
188     if (ret->GoToFirstRow() != NativeRdb::E_OK) {
189         MEDIA_ERR_LOG("go to first row failed");
190         return false;
191     }
192     int32_t colIndex = -1;
193     double editTime = -1;
194     double trashedTime = -1;
195     double hiddenTime = -1;
196     MEDIA_INFO_LOG("coIndex1 is %{public}d, editTime is %{public}d", colIndex, static_cast<int>(editTime));
197     ret->GetColumnIndex(PhotoColumn::PHOTO_EDIT_TIME, colIndex);
198     if (ret->GetDouble(colIndex, editTime) != NativeRdb::E_OK) {
199         MEDIA_ERR_LOG("Fail to query DB ");
200         MEDIA_INFO_LOG("coIndex2 is %{public}d, editTime is %{public}d", colIndex, static_cast<int>(editTime));
201         return false;
202     }
203     ret->GetColumnIndex(MediaColumn::MEDIA_DATE_TRASHED, colIndex);
204     if (ret->GetDouble(colIndex, trashedTime) != NativeRdb::E_OK) {
205         MEDIA_ERR_LOG("Fail to query DB ");
206         MEDIA_INFO_LOG("coIndex2 is %{public}d, trashedTime is %{public}d", colIndex, static_cast<int>(trashedTime));
207         return false;
208     }
209     ret->GetColumnIndex(PhotoColumn::PHOTO_HIDDEN_TIME, colIndex);
210     if (ret->GetDouble(colIndex, hiddenTime) != NativeRdb::E_OK) {
211         MEDIA_ERR_LOG("Fail to query DB ");
212         MEDIA_INFO_LOG("coIndex2 is %{public}d, hiddenTime is %{public}d", colIndex, static_cast<int>(hiddenTime));
213         return false;
214     }
215     MEDIA_INFO_LOG("editTime is %{public}d, trashedTime is %{public}d, hiddenTime is %{public}d",
216         static_cast<int>(editTime), static_cast<int>(trashedTime), static_cast<int>(hiddenTime));
217     return (editTime == 0 && trashedTime == 0 && hiddenTime == 0) ? true : false;
218 }
219 
GetPair(MediaLibraryCommand & cmd)220 std::shared_ptr<NativeRdb::ResultSet> EnhancementDatabaseOperations::GetPair(MediaLibraryCommand &cmd)
221 {
222     RdbPredicates firstServicePredicates(PhotoColumn::PHOTOS_TABLE);
223     RdbPredicates clientPredicates = RdbUtils::ToPredicates(cmd.GetDataSharePred(), PhotoColumn::PHOTOS_TABLE);
224     const vector<string> &whereUriArgs = clientPredicates.GetWhereArgs();
225     string UriArg = whereUriArgs.front();
226     if (!MediaFileUtils::StartsWith(UriArg, PhotoColumn::PHOTO_URI_PREFIX)) {
227         return nullptr;
228     }
229     string fileId = MediaFileUri::GetPhotoId(UriArg);
230     MEDIA_INFO_LOG("GetPair_build fileId: %{public}s", fileId.c_str());
231     vector<string> queryColumns = {PhotoColumn::PHOTO_EDIT_TIME, MediaColumn::MEDIA_DATE_TRASHED,
232         PhotoColumn::PHOTO_HIDDEN_TIME};
233     firstServicePredicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
234     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(firstServicePredicates, queryColumns);
235     if (IsEditedTrashedHidden(resultSet)) {
236         MEDIA_INFO_LOG("success into query stage after IsEditedTrashedHidden");
237         RdbPredicates secondServicePredicates(PhotoColumn::PHOTOS_TABLE);
238         secondServicePredicates.EqualTo(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, fileId);
239         vector<string> columns = {};
240         MEDIA_INFO_LOG("start query");
241         auto resultSetCallback = MediaLibraryRdbStore::QueryWithFilter(secondServicePredicates, columns);
242         if (IsEditedTrashedHidden(resultSetCallback)) {
243             return resultSetCallback;
244         }
245     }
246     MEDIA_INFO_LOG("PhotoAsset is edited or trashed or hidden");
247     return nullptr;
248 }
249 } // namespace Media
250 } // namespace OHOS