• 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 data operation management on database tables.
17 //! The managed data can be user input. Because we will prepare and bind data.
18 
19 use core::ffi::c_void;
20 use std::cmp::Ordering;
21 
22 use asset_definition::{log_throw_error, Conversion, DataType, ErrCode, Result, Value};
23 
24 use crate::{
25     database::Database,
26     statement::Statement,
27     transaction::Transaction,
28     types::{ColumnInfo, DbMap, QueryOptions, SQLITE_ROW},
29 };
30 
31 extern "C" {
SqliteChanges(db: *mut c_void) -> i3232     fn SqliteChanges(db: *mut c_void) -> i32;
33 }
34 
35 #[repr(C)]
36 pub(crate) struct Table<'a> {
37     pub(crate) table_name: String,
38     pub(crate) db: &'a Database,
39 }
40 
41 #[inline(always)]
bind_datas(datas: &DbMap, stmt: &Statement, index: &mut i32) -> Result<()>42 fn bind_datas(datas: &DbMap, stmt: &Statement, index: &mut i32) -> Result<()> {
43     for (_, value) in datas.iter() {
44         stmt.bind_data(*index, value)?;
45         *index += 1;
46     }
47     Ok(())
48 }
49 
50 #[inline(always)]
build_sql_columns_not_empty(columns: &Vec<&str>, sql: &mut String)51 fn build_sql_columns_not_empty(columns: &Vec<&str>, sql: &mut String) {
52     for i in 0..columns.len() {
53         let column = &columns[i];
54         sql.push_str(column);
55         if i != columns.len() - 1 {
56             sql.push(',');
57         }
58     }
59 }
60 
61 #[inline(always)]
build_sql_columns(columns: &Vec<&str>, sql: &mut String)62 fn build_sql_columns(columns: &Vec<&str>, sql: &mut String) {
63     if !columns.is_empty() {
64         build_sql_columns_not_empty(columns, sql);
65     } else {
66         sql.push('*');
67     }
68 }
69 
70 #[inline(always)]
build_sql_where(conditions: &DbMap, sql: &mut String)71 fn build_sql_where(conditions: &DbMap, sql: &mut String) {
72     if !conditions.is_empty() {
73         sql.push_str(" where ");
74         for (i, column_name) in conditions.keys().enumerate() {
75             sql.push_str(column_name);
76             sql.push_str("=?");
77             if i != conditions.len() - 1 {
78                 sql.push_str(" and ")
79             }
80         }
81     }
82 }
83 
84 #[inline(always)]
build_sql_values(len: usize, sql: &mut String)85 fn build_sql_values(len: usize, sql: &mut String) {
86     for i in 0..len {
87         sql.push('?');
88         if i != len - 1 {
89             sql.push(',');
90         }
91     }
92 }
93 
from_data_type_to_str(value: &DataType) -> &'static str94 fn from_data_type_to_str(value: &DataType) -> &'static str {
95     match *value {
96         DataType::Bytes => "BLOB",
97         DataType::Number => "INTEGER",
98         DataType::Bool => "INTEGER",
99     }
100 }
101 
from_data_value_to_str_value(value: &Value) -> String102 fn from_data_value_to_str_value(value: &Value) -> String {
103     match *value {
104         Value::Number(i) => format!("{}", i),
105         Value::Bytes(_) => String::from("NOT SUPPORTED"),
106         Value::Bool(b) => format!("{}", b),
107     }
108 }
109 
build_sql_query_options(query_options: Option<&QueryOptions>, sql: &mut String)110 fn build_sql_query_options(query_options: Option<&QueryOptions>, sql: &mut String) {
111     if let Some(option) = query_options {
112         if let Some(order_by) = &option.order_by {
113             if !order_by.is_empty() {
114                 sql.push_str(" order by ");
115                 build_sql_columns_not_empty(order_by, sql);
116             }
117         }
118         if let Some(order) = option.order {
119             let str = if order == Ordering::Greater {
120                 "ASC"
121             } else if order == Ordering::Less {
122                 "DESC"
123             } else {
124                 ""
125             };
126             sql.push_str(format!(" {}", str).as_str());
127         }
128         if let Some(limit) = option.limit {
129             sql.push_str(format!(" limit {}", limit).as_str());
130             if let Some(offset) = option.offset {
131                 sql.push_str(format!(" offset {}", offset).as_str());
132             }
133         } else if let Some(offset) = option.offset {
134             sql.push_str(format!(" limit -1 offset {}", offset).as_str());
135         }
136     }
137 }
138 
get_column_info(columns: &'static [ColumnInfo], db_column: &str) -> Result<&'static ColumnInfo>139 fn get_column_info(columns: &'static [ColumnInfo], db_column: &str) -> Result<&'static ColumnInfo> {
140     for column in columns.iter() {
141         if column.name.eq(db_column) {
142             return Ok(column);
143         }
144     }
145     log_throw_error!(ErrCode::DataCorrupted, "Database is corrupted.")
146 }
147 
148 impl<'a> Table<'a> {
new(table_name: &str, db: &'a Database) -> Table<'a>149     pub(crate) fn new(table_name: &str, db: &'a Database) -> Table<'a> {
150         Table { table_name: table_name.to_string(), db }
151     }
152 
153     #[allow(dead_code)]
exist(&self) -> Result<bool>154     pub(crate) fn exist(&self) -> Result<bool> {
155         let sql = format!("select * from sqlite_master where type ='table' and name = '{}'", self.table_name);
156         let stmt = Statement::prepare(sql.as_str(), self.db)?;
157         let ret = stmt.step()?;
158         if ret == SQLITE_ROW {
159             Ok(true)
160         } else {
161             Ok(false)
162         }
163     }
164 
165     #[allow(dead_code)]
delete(&self) -> Result<()>166     pub(crate) fn delete(&self) -> Result<()> {
167         let sql = format!("DROP TABLE {}", self.table_name);
168         self.db.exec(&sql)
169     }
170 
171     /// Create a table with name 'table_name'.
172     /// The columns is descriptions for each column.
create(&self, columns: &[ColumnInfo]) -> Result<()>173     pub(crate) fn create(&self, columns: &[ColumnInfo]) -> Result<()> {
174         let mut sql = format!("CREATE TABLE IF NOT EXISTS {}(", self.table_name);
175         for i in 0..columns.len() {
176             let column = &columns[i];
177             sql.push_str(column.name);
178             sql.push(' ');
179             sql.push_str(from_data_type_to_str(&column.data_type));
180             if column.is_primary_key {
181                 sql.push_str(" PRIMARY KEY");
182             }
183             if column.not_null {
184                 sql.push_str(" NOT NULL");
185             }
186             if i != columns.len() - 1 {
187                 sql.push(',')
188             };
189         }
190         sql.push_str(");");
191         self.db.exec(sql.as_str())
192     }
193 
194     /// Insert a row into table, and datas is the value to be insert.
195     ///
196     /// # Examples
197     ///
198     /// ```
199     /// // SQL: insert into table_name(id,alias) values (3,'alias1')
200     /// let datas = &DbMap::from([("id", Value::Number(3), ("alias", Value::Bytes(b"alias1"))]);
201     /// let ret = table.insert_row(datas);
202     /// ```
insert_row(&self, datas: &DbMap) -> Result<i32>203     pub(crate) fn insert_row(&self, datas: &DbMap) -> Result<i32> {
204         let mut sql = format!("insert into {} (", self.table_name);
205         for (i, column_name) in datas.keys().enumerate() {
206             sql.push_str(column_name);
207             if i != datas.len() - 1 {
208                 sql.push(',');
209             }
210         }
211 
212         sql.push_str(") values (");
213         build_sql_values(datas.len(), &mut sql);
214         sql.push(')');
215         let stmt = Statement::prepare(&sql, self.db)?;
216         let mut index = 1;
217         bind_datas(datas, &stmt, &mut index)?;
218         stmt.step()?;
219         let count = unsafe { SqliteChanges(self.db.handle as _) };
220         Ok(count)
221     }
222 
223     /// Delete row from table.
224     ///
225     /// # Examples
226     ///
227     /// ```
228     /// // SQL: delete from table_name where id=2
229     /// let condition = &DbMap::from([("id", Value::Number(2)]);
230     /// let ret = table.delete_row(condition);
231     /// ```
delete_row(&self, condition: &DbMap) -> Result<i32>232     pub(crate) fn delete_row(&self, condition: &DbMap) -> Result<i32> {
233         let mut sql = format!("delete from {}", self.table_name);
234         build_sql_where(condition, &mut sql);
235         let stmt = Statement::prepare(&sql, self.db)?;
236         let mut index = 1;
237         bind_datas(condition, &stmt, &mut index)?;
238         stmt.step()?;
239         let count = unsafe { SqliteChanges(self.db.handle as _) };
240         Ok(count)
241     }
242 
243     /// Update a row in table.
244     ///
245     /// # Examples
246     ///
247     /// ```
248     /// // SQL: update table_name set alias='update_value' where id=2
249     /// let condition = &DbMap::from([("id", Value::Number(2)]);
250     /// let datas = &DbMap::from([("alias", Value::Bytes(b"update_value")]);
251     /// let ret = table.update_row(conditions, datas);
252     /// ```
update_row(&self, condition: &DbMap, datas: &DbMap) -> Result<i32>253     pub(crate) fn update_row(&self, condition: &DbMap, datas: &DbMap) -> Result<i32> {
254         let mut sql = format!("update {} set ", self.table_name);
255         for (i, column_name) in datas.keys().enumerate() {
256             sql.push_str(column_name);
257             sql.push_str("=?");
258             if i != datas.len() - 1 {
259                 sql.push(',');
260             }
261         }
262         build_sql_where(condition, &mut sql);
263         let stmt = Statement::prepare(&sql, self.db)?;
264         let mut index = 1;
265         bind_datas(datas, &stmt, &mut index)?;
266         bind_datas(condition, &stmt, &mut index)?;
267         stmt.step()?;
268         let count = unsafe { SqliteChanges(self.db.handle as _) };
269         Ok(count)
270     }
271 
272     /// Query row from table.
273     /// If length of columns is 0, all table columns are queried. (eg. select * xxx)
274     /// If length of condition is 0, all data in the table is queried.
275     ///
276     /// # Examples
277     ///
278     /// ```
279     /// // SQL: select alias,blobs from table_name
280     /// let result_set = table.query_datas_with_key_value(&vec!["alias", "blobs"], &vec![]);
281     /// ```
query_row( &self, columns: &Vec<&'static str>, condition: &DbMap, query_options: Option<&QueryOptions>, column_info: &'static [ColumnInfo], ) -> Result<Vec<DbMap>>282     pub(crate) fn query_row(
283         &self,
284         columns: &Vec<&'static str>,
285         condition: &DbMap,
286         query_options: Option<&QueryOptions>,
287         column_info: &'static [ColumnInfo],
288     ) -> Result<Vec<DbMap>> {
289         let mut sql = String::from("select ");
290         if !columns.is_empty() {
291             sql.push_str("distinct ");
292         }
293         build_sql_columns(columns, &mut sql);
294         sql.push_str(" from ");
295         sql.push_str(self.table_name.as_str());
296         build_sql_where(condition, &mut sql);
297         build_sql_query_options(query_options, &mut sql);
298         let stmt = Statement::prepare(&sql, self.db)?;
299         let mut index = 1;
300         bind_datas(condition, &stmt, &mut index)?;
301         let mut result = vec![];
302         while stmt.step()? == SQLITE_ROW {
303             let mut record = DbMap::new();
304             let n = stmt.data_count();
305             for i in 0..n {
306                 let column_name = stmt.query_column_name(i)?;
307                 let column_info = get_column_info(column_info, column_name)?;
308                 match stmt.query_column_auto_type(i)? {
309                     Some(Value::Number(n)) if column_info.data_type == DataType::Bool => {
310                         record.insert(column_info.name, Value::Bool(n != 0))
311                     },
312                     Some(n) if n.data_type() == column_info.data_type => record.insert(column_info.name, n),
313                     Some(_) => return log_throw_error!(ErrCode::DataCorrupted, "The data in DB has been tampered with."),
314                     None => continue,
315                 };
316             }
317             result.push(record);
318         }
319         Ok(result)
320     }
321 
322     /// Count the number of datas with query condition(can be empty).
323     ///
324     /// # Examples
325     ///
326     /// ```
327     /// // SQL: select count(*) as count from table_name where id=3
328     /// let count = table.count_datas(&DbMap::from([("id", Value::Number(3))]));
329     /// ```
count_datas(&self, condition: &DbMap) -> Result<u32>330     pub(crate) fn count_datas(&self, condition: &DbMap) -> Result<u32> {
331         let mut sql = format!("select count(*) as count from {}", self.table_name);
332         build_sql_where(condition, &mut sql);
333         let stmt = Statement::prepare(&sql, self.db)?;
334         let mut index = 1;
335         bind_datas(condition, &stmt, &mut index)?;
336         stmt.step()?;
337         let count = stmt.query_column_int(0);
338         Ok(count)
339     }
340 
341     /// Check whether data exists in the database table.
342     ///
343     /// # Examples
344     ///
345     /// ```
346     /// // SQL: select count(*) as count from table_name where id=3 and alias='alias'
347     /// let exits = table
348     ///     .is_data_exists(&DbMap::from([("id", Value::Number(3)), ("alias", Value::Bytes(b"alias"))]));
349     /// ```
is_data_exists(&self, cond: &DbMap) -> Result<bool>350     pub(crate) fn is_data_exists(&self, cond: &DbMap) -> Result<bool> {
351         let ret = self.count_datas(cond);
352         match ret {
353             Ok(count) => Ok(count > 0),
354             Err(e) => Err(e),
355         }
356     }
357 
358     /// Add new column tp table.
359     /// 1. Primary key cannot be added.
360     /// 2. Cannot add a non-null column with no default value
361     /// 3. Only the integer and blob types support the default value, and the default value of the blob type is null.
362     ///
363     /// # Examples
364     ///
365     /// ```
366     /// // SQL: alter table table_name add cloumn id integer not null
367     /// let ret = table.add_column(
368     ///     ColumnInfo {
369     ///         name: "id",
370     ///         data_type: DataType::INTEGER,
371     ///         is_primary_key: false,
372     ///         not_null: true,
373     ///     },
374     ///     Some(Value::Number(0)),
375     /// );
376     /// ```
377     #[allow(dead_code)]
add_column(&self, column: ColumnInfo, default_value: Option<Value>) -> Result<()>378     pub(crate) fn add_column(&self, column: ColumnInfo, default_value: Option<Value>) -> Result<()> {
379         if column.is_primary_key {
380             return log_throw_error!(ErrCode::InvalidArgument, "The primary key already exists in the table.");
381         }
382         if column.not_null && default_value.is_none() {
383             return log_throw_error!(ErrCode::InvalidArgument, "A default value is required for a non-null column.");
384         }
385         let data_type = from_data_type_to_str(&column.data_type);
386         let mut sql = format!("ALTER TABLE {} ADD COLUMN {} {}", self.table_name, column.name, data_type);
387         if let Some(data) = default_value {
388             sql.push_str(" DEFAULT ");
389             sql.push_str(&from_data_value_to_str_value(&data));
390         }
391         if column.not_null {
392             sql.push_str(" NOT NULL");
393         }
394         self.db.exec(sql.as_str())
395     }
396 
replace_row(&self, condition: &DbMap, datas: &DbMap) -> Result<()>397     pub(crate) fn replace_row(&self, condition: &DbMap, datas: &DbMap) -> Result<()> {
398         let mut trans = Transaction::new(self.db);
399         trans.begin()?;
400         if self.delete_row(condition).is_ok() && self.insert_row(datas).is_ok() {
401             trans.commit()
402         } else {
403             trans.rollback()
404         }
405     }
406 }
407