1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
// Rust-oracle - Rust binding for Oracle database
//
// URL: https://github.com/kubo/rust-oracle
//
//-----------------------------------------------------------------------------
// Copyright (c) 2017-2021 Kubo Takehiro <kubo@jiubao.org>. All rights reserved.
// This program is free software: you can modify it and/or redistribute it
// under the terms of:
//
// (i) the Universal Permissive License v 1.0 or at your option, any
// later version (http://oss.oracle.com/licenses/upl); and/or
//
// (ii) the Apache License v 2.0. (http://www.apache.org/licenses/LICENSE-2.0)
//-----------------------------------------------------------------------------
//! Rust-oracle is based on ODPI-C using Oracle Call Interface (OCI) internally.
//! OCI treats resources as handles, which have various attributes documented [here].
//!
//! The module defines type parameters to access some OCI attributes and
//! the trait [`OciAttr`] to define your own type parameters to access attributes
//! which are not predefined in this module.
//!
//! [here]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-CB59C987-07E7-42D4-ADDF-96142CBD3D11
use crate::oci_attr::data_type::{DataType, DurationUsecU64, MaxStringSize};
#[cfg(any(doc, test))]
use crate::oci_attr::handle::Server;
use crate::oci_attr::handle::{HandleType, Session, Stmt, SvcCtx};
#[cfg(any(doc, test))]
use crate::oci_attr::mode::Write;
use crate::oci_attr::mode::{Mode, Read, ReadWrite};
#[cfg(doc)]
use crate::Connection;
#[cfg(doc)]
use std::time::Duration;
pub mod data_type;
pub mod handle;
pub mod mode;
pub unsafe trait OciAttr {
/// [`SvcCtx`], [`Session`], [`Server`] or [`Stmt`].
/// Other handle and descriptor types are unsupported.
type HandleType: HandleType;
/// [`Read`], [`Write`] or [`ReadWrite`]
type Mode: Mode;
/// Attribute data type
///
/// The following table is the mapping between basic data types. If
/// incorrect types are specified, the behavior is undefined.
///
/// Types in Oracle manual | Rust type
/// ---|---
/// `ub1*`/`ub1` | [`u8`]
/// `ub2*`/`ub2` | [`u16`]
/// `ub4*`/`ub4` | [`u32`]
/// `ub8*`/`ub8` | [`u64`]
/// `boolean*`/`boolean` | [`bool`]
/// pointer types such as `OCISession**`/`OCISession*` | `*mut c_void`
/// `oratext**`/`oratext*` | [`str`] [^str]
/// `ub1*`(with length; value is copied; is really a ub1 array) | `[u8]` [^u8slice]
///
/// The following table is the mapping of predefined types based on basic data types.
/// They are designed for specific attributes.
///
/// Types in Oracle manual | Rust type
/// ---|---
/// `ub8*` | [`DurationUsecU64`] which gets u64 values representing microsecods as [`Duration`]
/// `ub1*` | [`MaxStringSize`] which gets ub1 values as variants of [`MaxStringSize`]
///
/// Look at the source code of [`DurationUsecU64`] and [`MaxStringSize`] as samples
/// when you need to implement your own data types.
///
/// [^str]: Values are got as [`String`] because [`str`] implements [`ToOwned`] whose associate type `Owned` is [`String`].
///
/// [^u8slice]: Values are got as `Vec<u8>` because `[T]` where T: Clone implements [`ToOwned`] whose associate type `Owned` is `Vec<T>`.
///
type DataType: DataType + ?Sized;
/// Attribute number defined in `oci.h` included in Oracle Instant Client SDK
const ATTR_NUM: u32;
}
/// A type parameter for [`Connection::oci_attr`] to get [`OCI_ATTR_VARTYPE_MAXLEN_COMPAT`] as [`MaxStringSize`].
/// which controls the maximum size of `VARCHAR2`, `NVARCHAR` and `RAW`.
///
/// This corresponds to the result of the following SQL statement when
/// a database user has a privilege to access `v$parameter`.
///
/// ```sql
/// select value from v$parameter where name = 'max_string_size'
/// ```
///
/// [`OCI_ATTR_VARTYPE_MAXLEN_COMPAT`]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-D8EE68EB-7E38-4068-B06E-DF5686379E5E__GUID-2EFB39BC-6131-4EAD-BBF6-7CA8E5F2BBF4
#[derive(Debug)]
pub struct VarTypeMaxLenCompat;
const OCI_ATTR_VARTYPE_MAXLEN_COMPAT: u32 = 489;
unsafe impl OciAttr for VarTypeMaxLenCompat {
type HandleType = SvcCtx;
type Mode = Read;
type DataType = MaxStringSize;
const ATTR_NUM: u32 = OCI_ATTR_VARTYPE_MAXLEN_COMPAT;
}
/// A type parameter for [`Connection::oci_attr`] to get [`OCI_ATTR_CALL_TIME`] as [`Duration`][],
/// which is the server-side time for the preceding call
///
/// Set `true` to [`CollectCallTime`] in advance.
///
/// # Examples
///
/// ```
/// # use oracle::Error;
/// # use oracle::test_util;
/// use oracle::oci_attr::CallTime;
/// use oracle::oci_attr::CollectCallTime;
/// use std::time::Duration;
/// # let mut conn = test_util::connect()?;
/// # if !test_util::check_version(&conn, &test_util::VER11_2, &test_util::VER18)? {
/// # return Ok(());
/// # }
///
/// // Enable CollectCallTime
/// conn.set_oci_attr::<CollectCallTime>(&true)?;
///
/// // This SQL consumes one second in the server-side.
/// conn.execute("begin dbms_session.sleep(1); end;", &[])?;
/// let call_time = conn.oci_attr::<CallTime>()?;
/// assert!(call_time >= Duration::from_secs(1), "call_time is {:?}.", call_time);
/// # Ok::<(), Error>(())
/// ```
///
/// [`OCI_ATTR_CALL_TIME`]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-FB263210-118E-4DB3-A840-1769EF0CB977__GUID-AA22FE4F-8942-4819-B01F-068DCEAE9B72
/// [`Duration`]: std::time::Duration
pub struct CallTime;
const OCI_ATTR_CALL_TIME: u32 = 370;
unsafe impl OciAttr for CallTime {
type HandleType = Session;
type Mode = Read;
type DataType = DurationUsecU64;
const ATTR_NUM: u32 = OCI_ATTR_CALL_TIME;
}
/// A type parameter for [`Connection::oci_attr`] and [`Connection::set_oci_attr`] to get and set [`OCI_ATTR_COLLECT_CALL_TIME`],
/// which causes the server to measure call time for each subsequent OCI call
///
/// See [`CallTime`].
///
/// [`OCI_ATTR_COLLECT_CALL_TIME`]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-FB263210-118E-4DB3-A840-1769EF0CB977__GUID-D4B6CBB6-5627-474C-ABE6-F2CE694DE62B
pub struct CollectCallTime;
const OCI_ATTR_COLLECT_CALL_TIME: u32 = 369;
unsafe impl OciAttr for CollectCallTime {
type HandleType = Session;
type Mode = ReadWrite;
type DataType = bool;
const ATTR_NUM: u32 = OCI_ATTR_COLLECT_CALL_TIME;
}
/// A type parameter for [`Connection::oci_attr`] and [`Connection::set_oci_attr`] to get and set [`OCI_ATTR_DEFAULT_LOBPREFETCH_SIZE`],
/// which specifies the default prefetch buffer size for each LOB locator
///
/// # Examples
///
/// ```
/// # use oracle::Error;
/// # use oracle::test_util;
/// # use oracle::sql_type::Clob;
/// use oracle::oci_attr::DefaultLobPrefetchSize;
/// # let mut conn = test_util::connect()?;
///
/// let lob_size = 64 * 1024;
/// conn.set_oci_attr::<DefaultLobPrefetchSize>(&lob_size)?;
///
/// # conn.execute("insert into TestCLOBs values (1, '11111111111111111111111111111')", &[])?;
/// let mut stmt = conn
/// .statement("select CLOBCol from TestCLOBs where IntCol = :1")
/// .lob_locator()
/// .build()?;
/// let lob = stmt.query_row_as::<Clob>(&[&1])?;
/// # Ok::<(), Error>(())
/// ```
///
/// [`OCI_ATTR_DEFAULT_LOBPREFETCH_SIZE`]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-FB263210-118E-4DB3-A840-1769EF0CB977__GUID-13400E7D-C1E9-49AB-AD9B-132CBF11E16C
pub struct DefaultLobPrefetchSize;
const OCI_ATTR_DEFAULT_LOBPREFETCH_SIZE: u32 = 438;
unsafe impl OciAttr for DefaultLobPrefetchSize {
type HandleType = Session;
type Mode = ReadWrite;
type DataType = u32;
const ATTR_NUM: u32 = OCI_ATTR_DEFAULT_LOBPREFETCH_SIZE;
}
/// A type parameter for [`Connection::oci_attr`] to get [`OCI_ATTR_MAX_OPEN_CURSORS`],
/// which is the maximum number of SQL statements that can be opened in one session
///
/// This returns the same value with the result of the following SQL statement when
/// a database user has a privilege to access `v$parameter`.
///
/// ```sql
/// select value from v$parameter where name = 'open_cursors'
/// ```
///
/// Note that this attribute returns a proper value only when connected to a 12.1 server or later.
///
/// [`OCI_ATTR_MAX_OPEN_CURSORS`]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-FB263210-118E-4DB3-A840-1769EF0CB977__GUID-0F30D36A-E9E5-4CDB-BF53-C2C876C09E00
pub struct MaxOpenCursors;
const OCI_ATTR_MAX_OPEN_CURSORS: u32 = 471;
unsafe impl OciAttr for MaxOpenCursors {
type HandleType = Session;
type Mode = Read;
type DataType = u32;
const ATTR_NUM: u32 = OCI_ATTR_MAX_OPEN_CURSORS;
}
/// A type parameter for [`Connection::oci_attr`] to get [`OCI_ATTR_TRANSACTION_IN_PROGRESS`] as `bool`,
/// which indicates whether the connection has a currently active transaction.
///
/// Note that this requires Oracle client 12.1 or later.
///
/// # Examples
///
/// ```
/// # use oracle::Error;
/// # use oracle::Version;
/// # use oracle::test_util;
/// use oracle::oci_attr::TransactionInProgress;
/// # if Version::client()? < test_util::VER12_1 {
/// # return Ok(());
/// # }
/// # let mut conn = test_util::connect()?;
/// # conn.execute("drop table test_sql_fn_code purge", &[]);
///
/// // no active transaction at first
/// assert_eq!(conn.oci_attr::<TransactionInProgress>()?, false);
///
/// // start a transaction
/// conn.execute("insert into TestTempTable values (1, 'val1')", &[])?;
/// assert_eq!(conn.oci_attr::<TransactionInProgress>()?, true);
///
/// // rollback the transction
/// conn.rollback()?;
/// assert_eq!(conn.oci_attr::<TransactionInProgress>()?, false);
/// # Ok::<(), Error>(())
/// ```
/// [`OCI_ATTR_TRANSACTION_IN_PROGRESS`]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-FB263210-118E-4DB3-A840-1769EF0CB977__GUID-BCECC9A1-5B02-428F-8A1D-20C9A7997AE5
pub struct TransactionInProgress;
const OCI_ATTR_TRANSACTION_IN_PROGRESS: u32 = 484;
unsafe impl OciAttr for TransactionInProgress {
type HandleType = Session;
type Mode = Read;
type DataType = bool;
const ATTR_NUM: u32 = OCI_ATTR_TRANSACTION_IN_PROGRESS;
}
/// A type parameter for [`Statement::oci_attr`] to get [`OCI_ATTR_SQLFNCODE`],
/// which is the function code of the SQL command associated with the statement.
///
/// Note that the attribute must be read after the statement is executed.
///
/// # Examples
///
/// ```
/// # use oracle::Error;
/// # use oracle::test_util;
/// use oracle::oci_attr::SqlFnCode;
/// # use std::thread::sleep;
/// # use std::time::Duration;
/// # let mut conn = test_util::connect()?;
///
/// let stmt = conn.execute("insert into TestNumbers values(11, 12, 13, 14, 15)", &[])?;
/// assert_eq!(stmt.oci_attr::<SqlFnCode>()?, 3);
///
/// let stmt = conn.execute("update TestNumbers set NumberCol = 13 where IntCol = 11", &[])?;
/// assert_eq!(stmt.oci_attr::<SqlFnCode>()?, 5);
///
/// let stmt = conn.execute("delete TestNumbers where IntCol = 11", &[])?;
/// assert_eq!(stmt.oci_attr::<SqlFnCode>()?, 9);
///
/// # conn.rollback()?;
/// # Ok::<(), Error>(())
/// ```
///
/// [`Statement::oci_attr`]: crate::Statement::oci_attr
/// [`OCI_ATTR_SQLFNCODE`]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-A251CF91-EB9F-4DBC-8BB8-FB5EA92C20DE__GUID-9E3D8A93-DF13-4023-8444-3F06131D26FB
pub struct SqlFnCode;
const OCI_ATTR_SQLFNCODE: u32 = 10;
unsafe impl OciAttr for SqlFnCode {
type HandleType = Stmt;
type Mode = Read;
type DataType = u16;
const ATTR_NUM: u32 = OCI_ATTR_SQLFNCODE;
}
/// A type parameter for [`Statement::oci_attr`] to get [`OCI_ATTR_STATEMENT`],
/// which is the text of the SQL statement prepared.
///
/// # Examples
///
/// ```
/// # use oracle::Error;
/// # use oracle::test_util;
/// use oracle::oci_attr::Statement;
/// # let mut conn = test_util::connect()?;
///
/// let mut stmt = conn.statement("select * from dual").build()?;
/// assert_eq!(stmt.oci_attr::<Statement>()?, "select * from dual");
/// # Ok::<(), Error>(())
/// ```
///
/// [`Statement::oci_attr`]: crate::Statement::oci_attr
/// [`OCI_ATTR_STATEMENT`]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-A251CF91-EB9F-4DBC-8BB8-FB5EA92C20DE__GUID-30B1693F-EFC7-4108-8F06-0EC1DC3785FB
pub struct Statement;
const OCI_ATTR_STATEMENT: u32 = 144;
unsafe impl OciAttr for Statement {
type HandleType = Stmt;
type Mode = Read;
type DataType = str;
const ATTR_NUM: u32 = OCI_ATTR_STATEMENT;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util;
use crate::Result;
struct StmtCacheSize;
unsafe impl OciAttr for StmtCacheSize {
type HandleType = SvcCtx;
type Mode = ReadWrite;
type DataType = u32;
const ATTR_NUM: u32 = 176;
}
struct InternalName;
unsafe impl OciAttr for InternalName {
type HandleType = Server;
type Mode = ReadWrite;
type DataType = str;
const ATTR_NUM: u32 = 25;
}
struct Module;
unsafe impl OciAttr for Module {
type HandleType = Session;
type Mode = Write;
type DataType = str;
const ATTR_NUM: u32 = 366;
}
#[test]
fn read_write_svcctx_u32_attr() -> Result<()> {
let mut conn = test_util::connect()?;
let size = conn.stmt_cache_size()?;
assert_eq!(conn.oci_attr::<StmtCacheSize>()?, size);
let new_size = size + 20;
conn.set_oci_attr::<StmtCacheSize>(&new_size)?;
assert_eq!(conn.oci_attr::<StmtCacheSize>()?, new_size);
Ok(())
}
#[test]
fn read_write_server_str_attr() -> Result<()> {
let mut conn = test_util::connect()?;
conn.set_oci_attr::<InternalName>("test internal name")?;
assert_eq!(conn.oci_attr::<InternalName>()?, "test internal name");
Ok(())
}
#[test]
fn write_session_str_attr() -> Result<()> {
let mut conn = test_util::connect()?;
conn.set_oci_attr::<Module>("test module name")?;
let module =
conn.query_row_as::<String>("select sys_context('USERENV', 'MODULE') from dual", &[])?;
assert_eq!(module, "test module name");
Ok(())
}
}