Skip to main content

mz_repr/
optimize.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! Facilities for defining optimizer feature flags.
11
12use std::collections::BTreeMap;
13
14#[cfg(any(test, feature = "proptest"))]
15use proptest_derive::Arbitrary;
16use serde::{Deserialize, Serialize};
17
18/// A macro for feature flags managed by the optimizer.
19macro_rules! optimizer_feature_flags {
20    ({ $($feature:ident: $type:ty,)* }) => {
21        #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
22        #[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
23        pub struct OptimizerFeatures {
24            $(pub $feature: $type),*
25        }
26
27        #[derive(Clone, Debug, Deserialize, Serialize, PartialOrd, PartialEq, Eq, Ord)]
28        pub struct OptimizerFeatureOverrides {
29            $(pub $feature: Option<$type>),*
30        }
31
32        impl Default for OptimizerFeatureOverrides {
33            fn default() -> Self {
34                Self {
35                    $($feature: None),*
36                }
37            }
38        }
39
40        /// An [`OverrideFrom`] implementation that updates
41        /// [`OptimizerFeatures`] using [`OptimizerFeatureOverrides`] values.
42        impl OverrideFrom<OptimizerFeatureOverrides> for OptimizerFeatures {
43            fn override_from(mut self, overrides: &OptimizerFeatureOverrides) -> Self {
44                $(if let Some(feature_value) = overrides.$feature {
45                    self.$feature = feature_value;
46                })*
47                self
48            }
49        }
50
51        /// An `OptimizerFeatureOverrides ⇒ BTreeMap<String, String>`
52        /// conversion.
53        ///
54        /// WARNING: changing the definition of item might break catalog
55        /// re-hydration for some catalog items (such as entries for `CREATE
56        /// CLUSTER ... FEATURES(...)` statements).
57        impl From<BTreeMap<String, String>> for OptimizerFeatureOverrides {
58            fn from(value: BTreeMap<String, String>) -> Self {
59                let mut overrides = OptimizerFeatureOverrides::default();
60
61                for (name, value) in value.into_iter() {
62                    match name.as_str() {
63                        $(stringify!($feature) => {
64                            let value = Some(<$type>::decode(&value));
65                            overrides.$feature = value;
66                        }),*
67                        _ => (), // Ignore
68                    }
69                }
70
71                overrides
72            }
73        }
74
75        /// A `BTreeMap<String, String> ⇒ OptimizerFeatureOverrides` conversion.
76        ///
77        /// WARNING: changing the definition of item might break catalog
78        /// re-hydration for some catalog items (such as entries for `CREATE
79        /// CLUSTER ... FEATURES(...)` statements).
80        impl From<OptimizerFeatureOverrides> for BTreeMap<String, String> {
81            fn from(overrides: OptimizerFeatureOverrides) -> Self {
82                let mut map = BTreeMap::<String, String>::default();
83
84                $(if let Some(value) = overrides.$feature {
85                    let k = stringify!($feature).into();
86                    let v = value.encode();
87                    map.insert(k, v);
88                };)*
89
90                map
91            }
92        }
93    };
94}
95
96optimizer_feature_flags!({
97    // Use `EquivalenceClassesWithholdingErrors` instead of raw
98    // `EquivalenceClasses` during eq prop for joins.
99    enable_eq_classes_withholding_errors: bool,
100    // Bound from `SystemVars::enable_eager_delta_joins`.
101    enable_eager_delta_joins: bool,
102    // Enable Lattice-based fixpoint iteration on LetRec nodes in the
103    // Analysis framework.
104    enable_letrec_fixpoint_analysis: bool,
105    // Bound from `SystemVars::enable_new_outer_join_lowering`.
106    enable_new_outer_join_lowering: bool,
107    // Bound from `SystemVars::enable_reduce_mfp_fusion`.
108    enable_reduce_mfp_fusion: bool,
109    // Enable joint HIR ⇒ MIR lowering of stacks of left joins.
110    enable_variadic_left_join_lowering: bool,
111    // Enable cardinality estimation
112    enable_cardinality_estimates: bool,
113    // An exclusive upper bound on the number of results we may return from a
114    // Persist fast-path peek. Required by the `create_fast_path_plan` call in
115    // `peek::Optimizer`.
116    persist_fast_path_limit: usize,
117    // Reoptimize imported views when building and optimizing a
118    // `DataflowDescription` in the global MIR optimization phase.
119    reoptimize_imported_views: bool,
120    // See the feature flag of the same name.
121    enable_join_prioritize_arranged: bool,
122    // See the feature flag of the same name.
123    enable_projection_pushdown_after_relation_cse: bool,
124    // See the feature flag of the same name.
125    enable_less_reduce_in_eqprop: bool,
126    // See the feature flag of the same name.
127    enable_dequadratic_eqprop_map: bool,
128    // See the feature flag of the same name.
129    enable_fast_path_plan_insights: bool,
130    // See the feature flag of the same name.
131    enable_cast_elimination: bool,
132    // See the feature flag of the same name.
133    enable_case_literal_transform: bool,
134    // See the feature flag of the same name.
135    enable_simplify_quantified_comparisons: bool,
136    // See the feature flag of the same name.
137    enable_simplify_from_less_existence: bool,
138    // See the feature flag of the same name.
139    enable_coalesce_case_transform: bool,
140    // See the feature flag of the same name.
141    enable_will_distinct_propagation: bool,
142    // See the feature flag of the same name.
143    enable_fixed_correlated_cte_lowering: bool,
144});
145
146/// A trait used to implement layered config construction.
147pub trait OverrideFrom<T> {
148    /// Override the configuration represented by [`Self`] with values
149    /// from the given `layer`.
150    fn override_from(self, layer: &T) -> Self;
151}
152
153/// Overrides for `U` coming from an optional `T`.
154impl<T, U> OverrideFrom<Option<&T>> for U
155where
156    Self: OverrideFrom<T>,
157{
158    fn override_from(self, layer: &Option<&T>) -> Self {
159        match layer {
160            Some(layer) => self.override_from(layer),
161            None => self,
162        }
163    }
164}
165
166/// A trait that handles conversion of feature flags.
167trait OptimizerFeatureType {
168    fn encode(self) -> String;
169    fn decode(v: &str) -> Self;
170}
171
172/// A macro that implements [`OptimizerFeatureType`] for most common types.
173///
174/// WARNING: changing the definition of this macro might break catalog
175/// re-hydration for some catalog items (such as entries for `CREATE CLUSTER ...
176/// FEATURES(...)` statements).
177macro_rules! impl_optimizer_feature_type {
178    ($($type:ty),*) => {
179        $(
180            impl OptimizerFeatureType for $type {
181                fn encode(self) -> String {
182                    self.to_string()
183                }
184
185                fn decode(v: &str) -> Self {
186                    str::parse(&v).unwrap()
187                }
188            }
189        )*
190    };
191}
192
193// Implement `OptimizerFeatureType` for all types used in the
194// `optimizer_feature_flags!(...)`  call above.
195impl_optimizer_feature_type![usize];
196
197impl OptimizerFeatureType for bool {
198    fn encode(self) -> String {
199        self.to_string()
200    }
201
202    fn decode(v: &str) -> Self {
203        // Accept both the Rust spelling (`true`/`false`, what `encode` and
204        // `CREATE CLUSTER ... FEATURES` produce) and the canonical system-var /
205        // PostgreSQL spellings (`on`/`off`, ...). A cluster-coherent scoped
206        // override may arrive as the var's canonical `on`/`off`.
207        match v.trim().to_lowercase().as_str() {
208            "t" | "true" | "on" | "1" | "y" | "yes" => true,
209            "f" | "false" | "off" | "0" | "n" | "no" => false,
210            // The writer only stores values that passed `canonicalize`, so this
211            // arm is unreachable in practice. Log rather than panic anyway: a
212            // stored bad value reaching the plan path would otherwise crash the
213            // optimizer on every query for the affected cluster. Fall back to
214            // `false`.
215            other => {
216                mz_ore::soft_panic_or_log!("invalid boolean optimizer feature override: {other:?}");
217                false
218            }
219        }
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use std::collections::BTreeMap;
226
227    use super::OptimizerFeatureOverrides;
228
229    #[mz_ore::test]
230    fn bool_override_decodes_lenient_spellings() {
231        for (stored, want) in [
232            ("true", true),
233            ("false", false),
234            ("on", true),
235            ("off", false),
236        ] {
237            let map =
238                BTreeMap::from([("enable_eager_delta_joins".to_string(), stored.to_string())]);
239            assert_eq!(
240                OptimizerFeatureOverrides::from(map).enable_eager_delta_joins,
241                Some(want),
242            );
243        }
244    }
245}