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