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