launchbadge / sqlx

🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.
Apache License 2.0
13k stars 1.24k forks source link

MSSQL errors/panics when parsing colums with NVARCHAR(MAX) datatype #2232

Open cfsamson opened 1 year ago

cfsamson commented 1 year ago

Bug Description

NVARCHAR(MAX) doesn't parse correctly on Sql Server Express 16.0.1000.6.

On Sql Server 2016 version 12.0.6169.19 it simply panics with the error:

panicked at 'called `Result::unwrap()` on an `Err` value: encountered unexpected or invalid data: unknown value 
`0x00` for message type in token stream'

Minimal Reproduction

Assuming you have a local Mssql Express server running (quick setup guide if you don't):

On local sql server called "testserver" with a user test, pwd: test and port: 60000

CREATE TABLE test (col1 NVARCHAR(MAX) NULL);
INSERT INTO test VALUES ('sometext');

Setup project:

cargo new sqlx_nvarchar
cargo add sqlx --features "mssql runtime-tokio-rustls"
cargo add tokio --features full
$env:DATABASE_URL:"mssql://test:test@localhost:60000/testserver"
use std::error::Error;
use sqlx::MssqlPool;

#[derive(Debug)]
struct Test {
    col1: Option<String>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let pool = MssqlPool::connect(env!("DATABASE_URL")).await?;
    let test = sqlx::query_as!(Test, "SELECT col1 FROM test.dbo.test").fetch_one(&pool).await?;
    println!("{test:#?}");
    Ok(())
}

Run cargo run and you get the output:

Test {
    col1: Some(
        "\0\0\0\u{10}\0som",
    ),
}

Expected:

Test {
    col1: Some(
        "sometext",
    ),
}

On sql server 2016 this just panics.

Info

cfsamson commented 1 year ago

Temporary workaround:

If you know the max size of the data you work with you can change the SQL to:

SELECT CAST(col1 AS NVARCHAR(1024)) as col1 FROM test.dbo.test

Change the size to whatever size you want (it doesn't seem to matter just as long as there is an explicit size set).

codebling commented 1 year ago

Can confirm this. Can reproduce with docker image using default config:

docker run --rm -it -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=@Passw0rd" -p 1433:1433 mcr.microsoft.com/mssql/server:2022-latest

Also affects VARCHAR type.

codebling commented 1 year ago

Duplicate issues: #2286, #1838

lovasoa commented 1 year ago

I fixed multiple bugs related to string handling in mssql in https://github.com/lovasoa/sqlx

cfsamson commented 1 year ago

@lovasoa Great, I'll use that going forward 👍👍👍