odbc_safe/
environment.rs

1use super::*;
2use sys::*;
3use std::marker::PhantomData;
4use version::VersionOption;
5
6/// An `Environment` is a global context, in which to access data.
7///
8/// Associated with an `Environment` is any information that is global in nature, such as:
9///
10/// * The `Environment`'s state
11/// * The current environment-level diagnostics
12/// * The handles of connections currently allocated on the environment
13/// * The current stetting of each environment attribute
14///
15/// See: [Environment Handles in the ODBC Reference][1]
16/// [1]: https://docs.microsoft.com/sql/odbc/reference/develop-app/environment-handles
17#[derive(Debug)]
18pub struct Environment<V: VersionOption> {
19    version: PhantomData<V>,
20    /// Invariant: Should always point to a valid ODBC Environment with Version declared as V or
21    /// `NoVersion`
22    handle: HEnv,
23}
24
25impl<V: VersionOption> Environment<V> {
26    /// Provides access to the raw ODBC environment handle.
27    pub fn as_raw(&self) -> SQLHENV {
28        self.handle.as_raw()
29    }
30
31    /// Express state transiton
32    fn transit<Other: VersionOption>(self) -> Environment<Other> {
33        Environment {
34            version: PhantomData,
35            handle: self.handle,
36        }
37    }
38}
39
40impl<V: Version> Environment<V> {
41    /// Used by `Connection`s constructor
42    pub(crate) fn as_henv(&self) -> &HEnv {
43        &self.handle
44    }
45
46    /// Fills buffers with information about the available datasources
47    ///
48    /// A 32 / 64 Bit Application will only return information about either 32 or 64 Bit
49    /// DataSources.
50    ///
51    /// # Returns
52    ///
53    /// (server_name_length, description_length)
54    ///
55    /// See [SQLDataSources][1]
56    /// [1]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqldatasources-function
57    pub fn data_sources(
58        &mut self,
59        direction: FetchOrientation,
60        server_name: &mut [u8],
61        description: &mut [u8],
62    ) -> ReturnOption<(SQLSMALLINT, SQLSMALLINT)> {
63        self.handle.data_sources(
64            direction,
65            server_name,
66            description,
67        )
68    }
69
70    /// Fills buffers with information about the available datasources
71    ///
72    /// A 32 / 64 Bit Application will only return information about either 32 or 64 Bit
73    /// DataSources.
74    ///
75    /// # Returns
76    ///
77    /// (description_length, attributes_length)
78    ///
79    /// See [SQLDrivers][1]
80    /// [1]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqldrivers-function
81    pub fn drivers(
82        &mut self,
83        direction: FetchOrientation,
84        description: &mut [u8],
85        attributes: &mut [u8],
86    ) -> ReturnOption<(SQLSMALLINT, SQLSMALLINT)> {
87        self.handle.drivers(direction, description, attributes)
88    }
89}
90
91impl Environment<NoVersion> {
92    /// Allocates a new `Environment`
93    pub fn new() -> Return<Self> {
94        HEnv::allocate().map(|handle| {
95            Environment {
96                version: PhantomData,
97                handle: handle,
98            }
99        })
100    }
101
102    /// Before an application allocates a connection which specification it follows. Currently
103    /// these bindings only support ODBC 3.x.
104    ///
105    /// It is valid to specify ODBC 3.x even then connecting to an ODBC 2.x driver. Applications
106    /// must however avoid calling 3.x functionality on 2.x drivers. Since drivers are connected at
107    /// runtime, these kind of errors can not be catched by the type system.
108    pub fn declare_version<V: Version>(mut self) -> Return<Environment<V>, Environment<NoVersion>> {
109        let result = self.handle.declare_version(V::constant());
110        match result {
111            Success(()) => Success(self.transit()),
112            Info(()) => Success(self.transit()),
113            Error(()) => Success(self.transit()),
114        }
115    }
116
117    /// Before an application allocates a connection which specification it follows. Currently
118    /// these bindings only support ODBC 3.x.
119    ///
120    /// It is valid to specify ODBC 3.x even then connecting to an ODBC 2.x driver. Applications
121    /// must however avoid calling 3.x functionality on 2.x drivers. Since drivers are connected at
122    /// runtime, these kind of errors can not be catched by the type system.
123    ///
124    /// This method is a shorthand for `declare_version::<Odbc3m8>`.
125    pub fn declare_version_3_8(self) -> Return<Environment<Odbc3m8>, Environment<NoVersion>> {
126        self.declare_version()
127    }
128
129    /// Before an application allocates a connection which specification it follows. Currently
130    /// these bindings only support ODBC 3.x.
131    ///
132    /// It is valid to specify ODBC 3.x even then connecting to an ODBC 2.x driver. Applications
133    /// must however avoid calling 3.x functionality on 2.x drivers. Since drivers are connected at
134    /// runtime, these kind of errors can not be catched by the type system.
135    ///
136    /// This method is a shorthand for `declare_version::<Odbc3>`.
137    pub fn declare_version_3(self) -> Return<Environment<Odbc3>, Environment<NoVersion>> {
138        self.declare_version()
139    }
140}
141
142impl<V: VersionOption> Diagnostics for Environment<V> {
143    fn diagnostics(
144        &self,
145        rec_number: SQLSMALLINT,
146        message_text: &mut [SQLCHAR],
147    ) -> ReturnOption<DiagResult> {
148        self.handle.diagnostics(rec_number, message_text)
149    }
150}