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 #include "media_library_db_upgrade.h"
16
17 #include <string>
18 #include <vector>
19
20 #include "dfx_transaction.h"
21 #include "rdb_store.h"
22 #include "media_log.h"
23 #include "album_plugin_table_event_handler.h"
24 #include "db_upgrade_utils.h"
25 #include "medialibrary_rdb_transaction.h"
26 #include "photo_day_month_year_operation.h"
27
28 namespace OHOS::Media {
29 namespace DataTransfer {
30 /**
31 * @brief Upgrade the database, before data restore or clone.
32 */
OnUpgrade(NativeRdb::RdbStore & store)33 int32_t MediaLibraryDbUpgrade::OnUpgrade(NativeRdb::RdbStore &store)
34 {
35 int32_t ret = NativeRdb::E_OK;
36 MEDIA_INFO_LOG("Media_Restore: MediaLibraryDbUpgrade::OnUpgrade start");
37 ret = this->UpgradeAlbumPlugin(store);
38 if (ret != NativeRdb::E_OK) {
39 return ret;
40 }
41 ret = this->UpgradePhotoAlbum(store);
42 if (ret != NativeRdb::E_OK) {
43 return ret;
44 }
45 ret = this->UpgradePhotos(store);
46 if (ret != NativeRdb::E_OK) {
47 return ret;
48 }
49 ret = this->UpgradePhotoMap(store);
50 if (ret != NativeRdb::E_OK) {
51 return ret;
52 }
53 ret = this->MergeAlbumFromOldBundleNameToNewBundleName(store);
54 if (ret != NativeRdb::E_OK) {
55 return ret;
56 }
57 ret = this->UpgradePhotosBelongsToAlbum(store);
58 if (ret != NativeRdb::E_OK) {
59 return ret;
60 }
61 MEDIA_INFO_LOG("Media_Restore: MediaLibraryDbUpgrade::OnUpgrade end");
62 return NativeRdb::E_OK;
63 }
64
ExecSqlWithRetry(std::function<int32_t ()> execSql)65 int32_t MediaLibraryDbUpgrade::ExecSqlWithRetry(std::function<int32_t()> execSql)
66 {
67 int currentTime = 0;
68 int32_t busyRetryTime = 0;
69 int32_t err = NativeRdb::E_OK;
70 while (busyRetryTime < MAX_BUSY_TRY_TIMES && currentTime <= MAX_TRY_TIMES) {
71 err = execSql();
72 if (err == NativeRdb::E_OK) {
73 break;
74 } else if (err == NativeRdb::E_SQLITE_LOCKED) {
75 std::this_thread::sleep_for(std::chrono::milliseconds(TRANSACTION_WAIT_INTERVAL));
76 currentTime++;
77 MEDIA_ERR_LOG("ExecuteSqlInternal busy, ret:%{public}d, time:%{public}d", err, currentTime);
78 } else if (err == NativeRdb::E_SQLITE_BUSY || err == NativeRdb::E_DATABASE_BUSY) {
79 busyRetryTime++;
80 MEDIA_ERR_LOG("ExecuteSqlInternal busy, ret:%{public}d, busyRetryTime:%{public}d", err, busyRetryTime);
81 } else {
82 MEDIA_ERR_LOG("ExecuteSqlInternal faile, ret = %{public}d", err);
83 break;
84 }
85 }
86 return err;
87 }
88
MergeAlbumFromOldBundleNameToNewBundleName(NativeRdb::RdbStore & store)89 int32_t MediaLibraryDbUpgrade::MergeAlbumFromOldBundleNameToNewBundleName(NativeRdb::RdbStore &store)
90 {
91 MEDIA_INFO_LOG("Media_Restore: MediaLibraryDbUpgrade::MergeAlbumFromOldBundleNameToNewBundleName start");
92 int32_t ret = NativeRdb::E_OK;
93 for (const auto &executeSql : this->SQL_MERGE_ALBUM_FROM_OLD_BUNDLE_NAME_TO_NEW_BUNDLE_NAME) {
94 ret = ExecSqlWithRetry([&]() { return store.ExecuteSql(executeSql); });
95 if (ret != NativeRdb::E_OK) {
96 MEDIA_ERR_LOG("Media_Restore: executeSql failed, sql: %{public}s", executeSql.c_str());
97 return ret;
98 }
99 }
100 MEDIA_INFO_LOG("Media_Restore: MediaLibraryDbUpgrade::MergeAlbumFromOldBundleNameToNewBundleName end");
101 return NativeRdb::E_OK;
102 }
103
UpgradePhotosBelongsToAlbum(NativeRdb::RdbStore & store)104 int32_t MediaLibraryDbUpgrade::UpgradePhotosBelongsToAlbum(NativeRdb::RdbStore &store)
105 {
106 MEDIA_INFO_LOG("Media_Restore: MediaLibraryDbUpgrade::UpgradePhotosBelongsToAlbum start");
107 int32_t ret = NativeRdb::E_OK;
108 for (const auto &executeSql : this->SQL_PHOTOS_NEED_TO_BELONGS_TO_ALBUM) {
109 ret = ExecSqlWithRetry([&]() { return store.ExecuteSql(executeSql); });
110 if (ret != NativeRdb::E_OK) {
111 MEDIA_ERR_LOG("Media_Restore: executeSql failed, sql: %{public}s", executeSql.c_str());
112 return ret;
113 }
114 }
115 MEDIA_INFO_LOG("Media_Restore: MediaLibraryDbUpgrade::UpgradePhotosBelongsToAlbum end");
116 return NativeRdb::E_OK;
117 }
118
119 /**
120 * @brief Upgrade album_plugin table.
121 */
UpgradeAlbumPlugin(NativeRdb::RdbStore & store)122 int32_t MediaLibraryDbUpgrade::UpgradeAlbumPlugin(NativeRdb::RdbStore &store)
123 {
124 if (this->dbUpgradeUtils_.IsTableExists(store, "album_plugin")) {
125 return NativeRdb::E_OK;
126 }
127 AlbumPluginTableEventHandler handler;
128 return handler.OnUpgrade(store, 0, 0);
129 }
130
131 /**
132 * @brief Upgrade PhotoAlbum table.
133 */
UpgradePhotoAlbum(NativeRdb::RdbStore & store)134 int32_t MediaLibraryDbUpgrade::UpgradePhotoAlbum(NativeRdb::RdbStore &store)
135 {
136 int32_t ret = NativeRdb::E_OK;
137 ret = this->dbUpgradeUtils_.DropAllTriggers(store, "PhotoAlbum");
138 if (ret != NativeRdb::E_OK) {
139 return ret;
140 }
141 ret = this->dbUpgradeUtils_.DropAllUniqueIndex(store, "PhotoAlbum");
142 if (ret != NativeRdb::E_OK) {
143 return ret;
144 }
145 ret = this->AddlPathColumn(store);
146 if (ret != NativeRdb::E_OK) {
147 return ret;
148 }
149 return this->UpdatelPathColumn(store);
150 }
151
152 /**
153 * @brief Upgrade the lpath column in PhotoAlbum table.
154 */
UpdatelPathColumn(NativeRdb::RdbStore & store)155 int32_t MediaLibraryDbUpgrade::UpdatelPathColumn(NativeRdb::RdbStore &store)
156 {
157 std::string executeSql = this->SQL_PHOTO_ALBUM_TABLE_UPDATE_LPATH_COLUMN;
158 int32_t ret = ExecSqlWithRetry([&]() { return store.ExecuteSql(executeSql); });
159 if (ret != NativeRdb::E_OK) {
160 MEDIA_ERR_LOG("Media_Restore: MediaLibraryDbUpgrade::UpdatelPathColumn failed, ret=%{public}d, sql=%{public}s",
161 ret,
162 executeSql.c_str());
163 return ret;
164 }
165 MEDIA_INFO_LOG("Media_Restore: MediaLibraryDbUpgrade::UpdatelPathColumn success");
166 return ret;
167 }
168
169 /**
170 * @brief Add owner_album_id column to Photos table.
171 */
AddOwnerAlbumIdColumn(NativeRdb::RdbStore & store)172 int32_t MediaLibraryDbUpgrade::AddOwnerAlbumIdColumn(NativeRdb::RdbStore &store)
173 {
174 if (this->dbUpgradeUtils_.IsColumnExists(store, "Photos", "owner_album_id")) {
175 return NativeRdb::E_OK;
176 }
177 std::string sql = this->SQL_PHOTOS_TABLE_ADD_OWNER_ALBUM_ID;
178 int32_t ret = ExecSqlWithRetry([&]() { return store.ExecuteSql(sql); });
179 if (ret != NativeRdb::E_OK) {
180 MEDIA_ERR_LOG(
181 "Media_Restore: MediaLibraryDbUpgrade::AddOwnerAlbumIdColumn failed, ret=%{public}d, sql=%{public}s",
182 ret,
183 sql.c_str());
184 }
185 MEDIA_INFO_LOG("Media_Restore: MediaLibraryDbUpgrade::AddOwnerAlbumIdColumn success");
186 return ret;
187 }
188
189 /**
190 * @brief Add lpath column to PhotoAlbum table.
191 */
AddlPathColumn(NativeRdb::RdbStore & store)192 int32_t MediaLibraryDbUpgrade::AddlPathColumn(NativeRdb::RdbStore &store)
193 {
194 if (this->dbUpgradeUtils_.IsColumnExists(store, "PhotoAlbum", "lpath")) {
195 return NativeRdb::E_OK;
196 }
197 std::string sql = this->SQL_PHOTO_ALBUM_TABLE_ADD_LPATH_COLUMN;
198 return ExecSqlWithRetry([&]() { return store.ExecuteSql(sql); });
199 }
200
201 /**
202 * @brief Move the single relationship from PhotoMap table to Photos table, stored in owner_album_id.
203 */
MoveSingleRelationshipToPhotos(NativeRdb::RdbStore & store)204 int32_t MediaLibraryDbUpgrade::MoveSingleRelationshipToPhotos(NativeRdb::RdbStore &store)
205 {
206 std::vector<std::string> executeSqls = {this->SQL_TEMP_PHOTO_MAP_TABLE_DROP, this->SQL_TEMP_PHOTO_MAP_TABLE_CREATE};
207 executeSqls.insert(executeSqls.end(),
208 this->SQL_TEMP_PHOTO_MAP_TABLE_CREATE_INDEX_ARRAY.begin(),
209 this->SQL_TEMP_PHOTO_MAP_TABLE_CREATE_INDEX_ARRAY.end());
210 executeSqls.push_back(this->SQL_PHOTOS_TABLE_UPDATE_ALBUM_ID);
211 executeSqls.push_back(this->SQL_PHOTO_MAP_TABLE_DELETE_SINGLE_RELATIONSHIP);
212 executeSqls.push_back(this->SQL_TEMP_PHOTO_MAP_TABLE_DROP);
213 int ret = NativeRdb::E_OK;
214 MEDIA_INFO_LOG("MoveSingleRelationshipToPhotos begin");
215 auto [errCode, transaction] = store.CreateTransaction(OHOS::NativeRdb::Transaction::DEFERRED);
216 DfxTransaction reporter{__func__};
217 if (errCode != NativeRdb::E_OK || transaction == nullptr) {
218 reporter.ReportError(DfxTransaction::AbnormalType::CREATE_ERROR, errCode);
219 MEDIA_ERR_LOG("transaction failed, err:%{public}d", errCode);
220 return errCode;
221 }
222 for (const std::string &executeSql : executeSqls) {
223 auto res = transaction->Execute(executeSql);
224 ret = res.first;
225 if (ret != NativeRdb::E_OK) {
226 reporter.ReportError(DfxTransaction::AbnormalType::EXECUTE_ERROR, ret);
227 MEDIA_ERR_LOG("Media_Restore: MoveSingleRelationshipToPhotos failed, ret=%{public}d, sql=%{public}s",
228 ret,
229 executeSql.c_str());
230 transaction->Rollback();
231 return ret;
232 }
233 }
234 ret = transaction->Commit();
235 if (ret != NativeRdb::E_OK) {
236 reporter.ReportError(DfxTransaction::AbnormalType::COMMIT_ERROR, ret);
237 MEDIA_ERR_LOG("MoveSingleRelationshipToPhotos: tans finish fail!, ret:%{public}d", ret);
238 transaction->Rollback();
239 } else {
240 reporter.ReportIfTimeout();
241 }
242 return NativeRdb::E_OK;
243 }
244
245 /**
246 * @brief Upgrade Photos table.
247 */
UpgradePhotos(NativeRdb::RdbStore & store)248 int32_t MediaLibraryDbUpgrade::UpgradePhotos(NativeRdb::RdbStore &store)
249 {
250 int32_t ret = NativeRdb::E_OK;
251 ret = this->dbUpgradeUtils_.DropAllTriggers(store, "Photos");
252 if (ret != NativeRdb::E_OK) {
253 return ret;
254 }
255 ret = this->AddOwnerAlbumIdColumn(store);
256 if (ret != NativeRdb::E_OK) {
257 return ret;
258 }
259
260 ret = ExecSqlWithRetry([&]() { return PhotoDayMonthYearOperation::UpdatePhotosDate(store); });
261 CHECK_AND_RETURN_RET_LOG(ret == NativeRdb::E_OK, ret, "update photos date failed, ret=%{public}d", ret);
262
263 return NativeRdb::E_OK;
264 }
265
266 /**
267 * @brief Upgrade PhotoMap table.
268 */
UpgradePhotoMap(NativeRdb::RdbStore & store)269 int32_t MediaLibraryDbUpgrade::UpgradePhotoMap(NativeRdb::RdbStore &store)
270 {
271 int32_t ret = NativeRdb::E_OK;
272 ret = this->dbUpgradeUtils_.DropAllTriggers(store, "PhotoMap");
273 if (ret != NativeRdb::E_OK) {
274 return ret;
275 }
276 ret = this->MoveSingleRelationshipToPhotos(store);
277 if (ret != NativeRdb::E_OK) {
278 return ret;
279 }
280 return NativeRdb::E_OK;
281 }
282 } // namespace DataTransfer
283 } // namespace OHOS::Media