• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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