fix(sqlserver): return informational server messages
This commit is contained in:
1 parent
368351d70e
commit
9679d48824
6 files changed
+468
-65
No files matched your search
@@ -0,0 +1,75 @@
|
||||
use dbx_core::db::sqlserver;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "requires DBX_TEST_SQLSERVER_HOST and DBX_TEST_SQLSERVER_PASSWORD"]
|
||||
async fn sqlserver_dbcc_messages_do_not_replace_results_or_errors() {
|
||||
let host = std::env::var("DBX_TEST_SQLSERVER_HOST").expect("DBX_TEST_SQLSERVER_HOST");
|
||||
let port = std::env::var("DBX_TEST_SQLSERVER_PORT").ok().and_then(|value| value.parse().ok()).unwrap_or(1433);
|
||||
let user = std::env::var("DBX_TEST_SQLSERVER_USER").unwrap_or_else(|_| "sa".to_string());
|
||||
let password = std::env::var("DBX_TEST_SQLSERVER_PASSWORD").expect("DBX_TEST_SQLSERVER_PASSWORD");
|
||||
let mut client = sqlserver::connect_with_port_explicit(
|
||||
&host,
|
||||
port,
|
||||
true,
|
||||
&user,
|
||||
&password,
|
||||
Some("master"),
|
||||
Duration::from_secs(15),
|
||||
)
|
||||
.await
|
||||
.expect("connect to SQL Server");
|
||||
|
||||
let table = "dbo.dbx_issue_3583_messages";
|
||||
let setup = format!(
|
||||
"IF OBJECT_ID('{table}', 'U') IS NOT NULL DROP TABLE {table}; \
|
||||
CREATE TABLE {table} (id BIGINT IDENTITY(1,1) PRIMARY KEY, name NVARCHAR(20)); \
|
||||
INSERT INTO {table} (name) VALUES (N'test');"
|
||||
);
|
||||
sqlserver::execute_batch(&mut client, &setup).await.expect("create DBCC fixture");
|
||||
|
||||
let dbcc = sqlserver::execute_query(&mut client, &format!("DBCC CHECKIDENT ('{table}', RESEED)",))
|
||||
.await
|
||||
.expect("execute DBCC CHECKIDENT");
|
||||
assert_eq!(dbcc.columns, vec!["Message"]);
|
||||
assert!(dbcc.rows.len() >= 2, "expected SQL Server identity and completion messages: {dbcc:?}");
|
||||
assert!(dbcc.rows.iter().any(|row| row[0].as_str().is_some_and(|message| message.contains("identity"))));
|
||||
|
||||
let select = sqlserver::execute_query(&mut client, &format!("SELECT id, name FROM {table}"))
|
||||
.await
|
||||
.expect("ordinary SELECT remains available");
|
||||
assert_eq!(select.columns, vec!["id", "name"]);
|
||||
assert_eq!(select.rows.len(), 1);
|
||||
|
||||
let multi = sqlserver::execute_batch(&mut client, "SELECT 1 AS first; SELECT 2 AS second")
|
||||
.await
|
||||
.expect("multiple result sets remain available");
|
||||
assert_eq!(multi.len(), 2);
|
||||
assert_eq!(multi[0].columns, vec!["first"]);
|
||||
assert_eq!(multi[1].columns, vec!["second"]);
|
||||
|
||||
let dml = sqlserver::execute_query(&mut client, &format!("UPDATE {table} SET name = N'updated'"))
|
||||
.await
|
||||
.expect("ordinary DML remains available");
|
||||
assert_eq!(dml.affected_rows, 1);
|
||||
assert!(dml.columns.is_empty());
|
||||
|
||||
let use_database =
|
||||
sqlserver::execute_query(&mut client, "USE master").await.expect("execute database context change");
|
||||
assert_eq!(use_database.columns, vec!["Message"]);
|
||||
assert!(
|
||||
use_database.rows.iter().all(|row| !row[0]
|
||||
.as_str()
|
||||
.is_some_and(|message| message.starts_with("Database change")
|
||||
|| message.starts_with("SQL collation")
|
||||
|| message.starts_with("Packet size change"))),
|
||||
"internal TDS environment changes must not leak into server messages: {use_database:?}"
|
||||
);
|
||||
|
||||
let error = sqlserver::execute_query(&mut client, "SELECT * FROM dbo.dbx_issue_3583_missing")
|
||||
.await
|
||||
.expect_err("real SQL Server errors must remain failures");
|
||||
assert!(!error.trim().is_empty());
|
||||
|
||||
sqlserver::execute_query(&mut client, &format!("DROP TABLE {table}")).await.expect("clean up DBCC fixture");
|
||||
}
|
||||
Reference in new issue
Block a user