1use crate::{
2 QualifiedName, Span, Spanned,
3 drop::{CascadeOrRestrict, parse_cascade_or_restrict},
4 keywords::Keyword,
5 lexer::Token,
6 parser::{ParseError, Parser},
7 qualified_name::parse_qualified_name_unreserved,
8};
9
10use alloc::vec::Vec;
11
12#[derive(Debug, Clone)]
34pub struct TruncateTableSpec<'a> {
35 pub only_span: Option<Span>,
37 pub table_name: QualifiedName<'a>,
39 pub descendants_span: Option<Span>,
41}
42
43impl<'a> Spanned for TruncateTableSpec<'a> {
44 fn span(&self) -> Span {
45 self.table_name
46 .span()
47 .join_span(&self.only_span)
48 .join_span(&self.descendants_span)
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
54pub enum IdentityOption {
55 Restart(Span),
57 Continue(Span),
59}
60
61impl Spanned for IdentityOption {
62 fn span(&self) -> Span {
63 match self {
64 IdentityOption::Restart(span) => span.clone(),
65 IdentityOption::Continue(span) => span.clone(),
66 }
67 }
68}
69
70#[derive(Debug, Clone)]
71pub struct TruncateTable<'a> {
72 pub truncate_span: Span,
74 pub table_span: Option<Span>,
76 pub tables: Vec<TruncateTableSpec<'a>>,
78 pub identity_option: Option<IdentityOption>,
80 pub cascade_or_restrict: Option<CascadeOrRestrict>,
82}
83
84impl<'a> Spanned for TruncateTable<'a> {
85 fn span(&self) -> Span {
86 self.truncate_span
87 .join_span(&self.table_span)
88 .join_span(&self.tables)
89 .join_span(&self.identity_option)
90 .join_span(&self.cascade_or_restrict)
91 }
92}
93
94pub(crate) fn parse_truncate_table<'a>(
95 parser: &mut Parser<'a, '_>,
96) -> Result<TruncateTable<'a>, ParseError> {
97 let truncate_span = parser.consume_keyword(Keyword::TRUNCATE)?;
98 let table_span = parser.skip_keyword(Keyword::TABLE);
99
100 let mut tables = Vec::new();
101
102 loop {
104 let only_span = parser.skip_keyword(Keyword::ONLY);
105 parser.postgres_only(&only_span);
106
107 let table_name = parse_qualified_name_unreserved(parser)?;
108
109 let descendants_span = parser.skip_token(Token::Mul);
110 parser.postgres_only(&descendants_span);
111
112 tables.push(TruncateTableSpec {
113 only_span,
114 table_name,
115 descendants_span,
116 });
117
118 let comma_span = parser.skip_token(Token::Comma);
119 if comma_span.is_none() {
120 break;
121 }
122 parser.postgres_only(&comma_span);
124 }
125
126 let identity_option = if let Some(restart_span) = parser.skip_keyword(Keyword::RESTART) {
128 let identity_span = parser.consume_keyword(Keyword::IDENTITY)?;
129 let full_span = restart_span.join_span(&identity_span);
130 parser.postgres_only(&full_span);
131 Some(IdentityOption::Restart(full_span))
132 } else if let Some(continue_span) = parser.skip_keyword(Keyword::CONTINUE) {
133 let identity_span = parser.consume_keyword(Keyword::IDENTITY)?;
134 let full_span = continue_span.join_span(&identity_span);
135 parser.postgres_only(&full_span);
136 Some(IdentityOption::Continue(full_span))
137 } else {
138 None
139 };
140
141 let cascade_or_restrict = parse_cascade_or_restrict(parser);
142
143 Ok(TruncateTable {
144 truncate_span,
145 table_span,
146 tables,
147 identity_option,
148 cascade_or_restrict,
149 })
150}