Skip to content

Commit e0454a4

Browse files
TimelordUKclaude
andcommitted
feat: Add unified execution module foundation (Phase 0)
Implement the foundation for unifying script mode and single query mode execution paths. This Phase 0 work creates core infrastructure without modifying existing execution paths, ensuring zero regression risk. ## New Modules Created src/execution/ module with three core components: 1. **ExecutionContext** (context.rs) - Manages execution state (temp tables, variables, source table) - Provides table resolution (base, temp, DUAL) - Ensures proper context isolation between executions 2. **ExecutionConfig** (config.rs) - Controls preprocessing pipeline behavior - Manages case sensitivity and auto-hide settings - Provides builder pattern for flexible configuration - Helper for CLI flag translation 3. **StatementExecutor** (statement_executor.rs) - Core unified execution engine - Parse → Preprocess → Execute (no re-parsing!) - Direct AST execution via QueryEngine - Comprehensive execution statistics tracking ## Key Features - **Single execution path**: Eliminates re-parsing overhead - **Context management**: Proper temp table and variable isolation - **Configuration control**: Fine-grained transformer enablement - **Statistics tracking**: Preprocessing time, execution time, row/column counts - **DUAL table support**: Automatic for queries without FROM clause - **Temp table support**: Full registry with strict/fallback resolution ## Testing Added comprehensive test coverage: - 31 new unit tests across all modules - Integration test suite (tests/execution_unification_tests.rs) - All 918 existing tests still passing (521 lib + 396 integration + 1 benchmark) Test categories: - Context management (13 tests) - Configuration behavior (8 tests) - Statement execution (14 tests) - Module integration (21 tests) ## Architecture Designed for incremental integration: ``` StatementExecutor (Core) ├─ ExecutionContext (State) │ ├─ Temp tables │ ├─ Variables │ └─ Source table └─ ExecutionConfig (Behavior) ├─ Preprocessing flags └─ Transformer config ``` ## Documentation Added comprehensive 6-week roadmap: - docs/EXECUTION_MODE_UNIFICATION_PLAN.md - Documents current duplication issues - Outlines Phase 0-5 implementation strategy - Includes code examples and success metrics ## Changes to Existing Code Minimal, non-breaking changes: - src/lib.rs: Added execution module export - src/query_plan/mod.rs: Added Clone/Debug derives to TransformerConfig ## Backward Compatibility 100% backward compatible: - No changes to existing execution paths - No API modifications - All existing tests pass - New code is opt-in only ## Next Steps (Future Phases) Phase 1: Refactor script mode to use StatementExecutor Phase 2: Refactor single query mode to use StatementExecutor Phase 3: Achieve feature parity (temp tables, templates everywhere) Phase 4: TUI integration Phase 5: Cleanup and optimization This foundation enables systematic elimination of code duplication and execution mode divergence while maintaining stability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 64e5121 commit e0454a4

8 files changed

Lines changed: 2326 additions & 1 deletion

File tree

docs/EXECUTION_MODE_UNIFICATION_PLAN.md

Lines changed: 820 additions & 0 deletions
Large diffs are not rendered by default.

src/execution/config.rs

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
//! Execution configuration for controlling statement execution behavior
2+
//!
3+
//! This module defines configuration options that control how SQL statements
4+
//! are preprocessed and executed.
5+
6+
use crate::query_plan::TransformerConfig;
7+
8+
/// Configuration for statement execution
9+
///
10+
/// Controls preprocessing, case sensitivity, and other execution behaviors
11+
#[derive(Clone, Debug)]
12+
pub struct ExecutionConfig {
13+
/// Whether to show preprocessing transformations (debug output)
14+
pub show_preprocessing: bool,
15+
16+
/// Whether to use case-insensitive comparison
17+
pub case_insensitive: bool,
18+
19+
/// Whether to automatically hide empty columns
20+
pub auto_hide_empty: bool,
21+
22+
/// Configuration for AST transformers (preprocessing pipeline)
23+
pub transformer_config: TransformerConfig,
24+
25+
/// Whether to enable debug tracing during execution
26+
pub debug_trace: bool,
27+
}
28+
29+
impl Default for ExecutionConfig {
30+
fn default() -> Self {
31+
Self {
32+
show_preprocessing: false,
33+
case_insensitive: false,
34+
auto_hide_empty: false,
35+
transformer_config: TransformerConfig::default(),
36+
debug_trace: false,
37+
}
38+
}
39+
}
40+
41+
impl ExecutionConfig {
42+
/// Create a new execution config with default values
43+
pub fn new() -> Self {
44+
Self::default()
45+
}
46+
47+
/// Enable preprocessing debug output
48+
pub fn with_show_preprocessing(mut self, show: bool) -> Self {
49+
self.show_preprocessing = show;
50+
self
51+
}
52+
53+
/// Enable case-insensitive comparison
54+
pub fn with_case_insensitive(mut self, insensitive: bool) -> Self {
55+
self.case_insensitive = insensitive;
56+
self
57+
}
58+
59+
/// Enable automatic hiding of empty columns
60+
pub fn with_auto_hide_empty(mut self, hide: bool) -> Self {
61+
self.auto_hide_empty = hide;
62+
self
63+
}
64+
65+
/// Set transformer configuration
66+
pub fn with_transformer_config(mut self, config: TransformerConfig) -> Self {
67+
self.transformer_config = config;
68+
self
69+
}
70+
71+
/// Enable debug tracing
72+
pub fn with_debug_trace(mut self, trace: bool) -> Self {
73+
self.debug_trace = trace;
74+
self
75+
}
76+
77+
/// Disable all preprocessing transformers
78+
pub fn without_preprocessing(mut self) -> Self {
79+
self.transformer_config.enable_expression_lifter = false;
80+
self.transformer_config.enable_where_expansion = false;
81+
self.transformer_config.enable_group_by_expansion = false;
82+
self.transformer_config.enable_having_expansion = false;
83+
self.transformer_config.enable_cte_hoister = false;
84+
self.transformer_config.enable_in_lifter = false;
85+
self
86+
}
87+
88+
/// Create config from command-line flags (helper for non_interactive.rs)
89+
pub fn from_cli_flags(
90+
show_preprocessing: bool,
91+
case_insensitive: bool,
92+
auto_hide_empty: bool,
93+
no_expression_lifter: bool,
94+
no_where_expansion: bool,
95+
no_group_by_expansion: bool,
96+
no_having_expansion: bool,
97+
no_cte_hoister: bool,
98+
no_in_lifter: bool,
99+
debug_trace: bool,
100+
) -> Self {
101+
let config = Self {
102+
show_preprocessing,
103+
case_insensitive,
104+
auto_hide_empty,
105+
transformer_config: TransformerConfig {
106+
enable_expression_lifter: !no_expression_lifter,
107+
enable_where_expansion: !no_where_expansion,
108+
enable_group_by_expansion: !no_group_by_expansion,
109+
enable_having_expansion: !no_having_expansion,
110+
enable_cte_hoister: !no_cte_hoister,
111+
enable_in_lifter: !no_in_lifter,
112+
},
113+
debug_trace,
114+
};
115+
116+
config
117+
}
118+
}
119+
120+
#[cfg(test)]
121+
mod tests {
122+
use super::*;
123+
124+
#[test]
125+
fn test_default_config() {
126+
let config = ExecutionConfig::default();
127+
128+
assert!(!config.show_preprocessing);
129+
assert!(!config.case_insensitive);
130+
assert!(!config.auto_hide_empty);
131+
assert!(!config.debug_trace);
132+
133+
// All transformers enabled by default
134+
assert!(config.transformer_config.enable_expression_lifter);
135+
assert!(config.transformer_config.enable_where_expansion);
136+
assert!(config.transformer_config.enable_group_by_expansion);
137+
assert!(config.transformer_config.enable_having_expansion);
138+
assert!(config.transformer_config.enable_cte_hoister);
139+
assert!(config.transformer_config.enable_in_lifter);
140+
}
141+
142+
#[test]
143+
fn test_builder_pattern() {
144+
let config = ExecutionConfig::new()
145+
.with_show_preprocessing(true)
146+
.with_case_insensitive(true)
147+
.with_auto_hide_empty(true)
148+
.with_debug_trace(true);
149+
150+
assert!(config.show_preprocessing);
151+
assert!(config.case_insensitive);
152+
assert!(config.auto_hide_empty);
153+
assert!(config.debug_trace);
154+
}
155+
156+
#[test]
157+
fn test_without_preprocessing() {
158+
let config = ExecutionConfig::new().without_preprocessing();
159+
160+
assert!(!config.transformer_config.enable_expression_lifter);
161+
assert!(!config.transformer_config.enable_where_expansion);
162+
assert!(!config.transformer_config.enable_group_by_expansion);
163+
assert!(!config.transformer_config.enable_having_expansion);
164+
assert!(!config.transformer_config.enable_cte_hoister);
165+
assert!(!config.transformer_config.enable_in_lifter);
166+
}
167+
168+
#[test]
169+
fn test_from_cli_flags_all_disabled() {
170+
let config = ExecutionConfig::from_cli_flags(
171+
false, // show_preprocessing
172+
false, // case_insensitive
173+
false, // auto_hide_empty
174+
true, // no_expression_lifter
175+
true, // no_where_expansion
176+
true, // no_group_by_expansion
177+
true, // no_having_expansion
178+
true, // no_cte_hoister
179+
true, // no_in_lifter
180+
false, // debug_trace
181+
);
182+
183+
assert!(!config.show_preprocessing);
184+
assert!(!config.case_insensitive);
185+
assert!(!config.transformer_config.enable_expression_lifter);
186+
assert!(!config.transformer_config.enable_where_expansion);
187+
assert!(!config.transformer_config.enable_group_by_expansion);
188+
assert!(!config.transformer_config.enable_having_expansion);
189+
assert!(!config.transformer_config.enable_cte_hoister);
190+
assert!(!config.transformer_config.enable_in_lifter);
191+
}
192+
193+
#[test]
194+
fn test_from_cli_flags_all_enabled() {
195+
let config = ExecutionConfig::from_cli_flags(
196+
true, // show_preprocessing
197+
true, // case_insensitive
198+
true, // auto_hide_empty
199+
false, // no_expression_lifter
200+
false, // no_where_expansion
201+
false, // no_group_by_expansion
202+
false, // no_having_expansion
203+
false, // no_cte_hoister
204+
false, // no_in_lifter
205+
true, // debug_trace
206+
);
207+
208+
assert!(config.show_preprocessing);
209+
assert!(config.case_insensitive);
210+
assert!(config.auto_hide_empty);
211+
assert!(config.debug_trace);
212+
assert!(config.transformer_config.enable_expression_lifter);
213+
assert!(config.transformer_config.enable_where_expansion);
214+
assert!(config.transformer_config.enable_group_by_expansion);
215+
assert!(config.transformer_config.enable_having_expansion);
216+
assert!(config.transformer_config.enable_cte_hoister);
217+
assert!(config.transformer_config.enable_in_lifter);
218+
}
219+
220+
#[test]
221+
fn test_custom_transformer_config() {
222+
let custom_transformer = TransformerConfig {
223+
enable_expression_lifter: true,
224+
enable_where_expansion: false,
225+
enable_group_by_expansion: true,
226+
enable_having_expansion: false,
227+
enable_cte_hoister: true,
228+
enable_in_lifter: false,
229+
};
230+
231+
let config = ExecutionConfig::new().with_transformer_config(custom_transformer.clone());
232+
233+
assert!(config.transformer_config.enable_expression_lifter);
234+
assert!(!config.transformer_config.enable_where_expansion);
235+
assert!(config.transformer_config.enable_group_by_expansion);
236+
assert!(!config.transformer_config.enable_having_expansion);
237+
assert!(config.transformer_config.enable_cte_hoister);
238+
assert!(!config.transformer_config.enable_in_lifter);
239+
}
240+
}

0 commit comments

Comments
 (0)