1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! Caching strategies for expression evaluation
//!
//! This module provides caching mechanisms for:
//! - CSE (Common Subexpression Elimination)
//! - Subquery results
//!
//! Caches use LRU eviction and can be configured via environment variables.
use ;
use LruCache;
/// Default maximum size for CSE cache (entries)
/// Can be overridden via CSE_CACHE_SIZE environment variable
pub const DEFAULT_CSE_CACHE_SIZE: usize = 1000;
/// Default maximum size for subquery result cache (entries)
/// Increased from 100 to 5000 to handle complex test files with 400+ unique subqueries
/// (e.g., index/between/1000/slt_good_0.test has 401 subqueries)
/// Can be overridden via SUBQUERY_CACHE_SIZE environment variable
pub const DEFAULT_SUBQUERY_CACHE_SIZE: usize = 5000;
/// Check if CSE is enabled via environment variable
/// Defaults to true, can be disabled by setting CSE_ENABLED=false
pub
/// Get CSE cache size from environment variable
/// Defaults to DEFAULT_CSE_CACHE_SIZE, can be overridden by setting CSE_CACHE_SIZE
pub
/// Get subquery cache size from environment variable
/// Defaults to DEFAULT_SUBQUERY_CACHE_SIZE, can be overridden by setting SUBQUERY_CACHE_SIZE
pub
/// Create a new CSE cache with configured size
pub
/// Create a new subquery result cache with configured size
pub
// NOTE: Pointer-based hash caching was removed because it caused correctness bugs.
// See compute_subquery_hash() for details.
/// Compute a hash for a subquery to use as a cache key
///
/// # Implementation Note
///
/// Currently uses Debug format for hashing, which has trade-offs:
///
/// **Pros:**
/// - Simple and works with existing AST types
/// - Sufficient for typical queries in practice
/// - Hash collisions are rare
///
/// **Cons:**
/// - Fragile: Debug format could change with Rust versions
/// - Less efficient: Allocates string for each hash
/// - Not cryptographically secure (uses DefaultHasher)
///
/// **Future Improvement:**
/// Ideally, SelectStmt and child types should derive Hash for:
/// - Better performance (direct AST traversal)
/// - Stability (Hash trait is stable)
/// - Type safety (compiler-enforced consistency)
///
/// This requires adding Hash to ~15-20 AST types, which should be
/// done in a dedicated refactoring PR to minimize risk.
///
/// See: https://github.com/rjwalters/vibesql/issues/2137#hash-improvement
///
/// Compute hash directly without pointer-based caching.
///
/// While pointer-based caching can improve performance by avoiding repeated format!()
/// calls for the same AST within a query, it causes correctness bugs because:
/// 1. The thread-local cache persists across different query executions
/// 2. When memory is reused (same pointer for different AST nodes), stale hashes are returned
/// 3. This caused index/between tests to return wrong results
///
/// The performance cost of format!() is minimal compared to actual query execution.
/// For better performance, derive Hash for SelectStmt and related AST types.
pub
/// Clear the subquery hash cache (no-op).
///
/// Kept for API compatibility. Pointer-based hash caching has been removed
/// because it caused correctness bugs when memory was reused across queries.
/// Compute a composite cache key for a correlated subquery
///
/// The cache key combines:
/// 1. The subquery hash (AST structure)
/// 2. The correlation values (column values from outer row)
///
/// This allows caching correlated subquery results when the correlation
/// values are the same across different rows.
pub