Support for MSSQL CONVERT styles (#1219)

This commit is contained in:
Ifeanyi Ubah 2024-04-30 16:22:13 +02:00 committed by GitHub
parent 6fcf8c9abe
commit 0606024353
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 0 deletions

View file

@ -567,6 +567,10 @@ pub enum Expr {
charset: Option<ObjectName>, charset: Option<ObjectName>,
/// whether the target comes before the expr (MSSQL syntax) /// whether the target comes before the expr (MSSQL syntax)
target_before_value: bool, target_before_value: bool,
/// How to translate the expression.
///
/// [MSSQL]: https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver16#style
styles: Vec<Expr>,
}, },
/// `CAST` an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))` /// `CAST` an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
Cast { Cast {
@ -979,6 +983,7 @@ impl fmt::Display for Expr {
target_before_value, target_before_value,
data_type, data_type,
charset, charset,
styles,
} => { } => {
write!(f, "CONVERT(")?; write!(f, "CONVERT(")?;
if let Some(data_type) = data_type { if let Some(data_type) = data_type {
@ -994,6 +999,9 @@ impl fmt::Display for Expr {
} else { } else {
write!(f, "{expr}") // This should never happen write!(f, "{expr}") // This should never happen
}?; }?;
if !styles.is_empty() {
write!(f, ", {}", display_comma_separated(styles))?;
}
write!(f, ")") write!(f, ")")
} }
Expr::Cast { Expr::Cast {

View file

@ -1462,12 +1462,18 @@ impl<'a> Parser<'a> {
let data_type = self.parse_data_type()?; let data_type = self.parse_data_type()?;
self.expect_token(&Token::Comma)?; self.expect_token(&Token::Comma)?;
let expr = self.parse_expr()?; let expr = self.parse_expr()?;
let styles = if self.consume_token(&Token::Comma) {
self.parse_comma_separated(Parser::parse_expr)?
} else {
Default::default()
};
self.expect_token(&Token::RParen)?; self.expect_token(&Token::RParen)?;
Ok(Expr::Convert { Ok(Expr::Convert {
expr: Box::new(expr), expr: Box::new(expr),
data_type: Some(data_type), data_type: Some(data_type),
charset: None, charset: None,
target_before_value: true, target_before_value: true,
styles,
}) })
} }
@ -1489,6 +1495,7 @@ impl<'a> Parser<'a> {
data_type: None, data_type: None,
charset: Some(charset), charset: Some(charset),
target_before_value: false, target_before_value: false,
styles: vec![],
}); });
} }
self.expect_token(&Token::Comma)?; self.expect_token(&Token::Comma)?;
@ -1504,6 +1511,7 @@ impl<'a> Parser<'a> {
data_type: Some(data_type), data_type: Some(data_type),
charset, charset,
target_before_value: false, target_before_value: false,
styles: vec![],
}) })
} }

View file

@ -20,6 +20,7 @@ use test_utils::*;
use sqlparser::ast::*; use sqlparser::ast::*;
use sqlparser::dialect::{GenericDialect, MsSqlDialect}; use sqlparser::dialect::{GenericDialect, MsSqlDialect};
use sqlparser::parser::ParserError;
#[test] #[test]
fn parse_mssql_identifiers() { fn parse_mssql_identifiers() {
@ -437,9 +438,39 @@ fn parse_cast_varchar_max() {
#[test] #[test]
fn parse_convert() { fn parse_convert() {
let sql = "CONVERT(INT, 1, 2, 3, NULL)";
let Expr::Convert {
expr,
data_type,
charset,
target_before_value,
styles,
} = ms().verified_expr(sql)
else {
unreachable!()
};
assert_eq!(Expr::Value(number("1")), *expr);
assert_eq!(Some(DataType::Int(None)), data_type);
assert!(charset.is_none());
assert!(target_before_value);
assert_eq!(
vec![
Expr::Value(number("2")),
Expr::Value(number("3")),
Expr::Value(Value::Null),
],
styles
);
ms().verified_expr("CONVERT(VARCHAR(MAX), 'foo')"); ms().verified_expr("CONVERT(VARCHAR(MAX), 'foo')");
ms().verified_expr("CONVERT(VARCHAR(10), 'foo')"); ms().verified_expr("CONVERT(VARCHAR(10), 'foo')");
ms().verified_expr("CONVERT(DECIMAL(10,5), 12.55)"); ms().verified_expr("CONVERT(DECIMAL(10,5), 12.55)");
let error_sql = "SELECT CONVERT(INT, 'foo',) FROM T";
assert_eq!(
ParserError::ParserError("Expected an expression:, found: )".to_owned()),
ms().parse_sql_statements(error_sql).unwrap_err()
);
} }
#[test] #[test]