Skip to main content

odbc_api/
connection.rs

1use crate::{
2    BlockCursorIterator, ColumnsRow, CursorImpl, CursorPolling, Error, ForeignKeysRow, OwnedCursor,
3    ParameterCollectionRef, Preallocated, Prepared, PrimaryKeysRow, Sleep, TablesRow,
4    buffers::BufferDesc,
5    execute::execute_with_parameters_polling,
6    handles::{
7        self, SqlText, State, Statement, StatementConnection, StatementImpl, StatementParent,
8        slice_to_utf8,
9    },
10};
11use log::error;
12use std::{
13    borrow::Cow,
14    fmt::{self, Debug, Display},
15    mem::{ManuallyDrop, MaybeUninit},
16    ptr, str,
17    sync::Arc,
18    thread::panicking,
19};
20
21impl Drop for Connection<'_> {
22    fn drop(&mut self) {
23        match self.connection.disconnect().into_result(&self.connection) {
24            Ok(()) => (),
25            Err(Error::Diagnostics {
26                record,
27                function: _,
28            }) if record.state == State::INVALID_STATE_TRANSACTION => {
29                // Invalid transaction state. Let's rollback the current transaction and try again.
30                if let Err(e) = self.rollback() {
31                    // Connection might be in a suspended state. See documentation about suspended
32                    // state here:
33                    // <https://learn.microsoft.com/sql/odbc/reference/syntax/sqlendtran-function>
34                    //
35                    // See also issue:
36                    // <https://github.com/pacman82/odbc-api/issues/574#issuecomment-2286449125>
37
38                    #[cfg(not(feature = "structured_logging"))]
39                    error!(
40                        "Error rolling back transaction (in order to recover from invalid \
41                        transaction state during disconnect): {e}"
42                    );
43                    #[cfg(feature = "structured_logging")]
44                    error!(
45                        target: "odbc_api",
46                        error:err = e;
47                        "Failed rollback on disconnect"
48                    );
49                }
50                // Transaction might be rolled back or suspended. Now let's try again to disconnect.
51                if let Err(e) = self.connection.disconnect().into_result(&self.connection) {
52                    // Avoid panicking, if we already have a panic. We don't want to mask the
53                    // original error.
54                    if !panicking() {
55                        panic!("Unexpected error disconnecting (after rollback attempt): {e:?}")
56                    }
57                }
58            }
59            Err(e) => {
60                // Avoid panicking, if we already have a panic. We don't want to mask the original
61                // error.
62                if !panicking() {
63                    panic!("Unexpected error disconnecting: {e:?}")
64                }
65            }
66        }
67    }
68}
69
70/// The connection handle references storage of all information about the connection to the data
71/// source, including status, transaction state, and error information.
72///
73/// If you want to enable the connection pooling support build into the ODBC driver manager have a
74/// look at [`crate::Environment::set_connection_pooling`].
75///
76/// In order to create multiple statements with the same connection and for other use cases,
77/// operations like [`Self::execute`] or [`Self::prepare`] are taking a shared reference of `self`
78/// rather than `&mut self`. However, since error handling is done through state changes of the
79/// underlying connection managed by the ODBC driver, this implies that `Connection` must not be
80/// `Sync`.
81pub struct Connection<'c> {
82    connection: handles::Connection<'c>,
83}
84
85impl<'c> Connection<'c> {
86    pub(crate) fn new(connection: handles::Connection<'c>) -> Self {
87        Self { connection }
88    }
89
90    /// Transfer ownership of this open connection to a wrapper around the raw ODBC pointer. The
91    /// wrapper allows you to call ODBC functions on the handle, but doesn't care if the connection
92    /// is in the right state.
93    ///
94    /// You should not have a need to call this method if your use case is covered by this library,
95    /// but, in case it is not, this may help you to break out of the type structure which might be
96    /// to rigid for you, while simultaneously abondoning its safeguards.
97    pub fn into_handle(self) -> handles::Connection<'c> {
98        // We do not want the compiler to invoke `Drop`, since drop would disconnect, yet we want to
99        // transfer ownership to the connection handle.
100        let dont_drop_me = MaybeUninit::new(self);
101        let self_ptr = dont_drop_me.as_ptr();
102
103        // Safety: We know `dont_drop_me` is (still) valid at this point so reading the ptr is okay
104        unsafe { ptr::read(&(*self_ptr).connection) }
105    }
106
107    /// Executes an SQL statement. This is the fastest way to submit an SQL statement for one-time
108    /// execution. In case you do **not** want to execute more statements on this connection, you
109    /// may want to use [`Self::into_cursor`] instead, which would create a cursor taking ownership
110    /// of the connection.
111    ///
112    /// # Parameters
113    ///
114    /// * `query`: The text representation of the SQL statement. E.g. "SELECT * FROM my_table;".
115    /// * `params`: `?` may be used as a placeholder in the statement text. You can use `()` to
116    ///   represent no parameters. See the [`crate::parameter`] module level documentation for more
117    ///   information on how to pass parameters.
118    /// * `query_timeout_sec`: Use this to limit the time the query is allowed to take, before
119    ///   responding with data to the application. The driver may replace the number of seconds you
120    ///   provide with a minimum or maximum value.
121    ///
122    ///   For the timeout to work the driver must support this feature. E.g. PostgreSQL, and
123    ///   Microsoft SQL Server do, but SQLite or MariaDB do not.
124    ///
125    ///   You can specify ``0``, to deactivate the timeout, this is the default. So if you want no
126    ///   timeout, just leave it at `None`. Only reason to specify ``0`` is if for some reason your
127    ///   datasource does not have ``0`` as default.
128    ///
129    ///   This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
130    ///
131    ///   See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetstmtattr-function>
132    ///
133    /// # Return
134    ///
135    /// Returns `Some` if a cursor is created. If `None` is returned no cursor has been created (
136    /// e.g. the query came back empty). Note that an empty query may also create a cursor with zero
137    /// rows.
138    ///
139    /// # Example
140    ///
141    /// ```no_run
142    /// use odbc_api::{Environment, ConnectionOptions};
143    ///
144    /// let env = Environment::new()?;
145    ///
146    /// let mut conn = env.connect(
147    ///     "YourDatabase", "SA", "My@Test@Password1",
148    ///     ConnectionOptions::default()
149    /// )?;
150    /// // This query does not use any parameters.
151    /// let query_params = ();
152    /// let timeout_sec = None;
153    /// if let Some(cursor) = conn.execute(
154    ///     "SELECT year, name FROM Birthdays;",
155    ///     query_params,
156    ///     timeout_sec)?
157    /// {
158    ///     // Use cursor to process query results.
159    /// }
160    /// # Ok::<(), odbc_api::Error>(())
161    /// ```
162    pub fn execute(
163        &self,
164        query: &str,
165        params: impl ParameterCollectionRef,
166        query_timeout_sec: Option<usize>,
167    ) -> Result<Option<CursorImpl<StatementImpl<'_>>>, Error> {
168        // Only allocate the statement, if we know we are going to execute something.
169        if params.parameter_set_size() == 0 {
170            return Ok(None);
171        }
172        let mut statement = self.preallocate()?;
173        if let Some(seconds) = query_timeout_sec {
174            statement.set_query_timeout_sec(seconds)?;
175        }
176        statement.into_cursor(query, params)
177    }
178
179    /// Executes an SQL statement asynchronously using polling mode. ⚠️**Attention**⚠️: Please read
180    /// [Asynchronous execution using polling
181    /// mode](crate::guide#asynchronous-execution-using-polling-mode) before using this
182    /// functions.
183    ///
184    /// Asynchronous sibling of [`Self::execute`]. Each time the driver returns control to your
185    /// application the future returned by `sleep` is awaited, before the driver is polled again.
186    /// This avoids a busy loop. `sleep` is a synchronous factor for a future which is awaited.
187    /// `sleep` should not be implemented using a sleep which blocks the system thread, but rather
188    /// use methods provided by your asynchronous runtime. E.g.:
189    ///
190    /// ```
191    /// use odbc_api::{Connection, IntoParameter, Error};
192    /// use std::time::Duration;
193    ///
194    /// async fn insert_post<'a>(
195    ///     connection: &'a Connection<'a>,
196    ///     user: &str,
197    ///     post: &str,
198    /// ) -> Result<(), Error> {
199    ///     // Poll every 50 ms.
200    ///     let sleep = || tokio::time::sleep(Duration::from_millis(50));
201    ///     let sql = "INSERT INTO POSTS (user, post) VALUES (?, ?)";
202    ///     // Execute query using ODBC polling method
203    ///     let params = (&user.into_parameter(), &post.into_parameter());
204    ///     connection.execute_polling(&sql, params, sleep).await?;
205    ///     Ok(())
206    /// }
207    /// ```
208    ///
209    /// **Attention**: This feature requires driver support, otherwise the calls will just block
210    /// until they are finished. At the time of writing this out of Microsoft SQL Server,
211    /// PostgerSQL, SQLite and MariaDB this worked only with Microsoft SQL Server. For code generic
212    /// over every driver you may still use this. The functions will return with the correct results
213    /// just be aware that may block until they are finished.
214    ///
215    /// This uses the ODBC polling mode under the hood. See:
216    /// <https://learn.microsoft.com/sql/odbc/reference/develop-app/asynchronous-execution-polling-method>
217    pub async fn execute_polling(
218        &self,
219        query: &str,
220        params: impl ParameterCollectionRef,
221        sleep: impl Sleep,
222    ) -> Result<Option<CursorPolling<StatementImpl<'_>>>, Error> {
223        // Only allocate the statement, if we know we are going to execute something.
224        if params.parameter_set_size() == 0 {
225            return Ok(None);
226        }
227        let query = SqlText::new(query);
228        let mut statement = self.allocate_statement()?;
229        statement.set_async_enable(true).into_result(&statement)?;
230        execute_with_parameters_polling(statement, Some(&query), params, sleep).await
231    }
232
233    /// Similar to [`Self::execute`], but takes ownership of the connection. This is useful if e.g.
234    /// youwant to open a connection and execute a query in a function and return a self containing
235    /// cursor.
236    ///
237    /// # Parameters
238    ///
239    /// * `query`: The text representation of the SQL statement. E.g. "SELECT * FROM my_table;".
240    /// * `params`: `?` may be used as a placeholder in the statement text. You can use `()` to
241    ///   represent no parameters. See the [`crate::parameter`] module level documentation for more
242    ///   information on how to pass parameters.
243    /// * `query_timeout_sec`: Use this to limit the time the query is allowed to take, before
244    ///   responding with data to the application. The driver may replace the number of seconds you
245    ///   provide with a minimum or maximum value.
246    ///
247    ///   For the timeout to work the driver must support this feature. E.g. PostgreSQL, and
248    ///   Microsoft SQL Server do, but SQLite or MariaDB do not.
249    ///
250    ///   You can specify ``0``, to deactivate the timeout, this is the default. So if you want no
251    ///   timeout, just leave it at `None`. Only reason to specify ``0`` is if for some reason your
252    ///   datasource does not have ``0`` as default.
253    ///
254    ///   This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
255    ///
256    ///   See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetstmtattr-function>
257    ///
258    /// ```no_run
259    /// use odbc_api::{environment, Error, Cursor, ConnectionOptions};
260    ///
261    ///
262    /// const CONNECTION_STRING: &str =
263    ///     "Driver={ODBC Driver 18 for SQL Server};\
264    ///     Server=localhost;UID=SA;\
265    ///     PWD=My@Test@Password1;";
266    ///
267    /// fn execute_query(query: &str) -> Result<Option<impl Cursor>, Error> {
268    ///     let env = environment()?;
269    ///     let conn = env.connect_with_connection_string(
270    ///         CONNECTION_STRING,
271    ///         ConnectionOptions::default()
272    ///     )?;
273    ///
274    ///     // connect.execute(&query, (), None) // Compiler error: Would return local ref to
275    ///                                          // `conn`.
276    ///
277    ///     let maybe_cursor = conn.into_cursor(&query, (), None)?;
278    ///     Ok(maybe_cursor)
279    /// }
280    /// ```
281    pub fn into_cursor(
282        self,
283        query: &str,
284        params: impl ParameterCollectionRef,
285        query_timeout_sec: Option<usize>,
286    ) -> Result<Option<OwnedCursor<Connection<'c>>>, ConnectionAndError<'c>> {
287        // With the current Rust version the borrow checker needs some convincing, so that it allows
288        // us to return the Connection, even though the Result of execute borrows it.
289        let mut error = None;
290        let mut cursor = None;
291        match self.execute(query, params, query_timeout_sec) {
292            Ok(Some(c)) => cursor = Some(c),
293            Ok(None) => return Ok(None),
294            Err(e) => error = Some(e),
295        };
296        if let Some(e) = error {
297            drop(cursor);
298            return Err(ConnectionAndError {
299                error: e,
300                previous: self,
301            });
302        }
303        let cursor = cursor.unwrap();
304        // The rust compiler needs some help here. It assumes otherwise that the lifetime of the
305        // resulting cursor would depend on the lifetime of `params`.
306        let mut cursor = ManuallyDrop::new(cursor);
307        let handle = cursor.as_sys();
308        // Safe: `handle` is a valid statement, and we are giving up ownership of `self`.
309        let statement = unsafe { StatementConnection::new(handle, self) };
310        // Safe: `statement is in the cursor state`.
311        let cursor = unsafe { CursorImpl::new(statement) };
312        Ok(Some(cursor))
313    }
314
315    /// Prepares an SQL statement. This is recommended for repeated execution of similar queries.
316    ///
317    /// Should your use case require you to execute the same query several times with different
318    /// parameters, prepared queries are the way to go. These give the database a chance to cache
319    /// the access plan associated with your SQL statement. It is not unlike compiling your program
320    /// once and executing it several times.
321    ///
322    /// ```
323    /// use odbc_api::{Connection, Error, IntoParameter};
324    /// use std::io::{self, stdin, Read};
325    ///
326    /// fn interactive(conn: &Connection) -> io::Result<()>{
327    ///     let mut prepared = conn.prepare("SELECT * FROM Movies WHERE title=?;").unwrap();
328    ///     let mut title = String::new();
329    ///     stdin().read_line(&mut title)?;
330    ///     while !title.is_empty() {
331    ///         match prepared.execute(&title.as_str().into_parameter()) {
332    ///             Err(e) => println!("{}", e),
333    ///             // Most drivers would return a result set even if no Movie with the title is found,
334    ///             // the result set would just be empty. Well, most drivers.
335    ///             Ok(None) => println!("No result set generated."),
336    ///             Ok(Some(cursor)) => {
337    ///                 // ...print cursor contents...
338    ///             }
339    ///         }
340    ///         stdin().read_line(&mut title)?;
341    ///     }
342    ///     Ok(())
343    /// }
344    /// ```
345    ///
346    /// # Parameters
347    ///
348    /// * `query`: The text representation of the SQL statement. E.g. "SELECT * FROM my_table;". `?`
349    ///   may be used as a placeholder in the statement text, to be replaced with parameters during
350    ///   execution.
351    pub fn prepare(&self, query: &str) -> Result<Prepared<StatementImpl<'_>>, Error> {
352        let query = SqlText::new(query);
353        let mut stmt = self.allocate_statement()?;
354        stmt.prepare(&query).into_result(&stmt)?;
355        Ok(Prepared::new(stmt))
356    }
357
358    /// Prepares an SQL statement which takes ownership of the connection. The advantage over
359    /// [`Self::prepare`] is, that you do not need to keep track of the lifetime of the connection
360    /// seperatly and can create types which do own the prepared query and only depend on the
361    /// lifetime of the environment. The downside is that you can not use the connection for
362    /// anything else anymore.
363    ///
364    /// # Parameters
365    ///
366    /// * `query`: The text representation of the SQL statement. E.g. "SELECT * FROM my_table;". `?`
367    ///   may be used as a placeholder in the statement text, to be replaced with parameters during
368    ///   execution.
369    ///
370    /// ```no_run
371    /// use odbc_api::{
372    ///     environment, Error, ColumnarBulkInserter, handles::StatementConnection, BindParamDesc,
373    ///     buffers::BoxColumnBuffer, ConnectionOptions, Connection, parameter::WithDataType,
374    /// };
375    ///
376    /// const CONNECTION_STRING: &str =
377    ///     "Driver={ODBC Driver 18 for SQL Server};\
378    ///     Server=localhost;UID=SA;\
379    ///     PWD=My@Test@Password1;";
380    ///
381    /// /// Supports columnar bulk inserts on a heterogenous schema (columns have different types),
382    /// /// takes ownership of a connection created using an environment with static lifetime.
383    /// type Inserter = ColumnarBulkInserter<
384    ///     StatementConnection<Connection<'static>>,
385    ///     WithDataType<BoxColumnBuffer>
386    /// >;
387    ///
388    /// /// Creates an inserter which can be reused to bulk insert birthyears with static lifetime.
389    /// fn make_inserter(query: &str) -> Result<Inserter, Error> {
390    ///     let env = environment()?;
391    ///     let conn = env.connect_with_connection_string(
392    ///         CONNECTION_STRING,
393    ///         ConnectionOptions::default()
394    ///     )?;
395    ///     let prepared = conn.into_prepared("INSERT INTO Birthyear (name, year) VALUES (?, ?)")?;
396    ///     let params = [
397    ///         BindParamDesc::text(255),
398    ///         BindParamDesc::i16(false),
399    ///     ];
400    ///     let capacity = 400;
401    ///     prepared.into_column_inserter(capacity, params)
402    /// }
403    /// ```
404    pub fn into_prepared(
405        self,
406        query: &str,
407    ) -> Result<Prepared<StatementConnection<Connection<'c>>>, Error> {
408        let query = SqlText::new(query);
409        let mut stmt = self.allocate_statement()?;
410        stmt.prepare(&query).into_result(&stmt)?;
411        // Safe: `handle` is a valid statement, and we are giving up ownership of `self`.
412        let stmt = unsafe { StatementConnection::new(stmt.into_sys(), self) };
413        Ok(Prepared::new(stmt))
414    }
415
416    /// Allocates an SQL statement handle. This is recommended if you want to sequentially execute
417    /// different queries over the same connection, as you avoid the overhead of allocating a
418    /// statement handle for each query.
419    ///
420    /// Should you want to repeatedly execute the same query with different parameters try
421    /// [`Self::prepare`] instead.
422    ///
423    /// # Example
424    ///
425    /// ```
426    /// use odbc_api::{Connection, Error};
427    /// use std::io::{self, stdin, Read};
428    ///
429    /// fn interactive(conn: &Connection) -> io::Result<()>{
430    ///     let mut statement = conn.preallocate().unwrap();
431    ///     let mut query = String::new();
432    ///     stdin().read_line(&mut query)?;
433    ///     while !query.is_empty() {
434    ///         match statement.execute(&query, ()) {
435    ///             Err(e) => println!("{}", e),
436    ///             Ok(None) => println!("No results set generated."),
437    ///             Ok(Some(cursor)) => {
438    ///                 // ...print cursor contents...
439    ///             },
440    ///         }
441    ///         stdin().read_line(&mut query)?;
442    ///     }
443    ///     Ok(())
444    /// }
445    /// ```
446    pub fn preallocate(&self) -> Result<Preallocated<StatementImpl<'_>>, Error> {
447        let stmt = self.allocate_statement()?;
448        unsafe { Ok(Preallocated::new(stmt)) }
449    }
450
451    /// Creates a preallocated statement handle like [`Self::preallocate`]. Yet the statement handle
452    /// also takes ownership of the connection.
453    pub fn into_preallocated(
454        self,
455    ) -> Result<Preallocated<StatementConnection<Connection<'c>>>, Error> {
456        let stmt = self.allocate_statement()?;
457        // Safe: We know `stmt` is a valid statement handle and self is the connection which has
458        // been used to allocate it.
459        unsafe {
460            let stmt = StatementConnection::new(stmt.into_sys(), self);
461            Ok(Preallocated::new(stmt))
462        }
463    }
464
465    /// Specify the transaction mode. By default, ODBC transactions are in auto-commit mode.
466    /// Switching from manual-commit mode to auto-commit mode automatically commits any open
467    /// transaction on the connection. There is no open or begin transaction method. Each statement
468    /// execution automatically starts a new transaction or adds to the existing one.
469    ///
470    /// In manual commit mode you can use [`Connection::commit`] or [`Connection::rollback`]. Keep
471    /// in mind, that even `SELECT` statements can open new transactions. This library will rollback
472    /// open transactions if a connection goes out of SCOPE. This however will log an error, since
473    /// the transaction state is only discovered during a failed disconnect. It is preferable that
474    /// the application makes sure all transactions are closed if in manual commit mode.
475    pub fn set_autocommit(&self, enabled: bool) -> Result<(), Error> {
476        self.connection
477            .set_autocommit(enabled)
478            .into_result(&self.connection)
479    }
480
481    /// To commit a transaction in manual-commit mode.
482    pub fn commit(&self) -> Result<(), Error> {
483        self.connection.commit().into_result(&self.connection)
484    }
485
486    /// To rollback a transaction in manual-commit mode.
487    pub fn rollback(&self) -> Result<(), Error> {
488        self.connection.rollback().into_result(&self.connection)
489    }
490
491    /// Indicates the state of the connection. If `true` the connection has been lost. If `false`,
492    /// the connection is still active.
493    pub fn is_dead(&self) -> Result<bool, Error> {
494        self.connection.is_dead().into_result(&self.connection)
495    }
496
497    /// Network packet size in bytes. Requries driver support.
498    pub fn packet_size(&self) -> Result<u32, Error> {
499        self.connection.packet_size().into_result(&self.connection)
500    }
501
502    /// Get the name of the database management system used by the connection.
503    pub fn database_management_system_name(&self) -> Result<String, Error> {
504        let mut buf = Vec::new();
505        self.connection
506            .fetch_database_management_system_name(&mut buf)
507            .into_result(&self.connection)?;
508        let name = slice_to_utf8(&buf).unwrap();
509        Ok(name)
510    }
511
512    /// The character used to quote identifiers (a.k.a. delimited identifiers).
513    ///
514    /// Drivers which confrom to SQL 92 standard will always return `Some('"')`.
515    pub fn identifier_quote_char(&self) -> Result<Option<char>, Error> {
516        self.connection
517            .identifier_quote_char()
518            .into_result(&self.connection)
519    }
520
521    /// Maximum length of catalog names.
522    pub fn max_catalog_name_len(&self) -> Result<u16, Error> {
523        self.connection
524            .max_catalog_name_len()
525            .into_result(&self.connection)
526    }
527
528    /// Maximum length of schema names.
529    pub fn max_schema_name_len(&self) -> Result<u16, Error> {
530        self.connection
531            .max_schema_name_len()
532            .into_result(&self.connection)
533    }
534
535    /// Maximum length of table names.
536    pub fn max_table_name_len(&self) -> Result<u16, Error> {
537        self.connection
538            .max_table_name_len()
539            .into_result(&self.connection)
540    }
541
542    /// Maximum length of column names.
543    pub fn max_column_name_len(&self) -> Result<u16, Error> {
544        self.connection
545            .max_column_name_len()
546            .into_result(&self.connection)
547    }
548
549    /// Get the name of the current catalog being used by the connection.
550    pub fn current_catalog(&self) -> Result<String, Error> {
551        let mut buf = Vec::new();
552        self.connection
553            .fetch_current_catalog(&mut buf)
554            .into_result(&self.connection)?;
555        let name = slice_to_utf8(&buf).expect("Return catalog must be correctly encoded");
556        Ok(name)
557    }
558
559    /// An iterator over the columns of tables matching the patterns. Patterns support `%` for
560    /// multiple characters or `_` for a single character. Use `\` to escape.
561    ///
562    /// Returns an iterator over [`ColumnsRow`] items. If you need the raw cursor (e.g. to access
563    /// driver-specific columns beyond the standard 18), use [`Preallocated::columns_cursor`]
564    /// instead.
565    pub fn columns(
566        &self,
567        catalog_name: &str,
568        schema_name: &str,
569        table_name: &str,
570        column_name: &str,
571    ) -> Result<BlockCursorIterator<CursorImpl<StatementImpl<'_>>, ColumnsRow>, Error> {
572        let stmt = self.preallocate()?;
573        stmt.into_columns(catalog_name, schema_name, table_name, column_name)
574    }
575
576    /// List tables, schemas, views and catalogs of a datasource.
577    ///
578    /// # Parameters
579    ///
580    /// * `catalog_name`: Filter result by catalog name. Accept search patterns. Use `%` to match
581    ///   any number of characters. Use `_` to match exactly on character. Use `\` to escape
582    ///   characeters.
583    /// * `schema_name`: Filter result by schema. Accepts patterns in the same way as
584    ///   `catalog_name`.
585    /// * `table_name`: Filter result by table. Accepts patterns in the same way as `catalog_name`.
586    /// * `table_type`: Filters results by table type. E.g: 'TABLE', 'VIEW'. This argument accepts a
587    ///   comma separeted list of table types. Omit it to not filter the result by table type at
588    ///   all.
589    ///
590    /// # Example
591    ///
592    /// ```
593    /// use odbc_api::{Connection, Error, TablesRow};
594    ///
595    /// fn print_all_tables(conn: &Connection<'_>) -> Result<(), Error> {
596    ///     for row in conn.tables("", "", "", "")? {
597    ///         let row: TablesRow = row?;
598    ///         let table = row.table.as_str().unwrap().unwrap_or("NULL");
599    ///         let catalog = row.catalog.as_str().unwrap().unwrap_or("NULL");
600    ///         let schema = row.schema.as_str().unwrap().unwrap_or("NULL");
601    ///         println!("{catalog}.{schema}.{table}");
602    ///     }
603    ///     Ok(())
604    /// }
605    /// ```
606    pub fn tables(
607        &self,
608        catalog_name: &str,
609        schema_name: &str,
610        table_name: &str,
611        table_type: &str,
612    ) -> Result<BlockCursorIterator<CursorImpl<StatementImpl<'_>>, TablesRow>, Error> {
613        let statement = self.preallocate()?;
614        statement.into_tables(catalog_name, schema_name, table_name, table_type)
615    }
616
617    /// Create a result set which contains the column names that make up the primary key for the
618    /// table.
619    ///
620    /// # Parameters
621    ///
622    /// * `catalog_name`: Catalog name. If a driver supports catalogs for some tables but not for
623    ///   others, such as when the driver retrieves data from different DBMSs, an empty string ("")
624    ///   denotes those tables that do not have catalogs. `catalog_name` must not contain a string
625    ///   search pattern.
626    /// * `schema_name`: Schema name. If a driver supports schemas for some tables but not for
627    ///   others, such as when the driver retrieves data from different DBMSs, an empty string ("")
628    ///   denotes those tables that do not have schemas. `schema_name` must not contain a string
629    ///   search pattern.
630    /// * `table_name`: Table name. `table_name` must not contain a string search pattern.
631    ///
632    /// The resulting result set contains the following columns:
633    ///
634    /// * `TABLE_CAT`: Primary key table catalog name. NULL if not applicable to the data source. If
635    ///   a driver supports catalogs for some tables but not for others, such as when the driver
636    ///   retrieves data from different DBMSs, it returns an empty string ("") for those tables that
637    ///   do not have catalogs. `VARCHAR`
638    /// * `TABLE_SCHEM`: Primary key table schema name; NULL if not applicable to the data source.
639    ///   If a driver supports schemas for some tables but not for others, such as when the driver
640    ///   retrieves data from different DBMSs, it returns an empty string ("") for those tables that
641    ///   do not have schemas. `VARCHAR`
642    /// * `TABLE_NAME`: Primary key table name. `VARCHAR NOT NULL`
643    /// * `COLUMN_NAME`: Primary key column name. The driver returns an empty string for a column
644    ///   that does not have a name. `VARCHAR NOT NULL`
645    /// * `KEY_SEQ`: Column sequence number in key (starting with 1). `SMALLINT NOT NULL`
646    /// * `PK_NAME`: Primary key name. NULL if not applicable to the data source. `VARCHAR`
647    ///
648    /// The maximum length of the VARCHAR columns is driver specific.
649    ///
650    /// If [`crate::sys::StatementAttribute::MetadataId`] statement attribute is set to true,
651    /// catalog, schema and table name parameters are treated as an identifiers and their case is
652    /// not significant. If it is false, they are ordinary arguments. As such they treated literally
653    /// and their case is significant.
654    ///
655    /// See: <https://learn.microsoft.com/sql/odbc/reference/syntax/sqlprimarykeys-function>
656    pub fn primary_keys(
657        &self,
658        catalog_name: Option<&str>,
659        schema_name: Option<&str>,
660        table_name: &str,
661    ) -> Result<BlockCursorIterator<CursorImpl<StatementImpl<'_>>, PrimaryKeysRow>, Error> {
662        let stmt = self.preallocate()?;
663        stmt.into_primary_keys(catalog_name, schema_name, table_name)
664    }
665
666    /// This can be used to retrieve either a list of foreign keys in the specified table or a list
667    /// of foreign keys in other table that refer to the primary key of the specified table.
668    ///
669    /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlforeignkeys-function>
670    pub fn foreign_keys(
671        &self,
672        pk_catalog_name: &str,
673        pk_schema_name: &str,
674        pk_table_name: &str,
675        fk_catalog_name: &str,
676        fk_schema_name: &str,
677        fk_table_name: &str,
678    ) -> Result<BlockCursorIterator<CursorImpl<StatementImpl<'_>>, ForeignKeysRow>, Error> {
679        let statement = self.preallocate()?;
680        statement.into_foreign_keys(
681            pk_catalog_name,
682            pk_schema_name,
683            pk_table_name,
684            fk_catalog_name,
685            fk_schema_name,
686            fk_table_name,
687        )
688    }
689
690    /// The buffer descriptions for all standard buffers (not including extensions) returned in the
691    /// columns query (e.g. [`Preallocated::columns_cursor`]).
692    ///
693    /// # Arguments
694    ///
695    /// * `type_name_max_len` - The maximum expected length of type names.
696    /// * `remarks_max_len` - The maximum expected length of remarks.
697    /// * `column_default_max_len` - The maximum expected length of column defaults.
698    #[deprecated(
699        note = "Use `Connection::columns` or `Preallocated::columns` which return strongly typed \
700        `ColumnsRow` items instead."
701    )]
702    pub fn columns_buffer_descs(
703        &self,
704        type_name_max_len: usize,
705        remarks_max_len: usize,
706        column_default_max_len: usize,
707    ) -> Result<Vec<BufferDesc>, Error> {
708        let null_i16 = BufferDesc::I16 { nullable: true };
709
710        let not_null_i16 = BufferDesc::I16 { nullable: false };
711
712        let null_i32 = BufferDesc::I32 { nullable: true };
713
714        // The definitions for these descriptions are taken from the documentation of `SQLColumns`
715        // located at https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlcolumns-function
716        let catalog_name_desc = BufferDesc::Text {
717            max_str_len: self.max_catalog_name_len()? as usize,
718        };
719
720        let schema_name_desc = BufferDesc::Text {
721            max_str_len: self.max_schema_name_len()? as usize,
722        };
723
724        let table_name_desc = BufferDesc::Text {
725            max_str_len: self.max_table_name_len()? as usize,
726        };
727
728        let column_name_desc = BufferDesc::Text {
729            max_str_len: self.max_column_name_len()? as usize,
730        };
731
732        let data_type_desc = not_null_i16;
733
734        let type_name_desc = BufferDesc::Text {
735            max_str_len: type_name_max_len,
736        };
737
738        let column_size_desc = null_i32;
739        let buffer_len_desc = null_i32;
740        let decimal_digits_desc = null_i16;
741        let precision_radix_desc = null_i16;
742        let nullable_desc = not_null_i16;
743
744        let remarks_desc = BufferDesc::Text {
745            max_str_len: remarks_max_len,
746        };
747
748        let column_default_desc = BufferDesc::Text {
749            max_str_len: column_default_max_len,
750        };
751
752        let sql_data_type_desc = not_null_i16;
753        let sql_datetime_sub_desc = null_i16;
754        let char_octet_len_desc = null_i32;
755        let ordinal_pos_desc = BufferDesc::I32 { nullable: false };
756
757        // We expect strings to be `YES`, `NO`, or a zero-length string, so `3` should be
758        // sufficient.
759        const IS_NULLABLE_LEN_MAX_LEN: usize = 3;
760        let is_nullable_desc = BufferDesc::Text {
761            max_str_len: IS_NULLABLE_LEN_MAX_LEN,
762        };
763
764        Ok(vec![
765            catalog_name_desc,
766            schema_name_desc,
767            table_name_desc,
768            column_name_desc,
769            data_type_desc,
770            type_name_desc,
771            column_size_desc,
772            buffer_len_desc,
773            decimal_digits_desc,
774            precision_radix_desc,
775            nullable_desc,
776            remarks_desc,
777            column_default_desc,
778            sql_data_type_desc,
779            sql_datetime_sub_desc,
780            char_octet_len_desc,
781            ordinal_pos_desc,
782            is_nullable_desc,
783        ])
784    }
785
786    fn allocate_statement(&self) -> Result<StatementImpl<'_>, Error> {
787        self.connection
788            .allocate_statement()
789            .into_result(&self.connection)
790    }
791}
792
793/// Implement `Debug` for [`Connection`], in order to play nice with derive Debugs for struct
794/// holding a [`Connection`].
795impl Debug for Connection<'_> {
796    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
797        write!(f, "Connection")
798    }
799}
800
801/// We need to implement [`StatementParent`] for [`Connection`] in order to express ownership of a
802/// connection for a statement handle. This is e.g. needed for [`Connection::into_cursor`].
803///
804/// # Safety:
805///
806/// Connection wraps an open Connection. It keeps the handle alive and valid during its lifetime.
807unsafe impl StatementParent for Connection<'_> {}
808
809/// We need to implement [`StatementParent`] for `Arc<Connection>` in order to be able to express
810/// ownership of a shared connection from a statement handle. This is e.g. needed for
811/// [`ConnectionTransitions::into_cursor`].
812///
813/// # Safety:
814///
815/// `Arc<Connection>` wraps an open Connection. It keeps the handle alive and valid during its
816/// lifetime.
817unsafe impl StatementParent for Arc<Connection<'_>> {}
818
819/// Options to be passed then opening a connection to a datasource.
820#[derive(Default, Clone, Copy)]
821pub struct ConnectionOptions {
822    /// Number of seconds to wait for a login request to complete before returning to the
823    /// application. The default is driver-dependent. If `0` the timeout is disabled and a
824    /// connection attempt will wait indefinitely.
825    ///
826    /// If the specified timeout exceeds the maximum login timeout in the data source, the driver
827    /// substitutes that value and uses the maximum login timeout instead.
828    ///
829    /// This corresponds to the `SQL_ATTR_LOGIN_TIMEOUT` attribute in the ODBC specification.
830    ///
831    /// See:
832    /// <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetconnectattr-function>
833    pub login_timeout_sec: Option<u32>,
834    /// Packet size in bytes. Not all drivers support this option.
835    pub packet_size: Option<u32>,
836}
837
838impl ConnectionOptions {
839    /// Set the attributes corresponding to the connection options to an allocated connection
840    /// handle. Usually you would rather provide the options then creating the connection with e.g.
841    /// [`crate::Environment::connect_with_connection_string`] rather than calling this method
842    /// yourself.
843    pub fn apply(&self, handle: &handles::Connection) -> Result<(), Error> {
844        if let Some(timeout) = self.login_timeout_sec {
845            handle.set_login_timeout_sec(timeout).into_result(handle)?;
846        }
847        if let Some(packet_size) = self.packet_size {
848            handle.set_packet_size(packet_size).into_result(handle)?;
849        }
850        Ok(())
851    }
852}
853
854/// You can use this method to escape a password so it is suitable to be appended to an ODBC
855/// connection string as the value for the `PWD` attribute. This method is only of interest for
856/// application in need to create their own connection strings.
857///
858/// See:
859///
860/// * <https://stackoverflow.com/questions/22398212/escape-semicolon-in-odbc-connection-string-in-app-config-file>
861/// * <https://docs.microsoft.com/en-us/dotnet/api/system.data.odbc.odbcconnection.connectionstring>
862///
863/// # Example
864///
865/// ```
866/// use odbc_api::escape_attribute_value;
867///
868/// let password = "abc;123}";
869/// let user = "SA";
870/// let mut connection_string_without_credentials =
871///     "Driver={ODBC Driver 18 for SQL Server};Server=localhost;";
872///
873/// let connection_string = format!(
874///     "{}UID={};PWD={};",
875///     connection_string_without_credentials,
876///     user,
877///     escape_attribute_value(password)
878/// );
879///
880/// assert_eq!(
881///     "Driver={ODBC Driver 18 for SQL Server};Server=localhost;UID=SA;PWD={abc;123}}};",
882///     connection_string
883/// );
884/// ```
885///
886/// ```
887/// use odbc_api::escape_attribute_value;
888/// assert_eq!("abc", escape_attribute_value("abc"));
889/// assert_eq!("ab}c", escape_attribute_value("ab}c"));
890/// assert_eq!("{ab;c}", escape_attribute_value("ab;c"));
891/// assert_eq!("{a}}b;c}", escape_attribute_value("a}b;c"));
892/// assert_eq!("{ab+c}", escape_attribute_value("ab+c"));
893/// ```
894pub fn escape_attribute_value(unescaped: &str) -> Cow<'_, str> {
895    // Search the string for semicolon (';') if we do not find any, nothing is to do and we can work
896    // without an extra allocation.
897    //
898    // * We escape ';' because it serves as a separator between key=value pairs
899    // * We escape '+' because passwords with `+` must be escaped on PostgreSQL for some reason.
900    if unescaped.contains(&[';', '+'][..]) {
901        // Surround the string with curly braces ('{','}') and escape every closing curly brace by
902        // repeating it.
903        let escaped = unescaped.replace('}', "}}");
904        Cow::Owned(format!("{{{escaped}}}"))
905    } else {
906        Cow::Borrowed(unescaped)
907    }
908}
909
910/// A pair of the error and the previous state, before the operation caused the error.
911///
912/// Some functions in this crate take a `self` and return another type in the result to express a
913/// state transitions in the underlying ODBC handle. In order to make such operations retryable, or
914/// offer other alternatives of recovery, they may return this error type instead of a plain
915/// [`Error`].
916#[derive(Debug)]
917pub struct FailedStateTransition<S> {
918    /// The ODBC error which caused the state transition to fail.
919    pub error: Error,
920    /// The state before the transition failed. This is useful to e.g. retry the operation, or
921    /// recover in another way.
922    pub previous: S,
923}
924
925impl<S> From<FailedStateTransition<S>> for Error {
926    fn from(value: FailedStateTransition<S>) -> Self {
927        value.error
928    }
929}
930
931impl<S> Display for FailedStateTransition<S> {
932    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
933        write!(f, "{}", self.error)
934    }
935}
936
937impl<S> std::error::Error for FailedStateTransition<S>
938where
939    S: Debug,
940{
941    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
942        self.error.source()
943    }
944}
945
946/// An error type wrapping an [`Error`] and a [`Connection`]. It is used by
947/// [`Connection::into_cursor`], so that in case of failure the user can reuse the connection to try
948/// again. [`Connection::into_cursor`] could achieve the same by returning a tuple in case of an
949/// error, but this type causes less friction in most scenarios because [`Error`] implements
950/// [`From`] [`ConnectionAndError`] and it therfore works with the question mark operater (`?`).
951type ConnectionAndError<'conn> = FailedStateTransition<Connection<'conn>>;
952
953/// Ability to transition ownership of the connection to various children which represent statement
954/// handles in various states. E.g. [`crate::Prepared`] or [`crate::Cursor`]. Transfering ownership
955/// of the connection could e.g. be useful if you want to clean the connection after you are done
956/// with the child.
957///
958/// Having this in a trait rather than directly on [`Connection`] allows us to be generic over the
959/// type of ownership we express. E.g. we can express shared ownership of a connection by
960/// using an `Arc<Mutex<Connection>>` or `Arc<Connection>`. Or a still exclusive ownership using
961/// a plain [`Connection`].
962pub trait ConnectionTransitions: Sized {
963    // Note to self. This might eveolve into a `Connection` trait. Which expresses ownership
964    // of a connection (shared or not). It could allow to get a dereferened borrowed conection
965    // which does not allow for state transtions as of now (like StatementRef). I may not want to
966    // rock the boat that much right now.
967
968    /// The type passed to [crate::handles::StatementConnection] to express ownership of the
969    /// connection.
970    type StatementParent: StatementParent;
971
972    /// Similar to [`crate::Connection::into_cursor`], yet it operates on an
973    /// `Arc<Mutex<Connection>>`. `Arc<Connection>` can be used if you want shared ownership of
974    /// connections. However, `Arc<Connection>` is not `Send` due to `Connection` not being `Sync`.
975    /// So sometimes you may want to wrap your `Connection` into an `Arc<Mutex<Connection>>` to
976    /// allow shared ownership of the connection across threads. This function allows you to create
977    /// a cursor from such a shared which also holds a strong reference to it.
978    ///
979    /// # Parameters
980    ///
981    /// * `query`: The text representation of the SQL statement. E.g. "SELECT * FROM my_table;".
982    /// * `params`: `?` may be used as a placeholder in the statement text. You can use `()` to
983    ///   represent no parameters. See the [`crate::parameter`] module level documentation for more
984    ///   information on how to pass parameters.
985    /// * `query_timeout_sec`: Use this to limit the time the query is allowed to take, before
986    ///   responding with data to the application. The driver may replace the number of seconds you
987    ///   provide with a minimum or maximum value.
988    ///
989    ///   For the timeout to work the driver must support this feature. E.g. PostgreSQL, and
990    ///   Microsoft SQL Server do, but SQLite or MariaDB do not.
991    ///
992    ///   You can specify ``0``, to deactivate the timeout, this is the default. So if you want no
993    ///   timeout, just leave it at `None`. Only reason to specify ``0`` is if for some reason your
994    ///   datasource does not have ``0`` as default.
995    ///
996    ///   This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
997    ///
998    ///   See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetstmtattr-function>
999    fn into_cursor(
1000        self,
1001        query: &str,
1002        params: impl ParameterCollectionRef,
1003        query_timeout_sec: Option<usize>,
1004    ) -> Result<Option<OwnedCursor<Self::StatementParent>>, FailedStateTransition<Self>>;
1005
1006    /// Prepares an SQL statement which takes ownership of the connection. The advantage over
1007    /// [`Connection::prepare`] is, that you do not need to keep track of the lifetime of the
1008    /// connection seperatly and can create types which do own the prepared query and only depend on
1009    /// the lifetime of the environment.
1010    ///
1011    /// # Parameters
1012    ///
1013    /// * `query`: The text representation of the SQL statement. E.g. "SELECT * FROM my_table;". `?`
1014    ///   may be used as a placeholder in the statement text, to be replaced with parameters during
1015    ///   execution.
1016    ///
1017    /// ```no_run
1018    /// use odbc_api::{
1019    ///     environment, Error, ColumnarBulkInserter, ConnectionTransitions, Connection,
1020    ///     handles::StatementConnection, buffers::BoxColumnBuffer, ConnectionOptions,
1021    ///     BindParamDesc, parameter::WithDataType,
1022    /// };
1023    ///
1024    /// const CONNECTION_STRING: &str =
1025    ///     "Driver={ODBC Driver 18 for SQL Server};\
1026    ///     Server=localhost;UID=SA;\
1027    ///     PWD=My@Test@Password1;";
1028    ///
1029    /// /// Supports columnar bulk inserts on a heterogenous schema (columns have different types),
1030    /// /// takes ownership of a connection created using an environment with static lifetime.
1031    /// type Inserter = ColumnarBulkInserter<
1032    ///     StatementConnection<Connection<'static>>,
1033    ///     WithDataType<BoxColumnBuffer>
1034    /// >;
1035    ///
1036    /// /// Creates an inserter which can be reused to bulk insert birthyears with static lifetime.
1037    /// fn make_inserter(query: &str) -> Result<Inserter, Error> {
1038    ///     let env = environment()?;
1039    ///     let conn = env.connect_with_connection_string(
1040    ///         CONNECTION_STRING,
1041    ///         ConnectionOptions::default()
1042    ///     )?;
1043    ///     let prepared = conn.into_prepared("INSERT INTO Birthyear (name, year) VALUES (?, ?)")?;
1044    ///     let buffers = [
1045    ///         BindParamDesc::text(255),
1046    ///         BindParamDesc::i16(false),
1047    ///     ];
1048    ///     let capacity = 400;
1049    ///     prepared.into_column_inserter(capacity, buffers)
1050    /// }
1051    /// ```
1052    fn into_prepared(
1053        self,
1054        query: &str,
1055    ) -> Result<Prepared<StatementConnection<Self::StatementParent>>, Error>;
1056
1057    /// Creates a preallocated statement handle like [`Connection::preallocate`]. Yet the statement
1058    /// also takes ownership of the connection.
1059    fn into_preallocated(
1060        self,
1061    ) -> Result<Preallocated<StatementConnection<Self::StatementParent>>, Error>;
1062}
1063
1064impl<'env> ConnectionTransitions for Connection<'env> {
1065    type StatementParent = Self;
1066
1067    fn into_cursor(
1068        self,
1069        query: &str,
1070        params: impl ParameterCollectionRef,
1071        query_timeout_sec: Option<usize>,
1072    ) -> Result<Option<OwnedCursor<Self>>, FailedStateTransition<Self>> {
1073        self.into_cursor(query, params, query_timeout_sec)
1074    }
1075
1076    fn into_prepared(self, query: &str) -> Result<Prepared<StatementConnection<Self>>, Error> {
1077        self.into_prepared(query)
1078    }
1079
1080    fn into_preallocated(self) -> Result<Preallocated<StatementConnection<Self>>, Error> {
1081        self.into_preallocated()
1082    }
1083}
1084
1085impl<'env> ConnectionTransitions for Arc<Connection<'env>> {
1086    type StatementParent = Self;
1087
1088    fn into_cursor(
1089        self,
1090        query: &str,
1091        params: impl ParameterCollectionRef,
1092        query_timeout_sec: Option<usize>,
1093    ) -> Result<Option<OwnedCursor<Self>>, FailedStateTransition<Self>> {
1094        // Result borrows the connection. We convert the cursor into a raw pointer, to not confuse
1095        // the borrow checker.
1096        let result = self.execute(query, params, query_timeout_sec);
1097        let maybe_stmt_ptr = result
1098            .map(|opt| opt.map(|cursor| cursor.into_stmt().into_sys()))
1099            .map_err(|error| {
1100                // If the execute fails, we return a FailedStateTransition with the error and the
1101                // connection.
1102                FailedStateTransition {
1103                    error,
1104                    previous: Arc::clone(&self),
1105                }
1106            })?;
1107        let Some(stmt_ptr) = maybe_stmt_ptr else {
1108            return Ok(None);
1109        };
1110        // Safe: The connection is the parent of the statement referenced by `stmt_ptr`.
1111        let stmt = unsafe { StatementConnection::new(stmt_ptr, self) };
1112        // Safe: `stmt` is valid and in cursor state.
1113        let cursor = unsafe { CursorImpl::new(stmt) };
1114        Ok(Some(cursor))
1115    }
1116
1117    fn into_prepared(self, query: &str) -> Result<Prepared<StatementConnection<Self>>, Error> {
1118        let stmt = self.prepare(query)?;
1119        let stmt_ptr = stmt.into_handle().into_sys();
1120        // Safe: The connection is the parent of the statement referenced by `stmt_ptr`.
1121        let stmt = unsafe { StatementConnection::new(stmt_ptr, self) };
1122        // `stmt` is valid and in prepared state.
1123        let prepared = Prepared::new(stmt);
1124        Ok(prepared)
1125    }
1126
1127    fn into_preallocated(self) -> Result<Preallocated<StatementConnection<Self>>, Error> {
1128        let stmt = self.preallocate()?;
1129        let stmt_ptr = stmt.into_handle().into_sys();
1130        // Safe: The connection is the parent of the statement referenced by `stmt_ptr`.
1131        let stmt = unsafe { StatementConnection::new(stmt_ptr, self) };
1132        // Safe: `stmt` is valid and its state is allocated.
1133        let preallocated = unsafe { Preallocated::new(stmt) };
1134        Ok(preallocated)
1135    }
1136}