1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.

//! Facilities for defining optimizer feature flags.

use std::collections::BTreeMap;

use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};

/// A macro for feature flags managed by the optimizer.
macro_rules! optimizer_feature_flags {
    ({ $($feature:ident: $type:ty,)* }) => {
        #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, Arbitrary)]
        pub struct OptimizerFeatures {
            $(pub $feature: $type),*
        }

        #[derive(Clone, Debug, Deserialize, Serialize, PartialOrd, PartialEq, Eq, Ord)]
        pub struct OptimizerFeatureOverrides {
            $(pub $feature: Option<$type>),*
        }

        impl Default for OptimizerFeatureOverrides {
            fn default() -> Self {
                Self {
                    $($feature: None),*
                }
            }
        }

        /// An [`OverrideFrom`] implementation that updates
        /// [`OptimizerFeatures`] using [`OptimizerFeatureOverrides`] values.
        impl OverrideFrom<OptimizerFeatureOverrides> for OptimizerFeatures {
            fn override_from(mut self, overrides: &OptimizerFeatureOverrides) -> Self {
                $(if let Some(feature_value) = overrides.$feature {
                    self.$feature = feature_value;
                })*
                self
            }
        }

        /// An `OptimizerFeatureOverrides ⇒ BTreeMap<String, String>`
        /// conversion.
        ///
        /// WARNING: changing the definition of item might break catalog
        /// re-hydration for some catalog items (such as entries for `CREATE
        /// CLUSTER ... FEATURES(...)` statements).
        impl From<BTreeMap<String, String>> for OptimizerFeatureOverrides {
            fn from(value: BTreeMap<String, String>) -> Self {
                let mut overrides = OptimizerFeatureOverrides::default();

                for (name, value) in value.into_iter() {
                    match name.as_str() {
                        $(stringify!($feature) => {
                            let value = Some(<$type>::decode(&value));
                            overrides.$feature = value;
                        }),*
                        _ => (), // Ignore
                    }
                }

                overrides
            }
        }

        /// A `BTreeMap<String, String> ⇒ OptimizerFeatureOverrides` conversion.
        ///
        /// WARNING: changing the definition of item might break catalog
        /// re-hydration for some catalog items (such as entries for `CREATE
        /// CLUSTER ... FEATURES(...)` statements).
        impl From<OptimizerFeatureOverrides> for BTreeMap<String, String> {
            fn from(overrides: OptimizerFeatureOverrides) -> Self {
                let mut map = BTreeMap::<String, String>::default();

                $(if let Some(value) = overrides.$feature {
                    let k = stringify!($feature).into();
                    let v = value.encode();
                    map.insert(k, v);
                };)*

                map
            }
        }
    };
}

optimizer_feature_flags!({
    // Enable consolidation of unions that happen immediately after negate.
    //
    // The refinement happens in the LIR ⇒ LIR phase.
    enable_consolidate_after_union_negate: bool,
    // Bound from `SystemVars::enable_eager_delta_joins`.
    enable_eager_delta_joins: bool,
    // Enable Lattice-based fixpoint iteration on LetRec nodes in the
    // Analysis framework.
    enable_letrec_fixpoint_analysis: bool,
    // Bound from `SystemVars::enable_new_outer_join_lowering`.
    enable_new_outer_join_lowering: bool,
    // Bound from `SystemVars::enable_reduce_mfp_fusion`.
    enable_reduce_mfp_fusion: bool,
    // Enable joint HIR ⇒ MIR lowering of stacks of left joins.
    enable_variadic_left_join_lowering: bool,
    // Enable cardinality estimation
    enable_cardinality_estimates: bool,
    // An exclusive upper bound on the number of results we may return from a
    // Persist fast-path peek. Required by the `create_fast_path_plan` call in
    // `peek::Optimizer`.
    persist_fast_path_limit: usize,
    // Reoptimize imported views when building and optimizing a
    // `DataflowDescription` in the global MIR optimization phase.
    reoptimize_imported_views: bool,
    // See the feature flag of the same name.
    enable_reduce_reduction: bool,
});

/// A trait used to implement layered config construction.
pub trait OverrideFrom<T> {
    /// Override the configuration represented by [`Self`] with values
    /// from the given `layer`.
    fn override_from(self, layer: &T) -> Self;
}

/// Overrides for `U` coming from an optional `T`.
impl<T, U> OverrideFrom<Option<&T>> for U
where
    Self: OverrideFrom<T>,
{
    fn override_from(self, layer: &Option<&T>) -> Self {
        match layer {
            Some(layer) => self.override_from(layer),
            None => self,
        }
    }
}

/// A trait that handles conversion of feature flags.
trait OptimizerFeatureType {
    fn encode(self) -> String;
    fn decode(v: &str) -> Self;
}

/// A macro that implements [`OptimizerFeatureType`] for most common types.
///
/// WARNING: changing the definition of this macro might break catalog
/// re-hydration for some catalog items (such as entries for `CREATE CLUSTER ...
/// FEATURES(...)` statements).
macro_rules! impl_optimizer_feature_type {
    ($($type:ty),*) => {
        $(
            impl OptimizerFeatureType for $type {
                fn encode(self) -> String {
                    self.to_string()
                }

                fn decode(v: &str) -> Self {
                    str::parse(&v).unwrap()
                }
            }
        )*
    };
}

// Implement `OptimizerFeatureType` for all types used in the
// `optimizer_feature_flags!(...)`  call above.
impl_optimizer_feature_type![bool, usize];