1use crate::sql::parser::ast::{SqlExpression, WhereClause};
5use std::fmt;
6use std::time::{Duration, Instant};
7
8#[derive(Debug, Clone)]
10pub struct ExecutionStep {
11 pub step_type: StepType,
12 pub description: String,
13 pub details: Vec<String>,
14 pub rows_in: Option<usize>,
15 pub rows_out: Option<usize>,
16 pub duration: Option<Duration>,
17 pub children: Vec<ExecutionStep>,
18}
19
20#[derive(Debug, Clone)]
22pub enum StepType {
23 Parse,
24 LoadData,
25 TableScan,
26 Filter,
27 Sort,
28 GroupBy,
29 Having,
30 Select,
31 Limit,
32 Output,
33 Join,
34 WindowFunction,
35 Expression,
36 CTE,
37 Subquery,
38 Aggregate,
39 Distinct,
40 SetOperation,
41}
42
43impl fmt::Display for StepType {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 StepType::Parse => write!(f, "PARSE"),
47 StepType::LoadData => write!(f, "LOAD_DATA"),
48 StepType::TableScan => write!(f, "TABLE_SCAN"),
49 StepType::Filter => write!(f, "FILTER"),
50 StepType::Sort => write!(f, "SORT"),
51 StepType::GroupBy => write!(f, "GROUP_BY"),
52 StepType::Having => write!(f, "HAVING"),
53 StepType::Select => write!(f, "SELECT"),
54 StepType::Limit => write!(f, "LIMIT"),
55 StepType::Output => write!(f, "OUTPUT"),
56 StepType::Join => write!(f, "JOIN"),
57 StepType::WindowFunction => write!(f, "WINDOW"),
58 StepType::Expression => write!(f, "EXPR"),
59 StepType::CTE => write!(f, "CTE"),
60 StepType::Subquery => write!(f, "SUBQUERY"),
61 StepType::Aggregate => write!(f, "AGGREGATE"),
62 StepType::Distinct => write!(f, "DISTINCT"),
63 StepType::SetOperation => write!(f, "SET_OP"),
64 }
65 }
66}
67
68pub struct ExecutionPlanBuilder {
70 steps: Vec<ExecutionStep>,
71 current_step: Option<ExecutionStep>,
72 start_time: Option<Instant>,
73}
74
75impl ExecutionPlanBuilder {
76 pub fn new() -> Self {
77 Self {
78 steps: Vec::new(),
79 current_step: None,
80 start_time: None,
81 }
82 }
83
84 pub fn begin_step(&mut self, step_type: StepType, description: String) {
86 if let Some(current) = self.current_step.take() {
87 self.steps.push(current);
88 }
89
90 self.current_step = Some(ExecutionStep {
91 step_type,
92 description,
93 details: Vec::new(),
94 rows_in: None,
95 rows_out: None,
96 duration: None,
97 children: Vec::new(),
98 });
99 self.start_time = Some(Instant::now());
100 }
101
102 pub fn add_detail(&mut self, detail: String) {
104 if let Some(ref mut step) = self.current_step {
105 step.details.push(detail);
106 }
107 }
108
109 pub fn set_rows_in(&mut self, count: usize) {
111 if let Some(ref mut step) = self.current_step {
112 step.rows_in = Some(count);
113 }
114 }
115
116 pub fn set_rows_out(&mut self, count: usize) {
118 if let Some(ref mut step) = self.current_step {
119 step.rows_out = Some(count);
120 }
121 }
122
123 pub fn end_step(&mut self) {
125 if let Some(ref mut step) = self.current_step {
126 if let Some(start) = self.start_time {
127 step.duration = Some(start.elapsed());
128 }
129 }
130
131 if let Some(step) = self.current_step.take() {
132 self.steps.push(step);
133 }
134 self.start_time = None;
135 }
136
137 pub fn add_child_step(&mut self, child: ExecutionStep) {
139 if let Some(ref mut step) = self.current_step {
140 step.children.push(child);
141 }
142 }
143
144 pub fn build(mut self) -> ExecutionPlan {
146 if let Some(current) = self.current_step.take() {
147 self.steps.push(current);
148 }
149
150 let total_duration = self.steps.iter().filter_map(|s| s.duration).sum();
151
152 ExecutionPlan {
153 steps: self.steps,
154 total_duration,
155 }
156 }
157}
158
159pub struct ExecutionPlan {
161 pub steps: Vec<ExecutionStep>,
162 pub total_duration: Duration,
163}
164
165impl ExecutionPlan {
166 pub fn format_tree(&self) -> String {
168 let mut output = String::new();
169 output.push_str("\n");
170 output
171 .push_str("╔══════════════════════════════════════════════════════════════════════╗\n");
172 output
173 .push_str("║ EXECUTION PLAN ║\n");
174 output.push_str(
175 "╚══════════════════════════════════════════════════════════════════════╝\n\n",
176 );
177
178 for (i, step) in self.steps.iter().enumerate() {
179 self.format_step(&mut output, step, 0, i == self.steps.len() - 1);
180 }
181
182 output.push_str("\n");
183 output.push_str(&format!(
184 "Total Execution Time: {:.3}ms\n",
185 self.total_duration.as_secs_f64() * 1000.0
186 ));
187
188 output
189 }
190
191 fn format_step(&self, output: &mut String, step: &ExecutionStep, indent: usize, is_last: bool) {
192 let prefix = if indent == 0 {
193 if is_last {
194 "└─".to_string()
195 } else {
196 "├─".to_string()
197 }
198 } else {
199 format!(
200 "{}{}",
201 " ".repeat(indent),
202 if is_last { "└─" } else { "├─" }
203 )
204 };
205
206 let time_str = step
208 .duration
209 .map(|d| format!(" [{:.3}ms]", d.as_secs_f64() * 1000.0))
210 .unwrap_or_default();
211
212 let rows_str = match (step.rows_in, step.rows_out) {
213 (Some(i), Some(o)) if i != o => format!(" (rows: {} → {})", i, o),
214 (_, Some(o)) => format!(" (rows: {})", o),
215 _ => String::new(),
216 };
217
218 output.push_str(&format!(
219 "{} {} {}{}{}\n",
220 prefix, step.step_type, step.description, rows_str, time_str
221 ));
222
223 let detail_indent = if indent == 0 {
225 " ".to_string()
226 } else {
227 " ".repeat(indent + 1)
228 };
229 for detail in &step.details {
230 output.push_str(&format!("{} • {}\n", detail_indent, detail));
231 }
232
233 for (i, child) in step.children.iter().enumerate() {
235 self.format_step(output, child, indent + 1, i == step.children.len() - 1);
236 }
237 }
238
239 pub fn format_table(&self) -> String {
241 let mut output = String::new();
242 output.push_str("\n");
243 output.push_str(
244 "┌────────────────┬──────────────────────────────┬──────────┬──────────┬──────────┐\n",
245 );
246 output.push_str(
247 "│ Step │ Description │ Rows In │ Rows Out │ Time(ms) │\n",
248 );
249 output.push_str(
250 "├────────────────┼──────────────────────────────┼──────────┼──────────┼──────────┤\n",
251 );
252
253 for step in &self.steps {
254 self.format_step_table(&mut output, step, 0);
255 }
256
257 output.push_str(
258 "└────────────────┴──────────────────────────────┴──────────┴──────────┴──────────┘\n",
259 );
260 output.push_str(&format!(
261 "\nTotal Time: {:.3}ms\n",
262 self.total_duration.as_secs_f64() * 1000.0
263 ));
264
265 output
266 }
267
268 fn format_step_table(&self, output: &mut String, step: &ExecutionStep, indent: usize) {
269 let step_name = format!("{}{}", " ".repeat(indent), step.step_type);
270 let desc = if step.description.len() > 28 {
271 format!("{}...", &step.description[..25])
272 } else {
273 step.description.clone()
274 };
275
276 let rows_in = step
277 .rows_in
278 .map(|r| r.to_string())
279 .unwrap_or_else(|| "-".to_string());
280
281 let rows_out = step
282 .rows_out
283 .map(|r| r.to_string())
284 .unwrap_or_else(|| "-".to_string());
285
286 let time = step
287 .duration
288 .map(|d| format!("{:.3}", d.as_secs_f64() * 1000.0))
289 .unwrap_or_else(|| "-".to_string());
290
291 output.push_str(&format!(
292 "│ {:<14} │ {:<28} │ {:>8} │ {:>8} │ {:>8} │\n",
293 step_name, desc, rows_in, rows_out, time
294 ));
295
296 for child in &step.children {
297 self.format_step_table(output, child, indent + 1);
298 }
299 }
300
301 pub fn get_insights(&self) -> Vec<String> {
303 let mut insights = Vec::new();
304
305 let mut steps_with_time: Vec<_> = self
307 .steps
308 .iter()
309 .filter_map(|s| s.duration.map(|d| (s, d)))
310 .collect();
311 steps_with_time.sort_by_key(|(_, d)| std::cmp::Reverse(*d));
312
313 if let Some((slowest, duration)) = steps_with_time.first() {
314 let percentage = (duration.as_secs_f64() / self.total_duration.as_secs_f64()) * 100.0;
315 if percentage > 50.0 {
316 insights.push(format!(
317 "⚠️ {} step took {:.1}% of total execution time ({:.3}ms)",
318 slowest.step_type,
319 percentage,
320 duration.as_secs_f64() * 1000.0
321 ));
322 }
323 }
324
325 for step in &self.steps {
327 if matches!(step.step_type, StepType::Filter) {
328 if let (Some(rows_in), Some(rows_out)) = (step.rows_in, step.rows_out) {
329 if rows_in > 0 {
330 let selectivity = (rows_out as f64 / rows_in as f64) * 100.0;
331 if selectivity < 10.0 {
332 insights.push(format!(
333 "✓ Highly selective filter: {:.1}% of rows passed ({}→{})",
334 selectivity, rows_in, rows_out
335 ));
336 } else if selectivity > 90.0 {
337 insights.push(format!(
338 "⚠️ Low selectivity filter: {:.1}% of rows passed ({}→{})",
339 selectivity, rows_in, rows_out
340 ));
341 }
342 }
343 }
344 }
345 }
346
347 for step in &self.steps {
349 if matches!(step.step_type, StepType::Sort) {
350 if let Some(rows) = step.rows_in {
351 if rows > 10000 {
352 insights.push(format!("⚠️ Sorting large dataset: {} rows", rows));
353 }
354 }
355 }
356 }
357
358 insights
359 }
360}
361
362pub fn analyze_where_clause(where_clause: &WhereClause) -> Vec<String> {
364 let mut details = Vec::new();
365
366 let condition_count = where_clause.conditions.len();
368 details.push(format!("Conditions: {}", condition_count));
369
370 for (i, condition) in where_clause.conditions.iter().enumerate() {
372 let expr_detail = analyze_expression(&condition.expr);
373 details.push(format!(" Condition {}: {}", i + 1, expr_detail));
374
375 if let Some(connector) = &condition.connector {
376 details.push(format!(" Connector: {:?}", connector));
377 }
378 }
379
380 details
381}
382
383pub fn analyze_expression(expr: &SqlExpression) -> String {
385 match expr {
386 SqlExpression::Column(name) => format!("Column({})", name),
387 SqlExpression::BinaryOp { left, op, right } => {
388 format!(
389 "BinaryOp({} {} {})",
390 analyze_expression(left),
391 op,
392 analyze_expression(right)
393 )
394 }
395 SqlExpression::FunctionCall { name, args, .. } => {
396 format!("Function({}, {} args)", name, args.len())
397 }
398 SqlExpression::Between { expr, .. } => {
399 format!("Between({})", analyze_expression(expr))
400 }
401 SqlExpression::InList { expr, values } => {
402 format!(
403 "InList({}, {} values)",
404 analyze_expression(expr),
405 values.len()
406 )
407 }
408 SqlExpression::NotInList { expr, values } => {
409 format!(
410 "NotInList({}, {} values)",
411 analyze_expression(expr),
412 values.len()
413 )
414 }
415 _ => format!("{:?}", expr),
416 }
417}