Skip to content

fix(quaint): add url decode for MSSQL database name#5786

Open
dimsssss wants to merge 4 commits intoprisma:mainfrom
dimsssss:fix/db-name-url-decode
Open

fix(quaint): add url decode for MSSQL database name#5786
dimsssss wants to merge 4 commits intoprisma:mainfrom
dimsssss:fix/db-name-url-decode

Conversation

@dimsssss
Copy link
Copy Markdown
Contributor

@dimsssss dimsssss commented Feb 26, 2026

Title: fix(quaint): add url decode for MSSQL database name

Summary

  • Fix a bug where percent-encoded database names in MSSQL connection URLs (e.g., %E6%B5%8B%E8%AF%95%E5%BA%93测试库) were passed to the server
    without decoding, causing connection failures
  • Extends fix(quaint): add url decode for non-ascii db names #5750 (fix(quaint): add url decode for non-ascii db names) to MSSQL

Changes

  • quaint/src/connector/mssql/url.rs: Apply percent_decode in MssqlUrl::dbname() to return the decoded database name (&strCow<'_, str>)
  • quaint/src/connector/mssql/native/mod.rs: Override the database name on the tiberius Config with config.database(url.dbname()) so the
    decoded name is used for the actual connection
  • schema-engine/.../flavour/mssql.rs: Delegate percent-decoding in master_url() to MssqlUrl::dbname() instead of calling percent_decode
    directly, eliminating duplication. Also replace redundant JDBC parsing in drop_database() by reusing master_url(). This removes the need to add
    percent-encoding as a dependency to sql-schema-connector
  • quaint/src/connector/connection_info.rs: Adapt call site to the changed dbname() return type

Test plan

  • Unit tests: verify decoding for Chinese characters, spaces, and special characters in database names
  • Integration test: connect to a real MSSQL server using a percent-encoded Chinese database name (测试库) and verify with SELECT DB_NAME()
  • All 202 existing MSSQL tests pass (no regressions)
  • All 6 sql-schema-connector MSSQL tests pass

Summary by CodeRabbit

  • Bug Fixes

    • Properly handle percent-encoded and non-ASCII MSSQL database names (spaces, special characters, Chinese), decoding them when used for connections and database management.
    • Ensure the selected target/master database is consistently applied during connection attempts and protected from accidental drops.
  • Tests

    • Added tests covering decoding of encoded database names and related MSSQL connection behavior.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b5ef6b and c4ec394.

📒 Files selected for processing (1)
  • quaint/src/connector/mssql/url.rs

Walkthrough

MSSQL URL database names are now percent-decoded on access. MssqlUrl::dbname returns Cow<'_, str> (decoded when possible); callers set this decoded name into the MSSQL driver Config. Schema engine flows now derive the target DB and master URI directly from the URL-derived database name.

Changes

Cohort / File(s) Summary
MSSQL URL parsing & tests
quaint/src/connector/mssql/url.rs
MssqlUrl::dbname(&self) changed to return Cow<'_, str>; applies percent-decoding via percent_decode; returns owned decoded string on success, falls back to borrowed name on decode failure; tests added/updated for encoded names.
MSSQL native connector changes
quaint/src/connector/mssql/native/mod.rs
Make Config mutable and call config.database(url.dbname()) when creating connections and when retrying on routing errors so the decoded DB name is applied to the driver config.
Connection info handling
quaint/src/connector/connection_info.rs
Adjusted MSSQL-native dbname retrieval to use the new url.dbname() return type (Option now holds the value returned by url.dbname()), aligning ownership/typing with Cow<'_, str>.
Schema engine MSSQL flavour
schema-engine/connectors/sql-schema-connector/src/flavour/mssql.rs
master_url now constructs a MssqlUrl and extracts the DB via url.dbname() (removed previous JDBC-string property parsing). drop_database obtains (db_name, master_uri) from master_url and asserts the DB is not master immediately after retrieval.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding URL decoding for MSSQL database names to handle percent-encoded characters in connection URLs.
Docstring Coverage ✅ Passed Docstring coverage is 90.91% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6be8e6 and eed1a47.

📒 Files selected for processing (4)
  • quaint/src/connector/connection_info.rs
  • quaint/src/connector/mssql/native/mod.rs
  • quaint/src/connector/mssql/url.rs
  • schema-engine/connectors/sql-schema-connector/src/flavour/mssql.rs

Comment on lines 260 to 262
let (db_name, master_uri) = Self::master_url(&params.connector_params.connection_string)?;
assert!(db_name != "master", "Cannot drop the `master` database.");
let mut conn = Connection::new(&master_uri.to_string()).await?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider returning an error instead of panicking.

Using assert! in production code will cause a panic if the user attempts to drop the master database. While this is a clear programming error, returning a ConnectorError would provide a more graceful failure mode and better error messages to end users.

♻️ Proposed refactor to return an error instead of panicking
         let params = self.state.get_unwrapped_params();
         let (db_name, master_uri) = Self::master_url(&params.connector_params.connection_string)?;
-        assert!(db_name != "master", "Cannot drop the `master` database.");
+        if db_name == "master" {
+            return Err(ConnectorError::from_msg("Cannot drop the `master` database.".to_owned()));
+        }
         let mut conn = Connection::new(&master_uri.to_string()).await?;

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Feb 27, 2026

Merging this PR will not alter performance

✅ 11 untouched benchmarks
⏩ 11 skipped benchmarks1


Comparing dimsssss:fix/db-name-url-decode (4542acd) with main (94a226b)

Open in CodSpeed

Footnotes

  1. 11 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@jacek-prisma
Copy link
Copy Markdown
Contributor

Thanks for the contribution!
It looks like the newly added test is failing and make pedantic is also failing due to formatting (run cargo fmt)

@dimsssss
Copy link
Copy Markdown
Contributor Author

Thanks for the contribution! It looks like the newly added test is failing and make pedantic is also failing due to formatting (run cargo fmt)

Thank you, I applied it.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eed1a47 and 4542acd.

📒 Files selected for processing (1)
  • quaint/src/connector/mssql/url.rs

Comment on lines +101 to 111
/// Decoded database name. Defaults to `master`.
pub fn dbname(&self) -> Cow<'_, str> {
let db = self.query_params.database();
match percent_decode(db.as_bytes()).decode_utf8() {
Ok(decoded) => decoded,
Err(_) => {
tracing::warn!("Couldn't decode dbname to UTF-8, using the non-decoded version.");
Cow::Borrowed(db)
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider logging the error details for easier debugging.

The warning message could include the actual Utf8Error to help diagnose issues with malformed database names. This would provide more context about where the invalid UTF-8 sequence was encountered.

💡 Suggested improvement
         match percent_decode(db.as_bytes()).decode_utf8() {
             Ok(decoded) => decoded,
-            Err(_) => {
-                tracing::warn!("Couldn't decode dbname to UTF-8, using the non-decoded version.");
+            Err(e) => {
+                tracing::warn!(
+                    "Couldn't decode dbname '{}' to UTF-8: {}. Using the non-decoded version.",
+                    db,
+                    e
+                );
                 Cow::Borrowed(db)
             }
         }

Replace async integration test that requires a live MSSQL connection
with a unit test that only verifies URL parsing of percent-encoded
Chinese database names.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4542acd and 8b5ef6b.

📒 Files selected for processing (1)
  • quaint/src/connector/mssql/url.rs

Comment on lines +394 to +425
#[test]
fn should_decode_percent_encoded_dbname() {
// Chinese characters: 测试库 (test database)
let url = MssqlUrl::new("sqlserver://localhost:1433;database=%E6%B5%8B%E8%AF%95%E5%BA%93;user=SA;password=pass;trustServerCertificate=true").unwrap();
assert_eq!("测试库", url.dbname());
}

#[test]
fn should_decode_dbname_with_spaces() {
let url = MssqlUrl::new(
"sqlserver://localhost:1433;database=my%20database;user=SA;password=pass;trustServerCertificate=true",
)
.unwrap();
assert_eq!("my database", url.dbname());
}

#[test]
fn should_decode_dbname_with_special_characters() {
// test-db_name
let url = MssqlUrl::new(
"sqlserver://localhost:1433;database=test%2Ddb%5Fname;user=SA;password=pass;trustServerCertificate=true",
)
.unwrap();
assert_eq!("test-db_name", url.dbname());
}

#[test]
fn should_return_master_as_default_dbname() {
let url =
MssqlUrl::new("sqlserver://localhost:1433;user=SA;password=pass;trustServerCertificate=true").unwrap();
assert_eq!("master", url.dbname());
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding a test for the UTF-8 decode failure fallback path.

The test coverage is good for successful decoding scenarios. However, there's no test verifying the fallback behavior when percent_decode(...).decode_utf8() fails (returning Cow::Borrowed(db) with a warning). Adding such a test would ensure the error handling path is exercised.

💡 Suggested test for fallback behavior
#[test]
fn should_fallback_to_original_on_invalid_utf8() {
    // %FF is not valid UTF-8
    let url = MssqlUrl::new(
        "sqlserver://localhost:1433;database=test%FF;user=SA;password=pass;trustServerCertificate=true",
    )
    .unwrap();
    // Should return the original percent-encoded string since it can't decode to valid UTF-8
    assert_eq!("test%FF", url.dbname());
}

The same assertion was already covered by should_decode_percent_encoded_dbname.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants