Skip to content

Commit e66c5d2

Browse files
committed
sql-parser: select from clause (nested subqueries)
1 parent 7f571f6 commit e66c5d2

File tree

1 file changed

+152
-69
lines changed

1 file changed

+152
-69
lines changed

src/parser/select/mod.rs

+152-69
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pub trait SelectStatementParser {
2323

2424
fn parse_select_from_clause(&mut self) -> Result<Option<SelectFrom>, ParsingError>;
2525

26+
fn parse_select_from_clause_subquery(&mut self) -> Result<SelectFrom, ParsingError>;
27+
2628
fn parse_alias_if_exists(&mut self) -> Result<Option<String>, ParsingError>;
2729
}
2830

@@ -101,85 +103,87 @@ impl<'a> SelectStatementParser for Parser<'a> {
101103

102104
fn parse_select_from_clause(&mut self) -> Result<Option<SelectFrom>, ParsingError> {
103105
if let Ok(Keyword::From) = self.peek_as_keyword() {
104-
dbg!("parse_select_from_clause");
105106
self.consume_as_keyword(Keyword::From)?;
107+
return Ok(Some(self.parse_select_from_clause_subquery()?));
108+
}
109+
Ok(None)
110+
}
111+
112+
fn parse_select_from_clause_subquery(&mut self) -> Result<SelectFrom, ParsingError> {
113+
dbg!("parse_select_from_clause");
106114

115+
dbg!(&self.peek_token());
116+
if self.peek_as(TokenType::LeftParen).is_ok() {
117+
self.consume_as(TokenType::LeftParen)?;
107118
dbg!(&self.peek_token());
119+
120+
if let Ok(Keyword::Select) = self.peek_as_keyword() {
121+
let subquery = self.parse_select_statement()?;
122+
// Here the right parenthesis is mandatory
123+
self.consume_as(TokenType::RightParen)?;
124+
let alias = self.parse_alias_if_exists()?;
125+
return Ok(SelectFrom::Subquery(SelectFromSubquery {
126+
subquery: Box::new(subquery),
127+
alias,
128+
}));
129+
} else {
130+
let mut froms = Vec::new();
131+
loop {
132+
dbg!("parse_select_from_clause");
133+
let table_or_subquery = self.parse_select_from_clause_subquery()?;
134+
dbg!(&table_or_subquery);
135+
froms.push(table_or_subquery);
136+
137+
if self.consume_as(TokenType::Comma).is_err() {
138+
break;
139+
}
140+
}
141+
// Here the right parenthesis is mandatory
142+
self.consume_as(TokenType::RightParen)?;
143+
return Ok(SelectFrom::Froms(froms));
144+
};
145+
}
146+
147+
if let Ok(id) = self.parse_identifier() {
148+
dbg!("parse_select_from_clause");
108149
if self.peek_as(TokenType::LeftParen).is_ok() {
109150
self.consume_as(TokenType::LeftParen)?;
110-
dbg!(&self.peek_token());
111-
112-
if let Ok(Keyword::Select) = self.peek_as_keyword() {
113-
dbg!(&self.peek_token());
114-
let subquery = self.parse_select_statement()?;
115-
dbg!(&subquery);
116-
117-
// Here the right parenthesis is mandatory
118-
self.consume_as(TokenType::RightParen)?;
119-
if let Ok(Keyword::As) = self.peek_as_keyword() {
120-
self.consume_as_keyword(Keyword::As)?;
121-
let alias = self.consume_as_id()?;
122-
return Ok(Some(SelectFrom::Subquery(SelectFromSubquery {
123-
subquery: Box::new(subquery),
124-
alias: Some(alias.to_string()),
125-
})));
126-
}
127151

128-
if let Ok(value) = self.peek_as_id() {
129-
return Ok(Some(SelectFrom::Subquery(SelectFromSubquery {
130-
subquery: Box::new(subquery),
131-
alias: Some(value.to_string()),
132-
})));
152+
let arguments = self.parse_comma_separated_expressions()?;
153+
154+
self.consume_as(TokenType::RightParen)?;
155+
let alias = self.parse_alias_if_exists()?;
156+
return Ok(SelectFrom::Function(SelectFromFunction {
157+
function_name: id,
158+
arguments,
159+
alias,
160+
}));
161+
} else {
162+
let alias = self.parse_alias_if_exists()?;
163+
164+
let indexed_type = {
165+
if self.consume_as_keyword(Keyword::Indexed).is_ok() {
166+
self.consume_as_keyword(Keyword::By)?;
167+
Some(IndexedType::Indexed(self.consume_as_id()?))
168+
} else if self.consume_as_keyword(Keyword::Not).is_ok() {
169+
self.consume_as_keyword(Keyword::Indexed)?;
170+
Some(IndexedType::NotIndexed)
171+
} else {
172+
None
133173
}
174+
};
134175

135-
return Ok(Some(SelectFrom::Subquery(SelectFromSubquery {
136-
subquery: Box::new(subquery),
137-
alias: None,
138-
})));
139-
}
140-
}
141-
142-
if let Ok(id) = self.parse_identifier() {
143-
dbg!("parse_select_from_clause");
144-
if self.peek_as(TokenType::LeftParen).is_ok() {
145-
self.consume_as(TokenType::LeftParen)?;
146-
147-
let arguments = self.parse_comma_separated_expressions()?;
148-
149-
self.consume_as(TokenType::RightParen)?;
150-
let alias = self.parse_alias_if_exists()?;
151-
return Ok(Some(SelectFrom::Function(SelectFromFunction {
152-
function_name: id,
153-
arguments,
154-
alias,
155-
})));
156-
} else {
157-
let alias = self.parse_alias_if_exists()?;
158-
159-
let indexed_type = {
160-
if self.consume_as_keyword(Keyword::Indexed).is_ok() {
161-
self.consume_as_keyword(Keyword::By)?;
162-
Some(IndexedType::Indexed(self.consume_as_id()?))
163-
} else if self.consume_as_keyword(Keyword::Not).is_ok() {
164-
self.consume_as_keyword(Keyword::Indexed)?;
165-
Some(IndexedType::NotIndexed)
166-
} else {
167-
None
168-
}
169-
};
170-
171-
return Ok(Some(SelectFrom::Table(SelectFromTable {
172-
table_id: id,
173-
alias,
174-
indexed_type,
175-
})));
176-
}
176+
return Ok(SelectFrom::Table(SelectFromTable {
177+
table_id: id,
178+
alias,
179+
indexed_type,
180+
}));
177181
}
178-
179-
// TODO: Parse table-or-subquery
180-
return Ok(None);
181182
}
182-
Ok(None)
183+
// TODO: improve this error message
184+
Err(ParsingError::UnexpectedToken(
185+
self.peek_token()?.to_string(),
186+
))
183187
}
184188

185189
fn parse_alias_if_exists(&mut self) -> Result<Option<String>, ParsingError> {
@@ -670,3 +674,82 @@ mod test_select_from_table_function {
670674
);
671675
}
672676
}
677+
678+
#[cfg(test)]
679+
mod test_select_from_comma_separated_table_or_subqueries {
680+
use super::test_utils::select_statement_with_from;
681+
use crate::expression::test_utils::numeric_literal_expression;
682+
use crate::parser::test_utils::*;
683+
use crate::{
684+
Identifier, IndexedType, SelectFrom, SelectFromFunction, SelectFromSubquery,
685+
SelectFromTable, Statement,
686+
};
687+
688+
#[test]
689+
fn test_select_from_comma_separated_table_or_subqueries() {
690+
let expected_statement = select_statement_with_from(SelectFrom::Froms(vec![
691+
SelectFrom::Table(SelectFromTable::from(Identifier::Single(
692+
"table_1".to_string(),
693+
))),
694+
SelectFrom::Table(SelectFromTable::from(Identifier::Compound(vec![
695+
"schema2".to_string(),
696+
"table2".to_string(),
697+
]))),
698+
SelectFrom::Table(SelectFromTable {
699+
table_id: Identifier::Compound(vec!["schema3".to_string(), "table3".to_string()]),
700+
alias: Some("table3_alias".to_string()),
701+
indexed_type: None,
702+
}),
703+
SelectFrom::Table(SelectFromTable {
704+
table_id: Identifier::Single("indexed_table".to_string()),
705+
alias: Some("t1".to_string()),
706+
indexed_type: Some(IndexedType::Indexed("index_1".to_string())),
707+
}),
708+
SelectFrom::Table(SelectFromTable {
709+
table_id: Identifier::Single("not_indexed_table".to_string()),
710+
alias: Some("t2".to_string()),
711+
indexed_type: Some(IndexedType::NotIndexed),
712+
}),
713+
SelectFrom::Function(SelectFromFunction {
714+
function_name: Identifier::Compound(vec![
715+
"schema4".to_string(),
716+
"function_1".to_string(),
717+
]),
718+
arguments: vec![
719+
numeric_literal_expression("1"),
720+
numeric_literal_expression("2"),
721+
numeric_literal_expression("3"),
722+
],
723+
alias: Some("f1".to_string()),
724+
}),
725+
SelectFrom::Subquery(SelectFromSubquery {
726+
subquery: Box::new(select_statement_with_from(SelectFrom::Table(
727+
SelectFromTable::from(Identifier::Single("table_2".to_string())),
728+
))),
729+
alias: Some("select_alias".to_string()),
730+
}),
731+
SelectFrom::Froms(vec![
732+
SelectFrom::Table(SelectFromTable::from(Identifier::Single(
733+
"froms_1".to_string(),
734+
))),
735+
SelectFrom::Table(SelectFromTable::from(Identifier::Single(
736+
"froms_2".to_string(),
737+
))),
738+
]),
739+
]));
740+
741+
run_sunny_day_test(
742+
"SELECT * FROM (
743+
table_1,
744+
schema2.table2,
745+
schema3.table3 as table3_alias,
746+
indexed_table as t1 INDEXED BY index_1,
747+
not_indexed_table as t2 NOT INDEXED,
748+
schema4.function_1(1, 2, 3) as f1,
749+
(SELECT * FROM table_2) as select_alias,
750+
(froms_1, froms_2)
751+
)",
752+
Statement::Select(expected_statement),
753+
);
754+
}
755+
}

0 commit comments

Comments
 (0)