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}