1use crate::{
13 Expression, Identifier, QualifiedName, Span, Spanned,
14 alter_table::{IndexCol, IndexColExpr, parse_operator_class},
15 create_option::CreateOption,
16 expression::{PRIORITY_MAX, parse_expression_unreserved},
17 keywords::Keyword,
18 lexer::Token,
19 parser::{ParseError, Parser},
20 qualified_name::parse_qualified_name_unreserved,
21};
22
23#[derive(Clone, Debug)]
25pub struct WithOption<'a> {
26 pub name: Identifier<'a>,
27 pub eq_span: Span,
28 pub value: Expression<'a>,
29}
30
31impl<'a> Spanned for WithOption<'a> {
32 fn span(&self) -> Span {
33 self.name.join_span(&self.value)
34 }
35}
36use alloc::vec::Vec;
37
38#[derive(Clone, Debug)]
39pub enum UsingIndexMethod {
40 Gist(Span),
41 Bloom(Span),
42 Brin(Span),
43 Hnsw(Span),
44 Gin(Span),
45 BTree(Span),
46 Hash(Span),
47 RTree(Span),
48}
49
50impl Spanned for UsingIndexMethod {
51 fn span(&self) -> Span {
52 match self {
53 UsingIndexMethod::Gist(s) => s.clone(),
54 UsingIndexMethod::Bloom(s) => s.clone(),
55 UsingIndexMethod::Brin(s) => s.clone(),
56 UsingIndexMethod::Hnsw(s) => s.clone(),
57 UsingIndexMethod::BTree(s) => s.clone(),
58 UsingIndexMethod::Hash(s) => s.clone(),
59 UsingIndexMethod::RTree(s) => s.clone(),
60 UsingIndexMethod::Gin(s) => s.clone(),
61 }
62 }
63}
64
65pub(crate) fn parse_using_index_method<'a>(
66 parser: &mut Parser<'a, '_>,
67 using_span: Span,
68) -> Result<UsingIndexMethod, ParseError> {
69 match &parser.token {
70 Token::Ident(_, Keyword::GIST) => {
71 let gist_span = parser.consume_keyword(Keyword::GIST)?;
72 Ok(UsingIndexMethod::Gist(using_span.join_span(&gist_span)))
73 }
74 Token::Ident(_, Keyword::BLOOM) => {
75 let bloom_span = parser.consume_keyword(Keyword::BLOOM)?;
76 Ok(UsingIndexMethod::Bloom(using_span.join_span(&bloom_span)))
77 }
78 Token::Ident(_, Keyword::BRIN) => {
79 let brin_span = parser.consume_keyword(Keyword::BRIN)?;
80 Ok(UsingIndexMethod::Brin(using_span.join_span(&brin_span)))
81 }
82 Token::Ident(_, Keyword::HNSW) => {
83 let hnsw_span = parser.consume_keyword(Keyword::HNSW)?;
84 Ok(UsingIndexMethod::Hnsw(using_span.join_span(&hnsw_span)))
85 }
86 Token::Ident(_, Keyword::GIN) => {
87 let gin_span = parser.consume_keyword(Keyword::GIN)?;
88 Ok(UsingIndexMethod::Gin(using_span.join_span(&gin_span)))
89 }
90 Token::Ident(_, Keyword::BTREE) => {
91 let btree_span = parser.consume_keyword(Keyword::BTREE)?;
92 Ok(UsingIndexMethod::BTree(using_span.join_span(&btree_span)))
93 }
94 Token::Ident(_, Keyword::HASH) => {
95 let hash_span = parser.consume_keyword(Keyword::HASH)?;
96 Ok(UsingIndexMethod::Hash(using_span.join_span(&hash_span)))
97 }
98 Token::Ident(_, Keyword::RTREE) => {
99 let rtree_span = parser.consume_keyword(Keyword::RTREE)?;
100 Ok(UsingIndexMethod::RTree(using_span.join_span(&rtree_span)))
101 }
102 _ => Err(parser
103 .err_here("Expected GIST, BLOOM, BRIN, HNSW, BTREE, HASH, or RTREE after USING")?),
104 }
105}
106
107#[derive(Clone, Debug)]
108pub enum CreateIndexOption<'a> {
109 UsingIndex(UsingIndexMethod),
110 Algorithm(Span, Identifier<'a>),
111 AlgorithmDefault {
112 algorithm_span: Span,
113 default_span: Span,
114 },
115 Lock(Span, Identifier<'a>),
116}
117
118impl<'a> Spanned for CreateIndexOption<'a> {
119 fn span(&self) -> Span {
120 match self {
121 CreateIndexOption::UsingIndex(method) => method.span(),
122 CreateIndexOption::Algorithm(s, i) => s.join_span(i),
123 CreateIndexOption::AlgorithmDefault {
124 algorithm_span,
125 default_span,
126 } => algorithm_span.join_span(default_span),
127 CreateIndexOption::Lock(s, i) => s.join_span(i),
128 }
129 }
130}
131
132#[derive(Clone, Debug)]
133pub struct IncludeClause<'a> {
134 pub include_span: Span,
135 pub l_paren_span: Span,
136 pub columns: Vec<Identifier<'a>>,
137 pub r_paren_span: Span,
138}
139
140impl<'a> Spanned for IncludeClause<'a> {
141 fn span(&self) -> Span {
142 self.include_span
143 .join_span(&self.l_paren_span)
144 .join_span(&self.columns)
145 .join_span(&self.r_paren_span)
146 }
147}
148
149#[derive(Clone, Debug)]
150pub struct CreateIndex<'a> {
151 pub create_span: Span,
152 pub create_options: Vec<CreateOption<'a>>,
153 pub index_span: Span,
154 pub index_name: Option<Identifier<'a>>,
155 pub if_not_exists: Option<Span>,
156 pub on_span: Span,
157 pub table_name: QualifiedName<'a>,
158 pub index_options: Vec<CreateIndexOption<'a>>,
159 pub l_paren_span: Span,
160 pub column_names: Vec<IndexCol<'a>>,
161 pub r_paren_span: Span,
162 pub include_clause: Option<IncludeClause<'a>>,
163 pub with_options: Option<(Span, Vec<WithOption<'a>>)>,
164 pub where_: Option<(Span, Expression<'a>)>,
165 pub nulls_distinct: Option<(Span, Option<Span>)>,
166}
167
168impl<'a> Spanned for CreateIndex<'a> {
169 fn span(&self) -> Span {
170 self.create_span
171 .join_span(&self.create_options)
172 .join_span(&self.index_span)
173 .join_span(&self.index_name)
174 .join_span(&self.on_span)
175 .join_span(&self.table_name)
176 .join_span(&self.index_options)
177 .join_span(&self.l_paren_span)
178 .join_span(&self.column_names)
179 .join_span(&self.r_paren_span)
180 .join_span(&self.include_clause)
181 .join_span(&self.with_options.as_ref().map(|(s, c)| s.join_span(c)))
182 .join_span(&self.where_)
183 .join_span(&self.nulls_distinct)
184 }
185}
186
187pub(crate) fn parse_create_index<'a>(
188 parser: &mut Parser<'a, '_>,
189 create_span: Span,
190 mut create_options: Vec<CreateOption<'a>>,
191) -> Result<CreateIndex<'a>, ParseError> {
192 let index_span = parser.consume_keyword(Keyword::INDEX)?;
193
194 if let Some(concurrently_span) = parser.skip_keyword(Keyword::CONCURRENTLY) {
196 parser.postgres_only(&concurrently_span);
197 create_options.push(CreateOption::Concurrently(concurrently_span));
198 }
199
200 let if_not_exists = if let Some(s) = parser.skip_keyword(Keyword::IF) {
201 Some(s.join_span(&parser.consume_keywords(&[Keyword::NOT, Keyword::EXISTS])?))
202 } else {
203 None
204 };
205
206 let index_name = if let Token::Ident(_, Keyword::ON) = &parser.token {
208 None
210 } else {
211 Some(parser.consume_plain_identifier_unreserved()?)
213 };
214
215 if index_name.is_none() && parser.options.dialect.is_maria() {
217 parser.err("Index name required", &index_span);
218 }
219
220 let on_span = parser.consume_keyword(Keyword::ON)?;
221 let table_name = parse_qualified_name_unreserved(parser)?;
222
223 let mut index_options = Vec::new();
225 if let Some(using_span) = parser.skip_keyword(Keyword::USING) {
226 let using_index_method = parse_using_index_method(parser, using_span)?;
227 index_options.push(CreateIndexOption::UsingIndex(using_index_method));
228 }
229
230 let l_paren_span = parser.consume_token(Token::LParen)?;
231 let mut column_names = Vec::new();
232 loop {
233 let expr = if parser.token == Token::LParen {
235 parser.consume_token(Token::LParen)?;
237 let expression = parse_expression_unreserved(parser, PRIORITY_MAX)?;
238 parser.consume_token(Token::RParen)?;
239 IndexColExpr::Expression(expression)
240 } else {
241 let name = parser.consume_plain_identifier_unreserved()?;
243 IndexColExpr::Column(name)
244 };
245
246 let size = if parser.skip_token(Token::LParen).is_some() {
247 let size = parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
248 parser.consume_int()
249 })?;
250 parser.consume_token(Token::RParen)?;
251 Some(size)
252 } else {
253 None
254 };
255
256 let opclass = parse_operator_class(parser)?;
258
259 let asc = parser.skip_keyword(Keyword::ASC);
261 let desc = if asc.is_none() {
262 parser.skip_keyword(Keyword::DESC)
263 } else {
264 None
265 };
266
267 column_names.push(IndexCol {
268 expr,
269 size,
270 opclass,
271 asc,
272 desc,
273 });
274
275 if parser.skip_token(Token::Comma).is_none() {
276 break;
277 }
278 }
279
280 let r_paren_span = parser.consume_token(Token::RParen)?;
281
282 let include_clause = if let Some(include_span) = parser.skip_keyword(Keyword::INCLUDE) {
284 let l_paren = parser.consume_token(Token::LParen)?;
285 let mut include_cols = Vec::new();
286 loop {
287 include_cols.push(parser.consume_plain_identifier_unreserved()?);
288 if parser.skip_token(Token::Comma).is_none() {
289 break;
290 }
291 }
292 let r_paren = parser.consume_token(Token::RParen)?;
293 parser.postgres_only(&include_span);
294 Some(IncludeClause {
295 include_span,
296 l_paren_span: l_paren,
297 columns: include_cols,
298 r_paren_span: r_paren,
299 })
300 } else {
301 None
302 };
303
304 let with_options = if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
306 parser.postgres_only(&with_span);
307 parser.consume_token(Token::LParen)?;
308 let mut opts = Vec::new();
309 parser.recovered("')'", &|t| t == &Token::RParen, |parser| {
310 loop {
311 let name = parser.consume_plain_identifier_unreserved()?;
312 let eq_span = parser.consume_token(Token::Eq)?;
313 let value = parse_expression_unreserved(parser, PRIORITY_MAX)?;
314 opts.push(WithOption {
315 name,
316 eq_span,
317 value,
318 });
319 if parser.skip_token(Token::Comma).is_none() {
320 break;
321 }
322 }
323 Ok(())
324 })?;
325 parser.consume_token(Token::RParen)?;
326 Some((with_span, opts))
327 } else {
328 None
329 };
330
331 loop {
333 match &parser.token {
334 Token::Ident(_, Keyword::USING) => {
335 let using_span = parser.consume_keyword(Keyword::USING)?;
336 let using_index_method = parse_using_index_method(parser, using_span)?;
337 index_options.push(CreateIndexOption::UsingIndex(using_index_method));
338 }
339 Token::Ident(_, Keyword::ALGORITHM) => {
340 let algorithm_span = parser.consume_keyword(Keyword::ALGORITHM)?;
341 parser.skip_token(Token::Eq); if matches!(&parser.token, Token::Ident(_, Keyword::DEFAULT)) {
343 let default_span = parser.consume_keyword(Keyword::DEFAULT)?;
344 index_options.push(CreateIndexOption::AlgorithmDefault {
345 algorithm_span,
346 default_span,
347 });
348 } else {
349 let algorithm_value = parser.consume_plain_identifier_unreserved()?;
350 index_options.push(CreateIndexOption::Algorithm(
351 algorithm_span,
352 algorithm_value,
353 ));
354 }
355 }
356 Token::Ident(_, Keyword::LOCK) => {
357 let lock_span = parser.consume_keyword(Keyword::LOCK)?;
358 parser.skip_token(Token::Eq); let lock_value = parser.consume_plain_identifier_unreserved()?;
360 index_options.push(CreateIndexOption::Lock(lock_span, lock_value));
361 }
362 _ => break,
363 }
364 }
365
366 let mut where_ = None;
367 if let Some(where_span) = parser.skip_keyword(Keyword::WHERE) {
368 let where_expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
369 if parser.options.dialect.is_maria() {
370 parser.err(
371 "Partial indexes not supported",
372 &where_span.join_span(&where_expr),
373 );
374 }
375 where_ = Some((where_span, where_expr));
376 }
377
378 let nulls_distinct = if let Some(nulls_span) = parser.skip_keyword(Keyword::NULLS) {
380 let not_span = parser.skip_keyword(Keyword::NOT);
381 let distinct_span = parser.consume_keyword(Keyword::DISTINCT)?;
382 parser.postgres_only(&nulls_span.join_span(&distinct_span));
383 Some((nulls_span, not_span))
384 } else {
385 None
386 };
387
388 Ok(CreateIndex {
389 create_span,
390 create_options,
391 index_span,
392 index_name,
393 if_not_exists,
394 on_span,
395 table_name,
396 index_options,
397 l_paren_span,
398 column_names,
399 r_paren_span,
400 include_clause,
401 with_options,
402 where_,
403 nulls_distinct,
404 })
405}