odbc_api/
connection.rs

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