Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re rebalance coherence #25

Merged
merged 6 commits into from
Jan 17, 2019
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
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ chrono-time = ["chrono", "diesel/chrono"]
default = ["chrono-time"]

[replace]
"diesel:1.3.3" = { git = "https://github.com/GiGainfosystems/diesel", rev = "0d6a5d419" }
"diesel_derives:1.3.0" = { git = "https://github.com/GiGainfosystems/diesel", rev = "0d6a5d419" }
"diesel:1.3.3" = { git = "https://github.com/GiGainfosystems/diesel", rev = "9abf3addf001330" }
"diesel_derives:1.3.0" = { git = "https://github.com/GiGainfosystems/diesel", rev = "9abf3addf001330" }

36 changes: 24 additions & 12 deletions oci-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4679,8 +4679,10 @@ extern "C" {
svc: *const OCISvcCtx,
context: *mut ::std::os::raw::c_void,
get: ::std::option::Option<
unsafe extern "C" fn(context: *mut ::std::os::raw::c_void, last: *mut ub1)
-> *mut OCIRef,
unsafe extern "C" fn(
context: *mut ::std::os::raw::c_void,
last: *mut ub1,
) -> *mut OCIRef,
>,
ref_: *mut *mut OCIRef,
) -> sword;
Expand Down Expand Up @@ -4809,8 +4811,10 @@ extern "C" {
svc: *const OCISvcCtx,
context: *mut ::std::os::raw::c_void,
get: ::std::option::Option<
unsafe extern "C" fn(context: *mut ::std::os::raw::c_void, last: *mut ub1)
-> *mut OCIRef,
unsafe extern "C" fn(
context: *mut ::std::os::raw::c_void,
last: *mut ub1,
) -> *mut OCIRef,
>,
ref_: *mut *mut OCIRef,
) -> sword;
Expand Down Expand Up @@ -14446,8 +14450,10 @@ extern "C" {
mode: ub4,
ctxp: *mut ::std::os::raw::c_void,
malocfp: ::std::option::Option<
unsafe extern "C" fn(ctxp: *mut ::std::os::raw::c_void, size: usize)
-> *mut ::std::os::raw::c_void,
unsafe extern "C" fn(
ctxp: *mut ::std::os::raw::c_void,
size: usize,
) -> *mut ::std::os::raw::c_void,
>,
ralocfp: ::std::option::Option<
unsafe extern "C" fn(
Expand All @@ -14473,8 +14479,10 @@ extern "C" {
mode: ub4,
ctxp: *mut ::std::os::raw::c_void,
malocfp: ::std::option::Option<
unsafe extern "C" fn(ctxp: *mut ::std::os::raw::c_void, size: usize)
-> *mut ::std::os::raw::c_void,
unsafe extern "C" fn(
ctxp: *mut ::std::os::raw::c_void,
size: usize,
) -> *mut ::std::os::raw::c_void,
>,
ralocfp: ::std::option::Option<
unsafe extern "C" fn(
Expand All @@ -14499,8 +14507,10 @@ extern "C" {
mode: ub4,
ctxp: *mut ::std::os::raw::c_void,
malocfp: ::std::option::Option<
unsafe extern "C" fn(ctxp: *mut ::std::os::raw::c_void, size: usize)
-> *mut ::std::os::raw::c_void,
unsafe extern "C" fn(
ctxp: *mut ::std::os::raw::c_void,
size: usize,
) -> *mut ::std::os::raw::c_void,
>,
ralocfp: ::std::option::Option<
unsafe extern "C" fn(
Expand All @@ -14527,8 +14537,10 @@ extern "C" {
mode: ub4,
ctxp: *mut ::std::os::raw::c_void,
malocfp: ::std::option::Option<
unsafe extern "C" fn(ctxp: *mut ::std::os::raw::c_void, size: usize)
-> *mut ::std::os::raw::c_void,
unsafe extern "C" fn(
ctxp: *mut ::std::os::raw::c_void,
size: usize,
) -> *mut ::std::os::raw::c_void,
>,
ralocfp: ::std::option::Option<
unsafe extern "C" fn(
Expand Down
1 change: 1 addition & 0 deletions rust-toolchain
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nightly-2019-01-07
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do this w/o updating GST (as of now) or does this probably have invocations for GST as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to bump rustc for GST as well because everything needs to be build with the same compiler version. We don't need to use this specific nightly, any new one should also work. (To be more concrete: We should not use this one, because it contains no working rls build…)

2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![feature(re_rebalance_coherence, specialization)]

#[macro_use]
extern crate diesel;
extern crate byteorder;
Expand Down
2 changes: 1 addition & 1 deletion src/oracle/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl TypeMetadata for Oracle {
impl UsesAnsiSavepointSyntax for Oracle {}

// TODO: check if Oracle supports this
impl SupportsDefaultKeyword for Oracle {}
//impl SupportsDefaultKeyword for Oracle {}
impl SupportsReturningClause for Oracle {}

pub trait HasSqlTypeExt<ST>: HasSqlType<ST, MetadataLookup = ()> {
Expand Down
38 changes: 15 additions & 23 deletions src/oracle/connection/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,15 @@ const NUM_ELEMENTS: usize = 40;

impl Statement {
pub fn prepare(raw_connection: &Rc<RawConnection>, sql: &str) -> QueryResult<Self> {
let mut mysql = sql.to_string();
// TODO: this can go wrong: `UPDATE table SET k='LIMIT';`
if let Some(pos) = mysql.find("LIMIT") {
let mut limit_clause = mysql.split_off(pos);
let place_holder = limit_clause.split_off(String::from("LIMIT ").len());
mysql = mysql + &format!("OFFSET 0 ROWS FETCH NEXT {} ROWS ONLY", place_holder);
}
// TODO: this is bad, things will break
let is_returning =
(sql.starts_with("INSERT") || sql.starts_with("insert")) && sql.contains("RETURNING");
debug!("SQL Statement {}", mysql);
debug!("SQL Statement {}", sql);
let stmt = unsafe {
let mut stmt: *mut ffi::OCIStmt = ptr::null_mut();
let status = ffi::OCIStmtPrepare2(
raw_connection.service_handle,
&mut stmt,
raw_connection.env.error_handle,
mysql.as_ptr(),
mysql.len() as u32,
sql.as_ptr(),
sql.len() as u32,
ptr::null(),
0,
ffi::OCI_NTV_SYNTAX,
Expand All @@ -55,21 +45,21 @@ impl Statement {
Self::check_error_sql(
raw_connection.env.error_handle,
status,
&mysql,
&sql,
"PREPARING STMT",
)?;

// for create statements we need to run OCIStmtPrepare2 twice
// c.f. https://docs.oracle.com/database/121/LNOCI/oci17msc001.htm#LNOCI17165
// "To reexecute a DDL statement, you must prepare the statement again using OCIStmtPrepare2()."
if let Some(u) = mysql.to_string().find("CREATE") {
if let Some(u) = sql.find("CREATE") {
if u < 10 {
let status = ffi::OCIStmtPrepare2(
raw_connection.service_handle,
&mut stmt,
raw_connection.env.error_handle,
mysql.as_ptr(),
mysql.len() as u32,
sql.as_ptr(),
sql.len() as u32,
ptr::null(),
0,
ffi::OCI_NTV_SYNTAX,
Expand All @@ -79,12 +69,12 @@ impl Statement {
Self::check_error_sql(
raw_connection.env.error_handle,
status,
&mysql,
&sql,
"PREPARING STMT 2",
)?;
}
}
debug!("Executing {:?}", mysql);
debug!("Executing {:?}", sql);
stmt
};
Ok(Statement {
Expand All @@ -110,11 +100,12 @@ impl Statement {
// INNER JOIN geo_points w ON bbox.w = w.id
// ```
is_select: sql.starts_with("SELECT") || sql.starts_with("select"),
is_returning,
is_returning: (sql.starts_with("INSERT") || sql.starts_with("insert"))
&& sql.contains("RETURNING"),
buffers: Vec::with_capacity(NUM_ELEMENTS),
sizes: Vec::with_capacity(NUM_ELEMENTS),
indicators: Vec::with_capacity(NUM_ELEMENTS),
mysql,
mysql: sql.to_owned(),
returning_contexts: Vec::new(),
})
}
Expand Down Expand Up @@ -168,7 +159,7 @@ impl Statement {
pub fn check_error_sql(
error_handle: *mut ffi::OCIError,
status: i32,
sql: &String,
sql: &str,
action: &str,
) -> Result<(), Error> {
let check = Self::check_error(error_handle, status);
Expand Down Expand Up @@ -550,7 +541,8 @@ impl Drop for Statement {
status,
&self.mysql,
"DROPPING STMT",
).err()
)
.err()
{
debug!("{:?}", err);
}
Expand Down
120 changes: 81 additions & 39 deletions src/oracle/insertable.rs
Original file line number Diff line number Diff line change
@@ -1,56 +1,35 @@
#![feature(specialization)]

// This fails to compile since we cannot specialize QueryFragement here, but we would need to this
// since Oracle demands a different syntax for batch inserts, ala `insert into t(a,b) select (1,2)
// from dual union all select (4,5) from dual`
// once https://github.com/rust-lang/rfcs/pull/2451 has been accepted and
// implemented in Rust (or diesel changed something else) we can go forward with this
// otherwise we would need to implement an own SQL parser

// error[E0119]: conflicting implementations of trait `diesel::query_builder::QueryFragment<oracle::backend::Oracle>` for type `diesel::insertable::BatchInsert<'_, _, _>`:
// --> src/oracle/insertable.rs:21:1
// |
//21 | / impl<'a, T, Tab, Inner> QueryFragment<Oracle> for BatchInsert<'a, T, Tab>
//22 | | where
//23 | | &'a T: Insertable<Tab, Values = ValuesClause<Inner, Tab>>,
//24 | | ValuesClause<Inner, Tab>: QueryFragment<Oracle>,
//... |
//38 | | }
//39 | | }
// | |_^
// |
// = note: conflicting implementation in crate `diesel`:
// - impl<'a, T, Tab, Inner, DB> diesel::query_builder::QueryFragment<DB> for diesel::insertable::BatchInsert<'a, T, Tab>
// where <&'a T as diesel::Insertable<Tab>>::Values == diesel::query_builder::ValuesClause<Inner, Tab>, DB: diesel::backend::Backend, DB: diesel::backend::SupportsDefaultKeyword, &'a T: diesel::Insertable<Tab>, diesel::query_builder::ValuesClause<Inner, Tab>: diesel::query_builder::QueryFragment<DB>, Inner: diesel::query_builder::QueryFragment<DB>;

use diesel::expression::{AppearsOnTable, Expression};
use diesel::insertable::{
BatchInsert, CanInsertInSingleQuery, ColumnInsertValue, InsertValues, Insertable,
OwnedBatchInsert,
};
use diesel::query_builder::AstPass;
use diesel::query_builder::QueryFragment;
use diesel::query_builder::ValuesClause;

use diesel::backend::Backend;
use diesel::insertable::InsertValues;
use diesel::query_builder::insert_statement::DefaultValues;
use diesel::query_builder::AstPass;
use diesel::query_source::Table;
use diesel::query_source::Column;
use diesel::result::QueryResult;

use diesel::backend::SupportsDefaultKeyword;
use diesel::insertable::BatchInsert;
use diesel::insertable::Insertable;
use diesel::query_builder::insert_statement::InsertStatement;
use diesel::query_dsl::methods::ExecuteDsl;
use diesel::Table;

use super::backend::Oracle;

// please refer to https://stackoverflow.com/questions/39576/best-way-to-do-multi-row-insert-in-oracle

impl<'a, T, Tab, Inner> QueryFragment<Oracle> for BatchInsert<'a, T, Tab>
where
&'a T: Insertable<Tab, Values = ValuesClause<Inner, Tab>>,
ValuesClause<Inner, Tab>: QueryFragment<Oracle>,
Inner: QueryFragment<Oracle>,
Inner: QueryFragment<Oracle> + InsertValues<Tab, Oracle>,
Tab: Table,
{
fn walk_ast(&self, mut out: AstPass<Oracle>) -> QueryResult<()> {
let mut records = self.records.iter().map(Insertable::values);
if let Some(record) = records.next() {
record.walk_ast(out.reborrow())?;
out.push_sql("(");
record.values.column_names(out.reborrow())?;
out.push_sql(") ");
out.push_sql("select ");
record.values.walk_ast(out.reborrow())?;
out.push_sql(" from dual");
}
for record in records {
out.push_sql(" union all select ");
Expand All @@ -60,3 +39,66 @@ where
Ok(())
}
}

impl<Tab, Inner> QueryFragment<Oracle> for OwnedBatchInsert<ValuesClause<Inner, Tab>>
where
ValuesClause<Inner, Tab>: QueryFragment<Oracle>,
Inner: QueryFragment<Oracle> + InsertValues<Tab, Oracle>,
Tab: Table,
{
fn walk_ast(&self, mut out: AstPass<Oracle>) -> QueryResult<()> {
let mut records = self.values.iter();
if let Some(record) = records.next() {
out.push_sql("(");
record.values.column_names(out.reborrow())?;
out.push_sql(") ");
out.push_sql("select ");
record.values.walk_ast(out.reborrow())?;
out.push_sql(" from dual");
}
for record in records {
out.push_sql(" union all select ");
record.values.walk_ast(out.reborrow())?;
out.push_sql(" from dual");
}
Ok(())
}
}

impl<'a, T, Tab> CanInsertInSingleQuery<Oracle> for BatchInsert<'a, T, Tab> {
fn rows_to_insert(&self) -> Option<usize> {
Some(self.records.len())
}
}

impl<T> CanInsertInSingleQuery<Oracle> for OwnedBatchInsert<T> {
fn rows_to_insert(&self) -> Option<usize> {
Some(self.values.len())
}
}

impl<Col, Expr> QueryFragment<Oracle> for ColumnInsertValue<Col, Expr>
where
Expr: QueryFragment<Oracle>,
{
fn walk_ast(&self, mut out: AstPass<Oracle>) -> QueryResult<()> {
if let ColumnInsertValue::Expression(_, ref value) = *self {
value.walk_ast(out.reborrow())?;
} else {
out.push_sql("DEFAULT");
}
Ok(())
}
}

impl<Col, Expr> InsertValues<Col::Table, Oracle> for ColumnInsertValue<Col, Expr>
where
Col: Column,
Expr: Expression<SqlType = Col::SqlType> + AppearsOnTable<()>,
Self: QueryFragment<Oracle>,
{
fn column_names(&self, mut out: AstPass<Oracle>) -> QueryResult<()> {
out.push_identifier(Col::NAME)?;
Ok(())
}
}
1 change: 1 addition & 0 deletions src/oracle/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod backend;
pub mod connection;
pub mod insertable;
pub mod query_builder;
pub mod query_dsl;
pub mod types;
Loading