• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 #include <libxml/parser.h>
16 #include <libxml/tree.h>
17 
18 #include "geo_knowledge_restore.h"
19 
20 #include "backup_database_utils.h"
21 #include "medialibrary_data_manager_utils.h"
22 #include "media_file_utils.h"
23 #include "media_log.h"
24 #include "result_set_utils.h"
25 #include "locale_config.h"
26 #include "upgrade_restore_task_report.h"
27 #include "medialibrary_unistore_manager.h"
28 
29 namespace OHOS::Media {
30 const int32_t PAGE_SIZE = 200;
31 const int32_t UPDATE_GEO = 3;
32 const string NOT_MATCH = "NOT MATCH";
33 const string LATITUDE = "latitude";
34 const string LONGITUDE = "longitude";
35 const string LOCATION_KEY = "location_key";
36 const string LANGUAGE = "language";
37 const string COUNTRY = "country";
38 const string ADMIN_AREA = "admin_area";
39 const string SUB_ADMIN_AREA = "sub_admin_area";
40 const string LOCALITY = "locality";
41 const string SUB_LOCALITY = "sub_locality";
42 const string THOROUGHFARE = "thoroughfare";
43 const string SUB_THOROUGHFARE = "sub_thoroughfare";
44 const string FEATURE_NAME = "feature_name";
45 const string ADDRESS_DESCRIPTION = "address_description";
46 const string FILE_ID = "file_id";
47 const string DATA = "data";
48 const string SINGLE_CH = "zh-Hans";
49 const string SINGLE_EN = "en-Latn-US";
50 const string DOUBLE_CH = "zh";
51 const string DOUBLE_EN = "en";
52 const int32_t GEO_STATUS_SUCCESS = 1;
53 constexpr double DOUBLE_EPSILON = 1e-15;
54 
55 
Init(int32_t sceneCode,std::string taskId,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,std::shared_ptr<NativeRdb::RdbStore> galleryRdb)56 void GeoKnowledgeRestore::Init(int32_t sceneCode, std::string taskId,
57     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb, std::shared_ptr<NativeRdb::RdbStore> galleryRdb)
58 {
59     sceneCode_ = sceneCode;
60     taskId_ = taskId;
61     mediaLibraryRdb_ = mediaLibraryRdb;
62     galleryRdb_ = galleryRdb;
63     batchCnt_ = 0;
64     successInsertCnt_ = 0;
65     successUpdateCnt_ = 0;
66     failInsertCnt_ = 0;
67     failUpdateCnt_ = 0;
68     systemLanguage_ = Global::I18n::LocaleConfig::GetSystemLanguage();
69 }
70 
RestoreGeoKnowledgeInfos()71 void GeoKnowledgeRestore::RestoreGeoKnowledgeInfos()
72 {
73     bool cond = (galleryRdb_ == nullptr || mediaLibraryRdb_ == nullptr);
74     CHECK_AND_RETURN_LOG(!cond, "rdbStore is nullptr");
75     GetGeoKnowledgeInfos();
76 }
77 
GetGeoKnowledgeInfos()78 void GeoKnowledgeRestore::GetGeoKnowledgeInfos()
79 {
80     const std::string QUERY_SQL = "SELECT " + LATITUDE + ", " + LONGITUDE + ", " + LOCATION_KEY + ", " + LANGUAGE + ", "
81         + COUNTRY + ", " + ADMIN_AREA + ", " + SUB_ADMIN_AREA + ", " + LOCALITY + ", " + SUB_LOCALITY + ", "
82         + THOROUGHFARE + ", " + SUB_THOROUGHFARE + ", " + FEATURE_NAME + " "
83         "FROM t_geo_knowledge WHERE COALESCE(" + LANGUAGE + ", '') <> ' ' LIMIT ?, ?";
84     int rowCount = 0;
85     int offset = 0;
86     do {
87         std::vector<NativeRdb::ValueObject> params = {offset, PAGE_SIZE};
88         auto resultSet = galleryRdb_->QuerySql(QUERY_SQL, params);
89         if (resultSet == nullptr) {
90             MEDIA_ERR_LOG("resultSet is nullptr");
91             break;
92         }
93         while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
94             GeoKnowledgeInfo info;
95             info.latitude = GetDoubleVal(LATITUDE, resultSet);
96             info.longitude = GetDoubleVal(LONGITUDE, resultSet);
97             info.locationKey = GetInt64Val(LOCATION_KEY, resultSet);
98             info.language = GetStringVal(LANGUAGE, resultSet);
99             info.country = GetStringVal(COUNTRY, resultSet);
100             info.adminArea = GetStringVal(ADMIN_AREA, resultSet);
101             info.subAdminArea = GetStringVal(SUB_ADMIN_AREA, resultSet);
102             info.locality = GetStringVal(LOCALITY, resultSet);
103             info.subLocality = GetStringVal(SUB_LOCALITY, resultSet);
104             info.thoroughfare = GetStringVal(THOROUGHFARE, resultSet);
105             info.subThoroughfare = GetStringVal(SUB_THOROUGHFARE, resultSet);
106             info.featureName = GetStringVal(FEATURE_NAME, resultSet);
107             albumInfos_.emplace_back(info);
108         }
109         resultSet->GetRowCount(rowCount);
110         offset += PAGE_SIZE;
111         resultSet->Close();
112     } while (rowCount > 0);
113 }
114 
RestoreMaps(std::vector<FileInfo> & fileInfos)115 void GeoKnowledgeRestore::RestoreMaps(std::vector<FileInfo> &fileInfos)
116 {
117     if (mediaLibraryRdb_ == nullptr) {
118         MEDIA_ERR_LOG("rdbStore is nullptr");
119         batchCnt_ = 0;
120         return;
121     }
122     std::vector<std::string> fileIds;
123     std::vector<NativeRdb::ValuesBucket> values;
124     BatchQueryPhoto(fileInfos);
125     for (const auto &fileInfo : fileInfos) {
126         std::string fileIdString = UpdateMapInsertValues(values, fileInfo);
127         if (fileIdString != NOT_MATCH) {
128             fileIds.push_back(fileIdString);
129         }
130     }
131     int64_t rowNum = 0;
132     int32_t errCodeGeo = BatchInsertWithRetry("tab_analysis_geo_knowledge", values, rowNum);
133     if (errCodeGeo != E_OK) {
134         MEDIA_ERR_LOG("GeoKnowledge: RestoreMaps insert fail");
135         ErrorInfo errorInfo(RestoreError::INSERT_FAILED, values.size(),
136             "errCodeGeo: " + std::to_string(errCodeGeo), "GeoKnowledge: RestoreMaps insert fail");
137         UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
138         failInsertCnt_ += batchCnt_;
139         batchCnt_ = 0;
140         return;
141     }
142     successInsertCnt_ += batchCnt_;
143     int32_t errCodeUpdate = BatchUpdate("tab_analysis_total", fileIds);
144     if (errCodeUpdate != E_OK) {
145         MEDIA_ERR_LOG("AnalysisTotal: RestoreMaps update fail");
146         ErrorInfo errorInfo(RestoreError::UPDATE_FAILED, values.size(),
147             "errCodeUpdate: " + std::to_string(errCodeUpdate), "AnalysisTotal: RestoreMaps update fail");
148         UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
149         failUpdateCnt_ += batchCnt_;
150         batchCnt_ = 0;
151         return;
152     }
153     successUpdateCnt_ += batchCnt_;
154     batchCnt_ = 0;
155 }
156 
BatchQueryPhoto(std::vector<FileInfo> & fileInfos)157 void GeoKnowledgeRestore::BatchQueryPhoto(std::vector<FileInfo> &fileInfos)
158 {
159     std::stringstream querySql;
160     querySql << "SELECT " + FILE_ID + ", " + DATA + " FROM Photos WHERE " + DATA + " IN (";
161     std::vector<NativeRdb::ValueObject> params;
162     int32_t count = 0;
163     for (const auto &fileInfo : fileInfos) {
164         // no need query or alreay queried
165         if ((fabs(fileInfo.latitude) < DOUBLE_EPSILON && fabs(fileInfo.latitude) < DOUBLE_EPSILON)
166             || fileInfo.fileIdNew > 0) {
167             continue;
168         }
169         querySql << (count++ > 0 ? "," : "");
170         querySql << "?";
171         params.push_back(fileInfo.cloudPath);
172     }
173     querySql << ")";
174     auto resultSet = mediaLibraryRdb_->QuerySql(querySql.str(), params);
175     CHECK_AND_RETURN_LOG(resultSet != nullptr, "resultSet is nullptr");
176 
177     std::vector<NativeRdb::ValuesBucket> values;
178     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
179         int32_t fileId = GetInt32Val(FILE_ID, resultSet);
180         std::string data = GetStringVal(DATA, resultSet);
181         auto it = std::find_if(fileInfos.begin(), fileInfos.end(),
182             [data](const FileInfo& info) {
183                 return info.cloudPath == data;
184             });
185         if (it == fileInfos.end()) {
186             continue;
187         }
188         it->fileIdNew = fileId;
189     }
190     resultSet->Close();
191 }
192 
UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> & values,const FileInfo & fileInfo)193 std::string GeoKnowledgeRestore::UpdateMapInsertValues(std::vector<NativeRdb::ValuesBucket> &values,
194     const FileInfo &fileInfo)
195 {
196     // no need restore or info missing
197     bool cond =  ((fabs(fileInfo.latitude) < DOUBLE_EPSILON && fabs(fileInfo.latitude) < DOUBLE_EPSILON)
198     || fileInfo.fileIdNew <= 0);
199     CHECK_AND_RETURN_RET(!cond, NOT_MATCH);
200     return UpdateByGeoLocation(values, fileInfo, fileInfo.latitude, fileInfo.longitude);
201 }
202 
UpdateByGeoLocation(std::vector<NativeRdb::ValuesBucket> & values,const FileInfo & fileInfo,const double latitude,const double longitude)203 std::string GeoKnowledgeRestore::UpdateByGeoLocation(
204     std::vector<NativeRdb::ValuesBucket> &values, const FileInfo &fileInfo, const double latitude,
205     const double longitude)
206 {
207     std::string language = systemLanguage_;
208     if (language.empty()) {
209         language = DOUBLE_CH;
210     }
211     if (language == SINGLE_EN) {
212         language = DOUBLE_EN;
213     } else {
214         language = DOUBLE_CH;
215     }
216     auto it = std::find_if(albumInfos_.begin(), albumInfos_.end(),
217         [latitude, longitude, language](const GeoKnowledgeInfo& info) {
218             return std::fabs(info.latitude - latitude) < 0.0001
219         && std::fabs(info.longitude - longitude) < 0.0001 && info.language == language;
220         });
221     if (it == albumInfos_.end()) {
222         return NOT_MATCH;
223     }
224     values.push_back(GetMapInsertValue(it, fileInfo.fileIdNew));
225     batchCnt_++;
226     return std::to_string(fileInfo.fileIdNew);
227 }
228 
GetMapInsertValue(std::vector<GeoKnowledgeInfo>::iterator it,int32_t fileId)229 NativeRdb::ValuesBucket GeoKnowledgeRestore::GetMapInsertValue(std::vector<GeoKnowledgeInfo>::iterator it,
230     int32_t fileId)
231 {
232     NativeRdb::ValuesBucket value;
233     value.PutDouble(LATITUDE, it->latitude);
234     value.PutDouble(LONGITUDE, it->longitude);
235     value.PutLong(LOCATION_KEY, it->locationKey);
236     value.PutString(COUNTRY, it->country);
237     value.PutString(ADMIN_AREA, it->adminArea);
238     value.PutString(SUB_ADMIN_AREA, it->subAdminArea);
239     value.PutString(LOCALITY, it->locality);
240     value.PutString(SUB_LOCALITY, it->subLocality);
241     value.PutString(THOROUGHFARE, it->thoroughfare);
242     value.PutString(SUB_THOROUGHFARE, it->subThoroughfare);
243     value.PutString(FEATURE_NAME, it->featureName);
244     value.PutInt(FILE_ID, fileId);
245     if (it->adminArea == it->locality) {
246         value.PutString(ADDRESS_DESCRIPTION, it->locality + it->subLocality + it->thoroughfare
247         + it->subThoroughfare + it->featureName);
248     } else {
249         value.PutString(ADDRESS_DESCRIPTION, it->adminArea + it->subAdminArea + it->locality
250         + it->subLocality + it->thoroughfare + it->subThoroughfare + it->featureName);
251     }
252 
253     if (it->language == DOUBLE_CH) {
254         value.PutString(LANGUAGE, SINGLE_CH);
255         return value;
256     }
257 
258     value.PutString(LANGUAGE, SINGLE_EN);
259     return value;
260 }
261 
BatchInsertWithRetry(const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)262 int32_t GeoKnowledgeRestore::BatchInsertWithRetry(const std::string &tableName,
263     std::vector<NativeRdb::ValuesBucket> &values, int64_t &rowNum)
264 {
265     if (values.empty()) {
266         return E_OK;
267     }
268     int32_t errCode = E_ERR;
269     TransactionOperations trans{ __func__ };
270     trans.SetBackupRdbStore(mediaLibraryRdb_);
271     std::function<int(void)> func = [&]()->int {
272         errCode = trans.BatchInsert(rowNum, tableName, values);
273         CHECK_AND_PRINT_LOG(errCode == E_OK, "InsertSql failed, errCode: %{public}d, rowNum: %{public}ld.",
274             errCode, (long)rowNum);
275         return errCode;
276     };
277     errCode = trans.RetryTrans(func, true);
278     CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsertWithRetry: tans finish fail!, ret:%{public}d", errCode);
279     return errCode;
280 }
281 
BatchUpdate(const std::string & tableName,std::vector<std::string> & fileIds)282 int32_t GeoKnowledgeRestore::BatchUpdate(const std::string &tableName, std::vector<std::string> &fileIds)
283 {
284     NativeRdb::RdbPredicates updatePredicates(tableName);
285     updatePredicates.In(FILE_ID, fileIds);
286     NativeRdb::ValuesBucket rdbValues;
287     rdbValues.PutInt("geo", UPDATE_GEO);
288     int32_t changedRows = -1;
289     int32_t errCode = E_OK;
290     errCode = mediaLibraryRdb_->Update(changedRows, rdbValues, updatePredicates);
291     CHECK_AND_PRINT_LOG(errCode == E_OK, "Database update failed, errCode = %{public}d", errCode);
292     return errCode;
293 }
294 
ReportGeoRestoreTask()295 void GeoKnowledgeRestore::ReportGeoRestoreTask()
296 {
297     MEDIA_INFO_LOG("GeoKnowledge Insert successInsertCnt_: %{public}d, failInsertCnt_: %{public}d, "
298         "AnalysisTotal Update successUpdateCnt_: %{public}d, failUpdateCnt_: %{public}d, "
299         "Current System Language: %{public}s",
300         successInsertCnt_.load(), failInsertCnt_.load(), successUpdateCnt_.load(),
301         failUpdateCnt_.load(), systemLanguage_.c_str());
302     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
303         .Report("GeoKnowledge Restore", std::to_string(GEO_STATUS_SUCCESS),
304         "successInsertCnt_: " + std::to_string(successInsertCnt_) +
305         ", failInsertCnt_: " + std::to_string(failInsertCnt_) +
306         ", successUpdateCnt_: " + std::to_string(successUpdateCnt_) +
307         ", failUpdateCnt_: " + std::to_string(failUpdateCnt_) +
308         ", Current System Language: " + systemLanguage_);
309 }
310 } // namespace OHOS::Media