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