use std::sync::Arc;
use radixdb_core::CompactArc;
use radixdb_core::SmartString;
use radixdb_core::{Error, Result, Value, ValueMap, ValueSet};
use radixdb_sql::ast::*;
use radixdb_sql::token::TokenType;
use radixdb_storage::mvcc::engine::MVCCEngine;
use radixdb_storage::traits::{Engine, QueryResult};
use super::context::{
cache_batch_aggregate, cache_batch_aggregate_info, cache_count_counter,
cache_exists_correlation, cache_exists_fetcher, cache_exists_index, cache_exists_pred_key,
cache_exists_predicate, cache_exists_schema, cache_in_subquery, cache_scalar_subquery,
cache_semi_join_arc, compute_semi_join_cache_key, extract_table_names_for_cache,
get_cached_batch_aggregate, get_cached_batch_aggregate_info, get_cached_count_counter,
get_cached_exists_correlation, get_cached_exists_fetcher, get_cached_exists_index,
get_cached_exists_pred_key, get_cached_exists_predicate, get_cached_exists_schema,
get_cached_in_subquery, get_cached_scalar_subquery, get_cached_semi_join,
BatchAggregateLookupInfo, ExecutionContext, ExistsCorrelationInfo,
};
use super::expr_converter::convert_ast_to_storage_expr;
use super::expression::compute_expression_hash;
use super::operator::{ColumnInfo, MaterializedOperator, Operator};
use super::operators::hash_join::{HashJoinOperator, JoinSide, JoinType};
use super::utils::{dummy_token, dummy_token_clone, value_to_expression};
use crate::access::handle::QueryTableHandle;
const VISIBILITY_CHECK_BATCH_SIZE: usize = 10;
type CorrelationExtraction = (String, Option<String>, String, Option<Arc<Expression>>);
#[derive(Debug)]
pub struct SemiJoinInfo {
pub outer_column: String,
pub outer_table: Option<String>,
pub inner_column: String,
pub inner_table: String,
pub inner_alias: Option<String>,
pub non_correlated_where: Option<Arc<Expression>>,
pub is_negated: bool,
}
#[derive(Debug, Clone)]
struct IndexNestedLoopInfo {
outer_column: String,
outer_table: Option<String>,
inner_column: String,
inner_table: String,
#[allow(dead_code)]
additional_predicate: Option<Expression>,
}
mod correlation;
mod rewrite;
mod semi_join;
#[cfg(test)]
mod tests;
pub trait SubqueryHost: Sync {
fn subquery_engine(&self) -> &Arc<MVCCEngine>;
fn subquery_open_table(&self, table_name: &str) -> Result<QueryTableHandle>;
fn subquery_execute_select(
&self,
statement: &SelectStatement,
context: &ExecutionContext,
) -> Result<Box<dyn QueryResult>>;
}
pub struct SubqueryExecutor<'a, H: SubqueryHost + ?Sized> {
host: &'a H,
}
impl<'a, H: SubqueryHost + ?Sized> SubqueryExecutor<'a, H> {
fn new(host: &'a H) -> Self {
Self { host }
}
}
pub trait SubqueryExecutorExt: SubqueryHost {
fn process_where_subqueries(
&self,
expression: &Expression,
context: &ExecutionContext,
) -> Result<Expression> {
SubqueryExecutor::new(self).process_where_subqueries(expression, context)
}
fn execute_exists_subquery(
&self,
statement: &SelectStatement,
context: &ExecutionContext,
) -> Result<bool> {
SubqueryExecutor::new(self).execute_exists_subquery(statement, context)
}
fn try_process_select_subqueries(
&self,
columns: &[Expression],
context: &ExecutionContext,
) -> Result<Option<Vec<Expression>>> {
SubqueryExecutor::new(self).try_process_select_subqueries(columns, context)
}
fn process_correlated_expression(
&self,
expression: &Expression,
context: &ExecutionContext,
) -> Result<Expression> {
SubqueryExecutor::new(self).process_correlated_expression(expression, context)
}
fn process_correlated_where(
&self,
expression: &Expression,
context: &ExecutionContext,
) -> Result<Expression> {
SubqueryExecutor::new(self).process_correlated_where(expression, context)
}
fn should_use_index_nested_loop_for_anti_join(
&self,
info: &SemiJoinInfo,
outer_limit: Option<i64>,
) -> bool {
SubqueryExecutor::new(self).should_use_index_nested_loop_for_anti_join(info, outer_limit)
}
fn execute_semi_join_optimization(
&self,
info: &SemiJoinInfo,
context: &ExecutionContext,
) -> Result<CompactArc<ValueSet>> {
SubqueryExecutor::new(self).execute_semi_join_optimization(info, context)
}
fn execute_anti_join(
&self,
info: &SemiJoinInfo,
outer_rows: CompactArc<Vec<radixdb_core::Row>>,
outer_columns: &[String],
context: &ExecutionContext,
) -> Result<radixdb_core::RowVec> {
SubqueryExecutor::new(self).execute_anti_join(info, outer_rows, outer_columns, context)
}
fn try_optimize_exists_to_semi_join(
&self,
expression: &Expression,
context: &ExecutionContext,
outer_tables: &[String],
outer_limit: Option<i64>,
) -> Result<Option<Expression>> {
SubqueryExecutor::new(self).try_optimize_exists_to_semi_join(
expression,
context,
outer_tables,
outer_limit,
)
}
fn try_optimize_in_to_semi_join(
&self,
expression: &Expression,
context: &ExecutionContext,
outer_tables: &[String],
) -> Result<Option<Expression>> {
SubqueryExecutor::new(self).try_optimize_in_to_semi_join(expression, context, outer_tables)
}
fn has_subqueries(expression: &Expression) -> bool
where
Self: Sized,
{
SubqueryExecutor::<Self>::has_subqueries(expression)
}
fn has_correlated_subqueries(expression: &Expression) -> bool
where
Self: Sized,
{
SubqueryExecutor::<Self>::has_correlated_subqueries(expression)
}
fn has_correlated_select_subqueries(columns: &[Expression]) -> bool
where
Self: Sized,
{
SubqueryExecutor::<Self>::has_correlated_select_subqueries(columns)
}
fn is_subquery_correlated(statement: &SelectStatement) -> bool
where
Self: Sized,
{
SubqueryExecutor::<Self>::is_subquery_correlated(statement)
}
fn try_extract_not_exists_info(
expression: &Expression,
outer_tables: &[String],
) -> Option<SemiJoinInfo>
where
Self: Sized,
{
SubqueryExecutor::<Self>::try_extract_not_exists_info(expression, outer_tables)
}
fn collect_outer_table_names(table: &Option<Box<Expression>>) -> Vec<String>
where
Self: Sized,
{
SubqueryExecutor::<Self>::collect_outer_table_names(table)
}
}
impl<T: SubqueryHost + ?Sized> SubqueryExecutorExt for T {}