1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #define MLOG_TAG "Scanner"
16
17 #include "media_scanner_db.h"
18
19 #include "abs_rdb_predicates.h"
20 #include "medialibrary_asset_operations.h"
21 #include "media_column.h"
22 #include "media_file_utils.h"
23 #include "media_log.h"
24 #include "medialibrary_command.h"
25 #include "medialibrary_data_manager.h"
26 #include "medialibrary_db_const.h"
27 #include "medialibrary_errno.h"
28 #include "medialibrary_smartalbum_map_operations.h"
29 #include "medialibrary_type_const.h"
30 #include "medialibrary_unistore_manager.h"
31 #include "rdb_errno.h"
32 #include "rdb_utils.h"
33 #include "result_set.h"
34 #include "result_set_utils.h"
35 #include "userfile_manager_types.h"
36 #include "userfilemgr_uri.h"
37 #include "values_bucket.h"
38
39 namespace OHOS {
40 namespace Media {
41 using namespace std;
42 using namespace OHOS::NativeRdb;
43 using namespace OHOS::DataShare;
44
MediaScannerDb()45 MediaScannerDb::MediaScannerDb() {}
46
GetDatabaseInstance()47 unique_ptr<MediaScannerDb> MediaScannerDb::GetDatabaseInstance()
48 {
49 unique_ptr<MediaScannerDb> database = make_unique<MediaScannerDb>();
50 return database;
51 }
52
SetRdbHelper(void)53 void MediaScannerDb::SetRdbHelper(void)
54 {
55 }
56
57 #ifdef MEDIALIBRARY_COMPATIBILITY
SetVirtualPath(const Metadata & metadata,ValuesBucket & values)58 static inline void SetVirtualPath(const Metadata &metadata, ValuesBucket &values)
59 {
60 string relativePath = metadata.GetRelativePath();
61 string displayName = metadata.GetFileName();
62 string virtualPath = (relativePath.back() == '/' ? relativePath : relativePath + "/") + displayName;
63 values.PutString(MediaColumn::MEDIA_VIRTURL_PATH, virtualPath);
64 }
65 #endif
66
SetRemainFileMetadataApi9(const Metadata & metadata,ValuesBucket & values)67 static inline void SetRemainFileMetadataApi9(const Metadata &metadata, ValuesBucket &values)
68 {
69 values.PutString(MEDIA_DATA_DB_AUDIO_ALBUM, metadata.GetAlbum());
70 values.PutString(MEDIA_DATA_DB_ARTIST, metadata.GetFileArtist());
71 values.PutInt(MEDIA_DATA_DB_HEIGHT, metadata.GetFileHeight());
72 values.PutInt(MEDIA_DATA_DB_WIDTH, metadata.GetFileWidth());
73 values.PutInt(MEDIA_DATA_DB_ORIENTATION, metadata.GetOrientation());
74 values.PutString(MEDIA_DATA_DB_BUCKET_NAME, metadata.GetAlbumName());
75 values.PutInt(MEDIA_DATA_DB_PARENT_ID, metadata.GetParentId());
76 values.PutInt(MEDIA_DATA_DB_BUCKET_ID, metadata.GetParentId());
77 values.PutDouble(MEDIA_DATA_DB_LATITUDE, metadata.GetLatitude());
78 values.PutDouble(MEDIA_DATA_DB_LONGITUDE, metadata.GetLongitude());
79 }
80
SetValuesFromMetaDataAndType(const Metadata & metadata,ValuesBucket & values,MediaType mediaType,const string & tableName)81 static void SetValuesFromMetaDataAndType(const Metadata &metadata, ValuesBucket &values, MediaType mediaType,
82 const string &tableName)
83 {
84 #ifdef MEDIALIBRARY_COMPATIBILITY
85 if (mediaType == MediaType::MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO) {
86 if (tableName == MEDIALIBRARY_TABLE) {
87 SetRemainFileMetadataApi9(metadata, values);
88 } else {
89 values.PutInt(MEDIA_DATA_DB_HEIGHT, metadata.GetFileHeight());
90 values.PutInt(MEDIA_DATA_DB_WIDTH, metadata.GetFileWidth());
91 values.PutInt(MEDIA_DATA_DB_ORIENTATION, metadata.GetOrientation());
92 values.PutDouble(MEDIA_DATA_DB_LATITUDE, metadata.GetLongitude());
93 values.PutDouble(MEDIA_DATA_DB_LONGITUDE, metadata.GetLatitude());
94 SetVirtualPath(metadata, values);
95 if (metadata.GetPhotoSubType() != 0) {
96 values.PutInt(PhotoColumn::PHOTO_SUBTYPE, metadata.GetPhotoSubType());
97 }
98 }
99 } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
100 if (tableName == MEDIALIBRARY_TABLE) {
101 SetRemainFileMetadataApi9(metadata, values);
102 } else {
103 values.PutString(MEDIA_DATA_DB_AUDIO_ALBUM, metadata.GetAlbum());
104 values.PutString(MEDIA_DATA_DB_ARTIST, metadata.GetFileArtist());
105 SetVirtualPath(metadata, values);
106 }
107 } else {
108 SetRemainFileMetadataApi9(metadata, values);
109 }
110 #else
111 SetRemainFileMetadataApi9(metadata, values);
112 #endif
113 }
114
SetValuesFromMetaDataApi9(const Metadata & metadata,ValuesBucket & values,bool isInsert,const string & table)115 static void SetValuesFromMetaDataApi9(const Metadata &metadata, ValuesBucket &values, bool isInsert,
116 const string &table)
117 {
118 MediaType mediaType = metadata.GetFileMediaType();
119 values.PutString(MEDIA_DATA_DB_FILE_PATH, metadata.GetFilePath());
120 values.PutString(MEDIA_DATA_DB_RELATIVE_PATH, metadata.GetRelativePath());
121 values.PutString(MEDIA_DATA_DB_MIME_TYPE, metadata.GetFileMimeType());
122 values.PutInt(MEDIA_DATA_DB_MEDIA_TYPE, mediaType);
123 values.PutString(MEDIA_DATA_DB_NAME, metadata.GetFileName());
124 values.PutString(MEDIA_DATA_DB_TITLE, metadata.GetFileTitle());
125 values.PutLong(MEDIA_DATA_DB_SIZE, metadata.GetFileSize());
126 values.PutLong(MEDIA_DATA_DB_DATE_MODIFIED, metadata.GetFileDateModified());
127 values.PutInt(MEDIA_DATA_DB_DURATION, metadata.GetFileDuration());
128 values.PutLong(MEDIA_DATA_DB_DATE_TAKEN, metadata.GetDateTaken());
129 values.PutLong(MEDIA_DATA_DB_TIME_PENDING, 0);
130
131 SetValuesFromMetaDataAndType(metadata, values, mediaType, table);
132
133 if (isInsert) {
134 values.PutLong(MEDIA_DATA_DB_DATE_ADDED, MediaFileUtils::UTCTimeSeconds());
135 }
136 }
137
SetValuesFromMetaDataApi10(const Metadata & metadata,ValuesBucket & values,bool isInsert)138 static void SetValuesFromMetaDataApi10(const Metadata &metadata, ValuesBucket &values, bool isInsert)
139 {
140 MediaType mediaType = metadata.GetFileMediaType();
141
142 values.PutString(MediaColumn::MEDIA_FILE_PATH, metadata.GetFilePath());
143 values.PutString(MediaColumn::MEDIA_MIME_TYPE, metadata.GetFileMimeType());
144 values.PutInt(MediaColumn::MEDIA_TYPE, mediaType);
145
146 values.PutLong(MediaColumn::MEDIA_SIZE, metadata.GetFileSize());
147 values.PutLong(MediaColumn::MEDIA_DATE_MODIFIED, metadata.GetFileDateModified());
148 values.PutInt(MediaColumn::MEDIA_DURATION, metadata.GetFileDuration());
149 values.PutLong(MediaColumn::MEDIA_DATE_TAKEN, metadata.GetDateTaken());
150 values.PutLong(MediaColumn::MEDIA_TIME_PENDING, 0);
151
152 if (mediaType == MediaType::MEDIA_TYPE_IMAGE || mediaType == MEDIA_TYPE_VIDEO) {
153 values.PutInt(PhotoColumn::PHOTO_HEIGHT, metadata.GetFileHeight());
154 values.PutInt(PhotoColumn::PHOTO_WIDTH, metadata.GetFileWidth());
155 values.PutInt(PhotoColumn::PHOTO_ORIENTATION, metadata.GetOrientation());
156 values.PutDouble(PhotoColumn::PHOTO_LONGITUDE, metadata.GetLongitude());
157 values.PutDouble(PhotoColumn::PHOTO_LATITUDE, metadata.GetLatitude());
158 values.PutString(PhotoColumn::PHOTO_USER_COMMENT, metadata.GetUserComment());
159 values.PutString(PhotoColumn::PHOTO_ALL_EXIF, metadata.GetAllExif());
160 #ifdef MEDIALIBRARY_COMPATIBILITY
161 if (metadata.GetPhotoSubType() != 0) {
162 values.PutInt(PhotoColumn::PHOTO_SUBTYPE, metadata.GetPhotoSubType());
163 }
164 #endif
165 } else if (mediaType == MediaType::MEDIA_TYPE_AUDIO) {
166 values.PutString(AudioColumn::AUDIO_ALBUM, metadata.GetAlbum());
167 values.PutString(AudioColumn::AUDIO_ARTIST, metadata.GetFileArtist());
168 }
169
170 if (isInsert) {
171 values.PutLong(MEDIA_DATA_DB_DATE_ADDED, MediaFileUtils::UTCTimeSeconds());
172 }
173 }
174
GetTableNameByPath(int32_t mediaType,string & tableName,const string & path="")175 static void GetTableNameByPath(int32_t mediaType, string &tableName, const string &path = "")
176 {
177 if (!path.empty() && MediaFileUtils::IsFileTablePath(path)) {
178 tableName = MEDIALIBRARY_TABLE;
179 return;
180 }
181 switch (mediaType) {
182 case MediaType::MEDIA_TYPE_IMAGE:
183 case MediaType::MEDIA_TYPE_VIDEO: {
184 tableName = PhotoColumn::PHOTOS_TABLE;
185 break;
186 }
187 case MediaType::MEDIA_TYPE_AUDIO: {
188 tableName = AudioColumn::AUDIOS_TABLE;
189 break;
190 }
191 default: {
192 tableName = MEDIALIBRARY_TABLE;
193 break;
194 }
195 }
196 }
197
InsertMetadata(const Metadata & metadata,string & tableName,MediaLibraryApi api)198 string MediaScannerDb::InsertMetadata(const Metadata &metadata, string &tableName, MediaLibraryApi api)
199 {
200 MediaType mediaType = metadata.GetFileMediaType();
201 string mediaTypeUri;
202 ValuesBucket values;
203 if (api == MediaLibraryApi::API_10) {
204 mediaTypeUri = MediaFileUtils::GetMediaTypeUriV10(mediaType);
205 } else {
206 mediaTypeUri = MediaFileUtils::GetMediaTypeUri(mediaType);
207 #ifdef MEDIALIBRARY_COMPATIBILITY
208 if ((mediaType != MediaType::MEDIA_TYPE_IMAGE) && (mediaType != MediaType::MEDIA_TYPE_VIDEO) &&
209 (mediaType != MediaType::MEDIA_TYPE_AUDIO)) {
210 values.PutString(MEDIA_DATA_DB_URI, mediaTypeUri);
211 }
212 #else
213 values.PutString(MEDIA_DATA_DB_URI, mediaTypeUri);
214 #endif
215 }
216
217 tableName = MEDIALIBRARY_TABLE;
218 if (api == MediaLibraryApi::API_10) {
219 SetValuesFromMetaDataApi10(metadata, values, true);
220 GetTableNameByPath(mediaType, tableName);
221 } else {
222 #ifdef MEDIALIBRARY_COMPATIBILITY
223 GetTableNameByPath(mediaType, tableName, metadata.GetFilePath());
224 #endif
225 SetValuesFromMetaDataApi9(metadata, values, true, tableName);
226 }
227
228 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
229 CHECK_AND_RETURN_RET(rdbStore != nullptr, "");
230 auto rdbStorePtr = rdbStore->GetRaw();
231 CHECK_AND_RETURN_RET(rdbStorePtr != nullptr, "");
232
233 int64_t rowNum = 0;
234 int32_t result = rdbStorePtr->Insert(rowNum, tableName, values);
235 if (rowNum <= 0 || result != NativeRdb::E_OK) {
236 MEDIA_ERR_LOG("MediaDataAbility Insert functionality is failed, return %{public}ld", (long)rowNum);
237 return "";
238 }
239
240 if (mediaTypeUri.empty()) {
241 return "";
242 }
243 if (api == MediaLibraryApi::API_10) {
244 return MediaFileUtils::GetUriByExtrConditions(mediaTypeUri + "/", to_string(rowNum),
245 MediaFileUtils::GetExtraUri(metadata.GetFileName(), metadata.GetFilePath())) + "?api_version=10";
246 }
247 return MediaFileUtils::GetUriByExtrConditions(mediaTypeUri + "/", to_string(rowNum));
248 }
249
BatchInsert(const vector<Metadata> & metadataList)250 vector<string> MediaScannerDb::BatchInsert(const vector<Metadata> &metadataList)
251 {
252 vector<string> insertUriList;
253 for (auto itr : metadataList) {
254 string tableName;
255 insertUriList.push_back(InsertMetadata(itr, tableName));
256 }
257
258 return insertUriList;
259 }
260
GetUriStringInUpdate(MediaType mediaType,MediaLibraryApi api,string & mediaTypeUri,ValuesBucket & values)261 static inline void GetUriStringInUpdate(MediaType mediaType, MediaLibraryApi api, string &mediaTypeUri,
262 ValuesBucket &values)
263 {
264 if (api == MediaLibraryApi::API_10) {
265 mediaTypeUri = MediaFileUtils::GetMediaTypeUriV10(mediaType);
266 } else {
267 mediaTypeUri = MediaFileUtils::GetMediaTypeUri(mediaType);
268 #ifdef MEDIALIBRARY_COMPATIBILITY
269 if ((mediaType != MediaType::MEDIA_TYPE_IMAGE) && (mediaType != MediaType::MEDIA_TYPE_VIDEO) &&
270 (mediaType != MediaType::MEDIA_TYPE_AUDIO)) {
271 values.PutString(MEDIA_DATA_DB_URI, mediaTypeUri);
272 }
273 #else
274 values.PutString(MEDIA_DATA_DB_URI, mediaTypeUri);
275 #endif
276 }
277 }
278
279 /**
280 * @brief Update single metadata in the media database
281 *
282 * @param metadata The metadata object which has the information about the file
283 * @return string The mediatypeUri corresponding to the given metadata
284 */
UpdateMetadata(const Metadata & metadata,string & tableName,MediaLibraryApi api)285 string MediaScannerDb::UpdateMetadata(const Metadata &metadata, string &tableName, MediaLibraryApi api)
286 {
287 int32_t updateCount(0);
288 ValuesBucket values;
289 string whereClause = MEDIA_DATA_DB_ID + " = ?";
290 vector<string> whereArgs = { to_string(metadata.GetFileId()) };
291 MediaType mediaType = metadata.GetFileMediaType();
292 string mediaTypeUri;
293 GetUriStringInUpdate(mediaType, api, mediaTypeUri, values);
294
295 tableName = MEDIALIBRARY_TABLE;
296 if (api == MediaLibraryApi::API_10) {
297 SetValuesFromMetaDataApi10(metadata, values, false);
298 GetTableNameByPath(mediaType, tableName);
299 } else {
300 #ifdef MEDIALIBRARY_COMPATIBILITY
301 GetTableNameByPath(mediaType, tableName, metadata.GetFilePath());
302 #endif
303 SetValuesFromMetaDataApi9(metadata, values, false, tableName);
304 }
305
306 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
307 if (rdbStore == nullptr) {
308 return "";
309 }
310 auto rdbStorePtr = rdbStore->GetRaw();
311 if (rdbStorePtr == nullptr) {
312 return "";
313 }
314 int32_t result = rdbStorePtr->Update(updateCount, tableName, values, whereClause, whereArgs);
315 if (result != NativeRdb::E_OK || updateCount <= 0) {
316 MEDIA_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
317 return "";
318 }
319 if (mediaTypeUri.empty()) {
320 return "";
321 }
322 if (api == MediaLibraryApi::API_10) {
323 return MediaFileUtils::GetUriByExtrConditions(mediaTypeUri + "/", to_string(metadata.GetFileId()),
324 MediaFileUtils::GetExtraUri(metadata.GetFileName(), metadata.GetFilePath())) + "?api_version=10";
325 }
326 return MediaFileUtils::GetUriByExtrConditions(mediaTypeUri + "/", to_string(metadata.GetFileId()));
327 }
328
329 /**
330 * @brief Deletes particular entry in database based on row id
331 *
332 * @param idList The list of IDs to be deleted from the media db
333 * @return bool Status of the delete operation
334 */
DeleteMetadata(const vector<string> & idList,const string & tableName)335 bool MediaScannerDb::DeleteMetadata(const vector<string> &idList, const string &tableName)
336 {
337 if (idList.size() == 0) {
338 MEDIA_ERR_LOG("to-deleted idList size equals to 0");
339 return false;
340 }
341
342 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
343 if (rdbStore == nullptr) {
344 MEDIA_ERR_LOG("rdbStore is nullptr");
345 return E_ERR;
346 }
347
348 NativeRdb::RdbPredicates rdbPredicate(tableName);
349 rdbPredicate.In(MEDIA_DATA_DB_ID, idList);
350 int32_t ret = rdbStore->Delete(rdbPredicate);
351 return ret == static_cast<int32_t>(idList.size());
352 }
353
GetOprnObjectFromPath(const string & path)354 static OperationObject GetOprnObjectFromPath(const string &path)
355 {
356 const map<string, OperationObject> oprnMap = {
357 { ROOT_MEDIA_DIR + PHOTO_BUCKET, OperationObject::FILESYSTEM_PHOTO },
358 { ROOT_MEDIA_DIR + AUDIO_BUCKET, OperationObject::FILESYSTEM_AUDIO },
359 #ifdef MEDIALIBRARY_COMPATIBILITY
360 { ROOT_MEDIA_DIR + PIC_DIR_VALUES, OperationObject::FILESYSTEM_PHOTO },
361 { ROOT_MEDIA_DIR + AUDIO_DIR_VALUES, OperationObject::FILESYSTEM_AUDIO },
362 { ROOT_MEDIA_DIR + VIDEO_DIR_VALUES, OperationObject::FILESYSTEM_PHOTO },
363 { ROOT_MEDIA_DIR + CAMERA_DIR_VALUES, OperationObject::FILESYSTEM_PHOTO }
364 #endif
365 };
366
367 for (const auto &iter : oprnMap) {
368 if (path.find(iter.first) != string::npos) {
369 return iter.second;
370 }
371 }
372 return OperationObject::FILESYSTEM_ASSET;
373 }
374
GetQueryParamsByPath(const string & path,MediaLibraryApi api,vector<string> & columns,OperationObject & oprnObject,string & whereClause)375 static void GetQueryParamsByPath(const string &path, MediaLibraryApi api, vector<string> &columns,
376 OperationObject &oprnObject, string &whereClause)
377 {
378 oprnObject = GetOprnObjectFromPath(path);
379 if (api == MediaLibraryApi::API_10) {
380 whereClause = MediaColumn::MEDIA_FILE_PATH + " = ?";
381 if (oprnObject == OperationObject::FILESYSTEM_PHOTO) {
382 columns = {
383 MediaColumn::MEDIA_ID, MediaColumn::MEDIA_SIZE, MediaColumn::MEDIA_DATE_MODIFIED,
384 MediaColumn::MEDIA_NAME, PhotoColumn::PHOTO_ORIENTATION
385 };
386 } else if (oprnObject == OperationObject::FILESYSTEM_AUDIO) {
387 columns = {
388 MediaColumn::MEDIA_ID, MediaColumn::MEDIA_SIZE, MediaColumn::MEDIA_DATE_MODIFIED,
389 MediaColumn::MEDIA_NAME
390 };
391 }
392 } else {
393 #ifndef MEDIALIBRARY_COMPATIBILITY
394 oprnObject = OperationObject::FILESYSTEM_ASSET;
395 #endif
396 if (oprnObject == OperationObject::FILESYSTEM_PHOTO) {
397 whereClause = MediaColumn::MEDIA_FILE_PATH + " = ?";
398 columns = {
399 MediaColumn::MEDIA_ID, MediaColumn::MEDIA_SIZE, MediaColumn::MEDIA_DATE_MODIFIED,
400 MediaColumn::MEDIA_NAME, PhotoColumn::PHOTO_ORIENTATION
401 };
402 } else if (oprnObject == OperationObject::FILESYSTEM_AUDIO) {
403 whereClause = MediaColumn::MEDIA_FILE_PATH + " = ?";
404 columns = {
405 MediaColumn::MEDIA_ID, MediaColumn::MEDIA_SIZE, MediaColumn::MEDIA_DATE_MODIFIED,
406 MediaColumn::MEDIA_NAME
407 };
408 } else {
409 whereClause = MEDIA_DATA_DB_FILE_PATH + " = ? And " + MEDIA_DATA_DB_IS_TRASH + " = ? ";
410 columns = {
411 MEDIA_DATA_DB_ID, MEDIA_DATA_DB_SIZE, MEDIA_DATA_DB_DATE_MODIFIED,
412 MEDIA_DATA_DB_NAME, MEDIA_DATA_DB_ORIENTATION, MEDIA_DATA_DB_RECYCLE_PATH
413 };
414 }
415 }
416 }
417
418 /**
419 * @brief Get date modified, id, size and name info for a file
420 *
421 * @param path The file path for which to obtain the latest modification info from the db
422 * @return unique_ptr<Metadata> The metadata object representing the latest info for the given filepath
423 */
GetFileBasicInfo(const string & path,unique_ptr<Metadata> & ptr,MediaLibraryApi api)424 int32_t MediaScannerDb::GetFileBasicInfo(const string &path, unique_ptr<Metadata> &ptr, MediaLibraryApi api)
425 {
426 vector<string> columns;
427 string whereClause;
428 OperationObject oprnObject = OperationObject::FILESYSTEM_ASSET;
429 GetQueryParamsByPath(path, api, columns, oprnObject, whereClause);
430
431 vector<string> args;
432 if (oprnObject == OperationObject::FILESYSTEM_PHOTO || oprnObject == OperationObject::FILESYSTEM_AUDIO) {
433 args = { path };
434 } else {
435 args = { path, to_string(NOT_TRASHED) };
436 }
437
438 MediaLibraryCommand cmd(oprnObject, OperationType::QUERY, api);
439 cmd.GetAbsRdbPredicates()->SetWhereClause(whereClause);
440 cmd.GetAbsRdbPredicates()->SetWhereArgs(args);
441
442 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
443 if (rdbStore == nullptr) {
444 return E_RDB;
445 }
446 auto resultSet = rdbStore->Query(cmd, columns);
447 if (resultSet == nullptr) {
448 MEDIA_ERR_LOG("return nullptr when query rdb");
449 return E_RDB;
450 }
451
452 int32_t rowCount = 0;
453 int32_t ret = resultSet->GetRowCount(rowCount);
454 if (ret != NativeRdb::E_OK) {
455 MEDIA_ERR_LOG("failed to get row count");
456 return E_RDB;
457 }
458
459 if (rowCount == 0) {
460 return E_OK;
461 }
462
463 ret = resultSet->GoToFirstRow();
464 if (ret != NativeRdb::E_OK) {
465 MEDIA_ERR_LOG("failed to go to first row");
466 return E_RDB;
467 }
468 ptr->SetTableName(cmd.GetTableName());
469
470 return FillMetadata(resultSet, ptr);
471 }
472
PreparePredicatesAndColumns(const string & path,const string & tableName,const string & whitePath,AbsRdbPredicates & predicates,vector<string> & columns)473 static void PreparePredicatesAndColumns(const string &path, const string &tableName, const string &whitePath,
474 AbsRdbPredicates &predicates, vector<string> &columns)
475 {
476 string querySql;
477 vector<string> args;
478 if (whitePath.empty()) {
479 if (tableName == MEDIALIBRARY_TABLE) {
480 querySql = MEDIA_DATA_DB_FILE_PATH + " LIKE ? AND " + MEDIA_DATA_DB_IS_TRASH + " = ? ";
481 args = { path.back() != '/' ? path + "/%" : path + "%", to_string(NOT_TRASHED) };
482 columns = { MEDIA_DATA_DB_ID, MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_DATA_DB_RECYCLE_PATH };
483 } else {
484 querySql = MEDIA_DATA_DB_FILE_PATH + " LIKE ? AND " + MediaColumn::MEDIA_TIME_PENDING + " <> ? ";
485 args= { path.back() != '/' ? path + "/%" : path + "%", to_string(UNCREATE_FILE_TIMEPENDING) };
486 columns = { MEDIA_DATA_DB_ID, MEDIA_DATA_DB_MEDIA_TYPE };
487 }
488 } else {
489 if (tableName == MEDIALIBRARY_TABLE) {
490 querySql = MEDIA_DATA_DB_FILE_PATH + " LIKE ? AND " + MEDIA_DATA_DB_FILE_PATH + " NOT LIKE ? AND " +
491 MEDIA_DATA_DB_IS_TRASH + " = ? ";
492 args = { path.back() != '/' ? path + "/%" : path + "%",
493 whitePath.back() != '/' ? whitePath + "/%" : whitePath + "%", to_string(NOT_TRASHED) };
494 columns = { MEDIA_DATA_DB_ID, MEDIA_DATA_DB_MEDIA_TYPE, MEDIA_DATA_DB_RECYCLE_PATH };
495 } else {
496 querySql = MEDIA_DATA_DB_FILE_PATH + " LIKE ? AND " + MEDIA_DATA_DB_FILE_PATH + " NOT LIKE ? AND " +
497 MediaColumn::MEDIA_TIME_PENDING + " <> ? ";
498 args= { path.back() != '/' ? path + "/%" : path + "%",
499 whitePath.back() != '/' ? whitePath + "/%" : whitePath + "%", to_string(UNCREATE_FILE_TIMEPENDING) };
500 columns = { MEDIA_DATA_DB_ID, MEDIA_DATA_DB_MEDIA_TYPE };
501 }
502 }
503
504 predicates.SetWhereClause(querySql);
505 predicates.SetWhereArgs(args);
506 }
507
508 /**
509 * @brief Get the list of all IDs corresponding to given path
510 *
511 * @param path The path from which to obtain the list of child IDs
512 * @return unordered_map<int32_t, MediaType> The list of IDS along with mediaType information
513 */
GetIdsFromFilePath(const string & path,const string & tableName,const string & whitePath)514 unordered_map<int32_t, MediaType> MediaScannerDb::GetIdsFromFilePath(const string &path, const string &tableName,
515 const string &whitePath)
516 {
517 unordered_map<int32_t, MediaType> idMap = {};
518 AbsRdbPredicates predicates(tableName);
519 vector<string> columns;
520 PreparePredicatesAndColumns(path, tableName, whitePath, predicates, columns);
521
522 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
523 if (rdbStore == nullptr) {
524 return idMap;
525 }
526 auto rdbStorePtr = rdbStore->GetRaw();
527 if (rdbStorePtr == nullptr) {
528 return idMap;
529 }
530 auto resultSet = rdbStorePtr->Query(predicates, columns);
531 if (resultSet == nullptr) {
532 return idMap;
533 }
534
535 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
536 if (tableName == MEDIALIBRARY_TABLE) {
537 string recyclePath = GetStringVal(MEDIA_DATA_DB_RECYCLE_PATH, resultSet);
538 if (!recyclePath.empty()) {
539 continue;
540 }
541 }
542 int32_t id = GetInt32Val(MEDIA_DATA_DB_ID, resultSet);
543 int32_t mediaType = GetInt32Val(MEDIA_DATA_DB_MEDIA_TYPE, resultSet);
544 idMap.emplace(make_pair(id, static_cast<MediaType>(mediaType)));
545 }
546 return idMap;
547 }
548
GetFileDBUriFromPath(const string & path)549 string MediaScannerDb::GetFileDBUriFromPath(const string &path)
550 {
551 string uri;
552
553 vector<string> columns = {};
554 columns.push_back(MEDIA_DATA_DB_URI);
555
556 DataShare::DataSharePredicates predicates;
557 predicates.SetWhereClause(MEDIA_DATA_DB_FILE_PATH + " = ? AND " + MEDIA_DATA_DB_IS_TRASH + " = ?");
558 vector<string> args = { path, to_string(NOT_TRASHED) };
559 predicates.SetWhereArgs(args);
560
561 Uri queryUri(MEDIALIBRARY_DATA_URI);
562 MediaLibraryCommand cmd(queryUri, OperationType::QUERY);
563 int errCode = 0;
564 auto resultSet = MediaLibraryDataManager::GetInstance()->QueryRdb(cmd, columns, predicates, errCode);
565 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, uri, "No entries found for this path");
566 if ((resultSet == nullptr) || (resultSet->GoToFirstRow() != NativeRdb::E_OK)) {
567 MEDIA_ERR_LOG("No result found for this path");
568 return uri;
569 }
570
571 int32_t intValue(0);
572 int32_t columnIndex(0);
573 resultSet->GetColumnIndex(MEDIA_DATA_DB_ID, columnIndex);
574 resultSet->GetInt(columnIndex, intValue);
575 uri = MEDIALIBRARY_DATA_URI + "/" + to_string(intValue);
576 return uri;
577 }
578
GetIdFromPath(const string & path)579 int32_t MediaScannerDb::GetIdFromPath(const string &path)
580 {
581 int32_t id = UNKNOWN_ID;
582 int32_t columnIndex = -1;
583
584 DataShare::DataSharePredicates predicates;
585 predicates.SetWhereClause(MEDIA_DATA_DB_FILE_PATH + " = ? AND " + MEDIA_DATA_DB_IS_TRASH + " = ?");
586 vector<string> args = { path, to_string(NOT_TRASHED) };
587 predicates.SetWhereArgs(args);
588
589 Uri uri(MEDIALIBRARY_DATA_URI);
590 MediaLibraryCommand cmd(uri, OperationType::QUERY);
591 vector<string> columns = {MEDIA_DATA_DB_ID};
592 int errCode = 0;
593 auto resultSet = MediaLibraryDataManager::GetInstance()->QueryRdb(cmd, columns, predicates, errCode);
594 if ((resultSet == nullptr) || (resultSet->GoToFirstRow() != NativeRdb::E_OK)) {
595 MEDIA_ERR_LOG("No data found for the given path %{private}s", path.c_str());
596 return id;
597 }
598
599 resultSet->GetColumnIndex(MEDIA_DATA_DB_ID, columnIndex);
600 resultSet->GetInt(columnIndex, id);
601
602 return id;
603 }
604
ReadAlbums(const string & path,unordered_map<string,Metadata> & albumMap)605 int32_t MediaScannerDb::ReadAlbums(const string &path, unordered_map<string, Metadata> &albumMap)
606 {
607 if ((path + "/").find(ROOT_MEDIA_DIR) != 0) {
608 return E_INVALID_ARGUMENTS;
609 }
610
611 AbsRdbPredicates predicates(MEDIALIBRARY_TABLE);
612 string queryCmd = MEDIA_DATA_DB_MEDIA_TYPE + " = ? AND " + MEDIA_DATA_DB_FILE_PATH + " like ? AND " +
613 MEDIA_DATA_DB_IS_TRASH + " = ?";
614 string queryPath = path.back() != '/' ? path + "/%" : path + "%";
615 vector<string> args = { to_string(MediaType::MEDIA_TYPE_ALBUM), queryPath, to_string(NOT_TRASHED) };
616 predicates.SetWhereClause(queryCmd);
617 predicates.SetWhereArgs(args);
618 vector<string> columns = {MEDIA_DATA_DB_ID, MEDIA_DATA_DB_FILE_PATH, MEDIA_DATA_DB_DATE_MODIFIED};
619
620 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
621 if (rdbStore == nullptr) {
622 return E_HAS_DB_ERROR;
623 }
624 auto rdbStorePtr = rdbStore->GetRaw();
625 if (rdbStorePtr == nullptr) {
626 return E_HAS_DB_ERROR;
627 }
628 auto resultSet = rdbStorePtr->Query(predicates, columns);
629 if (resultSet == nullptr) {
630 return E_HAS_DB_ERROR;
631 }
632
633 albumMap.clear();
634 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
635 Metadata metadata;
636 int32_t intValue = GetInt32Val(MEDIA_DATA_DB_ID, resultSet);
637 metadata.SetFileId(intValue);
638 string strValue = GetStringVal(MEDIA_DATA_DB_FILE_PATH, resultSet);
639 metadata.SetFilePath(strValue);
640 int64_t dateModified = GetInt64Val(MEDIA_DATA_DB_DATE_MODIFIED, resultSet);
641 metadata.SetFileDateModified(dateModified);
642 albumMap.insert(make_pair(strValue, metadata));
643 }
644
645 return E_OK;
646 }
647
InsertAlbum(const Metadata & metadata)648 int32_t MediaScannerDb::InsertAlbum(const Metadata &metadata)
649 {
650 int32_t id = 0;
651
652 string tableName;
653 string uri = InsertMetadata(metadata, tableName);
654 id = stoi(MediaLibraryDataManagerUtils::GetIdFromUri(uri));
655
656 return id;
657 }
658
UpdateAlbum(const Metadata & metadata)659 int32_t MediaScannerDb::UpdateAlbum(const Metadata &metadata)
660 {
661 int32_t id = 0;
662
663 string tableName;
664 string uri = UpdateMetadata(metadata, tableName);
665 id = stoi(MediaLibraryDataManagerUtils::GetIdFromUri(uri));
666
667 return id;
668 }
669
NotifyDatabaseChange(const MediaType mediaType)670 void MediaScannerDb::NotifyDatabaseChange(const MediaType mediaType)
671 {
672 string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
673 Uri uri(notifyUri);
674
675 MediaLibraryDataManager::GetInstance()->NotifyChange(uri);
676 }
677
ExtractMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> & resultSet,unique_ptr<Metadata> & metadata,const std::string & col)678 void MediaScannerDb::ExtractMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> &resultSet,
679 unique_ptr<Metadata> &metadata, const std::string &col)
680 {
681 ResultSetDataType dataType = ResultSetDataType::TYPE_NULL;
682 Metadata::MetadataFnPtr requestFunc = nullptr;
683 auto itr = metadata->memberFuncMap_.find(col);
684 if (itr != metadata->memberFuncMap_.end()) {
685 dataType = itr->second.first;
686 requestFunc = itr->second.second;
687 } else {
688 MEDIA_ERR_LOG("invalid column name %{private}s", col.c_str());
689 return;
690 }
691
692 std::variant<int32_t, std::string, int64_t, double> data =
693 ResultSetUtils::GetValFromColumn<const shared_ptr<NativeRdb::ResultSet>>(col, resultSet, dataType);
694
695 // Use the function pointer from map and pass data to fn ptr
696 if (requestFunc != nullptr) {
697 (metadata.get()->*requestFunc)(data);
698 }
699 }
700
FillMetadata(const shared_ptr<NativeRdb::ResultSet> & resultSet,unique_ptr<Metadata> & ptr)701 int32_t MediaScannerDb::FillMetadata(const shared_ptr<NativeRdb::ResultSet> &resultSet,
702 unique_ptr<Metadata> &ptr)
703 {
704 std::vector<std::string> columnNames;
705 int32_t err = resultSet->GetAllColumnNames(columnNames);
706 if (err != NativeRdb::E_OK) {
707 MEDIA_ERR_LOG("failed to get all column names");
708 return E_RDB;
709 }
710
711 for (const auto &col : columnNames) {
712 ExtractMetaFromColumn(resultSet, ptr, col);
713 }
714
715 return E_OK;
716 }
717
RecordError(const std::string & err)718 int32_t MediaScannerDb::RecordError(const std::string &err)
719 {
720 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
721 if (rdbStore == nullptr) {
722 MEDIA_ERR_LOG("rdbStore is nullptr");
723 return E_ERR;
724 }
725
726 ValuesBucket valuesBucket;
727 valuesBucket.PutString(MEDIA_DATA_ERROR, err);
728 int64_t outRowId = -1;
729 auto rdbStorePtr = rdbStore->GetRaw();
730 if (rdbStorePtr == nullptr) {
731 MEDIA_ERR_LOG("rdbStorePtr is nullptr");
732 return E_ERR;
733 }
734 int32_t ret = rdbStorePtr->Insert(outRowId, MEDIALIBRARY_ERROR_TABLE, valuesBucket);
735 if (ret) {
736 MEDIA_ERR_LOG("rdb insert err %{public}d", ret);
737 return E_ERR;
738 }
739
740 return E_OK;
741 }
742
ReadError()743 std::set<std::string> MediaScannerDb::ReadError()
744 {
745 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
746 if (rdbStore == nullptr) {
747 MEDIA_ERR_LOG("rdbStore is nullptr");
748 return {};
749 }
750
751 AbsRdbPredicates predicates(MEDIALIBRARY_ERROR_TABLE);
752 vector<string> columns = { MEDIA_DATA_ERROR };
753 auto rdbStorePtr = rdbStore->GetRaw();
754 if (rdbStorePtr == nullptr) {
755 MEDIA_ERR_LOG("rdbStorePtr is nullptr");
756 return {};
757 }
758 auto resultSet = rdbStorePtr->Query(predicates, columns);
759 if (resultSet == nullptr) {
760 MEDIA_ERR_LOG("rdb query return nullptr");
761 return {};
762 }
763
764 int32_t rowCount = 0;
765 if (resultSet->GetRowCount(rowCount) != NativeRdb::E_OK) {
766 MEDIA_ERR_LOG("failed to get row count");
767 return {};
768 }
769
770 if (rowCount == 0) {
771 return {};
772 }
773
774 string str;
775 set<string> errSet;
776 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
777 resultSet->GetString(0, str);
778 errSet.insert(move(str));
779 }
780
781 return errSet;
782 }
783
DeleteError(const std::string & err)784 int32_t MediaScannerDb::DeleteError(const std::string &err)
785 {
786 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
787 if (rdbStore == nullptr) {
788 MEDIA_ERR_LOG("rdbStore is nullptr");
789 return E_ERR;
790 }
791
792 int32_t outRowId = -1;
793 string whereClause = MEDIA_DATA_ERROR + " = ?";
794 vector<string> whereArgs= { err };
795 auto rdbStorePtr = rdbStore->GetRaw();
796 if (rdbStorePtr == nullptr) {
797 MEDIA_ERR_LOG("rdbStorePtr is nullptr");
798 return E_ERR;
799 }
800 int32_t ret = rdbStorePtr->Delete(outRowId, MEDIALIBRARY_ERROR_TABLE, whereClause, whereArgs);
801 if (ret) {
802 MEDIA_ERR_LOG("rdb delete err %{public}d", ret);
803 return E_ERR;
804 }
805
806 return E_OK;
807 }
808 } // namespace Media
809 } // namespace OHOS
810