use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use rustc_hash::FxHashMap;
use super::compiler::{CompileContext, ExprCompiler};
use super::program::Program;
use super::vm::{ExecuteContext, ExprVM};
use crate::core::{Error, Result, Row, Value};
use crate::functions::{global_registry, FunctionRegistry};
use crate::parser::ast::Expression;
use crate::executor::context::ExecutionContext;
pub fn compile_expression(expr: &Expression, columns: &[String]) -> Result<SharedProgram> {
let ctx = CompileContext::with_global_registry(columns);
let compiler = ExprCompiler::new(&ctx);
compiler
.compile(expr)
.map(Arc::new)
.map_err(|e| Error::internal(format!("Compile error: {}", e)))
}
pub fn compile_expression_with_context(
expr: &Expression,
columns: &[String],
outer_columns: Option<&[String]>,
function_registry: &FunctionRegistry,
) -> Result<SharedProgram> {
let mut ctx = CompileContext::new(columns, function_registry);
if let Some(outer_cols) = outer_columns {
ctx = ctx.with_outer_columns(outer_cols);
}
let compiler = ExprCompiler::new(&ctx);
compiler
.compile(expr)
.map(Arc::new)
.map_err(|e| Error::internal(format!("Compile error: {}", e)))
}
#[derive(Clone)]
pub struct RowFilter {
program: SharedProgram,
params: Arc<[Value]>,
named_params: Arc<FxHashMap<String, Value>>,
}
impl RowFilter {
pub fn new(expr: &Expression, columns: &[String]) -> Result<Self> {
let program = compile_expression(expr, columns)?;
Ok(Self {
program,
params: Arc::from([]),
named_params: Arc::new(FxHashMap::default()),
})
}
pub fn with_aliases(
expr: &Expression,
columns: &[String],
aliases: &[(String, usize)],
) -> Result<Self> {
let alias_map: FxHashMap<String, u16> = aliases
.iter()
.map(|(name, idx)| (name.to_lowercase(), *idx as u16))
.collect();
let ctx = CompileContext::with_global_registry(columns).with_expression_aliases(alias_map);
let compiler = ExprCompiler::new(&ctx);
let program = compiler
.compile(expr)
.map(Arc::new)
.map_err(|e| Error::internal(format!("Compile error: {}", e)))?;
Ok(Self {
program,
params: Arc::from([]),
named_params: Arc::new(FxHashMap::default()),
})
}
pub fn with_params(mut self, params: Vec<Value>) -> Self {
self.params = Arc::from(params);
self
}
pub fn with_named_params(mut self, named_params: FxHashMap<String, Value>) -> Self {
self.named_params = Arc::new(named_params);
self
}
pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
self.params = Arc::from(ctx.params().to_vec());
self.named_params = Arc::clone(ctx.named_params_arc());
self
}
pub fn from_program(program: SharedProgram) -> Self {
Self {
program,
params: Arc::from([]),
named_params: Arc::new(FxHashMap::default()),
}
}
#[inline]
pub fn matches(&self, row: &Row) -> bool {
thread_local! {
static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
}
VM.with(|vm| {
let row_data = row.as_slice();
let mut ctx = ExecuteContext::new(row_data);
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
borrowed_vm.execute_bool(&self.program, &ctx)
} else {
let mut temp_vm = ExprVM::new();
temp_vm.execute_bool(&self.program, &ctx)
}
})
}
#[inline]
pub fn evaluate(&self, row: &Row) -> Result<Value> {
thread_local! {
static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
}
VM.with(|vm| {
let row_data = row.as_slice();
let mut ctx = ExecuteContext::new(row_data);
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
borrowed_vm.execute(&self.program, &ctx)
} else {
let mut temp_vm = ExprVM::new();
temp_vm.execute(&self.program, &ctx)
}
})
}
pub fn program(&self) -> &SharedProgram {
&self.program
}
}
const _: () = {
const fn assert_send_sync<T: Send + Sync>() {}
let _ = assert_send_sync::<RowFilter>;
};
#[derive(Clone)]
pub struct JoinFilter {
program: SharedProgram,
}
impl JoinFilter {
pub fn new(
expr: &Expression,
left_columns: &[String],
right_columns: &[String],
function_registry: &FunctionRegistry,
) -> Result<Self> {
let ctx =
CompileContext::new(left_columns, function_registry).with_second_row(right_columns);
let compiler = ExprCompiler::new(&ctx);
let program = compiler
.compile(expr)
.map_err(|e| Error::internal(format!("Compile error: {}", e)))?;
Ok(Self {
program: Arc::new(program),
})
}
#[inline]
pub fn matches(&self, left_row: &Row, right_row: &Row) -> bool {
thread_local! {
static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
}
VM.with(|vm| {
let ctx = ExecuteContext::for_join(left_row.as_slice(), right_row.as_slice());
if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
borrowed_vm.execute_bool(&self.program, &ctx)
} else {
let mut temp_vm = ExprVM::new();
temp_vm.execute_bool(&self.program, &ctx)
}
})
}
pub fn program(&self) -> &SharedProgram {
&self.program
}
}
const _: () = {
const fn assert_send_sync<T: Send + Sync>() {}
let _ = assert_send_sync::<JoinFilter>;
};
pub struct ExpressionEval {
program: SharedProgram,
vm: ExprVM,
params: Vec<Value>,
named_params: FxHashMap<String, Value>,
outer_row: Option<FxHashMap<Arc<str>, Value>>,
transaction_id: Option<u64>,
}
impl ExpressionEval {
pub fn compile(expr: &Expression, columns: &[String]) -> Result<Self> {
let program = compile_expression(expr, columns)?;
Ok(Self {
program,
vm: ExprVM::new(),
params: Vec::new(),
named_params: FxHashMap::default(),
outer_row: None,
transaction_id: None,
})
}
pub fn compile_with_aliases(
expr: &Expression,
columns: &[String],
aliases: &[(String, usize)],
) -> Result<Self> {
let alias_map: FxHashMap<String, u16> = aliases
.iter()
.map(|(name, idx)| (name.to_lowercase(), *idx as u16))
.collect();
Self::compile_with_options(
expr,
columns,
None,
None,
Some(alias_map),
global_registry(),
)
}
pub fn compile_with_options(
expr: &Expression,
columns: &[String],
columns2: Option<&[String]>,
outer_columns: Option<&[String]>,
expression_aliases: Option<FxHashMap<String, u16>>,
function_registry: &FunctionRegistry,
) -> Result<Self> {
let mut ctx = CompileContext::new(columns, function_registry);
if let Some(cols2) = columns2 {
ctx = ctx.with_second_row(cols2);
}
if let Some(outer) = outer_columns {
ctx = ctx.with_outer_columns(outer);
}
if let Some(aliases) = expression_aliases {
ctx = ctx.with_expression_aliases(aliases);
}
let compiler = ExprCompiler::new(&ctx);
let program = compiler
.compile(expr)
.map(Arc::new)
.map_err(|e| Error::internal(format!("Compile error: {}", e)))?;
Ok(Self {
program,
vm: ExprVM::new(),
params: Vec::new(),
named_params: FxHashMap::default(),
outer_row: None,
transaction_id: None,
})
}
pub fn from_program(program: SharedProgram) -> Self {
Self {
program,
vm: ExprVM::new(),
params: Vec::new(),
named_params: FxHashMap::default(),
outer_row: None,
transaction_id: None,
}
}
pub fn with_params(mut self, params: Vec<Value>) -> Self {
self.params = params;
self
}
pub fn with_named_params(mut self, named_params: FxHashMap<String, Value>) -> Self {
self.named_params = named_params;
self
}
pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
self.params = ctx.params().to_vec();
self.named_params = ctx
.named_params()
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect();
if let Some(outer) = ctx.outer_row() {
let mut arc_map = FxHashMap::default();
for (k, v) in outer.iter() {
arc_map.insert(Arc::from(k.as_str()), v.clone());
}
self.outer_row = Some(arc_map);
}
self.transaction_id = ctx.transaction_id();
self
}
pub fn with_transaction_id(mut self, txn_id: Option<u64>) -> Self {
self.transaction_id = txn_id;
self
}
pub fn set_outer_row(&mut self, outer: &FxHashMap<String, Value>) {
let mut arc_map = FxHashMap::default();
for (k, v) in outer.iter() {
arc_map.insert(Arc::from(k.as_str()), v.clone());
}
self.outer_row = Some(arc_map);
}
pub fn clear_outer_row(&mut self) {
self.outer_row = None;
}
#[inline]
pub fn eval(&mut self, row: &Row) -> Result<Value> {
let row_data = row.as_slice();
let mut ctx = ExecuteContext::new(row_data);
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
if let Some(ref outer) = self.outer_row {
ctx = ctx.with_outer_row(outer);
}
ctx = ctx.with_transaction_id(self.transaction_id);
self.vm.execute(&self.program, &ctx)
}
#[inline]
pub fn eval_bool(&mut self, row: &Row) -> bool {
let row_data = row.as_slice();
let mut ctx = ExecuteContext::new(row_data);
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
if let Some(ref outer) = self.outer_row {
ctx = ctx.with_outer_row(outer);
}
ctx = ctx.with_transaction_id(self.transaction_id);
self.vm.execute_bool(&self.program, &ctx)
}
#[inline]
pub fn eval_join(&mut self, left: &Row, right: &Row) -> Result<Value> {
let ctx = ExecuteContext::for_join(left.as_slice(), right.as_slice());
self.vm.execute(&self.program, &ctx)
}
#[inline]
pub fn eval_join_bool(&mut self, left: &Row, right: &Row) -> bool {
let ctx = ExecuteContext::for_join(left.as_slice(), right.as_slice());
self.vm.execute_bool(&self.program, &ctx)
}
#[inline]
pub fn eval_slice(&mut self, row: &[Value]) -> Result<Value> {
let mut ctx = ExecuteContext::new(row);
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
if let Some(ref outer) = self.outer_row {
ctx = ctx.with_outer_row(outer);
}
ctx = ctx.with_transaction_id(self.transaction_id);
self.vm.execute(&self.program, &ctx)
}
#[inline]
pub fn eval_slice_bool(&mut self, row: &[Value]) -> bool {
let mut ctx = ExecuteContext::new(row);
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
if let Some(ref outer) = self.outer_row {
ctx = ctx.with_outer_row(outer);
}
ctx = ctx.with_transaction_id(self.transaction_id);
self.vm.execute_bool(&self.program, &ctx)
}
pub fn program(&self) -> &SharedProgram {
&self.program
}
}
pub struct MultiExpressionEval {
programs: Vec<SharedProgram>,
vm: ExprVM,
params: Vec<Value>,
named_params: FxHashMap<String, Value>,
transaction_id: Option<u64>,
}
impl MultiExpressionEval {
pub fn compile(exprs: &[Expression], columns: &[String]) -> Result<Self> {
let ctx = CompileContext::with_global_registry(columns);
let compiler = ExprCompiler::new(&ctx);
let programs = exprs
.iter()
.map(|expr| {
compiler
.compile(expr)
.map(Arc::new)
.map_err(|e| Error::internal(format!("Compile error: {}", e)))
})
.collect::<Result<Vec<_>>>()?;
Ok(Self {
programs,
vm: ExprVM::new(),
params: Vec::new(),
named_params: FxHashMap::default(),
transaction_id: None,
})
}
pub fn compile_with_aliases(
exprs: &[Expression],
columns: &[String],
aliases: &[(String, usize)],
) -> Result<Self> {
let alias_map: FxHashMap<String, u16> = aliases
.iter()
.map(|(name, idx)| (name.to_lowercase(), *idx as u16))
.collect();
let ctx = CompileContext::with_global_registry(columns).with_expression_aliases(alias_map);
let compiler = ExprCompiler::new(&ctx);
let programs = exprs
.iter()
.map(|expr| {
compiler
.compile(expr)
.map(Arc::new)
.map_err(|e| Error::internal(format!("Compile error: {}", e)))
})
.collect::<Result<Vec<_>>>()?;
Ok(Self {
programs,
vm: ExprVM::new(),
params: Vec::new(),
named_params: FxHashMap::default(),
transaction_id: None,
})
}
pub fn with_params(mut self, params: Vec<Value>) -> Self {
self.params = params;
self
}
pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
self.params = ctx.params().to_vec();
self.named_params = ctx
.named_params()
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect();
self.transaction_id = ctx.transaction_id();
self
}
#[inline]
pub fn eval_all(&mut self, row: &Row) -> Result<Vec<Value>> {
let row_data = row.as_slice();
let mut ctx = ExecuteContext::new(row_data);
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
ctx = ctx.with_transaction_id(self.transaction_id);
self.programs
.iter()
.map(|prog| self.vm.execute(prog, &ctx))
.collect()
}
#[inline]
pub fn eval_into(&mut self, row: &Row, output: &mut Vec<Value>) -> Result<()> {
let row_data = row.as_slice();
let mut ctx = ExecuteContext::new(row_data);
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
ctx = ctx.with_transaction_id(self.transaction_id);
output.clear();
for prog in &self.programs {
output.push(self.vm.execute(prog, &ctx)?);
}
Ok(())
}
pub fn len(&self) -> usize {
self.programs.len()
}
pub fn is_empty(&self) -> bool {
self.programs.is_empty()
}
}
pub type SharedProgram = Arc<Program>;
pub struct CompiledEvaluator<'a> {
function_registry: &'a FunctionRegistry,
columns: Vec<String>,
columns2: Option<Vec<String>>,
outer_columns: Option<Vec<String>>,
params: Vec<Value>,
named_params: FxHashMap<String, Value>,
outer_row: Option<FxHashMap<Arc<str>, Value>>,
transaction_id: Option<u64>,
expression_aliases: FxHashMap<String, u16>,
column_aliases: FxHashMap<String, String>,
vm: ExprVM,
local_cache: FxHashMap<u64, SharedProgram>,
current_row: Option<Vec<Value>>,
current_row2: Option<Vec<Value>>,
}
impl<'a> CompiledEvaluator<'a> {
pub fn new(function_registry: &'a FunctionRegistry) -> Self {
Self {
function_registry,
columns: Vec::new(),
columns2: None,
outer_columns: None,
params: Vec::new(),
named_params: FxHashMap::default(),
outer_row: None,
transaction_id: None,
expression_aliases: FxHashMap::default(),
column_aliases: FxHashMap::default(),
vm: ExprVM::new(),
local_cache: FxHashMap::default(),
current_row: None,
current_row2: None,
}
}
pub fn with_defaults() -> CompiledEvaluator<'static> {
CompiledEvaluator::new(global_registry())
}
pub fn clear(&mut self) {
self.columns.clear();
self.columns2 = None;
self.outer_columns = None;
self.params.clear();
self.named_params.clear();
self.outer_row = None;
self.transaction_id = None;
self.expression_aliases.clear();
self.column_aliases.clear();
self.local_cache.clear();
self.current_row = None;
self.current_row2 = None;
}
pub fn set_transaction_id(&mut self, txn_id: u64) {
self.transaction_id = Some(txn_id);
}
pub fn with_params(mut self, params: Vec<Value>) -> Self {
self.params = params;
self
}
pub fn with_named_params(mut self, named_params: FxHashMap<String, Value>) -> Self {
self.named_params = named_params;
self
}
pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
self.params = ctx.params().to_vec();
self.named_params = ctx
.named_params()
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect();
if let Some(outer) = ctx.outer_row() {
let mut arc_map = FxHashMap::default();
let mut outer_cols = Vec::new();
for (k, v) in outer.iter() {
arc_map.insert(Arc::from(k.as_str()), v.clone());
outer_cols.push(k.clone());
}
self.outer_row = Some(arc_map);
if !outer_cols.is_empty() {
self.outer_columns = Some(outer_cols);
self.local_cache.clear();
}
}
self.transaction_id = ctx.transaction_id();
self
}
pub fn with_row(mut self, row: Row, columns: &[String]) -> Self {
self.init_columns(columns);
let _ = row; self
}
pub fn init_columns(&mut self, columns: &[String]) {
self.columns = columns.to_vec();
self.local_cache.clear();
}
pub fn add_aggregate_aliases(&mut self, aliases: &[(String, usize)]) {
for (expr_name, idx) in aliases {
let lower = expr_name.to_lowercase();
self.expression_aliases.insert(lower, *idx as u16);
}
self.local_cache.clear();
}
pub fn add_expression_aliases(&mut self, aliases: &[(String, usize)]) {
for (expr_str, idx) in aliases {
let lower = expr_str.to_lowercase();
self.expression_aliases.insert(lower, *idx as u16);
}
self.local_cache.clear();
}
#[inline]
pub fn set_row_array(&mut self, row: &Row) {
self.current_row = Some(row.as_slice().to_vec());
self.current_row2 = None;
}
#[inline]
pub fn set_join_rows(&mut self, left_row: &Row, right_row: &Row) {
self.current_row = Some(left_row.as_slice().to_vec());
self.current_row2 = Some(right_row.as_slice().to_vec());
}
pub fn init_join_columns(&mut self, left_columns: &[String], right_columns: &[String]) {
self.columns = left_columns.to_vec();
self.columns2 = Some(right_columns.to_vec());
self.local_cache.clear();
}
#[inline]
pub fn set_outer_row(&mut self, outer_row: Option<&FxHashMap<String, Value>>) {
if let Some(outer) = outer_row {
let mut arc_map = FxHashMap::default();
for (k, v) in outer.iter() {
arc_map.insert(Arc::from(k.as_str()), v.clone());
}
self.outer_row = Some(arc_map);
} else {
self.outer_row = None;
}
}
#[inline]
pub fn set_outer_row_owned(&mut self, outer_row: FxHashMap<String, Value>) {
let mut arc_map = FxHashMap::default();
let mut outer_cols = Vec::new();
for (k, v) in outer_row.into_iter() {
outer_cols.push(k.clone());
arc_map.insert(Arc::from(k.as_str()), v);
}
self.outer_row = Some(arc_map);
if !outer_cols.is_empty() {
outer_cols.sort();
self.outer_columns = Some(outer_cols);
self.local_cache.clear();
}
}
pub fn compile_shared(&mut self, expr: &Expression) -> Result<SharedProgram> {
self.get_or_compile(expr)
}
#[inline]
pub fn take_outer_row(&mut self) -> FxHashMap<String, Value> {
if let Some(arc_map) = self.outer_row.take() {
arc_map
.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect()
} else {
FxHashMap::default()
}
}
#[inline]
pub fn clear_outer_row(&mut self) {
self.outer_row = None;
}
pub fn init_outer_columns(&mut self, outer_columns: &[String]) {
self.outer_columns = Some(outer_columns.to_vec());
self.local_cache.clear();
}
pub fn has_outer_columns(&self) -> bool {
self.outer_columns.is_some()
}
pub fn get_outer_columns(&self) -> Option<&Vec<String>> {
self.outer_columns.as_ref()
}
pub fn clear_row(&mut self) {
self.current_row = None;
self.current_row2 = None;
}
#[inline]
fn expr_hash(&self, expr: &Expression) -> u64 {
let mut hasher = DefaultHasher::new();
Self::hash_expression(expr, &mut hasher);
hasher.finish()
}
fn hash_expression(expr: &Expression, hasher: &mut DefaultHasher) {
std::mem::discriminant(expr).hash(hasher);
match expr {
Expression::Identifier(id) => {
id.value_lower.hash(hasher);
}
Expression::QualifiedIdentifier(qid) => {
qid.qualifier.value_lower.hash(hasher);
qid.name.value_lower.hash(hasher);
}
Expression::IntegerLiteral(lit) => {
lit.value.hash(hasher);
}
Expression::FloatLiteral(lit) => {
lit.value.to_bits().hash(hasher);
}
Expression::StringLiteral(lit) => {
lit.value.hash(hasher);
lit.type_hint.hash(hasher);
}
Expression::BooleanLiteral(lit) => {
lit.value.hash(hasher);
}
Expression::NullLiteral(_) => {
}
Expression::IntervalLiteral(lit) => {
lit.value.hash(hasher);
lit.unit.hash(hasher);
}
Expression::Parameter(param) => {
param.index.hash(hasher);
param.name.hash(hasher);
}
Expression::Prefix(prefix) => {
std::mem::discriminant(&prefix.op_type).hash(hasher);
Self::hash_expression(&prefix.right, hasher);
}
Expression::Infix(infix) => {
std::mem::discriminant(&infix.op_type).hash(hasher);
Self::hash_expression(&infix.left, hasher);
Self::hash_expression(&infix.right, hasher);
}
Expression::List(list) => {
list.elements.len().hash(hasher);
for val in &list.elements {
Self::hash_expression(val, hasher);
}
}
Expression::Distinct(dist) => {
Self::hash_expression(&dist.expr, hasher);
}
Expression::Exists(exists) => {
format!("{:?}", exists.subquery).hash(hasher);
}
Expression::AllAny(aa) => {
aa.operator.hash(hasher);
std::mem::discriminant(&aa.all_any_type).hash(hasher);
Self::hash_expression(&aa.left, hasher);
format!("{:?}", aa.subquery).hash(hasher);
}
Expression::In(in_expr) => {
in_expr.not.hash(hasher);
Self::hash_expression(&in_expr.left, hasher);
Self::hash_expression(&in_expr.right, hasher);
}
Expression::InHashSet(in_hash) => {
in_hash.not.hash(hasher);
Self::hash_expression(&in_hash.column, hasher);
in_hash.values.len().hash(hasher);
}
Expression::Between(between) => {
between.not.hash(hasher);
Self::hash_expression(&between.expr, hasher);
Self::hash_expression(&between.lower, hasher);
Self::hash_expression(&between.upper, hasher);
}
Expression::Like(like) => {
like.operator.hash(hasher);
Self::hash_expression(&like.left, hasher);
Self::hash_expression(&like.pattern, hasher);
if let Some(ref escape) = like.escape {
true.hash(hasher);
Self::hash_expression(escape, hasher);
} else {
false.hash(hasher);
}
}
Expression::ScalarSubquery(sq) => {
format!("{:?}", sq.subquery).hash(hasher);
}
Expression::ExpressionList(list) => {
list.expressions.len().hash(hasher);
for expr in &list.expressions {
Self::hash_expression(expr, hasher);
}
}
Expression::Case(case) => {
if let Some(ref val) = case.value {
true.hash(hasher);
Self::hash_expression(val, hasher);
} else {
false.hash(hasher);
}
case.when_clauses.len().hash(hasher);
for when_clause in &case.when_clauses {
Self::hash_expression(&when_clause.condition, hasher);
Self::hash_expression(&when_clause.then_result, hasher);
}
if let Some(ref else_val) = case.else_value {
true.hash(hasher);
Self::hash_expression(else_val, hasher);
} else {
false.hash(hasher);
}
}
Expression::Cast(cast) => {
Self::hash_expression(&cast.expr, hasher);
cast.type_name.hash(hasher);
}
Expression::FunctionCall(func) => {
func.function.hash(hasher);
func.is_distinct.hash(hasher);
func.arguments.len().hash(hasher);
for arg in &func.arguments {
Self::hash_expression(arg, hasher);
}
if let Some(ref filter) = func.filter {
true.hash(hasher);
Self::hash_expression(filter, hasher);
} else {
false.hash(hasher);
}
}
Expression::Aliased(aliased) => {
aliased.alias.value_lower.hash(hasher);
Self::hash_expression(&aliased.expression, hasher);
}
Expression::Window(window) => {
window.function.function.hash(hasher);
window.function.is_distinct.hash(hasher);
window.function.arguments.len().hash(hasher);
for arg in &window.function.arguments {
Self::hash_expression(arg, hasher);
}
window.partition_by.len().hash(hasher);
for expr in &window.partition_by {
Self::hash_expression(expr, hasher);
}
window.order_by.len().hash(hasher);
for order in &window.order_by {
Self::hash_expression(&order.expression, hasher);
order.ascending.hash(hasher);
order.nulls_first.hash(hasher);
}
}
Expression::TableSource(ts) => {
ts.name.value_lower().hash(hasher);
if let Some(ref alias) = ts.alias {
true.hash(hasher);
alias.value_lower.hash(hasher);
} else {
false.hash(hasher);
}
}
Expression::JoinSource(js) => {
format!("{:?}", js).hash(hasher);
}
Expression::SubquerySource(sq) => {
if let Some(ref alias) = sq.alias {
true.hash(hasher);
alias.value_lower.hash(hasher);
} else {
false.hash(hasher);
}
format!("{:?}", sq.subquery).hash(hasher);
}
Expression::ValuesSource(vs) => {
if let Some(ref alias) = vs.alias {
true.hash(hasher);
alias.value_lower.hash(hasher);
} else {
false.hash(hasher);
}
vs.rows.len().hash(hasher);
}
Expression::FunctionTableSource(fts) => {
if let Some(ref alias) = fts.alias {
true.hash(hasher);
alias.value_lower.hash(hasher);
} else {
false.hash(hasher);
}
fts.function.value_lower.hash(hasher);
}
Expression::CteReference(cte) => {
cte.name.value_lower.hash(hasher);
}
Expression::Star(_) => {
}
Expression::QualifiedStar(qs) => {
qs.qualifier.hash(hasher);
}
Expression::Default(_) => {
}
}
}
fn get_or_compile(&mut self, expr: &Expression) -> Result<SharedProgram> {
let expr_key = self.expr_hash(expr);
if let Some(program) = self.local_cache.get(&expr_key) {
return Ok(Arc::clone(program));
}
let program = Arc::new(self.compile_expression(expr)?);
self.local_cache.insert(expr_key, Arc::clone(&program));
Ok(program)
}
fn compile_expression(&self, expr: &Expression) -> Result<Program> {
let mut ctx = CompileContext::new(&self.columns, self.function_registry);
if let Some(ref cols2) = self.columns2 {
ctx = ctx.with_second_row(cols2);
}
if let Some(ref outer_cols) = self.outer_columns {
ctx = ctx.with_outer_columns(outer_cols);
}
if !self.expression_aliases.is_empty() {
ctx = ctx.with_expression_aliases(self.expression_aliases.clone());
}
if !self.column_aliases.is_empty() {
ctx = ctx.with_column_aliases(self.column_aliases.clone());
}
let compiler = ExprCompiler::new(&ctx);
compiler
.compile(expr)
.map_err(|e| Error::internal(format!("Compile error: {}", e)))
}
pub fn evaluate(&mut self, expr: &Expression) -> Result<Value> {
let program = self.get_or_compile(expr)?;
let row = self.current_row.as_deref().unwrap_or(&[]);
let row2 = self.current_row2.as_deref();
let mut ctx = if let Some(r2) = row2 {
ExecuteContext::for_join(row, r2)
} else {
ExecuteContext::new(row)
};
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
if let Some(ref outer) = self.outer_row {
ctx = ctx.with_outer_row(outer);
}
ctx = ctx.with_transaction_id(self.transaction_id);
self.vm.execute(&program, &ctx)
}
pub fn evaluate_bool(&mut self, expr: &Expression) -> Result<bool> {
let program = self.get_or_compile(expr)?;
let row = self.current_row.as_deref().unwrap_or(&[]);
let row2 = self.current_row2.as_deref();
let mut ctx = if let Some(r2) = row2 {
ExecuteContext::for_join(row, r2)
} else {
ExecuteContext::new(row)
};
if !self.params.is_empty() {
ctx = ctx.with_params(&self.params);
}
if !self.named_params.is_empty() {
ctx = ctx.with_named_params(&self.named_params);
}
if let Some(ref outer) = self.outer_row {
ctx = ctx.with_outer_row(outer);
}
ctx = ctx.with_transaction_id(self.transaction_id);
Ok(self.vm.execute_bool(&program, &ctx))
}
}
impl Default for CompiledEvaluator<'static> {
fn default() -> Self {
Self::with_defaults()
}
}