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