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
use odbc_sys::{HStmt, Handle, HandleType};
use crate::{
    handles::{drop_handle, AsHandle, AsStatementRef, Statement, StatementRef},
    Connection,
};
/// Statement handle which also takes ownership of Connection
pub struct StatementConnection<'env> {
    handle: HStmt,
    _parent: Connection<'env>,
}
impl<'env> StatementConnection<'env> {
    pub(crate) unsafe fn new(handle: HStmt, parent: Connection<'env>) -> Self {
        Self {
            _parent: parent,
            handle,
        }
    }
    pub fn as_stmt_ref(&mut self) -> StatementRef<'_> {
        unsafe { StatementRef::new(self.handle) }
    }
}
impl<'s> Drop for StatementConnection<'s> {
    fn drop(&mut self) {
        unsafe {
            drop_handle(self.handle as Handle, HandleType::Stmt);
        }
    }
}
/// According to the ODBC documentation this is safe. See: 
/// <https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/multithreading>
/// 
/// Operations to a statement imply that interior state of the connection might be mutated,
/// depending on the implementation detail of the ODBC driver. According to the ODBC documentation
/// this could always be considered save, since Connection handles are basically described as
/// `Sync`. Yet making connections `Send` could very well lead to different statements on different
/// threads actually changing the connection at the same time and truly relying on the thread safety
/// of the ODBC driver. I am sceptical. Especially if on Linux unixODBC would not be configured to
/// protect connections.
///
/// Note to users of `unixodbc`: You may configure the threading level to make unixodbc
/// synchronize access to the driver (and thereby making them thread safe if they are not thread
/// safe by themself. This may however hurt your performance if the driver would actually be able to
/// perform operations in parallel.
///
/// See: <https://stackoverflow.com/questions/4207458/using-unixodbc-in-a-multithreaded-concurrent-setting>
/// 
/// `StatementConnection` however also owns the connection exclusively. Since connections are `Send`
/// it is reasonable to assume this would work even if implementers of the ODBC driver do not care
/// in particular about thread safety.
unsafe impl<'c> Send for StatementConnection<'c> {}
unsafe impl AsHandle for StatementConnection<'_> {
    fn as_handle(&self) -> Handle {
        self.handle as Handle
    }
    fn handle_type(&self) -> HandleType {
        HandleType::Stmt
    }
}
impl Statement for StatementConnection<'_> {
    fn as_sys(&self) -> HStmt {
        self.handle
    }
}
impl<'o> AsStatementRef for StatementConnection<'o> {
    fn as_stmt_ref(&mut self) -> StatementRef<'_> {
        self.as_stmt_ref()
    }
}