1 // Copyright (C) 2024 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 use cxx::SharedPtr; 15 use std::pin::Pin; 16 17 use crate::config::OpenConfig; 18 use crate::params::{FromSql, Params}; 19 use crate::wrapper::ffi::{self, Execute, NewRowEntity, Query}; 20 use crate::wrapper::open_rdb_store; 21 22 const E_OK: i32 = 0; 23 24 /// `RdbStore` ffi wrapper. 25 pub struct RdbStore<'a> { 26 inner: RdbStoreInner<'a>, 27 } 28 29 impl<'a> RdbStore<'a> { 30 /// Creates a new `RdbStore`. open(config: OpenConfig) -> Result<Self, i32>31 pub fn open(config: OpenConfig) -> Result<Self, i32> { 32 let rdb = open_rdb_store(config)?; 33 if rdb.is_null() { 34 return Err(-1); 35 } 36 Ok(Self { 37 inner: RdbStoreInner::Shared(rdb), 38 }) 39 } 40 41 /// Creates a `RdbStore` from a C structure. from_ffi(ffi: Pin<&'a mut ffi::RdbStore>) -> Self42 pub fn from_ffi(ffi: Pin<&'a mut ffi::RdbStore>) -> Self { 43 Self { 44 inner: RdbStoreInner::Ref(ffi), 45 } 46 } 47 48 /// Executes a sql statement. execute<P: Params>(&self, sql: &str, values: P) -> Result<(), i32>49 pub fn execute<P: Params>(&self, sql: &str, values: P) -> Result<(), i32> { 50 match Execute(self.inner.pin_mut(), sql, values.into_values_object()) { 51 0 => Ok(()), 52 err => Err(err), 53 } 54 } 55 56 /// Queries results with a sql statement. query<T>(&self, sql: &str, values: impl Params) -> Result<QuerySet<T>, i32>57 pub fn query<T>(&self, sql: &str, values: impl Params) -> Result<QuerySet<T>, i32> { 58 let result = Query(self.inner.pin_mut(), sql, values.into_values_object()); 59 if result.is_null() { 60 return Err(-1); 61 } 62 let ptr = result.as_ref().unwrap() as *const ffi::ResultSet as *mut ffi::ResultSet; 63 64 let mut column_count = 0; 65 match unsafe { Pin::new_unchecked(ptr.as_mut().unwrap()).GetColumnCount(&mut column_count) } 66 { 67 0 => {} 68 err => return Err(err), 69 }; 70 Ok(QuerySet { 71 inner: result, 72 column_count, 73 phantom: std::marker::PhantomData, 74 }) 75 } 76 } 77 78 enum RdbStoreInner<'a> { 79 Shared(SharedPtr<ffi::RdbStore>), 80 Ref(Pin<&'a mut ffi::RdbStore>), 81 } 82 83 impl RdbStoreInner<'_> { pin_mut(&self) -> Pin<&mut ffi::RdbStore>84 fn pin_mut(&self) -> Pin<&mut ffi::RdbStore> { 85 match self { 86 Self::Shared(ffi) => { 87 let ptr = ffi.as_ref().unwrap() as *const ffi::RdbStore as *mut ffi::RdbStore; 88 unsafe { Pin::new_unchecked(ptr.as_mut().unwrap()) } 89 } 90 Self::Ref(ffi) => { 91 let ptr = ffi.as_ref().get_ref() as *const ffi::RdbStore as *mut ffi::RdbStore; 92 unsafe { Pin::new_unchecked(ptr.as_mut().unwrap()) } 93 } 94 } 95 } 96 } 97 98 /// Query results. 99 pub struct QuerySet<T> { 100 inner: SharedPtr<ffi::ResultSet>, 101 column_count: i32, 102 phantom: std::marker::PhantomData<T>, 103 } 104 105 impl<T> QuerySet<T> { 106 /// Gets the count of the rows in the query result. row_count(&mut self) -> i32107 pub fn row_count(&mut self) -> i32 { 108 let mut row_count = 0; 109 match self.pin_mut().GetRowCount(&mut row_count) { 110 0 => row_count, 111 _err => 0, 112 } 113 } 114 115 /// Gets the counts of the columns in the query result. column_count(&self) -> i32116 pub fn column_count(&self) -> i32 { 117 self.column_count 118 } 119 pin_mut(&mut self) -> Pin<&mut ffi::ResultSet>120 fn pin_mut(&mut self) -> Pin<&mut ffi::ResultSet> { 121 let ptr = self.inner.as_ref().unwrap() as *const ffi::ResultSet as *mut ffi::ResultSet; 122 unsafe { Pin::new_unchecked(ptr.as_mut().unwrap()) } 123 } 124 } 125 126 impl<T> Iterator for QuerySet<T> 127 where 128 T: FromSql, 129 { 130 type Item = T; 131 next(&mut self) -> Option<Self::Item>132 fn next(&mut self) -> Option<Self::Item> { 133 let mut row = NewRowEntity(); 134 if self.pin_mut().GoToNextRow() != E_OK { 135 return None; 136 }; 137 if self.pin_mut().GetRow(row.pin_mut()) != E_OK { 138 return None; 139 } 140 Some(T::from_sql(0, row.pin_mut())) 141 } 142 } 143 144 macro_rules! single_tuple_impl { 145 ($(($field:tt $ftype:ident)),* $(,)?) => { 146 impl <$($ftype,) *> Iterator for QuerySet<($($ftype,) *)> where $($ftype: FromSql,)* { 147 type Item = ($($ftype,) *); 148 fn next(&mut self) -> Option<Self::Item> { 149 let mut row = NewRowEntity(); 150 if self.pin_mut().GoToNextRow() != E_OK { 151 return None; 152 }; 153 if (self.pin_mut().GetRow(row.pin_mut()) != E_OK) { 154 return None; 155 } 156 Some(($({ 157 $ftype::from_sql($field,row.pin_mut()) 158 }), *)) 159 160 } 161 } 162 }; 163 } 164 165 single_tuple_impl!((0 A), (1 B)); 166 single_tuple_impl!((0 A), (1 B), (2 C)); 167 single_tuple_impl!((0 A), (1 B), (2 C), (3 D)); 168 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E)); 169 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F)); 170 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G)); 171 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H)); 172 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I)); 173 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J)); 174 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K)); 175 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L)); 176 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M)); 177 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M), (13 N)); 178 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M), (13 N), (14 O)); 179 single_tuple_impl!((0 A), (1 B), (2 C), (3 D), (4 E), (5 F), (6 G), (7 H), (8 I), (9 J), (10 K), (11 L), (12 M), (13 N), (14 O), (15 P)); 180 181 #[cfg(test)] 182 mod ut_database { 183 include!("../tests/ut/ut_database.rs"); 184 } 185