Skip to content

Commit

Permalink
fix(postgres): prefer parsing non-localized notice severity field
Browse files Browse the repository at this point in the history
In order to support PostgreSQL <= 9.5, the b'S' field of an error/notice
message was parsed. However, this field can be localized and thus parsing
can fail for instances that use a non-english locale. In version > 9.5,
the b'V' field, that is guaranteed to be in english, was added. However,
even for these versions parsing would fail as the b'S' field was also
parsed. This patch prefers b'V' over b'S' if it exists and uses a default
severity in case b'V' is not present and b'S' could not be parsed.

Fixes #734
  • Loading branch information
dstoeckel committed Oct 18, 2020
1 parent d97014f commit dcef857
Showing 1 changed file with 40 additions and 18 deletions.
58 changes: 40 additions & 18 deletions sqlx-core/src/postgres/message/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,29 @@ impl PgSeverity {
}
}

impl std::convert::TryFrom<&str> for PgSeverity {
type Error = Error;

fn try_from(s: &str) -> Result<PgSeverity, Error> {
let result = match s {
"PANIC" => PgSeverity::Panic,
"FATAL" => PgSeverity::Fatal,
"ERROR" => PgSeverity::Error,
"WARNING" => PgSeverity::Warning,
"NOTICE" => PgSeverity::Notice,
"DEBUG" => PgSeverity::Debug,
"INFO" => PgSeverity::Info,
"LOG" => PgSeverity::Log,

severity => {
return Err(err_protocol!("unknown severity: {:?}", severity));
}
};

Ok(result)
}
}

#[derive(Debug)]
pub struct Notice {
storage: Bytes,
Expand Down Expand Up @@ -84,7 +107,12 @@ impl Notice {

impl Decode<'_> for Notice {
fn decode_with(buf: Bytes, _: ()) -> Result<Self, Error> {
let mut severity = PgSeverity::Log;
// In order to support PostgreSQL 9.5 and older we need to parse the localized S field.
// Newer versions additionally come with the V field that is guaranteed to be in English.
// We thus read both versions and prefer the unlocalized one if available.
const DEFAULT_SEVERITY: PgSeverity = PgSeverity::Log;
let mut severity_v = None;
let mut severity_s = None;
let mut message = (0, 0);
let mut code = (0, 0);

Expand All @@ -103,23 +131,17 @@ impl Decode<'_> for Notice {
break;
}

use std::convert::TryInto;
match field {
b'S' | b'V' => {
// unwrap: impossible to fail at this point
severity = match from_utf8(&buf[v.0 as usize..v.1 as usize]).unwrap() {
"PANIC" => PgSeverity::Panic,
"FATAL" => PgSeverity::Fatal,
"ERROR" => PgSeverity::Error,
"WARNING" => PgSeverity::Warning,
"NOTICE" => PgSeverity::Notice,
"DEBUG" => PgSeverity::Debug,
"INFO" => PgSeverity::Info,
"LOG" => PgSeverity::Log,

severity => {
return Err(err_protocol!("unknown severity: {:?}", severity));
}
};
b'S' => {
// Discard potential errors, because the message might be localized
severity_s = from_utf8(&buf[v.0 as usize..v.1 as usize]).unwrap().try_into().ok();
}

b'V' => {
// Propagate errors here, because V is not localized and thus we are missing a possible
// variant.
severity_v = Some(from_utf8(&buf[v.0 as usize..v.1 as usize]).unwrap().try_into()?);
}

b'M' => {
Expand All @@ -135,7 +157,7 @@ impl Decode<'_> for Notice {
}

Ok(Self {
severity,
severity: severity_v.or(severity_s).unwrap_or(DEFAULT_SEVERITY),
message,
code,
storage: buf,
Expand Down

0 comments on commit dcef857

Please sign in to comment.