diff --git a/crates/dbx-driver-support/src/navicat_mysql_tunnel.rs b/crates/dbx-driver-support/src/navicat_mysql_tunnel.rs index 632b1d0f5d..e38fdc4a11 100644 --- a/crates/dbx-driver-support/src/navicat_mysql_tunnel.rs +++ b/crates/dbx-driver-support/src/navicat_mysql_tunnel.rs @@ -289,7 +289,7 @@ fn validate_stateless_query(sql: &str) -> Result<(), String> { })); if transaction { return Err( - "Transactions and autocommit settings are not supported by Navicat HTTP tunnels: each request uses a separate MySQL session" + "Transactions, autocommit settings, and consistent snapshots are not supported by the stateless Navicat HTTP tunnel; use the DBX TCP HTTP tunnel (dbx_tunnel.php) for a fixed database session" .to_string(), ); } @@ -684,7 +684,9 @@ mod tests { let response = send_test_command(&mut client, 0x03, sql.as_bytes()).await; assert_eq!(response[0], 0xff, "{sql}"); assert_eq!(u16::from_le_bytes(response[1..3].try_into().unwrap()), 1235, "{sql}"); - assert!(String::from_utf8_lossy(&response[9..]).contains("separate MySQL session")); + let message = String::from_utf8_lossy(&response[9..]); + assert!(message.contains("stateless Navicat HTTP tunnel"), "{sql}: {message}"); + assert!(message.contains("fixed database session"), "{sql}: {message}"); } assert!(tokio::time::timeout(std::time::Duration::from_millis(50), http_listener.accept()).await.is_err()); assert_eq!(send_test_command(&mut client, 0x0e, b"").await[0], 0); diff --git a/deploy/NAVICAT_HTTP_TUNNEL.md b/deploy/NAVICAT_HTTP_TUNNEL.md index 38ae6c335c..1523726730 100644 --- a/deploy/NAVICAT_HTTP_TUNNEL.md +++ b/deploy/NAVICAT_HTTP_TUNNEL.md @@ -23,6 +23,14 @@ can change a POST request into a GET. This protocol supports regular queries, `USE`, ping, and disconnect. MySQL TLS and prepared statements are not supported by the Navicat HTTP tunnel protocol. -Each HTTP request opens a separate MySQL session. Transactions (including manual -transactions and consistent backup snapshots), savepoints, and autocommit -settings are rejected before any SQL is sent to the PHP host. +Each HTTP request opens a separate MySQL session, so this endpoint is appropriate +only for non-transactional operations and backups that do not request a consistent +snapshot. Transactions, savepoints, autocommit settings, and consistent-snapshot +backup sequences are rejected before any SQL is sent to the PHP host; this prevents +a successful-looking `ROLLBACK` from failing to undo a write that ran in another +session. + +For transaction workflows or backups that require a consistent snapshot, deploy +DBX's own `deploy/dbx_tunnel.php` endpoint instead. That endpoint keeps one +database TCP session alive for the lifetime of the tunnel and is configured as the +DBX TCP HTTP tunnel, not as the Navicat-compatible endpoint.