use std::sync::Arc;
use crate::core::{Error, Result, Row, Value};
use crate::parser::ast::*;
use crate::storage::traits::{Engine, QueryResult};
use super::context::ExecutionContext;
use super::result::ExecutorMemoryResult;
use super::Executor;
impl Executor {
pub(crate) fn execute_show_tables(
&self,
_stmt: &ShowTablesStatement,
_ctx: &ExecutionContext,
) -> Result<Box<dyn QueryResult>> {
let tx = self.engine.begin_transaction()?;
let tables = tx.list_tables()?;
let columns = vec!["table_name".to_string()];
let rows: Vec<Row> = tables
.into_iter()
.map(|name| Row::from_values(vec![Value::Text(Arc::from(name.as_str()))]))
.collect();
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
pub(crate) fn execute_show_views(
&self,
_stmt: &ShowViewsStatement,
_ctx: &ExecutionContext,
) -> Result<Box<dyn QueryResult>> {
let views = self.engine.list_views()?;
let columns = vec!["view_name".to_string()];
let rows: Vec<Row> = views
.into_iter()
.map(|name| Row::from_values(vec![Value::Text(Arc::from(name.as_str()))]))
.collect();
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
pub(crate) fn execute_show_create_table(
&self,
stmt: &ShowCreateTableStatement,
_ctx: &ExecutionContext,
) -> Result<Box<dyn QueryResult>> {
let table_name = &stmt.table_name.value;
let tx = self.engine.begin_transaction()?;
let table = tx.get_table(table_name)?;
let schema = table.schema();
let mut unique_columns: std::collections::HashSet<String> =
std::collections::HashSet::new();
if let Ok(indexes) = self.engine.list_table_indexes(table_name) {
for index_name in indexes.keys() {
if let Some(index) = table.get_index(index_name) {
let col_names = index.column_names();
if index.is_unique() && col_names.len() == 1 {
unique_columns.insert(col_names[0].to_lowercase());
}
}
}
}
let mut create_sql = format!("CREATE TABLE {} (", table_name);
let col_defs: Vec<String> = schema
.columns
.iter()
.map(|col| {
let mut def = format!("{} {:?}", col.name, col.data_type);
if col.primary_key {
def.push_str(" PRIMARY KEY");
if col.auto_increment {
def.push_str(" AUTO_INCREMENT");
}
} else {
if unique_columns.contains(&col.name.to_lowercase()) {
def.push_str(" UNIQUE");
}
if !col.nullable {
def.push_str(" NOT NULL");
}
}
if let Some(default_expr) = &col.default_expr {
def.push_str(&format!(" DEFAULT {}", default_expr));
}
if let Some(check) = &col.check_expr {
def.push_str(&format!(" CHECK ({})", check));
}
def
})
.collect();
create_sql.push_str(&col_defs.join(", "));
create_sql.push(')');
let columns = vec!["Table".to_string(), "Create Table".to_string()];
let rows = vec![Row::from_values(vec![
Value::Text(Arc::from(table_name.as_str())),
Value::Text(Arc::from(create_sql.as_str())),
])];
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
pub(crate) fn execute_show_create_view(
&self,
stmt: &ShowCreateViewStatement,
_ctx: &ExecutionContext,
) -> Result<Box<dyn QueryResult>> {
let view_name = &stmt.view_name.value;
let view_def = self
.engine
.get_view(view_name)?
.ok_or_else(|| Error::ViewNotFound(view_name.to_string()))?;
let create_sql = format!(
"CREATE VIEW {} AS {}",
view_def.original_name, view_def.query
);
let columns = vec!["View".to_string(), "Create View".to_string()];
let rows = vec![Row::from_values(vec![
Value::Text(Arc::from(view_def.original_name.as_str())),
Value::Text(Arc::from(create_sql.as_str())),
])];
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
pub(crate) fn execute_show_indexes(
&self,
stmt: &ShowIndexesStatement,
_ctx: &ExecutionContext,
) -> Result<Box<dyn QueryResult>> {
let table_name = &stmt.table_name.value;
let tx = self.engine.begin_transaction()?;
let table = tx.get_table(table_name)?;
let index_names = {
let indexes = self.engine.list_table_indexes(table_name)?;
indexes.keys().cloned().collect::<Vec<_>>()
};
let columns = vec![
"table_name".to_string(),
"index_name".to_string(),
"column_name".to_string(),
"index_type".to_string(),
"is_unique".to_string(),
];
let mut rows: Vec<Row> = Vec::new();
for index_name in index_names {
if let Some(index) = table.get_index(&index_name) {
let column_names = index.column_names();
let column_name = if column_names.len() > 1 {
format!("({})", column_names.join(", "))
} else {
column_names
.first()
.map(|s| s.to_string())
.unwrap_or_default()
};
let is_unique = index.is_unique();
let index_type = index.index_type().as_str().to_uppercase();
rows.push(Row::from_values(vec![
Value::Text(Arc::from(table_name.as_str())),
Value::Text(Arc::from(index_name.as_str())),
Value::Text(Arc::from(column_name.as_str())),
Value::Text(Arc::from(index_type)),
Value::Boolean(is_unique),
]));
}
}
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
pub(crate) fn execute_describe(
&self,
stmt: &DescribeStatement,
_ctx: &ExecutionContext,
) -> Result<Box<dyn QueryResult>> {
let table_name = &stmt.table_name.value;
let tx = self.engine.begin_transaction()?;
let table = tx.get_table(table_name)?;
let schema = table.schema();
let columns = vec![
"Field".to_string(),
"Type".to_string(),
"Null".to_string(),
"Key".to_string(),
"Default".to_string(),
"Extra".to_string(),
];
let mut rows: Vec<Row> = Vec::new();
for col in &schema.columns {
let type_str = format!("{:?}", col.data_type);
let null_str = if col.nullable { "YES" } else { "NO" };
let key_str = if col.primary_key { "PRI" } else { "" };
let default_str = col
.default_expr
.as_ref()
.map(|v| v.to_string())
.unwrap_or_default();
let extra_str =
if col.primary_key && col.data_type == crate::core::types::DataType::Integer {
"auto_increment"
} else {
""
};
rows.push(Row::from_values(vec![
Value::Text(Arc::from(col.name.as_str())),
Value::Text(Arc::from(type_str.as_str())),
Value::Text(Arc::from(null_str)),
Value::Text(Arc::from(key_str)),
Value::Text(Arc::from(default_str.as_str())),
Value::Text(Arc::from(extra_str)),
]));
}
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
}