use crate::parser::ast::*;
use crate::parser::error::{Expected, ParseResult};
use crate::parser::state::Parser;
use crate::parser::token::Keyword;
pub fn parse_select(parser: &mut Parser) -> ParseResult<SelectStmt> {
parser.expect_keyword(Keyword::Select)?;
parse_select_body(parser)
}
pub fn parse_select_body(parser: &mut Parser) -> ParseResult<SelectStmt> {
let mut current = parse_single_select_body(parser)?;
while let Some(Token::Keyword(k)) = parser.peek() {
let kind = match *k {
Keyword::Union => {
let _ = parser.next();
if matches!(parser.peek(), Some(Token::Keyword(Keyword::All))) {
let _ = parser.next();
SetOpKind::UnionAll
} else {
SetOpKind::Union
}
}
Keyword::Intersect => {
let _ = parser.next();
SetOpKind::Intersect
}
Keyword::Except => {
let _ = parser.next();
SetOpKind::Except
}
_ => break,
};
let right = parse_single_select(parser)?;
let mut target = &mut current;
while let Some(ref mut op) = target.set_op {
target = &mut op.right;
}
target.set_op = Some(Box::new(SetOp { kind, right }));
}
Ok(current)
}
fn parse_single_select(parser: &mut Parser) -> ParseResult<SelectStmt> {
parser.expect_keyword(Keyword::Select)?;
parse_single_select_body(parser)
}
pub fn parse_single_select_body(parser: &mut Parser) -> ParseResult<SelectStmt> {
let mut distinct = false;
if let Some(Token::Keyword(Keyword::Distinct)) = parser.peek() {
let _ = parser.next();
distinct = true;
}
let mut top = None;
if let Some(Token::Keyword(Keyword::Top)) = parser.peek() {
let _ = parser.next();
top = Some(TopSpec {
value: crate::parser::parse::expressions::parse_primary(parser)?,
});
}
let projection = parse_projection(parser)?;
let mut into_table = None;
if let Some(Token::Keyword(Keyword::Into)) = parser.peek() {
let _ = parser.next();
into_table = Some(parse_object_name(parse_multipart_name(parser)?));
}
let mut from = None;
let mut joins = Vec::new();
if let Some(tok) = parser.peek() {
let is_from = match tok {
Token::Keyword(Keyword::From) => true,
Token::Identifier(id) => id.eq_ignore_ascii_case("FROM"),
_ => false,
};
if is_from {
let _ = parser.next();
let tables =
crate::parser::parse::expressions::parse_comma_list(parser, parse_table_ref)?;
let mut iter = tables.into_iter();
from = iter.next();
for table in iter {
joins.push(JoinClause {
join_type: JoinType::Cross,
table,
on: None,
});
}
}
}
while let Some(join) = parse_join_clause(parser)? {
joins.push(join);
}
let mut applies = Vec::new();
while let Some(Token::Keyword(k)) = parser.peek() {
let apply_type = match *k {
Keyword::Cross => {
let saved = parser.save();
let _ = parser.next();
if matches!(parser.peek(), Some(Token::Keyword(Keyword::Apply))) {
let _ = parser.next();
ApplyType::Cross
} else {
parser.restore(saved);
break;
}
}
Keyword::Outer => {
let saved = parser.save();
let _ = parser.next();
if matches!(parser.peek(), Some(Token::Keyword(Keyword::Apply))) {
let _ = parser.next();
ApplyType::Outer
} else {
parser.restore(saved);
break;
}
}
_ => break,
};
let table = parse_table_ref(parser)?;
applies.push(ApplyClause { apply_type, table });
}
let mut selection = None;
if let Some(Token::Keyword(Keyword::Where)) = parser.peek() {
let _ = parser.next();
selection = Some(crate::parser::parse::expressions::parse_expr(parser)?);
}
let mut group_by = Vec::new();
if let Some(Token::Keyword(Keyword::Group)) = parser.peek() {
let _ = parser.next();
if matches!(parser.peek(), Some(Token::Keyword(Keyword::By))) {
let _ = parser.next();
}
group_by = crate::parser::parse::expressions::parse_comma_list(
parser,
crate::parser::parse::expressions::parse_expr,
)?;
}
let mut having = None;
if let Some(Token::Keyword(Keyword::Having)) = parser.peek() {
let _ = parser.next();
having = Some(crate::parser::parse::expressions::parse_expr(parser)?);
}
let mut order_by = Vec::new();
if let Some(Token::Keyword(Keyword::Order)) = parser.peek() {
let _ = parser.next();
if matches!(parser.peek(), Some(Token::Keyword(Keyword::By))) {
let _ = parser.next();
}
order_by =
crate::parser::parse::expressions::parse_comma_list(parser, parse_order_by_expr)?;
}
let mut offset = None;
let mut fetch = None;
if let Some(Token::Keyword(Keyword::Offset)) = parser.peek() {
let _ = parser.next();
offset = Some(crate::parser::parse::expressions::parse_expr(parser)?);
parser.expect_keyword(Keyword::Rows)?;
if let Some(Token::Keyword(Keyword::Fetch)) = parser.peek() {
let _ = parser.next();
parser.expect_keyword(Keyword::Next)?;
fetch = Some(crate::parser::parse::expressions::parse_expr(parser)?);
parser.expect_keyword(Keyword::Rows)?;
parser.expect_keyword(Keyword::Only)?;
}
}
Ok(SelectStmt {
distinct,
top,
projection,
into_table,
from,
joins,
applies,
selection,
group_by,
having,
order_by,
offset,
fetch,
set_op: None,
})
}
fn parse_projection(parser: &mut Parser) -> ParseResult<Vec<SelectItem>> {
let mut items = Vec::new();
loop {
items.push(parse_select_item(parser)?);
if let Some(Token::Comma) = parser.peek() {
let _ = parser.next();
continue;
}
if let Some(Token::Keyword(k)) = parser.peek() {
if matches!(
k,
Keyword::From
| Keyword::Into
| Keyword::Where
| Keyword::Group
| Keyword::Order
| Keyword::Having
| Keyword::Union
| Keyword::Intersect
| Keyword::Except
) {
break;
}
}
break;
}
Ok(items)
}
pub fn parse_table_ref(parser: &mut Parser) -> ParseResult<TableRef> {
let (factor, alias, hints) = match parser.peek() {
Some(Token::LParen) => {
let _ = parser.next();
if parser.at_keyword(Keyword::Values) {
let _ = parser.next();
let rows = crate::parser::parse::expressions::parse_comma_list(parser, |p| {
p.expect_lparen()?;
let vals = crate::parser::parse::expressions::parse_comma_list(
p,
crate::parser::parse::expressions::parse_expr,
)?;
p.expect_rparen()?;
Ok(vals)
})?;
parser.expect_rparen()?;
let alias = parse_required_alias(parser)?;
let mut columns = Vec::new();
if matches!(parser.peek(), Some(Token::LParen)) {
let _ = parser.next();
columns = crate::parser::parse::expressions::parse_comma_list(parser, |p| {
match p.next() {
Some(Token::Identifier(id)) => Ok(id.clone()),
Some(Token::Keyword(kw)) => Ok(kw.as_ref().to_string()),
_ => p.backtrack(Expected::Description("column name")),
}
})?;
parser.expect_rparen()?;
}
(
TableFactor::Values { rows, columns },
Some(alias),
Vec::new(),
)
} else if parser.at_keyword(Keyword::Select) {
let subquery = Box::new(parse_select(parser)?);
parser.expect_rparen()?;
let alias = parse_required_alias(parser)?;
(TableFactor::Derived(subquery), Some(alias), Vec::new())
} else {
let base = parse_table_ref(parser)?;
let mut joins = Vec::new();
while !matches!(parser.peek(), Some(Token::RParen)) {
match parse_join_clause(parser)? {
Some(join) => joins.push(join),
None => break,
}
}
parser.expect_rparen()?;
let alias = parse_optional_alias(parser);
(
TableFactor::JoinedGroup {
base: Box::new(base),
joins,
},
alias,
Vec::new(),
)
}
}
Some(Token::Identifier(_)) | Some(Token::Keyword(_)) | Some(Token::Variable(_)) => {
let name = parse_multipart_name(parser)?;
if matches!(parser.peek(), Some(Token::LParen)) {
let _ = parser.next();
let args = crate::parser::parse::expressions::parse_comma_list(
parser,
crate::parser::parse::expressions::parse_expr,
)?;
parser.expect_rparen()?;
let alias = parse_optional_alias(parser);
let factor = TableFactor::TableValuedFunction {
name,
args,
alias: alias.clone(),
};
return Ok(TableRef {
factor,
alias,
pivot: None,
unpivot: None,
hints: Vec::new(),
});
}
let alias = parse_optional_alias(parser);
let mut hints = Vec::new();
if let Some(Token::Keyword(Keyword::With)) = parser.peek() {
let saved = parser.save();
let _ = parser.next();
if matches!(parser.peek(), Some(Token::LParen)) {
let _ = parser.next();
hints = crate::parser::parse::expressions::parse_comma_list(parser, |p| {
if let Some(tok) = p.next() {
match tok {
Token::Identifier(id) => Ok(id.clone()),
Token::Keyword(kw) => Ok(kw.as_ref().to_string()),
_ => p.backtrack(Expected::Description("identifier")),
}
} else {
p.backtrack(Expected::Description("identifier"))
}
})?;
parser.expect_rparen()?;
} else {
parser.restore(saved);
}
}
(TableFactor::Named(parse_object_name(name)), alias, hints)
}
_ => return parser.backtrack(Expected::Description("table reference")),
};
let mut table = TableRef {
factor,
alias,
pivot: None,
unpivot: None,
hints,
};
loop {
match parser.peek() {
Some(Token::Keyword(Keyword::Pivot)) => {
let _ = parser.next();
parser.expect_lparen()?;
let aggregate_func = match parser.next() {
Some(Token::Identifier(id)) => id.clone(),
Some(Token::Keyword(kw)) => kw.as_ref().to_string(),
_ => return parser.backtrack(Expected::Description("identifier")),
};
parser.expect_lparen()?;
let aggregate_col = match parser.next() {
Some(Token::Identifier(id)) => id.clone(),
Some(Token::Keyword(kw)) => kw.as_ref().to_string(),
_ => return parser.backtrack(Expected::Description("identifier")),
};
parser.expect_rparen()?;
parser.expect_keyword(Keyword::For)?;
let pivot_col = match parser.next() {
Some(Token::Identifier(id)) => id.clone(),
Some(Token::Keyword(kw)) => kw.as_ref().to_string(),
_ => return parser.backtrack(Expected::Description("identifier")),
};
parser.expect_keyword(Keyword::In)?;
parser.expect_lparen()?;
let pivot_values =
crate::parser::parse::expressions::parse_comma_list(parser, |p| {
match p.next() {
Some(Token::Identifier(id)) => Ok(id.clone()),
Some(Token::Keyword(kw)) => Ok(kw.as_ref().to_string()),
_ => p.backtrack(Expected::Description("identifier")),
}
})?;
parser.expect_rparen()?;
parser.expect_rparen()?;
let alias = parse_required_alias(parser)?;
table.pivot = Some(Box::new(PivotSpec {
aggregate_func,
aggregate_col,
pivot_col,
pivot_values,
alias: Some(alias.clone()),
}));
table.alias = Some(alias);
}
Some(Token::Keyword(Keyword::Unpivot)) => {
let _ = parser.next();
parser.expect_lparen()?;
let value_col = match parser.next() {
Some(Token::Identifier(id)) => id.clone(),
Some(Token::Keyword(kw)) => kw.as_ref().to_string(),
_ => return parser.backtrack(Expected::Description("identifier")),
};
parser.expect_keyword(Keyword::For)?;
let pivot_col = match parser.next() {
Some(Token::Identifier(id)) => id.clone(),
Some(Token::Keyword(kw)) => kw.as_ref().to_string(),
_ => return parser.backtrack(Expected::Description("identifier")),
};
parser.expect_keyword(Keyword::In)?;
parser.expect_lparen()?;
let column_list =
crate::parser::parse::expressions::parse_comma_list(parser, |p| {
match p.next() {
Some(Token::Identifier(id)) => Ok(id.clone()),
Some(Token::Keyword(kw)) => Ok(kw.as_ref().to_string()),
_ => p.backtrack(Expected::Description("identifier")),
}
})?;
parser.expect_rparen()?;
parser.expect_rparen()?;
let alias = parse_required_alias(parser)?;
let source_alias = table.alias.clone();
table.unpivot = Some(Box::new(UnpivotSpec {
value_col,
pivot_col,
column_list,
alias: Some(alias.clone()),
source_alias,
}));
table.alias = Some(alias);
}
_ => break,
}
}
Ok(table)
}
pub fn parse_join_clause(parser: &mut Parser) -> ParseResult<Option<JoinClause>> {
let Some(Token::Keyword(k)) = parser.peek() else {
return Ok(None);
};
if matches!(
k,
Keyword::Cross | Keyword::Left | Keyword::Right | Keyword::Full
) && matches!(parser.peek_at(1), Some(Token::Keyword(Keyword::Apply)))
{
return Ok(None);
}
let join_type = match *k {
Keyword::Join => {
let _ = parser.next();
JoinType::Inner
}
Keyword::Inner | Keyword::Left | Keyword::Right | Keyword::Full | Keyword::Cross => {
let jt = match *k {
Keyword::Inner => JoinType::Inner,
Keyword::Left => JoinType::Left,
Keyword::Right => JoinType::Right,
Keyword::Full => JoinType::Full,
Keyword::Cross => JoinType::Cross,
_ => unreachable!(),
};
let _ = parser.next();
if matches!(parser.peek(), Some(Token::Keyword(Keyword::Outer))) {
let _ = parser.next();
}
parser.expect_keyword(Keyword::Join)?;
jt
}
_ => return Ok(None),
};
let table = parse_table_ref(parser)?;
let on = if join_type != JoinType::Cross {
parser.expect_keyword(Keyword::On)?;
Some(crate::parser::parse::expressions::parse_expr(parser)?)
} else {
None
};
Ok(Some(JoinClause {
join_type,
table,
on,
}))
}
fn parse_optional_alias(parser: &mut Parser) -> Option<String> {
let saved = parser.save();
match parser.peek() {
Some(Token::Keyword(Keyword::As)) => {
let _ = parser.next();
match parser.next() {
Some(Token::Identifier(alias)) => Some(alias.clone()),
Some(Token::String(alias)) => Some(alias.clone()),
Some(Token::Keyword(kw)) => Some(kw.as_ref().to_string()),
_ => {
parser.restore(saved);
None
}
}
}
Some(Token::Keyword(k))
if !crate::parser::parse::expressions::is_stop_keyword(k.as_sql()) =>
{
match parser.next() {
Some(Token::Identifier(alias)) => Some(alias.clone()),
Some(Token::Keyword(kw)) => Some(kw.as_ref().to_string()),
Some(Token::String(alias)) => Some(alias.clone()),
Some(_) | None => {
parser.restore(saved);
None
}
}
}
Some(Token::Identifier(alias))
if !crate::parser::parse::expressions::is_stop_keyword(alias) =>
{
let alias = alias.clone();
let _ = parser.next();
Some(alias)
}
Some(Token::String(alias)) => {
let alias = alias.clone();
let _ = parser.next();
Some(alias)
}
_ => {
parser.restore(saved);
None
}
}
}
fn parse_required_alias(parser: &mut Parser) -> ParseResult<String> {
parse_optional_alias(parser).ok_or_else(|| parser.error(Expected::Description("alias")))
}
pub fn parse_select_item(parser: &mut Parser) -> ParseResult<SelectItem> {
let expr = crate::parser::parse::expressions::parse_expr(parser)?;
let alias = if let Some(Token::Keyword(k)) = parser.peek() {
if *k == Keyword::As {
let _ = parser.next();
match parser.next() {
Some(Token::Identifier(alias)) => Some(alias.clone()),
Some(Token::String(alias)) => Some(alias.clone()),
_ => return parser.backtrack(Expected::Description("alias")),
}
} else if !crate::parser::parse::expressions::is_stop_keyword(k.as_sql()) {
match parser.next() {
Some(Token::Identifier(id)) => Some(id.clone()),
Some(_) | None => None,
}
} else {
None
}
} else if let Some(Token::Identifier(alias)) = parser.peek() {
if !crate::parser::parse::expressions::is_stop_keyword(alias) {
let alias = alias.clone();
let _ = parser.next();
Some(alias)
} else {
None
}
} else if let Some(Token::String(alias)) = parser.peek() {
let alias = alias.clone();
let _ = parser.next();
Some(alias)
} else {
None
};
Ok(SelectItem { expr, alias })
}
pub fn parse_order_by_expr(parser: &mut Parser) -> ParseResult<OrderByExpr> {
let expr = crate::parser::parse::expressions::parse_expr(parser)?;
let mut asc = true;
if let Some(Token::Keyword(Keyword::Desc)) = parser.peek() {
let _ = parser.next();
asc = false;
} else if let Some(Token::Keyword(Keyword::Asc)) = parser.peek() {
let _ = parser.next();
asc = true;
}
Ok(OrderByExpr { expr, asc })
}
pub fn parse_multipart_name(parser: &mut Parser) -> ParseResult<Vec<String>> {
let mut parts = Vec::new();
if let Some(tok) = parser.next() {
match tok {
Token::Identifier(id) | Token::Variable(id) => parts.push(id.clone()),
Token::Keyword(k) => parts.push(k.as_ref().to_string()),
_ => return parser.backtrack(Expected::Description("identifier")),
}
} else {
return parser.backtrack(Expected::Description("identifier"));
}
while matches!(parser.peek(), Some(Token::Dot)) {
let _ = parser.next();
if let Some(tok) = parser.next() {
match tok {
Token::Identifier(id) | Token::Variable(id) => parts.push(id.clone()),
Token::Keyword(k) => parts.push(k.as_ref().to_string()),
_ => return parser.backtrack(Expected::Description("identifier")),
}
} else {
return parser.backtrack(Expected::Description("identifier"));
}
}
Ok(parts)
}
pub fn parse_object_name(mut parts: Vec<String>) -> ObjectName {
match parts.len() {
0 => ObjectName {
database: None,
schema: None,
name: "".to_string(),
},
1 => ObjectName {
database: None,
schema: None,
name: parts.remove(0),
},
2 => {
let name = parts.pop().unwrap_or_default();
let schema = Some(parts.pop().unwrap_or_default());
ObjectName {
database: None,
schema,
name,
}
}
_ => {
let name = parts.pop().unwrap_or_default();
let schema = Some(parts.pop().unwrap_or_default());
let database = Some(parts.pop().unwrap_or_default());
ObjectName {
database,
schema,
name,
}
}
}
}