mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-12-30 05:11:13 +00:00
* fix(mysql): validate parameter count for prepared statements Add validation to ensure the number of provided parameters matches the expected count for MySQL prepared statements. This prevents protocol errors by returning an error if the counts do not match before sending the statement for execution. * refactor(mysql): use err_protocol macro for error creation Replace direct Error::Protocol(format!()) calls with err_protocol! macro in MySQL connection executor. * test(mysql): add parameter count validation tests - Add test for too few parameters provided to query - Add test for too many parameters provided to query - Add test for parameters provided when none expected - All tests verify Error::Protocol is returned for mismatches Covers cases for issue #3774 parameter validation fix.
150 lines
4.0 KiB
Rust
150 lines
4.0 KiB
Rust
use sqlx::{error::ErrorKind, mysql::MySql, Connection, Error};
|
|
use sqlx_test::new;
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_unique_violation() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let mut tx = conn.begin().await?;
|
|
|
|
sqlx::query("INSERT INTO tweet(id, text, owner_id) VALUES (1, 'Foo', 1)")
|
|
.execute(&mut *tx)
|
|
.await?;
|
|
|
|
let res: Result<_, sqlx::Error> = sqlx::query("INSERT INTO tweet VALUES (1, NOW(), 'Foo', 1);")
|
|
.execute(&mut *tx)
|
|
.await;
|
|
let err = res.unwrap_err();
|
|
|
|
let err = err.into_database_error().unwrap();
|
|
|
|
assert_eq!(err.kind(), ErrorKind::UniqueViolation);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_foreign_key_violation() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let mut tx = conn.begin().await?;
|
|
|
|
let res: Result<_, sqlx::Error> =
|
|
sqlx::query("INSERT INTO tweet_reply (tweet_id, text) VALUES (1, 'Reply!');")
|
|
.execute(&mut *tx)
|
|
.await;
|
|
let err = res.unwrap_err();
|
|
|
|
let err = err.into_database_error().unwrap();
|
|
|
|
assert_eq!(err.kind(), ErrorKind::ForeignKeyViolation);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_not_null_violation() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let mut tx = conn.begin().await?;
|
|
|
|
let res: Result<_, sqlx::Error> = sqlx::query("INSERT INTO tweet (text) VALUES (null);")
|
|
.execute(&mut *tx)
|
|
.await;
|
|
let err = res.unwrap_err();
|
|
|
|
let err = err.into_database_error().unwrap();
|
|
|
|
assert_eq!(err.kind(), ErrorKind::NotNullViolation);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_check_violation() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let mut tx = conn.begin().await?;
|
|
|
|
let res: Result<_, sqlx::Error> =
|
|
sqlx::query("INSERT INTO products VALUES (1, 'Product 1', 0);")
|
|
.execute(&mut *tx)
|
|
.await;
|
|
let err = res.unwrap_err();
|
|
|
|
let err = err.into_database_error().unwrap();
|
|
|
|
assert_eq!(err.kind(), ErrorKind::CheckViolation);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_begin_failed() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let res = conn.begin_with("SELECT * FROM tweet").await;
|
|
|
|
let err = res.unwrap_err();
|
|
|
|
assert!(matches!(err, Error::BeginFailed), "{err:?}");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_invalid_save_point_statement() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let mut txn = conn.begin().await?;
|
|
let txn_conn = sqlx::Acquire::acquire(&mut txn).await?;
|
|
let res = txn_conn.begin_with("BEGIN").await;
|
|
|
|
let err = res.unwrap_err();
|
|
|
|
assert!(matches!(err, Error::InvalidSavePointStatement), "{err}");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_parameter_count_mismatch_too_few() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let res: Result<_, sqlx::Error> =
|
|
sqlx::query("SELECT * FROM tweet WHERE id = ? AND owner_id = ?")
|
|
.bind(1_i64)
|
|
.execute(&mut conn)
|
|
.await;
|
|
|
|
let err = res.unwrap_err();
|
|
|
|
assert!(matches!(err, Error::Protocol(_)), "{err}");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_parameter_count_mismatch_too_many() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let res: Result<_, sqlx::Error> = sqlx::query("SELECT * FROM tweet WHERE id = ?")
|
|
.bind(1_i64)
|
|
.bind(2_i64)
|
|
.execute(&mut conn)
|
|
.await;
|
|
|
|
let err = res.unwrap_err();
|
|
|
|
assert!(matches!(err, Error::Protocol(_)), "{err}");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[sqlx_macros::test]
|
|
async fn it_fails_with_parameter_count_mismatch_zero_expected() -> anyhow::Result<()> {
|
|
let mut conn = new::<MySql>().await?;
|
|
let res: Result<_, sqlx::Error> = sqlx::query("SELECT COUNT(*) FROM tweet")
|
|
.bind(1_i64)
|
|
.execute(&mut conn)
|
|
.await;
|
|
|
|
let err = res.unwrap_err();
|
|
|
|
assert!(matches!(err, Error::Protocol(_)), "{err}");
|
|
|
|
Ok(())
|
|
}
|