Skip to main content

mssql_client/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![deny(unsafe_code)]
4
5// Module dependency graph (acyclic):
6//
7//   client ──→ config, state, error, stream, transaction, statement_cache
8//     ├── connect.rs ──→ config, state, instrumentation, mssql_tls, mssql_codec, tds_protocol
9//     ├── params.rs  ──→ mssql_types, tds_protocol
10//     └── response.rs ──→ error, mssql_codec, tds_protocol
11//   procedure ──→ client, error, state, stream, tds_protocol
12//   stream ──→ error, row
13//   row ──→ blob, error, mssql_types
14//   config ──→ mssql_auth, mssql_tls, tds_protocol
15//   bulk ──→ error, mssql_types, tds_protocol
16//   cancel ──→ error, mssql_codec, mssql_tls
17//   encryption ──→ mssql_auth, tds_protocol
18//   column_parser ──→ error, mssql_types, tds_protocol
19
20pub mod blob;
21pub mod blob_stream;
22pub(crate) mod browser;
23pub mod bulk;
24pub mod cancel;
25pub mod change_tracking;
26pub mod client;
27#[cfg(feature = "always-encrypted")]
28pub(crate) mod column_decryptor;
29pub(crate) mod column_parser;
30pub mod config;
31pub mod encryption;
32pub mod error;
33#[cfg(all(windows, feature = "filestream"))]
34#[allow(unsafe_code)] // Win32 FFI for OpenSqlFilestream; see SAFETY comments in each unsafe block
35pub mod filestream;
36pub mod from_row;
37pub mod instrumentation;
38pub(crate) mod plp;
39pub mod procedure;
40pub mod query;
41pub mod row;
42// Sans-IO incremental token decoder driving the streaming read path.
43pub(crate) mod row_source;
44pub mod row_stream;
45pub mod state;
46// Not yet wired into the query path (queries use sp_executesql); kept
47// crate-private until the cache is actually used, so the public API does not
48// expose types for an unshipped feature. Re-export when it lands.
49pub(crate) mod statement_cache;
50pub mod stream;
51pub mod to_params;
52pub mod transaction;
53pub mod tvp;
54pub(crate) mod validation;
55
56// Re-export commonly used types
57pub use bulk::{
58    BulkColumn, BulkInsert, BulkInsertBuilder, BulkInsertResult, BulkOptions, BulkWriter,
59};
60pub use cancel::CancelHandle;
61pub use client::Client;
62pub use config::{ApplicationIntent, Config, RedirectConfig, RetryPolicy, TimeoutConfig};
63pub use error::{Error, SharedIoError};
64// Sub-error types carried by `Error` variants and the `FromSql`/`ToSql` trait
65// return type. Re-exported so downstream crates can name them (e.g. match on
66// `Error::Type(e)`, or write `fn from_sql(..) -> Result<Self, TypeError>`)
67// without depending on the internal crates directly. `EncryptionError` is
68// intentionally NOT here: `Error` stringifies it (see `error.rs`) so key
69// material cannot leak, and it appears in no other public signature.
70pub use mssql_auth::AuthError;
71pub use mssql_codec::CodecError;
72#[cfg(feature = "tls")]
73pub use mssql_tls::TlsError;
74pub use mssql_types::TypeError;
75pub use tds_protocol::ProtocolError;
76
77// TLS configuration: re-export so the `Config::tls` field is usable (custom
78// root certificates, client auth) without a direct `mssql-tls` dependency.
79// `CertificateDer` is needed to add a root certificate.
80#[cfg(feature = "tls")]
81pub use mssql_tls::{CertificateDer, TlsConfig};
82
83// `KeyStoreProvider` extension trait: users implement it for custom Always
84// Encrypted key stores (per the encryption-module docs) without a direct
85// `mssql-auth` dependency.
86#[cfg(feature = "always-encrypted")]
87pub use mssql_auth::KeyStoreProvider;
88
89// `Collation` appears on `Column::collation` and the `with_collation` builders
90// (Column, BulkColumn); re-export so those are usable without a direct
91// `tds-protocol` dependency.
92pub use tds_protocol::token::Collation;
93
94// Derive macros, re-exported under the `derive` feature so users need only a
95// single `mssql-client` dependency (the macros' generated code resolves all
96// its paths through `mssql_client`, including `__private` below). The macro
97// names intentionally match the trait names — they live in the macro
98// namespace, so `#[derive(FromRow)]` and `impl FromRow` coexist (as with
99// serde's `Serialize`).
100#[cfg(feature = "derive")]
101pub use mssql_derive::{FromRow, ToParams, Tvp};
102
103/// Items the derive macros' generated code references. Not public API: hidden
104/// from docs and exempt from stability guarantees. Centralizing them here
105/// keeps the proc-macro crate decoupled from internal restructuring.
106#[doc(hidden)]
107pub mod __private {
108    pub use mssql_types::{ToSql, TypeError};
109}
110
111// Re-export TDS version for configuration
112pub use from_row::{FromRow, MapRows, RowIteratorExt};
113pub use mssql_auth::Credentials;
114pub use tds_protocol::version::TdsVersion;
115
116// Secure credential types (with zeroize feature)
117#[cfg(feature = "zeroize")]
118pub use mssql_auth::{SecretString, SecureCredentials};
119pub use mssql_types::{
120    Binary, Char, EncryptedParamType, FromSql, NChar, SqlTyped, SqlValue, ToSql, TypedNull, binary,
121    char, nchar, null,
122};
123#[cfg(feature = "chrono")]
124pub use mssql_types::{
125    DateTime2, DateTimeLegacy, DateTimeOffset, SmallDateTime, Time, datetime, datetime2,
126    datetimeoffset, time,
127};
128#[cfg(feature = "decimal")]
129pub use mssql_types::{Money, Numeric, SmallMoney, numeric};
130pub use procedure::ProcedureBuilder;
131pub use query::in_params;
132pub use row::{Column, Row};
133pub use state::{Connected, ConnectionState, Disconnected, InTransaction, ProtocolState, Ready};
134
135/// Internal entry points for the fuzzing harness in `fuzz/`.
136///
137/// Enabled only by the `fuzzing` feature; not public API and exempt from
138/// all stability guarantees.
139#[cfg(feature = "fuzzing")]
140#[doc(hidden)]
141pub mod __fuzzing {
142    pub use crate::column_parser::parse_column_value;
143}
144pub use blob_stream::BlobStream;
145pub use row_stream::RowStream;
146pub use stream::{
147    ExecuteResult, MultiResultStream, OutputParam, ProcedureResult, QueryStream, ResultSet,
148};
149pub use to_params::{NamedParam, ParamList, ToParams};
150pub use transaction::{IsolationLevel, SavePoint, Transaction};
151pub use tvp::{Tvp, TvpColumn, TvpRow, TvpValue};
152
153// FILESTREAM support (Windows only)
154#[cfg(all(windows, feature = "filestream"))]
155pub use filestream::{FileStream, FileStreamAccess, open_options as filestream_options};
156
157// Always Encrypted types
158pub use encryption::EncryptionConfig;
159
160// OpenTelemetry instrumentation (available whether or not otel feature is enabled)
161pub use instrumentation::{
162    DatabaseMetrics, OperationTimer, SanitizationConfig, attributes, metric_names, span_names,
163};
164
165// Change Tracking support
166pub use change_tracking::{
167    ChangeMetadata, ChangeOperation, ChangeTracking, ChangeTrackingQuery, SyncVersionStatus,
168};
169
170#[cfg(test)]
171mod auto_trait_tests {
172    //! Compile-time assertions that key async types are Send + Sync.
173    //!
174    //! These tests catch regressions where a type accidentally becomes
175    //! !Send or !Sync due to interior changes (e.g., adding an Rc, Cell,
176    //! or non-Send future). They cost nothing at runtime.
177
178    use super::*;
179
180    fn assert_send<T: Send>() {}
181    fn assert_sync<T: Sync>() {}
182
183    // --- Type-state Client variants ---
184    #[test]
185    fn client_ready_is_send_sync() {
186        assert_send::<Client<Ready>>();
187        assert_sync::<Client<Ready>>();
188    }
189
190    #[test]
191    fn client_in_transaction_is_send_sync() {
192        assert_send::<Client<InTransaction>>();
193        assert_sync::<Client<InTransaction>>();
194    }
195
196    #[test]
197    fn client_disconnected_is_send_sync() {
198        assert_send::<Client<Disconnected>>();
199        assert_sync::<Client<Disconnected>>();
200    }
201
202    #[test]
203    fn client_connected_is_send_sync() {
204        assert_send::<Client<Connected>>();
205        assert_sync::<Client<Connected>>();
206    }
207
208    // --- Configuration ---
209    #[test]
210    fn config_is_send_sync() {
211        assert_send::<Config>();
212        assert_sync::<Config>();
213    }
214
215    // --- Streaming types ---
216    #[test]
217    fn query_stream_is_send_sync() {
218        assert_send::<QueryStream<'_>>();
219        assert_sync::<QueryStream<'_>>();
220    }
221
222    #[test]
223    fn row_stream_is_send_sync() {
224        assert_send::<RowStream<'_>>();
225        assert_sync::<RowStream<'_>>();
226    }
227
228    #[test]
229    fn blob_stream_is_send_sync() {
230        assert_send::<BlobStream<'_>>();
231        assert_sync::<BlobStream<'_>>();
232    }
233
234    #[test]
235    fn multi_result_stream_is_send_sync() {
236        assert_send::<MultiResultStream<'_>>();
237        assert_sync::<MultiResultStream<'_>>();
238    }
239
240    #[test]
241    fn result_set_is_send_sync() {
242        assert_send::<ResultSet>();
243        assert_sync::<ResultSet>();
244    }
245
246    #[test]
247    fn execute_result_is_send_sync() {
248        assert_send::<ExecuteResult>();
249        assert_sync::<ExecuteResult>();
250    }
251
252    #[test]
253    fn procedure_result_is_send_sync() {
254        assert_send::<ProcedureResult>();
255        assert_sync::<ProcedureResult>();
256    }
257
258    #[test]
259    fn procedure_builder_is_send_sync() {
260        assert_send::<ProcedureBuilder<'_, Ready>>();
261        assert_sync::<ProcedureBuilder<'_, Ready>>();
262    }
263
264    // --- Bulk insert types ---
265    #[test]
266    fn bulk_insert_is_send_sync() {
267        assert_send::<BulkInsert>();
268        assert_sync::<BulkInsert>();
269    }
270
271    #[test]
272    fn bulk_insert_builder_is_send_sync() {
273        assert_send::<BulkInsertBuilder>();
274        assert_sync::<BulkInsertBuilder>();
275    }
276
277    #[test]
278    fn bulk_options_is_send_sync() {
279        assert_send::<BulkOptions>();
280        assert_sync::<BulkOptions>();
281    }
282
283    // --- Cancel handle ---
284    #[test]
285    fn cancel_handle_is_send_sync() {
286        assert_send::<CancelHandle>();
287        assert_sync::<CancelHandle>();
288    }
289
290    // --- Row and column types ---
291    #[test]
292    fn row_is_send_sync() {
293        assert_send::<Row>();
294        assert_sync::<Row>();
295    }
296
297    #[test]
298    fn column_is_send_sync() {
299        assert_send::<Column>();
300        assert_sync::<Column>();
301    }
302
303    // --- Statement cache (crate-private until wired) ---
304    #[test]
305    fn statement_cache_is_send_sync() {
306        use crate::statement_cache::StatementCache;
307        assert_send::<StatementCache>();
308        assert_sync::<StatementCache>();
309    }
310
311    // --- Error type ---
312    #[test]
313    fn error_is_send_sync() {
314        assert_send::<Error>();
315        assert_sync::<Error>();
316    }
317}