Skip to main content

odbc_api/
preallocated.rs

1use crate::{
2    BlockCursorIterator, Connection, Cursor, CursorImpl, Error, IdentifierQuoteChar,
3    ParameterCollectionRef, PreallocatedPolling,
4    buffers::RowVec,
5    catalog::{
6        ColumnsRow, ForeignKeysRow, PrimaryKeysRow, TablesRow, execute_columns,
7        execute_foreign_keys, execute_primary_keys, execute_tables,
8    },
9    execute::execute_with_parameters,
10    handles::{AsStatementRef, SqlText, Statement, StatementConnection, StatementRef},
11};
12
13/// A preallocated SQL statement handle intended for sequential execution of different queries. See
14/// [`crate::Connection::preallocate`].
15///
16/// # Example
17///
18/// ```
19/// use odbc_api::{Connection, Error};
20/// use std::io::{self, stdin, Read};
21///
22/// fn interactive(conn: &Connection<'_>) -> io::Result<()>{
23///     let mut statement = conn.preallocate().unwrap();
24///     let mut query = String::new();
25///     stdin().read_line(&mut query)?;
26///     while !query.is_empty() {
27///         match statement.execute(&query, ()) {
28///             Err(e) => println!("{}", e),
29///             Ok(None) => println!("No results set generated."),
30///             Ok(Some(cursor)) => {
31///                 // ...print cursor contents...
32///             },
33///         }
34///         stdin().read_line(&mut query)?;
35///     }
36///     Ok(())
37/// }
38/// ```
39pub struct Preallocated<S> {
40    /// A valid statement handle.
41    statement: S,
42}
43
44impl<S> Preallocated<S>
45where
46    S: Statement,
47{
48    /// Users which intend to write their application in safe Rust should prefer using
49    /// [`crate::Connection::preallocate`] as opposed to this constructor.
50    ///
51    /// # Safety
52    ///
53    /// `statement` must be an allocated handled with no pointers bound for either results or
54    /// arguments. The statement must not be prepared, but in the state of a "freshly" allocated
55    /// handle.
56    pub unsafe fn new(statement: S) -> Self {
57        Self { statement }
58    }
59
60    /// Executes a statement. This is the fastest way to sequentially execute different SQL
61    /// Statements.
62    ///
63    /// This method produces a cursor which borrowes the statement handle. If you want to take
64    /// ownership you can use the sibling [`Self::into_cursor`].
65    ///
66    /// # Parameters
67    ///
68    /// * `query`: The text representation of the SQL statement. E.g. "SELECT * FROM my_table;".
69    /// * `params`: `?` may be used as a placeholder in the statement text. You can use `()` to
70    ///   represent no parameters. Check the [`crate::parameter`] module level documentation for
71    ///   more information on how to pass parameters.
72    ///
73    /// # Return
74    ///
75    /// Returns `Some` if a cursor is created. If `None` is returned no cursor has been created (
76    /// e.g. the query came back empty). Note that an empty query may also create a cursor with zero
77    /// rows. Since we want to reuse the statement handle a returned cursor will not take ownership
78    /// of it and instead borrow it.
79    ///
80    /// # Example
81    ///
82    /// ```
83    /// use odbc_api::{Connection, Error};
84    /// use std::io::{self, stdin, Read};
85    ///
86    /// fn interactive(conn: &Connection) -> io::Result<()>{
87    ///     let mut statement = conn.preallocate().unwrap();
88    ///     let mut query = String::new();
89    ///     stdin().read_line(&mut query)?;
90    ///     while !query.is_empty() {
91    ///         match statement.execute(&query, ()) {
92    ///             Err(e) => println!("{}", e),
93    ///             Ok(None) => println!("No results set generated."),
94    ///             Ok(Some(cursor)) => {
95    ///                 // ...print cursor contents...
96    ///             },
97    ///         }
98    ///         stdin().read_line(&mut query)?;
99    ///     }
100    ///     Ok(())
101    /// }
102    /// ```
103    pub fn execute(
104        &mut self,
105        query: &str,
106        params: impl ParameterCollectionRef,
107    ) -> Result<Option<CursorImpl<StatementRef<'_>>>, Error> {
108        let query = SqlText::new(query);
109        let stmt = self.statement.as_stmt_ref();
110        execute_with_parameters(stmt, Some(&query), params)
111    }
112
113    /// Similar to [`Self::execute`], but transfers ownership of the statement handle to the
114    /// resulting cursor if any is created. This makes this method not suitable to repeatedly
115    /// execute statements. In most situations you may want to call [`crate::Connection::execute`]
116    /// instead of this method, yet this method is useful if you have some time in your application
117    /// until the query is known, and once you have it want to execute it as fast as possible.
118    pub fn into_cursor(
119        self,
120        query: &str,
121        params: impl ParameterCollectionRef,
122    ) -> Result<Option<CursorImpl<S>>, Error> {
123        let query = SqlText::new(query);
124        execute_with_parameters(self.statement, Some(&query), params)
125    }
126
127    /// Transfer ownership to the underlying statement handle.
128    ///
129    /// The resulting type is one level of indirection away from the raw pointer of the ODBC API. It
130    /// no longer has any guarantees about bound buffers, but is still guaranteed to be a valid
131    /// allocated statement handle. This serves together with
132    /// [`crate::handles::StatementImpl::into_sys`] or [`crate::handles::Statement::as_sys`] this
133    /// serves as an escape hatch to access the functionality provided by `crate::sys` not yet
134    /// accessible through safe abstractions.
135    pub fn into_handle(self) -> S {
136        self.statement
137    }
138
139    /// List tables, schemas, views and catalogs of a datasource.
140    ///
141    /// # Parameters
142    ///
143    /// * `catalog_name`: Filter result by catalog name. Accept search patterns. Use `%` to match
144    ///   any number of characters. Use `_` to match exactly on character. Use `\` to escape
145    ///   characeters.
146    /// * `schema_name`: Filter result by schema. Accepts patterns in the same way as
147    ///   `catalog_name`.
148    /// * `table_name`: Filter result by table. Accepts patterns in the same way as `catalog_name`.
149    /// * `table_type`: Filters results by table type. E.g: 'TABLE', 'VIEW'. This argument accepts a
150    ///   comma separeted list of table types. Omit it to not filter the result by table type at
151    ///   all.
152    pub fn tables_cursor(
153        &mut self,
154        catalog_name: &str,
155        schema_name: &str,
156        table_name: &str,
157        table_type: &str,
158    ) -> Result<CursorImpl<StatementRef<'_>>, Error> {
159        let stmt = self.statement.as_stmt_ref();
160        execute_tables(stmt, catalog_name, schema_name, table_name, table_type)
161    }
162
163    /// An iterator over the tables of a data source. Same as [`Self::tables_cursor`] but returns
164    /// strongly typed [`TablesRow`] items instead of a raw cursor.
165    pub fn tables(
166        &mut self,
167        catalog_name: &str,
168        schema_name: &str,
169        table_name: &str,
170        table_type: &str,
171    ) -> Result<BlockCursorIterator<CursorImpl<StatementRef<'_>>, TablesRow>, Error> {
172        let cursor = self.tables_cursor(catalog_name, schema_name, table_name, table_type)?;
173        let buffer = RowVec::<TablesRow>::new(100);
174        Ok(cursor.bind_buffer(buffer)?.into_iter())
175    }
176
177    /// Same as [`Self::tables_cursor`] but the cursor takes ownership of the statement handle.
178    pub fn into_tables_cursor(
179        self,
180        catalog_name: &str,
181        schema_name: &str,
182        table_name: &str,
183        table_type: &str,
184    ) -> Result<CursorImpl<S>, Error> {
185        execute_tables(
186            self.statement,
187            catalog_name,
188            schema_name,
189            table_name,
190            table_type,
191        )
192    }
193
194    /// Same as [`Self::tables`] but the cursor takes ownership of the statement handle.
195    pub fn into_tables(
196        self,
197        catalog_name: &str,
198        schema_name: &str,
199        table_name: &str,
200        table_type: &str,
201    ) -> Result<BlockCursorIterator<CursorImpl<S>, TablesRow>, Error> {
202        let cursor = self.into_tables_cursor(catalog_name, schema_name, table_name, table_type)?;
203        let buffer = RowVec::<TablesRow>::new(100);
204        Ok(cursor.bind_buffer(buffer)?.into_iter())
205    }
206
207    /// A cursor describing columns of all tables matching the patterns. Patterns support as
208    /// placeholder `%` for multiple characters or `_` for a single character. Use `\` to escape.The
209    /// returned cursor has the columns:
210    /// `TABLE_CAT`, `TABLE_SCHEM`, `TABLE_NAME`, `COLUMN_NAME`, `DATA_TYPE`, `TYPE_NAME`,
211    /// `COLUMN_SIZE`, `BUFFER_LENGTH`, `DECIMAL_DIGITS`, `NUM_PREC_RADIX`, `NULLABLE`,
212    /// `REMARKS`, `COLUMN_DEF`, `SQL_DATA_TYPE`, `SQL_DATETIME_SUB`, `CHAR_OCTET_LENGTH`,
213    /// `ORDINAL_POSITION`, `IS_NULLABLE`.
214    ///
215    /// In addition to that there may be a number of columns specific to the data source.
216    pub fn columns_cursor(
217        &mut self,
218        catalog_name: &str,
219        schema_name: &str,
220        table_name: &str,
221        column_name: &str,
222    ) -> Result<CursorImpl<StatementRef<'_>>, Error> {
223        let stmt = self.statement.as_stmt_ref();
224        execute_columns(
225            stmt,
226            &SqlText::new(catalog_name),
227            &SqlText::new(schema_name),
228            &SqlText::new(table_name),
229            &SqlText::new(column_name),
230        )
231    }
232
233    /// An iterator over the columns of a table. Same as [`Self::columns_cursor`] but returns
234    /// strongly typed [`ColumnsRow`] items instead of a raw cursor.
235    pub fn columns(
236        &mut self,
237        catalog_name: &str,
238        schema_name: &str,
239        table_name: &str,
240        column_name: &str,
241    ) -> Result<BlockCursorIterator<CursorImpl<StatementRef<'_>>, ColumnsRow>, Error> {
242        let cursor = self.columns_cursor(catalog_name, schema_name, table_name, column_name)?;
243        let buffer = RowVec::<ColumnsRow>::new(250);
244        Ok(cursor.bind_buffer(buffer)?.into_iter())
245    }
246
247    /// Same as [`Self::columns_cursor`], but the cursor takes ownership of the statement handle.
248    pub fn into_columns_cursor(
249        self,
250        catalog_name: &str,
251        schema_name: &str,
252        table_name: &str,
253        column_name: &str,
254    ) -> Result<CursorImpl<S>, Error> {
255        execute_columns(
256            self.statement,
257            &SqlText::new(catalog_name),
258            &SqlText::new(schema_name),
259            &SqlText::new(table_name),
260            &SqlText::new(column_name),
261        )
262    }
263
264    /// Same as [`Self::columns`] but the cursor takes ownership of the statement handle.
265    pub fn into_columns(
266        self,
267        catalog_name: &str,
268        schema_name: &str,
269        table_name: &str,
270        column_name: &str,
271    ) -> Result<BlockCursorIterator<CursorImpl<S>, ColumnsRow>, Error> {
272        let cursor =
273            self.into_columns_cursor(catalog_name, schema_name, table_name, column_name)?;
274        let buffer = RowVec::<ColumnsRow>::new(250);
275        Ok(cursor.bind_buffer(buffer)?.into_iter())
276    }
277
278    /// Create a result set which contains the column names that make up the primary key for the
279    /// table. Same as [`Self::into_primary_keys_cursor`] but the cursor borrowes the statement
280    /// handle instead of taking ownership of it. This allows you to reuse the statement handle for
281    /// multiple calls to [`Self::primary_keys_cursor`] or other queries, without the need to ask
282    /// the driver for repeated allocations of new handles.
283    ///
284    /// # Parameters
285    ///
286    /// * `catalog_name`: Catalog name. If a driver supports catalogs for some tables but not for
287    ///   others, such as when the driver retrieves data from different DBMSs, an empty string ("")
288    ///   denotes those tables that do not have catalogs. `catalog_name` must not contain a string
289    ///   search pattern.
290    /// * `schema_name`: Schema name. If a driver supports schemas for some tables but not for
291    ///   others, such as when the driver retrieves data from different DBMSs, an empty string ("")
292    ///   denotes those tables that do not have schemas. `schema_name` must not contain a string
293    ///   search pattern.
294    /// * `table_name`: Table name. `table_name` must not contain a string search pattern.
295    ///
296    /// The resulting result set contains the following columns:
297    ///
298    /// * `TABLE_CAT`: Primary key table catalog name. NULL if not applicable to the data source. If
299    ///   a driver supports catalogs for some tables but not for others, such as when the driver
300    ///   retrieves data from different DBMSs, it returns an empty string ("") for those tables that
301    ///   do not have catalogs. `VARCHAR`
302    /// * `TABLE_SCHEM`: Primary key table schema name; NULL if not applicable to the data source.
303    ///   If a driver supports schemas for some tables but not for others, such as when the driver
304    ///   retrieves data from different DBMSs, it returns an empty string ("") for those tables that
305    ///   do not have schemas. `VARCHAR`
306    /// * `TABLE_NAME`: Primary key table name. `VARCHAR NOT NULL`
307    /// * `COLUMN_NAME`: Primary key column name. The driver returns an empty string for a column
308    ///   that does not have a name. `VARCHAR NOT NULL`
309    /// * `KEY_SEQ`: Column sequence number in key (starting with 1). `SMALLINT NOT NULL`
310    /// * `PK_NAME`: Primary key name. NULL if not applicable to the data source. `VARCHAR`
311    ///
312    /// The maximum length of the VARCHAR columns is driver specific.
313    ///
314    /// If [`crate::sys::StatementAttribute::MetadataId`] statement attribute is set to true,
315    /// catalog, schema and table name parameters are treated as an identifiers and their case is
316    /// not significant. If it is false, they are ordinary arguments. As such they treated literally
317    /// and their case is significant.
318    ///
319    /// See: <https://learn.microsoft.com/sql/odbc/reference/syntax/sqlprimarykeys-function>
320    pub fn primary_keys_cursor(
321        &mut self,
322        catalog_name: Option<&str>,
323        schema_name: Option<&str>,
324        table_name: &str,
325    ) -> Result<CursorImpl<StatementRef<'_>>, Error> {
326        execute_primary_keys(
327            self.statement.as_stmt_ref(),
328            catalog_name,
329            schema_name,
330            table_name,
331        )
332    }
333
334    /// An iterator whose items contains the column names that make up the primary key for the
335    /// table. Same as [`Self::into_primary_keys`] but the cursor borrowes the statement handle
336    /// instead of taking ownership of it. This allows you to reuse the statement handle for
337    /// multiple calls to [`Self::primary_keys`] or other queries, without the need to ask the
338    /// driver for repeated allocations of new handles.
339    ///
340    /// # Parameters
341    ///
342    /// * `catalog_name`: Catalog name. If a driver supports catalogs for some tables but not for
343    ///   others, such as when the driver retrieves data from different DBMSs, an empty string ("")
344    ///   denotes those tables that do not have catalogs. `catalog_name` must not contain a string
345    ///   search pattern.
346    /// * `schema_name`: Schema name. If a driver supports schemas for some tables but not for
347    ///   others, such as when the driver retrieves data from different DBMSs, an empty string ("")
348    ///   denotes those tables that do not have schemas. `schema_name` must not contain a string
349    ///   search pattern.
350    /// * `table_name`: Table name. `table_name` must not contain a string search pattern.
351    ///
352    /// If [`crate::sys::StatementAttribute::MetadataId`] statement attribute is set to true,
353    /// catalog, schema and table name parameters are treated as an identifiers and their case is
354    /// not significant. If it is false, they are ordinary arguments. As such they treated literally
355    /// and their case is significant.
356    ///
357    /// See: <https://learn.microsoft.com/sql/odbc/reference/syntax/sqlprimarykeys-function>
358    pub fn primary_keys(
359        &mut self,
360        catalog_name: Option<&str>,
361        schema_name: Option<&str>,
362        table_name: &str,
363    ) -> Result<BlockCursorIterator<CursorImpl<StatementRef<'_>>, PrimaryKeysRow>, Error> {
364        let cursor = self.primary_keys_cursor(catalog_name, schema_name, table_name)?;
365        // 5 seems like a senisble soft upper bound for the number of columns in a primary key. If
366        // it is more than that, we need an extra roundtrip
367        let buffer = RowVec::<PrimaryKeysRow>::new(5);
368        Ok(cursor.bind_buffer(buffer)?.into_iter())
369    }
370
371    /// Same as [`Self::primary_keys_cursor`] but the cursor takes ownership of the statement handle.
372    pub fn into_primary_keys_cursor(
373        self,
374        catalog_name: Option<&str>,
375        schema_name: Option<&str>,
376        table_name: &str,
377    ) -> Result<CursorImpl<S>, Error> {
378        execute_primary_keys(self.statement, catalog_name, schema_name, table_name)
379    }
380
381    /// Same as [`Self::primary_keys`] but the cursor takes ownership of the statement handle.
382    pub fn into_primary_keys(
383        self,
384        catalog_name: Option<&str>,
385        schema_name: Option<&str>,
386        table_name: &str,
387    ) -> Result<BlockCursorIterator<CursorImpl<S>, PrimaryKeysRow>, Error> {
388        let cursor = self.into_primary_keys_cursor(catalog_name, schema_name, table_name)?;
389        // 5 seems like a senisble soft upper bound for the number of columns in a primary key. If
390        // it is more than that, we need an extra roundtrip
391        let buffer = RowVec::<PrimaryKeysRow>::new(5);
392        Ok(cursor.bind_buffer(buffer)?.into_iter())
393    }
394
395    /// This can be used to retrieve either a list of foreign keys in the specified table or a list
396    /// of foreign keys in other table that refer to the primary key of the specified table.
397    ///
398    /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlforeignkeys-function>
399    pub fn foreign_keys_cursor(
400        &mut self,
401        pk_catalog_name: &str,
402        pk_schema_name: &str,
403        pk_table_name: &str,
404        fk_catalog_name: &str,
405        fk_schema_name: &str,
406        fk_table_name: &str,
407    ) -> Result<CursorImpl<StatementRef<'_>>, Error> {
408        let stmt = self.statement.as_stmt_ref();
409        execute_foreign_keys(
410            stmt,
411            pk_catalog_name,
412            pk_schema_name,
413            pk_table_name,
414            fk_catalog_name,
415            fk_schema_name,
416            fk_table_name,
417        )
418    }
419
420    /// This can be used to retrieve either a list of foreign keys in the specified table or a list
421    /// of foreign keys in other table that refer to the primary key of the specified table.
422    ///
423    /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlforeignkeys-function>
424    pub fn into_foreign_keys_cursor(
425        self,
426        pk_catalog_name: &str,
427        pk_schema_name: &str,
428        pk_table_name: &str,
429        fk_catalog_name: &str,
430        fk_schema_name: &str,
431        fk_table_name: &str,
432    ) -> Result<CursorImpl<S>, Error> {
433        execute_foreign_keys(
434            self.statement,
435            pk_catalog_name,
436            pk_schema_name,
437            pk_table_name,
438            fk_catalog_name,
439            fk_schema_name,
440            fk_table_name,
441        )
442    }
443
444    /// An iterator over the foreign keys of a table.
445    ///
446    /// Same as [`Self::foreign_keys_cursor`] but returns [`ForeignKeysRow`] items instead of a raw
447    /// cursor.
448    ///
449    /// See: <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlforeignkeys-function>
450    pub fn foreign_keys(
451        &mut self,
452        pk_catalog_name: &str,
453        pk_schema_name: &str,
454        pk_table_name: &str,
455        fk_catalog_name: &str,
456        fk_schema_name: &str,
457        fk_table_name: &str,
458    ) -> Result<BlockCursorIterator<CursorImpl<StatementRef<'_>>, ForeignKeysRow>, Error> {
459        let cursor = self.foreign_keys_cursor(
460            pk_catalog_name,
461            pk_schema_name,
462            pk_table_name,
463            fk_catalog_name,
464            fk_schema_name,
465            fk_table_name,
466        )?;
467        let buffer = RowVec::<ForeignKeysRow>::new(100);
468        Ok(cursor.bind_buffer(buffer)?.into_iter())
469    }
470
471    /// Same as [`Self::foreign_keys`] but the cursor takes ownership of the statement handle.
472    pub fn into_foreign_keys(
473        self,
474        pk_catalog_name: &str,
475        pk_schema_name: &str,
476        pk_table_name: &str,
477        fk_catalog_name: &str,
478        fk_schema_name: &str,
479        fk_table_name: &str,
480    ) -> Result<BlockCursorIterator<CursorImpl<S>, ForeignKeysRow>, Error> {
481        let cursor = self.into_foreign_keys_cursor(
482            pk_catalog_name,
483            pk_schema_name,
484            pk_table_name,
485            fk_catalog_name,
486            fk_schema_name,
487            fk_table_name,
488        )?;
489        let buffer = RowVec::<ForeignKeysRow>::new(100);
490        Ok(cursor.bind_buffer(buffer)?.into_iter())
491    }
492
493    /// Number of rows affected by the last `INSERT`, `UPDATE` or `DELETE` statment. May return
494    /// `None` if row count is not available. Some drivers may also allow to use this to determine
495    /// how many rows have been fetched using `SELECT`. Most drivers however only know how many rows
496    /// have been fetched after they have been fetched.
497    ///
498    /// ```
499    /// use odbc_api::{Connection, Error};
500    ///
501    /// /// Make everyone rich and return how many colleagues are happy now.
502    /// fn raise_minimum_salary(
503    ///     conn: &Connection<'_>,
504    ///     new_min_salary: i32
505    /// ) -> Result<usize, Error> {
506    ///     // We won't use conn.execute directly, because we need a handle to ask about the number
507    ///     // of changed rows. So let's allocate the statement explicitly.
508    ///     let mut stmt = conn.preallocate()?;
509    ///     stmt.execute(
510    ///         "UPDATE Employees SET salary = ? WHERE salary < ?",
511    ///         (&new_min_salary, &new_min_salary),
512    ///     )?;
513    ///     let number_of_updated_rows = stmt
514    ///         .row_count()?
515    ///         .expect("For UPDATE statements row count must always be available.");
516    ///     Ok(number_of_updated_rows)
517    /// }
518    /// ```
519    pub fn row_count(&mut self) -> Result<Option<usize>, Error> {
520        self.statement
521            .row_count()
522            .into_result(&self.statement)
523            .map(|count| {
524                // ODBC returns -1 in case a row count is not available
525                if count == -1 {
526                    None
527                } else {
528                    Some(count.try_into().unwrap())
529                }
530            })
531    }
532
533    /// Use this to limit the time the query is allowed to take, before responding with data to the
534    /// application. The driver may replace the number of seconds you provide with a minimum or
535    /// maximum value. You can specify ``0``, to deactivate the timeout, this is the default. For
536    /// this to work the driver must support this feature. E.g. PostgreSQL, and Microsoft SQL Server
537    /// do, but SQLite or MariaDB do not.
538    ///
539    /// This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
540    ///
541    /// See:
542    /// <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetstmtattr-function>
543    pub fn set_query_timeout_sec(&mut self, timeout_sec: usize) -> Result<(), Error> {
544        self.statement
545            .set_query_timeout_sec(timeout_sec)
546            .into_result(&self.statement)
547    }
548
549    /// The number of seconds to wait for a SQL statement to execute before returning to the
550    /// application. If `timeout_sec` is equal to 0 (default), there is no timeout.
551    ///
552    /// This corresponds to `SQL_ATTR_QUERY_TIMEOUT` in the ODBC C API.
553    ///
554    /// See:
555    /// <https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlsetstmtattr-function>
556    pub fn query_timeout_sec(&mut self) -> Result<usize, Error> {
557        self.statement
558            .query_timeout_sec()
559            .into_result(&self.statement)
560    }
561
562    /// Call this method to enable asynchronous polling mode on the statement.
563    ///
564    /// ⚠️**Attention**⚠️: Please read
565    /// [Asynchronous execution using polling
566    /// mode](crate::guide#asynchronous-execution-using-polling-mode)
567    pub fn into_polling(mut self) -> Result<PreallocatedPolling<S>, Error> {
568        self.statement
569            .set_async_enable(true)
570            .into_result(&self.statement)?;
571        Ok(PreallocatedPolling::new(self.statement))
572    }
573}
574
575impl<S> AsStatementRef for Preallocated<S>
576where
577    S: AsStatementRef,
578{
579    fn as_stmt_ref(&mut self) -> StatementRef<'_> {
580        self.statement.as_stmt_ref()
581    }
582}
583
584impl IdentifierQuoteChar for Preallocated<StatementConnection<Connection<'_>>> {
585    fn identifier_quote_char(&self) -> Result<Option<char>, Error> {
586        // Safety:
587        //
588        // Querying identifier quote character does not invalidate the statement handle.
589        unsafe { self.statement.parent().identifier_quote_char() }
590    }
591}