Skip to content

Commit 11899fd

Browse files
authored
Support row_alias and col_aliases in INSERT statement for mysql and generic dialects (#1136)
1 parent 5da66ad commit 11899fd

File tree

4 files changed

+148
-4
lines changed

4 files changed

+148
-4
lines changed

src/ast/mod.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,8 @@ pub enum Statement {
17591759
replace_into: bool,
17601760
/// Only for mysql
17611761
priority: Option<MysqlInsertPriority>,
1762+
/// Only for mysql
1763+
insert_alias: Option<InsertAliases>,
17621764
},
17631765
/// ```sql
17641766
/// INSTALL
@@ -2773,6 +2775,7 @@ impl fmt::Display for Statement {
27732775
returning,
27742776
replace_into,
27752777
priority,
2778+
insert_alias,
27762779
} => {
27772780
let table_name = if let Some(alias) = table_alias {
27782781
format!("{table_name} AS {alias}")
@@ -2822,6 +2825,16 @@ impl fmt::Display for Statement {
28222825
write!(f, "DEFAULT VALUES")?;
28232826
}
28242827

2828+
if let Some(insert_alias) = insert_alias {
2829+
write!(f, " AS {0}", insert_alias.row_alias)?;
2830+
2831+
if let Some(col_aliases) = &insert_alias.col_aliases {
2832+
if !col_aliases.is_empty() {
2833+
write!(f, " ({})", display_comma_separated(col_aliases))?;
2834+
}
2835+
}
2836+
}
2837+
28252838
if let Some(on) = on {
28262839
write!(f, "{on}")?;
28272840
}
@@ -4194,6 +4207,14 @@ pub enum OnInsert {
41944207
OnConflict(OnConflict),
41954208
}
41964209

4210+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4211+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4212+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4213+
pub struct InsertAliases {
4214+
pub row_alias: ObjectName,
4215+
pub col_aliases: Option<Vec<Ident>>,
4216+
}
4217+
41974218
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
41984219
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41994220
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]

src/parser/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8419,6 +8419,19 @@ impl<'a> Parser<'a> {
84198419
(columns, partitioned, after_columns, source)
84208420
};
84218421

8422+
let insert_alias = if dialect_of!(self is MySqlDialect | GenericDialect)
8423+
&& self.parse_keyword(Keyword::AS)
8424+
{
8425+
let row_alias = self.parse_object_name(false)?;
8426+
let col_aliases = Some(self.parse_parenthesized_column_list(Optional, false)?);
8427+
Some(InsertAliases {
8428+
row_alias,
8429+
col_aliases,
8430+
})
8431+
} else {
8432+
None
8433+
};
8434+
84228435
let on = if self.parse_keyword(Keyword::ON) {
84238436
if self.parse_keyword(Keyword::CONFLICT) {
84248437
let conflict_target =
@@ -8488,6 +8501,7 @@ impl<'a> Parser<'a> {
84888501
returning,
84898502
replace_into,
84908503
priority,
8504+
insert_alias,
84918505
})
84928506
}
84938507
}

tests/sqlparser_mysql.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use matches::assert_matches;
1919
use sqlparser::ast::MysqlInsertPriority::{Delayed, HighPriority, LowPriority};
2020
use sqlparser::ast::*;
2121
use sqlparser::dialect::{GenericDialect, MySqlDialect};
22-
use sqlparser::parser::ParserOptions;
22+
use sqlparser::parser::{ParserError, ParserOptions};
2323
use sqlparser::tokenizer::Token;
2424
use test_utils::*;
2525

@@ -1330,6 +1330,112 @@ fn parse_priority_insert() {
13301330
}
13311331
}
13321332

1333+
#[test]
1334+
fn parse_insert_as() {
1335+
let sql = r"INSERT INTO `table` (`date`) VALUES ('2024-01-01') AS `alias`";
1336+
match mysql_and_generic().verified_stmt(sql) {
1337+
Statement::Insert {
1338+
table_name,
1339+
columns,
1340+
source,
1341+
insert_alias,
1342+
..
1343+
} => {
1344+
assert_eq!(
1345+
ObjectName(vec![Ident::with_quote('`', "table")]),
1346+
table_name
1347+
);
1348+
assert_eq!(vec![Ident::with_quote('`', "date")], columns);
1349+
let insert_alias = insert_alias.unwrap();
1350+
1351+
assert_eq!(
1352+
ObjectName(vec![Ident::with_quote('`', "alias")]),
1353+
insert_alias.row_alias
1354+
);
1355+
assert_eq!(Some(vec![]), insert_alias.col_aliases);
1356+
assert_eq!(
1357+
Some(Box::new(Query {
1358+
with: None,
1359+
body: Box::new(SetExpr::Values(Values {
1360+
explicit_row: false,
1361+
rows: vec![vec![Expr::Value(Value::SingleQuotedString(
1362+
"2024-01-01".to_string()
1363+
))]]
1364+
})),
1365+
order_by: vec![],
1366+
limit: None,
1367+
limit_by: vec![],
1368+
offset: None,
1369+
fetch: None,
1370+
locks: vec![],
1371+
for_clause: None,
1372+
})),
1373+
source
1374+
);
1375+
}
1376+
_ => unreachable!(),
1377+
}
1378+
1379+
let sql = r"INSERT INTO `table` (`date`) VALUES ('2024-01-01') AS `alias` ()";
1380+
assert!(matches!(
1381+
mysql_and_generic().parse_sql_statements(sql),
1382+
Err(ParserError::ParserError(_))
1383+
));
1384+
1385+
let sql = r"INSERT INTO `table` (`id`, `date`) VALUES (1, '2024-01-01') AS `alias` (`mek_id`, `mek_date`)";
1386+
match mysql_and_generic().verified_stmt(sql) {
1387+
Statement::Insert {
1388+
table_name,
1389+
columns,
1390+
source,
1391+
insert_alias,
1392+
..
1393+
} => {
1394+
assert_eq!(
1395+
ObjectName(vec![Ident::with_quote('`', "table")]),
1396+
table_name
1397+
);
1398+
assert_eq!(
1399+
vec![Ident::with_quote('`', "id"), Ident::with_quote('`', "date")],
1400+
columns
1401+
);
1402+
let insert_alias = insert_alias.unwrap();
1403+
assert_eq!(
1404+
ObjectName(vec![Ident::with_quote('`', "alias")]),
1405+
insert_alias.row_alias
1406+
);
1407+
assert_eq!(
1408+
Some(vec![
1409+
Ident::with_quote('`', "mek_id"),
1410+
Ident::with_quote('`', "mek_date")
1411+
]),
1412+
insert_alias.col_aliases
1413+
);
1414+
assert_eq!(
1415+
Some(Box::new(Query {
1416+
with: None,
1417+
body: Box::new(SetExpr::Values(Values {
1418+
explicit_row: false,
1419+
rows: vec![vec![
1420+
Expr::Value(number("1")),
1421+
Expr::Value(Value::SingleQuotedString("2024-01-01".to_string()))
1422+
]]
1423+
})),
1424+
order_by: vec![],
1425+
limit: None,
1426+
limit_by: vec![],
1427+
offset: None,
1428+
fetch: None,
1429+
locks: vec![],
1430+
for_clause: None,
1431+
})),
1432+
source
1433+
);
1434+
}
1435+
_ => unreachable!(),
1436+
}
1437+
}
1438+
13331439
#[test]
13341440
fn parse_replace_insert() {
13351441
let sql = r"REPLACE DELAYED INTO tasks (title, priority) VALUES ('Test Some Inserts', 1)";

tests/sqlparser_postgres.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3764,7 +3764,8 @@ fn test_simple_postgres_insert_with_alias() {
37643764
on: None,
37653765
returning: None,
37663766
replace_into: false,
3767-
priority: None
3767+
priority: None,
3768+
insert_alias: None
37683769
}
37693770
)
37703771
}
@@ -3830,7 +3831,8 @@ fn test_simple_postgres_insert_with_alias() {
38303831
on: None,
38313832
returning: None,
38323833
replace_into: false,
3833-
priority: None
3834+
priority: None,
3835+
insert_alias: None
38343836
}
38353837
)
38363838
}
@@ -3892,7 +3894,8 @@ fn test_simple_insert_with_quoted_alias() {
38923894
on: None,
38933895
returning: None,
38943896
replace_into: false,
3895-
priority: None
3897+
priority: None,
3898+
insert_alias: None,
38963899
}
38973900
)
38983901
}

0 commit comments

Comments
 (0)