1dfe32fa1Soh_ci/*
2dfe32fa1Soh_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3dfe32fa1Soh_ci * Licensed under the Apache License, Version 2.0 (the "License");
4dfe32fa1Soh_ci * you may not use this file except in compliance with the License.
5dfe32fa1Soh_ci * You may obtain a copy of the License at
6dfe32fa1Soh_ci *
7dfe32fa1Soh_ci *     http://www.apache.org/licenses/LICENSE-2.0
8dfe32fa1Soh_ci *
9dfe32fa1Soh_ci * Unless required by applicable law or agreed to in writing, software
10dfe32fa1Soh_ci * distributed under the License is distributed on an "AS IS" BASIS,
11dfe32fa1Soh_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12dfe32fa1Soh_ci * See the License for the specific language governing permissions and
13dfe32fa1Soh_ci * limitations under the License.
14dfe32fa1Soh_ci */
15dfe32fa1Soh_ci
16dfe32fa1Soh_ci//! This module provides interfaces for database management.
17dfe32fa1Soh_ci//! Databases are isolated based on users and protected by locks.
18dfe32fa1Soh_ci
19dfe32fa1Soh_ciuse core::ffi::c_void;
20dfe32fa1Soh_ciuse std::{collections::HashMap, ffi::CStr, fs, ptr::null_mut, sync::Mutex};
21dfe32fa1Soh_ci
22dfe32fa1Soh_ciuse asset_common::{CallingInfo, OwnerType};
23dfe32fa1Soh_ciuse asset_crypto_manager::secret_key::rename_key_alias;
24dfe32fa1Soh_ciuse asset_db_key_operator::DbKey;
25dfe32fa1Soh_ciuse asset_definition::{log_throw_error, AssetMap, ErrCode, Extension, Result, Tag, Value};
26dfe32fa1Soh_ciuse asset_file_operator::{ce_operator::remove_ce_files, common::is_file_exist};
27dfe32fa1Soh_ciuse asset_log::{loge, logi};
28dfe32fa1Soh_ciuse lazy_static::lazy_static;
29dfe32fa1Soh_ci
30dfe32fa1Soh_ciuse crate::{
31dfe32fa1Soh_ci    database_file_upgrade::{check_and_split_db, construct_splited_db_name},
32dfe32fa1Soh_ci    statement::Statement,
33dfe32fa1Soh_ci    table::Table,
34dfe32fa1Soh_ci    types::{
35dfe32fa1Soh_ci        column, sqlite_err_handle, DbMap, QueryOptions, COLUMN_INFO, DB_UPGRADE_VERSION, DB_UPGRADE_VERSION_V1,
36dfe32fa1Soh_ci        DB_UPGRADE_VERSION_V2, DB_UPGRADE_VERSION_V3, SQLITE_OK, TABLE_NAME, UPGRADE_COLUMN_INFO,
37dfe32fa1Soh_ci        UPGRADE_COLUMN_INFO_V2, UPGRADE_COLUMN_INFO_V3,
38dfe32fa1Soh_ci    },
39dfe32fa1Soh_ci};
40dfe32fa1Soh_ci
41dfe32fa1Soh_ciextern "C" {
42dfe32fa1Soh_ci    fn SqliteOpen(file_name: *const u8, pp_db: *mut *mut c_void) -> i32;
43dfe32fa1Soh_ci    fn SqliteCloseV2(db: *mut c_void) -> i32;
44dfe32fa1Soh_ci    fn SqliteExec(db: *mut c_void, sql: *const u8, msg: *mut *mut u8) -> i32;
45dfe32fa1Soh_ci    fn SqliteFree(data: *mut c_void);
46dfe32fa1Soh_ci    fn SqliteErrMsg(db: *mut c_void) -> *const u8;
47dfe32fa1Soh_ci    fn SqliteKey(db: *mut c_void, pKey: *const c_void, nKey: i32) -> i32;
48dfe32fa1Soh_ci}
49dfe32fa1Soh_ci
50dfe32fa1Soh_ci/// each user have a Database file
51dfe32fa1Soh_cipub(crate) struct UserDbLock {
52dfe32fa1Soh_ci    pub(crate) mtx: Mutex<i32>,
53dfe32fa1Soh_ci}
54dfe32fa1Soh_ci
55dfe32fa1Soh_cipub(crate) static OLD_DB_NAME: &str = "asset";
56dfe32fa1Soh_ci
57dfe32fa1Soh_cilazy_static! {
58dfe32fa1Soh_ci    static ref SPLIT_DB_LOCK_MAP: Mutex<HashMap<i32, &'static UserDbLock>> = Mutex::new(HashMap::new());
59dfe32fa1Soh_ci    static ref USER_DB_LOCK_MAP: Mutex<HashMap<(i32, String), &'static UserDbLock>> = Mutex::new(HashMap::new());
60dfe32fa1Soh_ci}
61dfe32fa1Soh_ci
62dfe32fa1Soh_cipub(crate) fn get_split_db_lock_by_user_id(user_id: i32) -> &'static UserDbLock {
63dfe32fa1Soh_ci    let mut map = SPLIT_DB_LOCK_MAP.lock().unwrap();
64dfe32fa1Soh_ci    if let Some(&lock) = map.get(&user_id) {
65dfe32fa1Soh_ci        return lock;
66dfe32fa1Soh_ci    }
67dfe32fa1Soh_ci
68dfe32fa1Soh_ci    let nf = Box::new(UserDbLock { mtx: Mutex::new(user_id) });
69dfe32fa1Soh_ci    // SAFETY: We just push item into SPLIT_DB_LOCK_MAP, never remove item or modify item,
70dfe32fa1Soh_ci    // so return a reference of leak item is safe.
71dfe32fa1Soh_ci    let nf: &'static UserDbLock = Box::leak(nf);
72dfe32fa1Soh_ci    map.insert(user_id, nf);
73dfe32fa1Soh_ci    nf
74dfe32fa1Soh_ci}
75dfe32fa1Soh_ci
76dfe32fa1Soh_ci/// If the user exists, the reference to the lock is returned.
77dfe32fa1Soh_ci/// Otherwise, a new lock is created and its reference is returned.
78dfe32fa1Soh_cipub(crate) fn get_file_lock_by_user_id_db_file_name(user_id: i32, db_file_name: String) -> &'static UserDbLock {
79dfe32fa1Soh_ci    let mut map = USER_DB_LOCK_MAP.lock().unwrap();
80dfe32fa1Soh_ci
81dfe32fa1Soh_ci    if let Some(&lock) = map.get(&(user_id, db_file_name.clone())) {
82dfe32fa1Soh_ci        return lock;
83dfe32fa1Soh_ci    }
84dfe32fa1Soh_ci
85dfe32fa1Soh_ci    let nf = Box::new(UserDbLock { mtx: Mutex::new(user_id) });
86dfe32fa1Soh_ci    // SAFETY: We just push item into USER_DB_LOCK_MAP, never remove item or modify item,
87dfe32fa1Soh_ci    // so return a reference of leak item is safe.
88dfe32fa1Soh_ci    let nf: &'static UserDbLock = Box::leak(nf);
89dfe32fa1Soh_ci    map.insert((user_id, db_file_name), nf);
90dfe32fa1Soh_ci    nf
91dfe32fa1Soh_ci}
92dfe32fa1Soh_ci
93dfe32fa1Soh_ci/// Struct used to store database files and connection information.
94dfe32fa1Soh_ci#[repr(C)]
95dfe32fa1Soh_cipub struct Database {
96dfe32fa1Soh_ci    pub(crate) path: String,
97dfe32fa1Soh_ci    pub(crate) backup_path: String,
98dfe32fa1Soh_ci    pub(crate) handle: usize, // Pointer to the database connection.
99dfe32fa1Soh_ci    pub(crate) db_lock: &'static UserDbLock,
100dfe32fa1Soh_ci    pub(crate) db_name: String,
101dfe32fa1Soh_ci}
102dfe32fa1Soh_ci
103dfe32fa1Soh_ci/// Callback for database upgrade.
104dfe32fa1Soh_cipub type UpgradeDbCallback = fn(db: &Database, old_ver: u32, new_ver: u32) -> Result<()>;
105dfe32fa1Soh_ci
106dfe32fa1Soh_ci#[cfg(not(test))]
107dfe32fa1Soh_cipub(crate) const DE_ROOT_PATH: &str = "/data/service/el1/public/asset_service";
108dfe32fa1Soh_ci#[cfg(test)]
109dfe32fa1Soh_cipub(crate) const DE_ROOT_PATH: &str = "/data/asset_test";
110dfe32fa1Soh_ci
111dfe32fa1Soh_cipub(crate) const CE_ROOT_PATH: &str = "/data/service/el2";
112dfe32fa1Soh_ci
113dfe32fa1Soh_ci#[inline(always)]
114dfe32fa1Soh_cipub(crate) fn fmt_backup_path(path: &str) -> String {
115dfe32fa1Soh_ci    let mut bp = path.to_string();
116dfe32fa1Soh_ci    bp.push_str(".backup");
117dfe32fa1Soh_ci    bp
118dfe32fa1Soh_ci}
119dfe32fa1Soh_ci
120dfe32fa1Soh_ci/// Get asset storage path.
121dfe32fa1Soh_cipub fn get_path() -> String {
122dfe32fa1Soh_ci    DE_ROOT_PATH.to_string()
123dfe32fa1Soh_ci}
124dfe32fa1Soh_ci
125dfe32fa1Soh_ci#[inline(always)]
126dfe32fa1Soh_cipub(crate) fn fmt_ce_db_path_with_name(user_id: i32, db_name: &str) -> String {
127dfe32fa1Soh_ci    format!("data/service/el2/{}/asset_service/{}.db", user_id, db_name)
128dfe32fa1Soh_ci}
129dfe32fa1Soh_ci
130dfe32fa1Soh_ci#[inline(always)]
131dfe32fa1Soh_cipub(crate) fn fmt_de_db_path_with_name(user_id: i32, db_name: &str) -> String {
132dfe32fa1Soh_ci    format!("{}/{}/{}.db", DE_ROOT_PATH, user_id, db_name)
133dfe32fa1Soh_ci}
134dfe32fa1Soh_ci
135dfe32fa1Soh_cifn check_validity_of_db_key(path: &str, user_id: i32) -> Result<()> {
136dfe32fa1Soh_ci    if is_file_exist(path)? && !DbKey::check_existance(user_id)? {
137dfe32fa1Soh_ci        loge!("[FATAL]There is database bot no database key. Now all data should be cleared and restart over.");
138dfe32fa1Soh_ci        remove_ce_files(user_id)?;
139dfe32fa1Soh_ci        return log_throw_error!(ErrCode::DataCorrupted, "[FATAL]All data is cleared in {}.", user_id);
140dfe32fa1Soh_ci    }
141dfe32fa1Soh_ci    Ok(())
142dfe32fa1Soh_ci}
143dfe32fa1Soh_ci
144dfe32fa1Soh_cipub(crate) fn get_db(user_id: i32, db_name: &str, upgrade_db_version: u32, db_key: Option<&DbKey>) -> Result<Database> {
145dfe32fa1Soh_ci    let path = if db_key.is_some() {
146dfe32fa1Soh_ci        fmt_ce_db_path_with_name(user_id, db_name)
147dfe32fa1Soh_ci    } else {
148dfe32fa1Soh_ci        fmt_de_db_path_with_name(user_id, db_name)
149dfe32fa1Soh_ci    };
150dfe32fa1Soh_ci    let backup_path = fmt_backup_path(path.as_str());
151dfe32fa1Soh_ci    let lock = get_file_lock_by_user_id_db_file_name(user_id, db_name.to_string().clone());
152dfe32fa1Soh_ci    let mut db = Database { path, backup_path, handle: 0, db_lock: lock, db_name: db_name.to_string() };
153dfe32fa1Soh_ci    let _lock = db.db_lock.mtx.lock().unwrap();
154dfe32fa1Soh_ci    db.open_and_restore(db_key)?;
155dfe32fa1Soh_ci    db.restore_if_exec_fail(|e: &Table| e.create_with_version(COLUMN_INFO, upgrade_db_version))?;
156dfe32fa1Soh_ci    db.upgrade(user_id, upgrade_db_version, |_, _, _| Ok(()))?;
157dfe32fa1Soh_ci    Ok(db)
158dfe32fa1Soh_ci}
159dfe32fa1Soh_ci
160dfe32fa1Soh_cipub(crate) fn get_normal_db(user_id: i32, db_name: &str, is_ce: bool) -> Result<Database> {
161dfe32fa1Soh_ci    let path =
162dfe32fa1Soh_ci        if is_ce { fmt_ce_db_path_with_name(user_id, db_name) } else { fmt_de_db_path_with_name(user_id, db_name) };
163dfe32fa1Soh_ci    let db_key = if is_ce {
164dfe32fa1Soh_ci        check_validity_of_db_key(&path, user_id)?;
165dfe32fa1Soh_ci        match DbKey::get_db_key(user_id) {
166dfe32fa1Soh_ci            Ok(res) => Some(res),
167dfe32fa1Soh_ci            Err(e) if e.code == ErrCode::NotFound || e.code == ErrCode::DataCorrupted => {
168dfe32fa1Soh_ci                loge!(
169dfe32fa1Soh_ci                    "[FATAL]The key is corrupted. Now all data should be cleared and restart over, err is {}.",
170dfe32fa1Soh_ci                    e.code
171dfe32fa1Soh_ci                );
172dfe32fa1Soh_ci                remove_ce_files(user_id)?;
173dfe32fa1Soh_ci                return log_throw_error!(ErrCode::DataCorrupted, "[FATAL]All data is cleared in {}.", user_id);
174dfe32fa1Soh_ci            },
175dfe32fa1Soh_ci            Err(e) => return Err(e),
176dfe32fa1Soh_ci        }
177dfe32fa1Soh_ci    } else {
178dfe32fa1Soh_ci        None
179dfe32fa1Soh_ci    };
180dfe32fa1Soh_ci    get_db(user_id, db_name, DB_UPGRADE_VERSION, db_key.as_ref())
181dfe32fa1Soh_ci}
182dfe32fa1Soh_ci
183dfe32fa1Soh_ci/// Create de db instance if the value of tag "RequireAttrEncrypted" is not specified or set to false.
184dfe32fa1Soh_ci/// Create ce db instance if true.
185dfe32fa1Soh_cipub fn create_db_instance(attributes: &AssetMap, calling_info: &CallingInfo) -> Result<Database> {
186dfe32fa1Soh_ci    match attributes.get(&Tag::RequireAttrEncrypted) {
187dfe32fa1Soh_ci        Some(Value::Bool(true)) => {
188dfe32fa1Soh_ci            let db = Database::build(
189dfe32fa1Soh_ci                calling_info.user_id(),
190dfe32fa1Soh_ci                calling_info.owner_type_enum(),
191dfe32fa1Soh_ci                calling_info.owner_info(),
192dfe32fa1Soh_ci                true,
193dfe32fa1Soh_ci            )?;
194dfe32fa1Soh_ci            Ok(db)
195dfe32fa1Soh_ci        },
196dfe32fa1Soh_ci        _ => {
197dfe32fa1Soh_ci            let db = Database::build(
198dfe32fa1Soh_ci                calling_info.user_id(),
199dfe32fa1Soh_ci                calling_info.owner_type_enum(),
200dfe32fa1Soh_ci                calling_info.owner_info(),
201dfe32fa1Soh_ci                false,
202dfe32fa1Soh_ci            )?;
203dfe32fa1Soh_ci            Ok(db)
204dfe32fa1Soh_ci        },
205dfe32fa1Soh_ci    }
206dfe32fa1Soh_ci}
207dfe32fa1Soh_ci
208dfe32fa1Soh_ciimpl Database {
209dfe32fa1Soh_ci    /// Create a database.
210dfe32fa1Soh_ci    pub fn build(user_id: i32, owner_type: OwnerType, owner_info: &[u8], is_ce: bool) -> Result<Database> {
211dfe32fa1Soh_ci        if !is_ce {
212dfe32fa1Soh_ci            // DE database needs trigger the upgrade action.
213dfe32fa1Soh_ci            check_and_split_db(user_id)?;
214dfe32fa1Soh_ci        }
215dfe32fa1Soh_ci        get_normal_db(user_id, &construct_splited_db_name(owner_type, owner_info, is_ce)?, is_ce)
216dfe32fa1Soh_ci    }
217dfe32fa1Soh_ci
218dfe32fa1Soh_ci    /// Create a database from a file name.
219dfe32fa1Soh_ci    pub fn build_with_file_name(user_id: i32, db_name: &str, is_ce: bool) -> Result<Database> {
220dfe32fa1Soh_ci        check_and_split_db(user_id)?;
221dfe32fa1Soh_ci        get_normal_db(user_id, db_name, is_ce)
222dfe32fa1Soh_ci    }
223dfe32fa1Soh_ci
224dfe32fa1Soh_ci    /// Check whether db is ok
225dfe32fa1Soh_ci    pub fn check_db_accessible(path: String, user_id: i32, db_name: String, db_key: Option<&DbKey>) -> Result<()> {
226dfe32fa1Soh_ci        let lock = get_file_lock_by_user_id_db_file_name(user_id, db_name.clone());
227dfe32fa1Soh_ci        let mut db = Database { path: path.clone(), backup_path: path, handle: 0, db_lock: lock, db_name };
228dfe32fa1Soh_ci        if db_key.is_some() {
229dfe32fa1Soh_ci            db.open_and_restore(db_key)?
230dfe32fa1Soh_ci        } else {
231dfe32fa1Soh_ci            db.open()?;
232dfe32fa1Soh_ci        }
233dfe32fa1Soh_ci        let table = Table::new(TABLE_NAME, &db);
234dfe32fa1Soh_ci        table.create(COLUMN_INFO)
235dfe32fa1Soh_ci    }
236dfe32fa1Soh_ci
237dfe32fa1Soh_ci    /// Open database connection.
238dfe32fa1Soh_ci    pub(crate) fn open(&mut self) -> Result<()> {
239dfe32fa1Soh_ci        let mut path_c = self.path.clone();
240dfe32fa1Soh_ci        path_c.push('\0');
241dfe32fa1Soh_ci
242dfe32fa1Soh_ci        let ret = unsafe { SqliteOpen(path_c.as_ptr(), &mut self.handle as *mut usize as _) };
243dfe32fa1Soh_ci        if ret == SQLITE_OK {
244dfe32fa1Soh_ci            Ok(())
245dfe32fa1Soh_ci        } else {
246dfe32fa1Soh_ci            self.close();
247dfe32fa1Soh_ci            log_throw_error!(sqlite_err_handle(ret), "[FATAL][DB]Open database failed, err={}", ret)
248dfe32fa1Soh_ci        }
249dfe32fa1Soh_ci    }
250dfe32fa1Soh_ci
251dfe32fa1Soh_ci    /// Open the database connection and restore the database if the connection fails.
252dfe32fa1Soh_ci    pub(crate) fn open_and_restore(&mut self, db_key: Option<&DbKey>) -> Result<()> {
253dfe32fa1Soh_ci        let result = self.open();
254dfe32fa1Soh_ci        if let Some(db_key) = db_key {
255dfe32fa1Soh_ci            self.set_db_key(db_key)?;
256dfe32fa1Soh_ci        }
257dfe32fa1Soh_ci        let result = match result {
258dfe32fa1Soh_ci            Err(ret) if ret.code == ErrCode::DataCorrupted => self.restore(),
259dfe32fa1Soh_ci            ret => ret,
260dfe32fa1Soh_ci        };
261dfe32fa1Soh_ci        result
262dfe32fa1Soh_ci    }
263dfe32fa1Soh_ci
264dfe32fa1Soh_ci    /// Get db name.
265dfe32fa1Soh_ci    pub(crate) fn get_db_name(&mut self) -> &str {
266dfe32fa1Soh_ci        &self.db_name
267dfe32fa1Soh_ci    }
268dfe32fa1Soh_ci
269dfe32fa1Soh_ci    /// Close database connection.
270dfe32fa1Soh_ci    fn close(&mut self) {
271dfe32fa1Soh_ci        if self.handle != 0 {
272dfe32fa1Soh_ci            unsafe { SqliteCloseV2(self.handle as _) };
273dfe32fa1Soh_ci            self.handle = 0;
274dfe32fa1Soh_ci        }
275dfe32fa1Soh_ci    }
276dfe32fa1Soh_ci
277dfe32fa1Soh_ci    /// Close database connection.
278dfe32fa1Soh_ci    pub(crate) fn close_db(&mut self) {
279dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
280dfe32fa1Soh_ci        self.close()
281dfe32fa1Soh_ci    }
282dfe32fa1Soh_ci
283dfe32fa1Soh_ci    /// Encrypt/Decrypt CE database.
284dfe32fa1Soh_ci    pub fn set_db_key(&mut self, p_key: &DbKey) -> Result<()> {
285dfe32fa1Soh_ci        let ret =
286dfe32fa1Soh_ci            unsafe { SqliteKey(self.handle as _, p_key.db_key.as_ptr() as *const c_void, p_key.db_key.len() as i32) };
287dfe32fa1Soh_ci        if ret == SQLITE_OK {
288dfe32fa1Soh_ci            Ok(())
289dfe32fa1Soh_ci        } else {
290dfe32fa1Soh_ci            log_throw_error!(sqlite_err_handle(ret), "[FATAL][DB]Set database key failed, err={}", ret)
291dfe32fa1Soh_ci        }
292dfe32fa1Soh_ci    }
293dfe32fa1Soh_ci
294dfe32fa1Soh_ci    // Recovery the corrupt database and reopen it.
295dfe32fa1Soh_ci    pub(crate) fn restore(&mut self) -> Result<()> {
296dfe32fa1Soh_ci        loge!("[WARNING]Database is corrupt, start to restore");
297dfe32fa1Soh_ci        self.close();
298dfe32fa1Soh_ci        if let Err(e) = fs::copy(&self.backup_path, &self.path) {
299dfe32fa1Soh_ci            return log_throw_error!(ErrCode::FileOperationError, "[FATAL][DB]Recovery database failed, err={}", e);
300dfe32fa1Soh_ci        }
301dfe32fa1Soh_ci        self.open()
302dfe32fa1Soh_ci    }
303dfe32fa1Soh_ci
304dfe32fa1Soh_ci    /// Get database version, default is 0.
305dfe32fa1Soh_ci    fn get_db_version(&self) -> Result<u32> {
306dfe32fa1Soh_ci        let stmt = Statement::prepare("pragma user_version", self)?;
307dfe32fa1Soh_ci        stmt.step()?;
308dfe32fa1Soh_ci        let version = stmt.query_column_int(0);
309dfe32fa1Soh_ci        Ok(version)
310dfe32fa1Soh_ci    }
311dfe32fa1Soh_ci
312dfe32fa1Soh_ci    /// Get database version, default is 0.
313dfe32fa1Soh_ci    #[allow(dead_code)]
314dfe32fa1Soh_ci    pub(crate) fn get_version(&self) -> Result<u32> {
315dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
316dfe32fa1Soh_ci        self.get_db_version()
317dfe32fa1Soh_ci    }
318dfe32fa1Soh_ci
319dfe32fa1Soh_ci    /// Update the database version for database upgrade.
320dfe32fa1Soh_ci    #[allow(dead_code)]
321dfe32fa1Soh_ci    pub(crate) fn set_version(&self, ver: u32) -> Result<()> {
322dfe32fa1Soh_ci        let sql = format!("pragma user_version = {}", ver);
323dfe32fa1Soh_ci        self.exec(sql.as_str())
324dfe32fa1Soh_ci    }
325dfe32fa1Soh_ci
326dfe32fa1Soh_ci    /// Upgrade database to new version.
327dfe32fa1Soh_ci    #[allow(dead_code)]
328dfe32fa1Soh_ci    pub fn upgrade(&mut self, user_id: i32, target_ver: u32, callback: UpgradeDbCallback) -> Result<()> {
329dfe32fa1Soh_ci        let mut current_ver = self.get_db_version()?;
330dfe32fa1Soh_ci        logi!("current database version: {}", current_ver);
331dfe32fa1Soh_ci        if current_ver >= target_ver {
332dfe32fa1Soh_ci            return Ok(());
333dfe32fa1Soh_ci        }
334dfe32fa1Soh_ci        while current_ver < target_ver {
335dfe32fa1Soh_ci            match current_ver {
336dfe32fa1Soh_ci                DB_UPGRADE_VERSION_V1 => {
337dfe32fa1Soh_ci                    self.restore_if_exec_fail(|e: &Table| e.upgrade(DB_UPGRADE_VERSION_V2, UPGRADE_COLUMN_INFO_V2))?;
338dfe32fa1Soh_ci                    current_ver += 1;
339dfe32fa1Soh_ci                },
340dfe32fa1Soh_ci                DB_UPGRADE_VERSION_V2 => {
341dfe32fa1Soh_ci                    self.restore_if_exec_fail(|e: &Table| e.upgrade(DB_UPGRADE_VERSION_V3, UPGRADE_COLUMN_INFO_V3))?;
342dfe32fa1Soh_ci                    current_ver += 1;
343dfe32fa1Soh_ci                },
344dfe32fa1Soh_ci                DB_UPGRADE_VERSION_V3 => {
345dfe32fa1Soh_ci                    if self.upgrade_key_alias(user_id)? {
346dfe32fa1Soh_ci                        self.restore_if_exec_fail(|e: &Table| e.upgrade(DB_UPGRADE_VERSION, UPGRADE_COLUMN_INFO))?;
347dfe32fa1Soh_ci                        current_ver += 1;
348dfe32fa1Soh_ci                    } else {
349dfe32fa1Soh_ci                        break;
350dfe32fa1Soh_ci                    }
351dfe32fa1Soh_ci                },
352dfe32fa1Soh_ci                _ => break,
353dfe32fa1Soh_ci            }
354dfe32fa1Soh_ci        }
355dfe32fa1Soh_ci
356dfe32fa1Soh_ci        callback(self, current_ver, target_ver)
357dfe32fa1Soh_ci    }
358dfe32fa1Soh_ci
359dfe32fa1Soh_ci    fn upgrade_key_alias(&mut self, user_id: i32) -> Result<bool> {
360dfe32fa1Soh_ci        let query_results = self.query_data_without_lock(
361dfe32fa1Soh_ci            &vec![
362dfe32fa1Soh_ci                column::OWNER_TYPE,
363dfe32fa1Soh_ci                column::OWNER,
364dfe32fa1Soh_ci                column::AUTH_TYPE,
365dfe32fa1Soh_ci                column::ACCESSIBILITY,
366dfe32fa1Soh_ci                column::REQUIRE_PASSWORD_SET,
367dfe32fa1Soh_ci            ],
368dfe32fa1Soh_ci            &DbMap::new(),
369dfe32fa1Soh_ci            None,
370dfe32fa1Soh_ci            true,
371dfe32fa1Soh_ci        )?;
372dfe32fa1Soh_ci
373dfe32fa1Soh_ci        let mut upgrade_result = true;
374dfe32fa1Soh_ci        for query_result in query_results {
375dfe32fa1Soh_ci            let owner_type = query_result.get_enum_attr(&column::OWNER_TYPE)?;
376dfe32fa1Soh_ci            let owner_info = query_result.get_bytes_attr(&column::OWNER)?;
377dfe32fa1Soh_ci            let calling_info = CallingInfo::new(user_id, owner_type, owner_info.to_vec());
378dfe32fa1Soh_ci            let auth_type = query_result.get_enum_attr(&column::AUTH_TYPE)?;
379dfe32fa1Soh_ci            let access_type = query_result.get_enum_attr(&column::ACCESSIBILITY)?;
380dfe32fa1Soh_ci            let require_password_set = query_result.get_bool_attr(&column::REQUIRE_PASSWORD_SET)?;
381dfe32fa1Soh_ci            // upgrade_result is set to false as long as any call in the loop for renaming key alias returned false.
382dfe32fa1Soh_ci            upgrade_result &= rename_key_alias(&calling_info, auth_type, access_type, require_password_set);
383dfe32fa1Soh_ci        }
384dfe32fa1Soh_ci
385dfe32fa1Soh_ci        Ok(upgrade_result)
386dfe32fa1Soh_ci    }
387dfe32fa1Soh_ci
388dfe32fa1Soh_ci    /// Delete database file.
389dfe32fa1Soh_ci    #[allow(dead_code)]
390dfe32fa1Soh_ci    pub(crate) fn delete(user_id: i32, db_name: &str) -> Result<()> {
391dfe32fa1Soh_ci        let path = fmt_de_db_path_with_name(user_id, db_name);
392dfe32fa1Soh_ci        let backup_path = fmt_backup_path(&path);
393dfe32fa1Soh_ci        if let Err(e) = fs::remove_file(path) {
394dfe32fa1Soh_ci            return log_throw_error!(ErrCode::FileOperationError, "[FATAL][DB]Delete database failed, err={}", e);
395dfe32fa1Soh_ci        }
396dfe32fa1Soh_ci
397dfe32fa1Soh_ci        if let Err(e) = fs::remove_file(backup_path) {
398dfe32fa1Soh_ci            return log_throw_error!(
399dfe32fa1Soh_ci                ErrCode::FileOperationError,
400dfe32fa1Soh_ci                "[FATAL][DB]Delete backup database failed, err={}",
401dfe32fa1Soh_ci                e
402dfe32fa1Soh_ci            );
403dfe32fa1Soh_ci        }
404dfe32fa1Soh_ci        Ok(())
405dfe32fa1Soh_ci    }
406dfe32fa1Soh_ci
407dfe32fa1Soh_ci    /// Print the error message of database.
408dfe32fa1Soh_ci    pub(crate) fn print_db_msg(&self) {
409dfe32fa1Soh_ci        let msg = unsafe { SqliteErrMsg(self.handle as _) };
410dfe32fa1Soh_ci        if !msg.is_null() {
411dfe32fa1Soh_ci            let s = unsafe { CStr::from_ptr(msg as _) };
412dfe32fa1Soh_ci            if let Ok(rs) = s.to_str() {
413dfe32fa1Soh_ci                loge!("[FATAL][DB]Database error message: {}", rs);
414dfe32fa1Soh_ci            }
415dfe32fa1Soh_ci        }
416dfe32fa1Soh_ci    }
417dfe32fa1Soh_ci
418dfe32fa1Soh_ci    /// execute sql without prepare
419dfe32fa1Soh_ci    pub fn exec(&self, sql: &str) -> Result<()> {
420dfe32fa1Soh_ci        let mut sql_s = sql.to_string();
421dfe32fa1Soh_ci        sql_s.push('\0');
422dfe32fa1Soh_ci        let mut msg: *mut u8 = null_mut();
423dfe32fa1Soh_ci        let ret = unsafe { SqliteExec(self.handle as _, sql_s.as_ptr(), &mut msg as _) };
424dfe32fa1Soh_ci        if !msg.is_null() {
425dfe32fa1Soh_ci            let s = unsafe { CStr::from_ptr(msg as _) };
426dfe32fa1Soh_ci            if let Ok(rs) = s.to_str() {
427dfe32fa1Soh_ci                return log_throw_error!(
428dfe32fa1Soh_ci                    sqlite_err_handle(ret),
429dfe32fa1Soh_ci                    "[FATAL]Database execute sql failed. error code={}, error msg={}",
430dfe32fa1Soh_ci                    ret,
431dfe32fa1Soh_ci                    rs
432dfe32fa1Soh_ci                );
433dfe32fa1Soh_ci            }
434dfe32fa1Soh_ci            unsafe { SqliteFree(msg as _) };
435dfe32fa1Soh_ci        }
436dfe32fa1Soh_ci        if ret == SQLITE_OK {
437dfe32fa1Soh_ci            Ok(())
438dfe32fa1Soh_ci        } else {
439dfe32fa1Soh_ci            log_throw_error!(sqlite_err_handle(ret), "[FATAL]Database execute sql failed. error code={}", ret)
440dfe32fa1Soh_ci        }
441dfe32fa1Soh_ci    }
442dfe32fa1Soh_ci
443dfe32fa1Soh_ci    /// execute func in db, if failed and error code is data corrupted then restore
444dfe32fa1Soh_ci    pub(crate) fn restore_if_exec_fail<T, F: Fn(&Table) -> Result<T>>(&mut self, func: F) -> Result<T> {
445dfe32fa1Soh_ci        let table = Table::new(TABLE_NAME, self);
446dfe32fa1Soh_ci        let result = func(&table);
447dfe32fa1Soh_ci        match result {
448dfe32fa1Soh_ci            Err(ret) if ret.code == ErrCode::DataCorrupted => {
449dfe32fa1Soh_ci                self.restore()?;
450dfe32fa1Soh_ci                let table = Table::new(TABLE_NAME, self); // Database handle will be changed.
451dfe32fa1Soh_ci                func(&table)
452dfe32fa1Soh_ci            },
453dfe32fa1Soh_ci            ret => ret,
454dfe32fa1Soh_ci        }
455dfe32fa1Soh_ci    }
456dfe32fa1Soh_ci
457dfe32fa1Soh_ci    /// Insert datas into database.
458dfe32fa1Soh_ci    /// The datas is a map of column-data pair.
459dfe32fa1Soh_ci    /// If the operation is successful, the number of inserted data is returned.
460dfe32fa1Soh_ci    ///
461dfe32fa1Soh_ci    /// # Examples
462dfe32fa1Soh_ci    ///
463dfe32fa1Soh_ci    /// ```
464dfe32fa1Soh_ci    /// use asset_definition::Value;
465dfe32fa1Soh_ci    /// use asset_db_operator::{database::Database, types::{column, DbMap}};
466dfe32fa1Soh_ci    ///
467dfe32fa1Soh_ci    /// // SQL: insert into table_name(Owner,OwnerType,Alias,value) values('owner',1,'alias','insert_value')
468dfe32fa1Soh_ci    /// let datas = DbMap::new();
469dfe32fa1Soh_ci    /// datas.insert(column::OWNER, Value::Bytes(b"owner".to_ver()));
470dfe32fa1Soh_ci    /// datas.insert(column::OWNER_TYPE, Value::Number(OwnerType::Native as u32));
471dfe32fa1Soh_ci    /// datas.insert(column::ALIAS, Value::Bytes(b"alias".to_ver()));
472dfe32fa1Soh_ci    /// datas.insert("value", Value::Bytes(b"insert_value".to_vec()));
473dfe32fa1Soh_ci    /// let user_id = 100;
474dfe32fa1Soh_ci    /// let ret = Database::build(user_id)?.insert_datas(&datas);
475dfe32fa1Soh_ci    /// ```
476dfe32fa1Soh_ci    ///
477dfe32fa1Soh_ci    #[inline(always)]
478dfe32fa1Soh_ci    pub fn insert_datas(&mut self, datas: &DbMap) -> Result<i32> {
479dfe32fa1Soh_ci        let _lock: std::sync::MutexGuard<'_, i32> = self.db_lock.mtx.lock().unwrap();
480dfe32fa1Soh_ci        let closure = |e: &Table| {
481dfe32fa1Soh_ci            let mut query = DbMap::new();
482dfe32fa1Soh_ci            query.insert_attr(column::ALIAS, datas.get_bytes_attr(&column::ALIAS)?.clone());
483dfe32fa1Soh_ci            query.insert_attr(column::OWNER, datas.get_bytes_attr(&column::OWNER)?.clone());
484dfe32fa1Soh_ci            query.insert_attr(column::OWNER_TYPE, datas.get_enum_attr::<OwnerType>(&column::OWNER_TYPE)?);
485dfe32fa1Soh_ci            if e.is_data_exists(&query, false)? {
486dfe32fa1Soh_ci                log_throw_error!(ErrCode::Duplicated, "[FATAL]The data with the specified alias already exists.")
487dfe32fa1Soh_ci            } else {
488dfe32fa1Soh_ci                e.insert_row(datas)
489dfe32fa1Soh_ci            }
490dfe32fa1Soh_ci        };
491dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
492dfe32fa1Soh_ci    }
493dfe32fa1Soh_ci
494dfe32fa1Soh_ci    /// Delete datas from database.
495dfe32fa1Soh_ci    /// The condition is a map of column-data pair.
496dfe32fa1Soh_ci    /// If the operation is successful, the number of deleted data is returned.
497dfe32fa1Soh_ci    ///
498dfe32fa1Soh_ci    /// # Examples
499dfe32fa1Soh_ci    ///
500dfe32fa1Soh_ci    /// ```
501dfe32fa1Soh_ci    /// use asset_definition::Value;
502dfe32fa1Soh_ci    /// use asset_db_operator::{database::Database, types::{column, DbMap}};
503dfe32fa1Soh_ci    ///
504dfe32fa1Soh_ci    /// // SQL: delete from table_name where Owner='owner' and OwnerType=1 and Alias='alias' and value='delete_value'
505dfe32fa1Soh_ci    /// let datas = DbMap::new();
506dfe32fa1Soh_ci    /// datas.insert(column::OWNER, Value::Bytes(b"owner".to_ver()));
507dfe32fa1Soh_ci    /// datas.insert(column::OWNER_TYPE, Value::Number(OwnerType::Native as u32));
508dfe32fa1Soh_ci    /// datas.insert(column::ALIAS, Value::Bytes(b"alias".to_ver()));
509dfe32fa1Soh_ci    /// datas.insert("value", Value::Bytes(b"delete_value".to_vec()));
510dfe32fa1Soh_ci    /// let user_id = 100;
511dfe32fa1Soh_ci    /// let ret = Database::build(user_id)?.delete_datas(&cond, None, false);
512dfe32fa1Soh_ci    /// ```
513dfe32fa1Soh_ci    ///
514dfe32fa1Soh_ci    ///
515dfe32fa1Soh_ci    #[inline(always)]
516dfe32fa1Soh_ci    pub fn delete_datas(
517dfe32fa1Soh_ci        &mut self,
518dfe32fa1Soh_ci        condition: &DbMap,
519dfe32fa1Soh_ci        reverse_condition: Option<&DbMap>,
520dfe32fa1Soh_ci        is_filter_sync: bool,
521dfe32fa1Soh_ci    ) -> Result<i32> {
522dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
523dfe32fa1Soh_ci        let closure = |e: &Table| e.delete_row(condition, reverse_condition, is_filter_sync);
524dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
525dfe32fa1Soh_ci    }
526dfe32fa1Soh_ci
527dfe32fa1Soh_ci    /// Delete datas from database with specific condition.
528dfe32fa1Soh_ci    /// If the operation is successful, the number of deleted data is returned.
529dfe32fa1Soh_ci    #[inline(always)]
530dfe32fa1Soh_ci    pub fn delete_specific_condition_datas(&mut self, specific_cond: &str, condition_value: &[Value]) -> Result<i32> {
531dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
532dfe32fa1Soh_ci        let closure = |e: &Table| e.delete_with_specific_cond(specific_cond, condition_value);
533dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
534dfe32fa1Soh_ci    }
535dfe32fa1Soh_ci
536dfe32fa1Soh_ci    /// Update datas in database.
537dfe32fa1Soh_ci    /// The datas is a map of column-data pair.
538dfe32fa1Soh_ci    /// If the operation is successful, the number of updated data is returned.
539dfe32fa1Soh_ci    ///
540dfe32fa1Soh_ci    /// # Examples
541dfe32fa1Soh_ci    ///
542dfe32fa1Soh_ci    /// ```
543dfe32fa1Soh_ci    /// use asset_definition::Value;
544dfe32fa1Soh_ci    /// use asset_db_operator::{database::Database, types::{column, DbMap}};
545dfe32fa1Soh_ci    ///
546dfe32fa1Soh_ci    /// // SQL: update table_name set alias='update_value' where Owner='owner' and OwnerType=1 and Alias='alias'
547dfe32fa1Soh_ci    /// let cond = DbMap.new();
548dfe32fa1Soh_ci    /// cond.insert(column::OWNER, Value::Bytes(b"owner".to_ver()));
549dfe32fa1Soh_ci    /// cond.insert(column::OWNER_TYPE, Value::Number(OwnerType::Native as u32));
550dfe32fa1Soh_ci    /// cond.insert(column::ALIAS, Value::Bytes(b"alias".to_ver()));
551dfe32fa1Soh_ci    /// let datas = DbMap::from([("alias", Value::Bytes(b"update_value".to_vec()))]);
552dfe32fa1Soh_ci    /// let user_id = 100;
553dfe32fa1Soh_ci    /// let ret = Database::build(user_id)?.update_datas(&condition, true, &datas);
554dfe32fa1Soh_ci    /// ```
555dfe32fa1Soh_ci    #[inline(always)]
556dfe32fa1Soh_ci    pub fn update_datas(&mut self, condition: &DbMap, is_filter_sync: bool, datas: &DbMap) -> Result<i32> {
557dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
558dfe32fa1Soh_ci        let closure = |e: &Table| e.update_row(condition, is_filter_sync, datas);
559dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
560dfe32fa1Soh_ci    }
561dfe32fa1Soh_ci
562dfe32fa1Soh_ci    /// Check whether data exists in the database.
563dfe32fa1Soh_ci    ///
564dfe32fa1Soh_ci    /// # Examples
565dfe32fa1Soh_ci    ///
566dfe32fa1Soh_ci    /// ```
567dfe32fa1Soh_ci    /// use asset_definition::Value;
568dfe32fa1Soh_ci    /// use asset_db_operator::{database::Database, types::{column, DbMap}};
569dfe32fa1Soh_ci    ///
570dfe32fa1Soh_ci    /// // SQL: select count(*) as count from table_name where Owner='owner' and OwnerType=1 and Alias='alias'
571dfe32fa1Soh_ci    /// let datas = DbMap::new();
572dfe32fa1Soh_ci    /// datas.insert(column::OWNER, Value::Bytes(b"owner".to_ver()));
573dfe32fa1Soh_ci    /// datas.insert(column::OWNER_TYPE, Value::Number(OwnerType::Native as u32));
574dfe32fa1Soh_ci    /// datas.insert(column::ALIAS, Value::Bytes(b"alias".to_ver()));
575dfe32fa1Soh_ci    /// let user_id = 100;
576dfe32fa1Soh_ci    /// let exist = Database::build(user_id)?.is_data_exists(&datas, false);
577dfe32fa1Soh_ci    /// ```
578dfe32fa1Soh_ci    #[inline(always)]
579dfe32fa1Soh_ci    pub fn is_data_exists(&mut self, condition: &DbMap, is_filter_sync: bool) -> Result<bool> {
580dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
581dfe32fa1Soh_ci        let closure = |e: &Table| e.is_data_exists(condition, is_filter_sync);
582dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
583dfe32fa1Soh_ci    }
584dfe32fa1Soh_ci
585dfe32fa1Soh_ci    /// Query data that meets specified conditions(can be empty) from the database.
586dfe32fa1Soh_ci    /// If the operation is successful, the resultSet is returned.
587dfe32fa1Soh_ci    ///
588dfe32fa1Soh_ci    /// # Examples
589dfe32fa1Soh_ci    ///
590dfe32fa1Soh_ci    /// ```
591dfe32fa1Soh_ci    /// use asset_definition::Value;
592dfe32fa1Soh_ci    /// use asset_db_operator::{database::Database, types::{column, DbMap}};
593dfe32fa1Soh_ci    ///
594dfe32fa1Soh_ci    /// // SQL: select * from table_name where Owner='owner' and OwnerType=1 and Alias='alias'
595dfe32fa1Soh_ci    /// let cond = DbMap::new();
596dfe32fa1Soh_ci    /// cond.insert(column::OWNER, Value::Bytes(b"owner".to_ver()));
597dfe32fa1Soh_ci    /// cond.insert(column::OWNER_TYPE, Value::Number(OwnerType::Native as u32));
598dfe32fa1Soh_ci    /// cond.insert(column::ALIAS, Value::Bytes(b"alias".to_ver()));
599dfe32fa1Soh_ci    /// let user_id = 100;
600dfe32fa1Soh_ci    /// let ret = Database::build(user_id)?.query_datas(&vec![], &cond, None, false);
601dfe32fa1Soh_ci    /// ```
602dfe32fa1Soh_ci    #[inline(always)]
603dfe32fa1Soh_ci    pub fn query_datas(
604dfe32fa1Soh_ci        &mut self,
605dfe32fa1Soh_ci        columns: &Vec<&'static str>,
606dfe32fa1Soh_ci        condition: &DbMap,
607dfe32fa1Soh_ci        query_options: Option<&QueryOptions>,
608dfe32fa1Soh_ci        is_filter_sync: bool,
609dfe32fa1Soh_ci    ) -> Result<Vec<DbMap>> {
610dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
611dfe32fa1Soh_ci        let closure = |e: &Table| e.query_row(columns, condition, query_options, is_filter_sync, COLUMN_INFO);
612dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
613dfe32fa1Soh_ci    }
614dfe32fa1Soh_ci
615dfe32fa1Soh_ci    /// Query data that meets specified conditions(can be empty) from the database.
616dfe32fa1Soh_ci    /// If the operation is successful, the resultSet is returned.
617dfe32fa1Soh_ci    ///
618dfe32fa1Soh_ci    /// # Examples
619dfe32fa1Soh_ci    ///
620dfe32fa1Soh_ci    /// ```
621dfe32fa1Soh_ci    /// use asset_definition::Value;
622dfe32fa1Soh_ci    /// use asset_db_operator::{database::Database, types::{column, DbMap}};
623dfe32fa1Soh_ci    ///
624dfe32fa1Soh_ci    /// // SQL: select * from table_name where Owner='owner' and OwnerType=1 and Alias='alias'
625dfe32fa1Soh_ci    /// let cond = DbMap::new();
626dfe32fa1Soh_ci    /// cond.insert(column::OWNER, Value::Bytes(b"owner".to_ver()));
627dfe32fa1Soh_ci    /// cond.insert(column::OWNER_TYPE, Value::Number(OwnerType::Native as u32));
628dfe32fa1Soh_ci    /// cond.insert(column::ALIAS, Value::Bytes(b"alias".to_ver()));
629dfe32fa1Soh_ci    /// let user_id = 100;
630dfe32fa1Soh_ci    /// let ret = Database::build(user_id)?.query_data_without_lock(&vec![], &cond, None, false);
631dfe32fa1Soh_ci    /// ```
632dfe32fa1Soh_ci    pub fn query_data_without_lock(
633dfe32fa1Soh_ci        &mut self,
634dfe32fa1Soh_ci        columns: &Vec<&'static str>,
635dfe32fa1Soh_ci        condition: &DbMap,
636dfe32fa1Soh_ci        query_options: Option<&QueryOptions>,
637dfe32fa1Soh_ci        is_filter_sync: bool,
638dfe32fa1Soh_ci    ) -> Result<Vec<DbMap>> {
639dfe32fa1Soh_ci        let closure = |e: &Table| e.query_row(columns, condition, query_options, is_filter_sync, COLUMN_INFO);
640dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
641dfe32fa1Soh_ci    }
642dfe32fa1Soh_ci
643dfe32fa1Soh_ci    /// query how many data fit the query condition
644dfe32fa1Soh_ci    pub fn query_data_count(&mut self, condition: &DbMap) -> Result<u32> {
645dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
646dfe32fa1Soh_ci        let closure = |e: &Table| e.count_datas(condition, false);
647dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
648dfe32fa1Soh_ci    }
649dfe32fa1Soh_ci
650dfe32fa1Soh_ci    /// Delete old data and insert new data.
651dfe32fa1Soh_ci    pub fn replace_datas(&mut self, condition: &DbMap, is_filter_sync: bool, datas: &DbMap) -> Result<()> {
652dfe32fa1Soh_ci        let _lock = self.db_lock.mtx.lock().unwrap();
653dfe32fa1Soh_ci        let closure = |e: &Table| e.replace_row(condition, is_filter_sync, datas);
654dfe32fa1Soh_ci        self.restore_if_exec_fail(closure)
655dfe32fa1Soh_ci    }
656dfe32fa1Soh_ci}
657dfe32fa1Soh_ci
658dfe32fa1Soh_ciimpl Drop for Database {
659dfe32fa1Soh_ci    fn drop(&mut self) {
660dfe32fa1Soh_ci        self.close_db()
661dfe32fa1Soh_ci    }
662dfe32fa1Soh_ci}
663