Skip to content

Commit 9967031

Browse files
committed
Move TableFactor to be a separate enum
ASTNode can now be renamed SQLExpression, as it represents a node in the "expression" part of the AST -- other nodes have their own types.
1 parent e0ceacd commit 9967031

File tree

4 files changed

+82
-67
lines changed

4 files changed

+82
-67
lines changed

src/sqlast/mod.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ mod sqltype;
2020
mod table_key;
2121
mod value;
2222

23-
pub use self::query::{Join, JoinConstraint, JoinOperator, SQLOrderByExpr, SQLSelect};
23+
pub use self::query::{Join, JoinConstraint, JoinOperator, SQLOrderByExpr, SQLSelect, TableFactor};
2424
pub use self::sqltype::SQLType;
2525
pub use self::table_key::{AlterOperation, Key, TableKey};
2626
pub use self::value::Value;
@@ -30,7 +30,8 @@ pub use self::sql_operator::SQLOperator;
3030
/// Identifier name, in the originally quoted form (e.g. `"id"`)
3131
pub type SQLIdent = String;
3232

33-
/// SQL Abstract Syntax Tree (AST)
33+
/// Represents a parsed SQL expression, which is a common building
34+
/// block of SQL statements (the part after SELECT, WHERE, etc.)
3435
#[derive(Debug, Clone, PartialEq)]
3536
pub enum ASTNode {
3637
/// Identifier e.g. table name or column name
@@ -73,11 +74,6 @@ pub enum ASTNode {
7374
results: Vec<ASTNode>,
7475
else_result: Option<Box<ASTNode>>,
7576
},
76-
/// A table name or a parenthesized subquery with an optional alias
77-
TableFactor {
78-
relation: Box<ASTNode>, // SQLNested or SQLCompoundIdentifier
79-
alias: Option<SQLIdent>,
80-
},
8177
/// A parenthesized subquery `(SELECT ...)`, used in expression like
8278
/// `SELECT (subquery) AS x` or `WHERE (subquery) = x`
8379
SQLSubquery(SQLSelect),
@@ -134,13 +130,6 @@ impl ToString for ASTNode {
134130
}
135131
s + " END"
136132
}
137-
ASTNode::TableFactor { relation, alias } => {
138-
if let Some(alias) = alias {
139-
format!("{} AS {}", relation.to_string(), alias)
140-
} else {
141-
relation.to_string()
142-
}
143-
}
144133
ASTNode::SQLSubquery(s) => format!("({})", s.to_string()),
145134
}
146135
}

src/sqlast/query.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub struct SQLSelect {
55
/// projection expressions
66
pub projection: Vec<ASTNode>,
77
/// FROM
8-
pub relation: Option<Box<ASTNode>>, // TableFactor
8+
pub relation: Option<TableFactor>,
99
// JOIN
1010
pub joins: Vec<Join>,
1111
/// WHERE
@@ -31,7 +31,7 @@ impl ToString for SQLSelect {
3131
.join(", ")
3232
);
3333
if let Some(ref relation) = self.relation {
34-
s += &format!(" FROM {}", relation.as_ref().to_string());
34+
s += &format!(" FROM {}", relation.to_string());
3535
}
3636
for join in &self.joins {
3737
s += &join.to_string();
@@ -69,9 +69,38 @@ impl ToString for SQLSelect {
6969
}
7070
}
7171

72+
/// A table name or a parenthesized subquery with an optional alias
73+
#[derive(Debug, Clone, PartialEq)]
74+
pub enum TableFactor {
75+
Table {
76+
name: SQLObjectName,
77+
alias: Option<SQLIdent>,
78+
},
79+
Derived {
80+
subquery: Box<SQLSelect>,
81+
alias: Option<SQLIdent>,
82+
},
83+
}
84+
85+
impl ToString for TableFactor {
86+
fn to_string(&self) -> String {
87+
let (base, alias) = match self {
88+
TableFactor::Table { name, alias } => (name.to_string(), alias),
89+
TableFactor::Derived { subquery, alias } => {
90+
(format!("({})", subquery.to_string()), alias)
91+
}
92+
};
93+
if let Some(alias) = alias {
94+
format!("{} AS {}", base, alias)
95+
} else {
96+
base
97+
}
98+
}
99+
}
100+
72101
#[derive(Debug, Clone, PartialEq)]
73102
pub struct Join {
74-
pub relation: ASTNode, // TableFactor
103+
pub relation: TableFactor,
75104
pub join_operator: JoinOperator,
76105
}
77106

src/sqlparser.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,8 +1119,8 @@ impl Parser {
11191119
pub fn parse_select(&mut self) -> Result<SQLSelect, ParserError> {
11201120
let projection = self.parse_expr_list()?;
11211121

1122-
let (relation, joins): (Option<Box<ASTNode>>, Vec<Join>) = if self.parse_keyword("FROM") {
1123-
let relation = Some(Box::new(self.parse_table_factor()?));
1122+
let (relation, joins) = if self.parse_keyword("FROM") {
1123+
let relation = Some(self.parse_table_factor()?);
11241124
let joins = self.parse_joins()?;
11251125
(relation, joins)
11261126
} else {
@@ -1171,20 +1171,21 @@ impl Parser {
11711171
}
11721172

11731173
/// A table name or a parenthesized subquery, followed by optional `[AS] alias`
1174-
pub fn parse_table_factor(&mut self) -> Result<ASTNode, ParserError> {
1175-
let relation = if self.consume_token(&Token::LParen) {
1174+
pub fn parse_table_factor(&mut self) -> Result<TableFactor, ParserError> {
1175+
if self.consume_token(&Token::LParen) {
11761176
self.expect_keyword("SELECT")?;
11771177
let subquery = self.parse_select()?;
11781178
self.expect_token(&Token::RParen)?;
1179-
ASTNode::SQLSubquery(subquery)
1179+
Ok(TableFactor::Derived {
1180+
subquery: Box::new(subquery),
1181+
alias: self.parse_optional_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?,
1182+
})
11801183
} else {
1181-
ASTNode::SQLCompoundIdentifier(self.parse_object_name()?.0)
1182-
};
1183-
let alias = self.parse_optional_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?;
1184-
Ok(ASTNode::TableFactor {
1185-
relation: Box::new(relation),
1186-
alias,
1187-
})
1184+
Ok(TableFactor::Table {
1185+
name: self.parse_object_name()?,
1186+
alias: self.parse_optional_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?,
1187+
})
1188+
}
11881189
}
11891190

11901191
fn parse_join_constraint(&mut self, natural: bool) -> Result<JoinConstraint, ParserError> {

tests/sqlparser_generic.rs

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,14 @@ fn parse_delimited_identifiers() {
432432
// check that quoted identifiers in any position remain quoted after serialization
433433
let sql = r#"SELECT "alias"."bar baz", "myfun"(), "simple id" FROM "a table" AS "alias""#;
434434
let select = verified_only_select(sql);
435+
// check FROM
436+
match select.relation.unwrap() {
437+
TableFactor::Table { name, alias } => {
438+
assert_eq!(vec![r#""a table""#.to_string()], name.0);
439+
assert_eq!(r#""alias""#, alias.unwrap());
440+
}
441+
_ => panic!("Expecting TableFactor::Table"),
442+
}
435443
// check SELECT
436444
assert_eq!(3, select.projection.len());
437445
assert_eq!(
@@ -515,45 +523,33 @@ fn parse_case_expression() {
515523
#[test]
516524
fn parse_implicit_join() {
517525
let sql = "SELECT * FROM t1, t2";
518-
519-
match verified_stmt(sql) {
520-
SQLStatement::SQLSelect(SQLSelect { joins, .. }) => {
521-
assert_eq!(joins.len(), 1);
522-
assert_eq!(
523-
joins[0],
524-
Join {
525-
relation: ASTNode::TableFactor {
526-
relation: Box::new(ASTNode::SQLCompoundIdentifier(vec!["t2".to_string()])),
527-
alias: None,
528-
},
529-
join_operator: JoinOperator::Implicit
530-
}
531-
)
532-
}
533-
_ => assert!(false),
534-
}
526+
let select = verified_only_select(sql);
527+
assert_eq!(
528+
&Join {
529+
relation: TableFactor::Table {
530+
name: SQLObjectName(vec!["t2".to_string()]),
531+
alias: None,
532+
},
533+
join_operator: JoinOperator::Implicit
534+
},
535+
only(&select.joins),
536+
);
535537
}
536538

537539
#[test]
538540
fn parse_cross_join() {
539541
let sql = "SELECT * FROM t1 CROSS JOIN t2";
540-
541-
match verified_stmt(sql) {
542-
SQLStatement::SQLSelect(SQLSelect { joins, .. }) => {
543-
assert_eq!(joins.len(), 1);
544-
assert_eq!(
545-
joins[0],
546-
Join {
547-
relation: ASTNode::TableFactor {
548-
relation: Box::new(ASTNode::SQLCompoundIdentifier(vec!["t2".to_string()])),
549-
alias: None,
550-
},
551-
join_operator: JoinOperator::Cross
552-
}
553-
)
554-
}
555-
_ => assert!(false),
556-
}
542+
let select = verified_only_select(sql);
543+
assert_eq!(
544+
&Join {
545+
relation: TableFactor::Table {
546+
name: SQLObjectName(vec!["t2".to_string()]),
547+
alias: None,
548+
},
549+
join_operator: JoinOperator::Cross
550+
},
551+
only(&select.joins),
552+
);
557553
}
558554

559555
#[test]
@@ -564,8 +560,8 @@ fn parse_joins_on() {
564560
f: impl Fn(JoinConstraint) -> JoinOperator,
565561
) -> Join {
566562
Join {
567-
relation: ASTNode::TableFactor {
568-
relation: Box::new(ASTNode::SQLCompoundIdentifier(vec![relation.into()])),
563+
relation: TableFactor::Table {
564+
name: SQLObjectName(vec![relation.into()]),
569565
alias,
570566
},
571567
join_operator: f(JoinConstraint::On(ASTNode::SQLBinaryExpr {
@@ -615,8 +611,8 @@ fn parse_joins_using() {
615611
f: impl Fn(JoinConstraint) -> JoinOperator,
616612
) -> Join {
617613
Join {
618-
relation: ASTNode::TableFactor {
619-
relation: Box::new(ASTNode::SQLCompoundIdentifier(vec![relation.into()])),
614+
relation: TableFactor::Table {
615+
name: SQLObjectName(vec![relation.into()]),
620616
alias,
621617
},
622618
join_operator: f(JoinConstraint::Using(vec!["c1".into()])),

0 commit comments

Comments
 (0)