Rust-oracle

Test Crates.io Docs Docs (in development)

This is an Oracle database driver for Rust based on ODPI-C.

Change Log

See ChangeLog.md.

Build-time Requirements

Run-time Requirements

Supported Rust Versions

The oracle crate supports at least 6 rust minor versions including the stable release at the time when the crate was released. The MSRV (minimum supported rust version) may be changed when a patch version is incremented though it will not be changed frequently. The current MSRV is 1.54.0.

Usage

Put this in your Cargo.toml:

text [dependencies] oracle = "0.5"

Optional Features

The following features can be enabled from Cargo.toml:

Feature | Description | available version ---|---|--- chrono | Implements [ToSql] and [FromSql] for [chrono] data types. | any stmt_without_lifetime | Removes conn lifetime from [Statement]. This is available to avoid lifetime conflicts. | since 0.5.6 aq_unstable | Enables Oracle Advanced Queuing support. This is unstable. It may be changed incompatibly by minor version upgrades. | since 0.5.5

Examples

Executes select statements and get rows:

```rust,no_run use oracle::{Connection, Error};

// Connect to a database. let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

let sql = "select ename, sal, comm from emp where deptno = :1";

// Select a table with a bind variable. println!("---------------|---------------|---------------|"); let rows = conn.query(sql, &[&30])?; for rowresult in rows { let row = rowresult?; // get a column value by position (0-based) let ename: String = row.get(0)?; // get a column by name (case-insensitive) let sal: i32 = row.get("sal")?; // Use Option<...> to get a nullable column. // Otherwise, Err(Error::NullValue) is returned // for null values. let comm: Option = row.get(2)?;

println!(" {:14}| {:>10}    | {:>10}    |",
         ename,
         sal,
         comm.map_or("".to_string(), |v| v.to_string()));

}

// Another way to fetch rows. // The rows iterator returns Result<(String, i32, Option)>. println!("---------------|---------------|---------------|"); let rows = conn.queryas::<(String, i32, Option)>(sql, &[&10])?; for rowresult in rows { let (ename, sal, comm) = rowresult?; println!(" {:14}| {:>10} | {:>10} |", ename, sal, comm.mapor("".tostring(), |v| v.tostring())); }

Ok::<(), oracle::Error>(())

```

Executes select statements and get the first rows:

```rust,no_run use oracle::Connection;

// Connect to a database. let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

let sql = "select ename, sal, comm from emp where empno = :1";

// Print the first row. let row = conn.queryrow(sql, &[&7369])?; let ename: String = row.get("empno")?; let sal: i32 = row.get("sal")?; let comm: Option = row.get("comm")?; println!("---------------|---------------|---------------|"); println!(" {:14}| {:>10} | {:>10} |", ename, sal, comm.mapor("".tostring(), |v| v.tostring())); // When no rows are found, conn.query_row() returns Err(Error::NoDataFound).

// Get the first row as a tupple let row = conn.queryrowas::<(String, i32, Option)>(sql, &[&7566])?; println!("---------------|---------------|---------------|"); println!(" {:14}| {:>10} | {:>10} |", row.0, row.1, row.2.mapor("".tostring(), |v| v.to_string()));

Ok::<(), oracle::Error>(())

```

Executes non-select statements:

```rust,no_run use oracle::Connection;

// Connect to a database. let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

conn.execute("create table person (id number(38), name varchar2(40))", &[])?;

// Execute a statement with positional parameters. conn.execute("insert into person values (:1, :2)", &[&1, // first parameter &"John" // second parameter ])?;

// Execute a statement with named parameters. conn.execute_named("insert into person values (:id, :name)", &[("id", &2), // 'id' parameter ("name", &"Smith"), // 'name' parameter ])?;

// Commit the transaction. conn.commit()?;

// Delete rows conn.execute("delete from person", &[])?;

// Rollback the transaction. conn.rollback()?;

Ok::<(), oracle::Error>(())

```

Prints column information:

```rust,no_run use oracle::Connection;

// Connect to a database. let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

let sql = "select ename, sal, comm from emp where 1 = 2"; let rows = conn.query(sql, &[])?;

// Print column names for info in rows.column_info() { print!(" {:14}|", info.name()); } println!("");

// Print column types for info in rows.columninfo() { print!(" {:14}|", info.oracletype().to_string()); } println!("");

Ok::<(), oracle::Error>(())

```

Prepared statement:

```rust,no_run use oracle::Connection;

let conn = Connection::connect("scott", "tiger", "//localhost/XE")?;

// Create a prepared statement let mut stmt = conn.statement("insert into person values (:1, :2)").build()?; // Insert one row stmt.execute(&[&1, &"John"])?; // Insert another row stmt.execute(&[&2, &"Smith"])?;

Ok::<(), oracle::Error>(())

```

This is more efficient than two conn.execute(). An SQL statement is executed in the DBMS as follows:

When a prepared statement is used, step 1 is called only once.

NLS_LANG parameter

NLS_LANG consists of three components: language, territory and charset. However the charset component is ignored and UTF-8(AL32UTF8) is used as charset because rust characters are UTF-8.

The territory component specifies numeric format, date format and so on. However it affects only conversion in Oracle. See the following example:

```rust,no_run use oracle::Connection;

// The territory is France. std::env::setvar("NLSLANG", "french_france.AL32UTF8"); let conn = Connection::connect("scott", "tiger", "")?;

// 10.1 is converted to a string in Oracle and fetched as a string. let result = conn.queryrowas::("select tochar(10.1) from dual", &[])?; asserteq!(result, "10,1"); // The decimal mark depends on the territory.

// 10.1 is fetched as a number and converted to a string in rust-oracle let result = conn.queryrowas::("select 10.1 from dual", &[])?; assert_eq!(result, "10.1"); // The decimal mark is always period(.).

Ok::<(), oracle::Error>(())

```

Note that NLS_LANG must be set before first rust-oracle function execution if required.

TODO

Related Projects

Other crates for connecting to Oracle: * [Sibyl]: an OCI-based interface supporting both blocking (threads) and nonblocking (async) API

Oracle-related crates: * [r2d2-oracle]: Oracle support for the [r2d2] connection pool * [bb8-oracle]: [bb8] connection pool support for oracle * [include-oracle-sql]: an extension of [include-sql] using [Sibyl] for database access

License

Rust-oracle and ODPI-C bundled in rust-oracle are under the terms of:

  1. the Universal Permissive License v 1.0 or at your option, any later version; and/or
  2. the Apache License v 2.0.