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