1- use std:: fmt:: Write ;
21use std:: ops:: Deref ;
32use std:: str:: FromStr ;
4- use std:: sync:: atomic:: { AtomicBool , Ordering } ;
5- use std:: time:: { Duration , SystemTime } ;
3+ use std:: time:: Duration ;
64
75use futures_core:: future:: BoxFuture ;
86
97use once_cell:: sync:: OnceCell ;
10-
11- use crate :: connection:: Connection ;
8+ use sqlx_core:: connection:: Connection ;
9+ use sqlx_core:: query_builder:: QueryBuilder ;
10+ use sqlx_core:: query_scalar:: query_scalar;
11+ use std:: fmt:: Write ;
1212
1313use crate :: error:: Error ;
1414use crate :: executor:: Executor ;
1515use crate :: pool:: { Pool , PoolOptions } ;
1616use crate :: query:: query;
17- use crate :: query_builder:: QueryBuilder ;
18- use crate :: query_scalar:: query_scalar;
1917use crate :: { MySql , MySqlConnectOptions , MySqlConnection } ;
2018
2119pub ( crate ) use sqlx_core:: testing:: * ;
2220
2321// Using a blocking `OnceCell` here because the critical sections are short.
2422static MASTER_POOL : OnceCell < Pool < MySql > > = OnceCell :: new ( ) ;
25- // Automatically delete any databases created before the start of the test binary.
26- static DO_CLEANUP : AtomicBool = AtomicBool :: new ( true ) ;
2723
2824impl TestSupport for MySql {
2925 fn test_context ( args : & TestArgs ) -> BoxFuture < ' _ , Result < TestContext < Self > , Error > > {
@@ -38,17 +34,7 @@ impl TestSupport for MySql {
3834 . acquire ( )
3935 . await ?;
4036
41- let db_id = db_id ( db_name) ;
42-
43- conn. execute ( & format ! ( "drop database if exists {db_name};" ) [ ..] )
44- . await ?;
45-
46- query ( "delete from _sqlx_test_databases where db_id = ?" )
47- . bind ( db_id)
48- . execute ( & mut * conn)
49- . await ?;
50-
51- Ok ( ( ) )
37+ do_cleanup ( & mut conn, db_name) . await
5238 } )
5339 }
5440
@@ -58,13 +44,55 @@ impl TestSupport for MySql {
5844
5945 let mut conn = MySqlConnection :: connect ( & url) . await ?;
6046
61- let now = SystemTime :: now ( )
62- . duration_since ( SystemTime :: UNIX_EPOCH )
63- . unwrap ( ) ;
47+ let delete_db_names: Vec < String > =
48+ query_scalar ( "select db_name from _sqlx_test_databases" )
49+ . fetch_all ( & mut conn)
50+ . await ?;
51+
52+ if delete_db_names. is_empty ( ) {
53+ return Ok ( None ) ;
54+ }
55+
56+ let mut deleted_db_names = Vec :: with_capacity ( delete_db_names. len ( ) ) ;
57+
58+ let mut command = String :: new ( ) ;
59+
60+ for db_name in & delete_db_names {
61+ command. clear ( ) ;
62+
63+ let db_name = format ! ( "_sqlx_test_database_{db_name}" ) ;
64+
65+ writeln ! ( command, "drop database if exists {db_name:?};" ) . ok ( ) ;
66+ match conn. execute ( & * command) . await {
67+ Ok ( _deleted) => {
68+ deleted_db_names. push ( db_name) ;
69+ }
70+ // Assume a database error just means the DB is still in use.
71+ Err ( Error :: Database ( dbe) ) => {
72+ eprintln ! ( "could not clean test database {db_name:?}: {dbe}" )
73+ }
74+ // Bubble up other errors
75+ Err ( e) => return Err ( e) ,
76+ }
77+ }
78+
79+ if deleted_db_names. is_empty ( ) {
80+ return Ok ( None ) ;
81+ }
82+
83+ let mut query =
84+ QueryBuilder :: new ( "delete from _sqlx_test_databases where db_name in (" ) ;
85+
86+ let mut separated = query. separated ( "," ) ;
87+
88+ for db_name in & deleted_db_names {
89+ separated. push_bind ( db_name) ;
90+ }
91+
92+ query. push ( ")" ) . build ( ) . execute ( & mut conn) . await ?;
6493
65- let num_deleted = do_cleanup ( & mut conn, now) . await ?;
6694 let _ = conn. close ( ) . await ;
67- Ok ( Some ( num_deleted ) )
95+ Ok ( Some ( delete_db_names . len ( ) ) )
6896 } )
6997 }
7098
@@ -117,42 +145,27 @@ async fn test_context(args: &TestArgs) -> Result<TestContext<MySql>, Error> {
117145 conn. execute (
118146 r#"
119147 create table if not exists _sqlx_test_databases (
120- db_id bigint unsigned primary key auto_increment ,
148+ db_name text primary key,
121149 test_path text not null,
122150 created_at timestamp not null default current_timestamp
123151 );
124152 "# ,
125153 )
126154 . await ?;
127155
128- // Record the current time _before_ we acquire the `DO_CLEANUP` permit. This
129- // prevents the first test thread from accidentally deleting new test dbs
130- // created by other test threads if we're a bit slow.
131- let now = SystemTime :: now ( )
132- . duration_since ( SystemTime :: UNIX_EPOCH )
133- . unwrap ( ) ;
134-
135- // Only run cleanup if the test binary just started.
136- if DO_CLEANUP . swap ( false , Ordering :: SeqCst ) {
137- do_cleanup ( & mut conn, now) . await ?;
138- }
156+ let db_name = MySql :: db_name ( args) ;
157+ do_cleanup ( & mut conn, & db_name) . await ?;
139158
140- query ( "insert into _sqlx_test_databases(test_path) values (?)" )
159+ query ( "insert into _sqlx_test_databases(db_name, test_path) values (?, ?)" )
160+ . bind ( & db_name)
141161 . bind ( args. test_path )
142162 . execute ( & mut * conn)
143163 . await ?;
144164
145- // MySQL doesn't have `INSERT ... RETURNING`
146- let new_db_id: u64 = query_scalar ( "select last_insert_id()" )
147- . fetch_one ( & mut * conn)
148- . await ?;
149-
150- let new_db_name = db_name ( new_db_id) ;
151-
152- conn. execute ( & format ! ( "create database {new_db_name}" ) [ ..] )
165+ conn. execute ( & format ! ( "create database {db_name:?}" ) [ ..] )
153166 . await ?;
154167
155- eprintln ! ( "created database {new_db_name }" ) ;
168+ eprintln ! ( "created database {db_name }" ) ;
156169
157170 Ok ( TestContext {
158171 pool_opts : PoolOptions :: new ( )
@@ -167,74 +180,18 @@ async fn test_context(args: &TestArgs) -> Result<TestContext<MySql>, Error> {
167180 . connect_options ( )
168181 . deref ( )
169182 . clone ( )
170- . database ( & new_db_name ) ,
171- db_name : new_db_name ,
183+ . database ( & db_name ) ,
184+ db_name,
172185 } )
173186}
174187
175- async fn do_cleanup ( conn : & mut MySqlConnection , created_before : Duration ) -> Result < usize , Error > {
176- // since SystemTime is not monotonic we added a little margin here to avoid race conditions with other threads
177- let created_before_as_secs = created_before. as_secs ( ) - 2 ;
178- let delete_db_ids: Vec < u64 > = query_scalar (
179- "select db_id from _sqlx_test_databases \
180- where created_at < from_unixtime(?)",
181- )
182- . bind ( created_before_as_secs)
183- . fetch_all ( & mut * conn)
184- . await ?;
185-
186- if delete_db_ids. is_empty ( ) {
187- return Ok ( 0 ) ;
188- }
189-
190- let mut deleted_db_ids = Vec :: with_capacity ( delete_db_ids. len ( ) ) ;
191-
192- let mut command = String :: new ( ) ;
193-
194- for db_id in delete_db_ids {
195- command. clear ( ) ;
196-
197- let db_name = db_name ( db_id) ;
198-
199- writeln ! ( command, "drop database if exists {db_name}" ) . ok ( ) ;
200- match conn. execute ( & * command) . await {
201- Ok ( _deleted) => {
202- deleted_db_ids. push ( db_id) ;
203- }
204- // Assume a database error just means the DB is still in use.
205- Err ( Error :: Database ( dbe) ) => {
206- eprintln ! ( "could not clean test database {db_id:?}: {dbe}" )
207- }
208- // Bubble up other errors
209- Err ( e) => return Err ( e) ,
210- }
211- }
212-
213- let mut query = QueryBuilder :: new ( "delete from _sqlx_test_databases where db_id in (" ) ;
214-
215- let mut separated = query. separated ( "," ) ;
216-
217- for db_id in & deleted_db_ids {
218- separated. push_bind ( db_id) ;
219- }
220-
221- query. push ( ")" ) . build ( ) . execute ( & mut * conn) . await ?;
222-
223- Ok ( deleted_db_ids. len ( ) )
224- }
225-
226- fn db_name ( id : u64 ) -> String {
227- format ! ( "_sqlx_test_database_{id}" )
228- }
229-
230- fn db_id ( name : & str ) -> u64 {
231- name. trim_start_matches ( "_sqlx_test_database_" )
232- . parse ( )
233- . unwrap_or_else ( |_1| panic ! ( "failed to parse ID from database name {name:?}" ) )
234- }
188+ async fn do_cleanup ( conn : & mut MySqlConnection , db_name : & str ) -> Result < ( ) , Error > {
189+ let delete_db_command = format ! ( "drop database if exists {db_name:?};" ) ;
190+ conn. execute ( & * delete_db_command) . await ?;
191+ query ( "delete from _sqlx_test.databases where db_name = $1::text" )
192+ . bind ( db_name)
193+ . execute ( & mut * conn)
194+ . await ?;
235195
236- #[ test]
237- fn test_db_name_id ( ) {
238- assert_eq ! ( db_name( 12345 ) , "_sqlx_test_database_12345" ) ;
239- assert_eq ! ( db_id( "_sqlx_test_database_12345" ) , 12345 ) ;
196+ Ok ( ( ) )
240197}
0 commit comments