use std::sync::Arc;
use crate::core::{DataType, Error, Result, Row, Value};
use crate::parser::{ast::*, Parser};
use crate::storage::traits::{Engine, QueryResult};
use super::context::ExecutionContext;
use super::result::ExecutorMemoryResult;
use super::Executor;
impl Executor {
pub(crate) fn execute_information_schema_table(
&self,
schema_table: &str,
_stmt: &SelectStatement,
_ctx: &ExecutionContext,
) -> Result<Box<dyn QueryResult>> {
match schema_table {
"tables" => self.build_tables_result(),
"columns" => self.build_columns_result(),
"functions" => self.build_functions_result(),
"views" => self.build_views_result(),
"statistics" => self.build_statistics_result(),
"sequences" => self.build_sequences_result(),
_ => Err(Error::TableNotFoundByName(format!(
"information_schema.{}",
schema_table
))),
}
}
fn build_tables_result(&self) -> Result<Box<dyn QueryResult>> {
let tx = self.engine.begin_transaction()?;
let table_names = tx.list_tables()?;
let view_names = self.engine.list_views()?;
let columns = vec![
"table_catalog".to_string(),
"table_schema".to_string(),
"table_name".to_string(),
"table_type".to_string(),
];
let mut rows: Vec<Row> = Vec::new();
for table_name in table_names {
let (schema_name, actual_table_name) = if let Some(dot_pos) = table_name.find('.') {
let schema = &table_name[..dot_pos];
let name = &table_name[dot_pos + 1..];
(schema.to_string(), name.to_string())
} else {
("public".to_string(), table_name.clone())
};
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")), Value::Text(Arc::from(schema_name)), Value::Text(Arc::from(actual_table_name)),
Value::Text(Arc::from("BASE TABLE")),
]));
}
for view_name in view_names {
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")), Value::Null(crate::core::DataType::Text), Value::Text(Arc::from(view_name.as_str())),
Value::Text(Arc::from("VIEW")),
]));
}
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
fn build_columns_result(&self) -> Result<Box<dyn QueryResult>> {
let tx = self.engine.begin_transaction()?;
let table_names = tx.list_tables()?;
let columns = vec![
"table_catalog".to_string(),
"table_schema".to_string(),
"table_name".to_string(),
"column_name".to_string(),
"ordinal_position".to_string(),
"column_default".to_string(),
"is_nullable".to_string(),
"data_type".to_string(),
"character_maximum_length".to_string(),
"numeric_precision".to_string(),
"numeric_scale".to_string(),
];
let mut rows: Vec<Row> = Vec::new();
for table_name in table_names {
let table = tx.get_table(&table_name)?;
let table_schema = table.schema();
let (schema_name, actual_table_name) = if let Some(dot_pos) = table_name.find('.') {
let schema = &table_name[..dot_pos];
let name = &table_name[dot_pos + 1..];
(schema.to_string(), name.to_string())
} else {
("public".to_string(), table_name.clone())
};
for (pos, col) in table_schema.columns.iter().enumerate() {
let ordinal = (pos + 1) as i64;
let default_value = col.default_expr.as_ref().and_then(|expr| {
let expr_str = expr.to_string();
let trimmed = expr_str.trim();
if trimmed.is_empty() || trimmed == "NULL" {
None
} else {
Some(trimmed.to_string())
}
});
let is_nullable = if col.nullable { "YES" } else { "NO" };
let data_type = format!("{:?}", col.data_type);
let char_max_len = match col.data_type {
crate::core::types::DataType::Text => Some(Value::Integer(65535)), _ => None,
};
let (num_precision, num_scale) = match col.data_type {
crate::core::types::DataType::Integer => {
(Some(Value::Integer(64)), Some(Value::Integer(0)))
}
crate::core::types::DataType::Float => (Some(Value::Integer(53)), None), _ => (None, None),
};
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")), Value::Text(Arc::from(schema_name.as_str())), Value::Text(Arc::from(actual_table_name.as_str())),
Value::Text(Arc::from(col.name.as_str())),
Value::Integer(ordinal),
match default_value {
Some(s) => Value::Text(Arc::from(s.as_str())),
None => Value::Null(DataType::Text),
},
Value::Text(Arc::from(is_nullable)),
Value::Text(Arc::from(data_type.as_str())),
char_max_len.unwrap_or(Value::Null(DataType::Integer)),
num_precision.unwrap_or(Value::Null(DataType::Integer)),
num_scale.unwrap_or(Value::Null(DataType::Integer)),
]));
}
}
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
fn build_functions_result(&self) -> Result<Box<dyn QueryResult>> {
let function_registry = self.function_registry();
let scalar_functions = function_registry.list_scalars();
let aggregate_functions = function_registry.list_aggregates();
let window_functions = function_registry.list_windows();
let columns = vec![
"function_catalog".to_string(),
"function_schema".to_string(),
"function_name".to_string(),
"function_type".to_string(),
"data_type".to_string(),
"is_deterministic".to_string(),
];
let mut rows: Vec<Row> = Vec::new();
fn function_data_type_to_string(dtype: &crate::functions::FunctionDataType) -> String {
match dtype {
crate::functions::FunctionDataType::Any => "ANY".to_string(),
crate::functions::FunctionDataType::Integer => "INTEGER".to_string(),
crate::functions::FunctionDataType::Float => "FLOAT".to_string(),
crate::functions::FunctionDataType::String => "TEXT".to_string(),
crate::functions::FunctionDataType::Boolean => "BOOLEAN".to_string(),
crate::functions::FunctionDataType::Timestamp => "TIMESTAMP".to_string(),
crate::functions::FunctionDataType::Date => "DATE".to_string(),
crate::functions::FunctionDataType::Time => "TIME".to_string(),
crate::functions::FunctionDataType::DateTime => "TIMESTAMP".to_string(),
crate::functions::FunctionDataType::Json => "JSON".to_string(),
crate::functions::FunctionDataType::Unknown => "UNKNOWN".to_string(),
}
}
for func_name in scalar_functions {
if let Some(func_info) = function_registry.get_info(&func_name) {
let return_type_str =
function_data_type_to_string(&func_info.signature.return_type);
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")),
Value::Text(Arc::from("sys")),
Value::Text(Arc::from(func_name.as_str())),
Value::Text(Arc::from("SCALAR")),
Value::Text(Arc::from(return_type_str.as_str())),
Value::Boolean(true), ]));
}
}
for func_name in aggregate_functions {
if let Some(func_info) = function_registry.get_info(&func_name) {
let return_type_str =
function_data_type_to_string(&func_info.signature.return_type);
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")),
Value::Text(Arc::from("sys")),
Value::Text(Arc::from(func_name.as_str())),
Value::Text(Arc::from("AGGREGATE")),
Value::Text(Arc::from(return_type_str.as_str())),
Value::Boolean(true),
]));
}
}
for func_name in window_functions {
if let Some(func_info) = function_registry.get_info(&func_name) {
let return_type_str =
function_data_type_to_string(&func_info.signature.return_type);
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")),
Value::Text(Arc::from("sys")),
Value::Text(Arc::from(func_name.as_str())),
Value::Text(Arc::from("WINDOW")),
Value::Text(Arc::from(return_type_str.as_str())),
Value::Boolean(true),
]));
}
}
let sql = "SELECT schema, name, parameters, return_type FROM _sys_functions ORDER BY name";
let mut parser = Parser::new(sql);
if let Ok(program) = parser.parse_program() {
if let Some(Statement::Select(stmt)) = program.statements.into_iter().next() {
if let Ok(mut result) = self.execute_select(&stmt, &ExecutionContext::default()) {
while result.next() {
let row = result.row();
if let (
Some(schema_val),
Some(Value::Text(name)),
Some(Value::Json(_params)),
Some(Value::Text(return_type_str)),
) = (row.get(0), row.get(1), row.get(2), row.get(3))
{
let function_schema = match schema_val {
Value::Text(s) => s.clone(),
Value::Null(_) => Arc::from("public"),
_ => Arc::from("public"),
};
let data_type = match return_type_str.as_ref() {
"INTEGER" => "INTEGER",
"TEXT" => "TEXT",
"BOOLEAN" => "BOOLEAN",
"FLOAT" => "FLOAT",
"TIMESTAMP" => "TIMESTAMP",
"DATE" => "DATE",
"TIME" => "TIME",
"JSON" => "JSON",
_ => "UNKNOWN",
};
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")),
Value::Text(function_schema),
Value::Text(name.clone()),
Value::Text(Arc::from("SCALAR")),
Value::Text(Arc::from(data_type)),
Value::Boolean(true),
]));
}
}
}
}
}
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
fn build_views_result(&self) -> Result<Box<dyn QueryResult>> {
let view_names = self.engine.list_views()?;
let columns = vec![
"table_catalog".to_string(),
"table_schema".to_string(),
"table_name".to_string(),
"view_definition".to_string(),
];
let mut rows: Vec<Row> = Vec::new();
for view_name in view_names {
if let Ok(Some(view_def)) = self.engine.get_view(&view_name) {
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")),
Value::Null(DataType::Text),
Value::Text(Arc::from(view_def.original_name.as_str())),
Value::Text(Arc::from(view_def.query.as_str())),
]));
}
}
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
fn build_statistics_result(&self) -> Result<Box<dyn QueryResult>> {
let tx = self.engine.begin_transaction()?;
let table_names = tx.list_tables()?;
let columns = vec![
"table_catalog".to_string(),
"table_schema".to_string(),
"table_name".to_string(),
"index_name".to_string(),
"seq_in_index".to_string(),
"column_name".to_string(),
"non_unique".to_string(),
"index_type".to_string(),
];
let mut rows: Vec<Row> = Vec::new();
for table_name in table_names {
let table = tx.get_table(&table_name)?;
let (schema_name, actual_table_name) = if let Some(dot_pos) = table_name.find('.') {
let schema = &table_name[..dot_pos];
let name = &table_name[dot_pos + 1..];
(schema.to_string(), name.to_string())
} else {
("public".to_string(), table_name.clone())
};
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 column_names = index.column_names();
let is_unique = index.is_unique();
let index_type = index.index_type().as_str().to_uppercase();
for (seq, col_name) in column_names.iter().enumerate() {
rows.push(Row::from_values(vec![
Value::Text(Arc::from("def")),
Value::Text(Arc::from(schema_name.as_str())),
Value::Text(Arc::from(actual_table_name.as_str())),
Value::Text(Arc::from(index_name.as_str())),
Value::Integer((seq + 1) as i64),
Value::Text(Arc::from(col_name.as_str())),
Value::Boolean(!is_unique),
Value::Text(Arc::from(index_type.as_str())),
]));
}
}
}
}
}
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
fn build_sequences_result(&self) -> Result<Box<dyn QueryResult>> {
let columns = vec![
"sequence_catalog".to_string(),
"sequence_schema".to_string(),
"sequence_name".to_string(),
"data_type".to_string(),
"numeric_precision".to_string(),
"numeric_scale".to_string(),
"start_value".to_string(),
"minimum_value".to_string(),
"maximum_value".to_string(),
"increment".to_string(),
"cycle_option".to_string(),
];
let rows: Vec<Row> = Vec::new();
Ok(Box::new(ExecutorMemoryResult::new(columns, rows)))
}
}