odbc_api/
statement_connection.rs

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()
    }
}