#![forbid(unsafe_code)]
#![warn(missing_docs)]
pub mod optimizer;
pub use optimizer::{
ConstantFolding, JoinAlgoHint, JoinAlgorithmPass, LimitPushThrough, OptPass, Optimizer,
PredicatePushdown, ProjectionPruning,
};
pub mod agg;
pub use agg::{extract_aggregates, is_aggregate_expr, AggFunc, AggregateExpr};
pub mod dml;
pub use dml::{plan_dml, DmlPlan};
pub mod validate;
pub use validate::{SchemaValidator, ValidationError};
pub mod cost;
pub use cost::{CostEstimate, CostModel, TableStats};
pub mod builder;
mod columns;
mod setops;
mod window;
pub use builder::QueryBuilder;
pub mod plan;
pub use plan::{JoinType, LogicalPlan, SetOpType, SortExpr, WindowFunctionDef};
pub mod planner;
pub use planner::{plan_query, plan_statement};
pub mod explain;
pub use explain::explain;
pub mod analysis;
pub use analysis::{count_params, extract_columns, extract_tables, is_read_only, normalize};
pub mod cache;
pub use cache::ParseCache;
use oxisql_core::OxiSqlError;
pub use sqlparser::ast::{Expr, JoinConstraint, ObjectName, SelectItem, Statement, TableFactor};
use sqlparser::dialect::Dialect;
pub use sqlparser::dialect::{GenericDialect, MySqlDialect, PostgreSqlDialect, SQLiteDialect};
use sqlparser::parser::Parser;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SqlDialect {
Generic,
Postgres,
MySQL,
SQLite,
}
impl SqlDialect {
pub(crate) fn to_sqlparser(self) -> Box<dyn Dialect> {
match self {
SqlDialect::Generic => Box::new(GenericDialect {}),
SqlDialect::Postgres => Box::new(PostgreSqlDialect {}),
SqlDialect::MySQL => Box::new(MySqlDialect {}),
SqlDialect::SQLite => Box::new(SQLiteDialect {}),
}
}
}
pub fn optimize(plan: LogicalPlan) -> LogicalPlan {
optimizer::optimize(plan)
}
pub fn parse_postgres(sql: &str) -> Result<Vec<Statement>, OxiSqlError> {
parse_with_dialect(sql, SqlDialect::Postgres)
}
pub fn parse_mysql(sql: &str) -> Result<Vec<Statement>, OxiSqlError> {
parse_with_dialect(sql, SqlDialect::MySQL)
}
pub fn parse_sqlite(sql: &str) -> Result<Vec<Statement>, OxiSqlError> {
parse_with_dialect(sql, SqlDialect::SQLite)
}
pub fn parse(sql: &str) -> Result<Vec<Statement>, OxiSqlError> {
let dialect = GenericDialect {};
Parser::parse_sql(&dialect, sql).map_err(|e| OxiSqlError::Parse(e.to_string()))
}
pub fn parse_with_dialect(sql: &str, dialect: SqlDialect) -> Result<Vec<Statement>, OxiSqlError> {
let d = dialect.to_sqlparser();
Parser::parse_sql(d.as_ref(), sql).map_err(|e| OxiSqlError::Parse(e.to_string()))
}
pub fn parse_one(sql: &str) -> Result<Statement, OxiSqlError> {
let mut stmts = parse(sql)?;
if stmts.len() != 1 {
return Err(OxiSqlError::Parse(format!(
"expected exactly 1 statement, got {}",
stmts.len()
)));
}
Ok(stmts.remove(0))
}
pub fn parse_one_with_dialect(sql: &str, dialect: SqlDialect) -> Result<Statement, OxiSqlError> {
let mut stmts = parse_with_dialect(sql, dialect)?;
if stmts.len() != 1 {
return Err(OxiSqlError::Parse(format!(
"expected exactly 1 statement, got {}",
stmts.len()
)));
}
Ok(stmts.remove(0))
}
pub fn format(stmt: &Statement) -> String {
stmt.to_string()
}
#[cfg(test)]
mod tests;