Skip to content
This repository has been archived by the owner on Nov 14, 2022. It is now read-only.

Commit

Permalink
feat(function): cast distinguish postgresql style
Browse files Browse the repository at this point in the history
  • Loading branch information
b41sh committed Apr 12, 2022
1 parent 08b8c31 commit b0571e8
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 11 deletions.
13 changes: 12 additions & 1 deletion src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ pub enum Expr {
Cast {
expr: Box<Expr>,
data_type: DataType,
pg_style: bool,
},
/// TRY_CAST an expression to a different data type e.g. `TRY_CAST(foo AS VARCHAR(123))`
// this differs from CAST in the choice of how to implement invalid conversions
Expand Down Expand Up @@ -346,7 +347,17 @@ impl fmt::Display for Expr {
write!(f, "{} {}", op, expr)
}
}
Expr::Cast { expr, data_type } => write!(f, "CAST({} AS {})", expr, data_type),
Expr::Cast {
expr,
data_type,
pg_style,
} => {
if *pg_style {
write!(f, "{}::{}", expr, data_type)
} else {
write!(f, "CAST({} AS {})", expr, data_type)
}
}
Expr::TryCast { expr, data_type } => write!(f, "TRY_CAST({} AS {})", expr, data_type),
Expr::Extract { field, expr } => write!(f, "EXTRACT({} FROM {})", field, expr),
Expr::Collate { expr, collation } => write!(f, "{} COLLATE {}", expr, collation),
Expand Down
2 changes: 2 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,7 @@ impl<'a> Parser<'a> {
Ok(Expr::Cast {
expr: Box::new(expr),
data_type,
pg_style: false,
})
}

Expand Down Expand Up @@ -1215,6 +1216,7 @@ impl<'a> Parser<'a> {
Ok(Expr::Cast {
expr: Box::new(expr),
data_type: self.parse_data_type()?,
pg_style: true,
})
}

Expand Down
6 changes: 4 additions & 2 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1480,7 +1480,8 @@ fn parse_cast() {
assert_eq!(
&Expr::Cast {
expr: Box::new(Expr::Identifier(Ident::new("id"))),
data_type: DataType::BigInt(None)
data_type: DataType::BigInt(None),
pg_style: false,
},
expr_from_projection(only(&select.projection))
);
Expand All @@ -1490,7 +1491,8 @@ fn parse_cast() {
assert_eq!(
&Expr::Cast {
expr: Box::new(Expr::Identifier(Ident::new("id"))),
data_type: DataType::TinyInt(None)
data_type: DataType::TinyInt(None),
pg_style: false,
},
expr_from_projection(only(&select.projection))
);
Expand Down
42 changes: 34 additions & 8 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,7 @@ fn parse_create_table_with_defaults() {
options: vec![
ColumnOptionDef {
name: None,
option: ColumnOption::Default(
pg().verified_expr("CAST(now() AS TEXT)")
)
option: ColumnOption::Default(pg().verified_expr("now()::TEXT"))
},
ColumnOptionDef {
name: None,
Expand Down Expand Up @@ -205,20 +203,23 @@ fn parse_create_table_from_pg_dump() {
release_year public.year,
active integer
)";
pg().one_statement_parses_to(sql, "CREATE TABLE public.customer (\
customer_id INT DEFAULT nextval(CAST('public.customer_customer_id_seq' AS REGCLASS)) NOT NULL, \
pg().one_statement_parses_to(
sql,
"CREATE TABLE public.customer (\
customer_id INT DEFAULT nextval('public.customer_customer_id_seq'::REGCLASS) NOT NULL, \
store_id SMALLINT NOT NULL, \
first_name CHARACTER VARYING(45) NOT NULL, \
last_name CHARACTER VARYING(45) NOT NULL, \
info TEXT[], \
address_id SMALLINT NOT NULL, \
activebool BOOLEAN DEFAULT true NOT NULL, \
create_date DATE DEFAULT CAST(now() AS DATE) NOT NULL, \
create_date1 DATE DEFAULT CAST(CAST('now' AS TEXT) AS DATE) NOT NULL, \
create_date DATE DEFAULT now()::DATE NOT NULL, \
create_date1 DATE DEFAULT 'now'::TEXT::DATE NOT NULL, \
last_update TIMESTAMP DEFAULT now(), \
release_year public.year, \
active INT\
)");
)",
);
}

#[test]
Expand Down Expand Up @@ -754,6 +755,31 @@ fn test_transaction_statement() {
);
}

#[test]
fn parse_cast() {
let sql = "SELECT id::BIGINT FROM customer";
let select = pg_and_generic().verified_only_select(sql);
assert_eq!(
&Expr::Cast {
expr: Box::new(Expr::Identifier(Ident::new("id"))),
data_type: DataType::BigInt(None),
pg_style: true,
},
expr_from_projection(only(&select.projection))
);

let sql = "SELECT id::TINYINT FROM customer";
let select = pg_and_generic().verified_only_select(sql);
assert_eq!(
&Expr::Cast {
expr: Box::new(Expr::Identifier(Ident::new("id"))),
data_type: DataType::TinyInt(None),
pg_style: true,
},
expr_from_projection(only(&select.projection))
);
}

fn pg() -> TestedDialects {
TestedDialects {
dialects: vec![Box::new(PostgreSqlDialect {})],
Expand Down

0 comments on commit b0571e8

Please sign in to comment.