diesel/mariadb/connection.rs
1use crate::mariadb::Mariadb;
2
3/// A connection to a Mariadb database. Connection URLs should be in the form
4/// `mariadb://[user[:password]@]host/database_name[?unix_socket=socket-path]`
5///
6///* `host` can be an IP address or a hostname. If it is set to `localhost`, a connection
7/// will be attempted through the socket at `/tmp/mysql.sock`. If you want to connect to
8/// a local server via TCP (e.g. docker containers), use `0.0.0.0` or `127.0.0.1` instead.
9/// * `unix_socket` expects the path to the unix socket
10///
11/// Errors carry the SQLSTATE the server or client library reports in
12/// [`DatabaseErrorInformation::sqlstate`](crate::result::DatabaseErrorInformation::sqlstate),
13/// including custom codes raised with
14/// [`SIGNAL`](https://mariadb.com/docs/server/reference/sql-statements/programmatic-compound-statements/signal).
15/// The server reports `HY000` for errors without a specific SQLSTATE, as
16/// described at <https://mariadb.com/docs/server/reference/sql-statements/programmatic-compound-statements/programmatic-compound-statements-diagnostics/sqlstate>.
17///
18/// # Supported loading model implementations
19///
20/// * [`DefaultLoadingMode`](crate::connection::DefaultLoadingMode)
21///
22/// As `MariadbConnection` only supports a single loading mode implementation
23/// it is **not required** to explicitly specify a loading mode
24/// when calling [`RunQueryDsl::load_iter()`](crate::query_dsl::RunQueryDsl::load_iter)
25/// or [`LoadConnection::load`](crate::connection::LoadConnection::load)
26///
27/// ## DefaultLoadingMode
28///
29/// `MariadbConnection` only supports a single loading mode, which loads
30/// values row by row from the result set.
31///
32/// ```rust,dejadoc
33/// # include!("../doctest_setup.rs");
34/// #
35/// # fn main() {
36/// # run_test().unwrap();
37/// # }
38/// #
39/// # fn run_test() -> QueryResult<()> {
40/// # use schema::users;
41/// # let connection = &mut establish_connection();
42/// use diesel::connection::DefaultLoadingMode;
43/// { // scope to restrict the lifetime of the iterator
44/// let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
45///
46/// for r in iter1 {
47/// let (id, name) = r?;
48/// println!("Id: {} Name: {}", id, name);
49/// }
50/// }
51///
52/// // works without specifying the loading mode
53/// let iter2 = users::table.load_iter::<(i32, String), _>(connection)?;
54///
55/// for r in iter2 {
56/// let (id, name) = r?;
57/// println!("Id: {} Name: {}", id, name);
58/// }
59/// # Ok(())
60/// # }
61/// ```
62///
63/// This mode does **not support** creating
64/// multiple iterators using the same connection.
65///
66/// ```compile_fail,dejadoc
67/// # include!("../../doctest_setup.rs");
68/// #
69/// # fn main() {
70/// # run_test().unwrap();
71/// # }
72/// #
73/// # fn run_test() -> QueryResult<()> {
74/// # use schema::users;
75/// # let connection = &mut establish_connection();
76/// use diesel::connection::DefaultLoadingMode;
77///
78/// let iter1 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
79/// let iter2 = users::table.load_iter::<(i32, String), DefaultLoadingMode>(connection)?;
80///
81/// for r in iter1 {
82/// let (id, name) = r?;
83/// println!("Id: {} Name: {}", id, name);
84/// }
85///
86/// for r in iter2 {
87/// let (id, name) = r?;
88/// println!("Id: {} Name: {}", id, name);
89/// }
90/// # Ok(())
91/// # }
92/// ```
93pub type MariadbConnection = crate::mysql_like::MysqlLikeConnection<Mariadb>;
94
95#[cfg(test)]
96mod tests {
97 extern crate dotenvy;
98
99 use super::*;
100 use std::env;
101
102 use crate::connection::Connection;
103 use crate::connection::SimpleConnection;
104 use crate::query_dsl::RunQueryDsl;
105
106 fn connection() -> MariadbConnection {
107 dotenvy::dotenv().ok();
108 let database_url = env::var("MARIADB_UNIT_TEST_DATABASE_URL")
109 .or_else(|_| env::var("MARIADB_DATABASE_URL"))
110 .or_else(|_| env::var("DATABASE_URL"))
111 .expect("DATABASE_URL must be set in order to run unit tests");
112 MariadbConnection::establish(&database_url).unwrap()
113 }
114
115 #[diesel_test_helper::test]
116 fn batch_execute_handles_single_queries_with_results() {
117 let connection = &mut connection();
118 assert!(connection.batch_execute("SELECT 1").is_ok());
119 assert!(connection.batch_execute("SELECT 1").is_ok());
120 }
121
122 #[diesel_test_helper::test]
123 fn batch_execute_handles_multi_queries_with_results() {
124 let connection = &mut connection();
125 let query = "SELECT 1; SELECT 2; SELECT 3;";
126 assert!(connection.batch_execute(query).is_ok());
127 assert!(connection.batch_execute(query).is_ok());
128 }
129
130 #[diesel_test_helper::test]
131 fn execute_handles_queries_which_return_results() {
132 let connection = &mut connection();
133 assert!(crate::sql_query("SELECT 1").execute(connection).is_ok());
134 assert!(crate::sql_query("SELECT 1").execute(connection).is_ok());
135 }
136
137 #[diesel_test_helper::test]
138 fn check_client_found_rows_flag() {
139 let conn = &mut crate::test_helpers::connection();
140 crate::sql_query("DROP TABLE IF EXISTS update_test CASCADE")
141 .execute(conn)
142 .unwrap();
143
144 crate::sql_query("CREATE TABLE update_test(id INTEGER PRIMARY KEY, num INTEGER NOT NULL)")
145 .execute(conn)
146 .unwrap();
147
148 crate::sql_query("INSERT INTO update_test(id, num) VALUES (1, 5)")
149 .execute(conn)
150 .unwrap();
151
152 let output = crate::sql_query("UPDATE update_test SET num = 5 WHERE id = 1")
153 .execute(conn)
154 .unwrap();
155
156 assert_eq!(output, 1);
157 }
158
159 #[crate::declare_sql_function]
160 extern "SQL" {
161 fn version() -> crate::sql_types::Text;
162 }
163
164 #[diesel_test_helper::test]
165 fn version_matches_the_server_reported_version() {
166 let connection = &mut connection();
167 let expected = connection.version().unwrap().to_string();
168 let reported = crate::select(version())
169 .get_result::<String>(connection)
170 .unwrap();
171 assert!(
172 reported.starts_with(&format!("{expected}-")),
173 "`{reported}` does not start with `{expected}-`"
174 );
175 }
176}