forked from transact-rs/sqlx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconnect.rs
More file actions
136 lines (124 loc) 路 4.66 KB
/
Copy pathconnect.rs
File metadata and controls
136 lines (124 loc) 路 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use crate::connection::ConnectOptions;
use crate::error::Error;
use crate::executor::Executor;
use crate::net::Socket;
use crate::{MySqlConnectOptions, MySqlConnection};
use log::LevelFilter;
use sqlx_core::sql_str::AssertSqlSafe;
use sqlx_core::Url;
use std::time::Duration;
impl MySqlConnectOptions {
/// Establish a fully initialized connection over a pre-connected socket.
///
/// This performs the MySQL handshake, authentication, and post-connect
/// initialization (`SET NAMES`, `sql_mode`, `time_zone`) over the
/// provided socket.
///
/// The socket must already be connected to a MySQL-compatible server.
/// This enables custom transports such as in-memory pipes, simulation
/// frameworks (e.g. turmoil), SSH tunnels, or SOCKS proxies.
///
/// # Example
///
/// ```rust,ignore
/// use sqlx::mysql::MySqlConnectOptions;
///
/// let options = MySqlConnectOptions::new()
/// .username("root")
/// .database("mydb");
///
/// let stream = tokio::net::TcpStream::connect("127.0.0.1:3306").await?;
/// let conn = options.connect_with_socket(stream).await?;
/// ```
pub async fn connect_with_socket<S: Socket>(
&self,
socket: S,
) -> Result<MySqlConnection, Error> {
let mut conn = MySqlConnection::connect_with_socket(self, socket).await?;
self.after_connect(&mut conn).await?;
Ok(conn)
}
/// Post-connection initialization shared between `connect()` and
/// `connect_with_socket()`.
///
/// After the connection is established, we initialize by configuring a few
/// connection parameters:
///
/// - <https://mariadb.com/kb/en/sql-mode/>
///
/// - `PIPES_AS_CONCAT` - Allows using the pipe character (ASCII 124) as string concatenation
/// operator. This means that "A" || "B" can be used in place of CONCAT("A", "B").
///
/// - `NO_ENGINE_SUBSTITUTION` - If not set, if the available storage engine specified by a
/// CREATE TABLE is not available, a warning is given and the default storage engine is used
/// instead.
///
/// - `NO_ZERO_DATE` - Don't allow '0000-00-00'. This is invalid in Rust.
///
/// - `NO_ZERO_IN_DATE` - Don't allow 'YYYY-00-00'. This is invalid in Rust.
///
/// Setting the time zone allows us to assume that the output from a TIMESTAMP field is UTC.
///
/// - <https://mathiasbynens.be/notes/mysql-utf8mb4>
async fn after_connect(&self, conn: &mut MySqlConnection) -> Result<(), Error> {
let mut sql_mode = Vec::new();
if self.pipes_as_concat {
sql_mode.push(r#"PIPES_AS_CONCAT"#);
}
if self.no_engine_substitution {
sql_mode.push(r#"NO_ENGINE_SUBSTITUTION"#);
}
let mut options = Vec::new();
if !sql_mode.is_empty() {
options.push(format!(
r#"sql_mode=(SELECT CONCAT(@@sql_mode, ',{}'))"#,
sql_mode.join(",")
));
}
if let Some(timezone) = &self.timezone {
options.push(format!(r#"time_zone='{}'"#, timezone));
}
if self.set_names {
// As it turns out, we don't _have_ to set a collation if we don't want to.
// We can let the server choose the default collation for the charset.
let set_names = if let Some(collation) = &self.collation {
format!(r#"NAMES {} COLLATE {collation}"#, self.charset,)
} else {
// Leaves the default collation up to the server,
// but ensures statements and results are encoded using the proper charset.
format!("NAMES {}", self.charset)
};
options.push(set_names);
}
if !options.is_empty() {
conn.execute(AssertSqlSafe(format!(r#"SET {};"#, options.join(","))))
.await?;
}
Ok(())
}
}
impl ConnectOptions for MySqlConnectOptions {
type Connection = MySqlConnection;
fn from_url(url: &Url) -> Result<Self, Error> {
Self::parse_from_url(url)
}
fn to_url_lossy(&self) -> Url {
self.build_url()
}
async fn connect(&self) -> Result<Self::Connection, Error>
where
Self::Connection: Sized,
{
let mut conn = MySqlConnection::establish(self).await?;
self.after_connect(&mut conn).await?;
Ok(conn)
}
fn log_statements(mut self, level: LevelFilter) -> Self {
self.log_settings.log_statements(level);
self
}
fn log_slow_statements(mut self, level: LevelFilter, duration: Duration) -> Self {
self.log_settings.log_slow_statements(level, duration);
self
}
}