vibesql_executor/
schema_ddl.rs1use vibesql_ast::*;
4use vibesql_storage::Database;
5
6use crate::{create_table::CreateTableExecutor, errors::ExecutorError};
7
8pub struct SchemaExecutor;
10
11impl SchemaExecutor {
12 pub fn execute_create_schema(
14 stmt: &CreateSchemaStmt,
15 database: &mut Database,
16 ) -> Result<String, ExecutorError> {
17 database.begin_transaction().map_err(|e| {
19 ExecutorError::StorageError(format!("Failed to begin transaction: {}", e))
20 })?;
21
22 let result = Self::execute_create_schema_internal(stmt, database);
24
25 match result {
27 Ok(msg) => {
28 database.commit_transaction().map_err(|e| {
29 ExecutorError::StorageError(format!("Failed to commit transaction: {}", e))
30 })?;
31 Ok(msg)
32 }
33 Err(e) => {
34 database.rollback_transaction().map_err(|rollback_err| {
35 ExecutorError::StorageError(format!(
36 "Failed to rollback transaction after error: {}. Original error: {}",
37 rollback_err, e
38 ))
39 })?;
40 Err(e)
41 }
42 }
43 }
44
45 fn execute_create_schema_internal(
47 stmt: &CreateSchemaStmt,
48 database: &mut Database,
49 ) -> Result<String, ExecutorError> {
50 if !stmt.if_not_exists || !database.catalog.schema_exists(&stmt.schema_name) {
52 database
53 .catalog
54 .create_schema(stmt.schema_name.clone())
55 .map_err(|e| ExecutorError::StorageError(format!("Catalog error: {:?}", e)))?;
56 }
57
58 let original_schema = database.catalog.get_current_schema().to_string();
60 database
61 .catalog
62 .set_current_schema(&stmt.schema_name)
63 .map_err(|e| ExecutorError::StorageError(format!("Schema error: {:?}", e)))?;
64
65 for element in &stmt.schema_elements {
67 let result = match element {
68 SchemaElement::CreateTable(table_stmt) => {
69 CreateTableExecutor::execute(table_stmt, database)
70 }
71 };
72
73 if let Err(e) = result {
76 let _ = database.catalog.set_current_schema(&original_schema);
78 return Err(ExecutorError::StorageError(format!(
79 "Failed to execute schema element: {}",
80 e
81 )));
82 }
83 }
84
85 database
87 .catalog
88 .set_current_schema(&original_schema)
89 .map_err(|e| ExecutorError::StorageError(format!("Schema error: {:?}", e)))?;
90
91 let element_count = stmt.schema_elements.len();
92 if element_count > 0 {
93 Ok(format!("Schema '{}' created with {} element(s)", stmt.schema_name, element_count))
94 } else {
95 Ok(format!("Schema '{}' created", stmt.schema_name))
96 }
97 }
98
99 pub fn execute_drop_schema(
101 stmt: &DropSchemaStmt,
102 database: &mut Database,
103 ) -> Result<String, ExecutorError> {
104 if stmt.if_exists && !database.catalog.schema_exists(&stmt.schema_name) {
105 return Ok(format!("Schema '{}' does not exist, skipping", stmt.schema_name));
106 }
107
108 database
109 .catalog
110 .drop_schema(&stmt.schema_name, stmt.cascade)
111 .map_err(|e| ExecutorError::StorageError(format!("Catalog error: {:?}", e)))?;
112 Ok(format!("Schema '{}' dropped", stmt.schema_name))
113 }
114
115 pub fn execute_set_schema(
117 stmt: &SetSchemaStmt,
118 database: &mut Database,
119 ) -> Result<String, ExecutorError> {
120 database
121 .catalog
122 .set_current_schema(&stmt.schema_name)
123 .map_err(|e| ExecutorError::StorageError(format!("Catalog error: {:?}", e)))?;
124 Ok(format!("Current schema set to '{}'", stmt.schema_name))
125 }
126
127 pub fn execute_set_catalog(
129 stmt: &vibesql_ast::SetCatalogStmt,
130 database: &mut Database,
131 ) -> Result<String, ExecutorError> {
132 database.catalog.set_current_catalog(Some(stmt.catalog_name.clone()));
133 Ok(format!("Current catalog set to '{}'", stmt.catalog_name))
134 }
135
136 pub fn execute_set_names(
138 stmt: &vibesql_ast::SetNamesStmt,
139 database: &mut Database,
140 ) -> Result<String, ExecutorError> {
141 database.catalog.set_current_charset(stmt.charset_name.clone());
142
143 if let Some(ref collation) = stmt.collation {
144 database.catalog.set_current_collation(Some(collation.clone()));
145 Ok(format!(
146 "Character set set to '{}' with collation '{}'",
147 stmt.charset_name, collation
148 ))
149 } else {
150 database.catalog.set_current_collation(None);
151 Ok(format!("Character set set to '{}'", stmt.charset_name))
152 }
153 }
154
155 pub fn execute_set_variable(
157 stmt: &vibesql_ast::SetVariableStmt,
158 database: &mut Database,
159 ) -> Result<String, ExecutorError> {
160 let empty_schema = vibesql_catalog::TableSchema::new(String::new(), vec![]);
163
164 let empty_row = vibesql_storage::Row::new(vec![]);
166
167 let evaluator = crate::evaluator::ExpressionEvaluator::with_database(
169 &empty_schema,
170 database,
171 );
172
173 let value = evaluator.eval(&stmt.value, &empty_row)?;
175
176 if stmt.variable.eq_ignore_ascii_case("sql_mode") {
178 let mode_str = match &value {
180 vibesql_types::SqlValue::Varchar(s) | vibesql_types::SqlValue::Character(s) => s.clone(),
181 other => other.to_string(),
182 };
183
184 let mode: vibesql_types::SqlMode = mode_str.parse().map_err(|e: String| {
186 ExecutorError::StorageError(e)
187 })?;
188
189 database.set_sql_mode(mode.clone());
191
192 return Ok(format!("SQL mode set to '{}'", mode));
193 }
194
195 database.set_session_variable(&stmt.variable, value.clone());
199
200 Ok(format!("Variable '{}' set to {:?}", stmt.variable, value))
201 }
202
203 pub fn execute_set_time_zone(
205 stmt: &vibesql_ast::SetTimeZoneStmt,
206 database: &mut Database,
207 ) -> Result<String, ExecutorError> {
208 let timezone_str = match &stmt.zone {
209 vibesql_ast::TimeZoneSpec::Local => {
210 database.catalog.set_current_timezone("LOCAL".to_string());
211 "LOCAL".to_string()
212 }
213 vibesql_ast::TimeZoneSpec::Interval(interval) => {
214 database.catalog.set_current_timezone(interval.clone());
215 interval.clone()
216 }
217 };
218
219 Ok(format!("Time zone set to '{}'", timezone_str))
220 }
221}