Skip to main content

sqlx_mssql_odbc_core/
describe.rs

1//! Compile-time query description for the MSSQL ODBC macros.
2//!
3//! Only available with the `offline` feature.
4
5use crate::{Mssql, MssqlConnectOptions, MssqlConnection, MssqlStatement};
6use sqlx_core::describe::Describe;
7use sqlx_core::sql_str::{AssertSqlSafe, SqlSafeStr};
8use sqlx_core::statement::Statement as _;
9use sqlx_core::Either;
10
11/// Compile-time query descriptor plugged into [`sqlx_macros_core`].
12#[doc(hidden)]
13pub const MSSQL_DRIVER: sqlx_macros_core::query::QueryDriver =
14    sqlx_macros_core::query::QueryDriver::new::<Mssql>();
15
16impl sqlx_macros_core::database::DatabaseExt for Mssql {
17    const DATABASE_PATH: &'static str = "sqlx_mssql_odbc::Mssql";
18    const ROW_PATH: &'static str = "sqlx_mssql_odbc::MssqlRow";
19
20    fn describe_blocking(
21        query: &str,
22        database_url: &str,
23        driver_config: &sqlx_core::config::drivers::Config,
24    ) -> sqlx_core::Result<Describe<Self>> {
25        describe_blocking(query, database_url, driver_config)
26    }
27}
28
29/// Connects to an MSSQL database via ODBC at compile time and describes a SQL query.
30///
31/// Returns column metadata, parameter count, and nullability information.
32/// This function is `#[doc(hidden)]` — it is only used by the proc macros.
33///
34/// # Limitations
35///
36/// - Nullability is always reported as `None` (ODBC cannot reliably determine
37///   nullability from `SQLDescribeCol` alone).
38/// - Parameter types are not available (only the count is reported).
39#[doc(hidden)]
40pub fn describe_blocking(
41    query: &str,
42    database_url: &str,
43    _driver_config: &sqlx_core::config::drivers::Config,
44) -> Result<Describe<Mssql>, sqlx_core::Error> {
45    // Parse the database URL into connection options.
46    let options: MssqlConnectOptions = database_url
47        .parse()
48        .map_err(|e| sqlx_core::Error::Configuration(Box::new(e)))?;
49
50    // Open a blocking connection.
51    let mut conn = MssqlConnection::connect_blocking(&options)?;
52
53    // Prepare the statement to get column metadata and parameter count.
54    let sql_str = AssertSqlSafe(query.to_owned()).into_sql_str();
55    let statement: MssqlStatement = conn.prepare_blocking(sql_str)?;
56
57    let column_count = statement.columns().len();
58    let parameter_count = statement
59        .parameters()
60        .map(|p| match p {
61            Either::Left(types) => types.len(),
62            Either::Right(count) => count,
63        })
64        .unwrap_or(0);
65
66    Ok(Describe {
67        columns: statement.columns().to_vec(),
68        parameters: Some(Either::Right(parameter_count)),
69        nullable: vec![None; column_count],
70    })
71}