(stmt: &Statement, loop_depth: usize)
| 53 | } |
| 54 | |
| 55 | fn validate_statement(stmt: &Statement, loop_depth: usize) -> Result<(), ProceduralError> { |
| 56 | match stmt { |
| 57 | Statement::Sql { sql } if is_side_effect_sql(sql) => { |
| 58 | Err(ProceduralError::validate(format!( |
| 59 | "side-effecting SQL is not allowed in function bodies: '{sql}'. \ |
| 60 | Use CREATE PROCEDURE for side-effecting logic" |
| 61 | ))) |
| 62 | } |
| 63 | Statement::Sql { .. } => Ok(()), // SELECT and other read-only SQL is allowed. |
| 64 | Statement::Commit => Err(ProceduralError::validate( |
| 65 | "COMMIT is not allowed in function bodies. \ |
| 66 | Use CREATE PROCEDURE for transaction control", |
| 67 | )), |
| 68 | Statement::Rollback | Statement::RollbackTo { .. } => Err(ProceduralError::validate( |
| 69 | "ROLLBACK is not allowed in function bodies. \ |
| 70 | Use CREATE PROCEDURE for transaction control", |
| 71 | )), |
| 72 | Statement::Savepoint { .. } | Statement::ReleaseSavepoint { .. } => { |
| 73 | Err(ProceduralError::validate( |
| 74 | "SAVEPOINT is not allowed in function bodies. \ |
| 75 | Use CREATE PROCEDURE for transaction control", |
| 76 | )) |
| 77 | } |
| 78 | Statement::If { |
| 79 | then_block, |
| 80 | elsif_branches, |
| 81 | else_block, |
| 82 | .. |
| 83 | } => { |
| 84 | for s in then_block { |
| 85 | validate_statement(s, loop_depth)?; |
| 86 | } |
| 87 | for branch in elsif_branches { |
| 88 | for s in &branch.body { |
| 89 | validate_statement(s, loop_depth)?; |
| 90 | } |
| 91 | } |
| 92 | if let Some(else_stmts) = else_block { |
| 93 | for s in else_stmts { |
| 94 | validate_statement(s, loop_depth)?; |
| 95 | } |
| 96 | } |
| 97 | Ok(()) |
| 98 | } |
| 99 | Statement::While { .. } | Statement::Loop { .. } => { |
| 100 | // Bare LOOP and WHILE in functions are rejected — we can't determine |
| 101 | // bound at compile time without analyzing the condition + body. |
| 102 | // Use FOR with known bounds instead. |
| 103 | Err(ProceduralError::validate( |
| 104 | "LOOP/WHILE is not supported in function bodies \ |
| 105 | (loop bounds cannot be determined at compile time). \ |
| 106 | Use FOR i IN start..end LOOP for bounded iteration, \ |
| 107 | or CREATE PROCEDURE for unbounded loops", |
| 108 | )) |
| 109 | } |
| 110 | Statement::For { |
| 111 | body, start, end, .. |
| 112 | } => { |
no test coverage detected