Skip to content

Commit 647ddce

Browse files
committed
Add support for PostgreSQL Insert table aliases (#1069)
1 parent c62ecb1 commit 647ddce

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)
@@ -2400,6 +2403,7 @@ impl fmt::Display for Statement {
24002403
ignore,
24012404
into,
24022405
table_name,
2406+
table_alias,
24032407
overwrite,
24042408
partitioned,
24052409
columns,
@@ -2411,6 +2415,12 @@ impl fmt::Display for Statement {
24112415
replace_into,
24122416
priority,
24132417
} => {
2418+
let table_name = if let Some(alias) = table_alias {
2419+
format!("{table_name} AS {alias}")
2420+
} else {
2421+
table_name.to_string()
2422+
};
2423+
24142424
if let Some(action) = or {
24152425
write!(f, "INSERT OR {action} INTO {table_name} ")?;
24162426
} else {

src/parser/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -7456,6 +7456,14 @@ impl<'a> Parser<'a> {
74567456
// Hive lets you put table here regardless
74577457
let table = self.parse_keyword(Keyword::TABLE);
74587458
let table_name = self.parse_object_name()?;
7459+
7460+
let table_alias =
7461+
if dialect_of!(self is PostgreSqlDialect) && self.parse_keyword(Keyword::AS) {
7462+
Some(self.parse_identifier()?)
7463+
} else {
7464+
None
7465+
};
7466+
74597467
let is_mysql = dialect_of!(self is MySqlDialect);
74607468

74617469
let (columns, partitioned, after_columns, source) =
@@ -7530,6 +7538,7 @@ impl<'a> Parser<'a> {
75307538
Ok(Statement::Insert {
75317539
or,
75327540
table_name,
7541+
table_alias,
75337542
ignore,
75347543
into,
75357544
overwrite,

tests/sqlparser_postgres.rs

+198
Original file line numberDiff line numberDiff line change
@@ -3500,3 +3500,201 @@ fn parse_join_constraint_unnest_alias() {
35003500
}]
35013501
);
35023502
}
3503+
3504+
#[test]
3505+
fn test_complex_postgres_insert_with_alias() {
3506+
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";
3507+
3508+
pg().verified_stmt(sql1);
3509+
}
3510+
3511+
#[cfg(not(feature = "bigdecimal"))]
3512+
#[test]
3513+
fn test_simple_postgres_insert_with_alias() {
3514+
let sql2 = "INSERT INTO test_tables AS test_table (id, a) VALUES (DEFAULT, 123)";
3515+
3516+
let statement = pg().verified_stmt(sql2);
3517+
3518+
assert_eq!(
3519+
statement,
3520+
Statement::Insert {
3521+
or: None,
3522+
ignore: false,
3523+
into: true,
3524+
table_name: ObjectName(vec![Ident {
3525+
value: "test_tables".to_string(),
3526+
quote_style: None
3527+
}]),
3528+
table_alias: Some(Ident {
3529+
value: "test_table".to_string(),
3530+
quote_style: None
3531+
}),
3532+
columns: vec![
3533+
Ident {
3534+
value: "id".to_string(),
3535+
quote_style: None
3536+
},
3537+
Ident {
3538+
value: "a".to_string(),
3539+
quote_style: None
3540+
}
3541+
],
3542+
overwrite: false,
3543+
source: Some(Box::new(Query {
3544+
with: None,
3545+
body: Box::new(SetExpr::Values(Values {
3546+
explicit_row: false,
3547+
rows: vec![vec![
3548+
Expr::Identifier(Ident {
3549+
value: "DEFAULT".to_string(),
3550+
quote_style: None
3551+
}),
3552+
Expr::Value(Value::Number("123".to_string(), false))
3553+
]]
3554+
})),
3555+
order_by: vec![],
3556+
limit: None,
3557+
limit_by: vec![],
3558+
offset: None,
3559+
fetch: None,
3560+
locks: vec![],
3561+
for_clause: None
3562+
})),
3563+
partitioned: None,
3564+
after_columns: vec![],
3565+
table: false,
3566+
on: None,
3567+
returning: None,
3568+
replace_into: false,
3569+
priority: None
3570+
}
3571+
)
3572+
}
3573+
3574+
#[cfg(feature = "bigdecimal")]
3575+
#[test]
3576+
fn test_simple_postgres_insert_with_alias() {
3577+
let sql2 = "INSERT INTO test_tables AS test_table (id, a) VALUES (DEFAULT, 123)";
3578+
3579+
let statement = pg().verified_stmt(sql2);
3580+
3581+
assert_eq!(
3582+
statement,
3583+
Statement::Insert {
3584+
or: None,
3585+
ignore: false,
3586+
into: true,
3587+
table_name: ObjectName(vec![Ident {
3588+
value: "test_tables".to_string(),
3589+
quote_style: None
3590+
}]),
3591+
table_alias: Some(Ident {
3592+
value: "test_table".to_string(),
3593+
quote_style: None
3594+
}),
3595+
columns: vec![
3596+
Ident {
3597+
value: "id".to_string(),
3598+
quote_style: None
3599+
},
3600+
Ident {
3601+
value: "a".to_string(),
3602+
quote_style: None
3603+
}
3604+
],
3605+
overwrite: false,
3606+
source: Some(Box::new(Query {
3607+
with: None,
3608+
body: Box::new(SetExpr::Values(Values {
3609+
explicit_row: false,
3610+
rows: vec![vec![
3611+
Expr::Identifier(Ident {
3612+
value: "DEFAULT".to_string(),
3613+
quote_style: None
3614+
}),
3615+
Expr::Value(Value::Number(
3616+
bigdecimal::BigDecimal::new(123.into(), 0),
3617+
false
3618+
))
3619+
]]
3620+
})),
3621+
order_by: vec![],
3622+
limit: None,
3623+
limit_by: vec![],
3624+
offset: None,
3625+
fetch: None,
3626+
locks: vec![],
3627+
for_clause: None
3628+
})),
3629+
partitioned: None,
3630+
after_columns: vec![],
3631+
table: false,
3632+
on: None,
3633+
returning: None,
3634+
replace_into: false,
3635+
priority: None
3636+
}
3637+
)
3638+
}
3639+
3640+
#[test]
3641+
fn test_simple_insert_with_quoted_alias() {
3642+
let sql = r#"INSERT INTO test_tables AS "Test_Table" (id, a) VALUES (DEFAULT, '0123')"#;
3643+
3644+
let statement = pg().verified_stmt(sql);
3645+
3646+
assert_eq!(
3647+
statement,
3648+
Statement::Insert {
3649+
or: None,
3650+
ignore: false,
3651+
into: true,
3652+
table_name: ObjectName(vec![Ident {
3653+
value: "test_tables".to_string(),
3654+
quote_style: None
3655+
}]),
3656+
table_alias: Some(Ident {
3657+
value: "Test_Table".to_string(),
3658+
quote_style: Some('"')
3659+
}),
3660+
columns: vec![
3661+
Ident {
3662+
value: "id".to_string(),
3663+
quote_style: None
3664+
},
3665+
Ident {
3666+
value: "a".to_string(),
3667+
quote_style: None
3668+
}
3669+
],
3670+
overwrite: false,
3671+
source: Some(Box::new(Query {
3672+
with: None,
3673+
body: Box::new(SetExpr::Values(Values {
3674+
explicit_row: false,
3675+
rows: vec![vec![
3676+
Expr::Identifier(Ident {
3677+
value: "DEFAULT".to_string(),
3678+
quote_style: None
3679+
}),
3680+
Expr::Value(Value::SingleQuotedString("0123".to_string()))
3681+
]]
3682+
})),
3683+
order_by: vec![],
3684+
limit: None,
3685+
limit_by: vec![],
3686+
offset: None,
3687+
fetch: None,
3688+
locks: vec![],
3689+
for_clause: None
3690+
})),
3691+
partitioned: None,
3692+
after_columns: vec![],
3693+
table: false,
3694+
on: None,
3695+
returning: None,
3696+
replace_into: false,
3697+
priority: None
3698+
}
3699+
)
3700+
}

0 commit comments

Comments
 (0)