vibesql_parser/parser/advanced_objects/
routines.rs1use crate::keywords::Keyword;
30use crate::parser::{ParseError, Parser};
31use crate::token::Token;
32use vibesql_ast::{
33 CallStmt, CreateFunctionStmt, CreateProcedureStmt, DropFunctionStmt, DropProcedureStmt,
34 FunctionParameter, ParameterMode, ProceduralStatement, ProcedureBody, ProcedureParameter,
35 SqlSecurity,
36};
37
38impl Parser {
39 pub fn parse_create_procedure(&mut self) -> Result<CreateProcedureStmt, ParseError> {
43 let procedure_name = self.parse_identifier()?;
45
46 self.expect_token(Token::LParen)?;
47 let parameters = self.parse_procedure_parameters()?;
48 self.expect_token(Token::RParen)?;
49
50 let (sql_security, comment, language) = self.parse_procedure_characteristics()?;
52
53 let body = self.parse_procedure_body()?;
54
55 Ok(CreateProcedureStmt {
56 procedure_name,
57 parameters,
58 body,
59 sql_security,
60 comment,
61 language,
62 })
63 }
64
65 pub fn parse_create_function(&mut self) -> Result<CreateFunctionStmt, ParseError> {
69 let function_name = self.parse_identifier()?;
71
72 self.expect_token(Token::LParen)?;
73 let parameters = self.parse_function_parameters()?;
74 self.expect_token(Token::RParen)?;
75
76 self.expect_keyword(Keyword::Returns)?;
77 let return_type = self.parse_data_type()?;
78
79 let (deterministic, sql_security, comment, language) =
81 self.parse_function_characteristics()?;
82
83 let body = self.parse_procedure_body()?;
84
85 Ok(CreateFunctionStmt {
86 function_name,
87 parameters,
88 return_type,
89 body,
90 deterministic,
91 sql_security,
92 comment,
93 language,
94 })
95 }
96
97 pub fn parse_drop_procedure(&mut self) -> Result<DropProcedureStmt, ParseError> {
101 let if_exists = self.try_consume_keyword(Keyword::If);
103 if if_exists {
104 self.expect_keyword(Keyword::Exists)?;
105 }
106
107 let procedure_name = self.parse_identifier()?;
108
109 Ok(DropProcedureStmt { procedure_name, if_exists })
110 }
111
112 pub fn parse_drop_function(&mut self) -> Result<DropFunctionStmt, ParseError> {
116 let if_exists = self.try_consume_keyword(Keyword::If);
118 if if_exists {
119 self.expect_keyword(Keyword::Exists)?;
120 }
121
122 let function_name = self.parse_identifier()?;
123
124 Ok(DropFunctionStmt { function_name, if_exists })
125 }
126
127 pub fn parse_call(&mut self) -> Result<CallStmt, ParseError> {
131 let procedure_name = self.parse_identifier()?;
133
134 self.expect_token(Token::LParen)?;
135 let arguments = self.parse_expression_list()?;
136 self.expect_token(Token::RParen)?;
137
138 Ok(CallStmt { procedure_name, arguments })
139 }
140
141 fn parse_procedure_parameters(&mut self) -> Result<Vec<ProcedureParameter>, ParseError> {
145 let mut parameters = Vec::new();
146
147 if self.peek() == &Token::RParen {
149 return Ok(parameters);
150 }
151
152 loop {
153 let mode = if self.try_consume_keyword(Keyword::In) {
155 ParameterMode::In
156 } else if self.try_consume_keyword(Keyword::Out) {
157 ParameterMode::Out
158 } else if self.try_consume_keyword(Keyword::InOut) {
159 ParameterMode::InOut
160 } else {
161 ParameterMode::In
163 };
164
165 let name = self.parse_identifier()?;
166 let data_type = self.parse_data_type()?;
167
168 parameters.push(ProcedureParameter { mode, name, data_type });
169
170 if !self.try_consume(&Token::Comma) {
171 break;
172 }
173 }
174
175 Ok(parameters)
176 }
177
178 fn parse_function_parameters(&mut self) -> Result<Vec<FunctionParameter>, ParseError> {
183 let mut parameters = Vec::new();
184
185 if self.peek() == &Token::RParen {
187 return Ok(parameters);
188 }
189
190 loop {
191 let name = self.parse_identifier()?;
192 let data_type = self.parse_data_type()?;
193
194 parameters.push(FunctionParameter { name, data_type });
195
196 if !self.try_consume(&Token::Comma) {
197 break;
198 }
199 }
200
201 Ok(parameters)
202 }
203
204 fn parse_procedure_body(&mut self) -> Result<ProcedureBody, ParseError> {
210 if self.try_consume_keyword(Keyword::Begin) {
211 let statements = self.parse_procedural_statements()?;
213 self.expect_keyword(Keyword::End)?;
214 Ok(ProcedureBody::BeginEnd(statements))
215 } else {
216 Err(ParseError { message: "Expected BEGIN keyword for procedure body".to_string() })
218 }
219 }
220
221 fn parse_procedural_statements(&mut self) -> Result<Vec<ProceduralStatement>, ParseError> {
234 let mut statements = Vec::new();
235
236 while !self.peek_keyword(Keyword::End) && self.peek() != &Token::Eof {
237 let stmt = if self.try_consume_keyword(Keyword::Declare) {
238 self.parse_declare_statement()?
239 } else if self.try_consume_keyword(Keyword::Set) {
240 self.parse_set_statement()?
241 } else if self.try_consume_keyword(Keyword::If) {
242 self.parse_if_statement()?
243 } else if self.try_consume_keyword(Keyword::While) {
244 self.parse_while_statement()?
245 } else if self.try_consume_keyword(Keyword::Loop) {
246 self.parse_loop_statement()?
247 } else if self.try_consume_keyword(Keyword::Repeat) {
248 self.parse_repeat_statement()?
249 } else if self.try_consume_keyword(Keyword::Return) {
250 let expr = self.parse_expression()?;
251 self.expect_token(Token::Semicolon)?;
252 ProceduralStatement::Return(Box::new(expr))
253 } else if self.try_consume_keyword(Keyword::Leave) {
254 let label = self.parse_identifier()?;
255 self.expect_token(Token::Semicolon)?;
256 ProceduralStatement::Leave(label)
257 } else if self.try_consume_keyword(Keyword::Iterate) {
258 let label = self.parse_identifier()?;
259 self.expect_token(Token::Semicolon)?;
260 ProceduralStatement::Iterate(label)
261 } else {
262 let sql_stmt = self.parse_statement()?;
264 ProceduralStatement::Sql(Box::new(sql_stmt))
265 };
266
267 statements.push(stmt);
268 }
269
270 Ok(statements)
271 }
272
273 fn parse_declare_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
277 let name = self.parse_identifier()?;
278 let data_type = self.parse_data_type()?;
279
280 let default_value = if self.try_consume_keyword(Keyword::Default) {
281 Some(Box::new(self.parse_expression()?))
282 } else {
283 None
284 };
285
286 self.expect_token(Token::Semicolon)?;
287
288 Ok(ProceduralStatement::Declare { name, data_type, default_value })
289 }
290
291 fn parse_set_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
295 let name = self.parse_identifier()?;
296 self.expect_token(Token::Symbol('='))?;
297 let value = self.parse_expression()?;
298 self.expect_token(Token::Semicolon)?;
299
300 Ok(ProceduralStatement::Set { name, value: Box::new(value) })
301 }
302
303 fn parse_if_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
307 let condition = self.parse_expression()?;
308 self.expect_keyword(Keyword::Then)?;
309
310 let then_statements =
311 self.parse_procedural_statements_until(&[Keyword::Else, Keyword::End])?;
312
313 let else_statements = if self.try_consume_keyword(Keyword::Else) {
314 Some(self.parse_procedural_statements_until(&[Keyword::End])?)
315 } else {
316 None
317 };
318
319 self.expect_keyword(Keyword::End)?;
320 self.expect_keyword(Keyword::If)?;
321 self.expect_token(Token::Semicolon)?;
322
323 Ok(ProceduralStatement::If {
324 condition: Box::new(condition),
325 then_statements,
326 else_statements,
327 })
328 }
329
330 fn parse_while_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
334 let condition = self.parse_expression()?;
335 self.expect_keyword(Keyword::Do)?;
336
337 let statements = self.parse_procedural_statements_until(&[Keyword::End])?;
338
339 self.expect_keyword(Keyword::End)?;
340 self.expect_keyword(Keyword::While)?;
341 self.expect_token(Token::Semicolon)?;
342
343 Ok(ProceduralStatement::While { condition: Box::new(condition), statements })
344 }
345
346 fn parse_loop_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
350 let statements = self.parse_procedural_statements_until(&[Keyword::End])?;
351
352 self.expect_keyword(Keyword::Loop)?;
353 self.expect_token(Token::Semicolon)?;
354
355 Ok(ProceduralStatement::Loop { statements })
356 }
357
358 fn parse_repeat_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
362 let statements = self.parse_procedural_statements_until(&[Keyword::Until])?;
363
364 self.expect_keyword(Keyword::Until)?;
365 let condition = self.parse_expression()?;
366 self.expect_keyword(Keyword::End)?;
367 self.expect_keyword(Keyword::Repeat)?;
368 self.expect_token(Token::Semicolon)?;
369
370 Ok(ProceduralStatement::Repeat { statements, condition: Box::new(condition) })
371 }
372
373 fn parse_procedural_statements_until(
378 &mut self,
379 stop_keywords: &[Keyword],
380 ) -> Result<Vec<ProceduralStatement>, ParseError> {
381 let mut statements = Vec::new();
382
383 while self.peek() != &Token::Eof {
384 if stop_keywords.iter().any(|kw| self.peek_keyword(*kw)) {
386 break;
387 }
388
389 let stmt = if self.try_consume_keyword(Keyword::Declare) {
390 self.parse_declare_statement()?
391 } else if self.try_consume_keyword(Keyword::Set) {
392 self.parse_set_statement()?
393 } else if self.try_consume_keyword(Keyword::If) {
394 self.parse_if_statement()?
395 } else if self.try_consume_keyword(Keyword::While) {
396 self.parse_while_statement()?
397 } else if self.try_consume_keyword(Keyword::Loop) {
398 self.parse_loop_statement()?
399 } else if self.try_consume_keyword(Keyword::Repeat) {
400 self.parse_repeat_statement()?
401 } else if self.try_consume_keyword(Keyword::Return) {
402 let expr = self.parse_expression()?;
403 self.expect_token(Token::Semicolon)?;
404 ProceduralStatement::Return(Box::new(expr))
405 } else if self.try_consume_keyword(Keyword::Leave) {
406 let label = self.parse_identifier()?;
407 self.expect_token(Token::Semicolon)?;
408 ProceduralStatement::Leave(label)
409 } else if self.try_consume_keyword(Keyword::Iterate) {
410 let label = self.parse_identifier()?;
411 self.expect_token(Token::Semicolon)?;
412 ProceduralStatement::Iterate(label)
413 } else {
414 let sql_stmt = self.parse_statement()?;
416 ProceduralStatement::Sql(Box::new(sql_stmt))
417 };
418
419 statements.push(stmt);
420 }
421
422 Ok(statements)
423 }
424
425 #[allow(clippy::type_complexity)]
429 fn parse_procedure_characteristics(
430 &mut self,
431 ) -> Result<(Option<SqlSecurity>, Option<String>, Option<String>), ParseError> {
432 let mut sql_security = None;
433 let mut comment = None;
434 let mut language = None;
435
436 loop {
438 if self.try_consume_keyword(Keyword::Sql) {
439 self.expect_keyword(Keyword::Security)?;
440 if self.try_consume_keyword(Keyword::Definer) {
441 sql_security = Some(SqlSecurity::Definer);
442 } else if self.try_consume_keyword(Keyword::Invoker) {
443 sql_security = Some(SqlSecurity::Invoker);
444 } else {
445 return Err(ParseError {
446 message: "Expected DEFINER or INVOKER after SQL SECURITY".to_string(),
447 });
448 }
449 } else if self.try_consume_keyword(Keyword::Comment) {
450 if let Token::String(s) = self.peek().clone() {
451 self.advance();
452 comment = Some(s);
453 } else {
454 return Err(ParseError {
455 message: "Expected string literal after COMMENT".to_string(),
456 });
457 }
458 } else if self.try_consume_keyword(Keyword::Language) {
459 self.expect_keyword(Keyword::Sql)?;
460 language = Some("SQL".to_string());
461 } else {
462 break;
464 }
465 }
466
467 Ok((sql_security, comment, language))
468 }
469
470 #[allow(clippy::type_complexity)]
474 fn parse_function_characteristics(
475 &mut self,
476 ) -> Result<(Option<bool>, Option<SqlSecurity>, Option<String>, Option<String>), ParseError>
477 {
478 let mut deterministic = None;
479 let mut sql_security = None;
480 let mut comment = None;
481 let mut language = None;
482
483 loop {
485 if self.try_consume_keyword(Keyword::Deterministic) {
486 deterministic = Some(true);
487 } else if self.try_consume_keyword(Keyword::Not) {
488 self.expect_keyword(Keyword::Deterministic)?;
489 deterministic = Some(false);
490 } else if self.try_consume_keyword(Keyword::Sql) {
491 self.expect_keyword(Keyword::Security)?;
492 if self.try_consume_keyword(Keyword::Definer) {
493 sql_security = Some(SqlSecurity::Definer);
494 } else if self.try_consume_keyword(Keyword::Invoker) {
495 sql_security = Some(SqlSecurity::Invoker);
496 } else {
497 return Err(ParseError {
498 message: "Expected DEFINER or INVOKER after SQL SECURITY".to_string(),
499 });
500 }
501 } else if self.try_consume_keyword(Keyword::Comment) {
502 if let Token::String(s) = self.peek().clone() {
503 self.advance();
504 comment = Some(s);
505 } else {
506 return Err(ParseError {
507 message: "Expected string literal after COMMENT".to_string(),
508 });
509 }
510 } else if self.try_consume_keyword(Keyword::Language) {
511 self.expect_keyword(Keyword::Sql)?;
512 language = Some("SQL".to_string());
513 } else {
514 break;
516 }
517 }
518
519 Ok((deterministic, sql_security, comment, language))
520 }
521}