1#![doc = include_str!("../README.md")]
17
18use odpic_sys::*;
19use std::os::raw::c_char;
20use std::ptr;
21use std::result;
22use std::slice;
23
24#[cfg(feature = "aq_unstable")]
25pub mod aq;
26mod batch;
27#[allow(dead_code)]
28#[allow(non_camel_case_types)]
29#[allow(non_snake_case)]
30#[allow(improper_ctypes)]
31pub mod conn;
32mod connection;
33mod context;
34mod error;
35pub mod io;
36pub mod oci_attr;
37pub mod pool;
38#[cfg(doctest)]
39mod procmacro;
40mod row;
41pub mod sql_type;
42mod sql_value;
43mod statement;
44mod util;
45mod version;
46
47pub use crate::batch::Batch;
48pub use crate::batch::BatchBindIndex;
49pub use crate::batch::BatchBuilder;
50pub use crate::connection::ConnStatus;
51pub use crate::connection::Connection;
52pub use crate::connection::Connector;
53pub use crate::connection::Privilege;
54pub use crate::connection::ShutdownMode;
55pub use crate::connection::StartupMode;
56use crate::context::Context;
57pub use crate::context::InitParams;
58pub use crate::error::DbError;
59pub use crate::error::Error;
60pub use crate::error::ErrorKind;
61pub use crate::error::ParseOracleTypeError;
62pub use crate::row::ResultSet;
63pub use crate::row::Row;
64pub use crate::row::RowValue;
65pub use crate::sql_value::SqlValue;
66pub use crate::statement::BindIndex;
67pub use crate::statement::ColumnIndex;
68pub use crate::statement::ColumnInfo;
69pub use crate::statement::Statement;
70pub use crate::statement::StatementBuilder;
71pub use crate::statement::StatementType;
72pub use crate::version::Version;
73pub use oracle_procmacro::RowValue;
74
75pub type Result<T> = result::Result<T, Error>;
76
77macro_rules! define_dpi_data_with_refcount {
78 ($name:ident) => {
79 define_dpi_data_with_refcount!(__define_struct__, $name);
80 paste::item! {
81 unsafe impl Send for [<Dpi $name>] {}
82 unsafe impl Sync for [<Dpi $name>] {}
83 }
84 };
85
86 ($name:ident, nosync) => {
87 define_dpi_data_with_refcount!(__define_struct__, $name);
88 paste::item! {
89 unsafe impl Send for [<Dpi $name>] {}
90 }
91 };
92
93 (__define_struct__, $name:ident) => {
94 paste::item! {
95 #[derive(Debug)]
96 struct [<Dpi $name>] {
97 raw: *mut [<dpi $name>],
98 }
99
100 impl [<Dpi $name>] {
101 fn new(raw: *mut [<dpi $name>]) -> [<Dpi $name>] {
102 [<Dpi $name>] { raw }
103 }
104
105 #[allow(dead_code)]
106 fn with_add_ref(raw: *mut [<dpi $name>]) -> [<Dpi $name>] {
107 unsafe { [<dpi $name _addRef>](raw) };
108 [<Dpi $name>] { raw }
109 }
110
111 #[allow(dead_code)]
112 fn null() -> [<Dpi $name>] {
113 [<Dpi $name>] {
114 raw: ptr::null_mut(),
115 }
116 }
117
118 #[allow(dead_code)]
119 fn is_null(&self) -> bool {
120 self.raw.is_null()
121 }
122
123 pub(crate) fn raw(&self) -> *mut [<dpi $name>] {
124 self.raw
125 }
126 }
127
128 impl Clone for [<Dpi $name>] {
129 fn clone(&self) -> [<Dpi $name>] {
130 if !self.is_null() {
131 unsafe { [<dpi $name _addRef>](self.raw()) };
132 }
133 [<Dpi $name>]::new(self.raw())
134 }
135 }
136
137 impl Drop for [<Dpi $name>] {
138 fn drop(&mut self) {
139 if !self.is_null() {
140 unsafe { [<dpi $name _release>](self.raw()) };
141 }
142 }
143 }
144 }
145 };
146}
147
148define_dpi_data_with_refcount!(Conn);
150
151define_dpi_data_with_refcount!(MsgProps);
153
154define_dpi_data_with_refcount!(ObjectType);
156
157define_dpi_data_with_refcount!(Pool);
159
160define_dpi_data_with_refcount!(ObjectAttr);
162
163define_dpi_data_with_refcount!(Queue);
165
166define_dpi_data_with_refcount!(Object, nosync);
168
169define_dpi_data_with_refcount!(Stmt, nosync);
171
172struct DpiVar {
174 raw: *mut dpiVar,
175 data: *mut dpiData,
176}
177
178impl DpiVar {
179 fn new(raw: *mut dpiVar, data: *mut dpiData) -> DpiVar {
180 DpiVar { raw, data }
181 }
182
183 fn with_add_ref(raw: *mut dpiVar, data: *mut dpiData) -> DpiVar {
184 unsafe { dpiVar_addRef(raw) };
185 DpiVar::new(raw, data)
186 }
187
188 fn is_null(&self) -> bool {
189 self.raw.is_null()
190 }
191}
192
193impl Drop for DpiVar {
194 fn drop(&mut self) {
195 if !self.is_null() {
196 unsafe { dpiVar_release(self.raw) };
197 }
198 }
199}
200
201unsafe impl Send for DpiVar {}
202
203#[allow(dead_code)]
204trait AssertSend: Send {}
205#[allow(dead_code)]
206trait AssertSync: Sync {}
207
208struct OdpiStr {
213 pub ptr: *const c_char,
214 pub len: u32,
215}
216
217impl OdpiStr {
218 fn new<T>(s: T) -> OdpiStr
219 where
220 T: AsRef<[u8]>,
221 {
222 let s = s.as_ref();
223 if s.is_empty() {
224 OdpiStr {
225 ptr: ptr::null(),
226 len: 0,
227 }
228 } else {
229 OdpiStr {
230 ptr: s.as_ptr() as *const c_char,
231 len: s.len() as u32,
232 }
233 }
234 }
235
236 #[allow(clippy::inherent_to_string)]
237 pub fn to_string(&self) -> String {
238 to_rust_str(self.ptr, self.len)
239 }
240
241 #[cfg(feature = "aq_unstable")]
242 pub fn to_vec(&self) -> Vec<u8> {
243 if self.ptr.is_null() {
244 Vec::new()
245 } else {
246 let ptr = self.ptr as *mut u8;
247 let len = self.len as usize;
248 unsafe { Vec::from_raw_parts(ptr, len, len) }
249 }
250 }
251}
252
253fn to_rust_str(ptr: *const c_char, len: u32) -> String {
254 if ptr.is_null() {
255 "".to_string()
256 } else {
257 let s = unsafe { slice::from_raw_parts(ptr as *mut u8, len as usize) };
258 String::from_utf8_lossy(s).into_owned()
259 }
260}
261
262fn to_rust_slice<'a>(ptr: *const c_char, len: u32) -> &'a [u8] {
263 if ptr.is_null() {
264 &[]
265 } else {
266 unsafe { slice::from_raw_parts(ptr as *mut u8, len as usize) }
267 }
268}
269
270mod private {
271 use std::os::raw::c_void;
272
273 pub trait Sealed {}
274
275 impl Sealed for u8 {}
276 impl Sealed for u16 {}
277 impl Sealed for u32 {}
278 impl Sealed for u64 {}
279 impl Sealed for usize {}
280 impl Sealed for bool {}
281 impl Sealed for str {}
282 impl Sealed for [u8] {}
283 impl Sealed for *mut c_void {}
284 impl Sealed for &str {}
285}
286
287#[allow(dead_code)]
288#[doc(hidden)]
289pub mod test_util {
291 use super::*;
292 use std::env;
293
294 pub const VER11_2: Version = Version::new(11, 2, 0, 0, 0);
295 pub const VER12_1: Version = Version::new(12, 1, 0, 0, 0);
296 pub const VER18: Version = Version::new(18, 0, 0, 0, 0);
297
298 fn env_var_or(env_name: &str, default: &str) -> String {
299 match env::var_os(env_name) {
300 Some(env_var) => env_var.into_string().unwrap(),
301 None => String::from(default),
302 }
303 }
304
305 pub fn main_user() -> String {
306 env_var_or("ODPIC_TEST_MAIN_USER", "odpic")
307 }
308
309 pub fn main_password() -> String {
310 env_var_or("ODPIC_TEST_MAIN_PASSWORD", "welcome")
311 }
312
313 pub fn edition_user() -> String {
314 env_var_or("ODPIC_TEST_EDITION_USER", "odpic_edition")
315 }
316
317 pub fn edition_password() -> String {
318 env_var_or("ODPIC_TEST_EDITION_PASSWORD", "welcome")
319 }
320
321 pub fn connect_string() -> String {
322 env_var_or("ODPIC_TEST_CONNECT_STRING", "localhost/orclpdb")
323 }
324
325 pub fn connect() -> Result<Connection> {
326 Connection::connect(main_user(), main_password(), connect_string())
327 }
328
329 pub fn check_version(
330 conn: &Connection,
331 client_ver: &Version,
332 server_ver: &Version,
333 ) -> Result<bool> {
334 Ok(&Version::client()? >= client_ver && &conn.server_version()?.0 >= server_ver)
335 }
336}