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