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_coalesce_case_transform: bool,
138 // See the feature flag of the same name.
139 enable_will_distinct_propagation: bool,
140 // See the feature flag of the same name.
141 enable_fixed_correlated_cte_lowering: bool,
142});
143
144/// A trait used to implement layered config construction.
145pub trait OverrideFrom<T> {
146 /// Override the configuration represented by [`Self`] with values
147 /// from the given `layer`.
148 fn override_from(self, layer: &T) -> Self;
149}
150
151/// Overrides for `U` coming from an optional `T`.
152impl<T, U> OverrideFrom<Option<&T>> for U
153where
154 Self: OverrideFrom<T>,
155{
156 fn override_from(self, layer: &Option<&T>) -> Self {
157 match layer {
158 Some(layer) => self.override_from(layer),
159 None => self,
160 }
161 }
162}
163
164/// A trait that handles conversion of feature flags.
165trait OptimizerFeatureType {
166 fn encode(self) -> String;
167 fn decode(v: &str) -> Self;
168}
169
170/// A macro that implements [`OptimizerFeatureType`] for most common types.
171///
172/// WARNING: changing the definition of this macro might break catalog
173/// re-hydration for some catalog items (such as entries for `CREATE CLUSTER ...
174/// FEATURES(...)` statements).
175macro_rules! impl_optimizer_feature_type {
176 ($($type:ty),*) => {
177 $(
178 impl OptimizerFeatureType for $type {
179 fn encode(self) -> String {
180 self.to_string()
181 }
182
183 fn decode(v: &str) -> Self {
184 str::parse(&v).unwrap()
185 }
186 }
187 )*
188 };
189}
190
191// Implement `OptimizerFeatureType` for all types used in the
192// `optimizer_feature_flags!(...)` call above.
193impl_optimizer_feature_type![usize];
194
195impl OptimizerFeatureType for bool {
196 fn encode(self) -> String {
197 self.to_string()
198 }
199
200 fn decode(v: &str) -> Self {
201 // Accept both the Rust spelling (`true`/`false`, what `encode` and
202 // `CREATE CLUSTER ... FEATURES` produce) and the canonical system-var /
203 // PostgreSQL spellings (`on`/`off`, ...). A cluster-coherent scoped
204 // override may arrive as the var's canonical `on`/`off`.
205 match v.trim().to_lowercase().as_str() {
206 "t" | "true" | "on" | "1" | "y" | "yes" => true,
207 "f" | "false" | "off" | "0" | "n" | "no" => false,
208 // The writer only stores values that passed `canonicalize`, so this
209 // arm is unreachable in practice. Log rather than panic anyway: a
210 // stored bad value reaching the plan path would otherwise crash the
211 // optimizer on every query for the affected cluster. Fall back to
212 // `false`.
213 other => {
214 mz_ore::soft_panic_or_log!("invalid boolean optimizer feature override: {other:?}");
215 false
216 }
217 }
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use std::collections::BTreeMap;
224
225 use super::OptimizerFeatureOverrides;
226
227 #[mz_ore::test]
228 fn bool_override_decodes_lenient_spellings() {
229 for (stored, want) in [
230 ("true", true),
231 ("false", false),
232 ("on", true),
233 ("off", false),
234 ] {
235 let map =
236 BTreeMap::from([("enable_eager_delta_joins".to_string(), stored.to_string())]);
237 assert_eq!(
238 OptimizerFeatureOverrides::from(map).enable_eager_delta_joins,
239 Some(want),
240 );
241 }
242 }
243}