vibesql_executor/
select_into.rs1use vibesql_ast::{ColumnDef, CreateTableStmt, SelectItem, SelectStmt};
7use vibesql_storage::Database;
8use vibesql_types::DataType;
9
10use crate::{errors::ExecutorError, select::SelectExecutor};
11
12pub struct SelectIntoExecutor;
13
14impl SelectIntoExecutor {
15 pub fn execute(
20 stmt: &SelectStmt,
21 target_table: &str,
22 database: &mut Database,
23 ) -> Result<String, ExecutorError> {
24 if stmt.into_table.is_none() {
26 return Err(ExecutorError::Other(
27 "execute_select_into called on non-SELECT INTO statement".to_string(),
28 ));
29 }
30
31 let executor = SelectExecutor::new(database);
33 let rows = executor.execute(stmt)?;
34
35 if rows.is_empty() {
37 return Err(ExecutorError::UnsupportedFeature(
38 "SELECT INTO returned no rows (expected exactly 1 row for Feature E111)"
39 .to_string(),
40 ));
41 }
42 if rows.len() > 1 {
43 return Err(ExecutorError::UnsupportedFeature(format!(
44 "SELECT INTO returned {} rows (expected exactly 1 row for Feature E111)",
45 rows.len()
46 )));
47 }
48
49 let column_defs = Self::derive_column_definitions(&stmt.select_list, &rows[0], database)?;
51
52 let create_stmt = CreateTableStmt {
54 temporary: false,
55 if_not_exists: false,
56 table_name: target_table.to_string(),
57 columns: column_defs,
58 table_constraints: vec![],
59 table_options: vec![],
60 quoted: false, as_query: None, without_rowid: false,
62 };
63
64 crate::CreateTableExecutor::execute(&create_stmt, database)?;
65
66 database
68 .insert_row(target_table, rows[0].clone())
69 .map_err(|e| ExecutorError::StorageError(e.to_string()))?;
70
71 Ok(format!("SELECT INTO: Created table '{}' with 1 row", target_table))
72 }
73
74 fn derive_column_definitions(
76 select_list: &[SelectItem],
77 result_row: &vibesql_storage::Row,
78 database: &Database,
79 ) -> Result<Vec<ColumnDef>, ExecutorError> {
80 let mut columns = Vec::new();
81
82 for (idx, item) in select_list.iter().enumerate() {
83 match item {
84 SelectItem::Wildcard { .. } => {
85 return Err(ExecutorError::UnsupportedFeature(
86 "SELECT * is not supported in SELECT INTO statements".to_string(),
87 ));
88 }
89 SelectItem::QualifiedWildcard { .. } => {
90 return Err(ExecutorError::UnsupportedFeature(
91 "SELECT table.* is not supported in SELECT INTO statements".to_string(),
92 ));
93 }
94 SelectItem::Expression { expr, alias, .. } => {
95 let column_name = if let Some(alias) = alias {
97 alias.clone()
98 } else {
99 Self::derive_column_name(expr, database)?
100 };
101
102 let data_type = Self::infer_data_type(&result_row.values[idx]);
104
105 columns.push(ColumnDef {
106 name: column_name,
107 data_type,
108 nullable: true, constraints: vec![],
110 default_value: None,
111 comment: None,
112 generated_expr: None,
113 is_exact_integer_type: false, });
115 }
116 }
117 }
118
119 Ok(columns)
120 }
121
122 fn derive_column_name(
124 expr: &vibesql_ast::Expression,
125 _database: &Database,
126 ) -> Result<String, ExecutorError> {
127 match expr {
128 vibesql_ast::Expression::ColumnRef(col_id) => Ok(col_id.column_canonical().to_string()),
129 vibesql_ast::Expression::Literal(_) => Ok("column".to_string()),
130 vibesql_ast::Expression::BinaryOp { .. } => Ok("expr".to_string()),
131 vibesql_ast::Expression::UnaryOp { .. } => Ok("expr".to_string()),
132 vibesql_ast::Expression::Function { name, .. } => Ok(name.to_lowercase()),
133 _ => Ok("column".to_string()),
134 }
135 }
136
137 fn infer_data_type(value: &vibesql_types::SqlValue) -> DataType {
139 match value {
140 vibesql_types::SqlValue::Null => DataType::Varchar { max_length: Some(255) }, vibesql_types::SqlValue::Integer(_) => DataType::Integer,
143 vibesql_types::SqlValue::Bigint(_) => DataType::Bigint,
144 vibesql_types::SqlValue::Unsigned(_) => DataType::Unsigned,
145 vibesql_types::SqlValue::Smallint(_) => DataType::Smallint,
146 vibesql_types::SqlValue::Numeric(_) => DataType::Numeric { precision: 38, scale: 0 },
147 vibesql_types::SqlValue::Float(_) => DataType::Float { precision: 53 },
148 vibesql_types::SqlValue::Real(_) => DataType::Real,
149 vibesql_types::SqlValue::Double(_) => DataType::DoublePrecision,
150 vibesql_types::SqlValue::Varchar(s) | vibesql_types::SqlValue::Character(s) => {
151 DataType::Varchar { max_length: Some(s.len().max(255)) }
152 }
153 vibesql_types::SqlValue::Boolean(_) => DataType::Boolean,
154 vibesql_types::SqlValue::Date(_) => DataType::Date,
155 vibesql_types::SqlValue::Time(_) => DataType::Time { with_timezone: false },
156 vibesql_types::SqlValue::Timestamp(_) => DataType::Timestamp { with_timezone: false },
157 vibesql_types::SqlValue::Interval(_) => DataType::Interval {
158 start_field: vibesql_types::IntervalField::Year,
159 end_field: Some(vibesql_types::IntervalField::Month),
160 },
161 vibesql_types::SqlValue::Vector(v) => DataType::Vector { dimensions: v.len() as u32 },
162 vibesql_types::SqlValue::Blob(_) => DataType::BinaryLargeObject,
163 }
164 }
165}