Skip to main content

uqa_execution/scalar/
context.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Physical scalar evaluation context and runtime capabilities.
8
9use uqa_sql::expr::{EngineHook, EvalContext, RowLookup};
10use uqa_sql::{ResultRow, SQLParam};
11
12use crate::batch::{PhysicalRow, RowSchema};
13
14use super::subquery::ScalarSubqueryRunner;
15
16pub struct ScalarEvalContext<'a> {
17    row: Option<&'a ResultRow>,
18    row_lookup: Option<&'a dyn RowLookup>,
19    row_schema: Option<&'a RowSchema>,
20    params: &'a [SQLParam],
21    function_hook: Option<&'a dyn EngineHook>,
22    subquery_runner: Option<&'a dyn ScalarSubqueryRunner>,
23    physical_outer_row: Option<(&'a RowSchema, &'a PhysicalRow)>,
24}
25
26impl<'a> ScalarEvalContext<'a> {
27    #[must_use]
28    pub fn new(row: Option<&'a ResultRow>, params: &'a [SQLParam]) -> Self {
29        Self {
30            row,
31            row_lookup: row.map(|row| row as &dyn RowLookup),
32            row_schema: None,
33            params,
34            function_hook: None,
35            subquery_runner: None,
36            physical_outer_row: None,
37        }
38    }
39
40    #[must_use]
41    pub fn from_row_lookup(row: &'a dyn RowLookup, params: &'a [SQLParam]) -> Self {
42        Self {
43            row: None,
44            row_lookup: Some(row),
45            row_schema: None,
46            params,
47            function_hook: None,
48            subquery_runner: None,
49            physical_outer_row: None,
50        }
51    }
52
53    #[must_use]
54    pub fn with_function_hook(mut self, hook: &'a dyn EngineHook) -> Self {
55        self.function_hook = Some(hook);
56        self
57    }
58
59    #[must_use]
60    pub fn with_row_schema(mut self, schema: &'a RowSchema) -> Self {
61        self.row_schema = Some(schema);
62        self
63    }
64
65    #[must_use]
66    pub fn with_subquery_runner(mut self, runner: &'a dyn ScalarSubqueryRunner) -> Self {
67        self.subquery_runner = Some(runner);
68        self
69    }
70
71    #[must_use]
72    pub fn with_physical_outer_row(mut self, schema: &'a RowSchema, row: &'a PhysicalRow) -> Self {
73        self.physical_outer_row = Some((schema, row));
74        self
75    }
76
77    pub(super) fn sql_context(&self) -> EvalContext<'_> {
78        let context = self.row_lookup.map_or_else(
79            || EvalContext::new(self.row, self.params),
80            |row| EvalContext::from_row_lookup(row, self.params),
81        );
82        match self.function_hook {
83            Some(hook) => context.with_engine(hook),
84            None => context,
85        }
86    }
87
88    pub(super) fn outer_row(&self) -> Option<&dyn RowLookup> {
89        self.row_lookup
90    }
91
92    pub(super) fn row_lookup(&self) -> Option<&'a dyn RowLookup> {
93        self.row_lookup
94    }
95
96    pub(super) fn row_schema(&self) -> Option<&'a RowSchema> {
97        self.row_schema
98    }
99
100    pub(super) fn params(&self) -> &'a [SQLParam] {
101        self.params
102    }
103
104    pub(super) fn function_hook(&self) -> Option<&'a dyn EngineHook> {
105        self.function_hook
106    }
107
108    pub(super) fn subquery_runner(&self) -> Option<&'a dyn ScalarSubqueryRunner> {
109        self.subquery_runner
110    }
111
112    pub(super) fn physical_outer_row(&self) -> Option<(&'a RowSchema, &'a PhysicalRow)> {
113        self.physical_outer_row
114    }
115}