radixdb_executor/subquery/
mod.rs1use std::sync::Arc;
23
24use radixdb_core::CompactArc;
25use radixdb_core::SmartString;
26
27use radixdb_core::{Error, Result, Value, ValueMap, ValueSet};
28use radixdb_sql::ast::*;
29use radixdb_sql::token::TokenType;
30use radixdb_storage::mvcc::engine::MVCCEngine;
31use radixdb_storage::traits::{Engine, QueryResult};
32
33use super::context::{
34 cache_batch_aggregate, cache_batch_aggregate_info, cache_count_counter,
35 cache_exists_correlation, cache_exists_fetcher, cache_exists_index, cache_exists_pred_key,
36 cache_exists_predicate, cache_exists_schema, cache_in_subquery, cache_scalar_subquery,
37 cache_semi_join_arc, compute_semi_join_cache_key, extract_table_names_for_cache,
38 get_cached_batch_aggregate, get_cached_batch_aggregate_info, get_cached_count_counter,
39 get_cached_exists_correlation, get_cached_exists_fetcher, get_cached_exists_index,
40 get_cached_exists_pred_key, get_cached_exists_predicate, get_cached_exists_schema,
41 get_cached_in_subquery, get_cached_scalar_subquery, get_cached_semi_join,
42 BatchAggregateLookupInfo, ExecutionContext, ExistsCorrelationInfo,
43};
44use super::expr_converter::convert_ast_to_storage_expr;
45use super::expression::compute_expression_hash;
46use super::operator::{ColumnInfo, MaterializedOperator, Operator};
47use super::operators::hash_join::{HashJoinOperator, JoinSide, JoinType};
48use super::utils::{dummy_token, dummy_token_clone, value_to_expression};
49use crate::access::handle::QueryTableHandle;
50
51const VISIBILITY_CHECK_BATCH_SIZE: usize = 10;
62
63type CorrelationExtraction = (String, Option<String>, String, Option<Arc<Expression>>);
69
70#[derive(Debug)]
78pub struct SemiJoinInfo {
79 pub outer_column: String,
81 pub outer_table: Option<String>,
83 pub inner_column: String,
85 pub inner_table: String,
87 pub inner_alias: Option<String>,
89 pub non_correlated_where: Option<Arc<Expression>>,
92 pub is_negated: bool,
94}
95
96#[derive(Debug, Clone)]
100struct IndexNestedLoopInfo {
101 outer_column: String,
102 outer_table: Option<String>,
103 inner_column: String,
104 inner_table: String,
105 #[allow(dead_code)]
106 additional_predicate: Option<Expression>,
107}
108
109mod correlation;
110mod rewrite;
111mod semi_join;
112#[cfg(test)]
113mod tests;
114
115pub trait SubqueryHost: Sync {
119 fn subquery_engine(&self) -> &Arc<MVCCEngine>;
120 fn subquery_open_table(&self, table_name: &str) -> Result<QueryTableHandle>;
121 fn subquery_execute_select(
122 &self,
123 statement: &SelectStatement,
124 context: &ExecutionContext,
125 ) -> Result<Box<dyn QueryResult>>;
126}
127
128pub struct SubqueryExecutor<'a, H: SubqueryHost + ?Sized> {
131 host: &'a H,
132}
133
134impl<'a, H: SubqueryHost + ?Sized> SubqueryExecutor<'a, H> {
135 fn new(host: &'a H) -> Self {
136 Self { host }
137 }
138}
139
140pub trait SubqueryExecutorExt: SubqueryHost {
142 fn process_where_subqueries(
143 &self,
144 expression: &Expression,
145 context: &ExecutionContext,
146 ) -> Result<Expression> {
147 SubqueryExecutor::new(self).process_where_subqueries(expression, context)
148 }
149
150 fn execute_exists_subquery(
151 &self,
152 statement: &SelectStatement,
153 context: &ExecutionContext,
154 ) -> Result<bool> {
155 SubqueryExecutor::new(self).execute_exists_subquery(statement, context)
156 }
157
158 fn try_process_select_subqueries(
159 &self,
160 columns: &[Expression],
161 context: &ExecutionContext,
162 ) -> Result<Option<Vec<Expression>>> {
163 SubqueryExecutor::new(self).try_process_select_subqueries(columns, context)
164 }
165
166 fn process_correlated_expression(
167 &self,
168 expression: &Expression,
169 context: &ExecutionContext,
170 ) -> Result<Expression> {
171 SubqueryExecutor::new(self).process_correlated_expression(expression, context)
172 }
173
174 fn process_correlated_where(
175 &self,
176 expression: &Expression,
177 context: &ExecutionContext,
178 ) -> Result<Expression> {
179 SubqueryExecutor::new(self).process_correlated_where(expression, context)
180 }
181
182 fn should_use_index_nested_loop_for_anti_join(
183 &self,
184 info: &SemiJoinInfo,
185 outer_limit: Option<i64>,
186 ) -> bool {
187 SubqueryExecutor::new(self).should_use_index_nested_loop_for_anti_join(info, outer_limit)
188 }
189
190 fn execute_semi_join_optimization(
191 &self,
192 info: &SemiJoinInfo,
193 context: &ExecutionContext,
194 ) -> Result<CompactArc<ValueSet>> {
195 SubqueryExecutor::new(self).execute_semi_join_optimization(info, context)
196 }
197
198 fn execute_anti_join(
199 &self,
200 info: &SemiJoinInfo,
201 outer_rows: CompactArc<Vec<radixdb_core::Row>>,
202 outer_columns: &[String],
203 context: &ExecutionContext,
204 ) -> Result<radixdb_core::RowVec> {
205 SubqueryExecutor::new(self).execute_anti_join(info, outer_rows, outer_columns, context)
206 }
207
208 fn try_optimize_exists_to_semi_join(
209 &self,
210 expression: &Expression,
211 context: &ExecutionContext,
212 outer_tables: &[String],
213 outer_limit: Option<i64>,
214 ) -> Result<Option<Expression>> {
215 SubqueryExecutor::new(self).try_optimize_exists_to_semi_join(
216 expression,
217 context,
218 outer_tables,
219 outer_limit,
220 )
221 }
222
223 fn try_optimize_in_to_semi_join(
224 &self,
225 expression: &Expression,
226 context: &ExecutionContext,
227 outer_tables: &[String],
228 ) -> Result<Option<Expression>> {
229 SubqueryExecutor::new(self).try_optimize_in_to_semi_join(expression, context, outer_tables)
230 }
231
232 fn has_subqueries(expression: &Expression) -> bool
233 where
234 Self: Sized,
235 {
236 SubqueryExecutor::<Self>::has_subqueries(expression)
237 }
238
239 fn has_correlated_subqueries(expression: &Expression) -> bool
240 where
241 Self: Sized,
242 {
243 SubqueryExecutor::<Self>::has_correlated_subqueries(expression)
244 }
245
246 fn has_correlated_select_subqueries(columns: &[Expression]) -> bool
247 where
248 Self: Sized,
249 {
250 SubqueryExecutor::<Self>::has_correlated_select_subqueries(columns)
251 }
252
253 fn is_subquery_correlated(statement: &SelectStatement) -> bool
254 where
255 Self: Sized,
256 {
257 SubqueryExecutor::<Self>::is_subquery_correlated(statement)
258 }
259
260 fn try_extract_not_exists_info(
261 expression: &Expression,
262 outer_tables: &[String],
263 ) -> Option<SemiJoinInfo>
264 where
265 Self: Sized,
266 {
267 SubqueryExecutor::<Self>::try_extract_not_exists_info(expression, outer_tables)
268 }
269
270 fn collect_outer_table_names(table: &Option<Box<Expression>>) -> Vec<String>
271 where
272 Self: Sized,
273 {
274 SubqueryExecutor::<Self>::collect_outer_table_names(table)
275 }
276}
277
278impl<T: SubqueryHost + ?Sized> SubqueryExecutorExt for T {}