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 implements database statements and provides precompiled query capabilities. 17 18 use core::ffi::c_void; 19 use std::ffi::CStr; 20 21 use asset_definition::{log_throw_error, ErrCode, Result, Value}; 22 use asset_log::loge; 23 24 use crate::{ 25 database::Database, 26 types::{sqlite_err_handle, SQLITE_DONE, SQLITE_OK, SQLITE_ROW}, 27 }; 28 29 type BindCallback = extern "C" fn(p: *mut c_void); 30 extern "C" { SqliteFinalize(stmt: *mut c_void) -> i3231 fn SqliteFinalize(stmt: *mut c_void) -> i32; SqlitePrepareV2(db: *mut c_void, z_sql: *const u8, pp_stmt: *mut *mut c_void, pz_tail: *mut *mut u8) -> i3232 fn SqlitePrepareV2(db: *mut c_void, z_sql: *const u8, pp_stmt: *mut *mut c_void, pz_tail: *mut *mut u8) -> i32; SqliteBindBlob(stmt: *mut c_void, index: i32, blob: *const u8, n: i32, callback: Option<BindCallback>) -> i3233 fn SqliteBindBlob(stmt: *mut c_void, index: i32, blob: *const u8, n: i32, callback: Option<BindCallback>) -> i32; SqliteBindInt64(stmt: *mut c_void, index: i32, value: i64) -> i3234 fn SqliteBindInt64(stmt: *mut c_void, index: i32, value: i64) -> i32; SqliteStep(stmt: *mut c_void) -> i3235 fn SqliteStep(stmt: *mut c_void) -> i32; SqliteColumnName(stmt: *mut c_void, n: i32) -> *const u836 fn SqliteColumnName(stmt: *mut c_void, n: i32) -> *const u8; SqliteDataCount(stmt: *mut c_void) -> i3237 fn SqliteDataCount(stmt: *mut c_void) -> i32; SqliteColumnBlob(stmt: *mut c_void, i_col: i32) -> *const u838 fn SqliteColumnBlob(stmt: *mut c_void, i_col: i32) -> *const u8; SqliteColumnInt64(stmt: *mut c_void, i_col: i32) -> i6439 fn SqliteColumnInt64(stmt: *mut c_void, i_col: i32) -> i64; SqliteColumnBytes(stmt: *mut c_void, i_col: i32) -> i3240 fn SqliteColumnBytes(stmt: *mut c_void, i_col: i32) -> i32; SqliteColumnType(stmt: *mut c_void, i_col: i32) -> i3241 fn SqliteColumnType(stmt: *mut c_void, i_col: i32) -> i32; SqliteReset(stmt: *mut c_void) -> i3242 fn SqliteReset(stmt: *mut c_void) -> i32; 43 } 44 45 const SQLITE_INTEGER: i32 = 1; 46 const SQLITE_BLOB: i32 = 4; 47 const SQLITE_NULL: i32 = 5; 48 49 #[repr(C)] 50 pub(crate) struct Statement<'b> { 51 pub(crate) sql: String, 52 db: &'b Database, 53 handle: usize, // Poiner to statement. 54 } 55 56 impl<'b> Statement<'b> { 57 /// Prepare a sql, you can use '?' for datas and bind datas later. prepare(sql: &str, db: &'b Database) -> Result<Statement<'b>>58 pub(crate) fn prepare(sql: &str, db: &'b Database) -> Result<Statement<'b>> { 59 let mut tail = 0usize; 60 let mut sql_s = sql.to_string(); 61 sql_s.push('\0'); 62 let mut stmt = Statement { sql: sql_s, handle: 0, db }; 63 let ret = unsafe { 64 SqlitePrepareV2( 65 db.handle as _, 66 stmt.sql.as_ptr(), 67 &mut stmt.handle as *mut usize as _, 68 &mut tail as *mut usize as _, 69 ) 70 }; 71 if ret == 0 { 72 Ok(stmt) 73 } else { 74 db.print_db_msg(); 75 log_throw_error!(sqlite_err_handle(ret), "Prepare statement failed, err={}", ret) 76 } 77 } 78 79 /// Executing the precompiled sql. if succ 80 /// If the execution is successful, return SQLITE_DONE for update, insert, delete and return SQLITE_ROW for select. step(&self) -> Result<i32>81 pub(crate) fn step(&self) -> Result<i32> { 82 let ret = unsafe { SqliteStep(self.handle as _) }; 83 if ret != SQLITE_ROW && ret != SQLITE_DONE { 84 self.db.print_db_msg(); 85 log_throw_error!(sqlite_err_handle(ret), "Step statement failed, err={}", ret) 86 } else { 87 Ok(ret) 88 } 89 } 90 91 /// Reset statement before bind data for insert statement. 92 #[allow(dead_code)] reset(&self) -> Result<()>93 pub(crate) fn reset(&self) -> Result<()> { 94 let ret = unsafe { SqliteReset(self.handle as _) }; 95 if ret != SQLITE_OK { 96 self.db.print_db_msg(); 97 log_throw_error!(sqlite_err_handle(ret), "Reset statement failed, err={}", ret) 98 } else { 99 Ok(()) 100 } 101 } 102 103 /// Bind data to prepared statement. The index is start from 1. bind_data(&self, index: i32, data: &Value) -> Result<()>104 pub(crate) fn bind_data(&self, index: i32, data: &Value) -> Result<()> { 105 let ret = match data { 106 Value::Bytes(b) => unsafe { SqliteBindBlob(self.handle as _, index, b.as_ptr(), b.len() as _, None) }, 107 Value::Number(i) => unsafe { SqliteBindInt64(self.handle as _, index, *i as _) }, 108 Value::Bool(b) => unsafe { SqliteBindInt64(self.handle as _, index, *b as _) }, 109 }; 110 if ret != SQLITE_OK { 111 self.db.print_db_msg(); 112 log_throw_error!(sqlite_err_handle(ret), "Bind data failed, index={}, err={}", index, ret) 113 } else { 114 Ok(()) 115 } 116 } 117 118 /// Query the column name. query_column_name(&self, n: i32) -> Result<&str>119 pub(crate) fn query_column_name(&self, n: i32) -> Result<&str> { 120 let s = unsafe { SqliteColumnName(self.handle as _, n) }; 121 if !s.is_null() { 122 let name = unsafe { CStr::from_ptr(s as _) }; 123 if let Ok(rn) = name.to_str() { 124 return Ok(rn); 125 } 126 } 127 log_throw_error!(ErrCode::DatabaseError, "[FATAL][DB]Get asset column name failed.") 128 } 129 130 /// Get the count of columns in the query result. data_count(&self) -> i32131 pub(crate) fn data_count(&self) -> i32 { 132 unsafe { SqliteDataCount(self.handle as _) } 133 } 134 135 /// Query column and return a value of the Value type. query_column_auto_type(&self, i: i32) -> Result<Option<Value>>136 pub(crate) fn query_column_auto_type(&self, i: i32) -> Result<Option<Value>> { 137 let tp = self.column_type(i); 138 let data = match tp { 139 SQLITE_INTEGER => Some(Value::Number(self.query_column_int(i))), 140 SQLITE_BLOB => { 141 let blob = self.query_column_blob(i); 142 if blob.is_empty() { 143 None 144 } else { 145 Some(Value::Bytes(blob.to_vec())) 146 } 147 }, 148 SQLITE_NULL => None, 149 t => return log_throw_error!(ErrCode::DatabaseError, "Unexpect column type: {}.", t), 150 }; 151 Ok(data) 152 } 153 154 /// Query column datas in result set of blob type 155 /// The index is start from 0. query_column_blob(&self, index: i32) -> &[u8]156 pub(crate) fn query_column_blob(&self, index: i32) -> &[u8] { 157 let blob = unsafe { SqliteColumnBlob(self.handle as _, index) }; 158 let len = self.column_bytes(index); 159 unsafe { core::slice::from_raw_parts(blob, len as _) } 160 } 161 162 /// Query column datas in result set of int type. 163 /// The index is start with 0. query_column_int(&self, index: i32) -> u32164 pub(crate) fn query_column_int(&self, index: i32) -> u32 { 165 unsafe { SqliteColumnInt64(self.handle as _, index) as u32 } 166 } 167 168 /// Get the bytes of data, you should first call query_column_text or query_column_blob, column_bytes(&self, index: i32) -> i32169 pub(crate) fn column_bytes(&self, index: i32) -> i32 { 170 unsafe { SqliteColumnBytes(self.handle as _, index) } 171 } 172 173 /// Get the type of column. column_type(&self, index: i32) -> i32174 pub(crate) fn column_type(&self, index: i32) -> i32 { 175 unsafe { SqliteColumnType(self.handle as _, index) } 176 } 177 } 178 179 impl<'b> Drop for Statement<'b> { drop(&mut self)180 fn drop(&mut self) { 181 if self.handle != 0 { 182 let ret = unsafe { SqliteFinalize(self.handle as _) }; 183 if ret != SQLITE_OK { 184 loge!("sqlite3 finalize fail ret {}", ret); 185 } 186 } 187 } 188 } 189