Skip to main content

odbc_api/
preallocated.rs

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