Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ version = "0.4"
[dependencies.diesel]
default-features = false
features = ["with-deprecated", "unstable"]
version = "=1.4.2"
version = "=1.4.3"

[dependencies.oci-sys]
path = "oci-sys"
Expand All @@ -43,5 +43,5 @@ r2d2 = ["diesel/r2d2"]
default = ["chrono-time", "r2d2"]

[replace]
"diesel:1.4.2" = { git = "https://github.com/GiGainfosystems/diesel", rev = "83ef2f8346" }
"diesel_derives:1.4.0" = { git = "https://github.com/GiGainfosystems/diesel", rev = "83ef2f8346" }
"diesel:1.4.3" = { git = "https://github.com/GiGainfosystems/diesel", rev = "700171d1e607c6675d105fdaa02753e448d216fa" }
"diesel_derives:1.4.1" = { git = "https://github.com/GiGainfosystems/diesel", rev = "700171d1e607c6675d105fdaa02753e448d216fa" }
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nightly-2019-07-02
nightly-2019-11-16
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(re_rebalance_coherence, specialization)]
#![feature(specialization)]

#[macro_use]
extern crate diesel;
Expand Down
44 changes: 39 additions & 5 deletions src/oracle/backend.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use byteorder::NativeEndian;
use diesel::backend::UsesAnsiSavepointSyntax;
use diesel::backend::*;
use diesel::query_builder::bind_collector::RawBytesBindCollector;
Expand All @@ -15,8 +14,18 @@ pub struct Oracle;
impl Backend for Oracle {
type QueryBuilder = OciQueryBuilder;
type BindCollector = RawBytesBindCollector<Oracle>;
type RawValue = OracleValue;
type ByteOrder = NativeEndian;
}

impl<'a> HasRawValue<'a> for Oracle {
type RawValue = OracleValue<'a>;
}

impl<'a> BinaryRawValue<'a> for Oracle {
type ByteOrder = byteorder::NativeEndian;

fn as_bytes(value: Self::RawValue) -> &'a [u8] {
value.bytes
}
}

impl TypeMetadata for Oracle {
Expand All @@ -31,9 +40,34 @@ impl UsesAnsiSavepointSyntax for Oracle {}
impl SupportsReturningClause for Oracle {}

pub trait HasSqlTypeExt<ST>: HasSqlType<ST, MetadataLookup = ()> {
fn oci_row_metadata(out: &mut Vec<Self::TypeMetadata>) {
fn oci_row_metadata(out: &mut Vec<Self::TypeMetadata>);
}

impl<ST> HasSqlTypeExt<ST> for Oracle
where
Oracle: HasSqlType<ST>,
{
default fn oci_row_metadata(out: &mut Vec<Self::TypeMetadata>) {
out.push(Self::metadata(&()))
}
}

impl<ST> HasSqlTypeExt<ST> for Oracle where Oracle: HasSqlType<ST> {}
macro_rules! tuple_impls {
($(
$Tuple:tt {
$(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
}
)+) => {
$(
impl<$($T),+> HasSqlTypeExt<($($T,)+)> for Oracle
where $(Oracle: HasSqlTypeExt<$T>,)*
{
fn oci_row_metadata(out: &mut Vec<Self::TypeMetadata>) {
$(<Oracle as HasSqlTypeExt<$T>>::oci_row_metadata(out);)+
}
}
)*
};
}

__diesel_for_each_tuple!(tuple_impls);
27 changes: 0 additions & 27 deletions src/oracle/clause_impl.rs

This file was deleted.

7 changes: 7 additions & 0 deletions src/oracle/connection/create_migration_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare
begin
create_if_not_exists('CREATE TABLE "__DIESEL_SCHEMA_MIGRATIONS" (
"VERSION" VARCHAR2(50) PRIMARY KEY NOT NULL,
"RUN_ON" TIMESTAMP with time zone DEFAULT sysdate not null
)');
end;
39 changes: 14 additions & 25 deletions src/oracle/connection/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use diesel::result::Error::DeserializationError;
use diesel::result::QueryResult;
use diesel::sql_types::HasSqlType;
use oci_sys as ffi;
use std::collections::HashMap;
use std::marker::PhantomData;

use super::row::{NamedOciRow, OciRow};
Expand Down Expand Up @@ -40,6 +39,18 @@ impl Field {
pub fn is_null(&self) -> bool {
*self.null_indicator == -1
}

pub fn buffer(&self) -> &[u8] {
&self.buffer
}

pub fn name(&self) -> &str {
&self.name
}

pub fn datatype(&self) -> OciDataType {
self.typ
}
}

impl Drop for Field {
Expand Down Expand Up @@ -103,14 +114,7 @@ where
}

self.current_row += 1;
let null_indicators = self.results.iter().map(|r| r.is_null()).collect();
let mut row = OciRow::new(
self.results
.iter_mut()
.map(|r: &mut Field| &r.buffer[..])
.collect::<Vec<&[u8]>>(),
null_indicators,
);
let mut row = OciRow::new(&self.results);
let value = T::Row::build_from_row(&mut row)
.map(T::build)
.map_err(DeserializationError);
Expand All @@ -121,20 +125,13 @@ where
pub struct NamedCursor<'a> {
stmt: &'a Statement,
results: Vec<Field>,
lut: HashMap<String, usize>,
}

impl<'a> NamedCursor<'a> {
pub fn new(stmt: &'a Statement, binds: Vec<Field>) -> NamedCursor<'a> {
let lut = binds
.iter()
.enumerate()
.map(|(i, b)| (b.name.clone(), i))
.collect();
NamedCursor {
stmt,
results: binds,
lut,
}
}

Expand Down Expand Up @@ -164,15 +161,7 @@ impl<'a> NamedCursor<'a> {
break;
}
}
let null_indicators = self.results.iter().map(|r| r.is_null()).collect();
let row = NamedOciRow::new(
self.results
.iter_mut()
.map(|r: &mut Field| &r.buffer[..])
.collect::<Vec<&[u8]>>(),
null_indicators,
&self.lut,
);
let row = NamedOciRow::new(&self.results);

ret.push(T::build(&row).map_err(DeserializationError)?);
}
Expand Down
12 changes: 12 additions & 0 deletions src/oracle/connection/define_create_if_not_exists.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
create or replace procedure create_if_not_exists(input_sql varchar2)
as
begin
execute immediate input_sql;
exception
when others then
if sqlcode = -955 then
NULL;
else
raise;
end if;
end;
62 changes: 22 additions & 40 deletions src/oracle/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use diesel::sql_types::HasSqlType;
use self::cursor::{Cursor, NamedCursor};
use self::stmt::Statement;
use self::transaction::OCITransactionManager;
use super::backend::Oracle;
use super::backend::{HasSqlTypeExt, Oracle};
use diesel::RunQueryDsl;

mod oracle_value;
pub use self::oracle_value::OracleValue;
Expand All @@ -34,29 +35,10 @@ pub struct OciConnection {
}

impl MigrationConnection for OciConnection {
#[cfg(ka)]
const CREATE_MIGRATIONS_FUNCTION: &'static str =
"create or replace procedure create_if_not_exists(input_sql varchar2) \
as \
begin \
execute immediate input_sql; \
exception \
when others then \
if sqlcode = -955 then \
NULL; \
else \
raise; \
end if; \
end; \n ";

const CREATE_MIGRATIONS_TABLE: &'static str = "
declare \
begin \
create_if_not_exists('CREATE TABLE \"__DIESEL_SCHEMA_MIGRATIONS\" (\
\"VERSION\" VARCHAR2(50) PRIMARY KEY NOT NULL,\
\"RUN_ON\" TIMESTAMP with time zone DEFAULT sysdate not null\
)'); \
end; \n";
fn setup(&self) -> QueryResult<usize> {
diesel::sql_query(include_str!("define_create_if_not_exists.sql")).execute(self)?;
diesel::sql_query(include_str!("create_migration_table.sql")).execute(self)
}
}

// This relies on the invariant that RawConnection or Statement are never
Expand All @@ -67,8 +49,8 @@ unsafe impl Send for OciConnection {}

impl SimpleConnection for OciConnection {
fn batch_execute(&self, query: &str) -> QueryResult<()> {
let mut stmt = try!(Statement::prepare(&self.raw, query));
try!(stmt.run(self.auto_commit(), &[]));
let mut stmt = Statement::prepare(&self.raw, query)?;
stmt.run(self.auto_commit(), &[])?;
stmt.bind_index = 0;
Ok(())
}
Expand All @@ -82,7 +64,7 @@ impl Connection for OciConnection {
/// should be a valid connection string for a given backend. See the
/// documentation for the specific backend for specifics.
fn establish(database_url: &str) -> ConnectionResult<Self> {
let r = try!(raw::RawConnection::establish(database_url));
let r = raw::RawConnection::establish(database_url)?;
let ret = OciConnection {
raw: Rc::new(r),
transaction_manager: OCITransactionManager::new(),
Expand All @@ -103,10 +85,10 @@ impl Connection for OciConnection {

#[doc(hidden)]
fn execute(&self, query: &str) -> QueryResult<usize> {
let mut stmt = try!(Statement::prepare(&self.raw, query));
try!(stmt.run(self.auto_commit(), &[]));
let mut stmt = Statement::prepare(&self.raw, query)?;
stmt.run(self.auto_commit(), &[])?;
stmt.bind_index = 0;
Ok(try!(stmt.get_affected_rows()))
Ok(stmt.get_affected_rows()?)
}

#[doc(hidden)]
Expand All @@ -115,10 +97,10 @@ impl Connection for OciConnection {
T: QueryFragment<Self::Backend> + QueryId,
{
// TODO: FIXME: this always returns 0 whereas the code looks proper
let mut stmt = try!(self.prepare_query(source));
try!(stmt.run(self.auto_commit(), &[]));
let mut stmt = self.prepare_query(source)?;
stmt.run(self.auto_commit(), &[])?;
stmt.bind_index = 0;
Ok(try!(stmt.get_affected_rows()))
Ok(stmt.get_affected_rows()?)
}

fn transaction_manager(&self) -> &Self::TransactionManager {
Expand All @@ -134,9 +116,7 @@ impl Connection for OciConnection {
{
let mut stmt = self.prepare_query(&source.as_query())?;
let mut metadata = Vec::new();
// TODO: FIXME: Georg will check if this can get un-deprecated.
#[allow(deprecated)]
Oracle::row_metadata(&mut metadata, &());
Oracle::oci_row_metadata(&mut metadata);
let cursor: Cursor<T::SqlType, U> = stmt.run_with_cursor(self.auto_commit(), metadata)?;
cursor.collect()
}
Expand All @@ -159,14 +139,14 @@ impl OciConnection {
&self,
source: &T,
) -> QueryResult<MaybeCached<Statement>> {
let mut statement = try!(self.cached_prepared_statement(source));
let mut statement = self.cached_prepared_statement(source)?;

let mut bind_collector = RawBytesBindCollector::<Oracle>::new();
try!(source.collect_binds(&mut bind_collector, &()));
source.collect_binds(&mut bind_collector, &())?;
let metadata = bind_collector.metadata;
let binds = bind_collector.binds;
for (tpe, value) in metadata.into_iter().zip(binds) {
try!(statement.bind(tpe, value));
statement.bind(tpe, value)?;
}

Ok(statement)
Expand Down Expand Up @@ -200,5 +180,7 @@ use diesel::r2d2::R2D2Connection;

#[cfg(feature = "r2d2")]
impl R2D2Connection for OciConnection {
const CHECK_QUERY_STRING: &'static str = "SELECT 1 FROM DUAL";
fn ping(&self) -> QueryResult<()> {
self.execute("SELECT 1 FROM DUAL").map(|_| ())
}
}
17 changes: 12 additions & 5 deletions src/oracle/connection/oracle_value.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
use oracle::types::OciDataType;

#[derive(Debug)]
pub struct OracleValue {
pub(crate) bytes: [u8],
pub struct OracleValue<'a> {
pub(crate) bytes: &'a [u8],
tpe: OciDataType,
}

impl OracleValue {
pub fn new(bytes: &[u8]) -> &Self {
unsafe { &*(bytes as *const [u8] as *const Self) }
impl<'a> OracleValue<'a> {
pub fn new(bytes: &'a [u8], tpe: OciDataType) -> Self {
Self { bytes, tpe }
}

pub fn datatype(&self) -> OciDataType {
self.tpe
}
}
Loading