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