1dfe32fa1Soh_ci/* 2dfe32fa1Soh_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3dfe32fa1Soh_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4dfe32fa1Soh_ci * you may not use this file except in compliance with the License. 5dfe32fa1Soh_ci * You may obtain a copy of the License at 6dfe32fa1Soh_ci * 7dfe32fa1Soh_ci * http://www.apache.org/licenses/LICENSE-2.0 8dfe32fa1Soh_ci * 9dfe32fa1Soh_ci * Unless required by applicable law or agreed to in writing, software 10dfe32fa1Soh_ci * distributed under the License is distributed on an "AS IS" BASIS, 11dfe32fa1Soh_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12dfe32fa1Soh_ci * See the License for the specific language governing permissions and 13dfe32fa1Soh_ci * limitations under the License. 14dfe32fa1Soh_ci */ 15dfe32fa1Soh_ci 16dfe32fa1Soh_ci//! This module implements database statements and provides precompiled query capabilities. 17dfe32fa1Soh_ci 18dfe32fa1Soh_ciuse core::ffi::c_void; 19dfe32fa1Soh_ciuse std::ffi::CStr; 20dfe32fa1Soh_ci 21dfe32fa1Soh_ciuse asset_definition::{log_throw_error, ErrCode, Result, Value}; 22dfe32fa1Soh_ciuse asset_log::loge; 23dfe32fa1Soh_ci 24dfe32fa1Soh_ciuse crate::{ 25dfe32fa1Soh_ci database::Database, 26dfe32fa1Soh_ci types::{sqlite_err_handle, SQLITE_DONE, SQLITE_OK, SQLITE_ROW}, 27dfe32fa1Soh_ci}; 28dfe32fa1Soh_ci 29dfe32fa1Soh_citype BindCallback = extern "C" fn(p: *mut c_void); 30dfe32fa1Soh_ciextern "C" { 31dfe32fa1Soh_ci fn SqliteFinalize(stmt: *mut c_void) -> i32; 32dfe32fa1Soh_ci fn SqlitePrepareV2(db: *mut c_void, z_sql: *const u8, pp_stmt: *mut *mut c_void, pz_tail: *mut *mut u8) -> i32; 33dfe32fa1Soh_ci fn SqliteBindBlob(stmt: *mut c_void, index: i32, blob: *const u8, n: i32, callback: Option<BindCallback>) -> i32; 34dfe32fa1Soh_ci fn SqliteBindInt64(stmt: *mut c_void, index: i32, value: i64) -> i32; 35dfe32fa1Soh_ci fn SqliteStep(stmt: *mut c_void) -> i32; 36dfe32fa1Soh_ci fn SqliteColumnName(stmt: *mut c_void, n: i32) -> *const u8; 37dfe32fa1Soh_ci fn SqliteDataCount(stmt: *mut c_void) -> i32; 38dfe32fa1Soh_ci fn SqliteColumnBlob(stmt: *mut c_void, i_col: i32) -> *const u8; 39dfe32fa1Soh_ci fn SqliteColumnInt64(stmt: *mut c_void, i_col: i32) -> i64; 40dfe32fa1Soh_ci fn SqliteColumnBytes(stmt: *mut c_void, i_col: i32) -> i32; 41dfe32fa1Soh_ci fn SqliteColumnType(stmt: *mut c_void, i_col: i32) -> i32; 42dfe32fa1Soh_ci fn SqliteReset(stmt: *mut c_void) -> i32; 43dfe32fa1Soh_ci} 44dfe32fa1Soh_ci 45dfe32fa1Soh_ciconst SQLITE_INTEGER: i32 = 1; 46dfe32fa1Soh_ciconst SQLITE_BLOB: i32 = 4; 47dfe32fa1Soh_ciconst SQLITE_NULL: i32 = 5; 48dfe32fa1Soh_ci 49dfe32fa1Soh_ci#[repr(C)] 50dfe32fa1Soh_cipub(crate) struct Statement<'b> { 51dfe32fa1Soh_ci pub(crate) sql: String, 52dfe32fa1Soh_ci db: &'b Database, 53dfe32fa1Soh_ci handle: usize, // Poiner to statement. 54dfe32fa1Soh_ci} 55dfe32fa1Soh_ci 56dfe32fa1Soh_ciimpl<'b> Statement<'b> { 57dfe32fa1Soh_ci /// Prepare a sql, you can use '?' for datas and bind datas later. 58dfe32fa1Soh_ci pub(crate) fn prepare(sql: &str, db: &'b Database) -> Result<Statement<'b>> { 59dfe32fa1Soh_ci let mut tail = 0usize; 60dfe32fa1Soh_ci let mut sql_s = sql.to_string(); 61dfe32fa1Soh_ci sql_s.push('\0'); 62dfe32fa1Soh_ci let mut stmt = Statement { sql: sql_s, handle: 0, db }; 63dfe32fa1Soh_ci let ret = unsafe { 64dfe32fa1Soh_ci SqlitePrepareV2( 65dfe32fa1Soh_ci db.handle as _, 66dfe32fa1Soh_ci stmt.sql.as_ptr(), 67dfe32fa1Soh_ci &mut stmt.handle as *mut usize as _, 68dfe32fa1Soh_ci &mut tail as *mut usize as _, 69dfe32fa1Soh_ci ) 70dfe32fa1Soh_ci }; 71dfe32fa1Soh_ci if ret == 0 { 72dfe32fa1Soh_ci Ok(stmt) 73dfe32fa1Soh_ci } else { 74dfe32fa1Soh_ci db.print_db_msg(); 75dfe32fa1Soh_ci log_throw_error!(sqlite_err_handle(ret), "Prepare statement failed, err={}", ret) 76dfe32fa1Soh_ci } 77dfe32fa1Soh_ci } 78dfe32fa1Soh_ci 79dfe32fa1Soh_ci /// Executing the precompiled sql. if succ 80dfe32fa1Soh_ci /// If the execution is successful, return SQLITE_DONE for update, insert, delete and return SQLITE_ROW for select. 81dfe32fa1Soh_ci pub(crate) fn step(&self) -> Result<i32> { 82dfe32fa1Soh_ci let ret = unsafe { SqliteStep(self.handle as _) }; 83dfe32fa1Soh_ci if ret != SQLITE_ROW && ret != SQLITE_DONE { 84dfe32fa1Soh_ci self.db.print_db_msg(); 85dfe32fa1Soh_ci log_throw_error!(sqlite_err_handle(ret), "Step statement failed, err={}", ret) 86dfe32fa1Soh_ci } else { 87dfe32fa1Soh_ci Ok(ret) 88dfe32fa1Soh_ci } 89dfe32fa1Soh_ci } 90dfe32fa1Soh_ci 91dfe32fa1Soh_ci /// Reset statement before bind data for insert statement. 92dfe32fa1Soh_ci #[allow(dead_code)] 93dfe32fa1Soh_ci pub(crate) fn reset(&self) -> Result<()> { 94dfe32fa1Soh_ci let ret = unsafe { SqliteReset(self.handle as _) }; 95dfe32fa1Soh_ci if ret != SQLITE_OK { 96dfe32fa1Soh_ci self.db.print_db_msg(); 97dfe32fa1Soh_ci log_throw_error!(sqlite_err_handle(ret), "Reset statement failed, err={}", ret) 98dfe32fa1Soh_ci } else { 99dfe32fa1Soh_ci Ok(()) 100dfe32fa1Soh_ci } 101dfe32fa1Soh_ci } 102dfe32fa1Soh_ci 103dfe32fa1Soh_ci /// Bind data to prepared statement. The index is start from 1. 104dfe32fa1Soh_ci pub(crate) fn bind_data(&self, index: i32, data: &Value) -> Result<()> { 105dfe32fa1Soh_ci let ret = match data { 106dfe32fa1Soh_ci Value::Bytes(b) => unsafe { SqliteBindBlob(self.handle as _, index, b.as_ptr(), b.len() as _, None) }, 107dfe32fa1Soh_ci Value::Number(i) => unsafe { SqliteBindInt64(self.handle as _, index, *i as _) }, 108dfe32fa1Soh_ci Value::Bool(b) => unsafe { SqliteBindInt64(self.handle as _, index, *b as _) }, 109dfe32fa1Soh_ci }; 110dfe32fa1Soh_ci if ret != SQLITE_OK { 111dfe32fa1Soh_ci self.db.print_db_msg(); 112dfe32fa1Soh_ci log_throw_error!(sqlite_err_handle(ret), "Bind data failed, index={}, err={}", index, ret) 113dfe32fa1Soh_ci } else { 114dfe32fa1Soh_ci Ok(()) 115dfe32fa1Soh_ci } 116dfe32fa1Soh_ci } 117dfe32fa1Soh_ci 118dfe32fa1Soh_ci /// Query the column name. 119dfe32fa1Soh_ci pub(crate) fn query_column_name(&self, n: i32) -> Result<&str> { 120dfe32fa1Soh_ci let s = unsafe { SqliteColumnName(self.handle as _, n) }; 121dfe32fa1Soh_ci if !s.is_null() { 122dfe32fa1Soh_ci let name = unsafe { CStr::from_ptr(s as _) }; 123dfe32fa1Soh_ci if let Ok(rn) = name.to_str() { 124dfe32fa1Soh_ci return Ok(rn); 125dfe32fa1Soh_ci } 126dfe32fa1Soh_ci } 127dfe32fa1Soh_ci log_throw_error!(ErrCode::DatabaseError, "[FATAL][DB]Get asset column name failed.") 128dfe32fa1Soh_ci } 129dfe32fa1Soh_ci 130dfe32fa1Soh_ci /// Get the count of columns in the query result. 131dfe32fa1Soh_ci pub(crate) fn data_count(&self) -> i32 { 132dfe32fa1Soh_ci unsafe { SqliteDataCount(self.handle as _) } 133dfe32fa1Soh_ci } 134dfe32fa1Soh_ci 135dfe32fa1Soh_ci /// Query column and return a value of the Value type. 136dfe32fa1Soh_ci pub(crate) fn query_column_auto_type(&self, i: i32) -> Result<Option<Value>> { 137dfe32fa1Soh_ci let tp = self.column_type(i); 138dfe32fa1Soh_ci let data = match tp { 139dfe32fa1Soh_ci SQLITE_INTEGER => Some(Value::Number(self.query_column_int(i))), 140dfe32fa1Soh_ci SQLITE_BLOB => { 141dfe32fa1Soh_ci let blob = self.query_column_blob(i); 142dfe32fa1Soh_ci if blob.is_empty() { 143dfe32fa1Soh_ci None 144dfe32fa1Soh_ci } else { 145dfe32fa1Soh_ci Some(Value::Bytes(blob.to_vec())) 146dfe32fa1Soh_ci } 147dfe32fa1Soh_ci }, 148dfe32fa1Soh_ci SQLITE_NULL => None, 149dfe32fa1Soh_ci t => return log_throw_error!(ErrCode::DatabaseError, "Unexpect column type: {}.", t), 150dfe32fa1Soh_ci }; 151dfe32fa1Soh_ci Ok(data) 152dfe32fa1Soh_ci } 153dfe32fa1Soh_ci 154dfe32fa1Soh_ci /// Query column datas in result set of blob type 155dfe32fa1Soh_ci /// The index is start from 0. 156dfe32fa1Soh_ci pub(crate) fn query_column_blob(&self, index: i32) -> &[u8] { 157dfe32fa1Soh_ci let blob = unsafe { SqliteColumnBlob(self.handle as _, index) }; 158dfe32fa1Soh_ci let len = self.column_bytes(index); 159dfe32fa1Soh_ci unsafe { core::slice::from_raw_parts(blob, len as _) } 160dfe32fa1Soh_ci } 161dfe32fa1Soh_ci 162dfe32fa1Soh_ci /// Query column datas in result set of int type. 163dfe32fa1Soh_ci /// The index is start with 0. 164dfe32fa1Soh_ci pub(crate) fn query_column_int(&self, index: i32) -> u32 { 165dfe32fa1Soh_ci unsafe { SqliteColumnInt64(self.handle as _, index) as u32 } 166dfe32fa1Soh_ci } 167dfe32fa1Soh_ci 168dfe32fa1Soh_ci /// Get the bytes of data, you should first call query_column_text or query_column_blob, 169dfe32fa1Soh_ci pub(crate) fn column_bytes(&self, index: i32) -> i32 { 170dfe32fa1Soh_ci unsafe { SqliteColumnBytes(self.handle as _, index) } 171dfe32fa1Soh_ci } 172dfe32fa1Soh_ci 173dfe32fa1Soh_ci /// Get the type of column. 174dfe32fa1Soh_ci pub(crate) fn column_type(&self, index: i32) -> i32 { 175dfe32fa1Soh_ci unsafe { SqliteColumnType(self.handle as _, index) } 176dfe32fa1Soh_ci } 177dfe32fa1Soh_ci} 178dfe32fa1Soh_ci 179dfe32fa1Soh_ciimpl<'b> Drop for Statement<'b> { 180dfe32fa1Soh_ci fn drop(&mut self) { 181dfe32fa1Soh_ci if self.handle != 0 { 182dfe32fa1Soh_ci let ret = unsafe { SqliteFinalize(self.handle as _) }; 183dfe32fa1Soh_ci if ret != SQLITE_OK { 184dfe32fa1Soh_ci loge!("sqlite3 finalize fail ret {}", ret); 185dfe32fa1Soh_ci } 186dfe32fa1Soh_ci } 187dfe32fa1Soh_ci } 188dfe32fa1Soh_ci} 189