vibesql_parser/parser/advanced_objects/
routines.rs1use vibesql_ast::{
30 CallStmt, CreateFunctionStmt, CreateProcedureStmt, DropFunctionStmt, DropProcedureStmt,
31 FunctionParameter, ParameterMode, ProceduralStatement, ProcedureBody, ProcedureParameter,
32 SqlSecurity,
33};
34
35use crate::{
36 keywords::Keyword,
37 parser::{ParseError, Parser},
38 token::Token,
39};
40
41impl Parser {
42 pub fn parse_create_procedure(&mut self) -> Result<CreateProcedureStmt, ParseError> {
46 let procedure_name = self.parse_identifier()?;
48
49 self.expect_token(Token::LParen)?;
50 let parameters = self.parse_procedure_parameters()?;
51 self.expect_token(Token::RParen)?;
52
53 let (sql_security, comment, language) = self.parse_procedure_characteristics()?;
55
56 let body = self.parse_procedure_body()?;
57
58 Ok(CreateProcedureStmt {
59 procedure_name,
60 parameters,
61 body,
62 sql_security,
63 comment,
64 language,
65 })
66 }
67
68 pub fn parse_create_function(&mut self) -> Result<CreateFunctionStmt, ParseError> {
73 let function_name = self.parse_identifier()?;
75
76 self.expect_token(Token::LParen)?;
77 let parameters = self.parse_function_parameters()?;
78 self.expect_token(Token::RParen)?;
79
80 self.expect_keyword(Keyword::Returns)?;
81 let return_type = self.parse_data_type()?;
82
83 let (deterministic, sql_security, comment, language) =
85 self.parse_function_characteristics()?;
86
87 let body = self.parse_procedure_body()?;
88
89 Ok(CreateFunctionStmt {
90 function_name,
91 parameters,
92 return_type,
93 body,
94 deterministic,
95 sql_security,
96 comment,
97 language,
98 })
99 }
100
101 pub fn parse_drop_procedure(&mut self) -> Result<DropProcedureStmt, ParseError> {
105 let if_exists = self.try_consume_keyword(Keyword::If);
107 if if_exists {
108 self.expect_keyword(Keyword::Exists)?;
109 }
110
111 let procedure_name = self.parse_identifier()?;
112
113 Ok(DropProcedureStmt { procedure_name, if_exists })
114 }
115
116 pub fn parse_drop_function(&mut self) -> Result<DropFunctionStmt, ParseError> {
120 let if_exists = self.try_consume_keyword(Keyword::If);
122 if if_exists {
123 self.expect_keyword(Keyword::Exists)?;
124 }
125
126 let function_name = self.parse_identifier()?;
127
128 Ok(DropFunctionStmt { function_name, if_exists })
129 }
130
131 pub fn parse_call(&mut self) -> Result<CallStmt, ParseError> {
135 let procedure_name = self.parse_identifier()?;
137
138 self.expect_token(Token::LParen)?;
139 let arguments = self.parse_expression_list()?;
140 self.expect_token(Token::RParen)?;
141
142 Ok(CallStmt { procedure_name, arguments })
143 }
144
145 fn parse_procedure_parameters(&mut self) -> Result<Vec<ProcedureParameter>, ParseError> {
149 let mut parameters = Vec::new();
150
151 if self.peek() == &Token::RParen {
153 return Ok(parameters);
154 }
155
156 loop {
157 let mode = if self.try_consume_keyword(Keyword::In) {
159 ParameterMode::In
160 } else if self.try_consume_keyword(Keyword::Out) {
161 ParameterMode::Out
162 } else if self.try_consume_keyword(Keyword::InOut) {
163 ParameterMode::InOut
164 } else {
165 ParameterMode::In
167 };
168
169 let name = self.parse_identifier()?;
170 let data_type = self.parse_data_type()?;
171
172 parameters.push(ProcedureParameter { mode, name, data_type });
173
174 if !self.try_consume(&Token::Comma) {
175 break;
176 }
177 }
178
179 Ok(parameters)
180 }
181
182 fn parse_function_parameters(&mut self) -> Result<Vec<FunctionParameter>, ParseError> {
187 let mut parameters = Vec::new();
188
189 if self.peek() == &Token::RParen {
191 return Ok(parameters);
192 }
193
194 loop {
195 let name = self.parse_identifier()?;
196 let data_type = self.parse_data_type()?;
197
198 parameters.push(FunctionParameter { name, data_type });
199
200 if !self.try_consume(&Token::Comma) {
201 break;
202 }
203 }
204
205 Ok(parameters)
206 }
207
208 fn parse_procedure_body(&mut self) -> Result<ProcedureBody, ParseError> {
214 if self.try_consume_keyword(Keyword::Begin) {
215 let statements = self.parse_procedural_statements()?;
217 self.expect_keyword(Keyword::End)?;
218 Ok(ProcedureBody::BeginEnd(statements))
219 } else {
220 Err(ParseError { message: "Expected BEGIN keyword for procedure body".to_string() })
222 }
223 }
224
225 fn parse_procedural_statements(&mut self) -> Result<Vec<ProceduralStatement>, ParseError> {
238 let mut statements = Vec::new();
239
240 while !self.peek_keyword(Keyword::End) && self.peek() != &Token::Eof {
241 let stmt = if self.try_consume_keyword(Keyword::Declare) {
242 self.parse_declare_statement()?
243 } else if self.try_consume_keyword(Keyword::Set) {
244 self.parse_set_statement()?
245 } else if self.try_consume_keyword(Keyword::If) {
246 self.parse_if_statement()?
247 } else if self.try_consume_keyword(Keyword::While) {
248 self.parse_while_statement()?
249 } else if self.try_consume_keyword(Keyword::Loop) {
250 self.parse_loop_statement()?
251 } else if self.try_consume_keyword(Keyword::Repeat) {
252 self.parse_repeat_statement()?
253 } else if self.try_consume_keyword(Keyword::Return) {
254 let expr = self.parse_expression()?;
255 self.expect_token(Token::Semicolon)?;
256 ProceduralStatement::Return(Box::new(expr))
257 } else if self.try_consume_keyword(Keyword::Leave) {
258 let label = self.parse_identifier()?;
259 self.expect_token(Token::Semicolon)?;
260 ProceduralStatement::Leave(label)
261 } else if self.try_consume_keyword(Keyword::Iterate) {
262 let label = self.parse_identifier()?;
263 self.expect_token(Token::Semicolon)?;
264 ProceduralStatement::Iterate(label)
265 } else {
266 let sql_stmt = self.parse_statement()?;
268 ProceduralStatement::Sql(Box::new(sql_stmt))
269 };
270
271 statements.push(stmt);
272 }
273
274 Ok(statements)
275 }
276
277 fn parse_declare_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
281 let name = self.parse_identifier()?;
282 let data_type = self.parse_data_type()?;
283
284 let default_value = if self.try_consume_keyword(Keyword::Default) {
285 Some(Box::new(self.parse_expression()?))
286 } else {
287 None
288 };
289
290 self.expect_token(Token::Semicolon)?;
291
292 Ok(ProceduralStatement::Declare { name, data_type, default_value })
293 }
294
295 fn parse_set_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
299 let name = self.parse_identifier()?;
300 self.expect_token(Token::Symbol('='))?;
301 let value = self.parse_expression()?;
302 self.expect_token(Token::Semicolon)?;
303
304 Ok(ProceduralStatement::Set { name, value: Box::new(value) })
305 }
306
307 fn parse_if_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
311 let condition = self.parse_expression()?;
312 self.expect_keyword(Keyword::Then)?;
313
314 let then_statements =
315 self.parse_procedural_statements_until(&[Keyword::Else, Keyword::End])?;
316
317 let else_statements = if self.try_consume_keyword(Keyword::Else) {
318 Some(self.parse_procedural_statements_until(&[Keyword::End])?)
319 } else {
320 None
321 };
322
323 self.expect_keyword(Keyword::End)?;
324 self.expect_keyword(Keyword::If)?;
325 self.expect_token(Token::Semicolon)?;
326
327 Ok(ProceduralStatement::If {
328 condition: Box::new(condition),
329 then_statements,
330 else_statements,
331 })
332 }
333
334 fn parse_while_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
338 let condition = self.parse_expression()?;
339 self.expect_keyword(Keyword::Do)?;
340
341 let statements = self.parse_procedural_statements_until(&[Keyword::End])?;
342
343 self.expect_keyword(Keyword::End)?;
344 self.expect_keyword(Keyword::While)?;
345 self.expect_token(Token::Semicolon)?;
346
347 Ok(ProceduralStatement::While { condition: Box::new(condition), statements })
348 }
349
350 fn parse_loop_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
354 let statements = self.parse_procedural_statements_until(&[Keyword::End])?;
355
356 self.expect_keyword(Keyword::Loop)?;
357 self.expect_token(Token::Semicolon)?;
358
359 Ok(ProceduralStatement::Loop { statements })
360 }
361
362 fn parse_repeat_statement(&mut self) -> Result<ProceduralStatement, ParseError> {
366 let statements = self.parse_procedural_statements_until(&[Keyword::Until])?;
367
368 self.expect_keyword(Keyword::Until)?;
369 let condition = self.parse_expression()?;
370 self.expect_keyword(Keyword::End)?;
371 self.expect_keyword(Keyword::Repeat)?;
372 self.expect_token(Token::Semicolon)?;
373
374 Ok(ProceduralStatement::Repeat { statements, condition: Box::new(condition) })
375 }
376
377 fn parse_procedural_statements_until(
382 &mut self,
383 stop_keywords: &[Keyword],
384 ) -> Result<Vec<ProceduralStatement>, ParseError> {
385 let mut statements = Vec::new();
386
387 while self.peek() != &Token::Eof {
388 if stop_keywords.iter().any(|kw| self.peek_keyword(*kw)) {
390 break;
391 }
392
393 let stmt = if self.try_consume_keyword(Keyword::Declare) {
394 self.parse_declare_statement()?
395 } else if self.try_consume_keyword(Keyword::Set) {
396 self.parse_set_statement()?
397 } else if self.try_consume_keyword(Keyword::If) {
398 self.parse_if_statement()?
399 } else if self.try_consume_keyword(Keyword::While) {
400 self.parse_while_statement()?
401 } else if self.try_consume_keyword(Keyword::Loop) {
402 self.parse_loop_statement()?
403 } else if self.try_consume_keyword(Keyword::Repeat) {
404 self.parse_repeat_statement()?
405 } else if self.try_consume_keyword(Keyword::Return) {
406 let expr = self.parse_expression()?;
407 self.expect_token(Token::Semicolon)?;
408 ProceduralStatement::Return(Box::new(expr))
409 } else if self.try_consume_keyword(Keyword::Leave) {
410 let label = self.parse_identifier()?;
411 self.expect_token(Token::Semicolon)?;
412 ProceduralStatement::Leave(label)
413 } else if self.try_consume_keyword(Keyword::Iterate) {
414 let label = self.parse_identifier()?;
415 self.expect_token(Token::Semicolon)?;
416 ProceduralStatement::Iterate(label)
417 } else {
418 let sql_stmt = self.parse_statement()?;
420 ProceduralStatement::Sql(Box::new(sql_stmt))
421 };
422
423 statements.push(stmt);
424 }
425
426 Ok(statements)
427 }
428
429 #[allow(clippy::type_complexity)]
433 fn parse_procedure_characteristics(
434 &mut self,
435 ) -> Result<(Option<SqlSecurity>, Option<String>, Option<String>), ParseError> {
436 let mut sql_security = None;
437 let mut comment = None;
438 let mut language = None;
439
440 loop {
442 if self.try_consume_keyword(Keyword::Sql) {
443 self.expect_keyword(Keyword::Security)?;
444 if self.try_consume_keyword(Keyword::Definer) {
445 sql_security = Some(SqlSecurity::Definer);
446 } else if self.try_consume_keyword(Keyword::Invoker) {
447 sql_security = Some(SqlSecurity::Invoker);
448 } else {
449 return Err(ParseError {
450 message: "Expected DEFINER or INVOKER after SQL SECURITY".to_string(),
451 });
452 }
453 } else if self.try_consume_keyword(Keyword::Comment) {
454 if let Token::String(s) = self.peek().clone() {
455 self.advance();
456 comment = Some(s);
457 } else {
458 return Err(ParseError {
459 message: "Expected string literal after COMMENT".to_string(),
460 });
461 }
462 } else if self.try_consume_keyword(Keyword::Language) {
463 self.expect_keyword(Keyword::Sql)?;
464 language = Some("SQL".to_string());
465 } else {
466 break;
468 }
469 }
470
471 Ok((sql_security, comment, language))
472 }
473
474 #[allow(clippy::type_complexity)]
478 fn parse_function_characteristics(
479 &mut self,
480 ) -> Result<(Option<bool>, Option<SqlSecurity>, Option<String>, Option<String>), ParseError>
481 {
482 let mut deterministic = None;
483 let mut sql_security = None;
484 let mut comment = None;
485 let mut language = None;
486
487 loop {
489 if self.try_consume_keyword(Keyword::Deterministic) {
490 deterministic = Some(true);
491 } else if self.try_consume_keyword(Keyword::Not) {
492 self.expect_keyword(Keyword::Deterministic)?;
493 deterministic = Some(false);
494 } else if self.try_consume_keyword(Keyword::Sql) {
495 self.expect_keyword(Keyword::Security)?;
496 if self.try_consume_keyword(Keyword::Definer) {
497 sql_security = Some(SqlSecurity::Definer);
498 } else if self.try_consume_keyword(Keyword::Invoker) {
499 sql_security = Some(SqlSecurity::Invoker);
500 } else {
501 return Err(ParseError {
502 message: "Expected DEFINER or INVOKER after SQL SECURITY".to_string(),
503 });
504 }
505 } else if self.try_consume_keyword(Keyword::Comment) {
506 if let Token::String(s) = self.peek().clone() {
507 self.advance();
508 comment = Some(s);
509 } else {
510 return Err(ParseError {
511 message: "Expected string literal after COMMENT".to_string(),
512 });
513 }
514 } else if self.try_consume_keyword(Keyword::Language) {
515 self.expect_keyword(Keyword::Sql)?;
516 language = Some("SQL".to_string());
517 } else {
518 break;
520 }
521 }
522
523 Ok((deterministic, sql_security, comment, language))
524 }
525}