Skip to main content

linkrs_query/executor/streaming/
parameters.rs

1//! Parameter binding and expression types for physical plans.
2//!
3//! Parameters are compiled from named references (`Expression::Parameter`) to
4//! typed slots at plan-build time.  At execution time, a `ParameterFrame`
5//! provides values by slot, avoiding string-based lookups in the hot path.
6
7use std::collections::HashMap;
8
9use linkrs_core::types::operators::BinaryOperator;
10use linkrs_core::DataType;
11use linkrs_core::Value;
12
13/// A stable slot index for a query parameter within a physical plan.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub struct ParameterSlot(pub usize);
16
17/// Describes one parameter in the plan's parameter schema.
18#[derive(Debug, Clone)]
19pub struct ParameterDesc {
20    pub name: String,
21    pub slot: ParameterSlot,
22    pub value_type: Option<DataType>,
23    pub nullable: bool,
24    pub default: Option<Value>,
25}
26
27/// The parameter schema of a physical plan.
28///
29/// Stores the name-to-slot mapping and type information for all parameters
30/// that the plan expects.  Attached to [`PhysicalPlan`](super::plan::types::PhysicalPlan)
31/// so that bindings can be validated before execution.
32#[derive(Debug, Clone, Default)]
33pub struct ParameterSchema {
34    pub params: Vec<ParameterDesc>,
35    pub name_to_slot: HashMap<String, ParameterSlot>,
36}
37
38impl ParameterSchema {
39    pub fn new(params: Vec<ParameterDesc>) -> Self {
40        let name_to_slot = params.iter().map(|p| (p.name.clone(), p.slot)).collect();
41        Self {
42            params,
43            name_to_slot,
44        }
45    }
46
47    pub fn slot(&self, name: &str) -> Option<ParameterSlot> {
48        self.name_to_slot.get(name).copied()
49    }
50
51    pub fn len(&self) -> usize {
52        self.params.len()
53    }
54
55    pub fn is_empty(&self) -> bool {
56        self.params.is_empty()
57    }
58}
59
60/// Runtime parameter values, bound at instance time.
61///
62/// Created from [`QueryBindings`](super::instance::QueryBindings) after
63/// validation and type coercion.  Shared across all tasks in a query
64/// instance via `Arc<ParameterFrame>`.
65#[derive(Debug, Clone)]
66pub struct ParameterFrame {
67    pub values: Vec<Value>,
68}
69
70impl ParameterFrame {
71    pub fn new(values: Vec<Value>) -> Self {
72        Self { values }
73    }
74
75    pub fn get(&self, slot: ParameterSlot) -> Option<&Value> {
76        self.values.get(slot.0)
77    }
78}
79
80/// Slot reference: refers to a column in the input chunk by position.
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
82pub struct SlotRef(pub usize);
83
84/// A bound expression that has been resolved against the plan's slot layout
85/// and parameter schema.
86///
87/// Unlike the logical [`Expression`](linkrs_core::types::expr::Expression),
88/// `BoundExpression` references slots and parameter slots directly, avoiding
89/// string-based resolution during execution.
90#[derive(Debug, Clone)]
91pub enum BoundExpression {
92    Literal(Value),
93    SlotRef(SlotRef),
94    ParameterRef(ParameterSlot),
95    Call {
96        name: String,
97        args: Vec<BoundExpression>,
98    },
99    Binary {
100        left: Box<BoundExpression>,
101        op: BinaryOperator,
102        right: Box<BoundExpression>,
103    },
104    /// Cast the result of an expression to a target type.
105    Cast {
106        expr: Box<BoundExpression>,
107        target_type: DataType,
108    },
109}