query_planning/mode.rs
1//! Aggregate and report execution-mode labels (wire DTOs).
2//!
3//! These labels describe aggregate evaluation contracts and preserved report
4//! vocabulary. They are not admission or product modes. The bounded resource
5//! controller owns the single bounded execution path. Result placement is
6//! carried by the plan's `ResultSink`. The plan-coverage modes
7//! (`native_required`, `native_preferred`, `functions_only`) described in
8//! `website/docs/design/native-lowering.mdx` classify DataFusion plan nodes
9//! and live in the adapter crate; nothing here selects between CPU and GPU.
10//!
11//! Every `as_str` value is a report and environment-variable contract. A
12//! label is renamed in place together with its consumers; `FromStr` accepts
13//! the short aliases only on input.
14
15use std::{fmt, str::FromStr};
16
17/// Execution contract for floating statistical aggregates such as
18/// `STDDEV_SAMP`, `STDDEV_POP`, `VAR_SAMP`, and `VAR_POP`.
19///
20/// [`Self::DataFusionExactHostWelford`] requires the supported DataFusion
21/// aggregate semantics and a validated input-order and evaluation contract.
22/// Bit-for-bit equivalence is claimed only for that contract. If the required
23/// contract is unavailable, planning rejects the native candidate, and a
24/// surrounding join or final sort does not supply exactness.
25/// [`Self::GpuNativeTolerant`] remains the default and does not promise
26/// bit-for-bit equivalence with DataFusion.
27#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum StatisticalAggregateExecutionMode {
29 /// Evaluate DataFusion's Welford accumulator on the host over the
30 /// aggregate input, in DataFusion input order where the plan carries it.
31 ///
32 /// Aggregates in the same spec keep DataFusion's integer and NaN
33 /// semantics. Planning rejects group-key and aggregate types that this
34 /// host kernel does not cover, as well as ungrouped floating `SUM` and `AVG`,
35 /// which DataFusion accumulates batch by batch. Those plans remain on
36 /// DataFusion. A NaN result matches as a NaN, with no bit-for-bit equality.
37 /// An add of two NaN operands keeps the sign of the operand the compiler
38 /// places first, in DataFusion and in this kernel alike.
39 DataFusionExactHostWelford,
40 /// Uses libcudf native grouped and scalar statistical kernels with each
41 /// aggregate's declared degrees of freedom. This mode is the default.
42 ///
43 /// Variance is derived from sum and sum-of-squares moments, while
44 /// DataFusion uses Welford updates. Floating-point results can differ from
45 /// DataFusion, and precision degrades when values are large relative to
46 /// their spread.
47 #[default]
48 GpuNativeTolerant,
49}
50
51impl StatisticalAggregateExecutionMode {
52 /// Stable snake-case mode label used in env vars and reports.
53 pub const fn as_str(self) -> &'static str {
54 match self {
55 Self::DataFusionExactHostWelford => "datafusion_exact_host_welford",
56 Self::GpuNativeTolerant => "gpu_native_tolerant",
57 }
58 }
59
60 /// Floating parity contract required by this execution mode.
61 pub const fn tolerance_contract(self) -> StatisticalAggregateToleranceContract {
62 match self {
63 Self::DataFusionExactHostWelford => StatisticalAggregateToleranceContract::Exact,
64 Self::GpuNativeTolerant => StatisticalAggregateToleranceContract::FloatTolerant,
65 }
66 }
67
68 /// Returns true when execution must preserve DataFusion's exact Welford bits.
69 ///
70 /// Admission reads this to decide whether a plan with floating statistical
71 /// aggregates is rejected for group-key or aggregate types the host kernel
72 /// does not cover; under the tolerant mode those plans run on libcudf.
73 pub const fn is_datafusion_exact(self) -> bool {
74 matches!(self, Self::DataFusionExactHostWelford)
75 }
76}
77
78impl fmt::Display for StatisticalAggregateExecutionMode {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 f.write_str(self.as_str())
81 }
82}
83
84impl FromStr for StatisticalAggregateExecutionMode {
85 type Err = StatisticalAggregateExecutionModeParseError;
86
87 fn from_str(value: &str) -> Result<Self, Self::Err> {
88 match value.to_ascii_lowercase().as_str() {
89 "datafusion_exact_host_welford" | "datafusion_exact" | "exact" => Ok(Self::DataFusionExactHostWelford),
90 "gpu_native_tolerant" | "gpu_native" | "tolerant" => Ok(Self::GpuNativeTolerant),
91 other => Err(StatisticalAggregateExecutionModeParseError { value: other.to_string() }),
92 }
93 }
94}
95
96/// Error returned when parsing a statistical aggregate execution-mode label
97/// fails.
98#[derive(Debug, Clone, PartialEq, Eq)]
99pub struct StatisticalAggregateExecutionModeParseError {
100 value: String,
101}
102
103impl fmt::Display for StatisticalAggregateExecutionModeParseError {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 write!(f, "invalid statistical aggregate execution mode: {}", self.value)
106 }
107}
108
109impl std::error::Error for StatisticalAggregateExecutionModeParseError {}
110
111/// Tolerance contract declared by a floating statistical aggregate execution
112/// mode.
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
114pub enum StatisticalAggregateToleranceContract {
115 /// Results are expected to be identical to the compatibility contract.
116 Exact,
117 /// Results are floating-point equivalent under a declared tolerance.
118 FloatTolerant,
119}
120
121impl StatisticalAggregateToleranceContract {
122 /// Stable snake-case tolerance-contract label used in reports.
123 pub const fn as_str(self) -> &'static str {
124 match self {
125 Self::Exact => "exact",
126 Self::FloatTolerant => "float_tolerant",
127 }
128 }
129}
130
131/// Admission status used by capability reports.
132///
133/// The single bounded controller owns admission. The `Display` implementation
134/// emits the stable serialized wire labels, which predate the capability-first
135/// vocabulary: `Admitted` serializes as `bounded` and `Rejected` as
136/// `unsupported_bounded`.
137#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
138pub enum CapabilityEnvelopeStatus {
139 /// The plan is ready for bounded execution.
140 Admitted,
141 /// At least one capability decision blocks bounded execution.
142 Rejected,
143}
144
145impl CapabilityEnvelopeStatus {
146 /// Stable wire label emitted by report serializers.
147 pub(crate) const fn as_str(self) -> &'static str {
148 match self {
149 Self::Admitted => "bounded",
150 Self::Rejected => "unsupported_bounded",
151 }
152 }
153}
154
155impl fmt::Display for CapabilityEnvelopeStatus {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 f.write_str(self.as_str())
158 }
159}