sql_cli/query_plan/
mod.rs

1// Main query plan module
2mod query_plan;
3
4// Sub-modules
5pub mod correlated_subquery_analyzer;
6pub mod cte_hoister;
7pub mod dependency_analyzer;
8pub mod expression_lifter;
9pub mod group_by_alias_expander;
10pub mod having_alias_transformer;
11pub mod in_operator_lifter;
12pub mod into_clause_remover;
13pub mod order_by_alias_transformer;
14pub mod pipeline;
15pub mod qualify_to_where_transformer;
16pub mod transformer_adapters;
17pub mod where_alias_expander;
18
19// Re-export main types
20pub use query_plan::{
21    DependencyGraph, PlanMetadata, QueryAnalyzer, QueryPlan, WorkUnit, WorkUnitExpression,
22    WorkUnitType,
23};
24
25// Re-export commonly used items
26pub use correlated_subquery_analyzer::{
27    CorrelatedSubqueryAnalyzer, CorrelationAnalysis, SubqueryInfo, SubqueryLocation, SubqueryType,
28};
29pub use cte_hoister::CTEHoister;
30pub use dependency_analyzer::{ScriptDependencyGraph, StatementNode};
31pub use expression_lifter::{ExpressionLifter, LiftableExpression};
32pub use group_by_alias_expander::GroupByAliasExpander;
33pub use having_alias_transformer::HavingAliasTransformer;
34pub use in_operator_lifter::{InOperatorLifter, LiftedInExpression};
35pub use into_clause_remover::IntoClauseRemover;
36pub use order_by_alias_transformer::OrderByAliasTransformer;
37pub use qualify_to_where_transformer::QualifyToWhereTransformer;
38pub use where_alias_expander::WhereAliasExpander;
39
40// Re-export pipeline types
41pub use pipeline::{
42    ASTTransformer, PipelineBuilder, PipelineConfig, PreprocessingPipeline, PreprocessingStats,
43    TransformStats,
44};
45
46// Re-export transformer adapters
47pub use transformer_adapters::{
48    CTEHoisterTransformer, ExpressionLifterTransformer, InOperatorLifterTransformer,
49};
50
51/// Configuration for selective transformer enabling/disabling
52#[derive(Clone, Debug)]
53pub struct TransformerConfig {
54    pub enable_expression_lifter: bool,
55    pub enable_where_expansion: bool,
56    pub enable_group_by_expansion: bool,
57    pub enable_having_expansion: bool,
58    pub enable_order_by_expansion: bool,
59    pub enable_qualify_to_where: bool,
60    pub enable_cte_hoister: bool,
61    pub enable_in_lifter: bool,
62}
63
64impl Default for TransformerConfig {
65    fn default() -> Self {
66        // By default, all transformers are enabled for compatibility
67        Self::all_enabled()
68    }
69}
70
71impl TransformerConfig {
72    /// Create a config with all transformers enabled
73    pub fn all_enabled() -> Self {
74        Self {
75            enable_expression_lifter: true,
76            enable_where_expansion: true,
77            enable_group_by_expansion: true,
78            enable_having_expansion: true,
79            enable_order_by_expansion: true,
80            enable_qualify_to_where: true,
81            enable_cte_hoister: true,
82            enable_in_lifter: true,
83        }
84    }
85}
86
87/// Create a preprocessing pipeline with configurable transformers
88///
89/// # Arguments
90/// * `verbose` - Whether to enable verbose logging
91/// * `transformer_config` - Configuration for which transformers to enable
92///
93/// # Example
94/// ```ignore
95/// let config = TransformerConfig::all_enabled();
96/// let mut pipeline = create_pipeline_with_config(false, config);
97/// let transformed = pipeline.process(statement)?;
98/// ```
99pub fn create_pipeline_with_config(
100    verbose: bool,
101    show_sql_transformations: bool,
102    transformer_config: TransformerConfig,
103) -> PreprocessingPipeline {
104    let config = if verbose || show_sql_transformations {
105        PipelineConfig {
106            enabled: true,
107            verbose_logging: verbose,
108            collect_stats: true,
109            debug_ast_changes: false,
110            show_sql_transformations,
111        }
112    } else {
113        PipelineConfig::default()
114    };
115
116    let mut builder = PipelineBuilder::with_config(config);
117
118    // Add transformers in the correct order based on configuration
119    // Order matters! ExpressionLifter must run before CTEHoister
120    // WhereAliasExpander and GroupByAliasExpander run early to expand aliases
121    // HavingAliasTransformer runs after GROUP BY to ensure proper aggregate aliases
122
123    if transformer_config.enable_expression_lifter {
124        builder = builder.with_transformer(Box::new(ExpressionLifterTransformer::new()));
125    }
126
127    // QualifyToWhereTransformer must run after ExpressionLifter
128    // so that window functions are already lifted to CTEs
129    if transformer_config.enable_qualify_to_where {
130        builder = builder.with_transformer(Box::new(QualifyToWhereTransformer::new()));
131    }
132
133    if transformer_config.enable_where_expansion {
134        builder = builder.with_transformer(Box::new(WhereAliasExpander::new()));
135    }
136
137    if transformer_config.enable_group_by_expansion {
138        builder = builder.with_transformer(Box::new(GroupByAliasExpander::new()));
139    }
140
141    if transformer_config.enable_having_expansion {
142        builder = builder.with_transformer(Box::new(HavingAliasTransformer::new()));
143    }
144
145    if transformer_config.enable_order_by_expansion {
146        builder = builder.with_transformer(Box::new(OrderByAliasTransformer::new()));
147    }
148
149    if transformer_config.enable_cte_hoister {
150        builder = builder.with_transformer(Box::new(CTEHoisterTransformer::new()));
151    }
152
153    if transformer_config.enable_in_lifter {
154        builder = builder.with_transformer(Box::new(InOperatorLifterTransformer::new()));
155    }
156
157    builder.build()
158}
159
160/// Create a standard preprocessing pipeline with all default transformers
161///
162/// The transformers are applied in this order:
163/// 1. ExpressionLifter - Lifts column alias dependencies and window functions
164/// 2. WhereAliasExpander - Expands SELECT aliases in WHERE clauses
165/// 3. GroupByAliasExpander - Expands SELECT aliases in GROUP BY clauses
166/// 4. HavingAliasTransformer - Adds aliases to aggregates and rewrites HAVING
167/// 5. CTEHoister - Hoists nested CTEs to top level
168/// 6. InOperatorLifter - Optimizes large IN expressions
169///
170/// # Arguments
171/// * `verbose` - Whether to enable verbose logging
172///
173/// # Example
174/// ```ignore
175/// let mut pipeline = create_standard_pipeline(false);
176/// let transformed = pipeline.process(statement)?;
177/// ```
178pub fn create_standard_pipeline(verbose: bool) -> PreprocessingPipeline {
179    let config = if verbose {
180        PipelineConfig {
181            enabled: true,
182            verbose_logging: true,
183            collect_stats: true,
184            debug_ast_changes: false,
185            show_sql_transformations: false,
186        }
187    } else {
188        PipelineConfig::default()
189    };
190
191    let mut builder = PipelineBuilder::with_config(config);
192
193    // Add transformers in the correct order
194    // Order matters! ExpressionLifter must run before CTEHoister
195    // WhereAliasExpander and GroupByAliasExpander run early to expand aliases
196    // HavingAliasTransformer and OrderByAliasTransformer run after GROUP BY
197    builder = builder
198        .with_transformer(Box::new(ExpressionLifterTransformer::new()))
199        .with_transformer(Box::new(WhereAliasExpander::new()))
200        .with_transformer(Box::new(GroupByAliasExpander::new()))
201        .with_transformer(Box::new(HavingAliasTransformer::new()))
202        .with_transformer(Box::new(OrderByAliasTransformer::new()))
203        .with_transformer(Box::new(CTEHoisterTransformer::new()))
204        .with_transformer(Box::new(InOperatorLifterTransformer::new()));
205
206    builder.build()
207}