1use alloc::{boxed::Box, vec::Vec};
2
3use crate::{
4 keywords::Keyword,
5 lexer::Token,
6 parser::{ParseError, Parser},
7 statement::parse_statement,
8 Identifier, Span, Spanned, Statement,
9};
10
11#[derive(Clone, Debug)]
12pub struct WithBlock<'a> {
13 pub identifier: Identifier<'a>,
15 pub as_span: Span,
17 pub lparen_span: Span,
19 pub statement: Statement<'a>,
21 pub rparen_span: Span,
23}
24
25impl<'a> Spanned for WithBlock<'a> {
26 fn span(&self) -> Span {
27 self.identifier
28 .span()
29 .join_span(&self.as_span)
30 .join_span(&self.lparen_span)
31 .join_span(&self.statement)
32 .join_span(&self.rparen_span)
33 }
34}
35
36#[derive(Clone, Debug)]
55pub struct WithQuery<'a> {
56 pub with_span: Span,
58 pub with_blocks: Vec<WithBlock<'a>>,
60 pub statement: Box<Statement<'a>>,
62}
63
64impl<'a> Spanned for WithQuery<'a> {
65 fn span(&self) -> Span {
66 self.with_span
67 .join_span(&self.with_blocks)
68 .join_span(&self.statement)
69 }
70}
71
72pub(crate) fn parse_with_query<'a>(
73 parser: &mut Parser<'a, '_>,
74) -> Result<WithQuery<'a>, ParseError> {
75 let with_span = parser.consume_keyword(Keyword::WITH)?;
76 let mut with_blocks = Vec::new();
77 loop {
78 let identifier = parser.consume_plain_identifier()?;
79 let as_span = parser.consume_keyword(Keyword::AS)?;
80 let lparen_span = parser.consume_token(Token::LParen)?;
81 let statement =
82 parser.recovered(
83 "')'",
84 &|t| t == &Token::RParen,
85 |parser| match parse_statement(parser)? {
86 Some(v) => Ok(Some(v)),
87 None => {
88 parser.expected_error("Statement");
89 Ok(None)
90 }
91 },
92 )?;
93 let rparen_span = parser.consume_token(Token::RParen)?;
94 let statement = match statement {
95 Some(v) => {
96 if !matches!(
97 &v,
98 Statement::Select(_)
99 | Statement::InsertReplace(_)
100 | Statement::Update(_)
101 | Statement::Delete(_)
102 ) {
103 parser.err(
104 "Only SELECT, INSERT, UPDATE or DELETE allowed within WITH query",
105 &v.span(),
106 );
107 }
108 v
109 }
110 None => Statement::Begin(lparen_span.clone()),
111 };
112 with_blocks.push(WithBlock {
113 identifier,
114 as_span,
115 lparen_span,
116 statement,
117 rparen_span,
118 });
119 if parser.skip_token(Token::Comma).is_none() {
120 break;
121 }
122 }
123 let statement = match parse_statement(parser)? {
124 Some(v) => {
125 if !matches!(
127 &v,
128 Statement::Select(_)
129 | Statement::InsertReplace(_)
130 | Statement::Update(_)
131 | Statement::Delete(_)
132 ) {
133 parser.err(
134 "Only SELECT, INSERT, UPDATE or DELETE allowed as WITH query",
135 &v.span(),
136 );
137 }
138 Box::new(v)
139 }
140 None => parser.expected_failure("Statement")?,
141 };
142 let res = WithQuery {
143 with_span,
144 with_blocks,
145 statement,
146 };
147 if !parser.options.dialect.is_postgresql() {
148 parser.err("WITH statements only supported by postgresql", &res.span());
149 }
150 Ok(res)
151}