Skip to content

Commit 85ba953

Browse files
authored
Merge pull request #87 from nickolay/pr/join-refactor
Refactor parse_joins
2 parents 2308c1c + d0f2de0 commit 85ba953

File tree

3 files changed

+92
-92
lines changed

3 files changed

+92
-92
lines changed

src/sqlast/query.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -271,34 +271,34 @@ impl ToString for Join {
271271
}
272272
fn suffix(constraint: &JoinConstraint) -> String {
273273
match constraint {
274-
JoinConstraint::On(expr) => format!("ON {}", expr.to_string()),
275-
JoinConstraint::Using(attrs) => format!("USING({})", attrs.join(", ")),
274+
JoinConstraint::On(expr) => format!(" ON {}", expr.to_string()),
275+
JoinConstraint::Using(attrs) => format!(" USING({})", attrs.join(", ")),
276276
_ => "".to_string(),
277277
}
278278
}
279279
match &self.join_operator {
280280
JoinOperator::Inner(constraint) => format!(
281-
" {}JOIN {} {}",
281+
" {}JOIN {}{}",
282282
prefix(constraint),
283283
self.relation.to_string(),
284284
suffix(constraint)
285285
),
286286
JoinOperator::Cross => format!(" CROSS JOIN {}", self.relation.to_string()),
287287
JoinOperator::Implicit => format!(", {}", self.relation.to_string()),
288288
JoinOperator::LeftOuter(constraint) => format!(
289-
" {}LEFT JOIN {} {}",
289+
" {}LEFT JOIN {}{}",
290290
prefix(constraint),
291291
self.relation.to_string(),
292292
suffix(constraint)
293293
),
294294
JoinOperator::RightOuter(constraint) => format!(
295-
" {}RIGHT JOIN {} {}",
295+
" {}RIGHT JOIN {}{}",
296296
prefix(constraint),
297297
self.relation.to_string(),
298298
suffix(constraint)
299299
),
300300
JoinOperator::FullOuter(constraint) => format!(
301-
" {}FULL JOIN {} {}",
301+
" {}FULL JOIN {}{}",
302302
prefix(constraint),
303303
self.relation.to_string(),
304304
suffix(constraint)

src/sqlparser.rs

+49-86
Original file line numberDiff line numberDiff line change
@@ -702,14 +702,10 @@ impl Parser {
702702
/// Consume the next token if it matches the expected token, otherwise return false
703703
#[must_use]
704704
pub fn consume_token(&mut self, expected: &Token) -> bool {
705-
match self.peek_token() {
706-
Some(ref t) => {
707-
if *t == *expected {
708-
self.next_token();
709-
true
710-
} else {
711-
false
712-
}
705+
match &self.peek_token() {
706+
Some(t) if *t == *expected => {
707+
self.next_token();
708+
true
713709
}
714710
_ => false,
715711
}
@@ -1503,90 +1499,62 @@ impl Parser {
15031499
fn parse_joins(&mut self) -> Result<Vec<Join>, ParserError> {
15041500
let mut joins = vec![];
15051501
loop {
1506-
let natural = match &self.peek_token() {
1507-
Some(Token::Comma) => {
1508-
self.next_token();
1509-
let relation = self.parse_table_factor()?;
1510-
let join = Join {
1511-
relation,
1512-
join_operator: JoinOperator::Implicit,
1513-
};
1514-
joins.push(join);
1515-
continue;
1516-
}
1517-
Some(Token::SQLWord(kw)) if kw.keyword == "CROSS" => {
1518-
self.next_token();
1519-
self.expect_keyword("JOIN")?;
1520-
let relation = self.parse_table_factor()?;
1521-
let join = Join {
1522-
relation,
1523-
join_operator: JoinOperator::Cross,
1524-
};
1525-
joins.push(join);
1526-
continue;
1527-
}
1528-
Some(Token::SQLWord(kw)) if kw.keyword == "NATURAL" => {
1529-
self.next_token();
1530-
true
1531-
}
1532-
Some(_) => false,
1533-
None => return Ok(joins),
1534-
};
1535-
15361502
let join = match &self.peek_token() {
1537-
Some(Token::SQLWord(kw)) if kw.keyword == "INNER" => {
1538-
self.next_token();
1539-
self.expect_keyword("JOIN")?;
1540-
Join {
1541-
relation: self.parse_table_factor()?,
1542-
join_operator: JoinOperator::Inner(self.parse_join_constraint(natural)?),
1543-
}
1544-
}
1545-
Some(Token::SQLWord(kw)) if kw.keyword == "JOIN" => {
1546-
self.next_token();
1547-
Join {
1548-
relation: self.parse_table_factor()?,
1549-
join_operator: JoinOperator::Inner(self.parse_join_constraint(natural)?),
1550-
}
1551-
}
1552-
Some(Token::SQLWord(kw)) if kw.keyword == "LEFT" => {
1503+
Some(Token::Comma) => {
15531504
self.next_token();
1554-
let _ = self.parse_keyword("OUTER");
1555-
self.expect_keyword("JOIN")?;
15561505
Join {
15571506
relation: self.parse_table_factor()?,
1558-
join_operator: JoinOperator::LeftOuter(
1559-
self.parse_join_constraint(natural)?,
1560-
),
1507+
join_operator: JoinOperator::Implicit,
15611508
}
15621509
}
1563-
Some(Token::SQLWord(kw)) if kw.keyword == "RIGHT" => {
1510+
Some(Token::SQLWord(kw)) if kw.keyword == "CROSS" => {
15641511
self.next_token();
1565-
let _ = self.parse_keyword("OUTER");
15661512
self.expect_keyword("JOIN")?;
15671513
Join {
15681514
relation: self.parse_table_factor()?,
1569-
join_operator: JoinOperator::RightOuter(
1570-
self.parse_join_constraint(natural)?,
1571-
),
1515+
join_operator: JoinOperator::Cross,
15721516
}
15731517
}
1574-
Some(Token::SQLWord(kw)) if kw.keyword == "FULL" => {
1575-
self.next_token();
1576-
let _ = self.parse_keyword("OUTER");
1577-
self.expect_keyword("JOIN")?;
1518+
_ => {
1519+
let natural = self.parse_keyword("NATURAL");
1520+
let peek_keyword = if let Some(Token::SQLWord(kw)) = self.peek_token() {
1521+
kw.keyword
1522+
} else {
1523+
String::default()
1524+
};
1525+
1526+
let join_operator_type = match peek_keyword.as_ref() {
1527+
"INNER" | "JOIN" => {
1528+
let _ = self.parse_keyword("INNER");
1529+
self.expect_keyword("JOIN")?;
1530+
JoinOperator::Inner
1531+
}
1532+
kw @ "LEFT" | kw @ "RIGHT" | kw @ "FULL" => {
1533+
let _ = self.next_token();
1534+
let _ = self.parse_keyword("OUTER");
1535+
self.expect_keyword("JOIN")?;
1536+
match kw {
1537+
"LEFT" => JoinOperator::LeftOuter,
1538+
"RIGHT" => JoinOperator::RightOuter,
1539+
"FULL" => JoinOperator::FullOuter,
1540+
_ => unreachable!(),
1541+
}
1542+
}
1543+
_ if natural => {
1544+
return self.expected("a join type after NATURAL", self.peek_token());
1545+
}
1546+
_ => break,
1547+
};
1548+
let relation = self.parse_table_factor()?;
1549+
let join_constraint = self.parse_join_constraint(natural)?;
15781550
Join {
1579-
relation: self.parse_table_factor()?,
1580-
join_operator: JoinOperator::FullOuter(
1581-
self.parse_join_constraint(natural)?,
1582-
),
1551+
relation,
1552+
join_operator: join_operator_type(join_constraint),
15831553
}
15841554
}
1585-
_ => break,
15861555
};
15871556
joins.push(join);
15881557
}
1589-
15901558
Ok(joins)
15911559
}
15921560

@@ -1611,10 +1579,9 @@ impl Parser {
16111579
let mut expr_list: Vec<ASTNode> = vec![];
16121580
loop {
16131581
expr_list.push(self.parse_expr()?);
1614-
match self.peek_token() {
1615-
Some(Token::Comma) => self.next_token(),
1616-
_ => break,
1617-
};
1582+
if !self.consume_token(&Token::Comma) {
1583+
break;
1584+
}
16181585
}
16191586
Ok(expr_list)
16201587
}
@@ -1649,10 +1616,9 @@ impl Parser {
16491616
}
16501617
}
16511618

1652-
match self.peek_token() {
1653-
Some(Token::Comma) => self.next_token(),
1654-
_ => break,
1655-
};
1619+
if !self.consume_token(&Token::Comma) {
1620+
break;
1621+
}
16561622
}
16571623
Ok(projections)
16581624
}
@@ -1672,10 +1638,7 @@ impl Parser {
16721638
};
16731639

16741640
expr_list.push(SQLOrderByExpr { expr, asc });
1675-
1676-
if let Some(Token::Comma) = self.peek_token() {
1677-
self.next_token();
1678-
} else {
1641+
if !self.consume_token(&Token::Comma) {
16791642
break;
16801643
}
16811644
}

tests/sqlparser_common.rs

+37
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,43 @@ fn parse_joins_using() {
12181218
);
12191219
}
12201220

1221+
#[test]
1222+
fn parse_natural_join() {
1223+
fn natural_join(f: impl Fn(JoinConstraint) -> JoinOperator) -> Join {
1224+
Join {
1225+
relation: TableFactor::Table {
1226+
name: SQLObjectName(vec!["t2".to_string()]),
1227+
alias: None,
1228+
args: vec![],
1229+
with_hints: vec![],
1230+
},
1231+
join_operator: f(JoinConstraint::Natural),
1232+
}
1233+
}
1234+
assert_eq!(
1235+
verified_only_select("SELECT * FROM t1 NATURAL JOIN t2").joins,
1236+
vec![natural_join(JoinOperator::Inner)]
1237+
);
1238+
assert_eq!(
1239+
verified_only_select("SELECT * FROM t1 NATURAL LEFT JOIN t2").joins,
1240+
vec![natural_join(JoinOperator::LeftOuter)]
1241+
);
1242+
assert_eq!(
1243+
verified_only_select("SELECT * FROM t1 NATURAL RIGHT JOIN t2").joins,
1244+
vec![natural_join(JoinOperator::RightOuter)]
1245+
);
1246+
assert_eq!(
1247+
verified_only_select("SELECT * FROM t1 NATURAL FULL JOIN t2").joins,
1248+
vec![natural_join(JoinOperator::FullOuter)]
1249+
);
1250+
1251+
let sql = "SELECT * FROM t1 natural";
1252+
assert_eq!(
1253+
ParserError::ParserError("Expected a join type after NATURAL, found: EOF".to_string()),
1254+
parse_sql_statements(sql).unwrap_err(),
1255+
);
1256+
}
1257+
12211258
#[test]
12221259
fn parse_complex_join() {
12231260
let sql = "SELECT c1, c2 FROM t1, t4 JOIN t2 ON t2.c = t1.c LEFT JOIN t3 USING(q, c) WHERE t4.c = t1.c";

0 commit comments

Comments
 (0)