mysql/lib.rs
1// Copyright (c) 2020 rust-mysql-simple contributors
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9//! This crate offers:
10//!
11//! * MySql database driver in pure rust;
12//! * connection pool.
13//!
14//! Features:
15//!
16//! * macOS, Windows and Linux support;
17//! * TLS support via **native-tls** or **rustls** (see the [SSL Support](#ssl-support) section);
18//! * MySql text protocol support, i.e. support of simple text queries and text result sets;
19//! * MySql binary protocol support, i.e. support of prepared statements and binary result sets;
20//! * support of multi-result sets;
21//! * support of named parameters for prepared statements (see the [Named Parameters](#named-parameters) section);
22//! * per-connection cache of prepared statements (see the [Statement Cache](#statement-cache) section);
23//! * buffer pool (see the [Buffer Pool](#buffer-pool) section);
24//! * support of MySql packets larger than 2^24;
25//! * support of Unix sockets and Windows named pipes;
26//! * support of custom LOCAL INFILE handlers;
27//! * support of MySql protocol compression;
28//! * support of auth plugins:
29//! * **mysql_native_password** - for MySql prior to v8;
30//! * **caching_sha2_password** - for MySql v8 and higher;
31//! * **mysql_clear_password** - opt-in (see [`Opts::get_enable_cleartext_plugin`].
32//!
33//! ## Installation
34//!
35//! Put the desired version of the crate into the `dependencies` section of your `Cargo.toml`:
36//!
37//! ```toml
38//! [dependencies]
39//! mysql = "*"
40//! ```
41//!
42//! ## Example
43//!
44//! ```rust
45//! use mysql::*;
46//! use mysql::prelude::*;
47//!
48//! #[derive(Debug, PartialEq, Eq)]
49//! struct Payment {
50//! customer_id: i32,
51//! amount: i32,
52//! account_name: Option<String>,
53//! }
54//!
55//! # def_get_opts!();
56//!
57//! fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
58//! let url = "mysql://root:password@localhost:3307/db_name";
59//! # Opts::try_from(url)?;
60//! # let url = get_opts();
61//! let pool = Pool::new(url)?;
62//!
63//! let mut conn = pool.get_conn()?;
64//!
65//! // Let's create a table for payments.
66//! conn.query_drop(
67//! r"CREATE TEMPORARY TABLE payment (
68//! customer_id int not null,
69//! amount int not null,
70//! account_name text
71//! )")?;
72//!
73//! let payments = vec![
74//! Payment { customer_id: 1, amount: 2, account_name: None },
75//! Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) },
76//! Payment { customer_id: 5, amount: 6, account_name: None },
77//! Payment { customer_id: 7, amount: 8, account_name: None },
78//! Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) },
79//! ];
80//!
81//! // Now let's insert payments to the database
82//! conn.exec_batch(
83//! r"INSERT INTO payment (customer_id, amount, account_name)
84//! VALUES (:customer_id, :amount, :account_name)",
85//! payments.iter().map(|p| params! {
86//! "customer_id" => p.customer_id,
87//! "amount" => p.amount,
88//! "account_name" => &p.account_name,
89//! })
90//! )?;
91//!
92//! // Let's select payments from database. Type inference should do the trick here.
93//! let selected_payments = conn
94//! .query_map(
95//! "SELECT customer_id, amount, account_name from payment",
96//! |(customer_id, amount, account_name)| {
97//! Payment { customer_id, amount, account_name }
98//! },
99//! )?;
100//!
101//! // Let's make sure, that `payments` equals to `selected_payments`.
102//! // Mysql gives no guaranties on order of returned rows
103//! // without `ORDER BY`, so assume we are lucky.
104//! assert_eq!(payments, selected_payments);
105//! println!("Yay!");
106//!
107//! Ok(())
108//! }
109//! ```
110//!
111//! ## Crate Features
112//!
113//! * feature sets:
114//!
115//! * **default** – includes `buffer-pool` `flate2/zlib` and `derive`
116//! * **default-rust** - same as `default` but with `flate2/rust_backend` instead of `flate2/zlib`
117//! * **minimal** - includes `flate2/zlib` only
118//! * **minimal-rust** - includes `flate2/rust_backend` only
119//!
120//! * features:
121//! * **buffer-pool** – enables buffer pooling
122//! (see the [Buffer Pool](#buffer-pool) section)
123//! * **derive** – reexports derive macros under `prelude`
124//! (see [corresponding section][derive_docs] in the `mysql_common` documentation)
125//!
126//! * TLS/SSL related features:
127//!
128//! * **native-tls** – specifies `native-tls` as the TLS backend
129//! (see the [SSL Support](#ssl-support) section)
130//! * **rustls-tls** – specifies `rustls` as the TLS backend using `aws-lc-rs` crypto provider
131//! (see the [SSL Support](#ssl-support) section)
132//! * **rustls-tls-ring** – specifies `rustls` as the TLS backend using `ring` crypto provider
133//! (see the [SSL Support](#ssl-support) section)
134//! * **rustls** - specifies `rustls` as the TLS backend without crypto provider
135//! (see the [SSL Support](#ssl-support) section)
136//!
137//! * features proxied from `mysql_common`:
138//!
139//! * **derive** - see [this table][common_features].
140//! * **chrono** - see [this table][common_features].
141//! * **time** - see [this table][common_features].
142//! * **bigdecimal** - see [this table][common_features].
143//! * **rust_decimal** - see [this table][common_features].
144//! * **frunk** - see [this table][common_features].
145//! * **binlog** - see [this table][common_features].
146//!
147//! Please note, that you'll need to reenable required features if you are using `default-features = false`:
148//!
149//! ```toml
150//! [dependencies]
151//! # Lets say that we want to use only the `rustls-tls` feature:
152//! mysql = { version = "*", default-features = false, features = ["minimal-rust", "rustls-tls"] }
153//! ```
154//!
155//! ## API Documentation
156//!
157//! Please refer to the [crate docs].
158//!
159//! ## Basic structures
160//!
161//! ### `Opts`
162//!
163//! This structure holds server host name, client username/password and other settings,
164//! that controls client behavior.
165//!
166//! #### URL-based connection string
167//!
168//! Note, that you can use URL-based connection string as a source of an `Opts` instance.
169//! URL schema must be `mysql`. Host, port and credentials, as well as query parameters,
170//! should be given in accordance with the RFC 3986.
171//!
172//! Examples:
173//!
174//! ```rust
175//! # mysql::doctest_wrapper!(__result, {
176//! # use mysql::Opts;
177//! let _ = Opts::from_url("mysql://localhost/some_db")?;
178//! let _ = Opts::from_url("mysql://[::1]/some_db")?;
179//! let _ = Opts::from_url("mysql://user:pass%20word@127.0.0.1:3307/some_db?")?;
180//! # });
181//! ```
182//!
183//! Supported URL parameters (for the meaning of each field please refer to the docs on `Opts`
184//! structure in the create API docs):
185//!
186//! * `user: string` – MySql client user name
187//! * `password: string` – MySql client password;
188//! * `db_name: string` – MySql database name;
189//! * `host: Host` – MySql server hostname/ip;
190//! * `port: u16` – MySql server port;
191//! * `pool_min: usize` – see [`PoolConstraints::min`];
192//! * `pool_max: usize` – see [`PoolConstraints::max`];
193//! * `prefer_socket: true | false` - see [`Opts::get_prefer_socket`];
194//! * `tcp_keepalive_time_ms: u32` - defines the value (in milliseconds)
195//! of the `tcp_keepalive_time` field in the `Opts` structure;
196//! * `tcp_keepalive_probe_interval_secs: u32` - defines the value
197//! of the `tcp_keepalive_probe_interval_secs` field in the `Opts` structure;
198//! * `tcp_keepalive_probe_count: u32` - defines the value
199//! of the `tcp_keepalive_probe_count` field in the `Opts` structure;
200//! * `tcp_connect_timeout_ms: u64` - defines the value (in milliseconds)
201//! of the `tcp_connect_timeout` field in the `Opts` structure;
202//! * `tcp_user_timeout_ms` - defines the value (in milliseconds)
203//! of the `tcp_user_timeout` field in the `Opts` structure;
204//! * `stmt_cache_size: u32` - defines the value of the same field in the `Opts` structure;
205//! * `enable_cleartext_plugin` – see [`Opts::get_enable_cleartext_plugin`];
206//! * `secure_auth` – see [`Opts::get_secure_auth`];
207//! * `reset_connection` – see [`PoolOpts::reset_connection`];
208//! * `check_health` – see [`PoolOpts::check_health`];
209//! * `compress` - defines the value of the same field in the `Opts` structure.
210//! Supported value are:
211//! * `true` - enables compression with the default compression level;
212//! * `fast` - enables compression with "fast" compression level;
213//! * `best` - enables compression with "best" compression level;
214//! * `1`..`9` - enables compression with the given compression level.
215//! * `socket` - socket path on UNIX, or pipe name on Windows.
216//!
217//! ### `OptsBuilder`
218//!
219//! It's a convenient builder for the `Opts` structure. It defines setters for fields
220//! of the `Opts` structure.
221//!
222//! ```no_run
223//! # mysql::doctest_wrapper!(__result, {
224//! # use mysql::*;
225//! let opts = OptsBuilder::new()
226//! .user(Some("foo"))
227//! .db_name(Some("bar"));
228//! let _ = Conn::new(opts)?;
229//! # });
230//! ```
231//!
232//! ### `Conn`
233//!
234//! This structure represents an active MySql connection. It also holds statement cache
235//! and metadata for the last result set.
236//!
237//! Conn's destructor will gracefully disconnect it from the server.
238//!
239//! ### `Transaction`
240//!
241//! It's a simple wrapper on top of a routine, that starts with `START TRANSACTION`
242//! and ends with `COMMIT` or `ROLLBACK`.
243//!
244//! ```
245//! # mysql::doctest_wrapper!(__result, {
246//! use mysql::*;
247//! use mysql::prelude::*;
248//!
249//! let pool = Pool::new(get_opts())?;
250//! let mut conn = pool.get_conn()?;
251//!
252//! let mut tx = conn.start_transaction(TxOpts::default())?;
253//! tx.query_drop("CREATE TEMPORARY TABLE tmp (TEXT a)")?;
254//! tx.exec_drop("INSERT INTO tmp (a) VALUES (?)", ("foo",))?;
255//! let val: Option<String> = tx.query_first("SELECT a from tmp")?;
256//! assert_eq!(val.unwrap(), "foo");
257//! // Note, that transaction will be rolled back implicitly on Drop, if not committed.
258//! tx.rollback();
259//!
260//! let val: Option<String> = conn.query_first("SELECT a from tmp")?;
261//! assert_eq!(val, None);
262//! # });
263//! ```
264//!
265//! ### `Pool`
266//!
267//! It's a reference to a connection pool, that can be cloned and shared between threads.
268//!
269//! ```
270//! # mysql::doctest_wrapper!(__result, {
271//! use mysql::*;
272//! use mysql::prelude::*;
273//!
274//! use std::thread::spawn;
275//!
276//! let pool = Pool::new(get_opts())?;
277//!
278//! let handles = (0..4).map(|i| {
279//! spawn({
280//! let pool = pool.clone();
281//! move || {
282//! let mut conn = pool.get_conn()?;
283//! conn.exec_first::<u32, _, _>("SELECT ? * 10", (i,))
284//! .map(Option::unwrap)
285//! }
286//! })
287//! });
288//!
289//! let result: Result<Vec<u32>> = handles.map(|handle| handle.join().unwrap()).collect();
290//!
291//! assert_eq!(result.unwrap(), vec![0, 10, 20, 30]);
292//! # });
293//! ```
294//!
295//! ### `Statement`
296//!
297//! Statement, actually, is just an identifier coupled with statement metadata, i.e an information
298//! about its parameters and columns. Internally the `Statement` structure also holds additional
299//! data required to support named parameters (see bellow).
300//!
301//! ```
302//! # mysql::doctest_wrapper!(__result, {
303//! use mysql::*;
304//! use mysql::prelude::*;
305//!
306//! let pool = Pool::new(get_opts())?;
307//! let mut conn = pool.get_conn()?;
308//!
309//! let stmt = conn.prep("DO ?")?;
310//!
311//! // The prepared statement will return no columns.
312//! assert!(stmt.columns().is_empty());
313//!
314//! // The prepared statement have one parameter.
315//! let param = stmt.params().get(0).unwrap();
316//! assert_eq!(param.schema_str(), "");
317//! assert_eq!(param.table_str(), "");
318//! assert_eq!(param.name_str(), "?");
319//! # });
320//! ```
321//!
322//! ### `Value`
323//!
324//! This enumeration represents the raw value of a MySql cell. Library offers conversion between
325//! `Value` and different rust types via `FromValue` trait described below.
326//!
327//! #### `FromValue` trait
328//!
329//! This trait is reexported from **mysql_common** create. Please refer to its
330//! [crate docs][mysql_common docs] for the list of supported conversions.
331//!
332//! Trait offers conversion in two flavours:
333//!
334//! * `from_value(Value) -> T` - convenient, but panicking conversion.
335//!
336//! Note, that for any variant of `Value` there exist a type, that fully covers its domain,
337//! i.e. for any variant of `Value` there exist `T: FromValue` such that `from_value` will never
338//! panic. This means, that if your database schema is known, then it's possible to write your
339//! application using only `from_value` with no fear of runtime panic.
340//!
341//! * `from_value_opt(Value) -> Option<T>` - non-panicking, but less convenient conversion.
342//!
343//! This function is useful to probe conversion in cases, where source database schema
344//! is unknown.
345//!
346//! ```
347//! # mysql::doctest_wrapper!(__result, {
348//! use mysql::*;
349//! use mysql::prelude::*;
350//!
351//! let via_test_protocol: u32 = from_value(Value::Bytes(b"65536".to_vec()));
352//! let via_bin_protocol: u32 = from_value(Value::UInt(65536));
353//! assert_eq!(via_test_protocol, via_bin_protocol);
354//!
355//! let unknown_val = // ...
356//! # Value::Time(false, 10, 2, 30, 0, 0);
357//!
358//! // Maybe it is a float?
359//! let unknown_val = match from_value_opt::<f64>(unknown_val) {
360//! Ok(float) => {
361//! println!("A float value: {}", float);
362//! return Ok(());
363//! }
364//! Err(FromValueError(unknown_val)) => unknown_val,
365//! };
366//!
367//! // Or a string?
368//! let unknown_val = match from_value_opt::<String>(unknown_val) {
369//! Ok(string) => {
370//! println!("A string value: {}", string);
371//! return Ok(());
372//! }
373//! Err(FromValueError(unknown_val)) => unknown_val,
374//! };
375//!
376//! // Screw this, I'll simply match on it
377//! match unknown_val {
378//! val @ Value::NULL => {
379//! println!("An empty value: {:?}", from_value::<Option<u8>>(val))
380//! },
381//! val @ Value::Bytes(..) => {
382//! // It's non-utf8 bytes, since we already tried to convert it to String
383//! println!("Bytes: {:?}", from_value::<Vec<u8>>(val))
384//! }
385//! val @ Value::Int(..) => {
386//! println!("A signed integer: {}", from_value::<i64>(val))
387//! }
388//! val @ Value::UInt(..) => {
389//! println!("An unsigned integer: {}", from_value::<u64>(val))
390//! }
391//! Value::Float(..) => unreachable!("already tried"),
392//! val @ Value::Double(..) => {
393//! println!("A double precision float value: {}", from_value::<f64>(val))
394//! }
395//! val @ Value::Date(..) => {
396//! use time::PrimitiveDateTime;
397//! println!("A date value: {}", from_value::<PrimitiveDateTime>(val))
398//! }
399//! val @ Value::Time(..) => {
400//! use std::time::Duration;
401//! println!("A time value: {:?}", from_value::<Duration>(val))
402//! }
403//! }
404//! # });
405//! ```
406//!
407//! ### `Row`
408//!
409//! Internally `Row` is a vector of `Value`s, that also allows indexing by a column name/offset,
410//! and stores row metadata. Library offers conversion between `Row` and sequences of Rust types
411//! via `FromRow` trait described below.
412//!
413//! #### `FromRow` trait
414//!
415//! This trait is reexported from **mysql_common** create. Please refer to its
416//! [crate docs][mysql_common docs] for the list of supported conversions.
417//!
418//! This conversion is based on the `FromValue` and so comes in two similar flavours:
419//!
420//! * `from_row(Row) -> T` - same as `from_value`, but for rows;
421//! * `from_row_opt(Row) -> Option<T>` - same as `from_value_opt`, but for rows.
422//!
423//! [`Queryable`](#queryable)
424//! trait offers implicit conversion for rows of a query result,
425//! that is based on this trait.
426//!
427//! ```
428//! # mysql::doctest_wrapper!(__result, {
429//! use mysql::*;
430//! use mysql::prelude::*;
431//!
432//! let mut conn = Conn::new(get_opts())?;
433//!
434//! // Single-column row can be converted to a singular value:
435//! let val: Option<String> = conn.query_first("SELECT 'foo'")?;
436//! assert_eq!(val.unwrap(), "foo");
437//!
438//! // Example of a multi-column row conversion to an inferred type:
439//! let row = conn.query_first("SELECT 255, 256")?;
440//! assert_eq!(row, Some((255u8, 256u16)));
441//!
442//! // The FromRow trait does not support to-tuple conversion for rows with more than 12 columns,
443//! // but you can do this by hand using row indexing or `Row::take` method:
444//! let row: Row = conn.exec_first("select 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12", ())?.unwrap();
445//! for i in 0..row.len() {
446//! assert_eq!(row[i], Value::Int(i as i64));
447//! }
448//!
449//! // Another way to handle wide rows is to use HList (requires `mysql_common/frunk` feature)
450//! use frunk::{HList, hlist, hlist_pat};
451//! let query = "select 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15";
452//! type RowType = HList!(u8, u16, u32, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8);
453//! let first_three_columns = conn.query_map(query, |row: RowType| {
454//! // do something with the row (see the `frunk` crate documentation)
455//! let hlist_pat![c1, c2, c3, ...] = row;
456//! (c1, c2, c3)
457//! });
458//! assert_eq!(first_three_columns.unwrap(), vec![(0_u8, 1_u16, 2_u32)]);
459//!
460//! // Some unknown row
461//! let row: Row = conn.query_first(
462//! // ...
463//! # "SELECT 255, Null",
464//! )?.unwrap();
465//!
466//! for column in row.columns_ref() {
467//! // Cells in a row can be indexed by numeric index or by column name
468//! let column_value = &row[column.name_str().as_ref()];
469//!
470//! println!(
471//! "Column {} of type {:?} with value {:?}",
472//! column.name_str(),
473//! column.column_type(),
474//! column_value,
475//! );
476//! }
477//! # });
478//! ```
479//!
480//! ### `Params`
481//!
482//! Represents parameters of a prepared statement, but this type won't appear directly in your code
483//! because binary protocol API will ask for `T: Into<Params>`, where `Into<Params>` is implemented:
484//!
485//! * for tuples of `Into<Value>` types up to arity 12;
486//!
487//! **Note:** singular tuple requires extra comma, e.g. `("foo",)`;
488//!
489//! * for `IntoIterator<Item: Into<Value>>` for cases, when your statement takes more
490//! than 12 parameters;
491//! * for named parameters representation (the value of the `params!` macro, described below).
492//!
493//! ```
494//! # mysql::doctest_wrapper!(__result, {
495//! use mysql::*;
496//! use mysql::prelude::*;
497//!
498//! let mut conn = Conn::new(get_opts())?;
499//!
500//! // Singular tuple requires extra comma:
501//! let row: Option<u8> = conn.exec_first("SELECT ?", (0,))?;
502//! assert_eq!(row.unwrap(), 0);
503//!
504//! // More than 12 parameters:
505//! let row: Option<u8> = conn.exec_first(
506//! "SELECT CONVERT(? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ? + ?, UNSIGNED)",
507//! (0..16).collect::<Vec<_>>(),
508//! )?;
509//! assert_eq!(row.unwrap(), 120);
510//! # });
511//! ```
512//!
513//! **Note:** Please refer to the [**mysql_common** crate docs][mysql_common docs] for the list
514//! of types, that implements `Into<Value>`.
515//!
516//! #### `Serialized`, `Deserialized`
517//!
518//! Wrapper structures for cases, when you need to provide a value for a JSON cell,
519//! or when you need to parse JSON cell as a struct.
520//!
521//! ```rust
522//! # mysql::doctest_wrapper!(__result, {
523//! use mysql::*;
524//! use mysql::prelude::*;
525//! use serde::{Deserialize, Serialize};
526//!
527//! /// Serializable structure.
528//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
529//! struct Example {
530//! foo: u32,
531//! }
532//!
533//! // Value::from for Serialized will emit json string.
534//! let value = Value::from(Serialized(Example { foo: 42 }));
535//! assert_eq!(value, Value::Bytes(br#"{"foo":42}"#.to_vec()));
536//!
537//! // from_value for Deserialized will parse json string.
538//! let structure: Deserialized<Example> = from_value(value);
539//! assert_eq!(structure, Deserialized(Example { foo: 42 }));
540//! # });
541//! ```
542//!
543//! ### [`QueryResult`]
544//!
545//! It's an iterator over rows of a query result with support of multi-result sets. It's intended
546//! for cases when you need full control during result set iteration. For other cases
547//! [`Queryable`](#queryable) provides a set of methods that will immediately consume
548//! the first result set and drop everything else.
549//!
550//! This iterator is lazy so it won't read the result from server until you iterate over it.
551//! MySql protocol is strictly sequential, so `Conn` will be mutably borrowed until the result
552//! is fully consumed (please also look at [`QueryResult::iter`] docs).
553//!
554//! ```rust
555//! # mysql::doctest_wrapper!(__result, {
556//! use mysql::*;
557//! use mysql::prelude::*;
558//!
559//! let mut conn = Conn::new(get_opts())?;
560//!
561//! // This query will emit two result sets.
562//! let mut result = conn.query_iter("SELECT 1, 2; SELECT 3, 3.14;")?;
563//!
564//! let mut sets = 0;
565//! while let Some(result_set) = result.iter() {
566//! sets += 1;
567//!
568//! println!("Result set columns: {:?}", result_set.columns());
569//! println!(
570//! "Result set meta: {}, {:?}, {} {}",
571//! result_set.affected_rows(),
572//! result_set.last_insert_id(),
573//! result_set.warnings(),
574//! result_set.info_str(),
575//! );
576//!
577//! for row in result_set {
578//! match sets {
579//! 1 => {
580//! // First result set will contain two numbers.
581//! assert_eq!((1_u8, 2_u8), from_row(row?));
582//! }
583//! 2 => {
584//! // Second result set will contain a number and a float.
585//! assert_eq!((3_u8, 3.14), from_row(row?));
586//! }
587//! _ => unreachable!(),
588//! }
589//! }
590//! }
591//!
592//! assert_eq!(sets, 2);
593//! # });
594//! ```
595//!
596//! ## Text protocol
597//!
598//! MySql text protocol is implemented in the set of `Queryable::query*` methods. It's useful when your
599//! query doesn't have parameters.
600//!
601//! **Note:** All values of a text protocol result set will be encoded as strings by the server,
602//! so `from_value` conversion may lead to additional parsing costs.
603//!
604//! Examples:
605//!
606//! ```rust
607//! # mysql::doctest_wrapper!(__result, {
608//! # use mysql::*;
609//! # use mysql::prelude::*;
610//! let pool = Pool::new(get_opts())?;
611//! let val = pool.get_conn()?.query_first("SELECT POW(2, 16)")?;
612//!
613//! // Text protocol returns bytes even though the result of POW
614//! // is actually a floating point number.
615//! assert_eq!(val, Some(Value::Bytes("65536".as_bytes().to_vec())));
616//! # });
617//! ```
618//!
619//! ### The `TextQuery` trait.
620//!
621//! The `TextQuery` trait covers the set of `Queryable::query*` methods from the perspective
622//! of a query, i.e. `TextQuery` is something, that can be performed if suitable connection
623//! is given. Suitable connections are:
624//!
625//! * `&Pool`
626//! * `Conn`
627//! * `PooledConn`
628//! * `&mut Conn`
629//! * `&mut PooledConn`
630//! * `&mut Transaction`
631//!
632//! The unique characteristic of this trait, is that you can give away the connection
633//! and thus produce `QueryResult` that satisfies `'static`:
634//!
635//! ```rust
636//! # mysql::doctest_wrapper!(__result, {
637//! use mysql::*;
638//! use mysql::prelude::*;
639//!
640//! fn iter(pool: &Pool) -> Result<impl Iterator<Item=Result<u32>>> {
641//! let result = "SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3".run(pool)?;
642//! Ok(result.map(|row| row.map(from_row)))
643//! }
644//!
645//! let pool = Pool::new(get_opts())?;
646//!
647//! let it = iter(&pool)?;
648//!
649//! assert_eq!(it.collect::<Result<Vec<u32>>>()?, vec![1, 2, 3]);
650//! # });
651//! ```
652//!
653//! ## Binary protocol and prepared statements.
654//!
655//! MySql binary protocol is implemented in `prep`, `close` and the set of `exec*` methods,
656//! defined on the [`Queryable`](#queryable) trait. Prepared statements is the only way to
657//! pass rust value to the MySql server. MySql uses `?` symbol as a parameter placeholder
658//! and it's only possible to use parameters where a single MySql value is expected.
659//! For example:
660//!
661//! ```rust
662//! # mysql::doctest_wrapper!(__result, {
663//! # use mysql::*;
664//! # use mysql::prelude::*;
665//! let pool = Pool::new(get_opts())?;
666//! let val = pool.get_conn()?.exec_first("SELECT POW(?, ?)", (2, 16))?;
667//!
668//! assert_eq!(val, Some(Value::Double(65536.0)));
669//! # });
670//! ```
671//!
672//! ### Statements
673//!
674//! In MySql each prepared statement belongs to a particular connection and can't be executed
675//! on another connection. Trying to do so will lead to an error. The driver won't tie statement
676//! to its connection in any way, but one can look on to the connection id, contained
677//! in the `Statement` structure.
678//!
679//! ```rust
680//! # mysql::doctest_wrapper!(__result, {
681//! # use mysql::*;
682//! # use mysql::prelude::*;
683//! let pool = Pool::new(get_opts())?;
684//!
685//! let mut conn_1 = pool.get_conn()?;
686//! let mut conn_2 = pool.get_conn()?;
687//!
688//! let stmt_1 = conn_1.prep("SELECT ?")?;
689//!
690//! // stmt_1 is for the conn_1, ..
691//! assert!(stmt_1.connection_id() == conn_1.connection_id());
692//! assert!(stmt_1.connection_id() != conn_2.connection_id());
693//!
694//! // .. so stmt_1 will execute only on conn_1
695//! assert!(conn_1.exec_drop(&stmt_1, ("foo",)).is_ok());
696//! assert!(conn_2.exec_drop(&stmt_1, ("foo",)).is_err());
697//! # });
698//! ```
699//!
700//! ### Statement cache
701//!
702//! #### Note
703//!
704//! Statement cache only works for:
705//! 1. for raw [`Conn`]
706//! 2. for [`PooledConn`]:
707//! * within its lifetime if [`PoolOpts::reset_connection`] is `true`
708//! * within the lifetime of a wrapped [`Conn`] if [`PoolOpts::reset_connection`] is `false`
709//!
710//! #### Description
711//!
712//! `Conn` will manage the cache of prepared statements on the client side, so subsequent calls
713//! to prepare with the same statement won't lead to a client-server roundtrip. Cache size
714//! for each connection is determined by the `stmt_cache_size` field of the `Opts` structure.
715//! Statements, that are out of this boundary will be closed in LRU order.
716//!
717//! Statement cache is completely disabled if `stmt_cache_size` is zero.
718//!
719//! **Caveats:**
720//!
721//! * disabled statement cache means, that you have to close statements yourself using
722//! `Conn::close`, or they'll exhaust server limits/resources;
723//!
724//! * you should be aware of the [`max_prepared_stmt_count`][max_prepared_stmt_count]
725//! option of the MySql server. If the number of active connections times the value
726//! of `stmt_cache_size` is greater, than you could receive an error while preparing
727//! another statement.
728//!
729//! ### Named parameters
730//!
731//! MySql itself doesn't have named parameters support, so it's implemented on the client side.
732//! One should use `:name` as a placeholder syntax for a named parameter. Named parameters uses
733//! the following naming convention:
734//!
735//! * parameter name must start with either `_` or `a..z`
736//! * parameter name may continue with `_`, `a..z` and `0..9`
737//!
738//! Named parameters may be repeated within the statement, e.g `SELECT :foo, :foo` will require
739//! a single named parameter `foo` that will be repeated on the corresponding positions during
740//! statement execution.
741//!
742//! One should use the `params!` macro to build parameters for execution.
743//!
744//! **Note:** Positional and named parameters can't be mixed within the single statement.
745//!
746//! Examples:
747//!
748//! ```rust
749//! # mysql::doctest_wrapper!(__result, {
750//! # use mysql::*;
751//! # use mysql::prelude::*;
752//! let pool = Pool::new(get_opts())?;
753//!
754//! let mut conn = pool.get_conn()?;
755//! let stmt = conn.prep("SELECT :foo, :bar, :foo")?;
756//!
757//! let foo = 42;
758//!
759//! let val_13 = conn.exec_first(&stmt, params! { "foo" => 13, "bar" => foo })?.unwrap();
760//! // Short syntax is available when param name is the same as variable name:
761//! let val_42 = conn.exec_first(&stmt, params! { foo, "bar" => 13 })?.unwrap();
762//!
763//! assert_eq!((foo, 13, foo), val_42);
764//! assert_eq!((13, foo, 13), val_13);
765//! # });
766//! ```
767//!
768//! ### Buffer pool
769//!
770//! Crate uses the global lock-free buffer pool for the purpose of IO and data serialization/deserialization,
771//! that helps to avoid allocations for basic scenarios. You can control its characteristics using
772//! the following environment variables:
773//!
774//! * `RUST_MYSQL_BUFFER_POOL_CAP` (defaults to 128) – controls the pool capacity. Dropped buffer will
775//! be immediately deallocated if the pool is full. Set it to `0` to disable the pool at runtime.
776//!
777//! * `RUST_MYSQL_BUFFER_SIZE_CAP` (defaults to 4MiB) – controls the maximum capacity of a buffer
778//! stored in the pool. Capacity of a dropped buffer will be shrunk to this value when buffer
779//! is returned to the pool.
780//!
781//! To completely disable the pool (say you are using jemalloc) please remove the `buffer-pool` feature
782//! from the set of default crate features (see the [Crate Features](#crate-features) section).
783//!
784//! ### `BinQuery` and `BatchQuery` traits.
785//!
786//! `BinQuery` and `BatchQuery` traits covers the set of `Queryable::exec*` methods from
787//! the perspective of a query, i.e. `BinQuery` is something, that can be performed if suitable
788//! connection is given (see [`TextQuery`](#the-textquery-trait) section for the list
789//! of suitable connections).
790//!
791//! As with the [`TextQuery`](#the-textquery-trait) you can give away the connection and acquire
792//! `QueryResult` that satisfies `'static`.
793//!
794//! `BinQuery` is for prepared statements, and prepared statements requires a set of parameters,
795//! so `BinQuery` is implemented for `QueryWithParams` structure, that can be acquired, using
796//! `WithParams` trait.
797//!
798//! Example:
799//!
800//! ```rust
801//! # mysql::doctest_wrapper!(__result, {
802//! use mysql::*;
803//! use mysql::prelude::*;
804//!
805//! let pool = Pool::new(get_opts())?;
806//!
807//! let result: Option<(u8, u8, u8)> = "SELECT ?, ?, ?"
808//! .with((1, 2, 3)) // <- WithParams::with will construct an instance of QueryWithParams
809//! .first(&pool)?; // <- QueryWithParams is executed on the given pool
810//!
811//! assert_eq!(result.unwrap(), (1, 2, 3));
812//! # });
813//! ```
814//!
815//! The `BatchQuery` trait is a helper for batch statement execution. It's implemented for
816//! `QueryWithParams` where parameters is an iterator over parameters:
817//!
818//! ```rust
819//! # mysql::doctest_wrapper!(__result, {
820//! use mysql::*;
821//! use mysql::prelude::*;
822//!
823//! let pool = Pool::new(get_opts())?;
824//! let mut conn = pool.get_conn()?;
825//!
826//! "CREATE TEMPORARY TABLE batch (x INT)".run(&mut conn)?;
827//! "INSERT INTO batch (x) VALUES (?)"
828//! .with((0..3).map(|x| (x,))) // <- QueryWithParams constructed with an iterator
829//! .batch(&mut conn)?; // <- batch execution is preformed here
830//!
831//! let result: Vec<u8> = "SELECT x FROM batch".fetch(conn)?;
832//!
833//! assert_eq!(result, vec![0, 1, 2]);
834//! # });
835//! ```
836//!
837//! ### `Queryable`
838//!
839//! The `Queryable` trait defines common methods for `Conn`, `PooledConn` and `Transaction`.
840//! The set of basic methods consts of:
841//!
842//! * `query_iter` - basic methods to execute text query and get `QueryResult`;
843//! * `prep` - basic method to prepare a statement;
844//! * `exec_iter` - basic method to execute statement and get `QueryResult`;
845//! * `close` - basic method to close the statement;
846//!
847//! The trait also defines the set of helper methods, that is based on basic methods.
848//! These methods will consume only the first result set, other result sets will be dropped:
849//!
850//! * `{query|exec}` - to collect the result into a `Vec<T: FromRow>`;
851//! * `{query|exec}_first` - to get the first `T: FromRow`, if any;
852//! * `{query|exec}_map` - to map each `T: FromRow` to some `U`;
853//! * `{query|exec}_fold` - to fold the set of `T: FromRow` to a single value;
854//! * `{query|exec}_drop` - to immediately drop the result.
855//!
856//! The trait also defines the `exec_batch` function, which is a helper for batch statement
857//! execution.
858//!
859//! ## SSL Support
860//!
861//! SSL support comes in two flavors:
862//!
863//! 1. Based on the `native-tls` crate – native TLS backend.
864//!
865//! This uses the native OS SSL/TLS provider. Enabled by the **rustls-tls** feature.
866//!
867//! 2. Based on the `rustls` – TLS backend written in Rust. You have three options here:
868//!
869//! 1. **rustls-tls** feature enables `rustls` backend with `aws-lc-rs` crypto provider
870//! 2. **rustls-tls-ring** feature enables `rustls` backend with `ring` crypto provider
871//! 3. **rustls** feature enables `rustls` backend without crypto provider — you have to
872//! install your own provider to avoid "no process-level CryptoProvider available" error
873//! (see relevant section of the [`rustls` crate docs](https://docs.rs/rustls))
874//!
875//! Please also note a few things about **rustls**:
876//!
877//! * it will fail if you'll try to connect to the server by its IP address, hostname is required;
878//! * it, most likely, won't work on windows, at least with default server certs, generated by the
879//! MySql installer.
880//!
881//! [crate docs]: https://docs.rs/mysql
882//! [mysql_common docs]: https://docs.rs/mysql_common
883//! [max_prepared_stmt_count]: https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_max_prepared_stmt_count
884//! [derive_docs]: https://docs.rs/mysql_common/latest/mysql_common/#derive-macros
885//! [common_features]: https://docs.rs/mysql_common/latest/mysql_common/#crate-features
886
887#![cfg_attr(feature = "nightly", feature(test))]
888#![cfg_attr(docsrs, feature(doc_cfg))]
889#[cfg(feature = "nightly")]
890extern crate test;
891
892use mysql_common as myc;
893
894mod buffer_pool;
895mod conn;
896pub mod error;
897mod io;
898
899#[cfg(feature = "derive")]
900extern crate mysql_common;
901
902#[doc(inline)]
903pub use crate::myc::constants as consts;
904
905#[doc(inline)]
906pub use crate::myc::packets::{binlog_request::BinlogRequest, BinlogDumpFlags};
907
908#[cfg(feature = "binlog")]
909#[cfg_attr(docsrs, doc(cfg(feature = "binlog")))]
910pub mod binlog {
911 #[doc(inline)]
912 pub use crate::myc::binlog::consts::*;
913
914 #[doc(inline)]
915 pub use crate::myc::binlog::{events, jsonb, jsondiff, row, value};
916}
917
918#[cfg(any(feature = "native-tls", feature = "rustls"))]
919#[cfg_attr(
920 docsrs,
921 doc(cfg(any(
922 feature = "native-tls",
923 feature = "rustls-tls",
924 feature = "rustls-tls-ring"
925 )))
926)]
927#[doc(inline)]
928pub use crate::conn::opts::ClientIdentity;
929
930#[doc(inline)]
931pub use crate::myc::packets::{session_state_change, SessionStateInfo};
932
933#[cfg(feature = "binlog")]
934#[doc(inline)]
935pub use crate::conn::binlog_stream::BinlogStream;
936#[doc(inline)]
937pub use crate::conn::local_infile::{LocalInfile, LocalInfileHandler};
938#[doc(inline)]
939pub use crate::conn::opts::SslOpts;
940#[doc(inline)]
941pub use crate::conn::opts::{
942 pool_opts::{PoolConstraints, PoolOpts},
943 ChangeUserOpts, Opts, OptsBuilder, DEFAULT_STMT_CACHE_SIZE,
944};
945#[doc(inline)]
946pub use crate::conn::pool::{Pool, PooledConn};
947#[doc(inline)]
948pub use crate::conn::query::QueryWithParams;
949#[doc(inline)]
950pub use crate::conn::query_result::{Binary, QueryResult, ResultSet, SetColumns, Text};
951#[doc(inline)]
952pub use crate::conn::stmt::Statement;
953#[doc(inline)]
954pub use crate::conn::transaction::{AccessMode, IsolationLevel, Transaction, TxOpts};
955#[doc(inline)]
956pub use crate::conn::Conn;
957#[doc(inline)]
958pub use crate::error::{DriverError, Error, MySqlError, Result, ServerError, UrlError};
959#[doc(inline)]
960pub use crate::myc::packets::Column;
961#[doc(inline)]
962pub use crate::myc::params::Params;
963#[doc(inline)]
964pub use crate::myc::proto::codec::Compression;
965#[doc(inline)]
966pub use crate::myc::row::convert::{from_row, from_row_opt, FromRowError};
967#[doc(inline)]
968pub use crate::myc::row::Row;
969#[doc(inline)]
970pub use crate::myc::value::convert::{from_value, from_value_opt, FromValueError};
971#[doc(inline)]
972pub use crate::myc::value::json::{Deserialized, Serialized};
973#[doc(inline)]
974pub use crate::myc::value::Value;
975
976pub mod prelude {
977 #[doc(inline)]
978 pub use crate::conn::query::{BatchQuery, BinQuery, TextQuery, WithParams};
979 #[doc(inline)]
980 pub use crate::conn::queryable::{AsStatement, Queryable};
981 #[doc(inline)]
982 pub use crate::myc::prelude::FromRow;
983 #[doc(inline)]
984 pub use crate::myc::prelude::{FromValue, ToValue};
985 #[doc(inline)]
986 pub use crate::myc::row::ColumnIndex;
987
988 /// Trait for protocol markers [`crate::Binary`] and [`crate::Text`].
989 pub trait Protocol: crate::conn::query_result::Protocol {}
990 impl Protocol for crate::Binary {}
991 impl Protocol for crate::Text {}
992}
993
994#[doc(inline)]
995pub use crate::myc::params;
996
997#[doc(hidden)]
998#[macro_export]
999macro_rules! def_database_url {
1000 () => {
1001 if let Ok(url) = std::env::var("DATABASE_URL") {
1002 let opts = $crate::Opts::from_url(&url).expect("DATABASE_URL invalid");
1003 if opts
1004 .get_db_name()
1005 .expect("a database name is required")
1006 .is_empty()
1007 {
1008 panic!("database name is empty");
1009 }
1010 url
1011 } else {
1012 "mysql://root:password@localhost:3307/mysql".into()
1013 }
1014 };
1015}
1016
1017#[doc(hidden)]
1018#[macro_export]
1019macro_rules! def_get_opts {
1020 () => {
1021 pub fn test_ssl() -> bool {
1022 let ssl = std::env::var("SSL").ok().unwrap_or("false".into());
1023 ssl == "true" || ssl == "1"
1024 }
1025
1026 pub fn test_compression() -> bool {
1027 let compress = std::env::var("COMPRESS").ok().unwrap_or("false".into());
1028 compress == "true" || compress == "1"
1029 }
1030
1031 pub fn get_opts() -> $crate::OptsBuilder {
1032 let database_url = $crate::def_database_url!();
1033 let mut builder =
1034 $crate::OptsBuilder::from_opts($crate::Opts::from_url(&*database_url).unwrap())
1035 .init(vec!["SET GLOBAL sql_mode = 'TRADITIONAL'"])
1036 .connect_attrs::<String, String>(None);
1037 if test_compression() {
1038 builder = builder.compress(Some(Default::default()));
1039 }
1040 if test_ssl() {
1041 let ssl_opts = $crate::SslOpts::default()
1042 .with_danger_skip_domain_validation(true)
1043 .with_danger_accept_invalid_certs(true);
1044 builder = builder.prefer_socket(false).ssl_opts(ssl_opts);
1045 }
1046 builder
1047 }
1048 };
1049}
1050
1051#[doc(hidden)]
1052#[macro_export]
1053macro_rules! doctest_wrapper {
1054 ($body:block) => {
1055 fn fun() {
1056 $crate::def_get_opts!();
1057 $body;
1058 }
1059 fun()
1060 };
1061 (__result, $body:block) => {
1062 fn fun() -> std::result::Result<(), Box<dyn std::error::Error>> {
1063 $crate::def_get_opts!();
1064 Ok($body)
1065 }
1066 fun()
1067 };
1068}
1069
1070#[cfg(test)]
1071mod test_misc {
1072 use crate::{def_database_url, def_get_opts};
1073
1074 #[allow(dead_code)]
1075 fn error_should_implement_send_and_sync() {
1076 fn _dummy<T: Send + Sync>(_: T) {}
1077 _dummy(crate::error::Error::FromValueError(crate::Value::NULL));
1078 }
1079
1080 #[allow(dead_code)]
1081 fn database_url() {
1082 def_database_url!();
1083 }
1084
1085 def_get_opts!();
1086}