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