1pub mod aggregate_walk;
14pub mod catalog;
15pub mod coerce;
16pub mod ddl_ast;
17pub mod dsl_bind;
18pub mod engine_rules;
19pub mod error;
20pub mod fts_types;
21pub mod functions;
22pub mod optimizer;
23pub mod params;
24pub mod parser;
25pub mod placeholder_types;
26pub mod planner;
27pub mod reserved;
28pub mod resolver;
29pub mod temporal;
30pub mod types;
31pub mod types_array;
32pub mod types_expr;
33pub mod visitor;
34
35pub use temporal::{TemporalScope, ValidTime};
36pub use visitor::PlanVisitor;
37pub use visitor::dispatch;
38pub use visitor::plan_visitor::args::*;
39
40pub use catalog::{SqlCatalog, SqlCatalogError};
41pub use error::{Result, SqlError};
42pub use params::ParamValue;
43pub use placeholder_types::{InferredParamType, infer_placeholder_types};
44pub use planner::returning::resolve_returning_items;
45pub use types::*;
46
47pub fn parse_expr_string(expr_text: &str) -> Result<SqlExpr> {
52 use sqlparser::dialect::GenericDialect;
53 use sqlparser::parser::Parser;
54
55 let dialect = GenericDialect {};
56 let ast_expr = Parser::new(&dialect)
57 .try_with_sql(expr_text)
58 .map_err(|e| SqlError::Parse {
59 detail: e.to_string(),
60 })?
61 .parse_expr()
62 .map_err(|e| SqlError::Parse {
63 detail: e.to_string(),
64 })?;
65
66 resolver::expr::convert_expr(&ast_expr, &resolver::ColumnScope::Unchecked)
67}
68
69use functions::registry::FunctionRegistry;
70use parser::array_stmt::{ArrayStatement, try_parse_array_statement};
71use parser::preprocess;
72use parser::statement::{StatementKind, classify, parse_sql};
73
74pub fn plan_sql(sql: &str, catalog: &dyn SqlCatalog) -> Result<Vec<SqlPlan>> {
79 if let Some(stmt) = try_parse_array_statement(sql)? {
82 return plan_array_statement(stmt, catalog);
83 }
84 let preprocessed = preprocess::preprocess(sql)?;
85 let effective_sql = preprocessed.as_ref().map_or(sql, |p| p.sql.as_str());
86 let is_upsert = preprocessed.as_ref().is_some_and(|p| p.is_upsert);
87 let temporal = preprocessed
88 .as_ref()
89 .map(|p| p.temporal)
90 .unwrap_or_default();
91
92 let statements = parse_sql(effective_sql)?;
93 plan_statements(&statements, is_upsert, temporal, catalog)
94}
95
96pub fn plan_sql_with_params(
103 sql: &str,
104 params: &[ParamValue],
105 catalog: &dyn SqlCatalog,
106) -> Result<Vec<SqlPlan>> {
107 if let Some(stmt) = try_parse_array_statement(sql)? {
111 let _ = params; return plan_array_statement(stmt, catalog);
113 }
114 let preprocessed = preprocess::preprocess(sql)?;
115 let effective_sql = preprocessed.as_ref().map_or(sql, |p| p.sql.as_str());
116 let is_upsert = preprocessed.as_ref().is_some_and(|p| p.is_upsert);
117 let temporal = preprocessed
118 .as_ref()
119 .map(|p| p.temporal)
120 .unwrap_or_default();
121
122 let mut statements = parse_sql(effective_sql)?;
123 for stmt in &mut statements {
124 params::bind_params(stmt, params);
125 }
126 plan_statements(&statements, is_upsert, temporal, catalog)
127}
128
129fn plan_statements(
131 statements: &[sqlparser::ast::Statement],
132 is_upsert: bool,
133 temporal: TemporalScope,
134 catalog: &dyn SqlCatalog,
135) -> Result<Vec<SqlPlan>> {
136 let functions = FunctionRegistry::new();
137 let mut plans = Vec::new();
138
139 for stmt in statements {
140 match classify(stmt) {
141 StatementKind::Select(query) => {
142 let plan =
143 planner::select::plan_statement_query(query, catalog, &functions, temporal)?;
144 let plan = optimizer::optimize(plan, catalog)?;
145 plans.push(plan);
146 }
147 StatementKind::Insert(ins) => {
148 let mut dml_plans = if is_upsert {
149 planner::dml::plan_upsert(ins, catalog)?
150 } else {
151 planner::dml::plan_insert(ins, catalog, &functions, temporal)?
152 };
153 plans.append(&mut dml_plans);
154 }
155 StatementKind::Update(stmt) => {
156 let mut update_plans = planner::dml::plan_update(stmt, catalog)?;
157 plans.append(&mut update_plans);
158 }
159 StatementKind::Delete(stmt) => {
160 let mut delete_plans = planner::dml::plan_delete(stmt, catalog)?;
161 plans.append(&mut delete_plans);
162 }
163 StatementKind::Truncate(stmt) => {
164 let mut trunc_plans = planner::dml::plan_truncate_stmt(stmt, catalog)?;
165 plans.append(&mut trunc_plans);
166 }
167 StatementKind::Merge(stmt) => {
168 let mut merge_plans = planner::merge::plan_merge(stmt, catalog)?;
169 plans.append(&mut merge_plans);
170 }
171 StatementKind::CreateIndex(ci) => {
172 plans.push(planner::index_ddl::plan_create_index(ci)?);
173 }
174 StatementKind::DropIndex(stmt) => {
175 plans.push(planner::index_ddl::plan_drop_index(stmt)?);
176 }
177 StatementKind::Other => {
178 return Err(SqlError::Unsupported {
179 detail: format!("statement type: {stmt}"),
180 });
181 }
182 }
183 }
184
185 for plan in &plans {
186 planner::search_scope::refuse_row_scoped_search_functions(plan, &functions)?;
187 }
188 Ok(plans)
189}
190
191fn plan_array_statement(stmt: ArrayStatement, catalog: &dyn SqlCatalog) -> Result<Vec<SqlPlan>> {
193 match stmt {
194 ArrayStatement::Create(c) => Ok(vec![planner::array_ddl::plan_create_array(&c)?]),
195 ArrayStatement::Drop(d) => Ok(vec![planner::array_ddl::plan_drop_array(&d)?]),
196 ArrayStatement::Insert(i) => planner::array_dml::plan_insert_array(&i, catalog),
197 ArrayStatement::Delete(d) => planner::array_dml::plan_delete_array(&d, catalog),
198 ArrayStatement::Alter(a) => Ok(vec![planner::array_ddl::plan_alter_array(&a)?]),
199 }
200}