vibesql_executor/advanced_objects/
views.rs

1//! Executor for VIEW objects (SQL:1999)
2
3use vibesql_ast::*;
4use vibesql_catalog::ViewDropBehavior;
5use vibesql_storage::Database;
6
7use crate::errors::ExecutorError;
8
9/// Execute CREATE VIEW statement
10pub fn execute_create_view(stmt: &CreateViewStmt, db: &mut Database) -> Result<(), ExecutorError> {
11    use vibesql_catalog::ViewDefinition;
12
13    // If no explicit column list is provided, derive column names from the query
14    // This ensures views with SELECT * preserve original column names
15    let columns = if stmt.columns.is_none() {
16        // Execute the query once to derive column names
17        use crate::select::SelectExecutor;
18        let executor = SelectExecutor::new(db);
19        let result = executor.execute_with_columns(&stmt.query)?;
20        Some(result.columns)
21    } else {
22        stmt.columns.clone()
23    };
24
25    let view = ViewDefinition::new(
26        stmt.view_name.clone(),
27        columns,
28        (*stmt.query).clone(),
29        stmt.with_check_option,
30    );
31
32    if stmt.or_replace {
33        // DROP the view if it exists, then CREATE
34        let _ = db.catalog.drop_view(&stmt.view_name, false);
35        db.catalog.create_view(view)?;
36    } else {
37        // Regular CREATE VIEW (will fail if view already exists)
38        db.catalog.create_view(view)?;
39    }
40    Ok(())
41}
42
43/// Execute DROP VIEW statement
44pub fn execute_drop_view(stmt: &DropViewStmt, db: &mut Database) -> Result<(), ExecutorError> {
45    // Check if view exists
46    let view_exists = db.catalog.get_view(&stmt.view_name).is_some();
47
48    // If IF EXISTS is specified and view doesn't exist, succeed silently
49    if stmt.if_exists && !view_exists {
50        return Ok(());
51    }
52
53    // Determine drop behavior:
54    // - CASCADE: drop dependent views recursively
55    // - RESTRICT (explicit): fail if dependents exist
56    // - Neither: SQLite-compatible behavior (just drop, ignore dependents)
57    let drop_behavior = if stmt.cascade {
58        ViewDropBehavior::Cascade
59    } else if stmt.restrict {
60        ViewDropBehavior::Restrict
61    } else {
62        ViewDropBehavior::Silent // SQLite-compatible: allow dropping even with dependents
63    };
64
65    db.catalog.drop_view_with_behavior(&stmt.view_name, drop_behavior)?;
66    Ok(())
67}