1use crate::errors::ExecutorError;
2
3#[allow(dead_code)]
6pub fn evaluate_insert_expression(
7 expr: &vibesql_ast::Expression,
8 column: &vibesql_catalog::ColumnSchema,
9 procedural_context: Option<&crate::procedural::ExecutionContext>,
10) -> Result<vibesql_types::SqlValue, ExecutorError> {
11 evaluate_insert_expression_with_trigger_context(
12 expr,
13 column,
14 procedural_context,
15 None,
16 None,
17 None,
18 )
19}
20
21pub fn evaluate_insert_expression_with_trigger_context(
28 expr: &vibesql_ast::Expression,
29 column: &vibesql_catalog::ColumnSchema,
30 procedural_context: Option<&crate::procedural::ExecutionContext>,
31 trigger_context: Option<&crate::trigger_execution::TriggerContext>,
32 database: Option<&vibesql_storage::Database>,
33 cte_results: Option<&std::collections::HashMap<String, crate::select::cte::CteResult>>,
34) -> Result<vibesql_types::SqlValue, ExecutorError> {
35 match expr {
36 vibesql_ast::Expression::Literal(lit) => Ok(lit.clone()),
37 vibesql_ast::Expression::Default => {
38 if let Some(default_expr) = &column.default_value {
40 evaluate_default_expression(default_expr)
42 } else {
43 Ok(vibesql_types::SqlValue::Null)
45 }
46 }
47 vibesql_ast::Expression::ColumnRef(col_id)
48 if col_id.schema_canonical().is_none() && col_id.table_canonical().is_none() =>
49 {
50 let col_name = col_id.column_canonical();
51 if let Some(ctx) = procedural_context {
53 if let Some(value) = ctx.get_value(col_name) {
55 return Ok(value.clone());
56 }
57 }
58 Err(ExecutorError::UnsupportedExpression(format!(
60 "Column reference '{}' not supported in INSERT VALUES. Did you mean to use a procedural variable?",
61 col_name
62 )))
63 }
64 vibesql_ast::Expression::PseudoVariable { .. } => {
65 if let (Some(ctx), Some(db)) = (trigger_context, database) {
68 let dummy_row = vibesql_storage::Row::new(vec![]);
70 let evaluator =
71 crate::ExpressionEvaluator::with_trigger_context(ctx.table_schema, db, ctx);
72 evaluator.eval(expr, &dummy_row)
73 } else {
74 Err(ExecutorError::UnsupportedExpression(
75 "Pseudo-variables (OLD/NEW) are only valid within trigger bodies".to_string(),
76 ))
77 }
78 }
79 _ => {
80 if let (Some(ctx), Some(db)) = (trigger_context, database) {
82 let dummy_row = vibesql_storage::Row::new(vec![]);
84 let mut evaluator =
85 crate::ExpressionEvaluator::with_trigger_context(ctx.table_schema, db, ctx);
86 if let Some(ctes) = cte_results {
87 evaluator = evaluator.with_cte_context(ctes);
88 }
89 evaluator.eval(expr, &dummy_row)
90 } else if let Some(db) = database {
91 let dummy_schema =
95 vibesql_catalog::TableSchema::new("__insert_expr__".to_string(), vec![]);
96 let dummy_row = vibesql_storage::Row::new(vec![]);
97 let mut evaluator = crate::ExpressionEvaluator::with_database(&dummy_schema, db);
98 if let Some(ctes) = cte_results {
99 evaluator = evaluator.with_cte_context(ctes);
100 }
101 evaluator.eval(expr, &dummy_row)
102 } else {
103 Err(ExecutorError::UnsupportedExpression(
104 "Complex expressions in INSERT VALUES require database context".to_string(),
105 ))
106 }
107 }
108 }
109}
110
111pub fn evaluate_default_expression(
117 expr: &vibesql_ast::Expression,
118) -> Result<vibesql_types::SqlValue, ExecutorError> {
119 match expr {
120 vibesql_ast::Expression::Literal(lit) => Ok(lit.clone()),
121 vibesql_ast::Expression::UnaryOp { op, expr } => {
123 let inner = evaluate_default_expression(expr)?;
124 match op {
125 vibesql_ast::UnaryOperator::Plus => Ok(inner), vibesql_ast::UnaryOperator::Minus => {
127 match inner {
129 vibesql_types::SqlValue::Integer(i) => {
130 Ok(vibesql_types::SqlValue::Integer(-i))
131 }
132 vibesql_types::SqlValue::Bigint(i) => {
133 Ok(vibesql_types::SqlValue::Bigint(-i))
134 }
135 vibesql_types::SqlValue::Smallint(i) => {
136 Ok(vibesql_types::SqlValue::Smallint(-i))
137 }
138 vibesql_types::SqlValue::Float(f) => Ok(vibesql_types::SqlValue::Float(-f)),
139 vibesql_types::SqlValue::Real(f) => Ok(vibesql_types::SqlValue::Real(-f)),
140 vibesql_types::SqlValue::Double(f) => {
141 Ok(vibesql_types::SqlValue::Double(-f))
142 }
143 vibesql_types::SqlValue::Numeric(f) => {
144 Ok(vibesql_types::SqlValue::Numeric(-f))
145 }
146 _ => Err(ExecutorError::UnsupportedExpression(format!(
147 "Cannot apply unary minus to {:?}",
148 inner
149 ))),
150 }
151 }
152 _ => Err(ExecutorError::UnsupportedExpression(format!(
153 "Unary operator {:?} not supported in DEFAULT expressions",
154 op
155 ))),
156 }
157 }
158 vibesql_ast::Expression::NextValue { sequence_name } => {
159 Err(ExecutorError::UnsupportedExpression(format!(
162 "Sequence '{}' requires database context - this should have been handled earlier",
163 sequence_name
164 )))
165 }
166 vibesql_ast::Expression::ColumnRef(col_id)
169 if col_id.schema_canonical().is_none() && col_id.table_canonical().is_none() =>
170 {
171 let col_name = col_id.column_canonical();
173 Ok(vibesql_types::SqlValue::Varchar(arcstr::ArcStr::from(col_name)))
174 }
175 vibesql_ast::Expression::Function { name, .. } => {
176 match name.to_uppercase().as_str() {
178 "CURRENT_DATE" => {
179 use chrono::Datelike;
180 let now = chrono::Local::now();
181 let date =
182 vibesql_types::Date::new(now.year(), now.month() as u8, now.day() as u8)
183 .map_err(|e| {
184 ExecutorError::UnsupportedFeature(format!(
185 "Failed to create date: {}",
186 e
187 ))
188 })?;
189 Ok(vibesql_types::SqlValue::Date(date))
190 }
191 "CURRENT_TIME" => {
192 use chrono::Timelike;
193 let now = chrono::Local::now();
194 let time_naive = now.time();
195 let time = vibesql_types::Time::new(
196 time_naive.hour() as u8,
197 time_naive.minute() as u8,
198 time_naive.second() as u8,
199 time_naive.nanosecond(),
200 )
201 .map_err(|e| {
202 ExecutorError::UnsupportedFeature(format!("Failed to create time: {}", e))
203 })?;
204 Ok(vibesql_types::SqlValue::Time(time))
205 }
206 "CURRENT_TIMESTAMP" => {
207 use chrono::{Datelike, Timelike};
208 let now = chrono::Local::now();
209 let time_naive = now.time();
210 let date =
211 vibesql_types::Date::new(now.year(), now.month() as u8, now.day() as u8)
212 .map_err(|e| {
213 ExecutorError::UnsupportedFeature(format!(
214 "Failed to create date: {}",
215 e
216 ))
217 })?;
218 let time = vibesql_types::Time::new(
219 time_naive.hour() as u8,
220 time_naive.minute() as u8,
221 time_naive.second() as u8,
222 time_naive.nanosecond(),
223 )
224 .map_err(|e| {
225 ExecutorError::UnsupportedFeature(format!("Failed to create time: {}", e))
226 })?;
227 Ok(vibesql_types::SqlValue::Timestamp(vibesql_types::Timestamp::new(
228 date, time,
229 )))
230 }
231 "CURRENT_USER" | "USER" | "SESSION_USER" => {
232 Ok(vibesql_types::SqlValue::Varchar(arcstr::ArcStr::from("public")))
234 }
235 "CURRENT_ROLE" => {
236 Ok(vibesql_types::SqlValue::Varchar(arcstr::ArcStr::from("public")))
238 }
239 _ => Err(ExecutorError::UnsupportedExpression(format!(
240 "Function '{}' not supported in DEFAULT expressions",
241 name
242 ))),
243 }
244 }
245 vibesql_ast::Expression::CurrentDate => {
252 use chrono::Datelike;
253 let now = chrono::Local::now();
254 let date = vibesql_types::Date::new(now.year(), now.month() as u8, now.day() as u8)
255 .map_err(|e| {
256 ExecutorError::UnsupportedFeature(format!("Failed to create date: {}", e))
257 })?;
258 Ok(vibesql_types::SqlValue::Date(date))
259 }
260 vibesql_ast::Expression::CurrentTime { .. } => {
261 use chrono::Timelike;
262 let now = chrono::Local::now();
263 let time_naive = now.time();
264 let time = vibesql_types::Time::new(
265 time_naive.hour() as u8,
266 time_naive.minute() as u8,
267 time_naive.second() as u8,
268 time_naive.nanosecond(),
269 )
270 .map_err(|e| {
271 ExecutorError::UnsupportedFeature(format!("Failed to create time: {}", e))
272 })?;
273 Ok(vibesql_types::SqlValue::Time(time))
274 }
275 vibesql_ast::Expression::CurrentTimestamp { .. } => {
276 use chrono::{Datelike, Timelike};
277 let now = chrono::Local::now();
278 let time_naive = now.time();
279 let date = vibesql_types::Date::new(now.year(), now.month() as u8, now.day() as u8)
280 .map_err(|e| {
281 ExecutorError::UnsupportedFeature(format!("Failed to create date: {}", e))
282 })?;
283 let time = vibesql_types::Time::new(
284 time_naive.hour() as u8,
285 time_naive.minute() as u8,
286 time_naive.second() as u8,
287 time_naive.nanosecond(),
288 )
289 .map_err(|e| {
290 ExecutorError::UnsupportedFeature(format!("Failed to create time: {}", e))
291 })?;
292 Ok(vibesql_types::SqlValue::Timestamp(vibesql_types::Timestamp::new(date, time)))
293 }
294 _ => Err(ExecutorError::UnsupportedExpression(
295 "Only literals and functions are supported in DEFAULT expressions".to_string(),
296 )),
297 }
298}
299
300#[allow(dead_code)]
306pub fn apply_default_values(
307 schema: &vibesql_catalog::TableSchema,
308 row_values: &mut [vibesql_types::SqlValue],
309 database: &mut vibesql_storage::Database,
310) -> Result<Option<i64>, ExecutorError> {
311 apply_default_values_with_table_name(schema, row_values, database, &schema.name)
312}
313
314pub fn apply_default_values_with_table_name(
322 schema: &vibesql_catalog::TableSchema,
323 row_values: &mut [vibesql_types::SqlValue],
324 database: &mut vibesql_storage::Database,
325 storage_table_name: &str,
326) -> Result<Option<i64>, ExecutorError> {
327 apply_default_values_with_batch_context(schema, row_values, database, storage_table_name, None)
328}
329
330pub fn apply_default_values_with_batch_context(
339 schema: &vibesql_catalog::TableSchema,
340 row_values: &mut [vibesql_types::SqlValue],
341 database: &mut vibesql_storage::Database,
342 storage_table_name: &str,
343 batch_max_ipk: Option<i64>,
344) -> Result<Option<i64>, ExecutorError> {
345 let mut first_generated_id: Option<i64> = None;
346
347 if let Some(ipk_idx) = schema.get_integer_primary_key_index() {
350 if row_values[ipk_idx] == vibesql_types::SqlValue::Null {
351 let table_max = compute_next_integer_pk_value(database, storage_table_name, ipk_idx)?;
353 let next_val = match batch_max_ipk {
355 Some(batch_max) => table_max.max(batch_max + 1),
356 None => table_max,
357 };
358 row_values[ipk_idx] = vibesql_types::SqlValue::Integer(next_val);
359
360 if first_generated_id.is_none() {
362 first_generated_id = Some(next_val);
363 }
364 }
365 }
366
367 for (col_idx, col) in schema.columns.iter().enumerate() {
368 if row_values[col_idx] == vibesql_types::SqlValue::Null {
370 if let Some(default_expr) = &col.default_value {
371 let default_value = match default_expr {
373 vibesql_ast::Expression::NextValue { sequence_name } => {
374 let seq =
376 database.catalog.get_sequence_mut(sequence_name).map_err(|e| {
377 ExecutorError::UnsupportedExpression(format!(
378 "Sequence error: {:?}",
379 e
380 ))
381 })?;
382 let next_val = seq.next_value().map_err(|e| {
383 ExecutorError::ConstraintViolation(format!("Sequence error: {}", e))
384 })?;
385
386 if first_generated_id.is_none() {
388 first_generated_id = Some(next_val);
389 }
390
391 vibesql_types::SqlValue::Integer(next_val)
392 }
393 _ => evaluate_default_expression(default_expr)?,
394 };
395 let coerced_value = super::validation::coerce_value(default_value, &col.data_type)?;
396 row_values[col_idx] = coerced_value;
397 }
398 }
399 }
400 Ok(first_generated_id)
401}
402
403fn compute_next_integer_pk_value(
409 database: &vibesql_storage::Database,
410 table_name: &str,
411 pk_col_idx: usize,
412) -> Result<i64, ExecutorError> {
413 let table = match database.get_table(table_name) {
414 Some(t) => t,
415 None => {
416 return Ok(1);
418 }
419 };
420
421 let mut max_val: i64 = 0;
423
424 for row in table.scan() {
425 if let Some(value) = row.get(pk_col_idx) {
426 let int_val = match value {
427 vibesql_types::SqlValue::Integer(i) => *i,
428 vibesql_types::SqlValue::Bigint(i) => *i,
429 vibesql_types::SqlValue::Null => continue, _ => continue, };
432 if int_val > max_val {
433 max_val = int_val;
434 }
435 }
436 }
437
438 Ok(max_val + 1)
440}
441
442pub fn apply_generated_columns(
445 schema: &vibesql_catalog::TableSchema,
446 row_values: &mut [vibesql_types::SqlValue],
447 _database: &vibesql_storage::Database,
448) -> Result<(), ExecutorError> {
449 let temp_row = vibesql_storage::Row::new(row_values.to_vec());
453 let evaluator = crate::ExpressionEvaluator::new(schema)
454 .with_schema_context(crate::evaluator::SchemaExprContext::GeneratedColumn);
455
456 for (col_idx, col) in schema.columns.iter().enumerate() {
457 if let Some(generated_expr) = &col.generated_expr {
459 let generated_value = evaluator.eval(generated_expr, &temp_row)?;
460 let coerced_value = super::validation::coerce_value(generated_value, &col.data_type)?;
461 row_values[col_idx] = coerced_value;
462 }
463 }
464 Ok(())
465}