Skip to content

Commit c703015

Browse files
committed
Clear the MySQL connection statement cache on error
Some cloud offerings like AWS Aurora allow for "zero-downtime" restarts for patches, which preserves existing TCP connections but wipes out a lot of server state, including the statement cache. In that scenario, trying to execute a previously prepared statement causes an error response with ``` HY000 Unknown prepared statement handler (<id>) given to mysql_stmt_precheck ``` which appears to be the only way to detect this scenario. To avoid subsequent errors for the same connection, we can clear the statement cache on the client side, causing all queries to get re-prepared. This is basically what ActiveRecord does,[0] which we can confirm is not vulnerable to the same issue. An even better solution would be to re-prepare and -try the query right there, like ActiveRecord does. [0]: https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters/mysql2/database_statements.rb#L66-L78
1 parent c01f513 commit c703015

File tree

1 file changed

+5
-1
lines changed

1 file changed

+5
-1
lines changed

sqlx-mysql/src/connection/executor.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ impl MySqlConnection {
183183
loop {
184184
// query response is a meta-packet which may be one of:
185185
// Ok, Err, ResultSet, or (unhandled) LocalInfileRequest
186-
let mut packet = self.inner.stream.recv_packet().await?;
186+
let mut packet = self.inner.stream.recv_packet().await.inspect_err(|_| {
187+
// if a prepared statement vanished on the server side, we get an error here
188+
// clear the statement cache in case the connection got reset to cause re-preparing
189+
self.inner.cache_statement.clear();
190+
})?;
187191

188192
if packet[0] == 0x00 || packet[0] == 0xff {
189193
// first packet in a query response is OK or ERR

0 commit comments

Comments
 (0)