sqlx-mssql-odbc 0.1.3

MSSQL driver for SQLx via ODBC.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
//! MSSQL driver for SQLx via ODBC.
//!
//! `sqlx-mssql-odbc` connects SQLx to Microsoft SQL Server through an ODBC driver
//! manager. This is the **facade crate** — it re-exports everything from
//! [`sqlx-mssql-odbc-core`].
//!
//! # Quick start
//!
//! ```toml
//! [dependencies]
//! sqlx-core = "=0.9.0"
//! sqlx-mssql-odbc = "0.1"
//! tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
//! ```
//!
//! ```no_run
//! use sqlx_core::connection::Connection;
//! use sqlx_core::row::Row;
//! use sqlx_mssql_odbc::MssqlConnection;
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
//! let mut conn = MssqlConnection::connect(
//!     "mssql://user:password@localhost:1433/database"
//! ).await?;
//!
//! let row = sqlx_core::query::query("SELECT 42")
//!     .fetch_one(&mut conn)
//!     .await?;
//!
//! let value: i32 = row.try_get(0)?;
//! assert_eq!(value, 42);
//!
//! conn.close().await?;
//! # Ok(())
//! # }
//! ```
//!
//! `MssqlConnection::connect()` accepts a standard `mssql://` URL, a raw ODBC
//! connection string, or a bare DSN name.
//!
//! # Usage patterns
//!
//! ## Connection pooling
//!
//! ```no_run
//! use sqlx_mssql_odbc::MssqlPoolOptions;
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
//! let pool = MssqlPoolOptions::new()
//!     .max_connections(10)
//!     .connect("mssql://user:password@localhost:1433/database")
//!     .await?;
//!
//! let row = sqlx_core::query::query("SELECT 1")
//!     .fetch_one(&pool)
//!     .await?;
//!
//! pool.close().await;
//! # Ok(())
//! # }
//! ```
//!
//! ## Parameterised queries
//!
//! ```no_run
//! use sqlx_core::row::Row;
//! use sqlx_mssql_odbc::MssqlConnection;
//! use sqlx_core::connection::Connection;
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
//! let mut conn = MssqlConnection::connect("mssql://…").await?;
//!
//! let row = sqlx_core::query::query("SELECT @p1 + @p2")
//!     .bind(10i32)
//!     .bind(20i32)
//!     .fetch_one(&mut conn)
//!     .await?;
//!
//! let total: i32 = row.try_get(0)?;
//! assert_eq!(total, 30);
//! # Ok(())
//! # }
//! ```
//!
//! ## Compile-time checked queries (`macros` feature)
//!
//! Enable the `macros` feature to get compile-time validation of SQL against a
//! live database:
//!
//! ```toml
//! [dependencies]
//! sqlx-mssql-odbc = { version = "0.1", features = ["macros"] }
//! ```
//!
//! ```ignore
//! # use sqlx_mssql_odbc::MssqlConnection;
//! # use sqlx_core::connection::Connection;
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let mut conn = MssqlConnection::connect("…").await?;
//!
//! // The column name and type are checked at compile time.
//! let row = sqlx_mssql_odbc::query!("SELECT 1 AS one")
//!     .fetch_one(&mut conn)
//!     .await?;
//! assert_eq!(row.one, 1i32);
//!
//! // Bind parameters with $1, $2, etc.
//! let row = sqlx_mssql_odbc::query!("SELECT @p1 + @p2 AS total", 10i32, 20i32)
//!     .fetch_one(&mut conn)
//!     .await?;
//! assert_eq!(row.total, 30);
//! # Ok(())
//! # }
//! ```
//!
//! For CI or offline builds, use `cargo sqlx prepare` to cache the schema so
//! the macros can check queries without a live database.
//!
//! ## Derive macros (`derive` feature)
//!
//! ```toml
//! [dependencies]
//! sqlx-mssql-odbc = { version = "0.1", features = ["derive"] }
//! ```
//!
//! ```ignore
//! use sqlx_mssql_odbc::FromRow;
//!
//! #[derive(Debug, FromRow)]
//! struct User {
//!     id: i32,
//!     name: String,
//!     email: Option<String>,
//! }
//!
//! # async fn example(mut conn: sqlx_mssql_odbc::MssqlConnection)
//! #     -> Result<(), Box<dyn std::error::Error>>
//! # {
//! let users = sqlx_mssql_odbc::query_as!(User, "SELECT id, name, email FROM users")
//!     .fetch_all(&mut conn)
//!     .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Transactions
//!
//! ```no_run
//! use sqlx_core::connection::Connection;
//! use sqlx_core::executor::Executor;
//! use sqlx_mssql_odbc::MssqlConnection;
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
//! let mut conn = MssqlConnection::connect("mssql://…").await?;
//!
//! conn.begin().await?;
//! sqlx_core::query::query("INSERT INTO users (name) VALUES (@p1)")
//!     .bind("Alice")
//!     .execute(&mut conn)
//!     .await?;
//! conn.commit().await?;
//! # Ok(())
//! # }
//! ```
//!
//! # URL parameters
//!
//! | Parameter | Description |
//! |---|---|
//! | `encrypt=true` | Enable TLS encryption |
//! | `trust_certificate=true` | Skip certificate validation |
//! | `driver=…` | Custom ODBC driver name (default: `ODBC Driver 18 for SQL Server`) |
//!
//! # Requirements
//!
//! On Linux and macOS you need both a driver manager (unixODBC) and the
//! Microsoft ODBC Driver for SQL Server (version 17 or 18). See the
//! [repository README](https://github.com/strawberyy-coconut/sqlx-mssql-odbc)
//! for platform-specific installation instructions.
//!
//! Enable the `vendored-unix-odbc` feature to statically link unixODBC into
//! your application on Linux or macOS.
//!
//! # Features
//!
//! | Feature | Description |
//! |---|---|
//! | `bigdecimal` | [`BigDecimal`] type support |
//! | `chrono` | [`chrono`] datetime types |
//! | `rust_decimal` / `decimal` | [`rust_decimal::Decimal`] support |
//! | `json` | [`serde_json::Value`] support |
//! | `time` | [`time`] crate datetime types |
//! | `uuid` | [`uuid::Uuid`] support |
//! | `macros` | `query!()`, `query_as!()` and other proc macros |
//! | `derive` | `Encode`, `Decode`, `Type`, `FromRow` derive macros |
//! | `offline` | Compile-time query checking with `query!()` |
//! | `migrate` | Database migration support |
//! | `runtime-tokio` | Tokio runtime support |
//! | `tls-none` | No TLS (default) |
//! | `spatial` | [`geo_types`] spatial type support |
//! | `vendored-unix-odbc` | Statically link unixODBC |

#![cfg_attr(docsrs, feature(doc_cfg))]

// Re-export everything from sqlx-mssql-odbc-core.
pub use sqlx_mssql_odbc_core::*;

/// Re-export of the core crate for direct access.
pub use sqlx_mssql_odbc_core as core;

// ---------------------------------------------------------------------------
// Macro wrappers — only available with the `macros` feature
// ---------------------------------------------------------------------------

#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use sqlx_mssql_odbc_macros::expand_query;

/// Compile-time checked SQL query for MSSQL via ODBC.
///
/// The SQL is sent to a live database at compile time so column names and
/// types are verified. The returned row lets you access columns as named
/// fields with correct Rust types — no runtime mapping needed.
///
/// # Without parameters
///
/// ```ignore
/// # use sqlx_mssql_odbc::MssqlConnection;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let mut conn = MssqlConnection::connect("…").await?;
///
/// let row = sqlx_mssql_odbc::query!("SELECT id, name, email FROM users WHERE id = 1")
///     .fetch_one(&mut conn)
///     .await?;
///
/// // Fields are checked at compile time — typos become compile errors!
/// println!("{} <{}>", row.name, row.email.unwrap_or_default());
/// # Ok(())
/// # }
/// ```
///
/// # With parameters
///
/// Bind parameters with `@p1`, `@p2`, etc. The macro infers types from the
/// Rust expressions:
///
/// ```ignore
/// # use sqlx_mssql_odbc::MssqlConnection;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut conn = MssqlConnection::connect("…").await?;
/// let user_id = 42;
/// let rows = sqlx_mssql_odbc::query!(
///     "SELECT id, name FROM users WHERE id = @p1 OR name LIKE @p2",
///     user_id,
///     "%Smith%"
/// )
///     .fetch_all(&mut conn)
///     .await?;
/// # Ok(())
/// # }
/// ```
///
/// # Inferring multiple result columns
///
/// ```ignore
/// # use sqlx_mssql_odbc::MssqlConnection;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut conn = MssqlConnection::connect("…").await?;
/// let row = sqlx_mssql_odbc::query!("SELECT COUNT(*) AS count, AVG(age) AS avg_age FROM users")
///     .fetch_one(&mut conn)
///     .await?;
/// println!("{} users, average age {}", row.count, row.avg_age);
/// # Ok(())
/// # }
/// ```
///
/// Requires the `macros` feature and a live database (or a prepared offline
/// cache via `cargo sqlx prepare`).
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
#[macro_export]
macro_rules! query {
    ($query:expr) => ({
        $crate::expand_query!(source = $query)
    });
    ($query:expr, $($args:tt)*) => ({
        $crate::expand_query!(source = $query, args = [$($args)*])
    });
}

/// Compile-time checked SQL query for MSSQL via ODBC, mapping to a named struct.
///
/// Like [`query!`] but deserialises each row into a struct you provide. The
/// struct fields are matched to columns by name and their types are checked
/// against the database schema at compile time.
///
/// ```ignore
/// # use sqlx_mssql_odbc::MssqlConnection;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut conn = MssqlConnection::connect("…").await?;
/// struct User {
///     id: i32,
///     name: String,
/// }
///
/// let users = sqlx_mssql_odbc::query_as!(User, "SELECT id, name FROM users")
///     .fetch_all(&mut conn)
///     .await?;
///
/// for user in users {
///     println!("{}: {}", user.id, user.name);
/// }
/// # Ok(())
/// # }
/// ```
///
/// Combine with the `derive` feature's `FromRow` derive to avoid manually
/// writing struct definitions:
///
/// ```ignore
/// # use sqlx_mssql_odbc::{MssqlConnection, FromRow};
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut conn = MssqlConnection::connect("…").await?;
/// #[derive(Debug, FromRow)]
/// struct Order {
///     id: i32,
///     total: rust_decimal::Decimal,
///     placed_at: chrono::NaiveDateTime,
/// }
///
/// let orders = sqlx_mssql_odbc::query_as!(Order, "SELECT id, total, placed_at FROM orders")
///     .fetch_all(&mut conn)
///     .await?;
/// # Ok(())
/// # }
/// ```
///
/// Requires the `macros` feature.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
#[macro_export]
macro_rules! query_as {
    ($out_struct:path, $query:expr) => ({
        $crate::expand_query!(record = $out_struct, source = $query)
    });
    ($out_struct:path, $query:expr, $($args:tt)*) => ({
        $crate::expand_query!(record = $out_struct, source = $query, args = [$($args)*])
    });
}

/// Compile-time checked SQL query for MSSQL via ODBC, returning a single scalar
/// value.
///
/// ```ignore
/// # use sqlx_mssql_odbc::MssqlConnection;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut conn = MssqlConnection::connect("…").await?;
/// let count: i64 = sqlx_mssql_odbc::query_scalar!("SELECT COUNT(*) FROM users")
///     .fetch_one(&mut conn)
///     .await?;
///
/// let max_id: Option<i32> = sqlx_mssql_odbc::query_scalar!("SELECT MAX(id) FROM users")
///     .fetch_optional(&mut conn)
///     .await?;
/// # Ok(())
/// # }
/// ```
///
/// Requires the `macros` feature.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
#[macro_export]
macro_rules! query_scalar {
    ($query:expr) => (
        $crate::expand_query!(scalar = _, source = $query)
    );
    ($query:expr, $($args:tt)*) => (
        $crate::expand_query!(scalar = _, source = $query, args = [$($args)*])
    );
}

/// Compile-time checked SQL query read from a file at compile time.
///
/// The file path is relative to the crate root. This keeps large queries out
/// of your Rust source files.
///
/// ```ignore
/// # use sqlx_mssql_odbc::MssqlConnection;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut conn = MssqlConnection::connect("…").await?;
/// let reports = sqlx_mssql_odbc::query_file!("queries/monthly_report.sql")
///     .fetch_all(&mut conn)
///     .await?;
/// # Ok(())
/// # }
/// ```
///
/// Requires the `macros` feature.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
#[macro_export]
macro_rules! query_file {
    ($path:literal) => ({
        $crate::expand_query!(source_file = $path)
    });
    ($path:literal, $($args:tt)*) => ({
        $crate::expand_query!(source_file = $path, args = [$($args)*])
    });
}

/// Compile-time checked SQL query read from a file, mapping to a named struct.
///
/// Combines [`query_file!`] and [`query_as!`]: the SQL lives in a separate
/// `.sql` file and rows are deserialised into the given struct.
///
/// ```ignore
/// # use sqlx_mssql_odbc::MssqlConnection;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut conn = MssqlConnection::connect("…").await?;
/// struct UserReport {
///     name: String,
///     order_count: i64,
/// }
///
/// let reports = sqlx_mssql_odbc::query_file_as!(UserReport, "queries/user_reports.sql")
///     .fetch_all(&mut conn)
///     .await?;
/// # Ok(())
/// # }
/// ```
///
/// Requires the `macros` feature.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
#[macro_export]
macro_rules! query_file_as {
    ($out_struct:path, $path:literal) => ({
        $crate::expand_query!(record = $out_struct, source_file = $path)
    });
    ($out_struct:path, $path:literal, $($args:tt)*) => ({
        $crate::expand_query!(record = $out_struct, source_file = $path, args = [$($args)*])
    });
}

/// Compile-time checked SQL query read from a file, returning a single scalar.
///
/// Like [`query_file!`] but returns a single value — useful for report
/// totals, row counts, or other aggregate queries stored in files.
///
/// ```ignore
/// # use sqlx_mssql_odbc::MssqlConnection;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut conn = MssqlConnection::connect("…").await?;
/// let total: f64 = sqlx_mssql_odbc::query_file_scalar!("queries/total_revenue.sql")
///     .fetch_one(&mut conn)
///     .await?;
/// # Ok(())
/// # }
/// ```
///
/// Requires the `macros` feature.
#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
#[macro_export]
macro_rules! query_file_scalar {
    ($path:literal) => (
        $crate::expand_query!(scalar = _, source_file = $path)
    );
    ($path:literal, $($args:tt)*) => (
        $crate::expand_query!(scalar = _, source_file = $path, args = [$($args)*])
    );
}

// Re-export derive macros behind `derive` feature.
#[cfg(feature = "derive")]
#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
pub use sqlx_mssql_odbc_macros::{Encode, Decode, Type, FromRow};