Skip to content

Commit a71b3f5

Browse files
authored
Add support for PostgreSQL Insert table aliases (#1069) (#1084)
1 parent ce49886 commit a71b3f5

File tree

3 files changed

+217
-0
lines changed

3 files changed

+217
-0
lines changed

src/ast/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#[cfg(not(feature = "std"))]
1515
use alloc::{
1616
boxed::Box,
17+
format,
1718
string::{String, ToString},
1819
vec::Vec,
1920
};
@@ -1428,6 +1429,8 @@ pub enum Statement {
14281429
/// TABLE
14291430
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
14301431
table_name: ObjectName,
1432+
/// table_name as foo (for PostgreSQL)
1433+
table_alias: Option<Ident>,
14311434
/// COLUMNS
14321435
columns: Vec<Ident>,
14331436
/// Overwrite (Hive)
@@ -2459,6 +2462,7 @@ impl fmt::Display for Statement {
24592462
ignore,
24602463
into,
24612464
table_name,
2465+
table_alias,
24622466
overwrite,
24632467
partitioned,
24642468
columns,
@@ -2470,6 +2474,12 @@ impl fmt::Display for Statement {
24702474
replace_into,
24712475
priority,
24722476
} => {
2477+
let table_name = if let Some(alias) = table_alias {
2478+
format!("{table_name} AS {alias}")
2479+
} else {
2480+
table_name.to_string()
2481+
};
2482+
24732483
if let Some(action) = or {
24742484
write!(f, "INSERT OR {action} INTO {table_name} ")?;
24752485
} else {

src/parser/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -7678,6 +7678,14 @@ impl<'a> Parser<'a> {
76787678
// Hive lets you put table here regardless
76797679
let table = self.parse_keyword(Keyword::TABLE);
76807680
let table_name = self.parse_object_name()?;
7681+
7682+
let table_alias =
7683+
if dialect_of!(self is PostgreSqlDialect) && self.parse_keyword(Keyword::AS) {
7684+
Some(self.parse_identifier()?)
7685+
} else {
7686+
None
7687+
};
7688+
76817689
let is_mysql = dialect_of!(self is MySqlDialect);
76827690

76837691
let (columns, partitioned, after_columns, source) =
@@ -7752,6 +7760,7 @@ impl<'a> Parser<'a> {
77527760
Ok(Statement::Insert {
77537761
or,
77547762
table_name,
7763+
table_alias,
77557764
ignore,
77567765
into,
77577766
overwrite,

tests/sqlparser_postgres.rs

+198
Original file line numberDiff line numberDiff line change
@@ -3574,3 +3574,201 @@ fn parse_join_constraint_unnest_alias() {
35743574
}]
35753575
);
35763576
}
3577+
3578+
#[test]
3579+
fn test_complex_postgres_insert_with_alias() {
3580+
let sql1 = "WITH existing AS (SELECT test_table.id FROM test_tables AS test_table WHERE (a = 12) AND (b = 34)), inserted AS (INSERT INTO test_tables AS test_table (id, a, b, c) VALUES (DEFAULT, 56, 78, 90) ON CONFLICT(a, b) DO UPDATE SET c = EXCLUDED.c WHERE (test_table.c <> EXCLUDED.c)) SELECT c FROM existing";
3581+
3582+
pg().verified_stmt(sql1);
3583+
}
3584+
3585+
#[cfg(not(feature = "bigdecimal"))]
3586+
#[test]
3587+
fn test_simple_postgres_insert_with_alias() {
3588+
let sql2 = "INSERT INTO test_tables AS test_table (id, a) VALUES (DEFAULT, 123)";
3589+
3590+
let statement = pg().verified_stmt(sql2);
3591+
3592+
assert_eq!(
3593+
statement,
3594+
Statement::Insert {
3595+
or: None,
3596+
ignore: false,
3597+
into: true,
3598+
table_name: ObjectName(vec![Ident {
3599+
value: "test_tables".to_string(),
3600+
quote_style: None
3601+
}]),
3602+
table_alias: Some(Ident {
3603+
value: "test_table".to_string(),
3604+
quote_style: None
3605+
}),
3606+
columns: vec![
3607+
Ident {
3608+
value: "id".to_string(),
3609+
quote_style: None
3610+
},
3611+
Ident {
3612+
value: "a".to_string(),
3613+
quote_style: None
3614+
}
3615+
],
3616+
overwrite: false,
3617+
source: Some(Box::new(Query {
3618+
with: None,
3619+
body: Box::new(SetExpr::Values(Values {
3620+
explicit_row: false,
3621+
rows: vec![vec![
3622+
Expr::Identifier(Ident {
3623+
value: "DEFAULT".to_string(),
3624+
quote_style: None
3625+
}),
3626+
Expr::Value(Value::Number("123".to_string(), false))
3627+
]]
3628+
})),
3629+
order_by: vec![],
3630+
limit: None,
3631+
limit_by: vec![],
3632+
offset: None,
3633+
fetch: None,
3634+
locks: vec![],
3635+
for_clause: None
3636+
})),
3637+
partitioned: None,
3638+
after_columns: vec![],
3639+
table: false,
3640+
on: None,
3641+
returning: None,
3642+
replace_into: false,
3643+
priority: None
3644+
}
3645+
)
3646+
}
3647+
3648+
#[cfg(feature = "bigdecimal")]
3649+
#[test]
3650+
fn test_simple_postgres_insert_with_alias() {
3651+
let sql2 = "INSERT INTO test_tables AS test_table (id, a) VALUES (DEFAULT, 123)";
3652+
3653+
let statement = pg().verified_stmt(sql2);
3654+
3655+
assert_eq!(
3656+
statement,
3657+
Statement::Insert {
3658+
or: None,
3659+
ignore: false,
3660+
into: true,
3661+
table_name: ObjectName(vec![Ident {
3662+
value: "test_tables".to_string(),
3663+
quote_style: None
3664+
}]),
3665+
table_alias: Some(Ident {
3666+
value: "test_table".to_string(),
3667+
quote_style: None
3668+
}),
3669+
columns: vec![
3670+
Ident {
3671+
value: "id".to_string(),
3672+
quote_style: None
3673+
},
3674+
Ident {
3675+
value: "a".to_string(),
3676+
quote_style: None
3677+
}
3678+
],
3679+
overwrite: false,
3680+
source: Some(Box::new(Query {
3681+
with: None,
3682+
body: Box::new(SetExpr::Values(Values {
3683+
explicit_row: false,
3684+
rows: vec![vec![
3685+
Expr::Identifier(Ident {
3686+
value: "DEFAULT".to_string(),
3687+
quote_style: None
3688+
}),
3689+
Expr::Value(Value::Number(
3690+
bigdecimal::BigDecimal::new(123.into(), 0),
3691+
false
3692+
))
3693+
]]
3694+
})),
3695+
order_by: vec![],
3696+
limit: None,
3697+
limit_by: vec![],
3698+
offset: None,
3699+
fetch: None,
3700+
locks: vec![],
3701+
for_clause: None
3702+
})),
3703+
partitioned: None,
3704+
after_columns: vec![],
3705+
table: false,
3706+
on: None,
3707+
returning: None,
3708+
replace_into: false,
3709+
priority: None
3710+
}
3711+
)
3712+
}
3713+
3714+
#[test]
3715+
fn test_simple_insert_with_quoted_alias() {
3716+
let sql = r#"INSERT INTO test_tables AS "Test_Table" (id, a) VALUES (DEFAULT, '0123')"#;
3717+
3718+
let statement = pg().verified_stmt(sql);
3719+
3720+
assert_eq!(
3721+
statement,
3722+
Statement::Insert {
3723+
or: None,
3724+
ignore: false,
3725+
into: true,
3726+
table_name: ObjectName(vec![Ident {
3727+
value: "test_tables".to_string(),
3728+
quote_style: None
3729+
}]),
3730+
table_alias: Some(Ident {
3731+
value: "Test_Table".to_string(),
3732+
quote_style: Some('"')
3733+
}),
3734+
columns: vec![
3735+
Ident {
3736+
value: "id".to_string(),
3737+
quote_style: None
3738+
},
3739+
Ident {
3740+
value: "a".to_string(),
3741+
quote_style: None
3742+
}
3743+
],
3744+
overwrite: false,
3745+
source: Some(Box::new(Query {
3746+
with: None,
3747+
body: Box::new(SetExpr::Values(Values {
3748+
explicit_row: false,
3749+
rows: vec![vec![
3750+
Expr::Identifier(Ident {
3751+
value: "DEFAULT".to_string(),
3752+
quote_style: None
3753+
}),
3754+
Expr::Value(Value::SingleQuotedString("0123".to_string()))
3755+
]]
3756+
})),
3757+
order_by: vec![],
3758+
limit: None,
3759+
limit_by: vec![],
3760+
offset: None,
3761+
fetch: None,
3762+
locks: vec![],
3763+
for_clause: None
3764+
})),
3765+
partitioned: None,
3766+
after_columns: vec![],
3767+
table: false,
3768+
on: None,
3769+
returning: None,
3770+
replace_into: false,
3771+
priority: None
3772+
}
3773+
)
3774+
}

0 commit comments

Comments
 (0)