vibesql_executor/procedural/
control_flow.rs1use crate::errors::ExecutorError;
10use crate::procedural::{ControlFlow, ExecutionContext};
11use vibesql_ast::ProceduralStatement;
12use vibesql_storage::Database;
13use vibesql_types::SqlValue;
14
15use super::executor::evaluate_expression;
17
18pub fn execute_if(
20 condition: &vibesql_ast::Expression,
21 then_statements: &[ProceduralStatement],
22 else_statements: &Option<Vec<ProceduralStatement>>,
23 ctx: &mut ExecutionContext,
24 db: &mut Database,
25) -> Result<ControlFlow, ExecutorError> {
26 let condition_value = evaluate_expression(condition, db, ctx)?;
28
29 let is_true = match condition_value {
31 SqlValue::Boolean(b) => b,
32 SqlValue::Integer(i) => i != 0,
33 SqlValue::Null => false,
34 _ => {
35 return Err(ExecutorError::TypeError(format!(
36 "IF condition must evaluate to boolean, got {:?}",
37 condition_value
38 )))
39 }
40 };
41
42 if is_true {
44 for stmt in then_statements {
45 let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
46 if flow != ControlFlow::Continue {
47 return Ok(flow);
48 }
49 }
50 } else if let Some(else_stmts) = else_statements {
51 for stmt in else_stmts {
52 let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
53 if flow != ControlFlow::Continue {
54 return Ok(flow);
55 }
56 }
57 }
58
59 Ok(ControlFlow::Continue)
60}
61
62pub fn execute_while(
64 condition: &vibesql_ast::Expression,
65 statements: &[ProceduralStatement],
66 ctx: &mut ExecutionContext,
67 db: &mut Database,
68) -> Result<ControlFlow, ExecutorError> {
69 loop {
70 let condition_value = evaluate_expression(condition, db, ctx)?;
72
73 let is_true = match condition_value {
75 SqlValue::Boolean(b) => b,
76 SqlValue::Integer(i) => i != 0,
77 SqlValue::Null => false,
78 _ => {
79 return Err(ExecutorError::TypeError(format!(
80 "WHILE condition must evaluate to boolean, got {:?}",
81 condition_value
82 )))
83 }
84 };
85
86 if !is_true {
87 break;
88 }
89
90 for stmt in statements {
92 let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
93 match flow {
94 ControlFlow::Continue => {}
95 ControlFlow::Return(_) => return Ok(flow),
96 ControlFlow::Leave(_) => return Ok(flow),
97 ControlFlow::Iterate(_) => break, }
99 }
100 }
101
102 Ok(ControlFlow::Continue)
103}
104
105pub fn execute_loop(
107 statements: &[ProceduralStatement],
108 ctx: &mut ExecutionContext,
109 db: &mut Database,
110) -> Result<ControlFlow, ExecutorError> {
111 loop {
112 for stmt in statements {
113 let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
114 match flow {
115 ControlFlow::Continue => {}
116 ControlFlow::Return(_) => return Ok(flow),
117 ControlFlow::Leave(_) => return Ok(ControlFlow::Continue), ControlFlow::Iterate(_) => break, }
120 }
121 }
122}
123
124pub fn execute_repeat(
126 statements: &[ProceduralStatement],
127 condition: &vibesql_ast::Expression,
128 ctx: &mut ExecutionContext,
129 db: &mut Database,
130) -> Result<ControlFlow, ExecutorError> {
131 loop {
132 for stmt in statements {
134 let flow = super::executor::execute_procedural_statement(stmt, ctx, db)?;
135 match flow {
136 ControlFlow::Continue => {}
137 ControlFlow::Return(_) => return Ok(flow),
138 ControlFlow::Leave(_) => return Ok(flow),
139 ControlFlow::Iterate(_) => break, }
141 }
142
143 let condition_value = evaluate_expression(condition, db, ctx)?;
145
146 let should_exit = match condition_value {
148 SqlValue::Boolean(b) => b,
149 SqlValue::Integer(i) => i != 0,
150 SqlValue::Null => false,
151 _ => {
152 return Err(ExecutorError::TypeError(format!(
153 "REPEAT UNTIL condition must evaluate to boolean, got {:?}",
154 condition_value
155 )))
156 }
157 };
158
159 if should_exit {
160 break;
161 }
162 }
163
164 Ok(ControlFlow::Continue)
165}