Skip to main content

mz_sql/session/vars/
definitions.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
10use std::borrow::Cow;
11use std::num::NonZeroU32;
12use std::str::FromStr;
13use std::sync::Arc;
14use std::sync::LazyLock;
15use std::time::Duration;
16
17use chrono::{DateTime, Utc};
18use derivative::Derivative;
19use mz_adapter_types::timestamp_oracle::{
20    DEFAULT_PG_TIMESTAMP_ORACLE_CONNPOOL_MAX_SIZE, DEFAULT_PG_TIMESTAMP_ORACLE_CONNPOOL_MAX_WAIT,
21    DEFAULT_PG_TIMESTAMP_ORACLE_CONNPOOL_TTL, DEFAULT_PG_TIMESTAMP_ORACLE_CONNPOOL_TTL_STAGGER,
22};
23use mz_dyncfg::ParameterScope;
24use mz_ore::cast::{self, CastFrom};
25use mz_repr::adt::numeric::Numeric;
26use mz_repr::adt::timestamp::CheckedTimestamp;
27use mz_repr::bytes::ByteSize;
28use mz_repr::optimize::OptimizerFeatures;
29use mz_sql_parser::ast::Ident;
30use mz_sql_parser::ident;
31use mz_storage_types::parameters::REPLICA_STATUS_HISTORY_RETENTION_WINDOW_DEFAULT;
32use mz_storage_types::parameters::{
33    DEFAULT_PG_SOURCE_CONNECT_TIMEOUT, DEFAULT_PG_SOURCE_TCP_CONFIGURE_SERVER,
34    DEFAULT_PG_SOURCE_TCP_KEEPALIVES_IDLE, DEFAULT_PG_SOURCE_TCP_KEEPALIVES_INTERVAL,
35    DEFAULT_PG_SOURCE_TCP_KEEPALIVES_RETRIES, DEFAULT_PG_SOURCE_TCP_USER_TIMEOUT,
36    DEFAULT_PG_SOURCE_WAL_SENDER_TIMEOUT, STORAGE_MANAGED_COLLECTIONS_BATCH_DURATION_DEFAULT,
37};
38use mz_tracing::{CloneableEnvFilter, SerializableDirective};
39use uncased::UncasedStr;
40
41use crate::session::user::{SUPPORT_USER, SYSTEM_USER, User};
42use crate::session::vars::constraints::{
43    BYTESIZE_AT_LEAST_1MB, DomainConstraint, NON_ZERO_DURATION, NUMERIC_BOUNDED_0_1_INCLUSIVE,
44    NUMERIC_NON_NEGATIVE, ValueConstraint,
45};
46use crate::session::vars::errors::VarError;
47use crate::session::vars::polyfill::{LazyValueFn, lazy_value, value};
48use crate::session::vars::value::{
49    ClientEncoding, ClientSeverity, DEFAULT_DATE_STYLE, Failpoints, IntervalStyle, IsolationLevel,
50    TimeZone, Value,
51};
52use crate::session::vars::{FeatureFlag, Var, VarInput, VarParseError};
53use crate::{DEFAULT_SCHEMA, WEBHOOK_CONCURRENCY_LIMIT};
54
55/// Definition of a variable.
56#[derive(Clone, Derivative)]
57#[derivative(Debug)]
58pub struct VarDefinition {
59    /// Name of the variable, case-insensitive matching.
60    pub name: &'static UncasedStr,
61    /// Description of the variable.
62    pub description: &'static str,
63    /// Is the variable visible to users, when false only visible to system users.
64    pub user_visible: bool,
65
66    /// Default compiled in value for this variable.
67    pub value: VarDefaultValue,
68    /// Constraint that must be upheld for this variable to be valid.
69    pub constraint: Option<ValueConstraint>,
70    /// When set, prevents getting or setting the variable unless the specified
71    /// feature flag is enabled.
72    pub require_feature_flag: Option<&'static FeatureFlag>,
73    /// The scope at which this variable's value may be overridden by the
74    /// LaunchDarkly sync loop.
75    pub scope: ParameterScope,
76
77    /// Method to parse [`VarInput`] into a type that implements [`Value`].
78    ///
79    /// The reason `parse` exists as a function pointer is because we want to achieve two things:
80    ///   1. `VarDefinition` has no generic parameters.
81    ///   2. `Value::parse` returns an instance of `Self`.
82    /// `VarDefinition` holds a `dyn Value`, but `Value::parse` is not object safe because it
83    /// returns `Self`, so we can't call that method. We could change `Value::parse` to return a
84    /// `Box<dyn Value>` making it object safe, but that creates a footgun where it's possible for
85    /// `Value::parse` to return a type that isn't `Self`, e.g. `<String as Value>::parse` could
86    /// return a `usize`!
87    ///
88    /// So to prevent making `VarDefinition` generic over some type `V: Value`, but also defining
89    /// `Value::parse` as returning `Self`, we store a static function pointer to the `parse`
90    /// implementation of our default value.
91    #[derivative(Debug = "ignore")]
92    parse: fn(VarInput) -> Result<Box<dyn Value>, VarParseError>,
93    /// Returns a human readable name for the type of this variable. We store this as a static
94    /// function pointer for the same reason as `parse`.
95    #[derivative(Debug = "ignore")]
96    type_name: fn() -> Cow<'static, str>,
97}
98static_assertions::assert_impl_all!(VarDefinition: Send, Sync);
99
100impl VarDefinition {
101    /// Create a new [`VarDefinition`] in a const context with a value known at compile time.
102    pub const fn new<V: Value>(
103        name: &'static str,
104        value: &'static V,
105        description: &'static str,
106        user_visible: bool,
107    ) -> Self {
108        VarDefinition {
109            name: UncasedStr::new(name),
110            description,
111            value: VarDefaultValue::Static(value),
112            user_visible,
113            parse: V::parse_dyn_value,
114            type_name: V::type_name,
115            constraint: None,
116            require_feature_flag: None,
117            scope: ParameterScope::DEFAULT,
118        }
119    }
120
121    /// Create a new [`VarDefinition`] in a const context with a lazily evaluated value.
122    pub const fn new_lazy<V: Value, L: LazyValueFn<V>>(
123        name: &'static str,
124        _value: L,
125        description: &'static str,
126        user_visible: bool,
127    ) -> Self {
128        VarDefinition {
129            name: UncasedStr::new(name),
130            description,
131            value: VarDefaultValue::Lazy(L::LAZY_VALUE_FN),
132            user_visible,
133            parse: V::parse_dyn_value,
134            type_name: V::type_name,
135            constraint: None,
136            require_feature_flag: None,
137            scope: ParameterScope::DEFAULT,
138        }
139    }
140
141    /// Create a new [`VarDefinition`] with a value known at runtime.
142    pub fn new_runtime<V: Value>(
143        name: &'static str,
144        value: V,
145        description: &'static str,
146        user_visible: bool,
147    ) -> Self {
148        VarDefinition {
149            name: UncasedStr::new(name),
150            description,
151            value: VarDefaultValue::Runtime(Arc::new(value)),
152            user_visible,
153            parse: V::parse_dyn_value,
154            type_name: V::type_name,
155            constraint: None,
156            require_feature_flag: None,
157            scope: ParameterScope::DEFAULT,
158        }
159    }
160
161    /// TODO(parkmycar): Refactor this method onto a `VarDefinitionBuilder` that would allow us to
162    /// constrain `V` here to be the same `V` used in [`VarDefinition::new`].
163    pub const fn with_constraint<V: Value, D: DomainConstraint<Value = V>>(
164        mut self,
165        constraint: &'static D,
166    ) -> Self {
167        self.constraint = Some(ValueConstraint::Domain(constraint));
168        self
169    }
170
171    pub const fn fixed(mut self) -> Self {
172        self.constraint = Some(ValueConstraint::Fixed);
173        self
174    }
175
176    pub const fn read_only(mut self) -> Self {
177        self.constraint = Some(ValueConstraint::ReadOnly);
178        self
179    }
180
181    pub const fn with_feature_flag(mut self, feature_flag: &'static FeatureFlag) -> Self {
182        self.require_feature_flag = Some(feature_flag);
183        self
184    }
185
186    /// Declares the [`ParameterScope`] of this variable, overriding the
187    /// [default](ParameterScope::DEFAULT). See [`ParameterScope`] for the
188    /// semantics of each scope class.
189    pub const fn scoped(mut self, scope: ParameterScope) -> Self {
190        self.scope = scope;
191        self
192    }
193
194    pub fn parse(&self, input: VarInput) -> Result<Box<dyn Value>, VarError> {
195        (self.parse)(input).map_err(|err| err.into_var_error(self))
196    }
197
198    pub fn default_value(&self) -> &'_ dyn Value {
199        self.value.value()
200    }
201}
202
203impl Var for VarDefinition {
204    fn name(&self) -> &'static str {
205        self.name.as_str()
206    }
207
208    fn value(&self) -> String {
209        self.default_value().format()
210    }
211
212    fn description(&self) -> &'static str {
213        self.description
214    }
215
216    fn type_name(&self) -> Cow<'static, str> {
217        (self.type_name)()
218    }
219
220    fn scope(&self) -> ParameterScope {
221        self.scope
222    }
223
224    fn visible(&self, user: &User, system_vars: &super::SystemVars) -> Result<(), VarError> {
225        if !self.user_visible && user != &*SYSTEM_USER && user != &*SUPPORT_USER {
226            Err(VarError::UnknownParameter(self.name().to_string()))
227        } else if self.is_unsafe() && !system_vars.allow_unsafe() {
228            Err(VarError::RequiresUnsafeMode(self.name()))
229        } else {
230            if let Some(flag) = self.require_feature_flag {
231                flag.require(system_vars)?;
232            }
233
234            Ok(())
235        }
236    }
237}
238
239/// The kinds of compiled in default values that can be used with [`VarDefinition`].
240#[derive(Clone, Debug)]
241pub enum VarDefaultValue {
242    /// Static that can be evaluated at compile time.
243    Static(&'static dyn Value),
244    /// Lazy value that is defined at compile time, but created at runtime.
245    Lazy(fn() -> &'static dyn Value),
246    /// Value created at runtime. Note: This is generally an escape hatch.
247    Runtime(Arc<dyn Value>),
248}
249
250impl VarDefaultValue {
251    pub fn value(&self) -> &'_ dyn Value {
252        match self {
253            VarDefaultValue::Static(s) => *s,
254            VarDefaultValue::Lazy(l) => (l)(),
255            VarDefaultValue::Runtime(r) => r.as_ref(),
256        }
257    }
258}
259
260// We pretend to be Postgres v9.5.0, which is also what CockroachDB pretends to
261// be. Too new and some clients will emit a "server too new" warning. Too old
262// and some clients will fall back to legacy code paths. v9.5.0 empirically
263// seems to be a good compromise.
264
265/// The major version of PostgreSQL that Materialize claims to be.
266pub const SERVER_MAJOR_VERSION: u8 = 9;
267
268/// The minor version of PostgreSQL that Materialize claims to be.
269pub const SERVER_MINOR_VERSION: u8 = 5;
270
271/// The patch version of PostgreSQL that Materialize claims to be.
272pub const SERVER_PATCH_VERSION: u8 = 0;
273
274/// The name of the default database that Materialize uses.
275pub const DEFAULT_DATABASE_NAME: &str = "materialize";
276
277pub static APPLICATION_NAME: VarDefinition = VarDefinition::new(
278    "application_name",
279    value!(String; String::new()),
280    "Sets the application name to be reported in statistics and logs (PostgreSQL).",
281    true,
282);
283
284pub static CLIENT_ENCODING: VarDefinition = VarDefinition::new(
285    "client_encoding",
286    value!(ClientEncoding; ClientEncoding::Utf8),
287    "Sets the client's character set encoding (PostgreSQL).",
288    true,
289);
290
291pub static CLIENT_MIN_MESSAGES: VarDefinition = VarDefinition::new(
292    "client_min_messages",
293    value!(ClientSeverity; ClientSeverity::Notice),
294    "Sets the message levels that are sent to the client (PostgreSQL).",
295    true,
296);
297
298pub static CLUSTER: VarDefinition = VarDefinition::new_lazy(
299    "cluster",
300    lazy_value!(String; || "quickstart".to_string()),
301    "Sets the current cluster (Materialize).",
302    true,
303);
304
305pub static CLUSTER_REPLICA: VarDefinition = VarDefinition::new(
306    "cluster_replica",
307    value!(Option<String>; None),
308    "Sets a target cluster replica for SELECT queries (Materialize).",
309    true,
310);
311
312pub static CURRENT_OBJECT_MISSING_WARNINGS: VarDefinition = VarDefinition::new(
313    "current_object_missing_warnings",
314    value!(bool; true),
315    "Whether to emit warnings when the current database, schema, or cluster is missing (Materialize).",
316    true,
317);
318
319pub static DATABASE: VarDefinition = VarDefinition::new_lazy(
320    "database",
321    lazy_value!(String; || DEFAULT_DATABASE_NAME.to_string()),
322    "Sets the current database (CockroachDB).",
323    true,
324);
325
326pub static DATE_STYLE: VarDefinition = VarDefinition::new(
327    // DateStyle has nonstandard capitalization for historical reasons.
328    "DateStyle",
329    &DEFAULT_DATE_STYLE,
330    "Sets the display format for date and time values (PostgreSQL).",
331    true,
332);
333
334pub static DEFAULT_CLUSTER_REPLICATION_FACTOR: VarDefinition = VarDefinition::new(
335    "default_cluster_replication_factor",
336    value!(u32; 1),
337    "Default cluster replication factor (Materialize).",
338    true,
339);
340
341pub static EXTRA_FLOAT_DIGITS: VarDefinition = VarDefinition::new(
342    "extra_float_digits",
343    value!(i32; 3),
344    "Adjusts the number of digits displayed for floating-point values (PostgreSQL).",
345    true,
346);
347
348pub static FAILPOINTS: VarDefinition = VarDefinition::new(
349    "failpoints",
350    value!(Failpoints; Failpoints),
351    "Allows failpoints to be dynamically activated.",
352    true,
353);
354
355pub static INTEGER_DATETIMES: VarDefinition = VarDefinition::new(
356    "integer_datetimes",
357    value!(bool; true),
358    "Reports whether the server uses 64-bit-integer dates and times (PostgreSQL).",
359    true,
360)
361.fixed();
362
363pub static INTERVAL_STYLE: VarDefinition = VarDefinition::new(
364    // IntervalStyle has nonstandard capitalization for historical reasons.
365    "IntervalStyle",
366    value!(IntervalStyle; IntervalStyle::Postgres),
367    "Sets the display format for interval values (PostgreSQL).",
368    true,
369);
370
371pub const MZ_VERSION_NAME: &UncasedStr = UncasedStr::new("mz_version");
372pub const IS_SUPERUSER_NAME: &UncasedStr = UncasedStr::new("is_superuser");
373
374// Schema can be used an alias for a search path with a single element.
375pub const SCHEMA_ALIAS: &UncasedStr = UncasedStr::new("schema");
376pub static SEARCH_PATH: VarDefinition = VarDefinition::new_lazy(
377    "search_path",
378    lazy_value!(Vec<Ident>; || vec![ident!(DEFAULT_SCHEMA)]),
379    "Sets the schema search order for names that are not schema-qualified (PostgreSQL).",
380    true,
381);
382
383pub static STATEMENT_TIMEOUT: VarDefinition = VarDefinition::new(
384    "statement_timeout",
385    value!(Duration; Duration::from_secs(60)),
386    "Sets the maximum allowed duration of INSERT...SELECT, UPDATE, and DELETE operations. \
387    If this value is specified without units, it is taken as milliseconds.",
388    true,
389);
390
391pub static IDLE_IN_TRANSACTION_SESSION_TIMEOUT: VarDefinition = VarDefinition::new(
392    "idle_in_transaction_session_timeout",
393    value!(Duration; Duration::from_secs(60 * 2)),
394    "Sets the maximum allowed duration that a session can sit idle in a transaction before \
395    being terminated. If this value is specified without units, it is taken as milliseconds. \
396    A value of zero disables the timeout (PostgreSQL).",
397    true,
398);
399
400pub static SERVER_VERSION: VarDefinition = VarDefinition::new_lazy(
401    "server_version",
402    lazy_value!(String; || {
403        format!("{SERVER_MAJOR_VERSION}.{SERVER_MINOR_VERSION}.{SERVER_PATCH_VERSION}")
404    }),
405    "Shows the PostgreSQL compatible server version (PostgreSQL).",
406    true,
407)
408.read_only();
409
410pub static SERVER_VERSION_NUM: VarDefinition = VarDefinition::new(
411    "server_version_num",
412    value!(i32; (cast::u8_to_i32(SERVER_MAJOR_VERSION) * 10_000)
413        + (cast::u8_to_i32(SERVER_MINOR_VERSION) * 100)
414        + cast::u8_to_i32(SERVER_PATCH_VERSION)),
415    "Shows the PostgreSQL compatible server version as an integer (PostgreSQL).",
416    true,
417)
418.read_only();
419
420pub static SQL_SAFE_UPDATES: VarDefinition = VarDefinition::new(
421    "sql_safe_updates",
422    value!(bool; false),
423    "Prohibits SQL statements that may be overly destructive (CockroachDB).",
424    true,
425);
426
427pub static STANDARD_CONFORMING_STRINGS: VarDefinition = VarDefinition::new(
428    "standard_conforming_strings",
429    value!(bool; true),
430    "Causes '...' strings to treat backslashes literally (PostgreSQL).",
431    true,
432)
433.fixed();
434
435pub static TIMEZONE: VarDefinition = VarDefinition::new(
436    // TimeZone has nonstandard capitalization for historical reasons.
437    "TimeZone",
438    value!(TimeZone; TimeZone::UTC),
439    "Sets the time zone for displaying and interpreting time stamps (PostgreSQL).",
440    true,
441);
442
443pub const TRANSACTION_ISOLATION_VAR_NAME: &str = "transaction_isolation";
444pub static TRANSACTION_ISOLATION: VarDefinition = VarDefinition::new(
445    TRANSACTION_ISOLATION_VAR_NAME,
446    value!(IsolationLevel; IsolationLevel::StrictSerializable),
447    "Sets the current transaction's isolation level (PostgreSQL).",
448    true,
449);
450
451pub static MAX_KAFKA_CONNECTIONS: VarDefinition = VarDefinition::new(
452    "max_kafka_connections",
453    value!(u32; 1000),
454    "The maximum number of Kafka connections in the region, across all schemas (Materialize).",
455    true,
456);
457
458pub static MAX_POSTGRES_CONNECTIONS: VarDefinition = VarDefinition::new(
459    "max_postgres_connections",
460    value!(u32; 1000),
461    "The maximum number of PostgreSQL connections in the region, across all schemas (Materialize).",
462    true,
463);
464
465pub static MAX_MYSQL_CONNECTIONS: VarDefinition = VarDefinition::new(
466    "max_mysql_connections",
467    value!(u32; 1000),
468    "The maximum number of MySQL connections in the region, across all schemas (Materialize).",
469    true,
470);
471
472pub static MAX_SQL_SERVER_CONNECTIONS: VarDefinition = VarDefinition::new(
473    "max_sql_server_connections",
474    value!(u32; 1000),
475    "The maximum number of SQL Server connections in the region, across all schemas (Materialize).",
476    true,
477);
478
479pub static MAX_AWS_PRIVATELINK_CONNECTIONS: VarDefinition = VarDefinition::new(
480    "max_aws_privatelink_connections",
481    value!(u32; 0),
482    "The maximum number of AWS PrivateLink connections in the region, across all schemas (Materialize).",
483    true,
484);
485
486pub static MAX_TABLES: VarDefinition = VarDefinition::new(
487    "max_tables",
488    value!(u32; 200),
489    "The maximum number of tables in the region, across all schemas (Materialize).",
490    true,
491);
492
493pub static MAX_SOURCES: VarDefinition = VarDefinition::new(
494    "max_sources",
495    value!(u32; 200),
496    "The maximum number of sources in the region, across all schemas (Materialize).",
497    true,
498);
499
500pub static MAX_SINKS: VarDefinition = VarDefinition::new(
501    "max_sinks",
502    value!(u32; 1000),
503    "The maximum number of sinks in the region, across all schemas (Materialize).",
504    true,
505);
506
507pub static MAX_MATERIALIZED_VIEWS: VarDefinition = VarDefinition::new(
508    "max_materialized_views",
509    value!(u32; 500),
510    "The maximum number of materialized views in the region, across all schemas (Materialize).",
511    true,
512);
513
514pub static MAX_CLUSTERS: VarDefinition = VarDefinition::new(
515    "max_clusters",
516    value!(u32; 25),
517    "The maximum number of clusters in the region (Materialize).",
518    true,
519);
520
521pub static MAX_REPLICAS_PER_CLUSTER: VarDefinition = VarDefinition::new(
522    "max_replicas_per_cluster",
523    value!(u32; 5),
524    "The maximum number of replicas of a single cluster (Materialize).",
525    true,
526);
527
528pub static MAX_CREDIT_CONSUMPTION_RATE: VarDefinition = VarDefinition::new_lazy(
529    "max_credit_consumption_rate",
530    lazy_value!(Numeric; || 1024.into()),
531    "The maximum rate of credit consumption in a region. Credits are consumed based on the size of cluster replicas in use (Materialize).",
532    true,
533)
534.with_constraint(&NUMERIC_NON_NEGATIVE);
535
536pub static MAX_DATABASES: VarDefinition = VarDefinition::new(
537    "max_databases",
538    value!(u32; 1000),
539    "The maximum number of databases in the region (Materialize).",
540    true,
541);
542
543pub static MAX_SCHEMAS_PER_DATABASE: VarDefinition = VarDefinition::new(
544    "max_schemas_per_database",
545    value!(u32; 1000),
546    "The maximum number of schemas in a database (Materialize).",
547    true,
548);
549
550pub static MAX_OBJECTS_PER_SCHEMA: VarDefinition = VarDefinition::new(
551    "max_objects_per_schema",
552    value!(u32; 1000),
553    "The maximum number of objects in a schema (Materialize).",
554    true,
555);
556
557pub static MAX_SECRETS: VarDefinition = VarDefinition::new(
558    "max_secrets",
559    value!(u32; 100),
560    "The maximum number of secrets in the region, across all schemas (Materialize).",
561    true,
562);
563
564pub static MAX_ROLES: VarDefinition = VarDefinition::new(
565    "max_roles",
566    value!(u32; 1000),
567    "The maximum number of roles in the region (Materialize).",
568    true,
569);
570
571pub static MAX_NETWORK_POLICIES: VarDefinition = VarDefinition::new(
572    "max_network_policies",
573    value!(u32; 25),
574    "The maximum number of network policies in the region.",
575    true,
576);
577
578pub static MAX_RULES_PER_NETWORK_POLICY: VarDefinition = VarDefinition::new(
579    "max_rules_per_network_policy",
580    value!(u32; 25),
581    "The maximum number of rules per network policies.",
582    true,
583);
584
585// Cloud environmentd is configured with 4 GiB of RAM, so 1 GiB is a good heuristic for a single
586// query.
587//
588// We constrain this parameter to a minimum of 1MB, to avoid accidental usage of values that will
589// interfere with queries executed by the system itself.
590//
591// TODO(jkosh44) Eventually we want to be able to return arbitrary sized results.
592pub static MAX_RESULT_SIZE: VarDefinition = VarDefinition::new(
593    "max_result_size",
594    value!(ByteSize; ByteSize::gb(1)),
595    "The maximum size in bytes for an internal query result (Materialize).",
596    true,
597)
598.with_constraint(&BYTESIZE_AT_LEAST_1MB);
599
600pub static MAX_QUERY_RESULT_SIZE: VarDefinition = VarDefinition::new(
601    "max_query_result_size",
602    value!(ByteSize; ByteSize::gb(1)),
603    "The maximum size in bytes for a single query's result (Materialize).",
604    true,
605);
606
607pub static MAX_COPY_FROM_ROW_SIZE: VarDefinition = VarDefinition::new(
608    "max_copy_from_row_size",
609    value!(ByteSize; ByteSize::mb(128)),
610    "The maximum size in bytes for a single COPY FROM STDIN row (Materialize).",
611    true,
612);
613
614pub static MAX_IDENTIFIER_LENGTH: VarDefinition = VarDefinition::new(
615    "max_identifier_length",
616    value!(usize; mz_sql_lexer::lexer::MAX_IDENTIFIER_LENGTH),
617    "The maximum length of object identifiers in bytes (PostgreSQL).",
618    true,
619);
620
621pub static WELCOME_MESSAGE: VarDefinition = VarDefinition::new(
622    "welcome_message",
623    value!(bool; true),
624    "Whether to send a notice with a welcome message after a successful connection (Materialize).",
625    true,
626);
627
628/// The logical compaction window for builtin tables and sources that have the
629/// `retained_metrics_relation` flag set.
630///
631/// The existence of this variable is a bit of a hack until we have a fully
632/// general solution for controlling retention windows.
633pub static METRICS_RETENTION: VarDefinition = VarDefinition::new(
634    "metrics_retention",
635    // 30 days
636    value!(Duration; Duration::from_secs(30 * 24 * 60 * 60)),
637    "The time to retain cluster utilization metrics (Materialize).",
638    false,
639);
640
641pub static ALLOWED_CLUSTER_REPLICA_SIZES: VarDefinition = VarDefinition::new(
642    "allowed_cluster_replica_sizes",
643    value!(Vec<Ident>; Vec::new()),
644    "The allowed sizes when creating a new cluster replica (Materialize).",
645    true,
646);
647
648pub static PERSIST_FAST_PATH_LIMIT: VarDefinition = VarDefinition::new(
649    "persist_fast_path_limit",
650    value!(usize; 25),
651    "An exclusive upper bound on the number of results we may return from a Persist fast-path peek; \
652    queries that may return more results will follow the normal / slow path. \
653    Setting this to 0 disables the feature.",
654    false,
655);
656
657/// Controls `mz_adapter::coord::timestamp_oracle::postgres_oracle::DynamicConfig::pg_connection_pool_max_size`.
658pub static PG_TIMESTAMP_ORACLE_CONNECTION_POOL_MAX_SIZE: VarDefinition = VarDefinition::new(
659    "pg_timestamp_oracle_connection_pool_max_size",
660    value!(usize; DEFAULT_PG_TIMESTAMP_ORACLE_CONNPOOL_MAX_SIZE),
661    "Maximum size of the Postgres/CRDB connection pool, used by the Postgres/CRDB timestamp oracle.",
662    false,
663);
664
665/// Controls `mz_adapter::coord::timestamp_oracle::postgres_oracle::DynamicConfig::pg_connection_pool_max_wait`.
666pub static PG_TIMESTAMP_ORACLE_CONNECTION_POOL_MAX_WAIT: VarDefinition = VarDefinition::new(
667    "pg_timestamp_oracle_connection_pool_max_wait",
668    value!(Option<Duration>; Some(DEFAULT_PG_TIMESTAMP_ORACLE_CONNPOOL_MAX_WAIT)),
669    "The maximum time to wait when attempting to obtain a connection from the Postgres/CRDB connection pool, used by the Postgres/CRDB timestamp oracle.",
670    false,
671);
672
673/// Controls `mz_adapter::coord::timestamp_oracle::postgres_oracle::DynamicConfig::pg_connection_pool_ttl`.
674pub static PG_TIMESTAMP_ORACLE_CONNECTION_POOL_TTL: VarDefinition = VarDefinition::new(
675    "pg_timestamp_oracle_connection_pool_ttl",
676    value!(Duration; DEFAULT_PG_TIMESTAMP_ORACLE_CONNPOOL_TTL),
677    "The minimum TTL of a Consensus connection to Postgres/CRDB before it is proactively terminated",
678    false,
679);
680
681/// Controls `mz_adapter::coord::timestamp_oracle::postgres_oracle::DynamicConfig::pg_connection_pool_ttl_stagger`.
682pub static PG_TIMESTAMP_ORACLE_CONNECTION_POOL_TTL_STAGGER: VarDefinition = VarDefinition::new(
683    "pg_timestamp_oracle_connection_pool_ttl_stagger",
684    value!(Duration; DEFAULT_PG_TIMESTAMP_ORACLE_CONNPOOL_TTL_STAGGER),
685    "The minimum time between TTLing Consensus connections to Postgres/CRDB.",
686    false,
687);
688
689pub static UNSAFE_NEW_TRANSACTION_WALL_TIME: VarDefinition = VarDefinition::new(
690    "unsafe_new_transaction_wall_time",
691    value!(Option<CheckedTimestamp<DateTime<Utc>>>; None),
692    "Sets the wall time for all new explicit or implicit transactions to control the value of `now()`. \
693    If not set, uses the system's clock.",
694    // This needs to be true because `user_visible: false` things are only modifiable by the mz_system
695    // and mz_support users, and we want sqllogictest to have access with its user. Because the name
696    // starts with "unsafe" it still won't be visible or changeable by users unless unsafe mode is
697    // enabled.
698    true,
699);
700
701pub static SCRAM_ITERATIONS: VarDefinition = VarDefinition::new(
702    "scram_iterations",
703    // / The default iteration count as suggested by
704    // / <https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html>
705    value!(NonZeroU32; NonZeroU32::new(600_000).unwrap()),
706    "Iterations to use when hashing passwords. Higher iterations are more secure, but take longer to validated. \
707    Please consider the security risks before reducing this below the default value.",
708    true,
709);
710
711/// Tuning for RocksDB used by `UPSERT` sources that takes effect on restart.
712pub mod upsert_rocksdb {
713    use super::*;
714    use mz_rocksdb_types::config::{CompactionStyle, CompressionType};
715
716    pub static UPSERT_ROCKSDB_COMPACTION_STYLE: VarDefinition = VarDefinition::new(
717        "upsert_rocksdb_compaction_style",
718        value!(CompactionStyle; mz_rocksdb_types::defaults::DEFAULT_COMPACTION_STYLE),
719        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
720        sources. Described in the `mz_rocksdb_types::config` module. \
721        Only takes effect on source restart (Materialize).",
722        false,
723    );
724
725    pub static UPSERT_ROCKSDB_OPTIMIZE_COMPACTION_MEMTABLE_BUDGET: VarDefinition =
726        VarDefinition::new(
727            "upsert_rocksdb_optimize_compaction_memtable_budget",
728            value!(usize; mz_rocksdb_types::defaults::DEFAULT_OPTIMIZE_COMPACTION_MEMTABLE_BUDGET),
729            "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
730        sources. Described in the `mz_rocksdb_types::config` module. \
731        Only takes effect on source restart (Materialize).",
732            false,
733        );
734
735    pub static UPSERT_ROCKSDB_LEVEL_COMPACTION_DYNAMIC_LEVEL_BYTES: VarDefinition =
736        VarDefinition::new(
737            "upsert_rocksdb_level_compaction_dynamic_level_bytes",
738            value!(bool; mz_rocksdb_types::defaults::DEFAULT_LEVEL_COMPACTION_DYNAMIC_LEVEL_BYTES),
739            "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
740        sources. Described in the `mz_rocksdb_types::config` module. \
741        Only takes effect on source restart (Materialize).",
742            false,
743        );
744
745    pub static UPSERT_ROCKSDB_UNIVERSAL_COMPACTION_RATIO: VarDefinition = VarDefinition::new(
746        "upsert_rocksdb_universal_compaction_ratio",
747        value!(i32; mz_rocksdb_types::defaults::DEFAULT_UNIVERSAL_COMPACTION_RATIO),
748        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
749        sources. Described in the `mz_rocksdb_types::config` module. \
750        Only takes effect on source restart (Materialize).",
751        false,
752    );
753
754    pub static UPSERT_ROCKSDB_PARALLELISM: VarDefinition = VarDefinition::new(
755        "upsert_rocksdb_parallelism",
756        value!(Option<i32>; mz_rocksdb_types::defaults::DEFAULT_PARALLELISM),
757        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
758        sources. Described in the `mz_rocksdb_types::config` module. \
759        Only takes effect on source restart (Materialize).",
760        false,
761    );
762
763    pub static UPSERT_ROCKSDB_COMPRESSION_TYPE: VarDefinition = VarDefinition::new(
764        "upsert_rocksdb_compression_type",
765        value!(CompressionType; mz_rocksdb_types::defaults::DEFAULT_COMPRESSION_TYPE),
766        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
767        sources. Described in the `mz_rocksdb_types::config` module. \
768        Only takes effect on source restart (Materialize).",
769        false,
770    );
771
772    pub static UPSERT_ROCKSDB_BOTTOMMOST_COMPRESSION_TYPE: VarDefinition = VarDefinition::new(
773        "upsert_rocksdb_bottommost_compression_type",
774        value!(CompressionType; mz_rocksdb_types::defaults::DEFAULT_BOTTOMMOST_COMPRESSION_TYPE),
775        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
776        sources. Described in the `mz_rocksdb_types::config` module. \
777        Only takes effect on source restart (Materialize).",
778        false,
779    );
780
781    pub static UPSERT_ROCKSDB_BATCH_SIZE: VarDefinition = VarDefinition::new(
782        "upsert_rocksdb_batch_size",
783        value!(usize; mz_rocksdb_types::defaults::DEFAULT_BATCH_SIZE),
784        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
785        sources. Described in the `mz_rocksdb_types::config` module. \
786        Can be changed dynamically (Materialize).",
787        false,
788    );
789
790    pub static UPSERT_ROCKSDB_RETRY_DURATION: VarDefinition = VarDefinition::new(
791        "upsert_rocksdb_retry_duration",
792        value!(Duration; mz_rocksdb_types::defaults::DEFAULT_RETRY_DURATION),
793        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
794        sources. Described in the `mz_rocksdb_types::config` module. \
795        Only takes effect on source restart (Materialize).",
796        false,
797    );
798
799    pub static UPSERT_ROCKSDB_STATS_LOG_INTERVAL_SECONDS: VarDefinition = VarDefinition::new(
800        "upsert_rocksdb_stats_log_interval_seconds",
801        value!(u32; mz_rocksdb_types::defaults::DEFAULT_STATS_LOG_INTERVAL_S),
802        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
803        sources. Described in the `mz_rocksdb_types::config` module. \
804        Only takes effect on source restart (Materialize).",
805        false,
806    );
807
808    pub static UPSERT_ROCKSDB_STATS_PERSIST_INTERVAL_SECONDS: VarDefinition = VarDefinition::new(
809        "upsert_rocksdb_stats_persist_interval_seconds",
810        value!(u32; mz_rocksdb_types::defaults::DEFAULT_STATS_PERSIST_INTERVAL_S),
811        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
812        sources. Described in the `mz_rocksdb_types::config` module. \
813        Only takes effect on source restart (Materialize).",
814        false,
815    );
816
817    pub static UPSERT_ROCKSDB_POINT_LOOKUP_BLOCK_CACHE_SIZE_MB: VarDefinition = VarDefinition::new(
818        "upsert_rocksdb_point_lookup_block_cache_size_mb",
819        value!(Option<u32>; None),
820        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
821        sources. Described in the `mz_rocksdb_types::config` module. \
822        Only takes effect on source restart (Materialize).",
823        false,
824    );
825
826    /// The number of times by which allocated buffers will be shrinked in upsert rocksdb.
827    /// If value is 0, then no shrinking will occur.
828    pub static UPSERT_ROCKSDB_SHRINK_ALLOCATED_BUFFERS_BY_RATIO: VarDefinition = VarDefinition::new(
829        "upsert_rocksdb_shrink_allocated_buffers_by_ratio",
830        value!(usize; mz_rocksdb_types::defaults::DEFAULT_SHRINK_BUFFERS_BY_RATIO),
831        "The number of times by which allocated buffers will be shrinked in upsert rocksdb.",
832        false,
833    );
834
835    /// Only used if `upsert_rocksdb_write_buffer_manager_memory_bytes` is also set
836    /// and write buffer manager is enabled
837    pub static UPSERT_ROCKSDB_WRITE_BUFFER_MANAGER_CLUSTER_MEMORY_FRACTION: VarDefinition =
838        VarDefinition::new(
839            "upsert_rocksdb_write_buffer_manager_cluster_memory_fraction",
840            value!(Option<Numeric>; None),
841            "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
842        sources. Described in the `mz_rocksdb_types::config` module. \
843        Only takes effect on source restart (Materialize).",
844            false,
845        );
846
847    /// `upsert_rocksdb_write_buffer_manager_memory_bytes` needs to be set for write buffer manager to be
848    /// used.
849    pub static UPSERT_ROCKSDB_WRITE_BUFFER_MANAGER_MEMORY_BYTES: VarDefinition = VarDefinition::new(
850        "upsert_rocksdb_write_buffer_manager_memory_bytes",
851        value!(Option<usize>; None),
852        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
853        sources. Described in the `mz_rocksdb_types::config` module. \
854        Only takes effect on source restart (Materialize).",
855        false,
856    );
857
858    pub static UPSERT_ROCKSDB_WRITE_BUFFER_MANAGER_ALLOW_STALL: VarDefinition = VarDefinition::new(
859        "upsert_rocksdb_write_buffer_manager_allow_stall",
860        value!(bool; false),
861        "Tuning parameter for RocksDB as used in `UPSERT/DEBEZIUM` \
862        sources. Described in the `mz_rocksdb_types::config` module. \
863        Only takes effect on source restart (Materialize).",
864        false,
865    );
866}
867
868pub static LOGGING_FILTER: VarDefinition = VarDefinition::new_lazy(
869    "log_filter",
870    lazy_value!(CloneableEnvFilter; || CloneableEnvFilter::from_str("info").expect("valid EnvFilter")),
871    "Sets the filter to apply to stderr logging.",
872    false,
873);
874
875pub static OPENTELEMETRY_FILTER: VarDefinition = VarDefinition::new_lazy(
876    "opentelemetry_filter",
877    lazy_value!(CloneableEnvFilter; || CloneableEnvFilter::from_str("info").expect("valid EnvFilter")),
878    "Sets the filter to apply to OpenTelemetry-backed distributed tracing.",
879    false,
880);
881
882pub static LOGGING_FILTER_DEFAULTS: VarDefinition = VarDefinition::new_lazy(
883    "log_filter_defaults",
884    lazy_value!(Vec<SerializableDirective>; || {
885        mz_ore::tracing::LOGGING_DEFAULTS
886            .iter()
887            .map(|d| d.clone().into())
888            .collect()
889    }),
890    "Sets additional default directives to apply to stderr logging. \
891        These apply to all variations of `log_filter`. Directives other than \
892        `module=off` are likely incorrect.",
893    false,
894);
895
896pub static OPENTELEMETRY_FILTER_DEFAULTS: VarDefinition = VarDefinition::new_lazy(
897    "opentelemetry_filter_defaults",
898    lazy_value!(Vec<SerializableDirective>; || {
899        mz_ore::tracing::OPENTELEMETRY_DEFAULTS
900            .iter()
901            .map(|d| d.clone().into())
902            .collect()
903    }),
904    "Sets additional default directives to apply to OpenTelemetry-backed \
905        distributed tracing. \
906        These apply to all variations of `opentelemetry_filter`. Directives other than \
907        `module=off` are likely incorrect.",
908    false,
909);
910
911pub static SENTRY_FILTERS: VarDefinition = VarDefinition::new_lazy(
912    "sentry_filters",
913    lazy_value!(Vec<SerializableDirective>; || {
914        mz_ore::tracing::SENTRY_DEFAULTS
915            .iter()
916            .map(|d| d.clone().into())
917            .collect()
918    }),
919    "Sets additional default directives to apply to sentry logging. \
920        These apply on top of a default `info` directive. Directives other than \
921        `module=off` are likely incorrect.",
922    false,
923);
924
925pub static WEBHOOKS_SECRETS_CACHING_TTL_SECS: VarDefinition = VarDefinition::new_lazy(
926    "webhooks_secrets_caching_ttl_secs",
927    lazy_value!(usize; || {
928        usize::cast_from(mz_secrets::cache::DEFAULT_TTL_SECS)
929    }),
930    "Sets the time-to-live for values in the Webhooks secrets cache.",
931    false,
932);
933
934pub static COORD_SLOW_MESSAGE_WARN_THRESHOLD: VarDefinition = VarDefinition::new(
935    "coord_slow_message_warn_threshold",
936    value!(Duration; Duration::from_secs(30)),
937    "Sets the threshold at which we will error! for a coordinator message being slow.",
938    false,
939);
940
941/// Controls the connect_timeout setting when connecting to PG via `mz_postgres_util`.
942pub static PG_SOURCE_CONNECT_TIMEOUT: VarDefinition = VarDefinition::new(
943    "pg_source_connect_timeout",
944    value!(Duration; DEFAULT_PG_SOURCE_CONNECT_TIMEOUT),
945    "Sets the timeout applied to socket-level connection attempts for PG \
946    replication connections (Materialize).",
947    false,
948);
949
950/// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection
951/// when connecting to PG via `mz_postgres_util`.
952pub static PG_SOURCE_TCP_KEEPALIVES_RETRIES: VarDefinition = VarDefinition::new(
953    "pg_source_tcp_keepalives_retries",
954    value!(u32; DEFAULT_PG_SOURCE_TCP_KEEPALIVES_RETRIES),
955    "Sets the maximum number of TCP keepalive probes that will be sent before dropping \
956    a connection when connecting to PG via `mz_postgres_util` (Materialize).",
957    false,
958);
959
960/// Sets the amount of idle time before a keepalive packet is sent on the connection when connecting
961/// to PG via `mz_postgres_util`.
962pub static PG_SOURCE_TCP_KEEPALIVES_IDLE: VarDefinition = VarDefinition::new(
963    "pg_source_tcp_keepalives_idle",
964    value!(Duration; DEFAULT_PG_SOURCE_TCP_KEEPALIVES_IDLE),
965    "Sets the amount of idle time before a keepalive packet is sent on the connection \
966        when connecting to PG via `mz_postgres_util` (Materialize).",
967    false,
968);
969
970/// Sets the time interval between TCP keepalive probes when connecting to PG via `mz_postgres_util`.
971pub static PG_SOURCE_TCP_KEEPALIVES_INTERVAL: VarDefinition = VarDefinition::new(
972    "pg_source_tcp_keepalives_interval",
973    value!(Duration; DEFAULT_PG_SOURCE_TCP_KEEPALIVES_INTERVAL),
974    "Sets the time interval between TCP keepalive probes when connecting to PG via \
975        replication (Materialize).",
976    false,
977);
978
979/// Sets the TCP user timeout when connecting to PG via `mz_postgres_util`.
980pub static PG_SOURCE_TCP_USER_TIMEOUT: VarDefinition = VarDefinition::new(
981    "pg_source_tcp_user_timeout",
982    value!(Duration; DEFAULT_PG_SOURCE_TCP_USER_TIMEOUT),
983    "Sets the TCP user timeout when connecting to PG via `mz_postgres_util` (Materialize).",
984    false,
985);
986
987/// Sets whether to apply the TCP configuration parameters on the server when
988/// connecting to PG via `mz_postgres_util`.
989pub static PG_SOURCE_TCP_CONFIGURE_SERVER: VarDefinition = VarDefinition::new(
990    "pg_source_tcp_configure_server",
991    value!(bool; DEFAULT_PG_SOURCE_TCP_CONFIGURE_SERVER),
992    "Sets whether to apply the TCP configuration parameters on the server when connecting to PG via `mz_postgres_util` (Materialize).",
993    false,
994);
995
996/// Sets the `statement_timeout` value to use during the snapshotting phase of
997/// PG sources.
998pub static PG_SOURCE_SNAPSHOT_STATEMENT_TIMEOUT: VarDefinition = VarDefinition::new(
999    "pg_source_snapshot_statement_timeout",
1000    value!(Duration; mz_postgres_util::DEFAULT_SNAPSHOT_STATEMENT_TIMEOUT),
1001    "Sets the `statement_timeout` value to use during the snapshotting phase of PG sources (Materialize)",
1002    false,
1003);
1004
1005/// Sets the `wal_sender_timeout` value to use during the replication phase of
1006/// PG sources.
1007pub static PG_SOURCE_WAL_SENDER_TIMEOUT: VarDefinition = VarDefinition::new(
1008    "pg_source_wal_sender_timeout",
1009    value!(Option<Duration>; DEFAULT_PG_SOURCE_WAL_SENDER_TIMEOUT),
1010    "Sets the `wal_sender_timeout` value to use during the replication phase of PG sources (Materialize)",
1011    false,
1012);
1013
1014/// Please see `PgSourceSnapshotConfig`.
1015pub static PG_SOURCE_SNAPSHOT_COLLECT_STRICT_COUNT: VarDefinition = VarDefinition::new(
1016    "pg_source_snapshot_collect_strict_count",
1017    value!(bool; mz_storage_types::parameters::PgSourceSnapshotConfig::new().collect_strict_count),
1018    "Please see <https://dev.materialize.com/api/rust-private\
1019        /mz_storage_types/parameters\
1020        /struct.PgSourceSnapshotConfig.html#structfield.collect_strict_count>",
1021    false,
1022);
1023
1024/// Sets the time between TCP keepalive probes when connecting to MySQL via `mz_mysql_util`.
1025pub static MYSQL_SOURCE_TCP_KEEPALIVE: VarDefinition = VarDefinition::new(
1026    "mysql_source_tcp_keepalive",
1027    value!(Duration; mz_mysql_util::DEFAULT_TCP_KEEPALIVE),
1028    "Sets the time between TCP keepalive probes when connecting to MySQL",
1029    false,
1030);
1031
1032/// Sets the `max_execution_time` value to use during the snapshotting phase of
1033/// MySQL sources.
1034pub static MYSQL_SOURCE_SNAPSHOT_MAX_EXECUTION_TIME: VarDefinition = VarDefinition::new(
1035    "mysql_source_snapshot_max_execution_time",
1036    value!(Duration; mz_mysql_util::DEFAULT_SNAPSHOT_MAX_EXECUTION_TIME),
1037    "Sets the `max_execution_time` value to use during the snapshotting phase of MySQL sources (Materialize)",
1038    false,
1039);
1040
1041/// Sets the `lock_wait_timeout` value to use during the snapshotting phase of
1042/// MySQL sources.
1043pub static MYSQL_SOURCE_SNAPSHOT_LOCK_WAIT_TIMEOUT: VarDefinition = VarDefinition::new(
1044    "mysql_source_snapshot_lock_wait_timeout",
1045    value!(Duration; mz_mysql_util::DEFAULT_SNAPSHOT_LOCK_WAIT_TIMEOUT),
1046    "Sets the `lock_wait_timeout` value to use during the snapshotting phase of MySQL sources (Materialize)",
1047    false,
1048);
1049
1050/// Sets the `wait_timeout` session value on connections used during the
1051/// snapshotting phase of MySQL sources.
1052pub static MYSQL_SOURCE_SNAPSHOT_WAIT_TIMEOUT: VarDefinition = VarDefinition::new(
1053    "mysql_source_snapshot_wait_timeout",
1054    value!(Duration; mz_mysql_util::DEFAULT_SNAPSHOT_WAIT_TIMEOUT),
1055    "Sets the `wait_timeout` value to use on connections during the snapshotting phase of MySQL sources (Materialize)",
1056    false,
1057);
1058
1059/// Sets the timeout for establishing an authenticated connection to MySQL
1060pub static MYSQL_SOURCE_CONNECT_TIMEOUT: VarDefinition = VarDefinition::new(
1061    "mysql_source_connect_timeout",
1062    value!(Duration; mz_mysql_util::DEFAULT_CONNECT_TIMEOUT),
1063    "Sets the timeout for establishing an authenticated connection to MySQL",
1064    false,
1065);
1066
1067/// Controls the check interval for connections to SSH bastions via `mz_ssh_util`.
1068pub static SSH_CHECK_INTERVAL: VarDefinition = VarDefinition::new(
1069    "ssh_check_interval",
1070    value!(Duration; mz_ssh_util::tunnel::DEFAULT_CHECK_INTERVAL),
1071    "Controls the check interval for connections to SSH bastions via `mz_ssh_util`.",
1072    false,
1073)
1074.with_constraint(&NON_ZERO_DURATION);
1075
1076/// Controls the connect timeout for connections to SSH bastions via `mz_ssh_util`.
1077pub static SSH_CONNECT_TIMEOUT: VarDefinition = VarDefinition::new(
1078    "ssh_connect_timeout",
1079    value!(Duration; mz_ssh_util::tunnel::DEFAULT_CONNECT_TIMEOUT),
1080    "Controls the connect timeout for connections to SSH bastions via `mz_ssh_util`.",
1081    false,
1082);
1083
1084/// Controls the keepalive idle interval for connections to SSH bastions via `mz_ssh_util`.
1085pub static SSH_KEEPALIVES_IDLE: VarDefinition = VarDefinition::new(
1086    "ssh_keepalives_idle",
1087    value!(Duration; mz_ssh_util::tunnel::DEFAULT_KEEPALIVES_IDLE),
1088    "Controls the keepalive idle interval for connections to SSH bastions via `mz_ssh_util`.",
1089    false,
1090);
1091
1092/// Enables `socket.keepalive.enable` for rdkafka client connections. Defaults to true.
1093pub static KAFKA_SOCKET_KEEPALIVE: VarDefinition = VarDefinition::new(
1094    "kafka_socket_keepalive",
1095    value!(bool; mz_kafka_util::client::DEFAULT_KEEPALIVE),
1096    "Enables `socket.keepalive.enable` for rdkafka client connections. Defaults to true.",
1097    false,
1098);
1099
1100/// Controls `socket.timeout.ms` for rdkafka client connections. Defaults to the rdkafka default
1101/// (60000ms). Cannot be greater than 300000ms, more than 100ms greater than
1102/// `kafka_transaction_timeout`, or less than 10ms.
1103pub static KAFKA_SOCKET_TIMEOUT: VarDefinition = VarDefinition::new(
1104    "kafka_socket_timeout",
1105    value!(Option<Duration>; None),
1106    "Controls `socket.timeout.ms` for rdkafka \
1107        client connections. Defaults to the rdkafka default (60000ms) or \
1108        the set transaction timeout + 100ms, whichever one is smaller. \
1109        Cannot be greater than 300000ms, more than 100ms greater than \
1110        `kafka_transaction_timeout`, or less than 10ms.",
1111    false,
1112);
1113
1114/// Controls `transaction.timeout.ms` for rdkafka client connections. Defaults to the rdkafka default
1115/// (60000ms). Cannot be greater than `i32::MAX` or less than 1000ms.
1116pub static KAFKA_TRANSACTION_TIMEOUT: VarDefinition = VarDefinition::new(
1117    "kafka_transaction_timeout",
1118    value!(Duration; mz_kafka_util::client::DEFAULT_TRANSACTION_TIMEOUT),
1119    "Controls `transaction.timeout.ms` for rdkafka \
1120        client connections. Defaults to the 10min. \
1121        Cannot be greater than `i32::MAX` or less than 1000ms.",
1122    false,
1123);
1124
1125/// Controls `socket.connection.setup.timeout.ms` for rdkafka client connections. Defaults to the rdkafka default
1126/// (30000ms). Cannot be greater than `i32::MAX` or less than 1000ms
1127pub static KAFKA_SOCKET_CONNECTION_SETUP_TIMEOUT: VarDefinition = VarDefinition::new(
1128    "kafka_socket_connection_setup_timeout",
1129    value!(Duration; mz_kafka_util::client::DEFAULT_SOCKET_CONNECTION_SETUP_TIMEOUT),
1130    "Controls `socket.connection.setup.timeout.ms` for rdkafka \
1131        client connections. Defaults to the rdkafka default (30000ms). \
1132        Cannot be greater than `i32::MAX` or less than 1000ms",
1133    false,
1134);
1135
1136/// Controls the timeout when fetching kafka metadata. Defaults to 10s.
1137pub static KAFKA_FETCH_METADATA_TIMEOUT: VarDefinition = VarDefinition::new(
1138    "kafka_fetch_metadata_timeout",
1139    value!(Duration; mz_kafka_util::client::DEFAULT_FETCH_METADATA_TIMEOUT),
1140    "Controls the timeout when fetching kafka metadata. \
1141        Defaults to 10s.",
1142    false,
1143);
1144
1145/// Controls the timeout when fetching kafka progress records. Defaults to 60s.
1146pub static KAFKA_PROGRESS_RECORD_FETCH_TIMEOUT: VarDefinition = VarDefinition::new(
1147    "kafka_progress_record_fetch_timeout",
1148    value!(Option<Duration>; None),
1149    "Controls the timeout when fetching kafka progress records. \
1150        Defaults to 60s or the transaction timeout, whichever one is larger.",
1151    false,
1152);
1153
1154/// The maximum number of in-flight bytes emitted by persist_sources feeding _storage
1155/// dataflows_.
1156/// Currently defaults to 256MiB = 268435456 bytes
1157/// Note: Backpressure will only be turned on if disk is enabled based on
1158/// `storage_dataflow_max_inflight_bytes_disk_only` flag
1159pub static STORAGE_DATAFLOW_MAX_INFLIGHT_BYTES: VarDefinition = VarDefinition::new(
1160    "storage_dataflow_max_inflight_bytes",
1161    value!(Option<usize>; Some(256 * 1024 * 1024)),
1162    "The maximum number of in-flight bytes emitted by persist_sources feeding \
1163        storage dataflows. Defaults to backpressure enabled (Materialize).",
1164    false,
1165);
1166
1167/// Configuration ratio to shrink unusef buffers in upsert by.
1168/// For eg: is 2 is set, then the buffers will be reduced by 2 i.e. halved.
1169/// Default is 0, which means shrinking is disabled.
1170pub static STORAGE_SHRINK_UPSERT_UNUSED_BUFFERS_BY_RATIO: VarDefinition = VarDefinition::new(
1171    "storage_shrink_upsert_unused_buffers_by_ratio",
1172    value!(usize; 0),
1173    "Configuration ratio to shrink unusef buffers in upsert by",
1174    false,
1175);
1176
1177/// The fraction of the cluster replica size to be used as the maximum number of
1178/// in-flight bytes emitted by persist_sources feeding storage dataflows.
1179/// If not configured, the storage_dataflow_max_inflight_bytes value will be used.
1180/// For this value to be used storage_dataflow_max_inflight_bytes needs to be set.
1181pub static STORAGE_DATAFLOW_MAX_INFLIGHT_BYTES_TO_CLUSTER_SIZE_FRACTION: VarDefinition =
1182    VarDefinition::new_lazy(
1183        "storage_dataflow_max_inflight_bytes_to_cluster_size_fraction",
1184        lazy_value!(Option<Numeric>; || Some(0.01.into())),
1185        "The fraction of the cluster replica size to be used as the maximum number of \
1186            in-flight bytes emitted by persist_sources feeding storage dataflows. \
1187            If not configured, the storage_dataflow_max_inflight_bytes value will be used.",
1188        false,
1189    );
1190
1191pub static STORAGE_DATAFLOW_MAX_INFLIGHT_BYTES_DISK_ONLY: VarDefinition = VarDefinition::new(
1192    "storage_dataflow_max_inflight_bytes_disk_only",
1193    value!(bool; true),
1194    "Whether or not `storage_dataflow_max_inflight_bytes` applies only to \
1195        upsert dataflows using disks. Defaults to true (Materialize).",
1196    false,
1197);
1198
1199/// The interval to submit statistics to `mz_source_statistics_per_worker` and `mz_sink_statistics_per_worker`.
1200pub static STORAGE_STATISTICS_INTERVAL: VarDefinition = VarDefinition::new(
1201    "storage_statistics_interval",
1202    value!(Duration; mz_storage_types::parameters::STATISTICS_INTERVAL_DEFAULT),
1203    "The interval to submit statistics to `mz_source_statistics_per_worker` \
1204        and `mz_sink_statistics` (Materialize).",
1205    false,
1206)
1207.with_constraint(&NON_ZERO_DURATION);
1208
1209/// The interval to collect statistics for `mz_source_statistics_per_worker` and `mz_sink_statistics_per_worker` in
1210/// clusterd. Controls the accuracy of metrics.
1211pub static STORAGE_STATISTICS_COLLECTION_INTERVAL: VarDefinition = VarDefinition::new(
1212    "storage_statistics_collection_interval",
1213    value!(Duration; mz_storage_types::parameters::STATISTICS_COLLECTION_INTERVAL_DEFAULT),
1214    "The interval to collect statistics for `mz_source_statistics_per_worker` \
1215        and `mz_sink_statistics_per_worker` in clusterd. Controls the accuracy of metrics \
1216        (Materialize).",
1217    false,
1218);
1219
1220pub static STORAGE_RECORD_SOURCE_SINK_NAMESPACED_ERRORS: VarDefinition = VarDefinition::new(
1221    "storage_record_source_sink_namespaced_errors",
1222    value!(bool; true),
1223    "Whether or not to record namespaced errors in the status history tables",
1224    false,
1225);
1226
1227/// Boolean flag indicating whether to enable syncing from
1228/// LaunchDarkly. Can be turned off as an emergency measure to still
1229/// be able to alter parameters while LD is broken.
1230pub static ENABLE_LAUNCHDARKLY: VarDefinition = VarDefinition::new(
1231    "enable_launchdarkly",
1232    value!(bool; true),
1233    "Boolean flag indicating whether flag synchronization from LaunchDarkly should be enabled (Materialize).",
1234    false,
1235);
1236
1237/// Feature flag indicating whether real time recency is enabled. Not that
1238/// unlike other feature flags, this is made available at the session level, so
1239/// is additionally gated by a feature flag.
1240pub static REAL_TIME_RECENCY: VarDefinition = VarDefinition::new(
1241    "real_time_recency",
1242    value!(bool; false),
1243    "Feature flag indicating whether real time recency is enabled (Materialize).",
1244    true,
1245)
1246.with_feature_flag(&ALLOW_REAL_TIME_RECENCY);
1247
1248pub static REAL_TIME_RECENCY_TIMEOUT: VarDefinition = VarDefinition::new(
1249    "real_time_recency_timeout",
1250    value!(Duration; Duration::from_secs(10)),
1251    "Sets the maximum allowed duration of SELECTs that actively use real-time \
1252    recency, i.e. reach out to an external system to determine their most recencly exposed \
1253    data (Materialize).",
1254    true,
1255)
1256.with_feature_flag(&ALLOW_REAL_TIME_RECENCY);
1257
1258pub static EMIT_PLAN_INSIGHTS_NOTICE: VarDefinition = VarDefinition::new(
1259    "emit_plan_insights_notice",
1260    value!(bool; false),
1261    "Boolean flag indicating whether to send a NOTICE with JSON-formatted plan insights before executing a SELECT statement (Materialize).",
1262    true,
1263);
1264
1265pub static EMIT_TIMESTAMP_NOTICE: VarDefinition = VarDefinition::new(
1266    "emit_timestamp_notice",
1267    value!(bool; false),
1268    "Boolean flag indicating whether to send a NOTICE with timestamp explanations of queries (Materialize).",
1269    true,
1270);
1271
1272pub static EMIT_TRACE_ID_NOTICE: VarDefinition = VarDefinition::new(
1273    "emit_trace_id_notice",
1274    value!(bool; false),
1275    "Boolean flag indicating whether to send a NOTICE specifying the trace id when available (Materialize).",
1276    true,
1277);
1278
1279pub static UNSAFE_MOCK_AUDIT_EVENT_TIMESTAMP: VarDefinition = VarDefinition::new(
1280    "unsafe_mock_audit_event_timestamp",
1281    value!(Option<mz_repr::Timestamp>; None),
1282    "Mocked timestamp to use for audit events for testing purposes",
1283    false,
1284);
1285
1286pub static ENABLE_RBAC_CHECKS: VarDefinition = VarDefinition::new(
1287    "enable_rbac_checks",
1288    value!(bool; true),
1289    "User facing global boolean flag indicating whether to apply RBAC checks before \
1290        executing statements (Materialize).",
1291    true,
1292);
1293
1294pub static ENABLE_SESSION_RBAC_CHECKS: VarDefinition = VarDefinition::new(
1295    "enable_session_rbac_checks",
1296    // TODO(jkosh44) Once RBAC is enabled in all environments, change this to `true`.
1297    value!(bool; false),
1298    "User facing session boolean flag indicating whether to apply RBAC checks before \
1299        executing statements (Materialize).",
1300    true,
1301);
1302
1303pub static RESTRICT_TO_USER_OBJECTS: VarDefinition = VarDefinition::new(
1304    "restrict_to_user_objects",
1305    value!(bool; false),
1306    "When enabled, queries are restricted from accessing system catalog objects. \
1307        Useful for MCP tool queries that should only access user-created data products.",
1308    true,
1309);
1310
1311pub static EMIT_INTROSPECTION_QUERY_NOTICE: VarDefinition = VarDefinition::new(
1312    "emit_introspection_query_notice",
1313    value!(bool; true),
1314    "Whether to print a notice when querying per-replica introspection sources.",
1315    true,
1316);
1317
1318// TODO(mgree) change this to a SelectOption
1319pub static ENABLE_SESSION_CARDINALITY_ESTIMATES: VarDefinition = VarDefinition::new(
1320    "enable_session_cardinality_estimates",
1321    value!(bool; false),
1322    "Feature flag indicating whether to use cardinality estimates when optimizing queries; \
1323        does not affect EXPLAIN WITH(cardinality) (Materialize).",
1324    true,
1325)
1326.with_feature_flag(&ENABLE_CARDINALITY_ESTIMATES);
1327
1328pub static OPTIMIZER_STATS_TIMEOUT: VarDefinition = VarDefinition::new(
1329    "optimizer_stats_timeout",
1330    value!(Duration; Duration::from_millis(250)),
1331    "Sets the timeout applied to the optimizer's statistics collection from storage; \
1332        applied to non-oneshot, i.e., long-lasting queries, like CREATE MATERIALIZED VIEW (Materialize).",
1333    false,
1334);
1335
1336pub static OPTIMIZER_ONESHOT_STATS_TIMEOUT: VarDefinition = VarDefinition::new(
1337    "optimizer_oneshot_stats_timeout",
1338    value!(Duration; Duration::from_millis(10)),
1339    "Sets the timeout applied to the optimizer's statistics collection from storage; \
1340        applied to oneshot queries, like SELECT (Materialize).",
1341    false,
1342);
1343
1344pub static PRIVATELINK_STATUS_UPDATE_QUOTA_PER_MINUTE: VarDefinition = VarDefinition::new(
1345    "privatelink_status_update_quota_per_minute",
1346    value!(u32; 20),
1347    "Sets the per-minute quota for privatelink vpc status updates to be written to \
1348        the storage-collection-backed system table. This value implies the total and burst quota per-minute.",
1349    false,
1350);
1351
1352pub static STATEMENT_LOGGING_SAMPLE_RATE: VarDefinition = VarDefinition::new_lazy(
1353    "statement_logging_sample_rate",
1354    lazy_value!(Numeric; || 0.1.into()),
1355    "User-facing session variable indicating how many statement executions should be \
1356        logged, subject to constraint by the system variable `statement_logging_max_sample_rate` (Materialize).",
1357    true,
1358).with_constraint(&NUMERIC_BOUNDED_0_1_INCLUSIVE);
1359
1360pub static ENABLE_DEFAULT_CONNECTION_VALIDATION: VarDefinition = VarDefinition::new(
1361    "enable_default_connection_validation",
1362    value!(bool; true),
1363    "LD facing global boolean flag that allows turning default connection validation off for everyone (Materialize).",
1364    false,
1365);
1366
1367pub static STATEMENT_LOGGING_MAX_DATA_CREDIT: VarDefinition = VarDefinition::new(
1368    "statement_logging_max_data_credit",
1369    value!(Option<usize>; Some(50 * 1024 * 1024)),
1370    // The idea is that during periods of low logging, tokens can accumulate up to this value,
1371    // and then be depleted during periods of high logging.
1372    "The maximum number of bytes that can be logged for statement logging in short burts, or NULL if unlimited (Materialize).",
1373    false,
1374);
1375
1376pub static STATEMENT_LOGGING_TARGET_DATA_RATE: VarDefinition = VarDefinition::new(
1377    "statement_logging_target_data_rate",
1378    value!(Option<usize>; Some(2071)),
1379    "The maximum sustained data rate of statement logging, in bytes per second, or NULL if unlimited (Materialize).",
1380    false,
1381);
1382
1383pub static STATEMENT_LOGGING_MAX_SAMPLE_RATE: VarDefinition = VarDefinition::new_lazy(
1384    "statement_logging_max_sample_rate",
1385    lazy_value!(Numeric; || 0.99.into()),
1386    "The maximum rate at which statements may be logged. If this value is less than \
1387        that of `statement_logging_sample_rate`, the latter is ignored (Materialize).",
1388    true,
1389)
1390.with_constraint(&NUMERIC_BOUNDED_0_1_INCLUSIVE);
1391
1392pub static STATEMENT_LOGGING_DEFAULT_SAMPLE_RATE: VarDefinition = VarDefinition::new_lazy(
1393    "statement_logging_default_sample_rate",
1394    lazy_value!(Numeric; || 0.99.into()),
1395    "The default value of `statement_logging_sample_rate` for new sessions (Materialize).",
1396    true,
1397)
1398.with_constraint(&NUMERIC_BOUNDED_0_1_INCLUSIVE);
1399
1400pub static ENABLE_INTERNAL_STATEMENT_LOGGING: VarDefinition = VarDefinition::new(
1401    "enable_internal_statement_logging",
1402    value!(bool; false),
1403    "Whether to log statements from the `mz_system` user.",
1404    false,
1405);
1406
1407/// When on, the SQL frontends log incoming statements and other frontend
1408/// messages at info level as soon as they arrive, before processing them
1409/// (except that SQL text is parsed, for redaction). Messages consumed by
1410/// pgwire's COPY subprotocol or its post-error drain loop are not logged.
1411///
1412/// This is an emergency diagnostic for statements that crash the process
1413/// before they reach the statement log (or before its contents are written
1414/// out to persist). It adds a lot of log volume, so use it only in emergencies,
1415/// i.e. to debug active incidents.
1416///
1417/// SQL text is logged with its literals redacted, which is the same redaction
1418/// the statement log applies, see `redact_sql_for_logging`.
1419pub static ENABLE_STATEMENT_ARRIVAL_LOGGING: VarDefinition = VarDefinition::new(
1420    "enable_statement_arrival_logging",
1421    value!(bool; false),
1422    "Whether to log incoming statements and other frontend messages at info \
1423    level as they arrive at the SQL frontends, before processing. SQL text is \
1424    logged with its literals redacted, as in the statement log. Use it only in \
1425    emergencies, i.e. debugging active incidents.",
1426    false,
1427);
1428
1429pub static AUTO_ROUTE_CATALOG_QUERIES: VarDefinition = VarDefinition::new(
1430    "auto_route_catalog_queries",
1431    value!(bool; true),
1432    "Whether to force queries that depend only on system tables, to run on the mz_catalog_server cluster (Materialize).",
1433    true,
1434);
1435
1436pub static MAX_CONNECTIONS: VarDefinition = VarDefinition::new(
1437    "max_connections",
1438    value!(u32; 5000),
1439    "The maximum number of concurrent connections (PostgreSQL).",
1440    true,
1441);
1442
1443pub static SUPERUSER_RESERVED_CONNECTIONS: VarDefinition = VarDefinition::new(
1444    "superuser_reserved_connections",
1445    value!(u32; 3),
1446    "The number of connections that are reserved for superusers (PostgreSQL).",
1447    true,
1448);
1449
1450/// Controls [`mz_storage_types::parameters::StorageParameters::keep_n_source_status_history_entries`].
1451pub static KEEP_N_SOURCE_STATUS_HISTORY_ENTRIES: VarDefinition = VarDefinition::new(
1452    "keep_n_source_status_history_entries",
1453    value!(usize; 5),
1454    "On reboot, truncate all but the last n entries per ID in the source_status_history collection (Materialize).",
1455    false,
1456);
1457
1458/// Controls [`mz_storage_types::parameters::StorageParameters::keep_n_sink_status_history_entries`].
1459pub static KEEP_N_SINK_STATUS_HISTORY_ENTRIES: VarDefinition = VarDefinition::new(
1460    "keep_n_sink_status_history_entries",
1461    value!(usize; 5),
1462    "On reboot, truncate all but the last n entries per ID in the sink_status_history collection (Materialize).",
1463    false,
1464);
1465
1466/// Controls [`mz_storage_types::parameters::StorageParameters::keep_n_privatelink_status_history_entries`].
1467pub static KEEP_N_PRIVATELINK_STATUS_HISTORY_ENTRIES: VarDefinition = VarDefinition::new(
1468    "keep_n_privatelink_status_history_entries",
1469    value!(usize; 5),
1470    "On reboot, truncate all but the last n entries per ID in the mz_aws_privatelink_connection_status_history \
1471        collection (Materialize).",
1472    false,
1473);
1474
1475/// Controls [`mz_storage_types::parameters::StorageParameters::replica_status_history_retention_window`].
1476pub static REPLICA_STATUS_HISTORY_RETENTION_WINDOW: VarDefinition = VarDefinition::new(
1477    "replica_status_history_retention_window",
1478    value!(Duration; REPLICA_STATUS_HISTORY_RETENTION_WINDOW_DEFAULT),
1479    "On reboot, truncate up all entries past the retention window in the mz_cluster_replica_status_history \
1480        collection (Materialize).",
1481    false,
1482);
1483
1484pub static ENABLE_STORAGE_SHARD_FINALIZATION: VarDefinition = VarDefinition::new(
1485    "enable_storage_shard_finalization",
1486    value!(bool; true),
1487    "Whether to allow the storage client to finalize shards (Materialize).",
1488    false,
1489);
1490
1491pub static DEFAULT_TIMESTAMP_INTERVAL: VarDefinition = VarDefinition::new(
1492    "default_timestamp_interval",
1493    value!(Duration; Duration::from_millis(1000)),
1494    "The interval at which timestamps are assigned to data from sources and tables.",
1495    false,
1496)
1497.with_constraint(&NON_ZERO_DURATION);
1498
1499pub static MIN_TIMESTAMP_INTERVAL: VarDefinition = VarDefinition::new(
1500    "min_timestamp_interval",
1501    value!(Duration; Duration::from_millis(1000)),
1502    "Minimum timestamp interval",
1503    false,
1504);
1505
1506pub static MAX_TIMESTAMP_INTERVAL: VarDefinition = VarDefinition::new(
1507    "max_timestamp_interval",
1508    value!(Duration; Duration::from_millis(1000)),
1509    "Maximum timestamp interval",
1510    false,
1511);
1512
1513pub static WEBHOOK_CONCURRENT_REQUEST_LIMIT: VarDefinition = VarDefinition::new(
1514    "webhook_concurrent_request_limit",
1515    value!(usize; WEBHOOK_CONCURRENCY_LIMIT),
1516    "Maximum number of concurrent requests for appending to a webhook source.",
1517    false,
1518);
1519
1520pub static USER_STORAGE_MANAGED_COLLECTIONS_BATCH_DURATION: VarDefinition = VarDefinition::new(
1521    "user_storage_managed_collections_batch_duration",
1522    value!(Duration; STORAGE_MANAGED_COLLECTIONS_BATCH_DURATION_DEFAULT),
1523    "Duration which we'll wait to collect a batch of events for a webhook source.",
1524    false,
1525);
1526
1527// This system var will need to point to the name of an existing network policy
1528// this will be enforced on alter_system_set
1529pub static NETWORK_POLICY: VarDefinition = VarDefinition::new_lazy(
1530    "network_policy",
1531    lazy_value!(String; || "default".to_string()),
1532    "Sets the fallback network policy applied to all users without an explicit policy.",
1533    true,
1534);
1535
1536pub static FORCE_SOURCE_TABLE_SYNTAX: VarDefinition = VarDefinition::new(
1537    "force_source_table_syntax",
1538    value!(bool; false),
1539    "Force use of new source model (CREATE TABLE .. FROM SOURCE) and migrate existing sources",
1540    true,
1541);
1542
1543pub static OPTIMIZER_E2E_LATENCY_WARNING_THRESHOLD: VarDefinition = VarDefinition::new(
1544    "optimizer_e2e_latency_warning_threshold",
1545    value!(Duration; Duration::from_millis(500)),
1546    "Sets the duration that a query can take to compile; queries that take longer \
1547        will trigger a warning. If this value is specified without units, it is taken as \
1548        milliseconds. A value of zero disables the timeout (Materialize).",
1549    true,
1550);
1551
1552/// Configuration for gRPC client connections.
1553pub mod grpc_client {
1554    use super::*;
1555
1556    pub static CONNECT_TIMEOUT: VarDefinition = VarDefinition::new(
1557        "grpc_client_connect_timeout",
1558        value!(Duration; Duration::from_secs(5)),
1559        "Timeout to apply to initial gRPC client connection establishment.",
1560        false,
1561    );
1562
1563    pub static HTTP2_KEEP_ALIVE_INTERVAL: VarDefinition = VarDefinition::new(
1564        "grpc_client_http2_keep_alive_interval",
1565        value!(Duration; Duration::from_secs(3)),
1566        "Idle time to wait before sending HTTP/2 PINGs to maintain established gRPC client connections.",
1567        false,
1568    );
1569
1570    pub static HTTP2_KEEP_ALIVE_TIMEOUT: VarDefinition = VarDefinition::new(
1571        "grpc_client_http2_keep_alive_timeout",
1572        value!(Duration; Duration::from_secs(60)),
1573        "Time to wait for HTTP/2 pong response before terminating a gRPC client connection.",
1574        false,
1575    );
1576}
1577
1578/// Configuration for how cluster replicas are scheduled.
1579pub mod cluster_scheduling {
1580    use super::*;
1581    use mz_orchestrator::scheduling_config::*;
1582
1583    pub static CLUSTER_MULTI_PROCESS_REPLICA_AZ_AFFINITY_WEIGHT: VarDefinition = VarDefinition::new(
1584        "cluster_multi_process_replica_az_affinity_weight",
1585        value!(Option<i32>; DEFAULT_POD_AZ_AFFINITY_WEIGHT),
1586        "Whether or not to add an availability zone affinity between instances of \
1587            multi-process replicas. Either an affinity weight or empty (off) (Materialize).",
1588        false,
1589    );
1590
1591    pub static CLUSTER_SOFTEN_REPLICATION_ANTI_AFFINITY: VarDefinition = VarDefinition::new(
1592        "cluster_soften_replication_anti_affinity",
1593        value!(bool; DEFAULT_SOFTEN_REPLICATION_ANTI_AFFINITY),
1594        "Whether or not to turn the node-scope anti affinity between replicas \
1595            in the same cluster into a preference (Materialize).",
1596        false,
1597    );
1598
1599    pub static CLUSTER_SOFTEN_REPLICATION_ANTI_AFFINITY_WEIGHT: VarDefinition = VarDefinition::new(
1600        "cluster_soften_replication_anti_affinity_weight",
1601        value!(i32; DEFAULT_SOFTEN_REPLICATION_ANTI_AFFINITY_WEIGHT),
1602        "The preference weight for `cluster_soften_replication_anti_affinity` (Materialize).",
1603        false,
1604    );
1605
1606    pub static CLUSTER_ENABLE_TOPOLOGY_SPREAD: VarDefinition = VarDefinition::new(
1607        "cluster_enable_topology_spread",
1608        value!(bool; DEFAULT_TOPOLOGY_SPREAD_ENABLED),
1609        "Whether or not to add topology spread constraints among replicas in the same cluster (Materialize).",
1610        false,
1611    );
1612
1613    pub static CLUSTER_TOPOLOGY_SPREAD_IGNORE_NON_SINGULAR_SCALE: VarDefinition =
1614        VarDefinition::new(
1615            "cluster_topology_spread_ignore_non_singular_scale",
1616            value!(bool; DEFAULT_TOPOLOGY_SPREAD_IGNORE_NON_SINGULAR_SCALE),
1617            "If true, ignore replicas with more than 1 process when adding topology spread constraints (Materialize).",
1618            false,
1619        );
1620
1621    pub static CLUSTER_TOPOLOGY_SPREAD_MAX_SKEW: VarDefinition = VarDefinition::new(
1622        "cluster_topology_spread_max_skew",
1623        value!(i32; DEFAULT_TOPOLOGY_SPREAD_MAX_SKEW),
1624        "The `maxSkew` for replica topology spread constraints (Materialize).",
1625        false,
1626    );
1627
1628    // `minDomains`, like maxSkew, is used to spread across a topology
1629    // key. Unlike max skew, minDomains will force node creation to ensure
1630    // distribution across a minimum number of keys.
1631    // https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/#spread-constraint-definition
1632    pub static CLUSTER_TOPOLOGY_SPREAD_MIN_DOMAINS: VarDefinition = VarDefinition::new(
1633        "cluster_topology_spread_min_domains",
1634        value!(Option<i32>; None),
1635        "`minDomains` for replica topology spread constraints. \
1636            Should be set to the number of Availability Zones (Materialize).",
1637        false,
1638    );
1639
1640    pub static CLUSTER_TOPOLOGY_SPREAD_SOFT: VarDefinition = VarDefinition::new(
1641        "cluster_topology_spread_soft",
1642        value!(bool; DEFAULT_TOPOLOGY_SPREAD_SOFT),
1643        "If true, soften the topology spread constraints for replicas (Materialize).",
1644        false,
1645    );
1646
1647    pub static CLUSTER_SOFTEN_AZ_AFFINITY: VarDefinition = VarDefinition::new(
1648        "cluster_soften_az_affinity",
1649        value!(bool; DEFAULT_SOFTEN_AZ_AFFINITY),
1650        "Whether or not to turn the az-scope node affinity for replicas. \
1651            Note this could violate requests from the user (Materialize).",
1652        false,
1653    );
1654
1655    pub static CLUSTER_SOFTEN_AZ_AFFINITY_WEIGHT: VarDefinition = VarDefinition::new(
1656        "cluster_soften_az_affinity_weight",
1657        value!(i32; DEFAULT_SOFTEN_AZ_AFFINITY_WEIGHT),
1658        "The preference weight for `cluster_soften_az_affinity` (Materialize).",
1659        false,
1660    );
1661
1662    const DEFAULT_CLUSTER_ALTER_CHECK_READY_INTERVAL: Duration = Duration::from_secs(3);
1663
1664    pub static CLUSTER_ALTER_CHECK_READY_INTERVAL: VarDefinition = VarDefinition::new(
1665        "cluster_alter_check_ready_interval",
1666        value!(Duration; DEFAULT_CLUSTER_ALTER_CHECK_READY_INTERVAL),
1667        "How often to poll readiness checks for cluster alter",
1668        false,
1669    );
1670
1671    const DEFAULT_CHECK_SCHEDULING_POLICIES_INTERVAL: Duration = Duration::from_secs(3);
1672
1673    pub static CLUSTER_CHECK_SCHEDULING_POLICIES_INTERVAL: VarDefinition = VarDefinition::new(
1674        "cluster_check_scheduling_policies_interval",
1675        value!(Duration; DEFAULT_CHECK_SCHEDULING_POLICIES_INTERVAL),
1676        "How often policies are invoked to automatically start/stop clusters, e.g., \
1677            for REFRESH EVERY materialized views.",
1678        false,
1679    )
1680    .with_constraint(&NON_ZERO_DURATION);
1681
1682    pub static CLUSTER_SECURITY_CONTEXT_ENABLED: VarDefinition = VarDefinition::new(
1683        "cluster_security_context_enabled",
1684        value!(bool; DEFAULT_SECURITY_CONTEXT_ENABLED),
1685        "Enables SecurityContext for clusterd instances, restricting capabilities to improve security.",
1686        false,
1687    );
1688
1689    const DEFAULT_CLUSTER_REFRESH_MV_COMPACTION_ESTIMATE: Duration = Duration::from_secs(1200);
1690
1691    pub static CLUSTER_REFRESH_MV_COMPACTION_ESTIMATE: VarDefinition = VarDefinition::new(
1692        "cluster_refresh_mv_compaction_estimate",
1693        value!(Duration; DEFAULT_CLUSTER_REFRESH_MV_COMPACTION_ESTIMATE),
1694        "How much time to wait for compaction after a REFRESH MV completes a refresh \
1695            before turning off the refresh cluster. This is needed because Persist does compaction \
1696            only after a write, but refresh MVs do writes only at their refresh times. \
1697            (In the long term, we'd like to remove this configuration and instead wait exactly \
1698            until compaction has settled. We'd need some new Persist API for this.)",
1699        false,
1700    );
1701}
1702
1703/// Macro to simplify creating feature flags, i.e. boolean flags that we use to toggle the
1704/// availability of features.
1705///
1706/// The arguments to `feature_flags!` are:
1707/// - `$name`, which will be the name of the feature flag, in snake_case
1708/// - `$feature_desc`, a human-readable description of the feature
1709/// - `$value`, which if not provided, defaults to `false`
1710///
1711/// Note that not all `VarDefinition<bool>` are feature flags. Feature flags are for variables that:
1712/// - Belong to `SystemVars`, _not_ `SessionVars`
1713/// - Default to false and must be explicitly enabled, or default to `true` and can be explicitly disabled.
1714///
1715/// WARNING / CONTRACT: Syntax-related feature flags must always *enable* behavior. In other words,
1716/// setting a feature flag must make the system more permissive. For example, let's suppose we'd like
1717/// to gate deprecated upsert syntax behind a feature flag. In this case, do not add a feature flag
1718/// like `disable_deprecated_upsert_syntax`, as `disable_deprecated_upsert_syntax = on` would
1719/// _prevent_ the system from parsing the deprecated upsert syntax. Instead, use a feature flag
1720/// like `enable_deprecated_upsert_syntax`.
1721///
1722/// The hazard this protects against is related to reboots after feature flags have been disabled.
1723/// Say someone creates a Kinesis source while `enable_kinesis_sources = on`. Materialize will
1724/// commit this source to the system catalog. Then, suppose we discover a catastrophic bug in
1725/// Kinesis sources and set `enable_kinesis_sources` to `off`. This prevents users from creating
1726/// new Kinesis sources, but leaves the existing Kinesis sources in place. This is because
1727/// disabling a feature flag doesn't remove access to catalog objects created while the feature
1728/// flag was live. On the next reboot, Materialize will proceed to load the Kinesis source from the
1729/// catalog, reparsing and replanning the `CREATE SOURCE` definition and rechecking the
1730/// `enable_kinesis_sources` feature flag along the way. Even though the feature flag has been
1731/// switched to `off`, we need to temporarily re-enable it during parsing and planning to be able
1732/// to boot successfully.
1733///
1734/// Ensuring that all syntax-related feature flags *enable* behavior means that setting all such
1735/// feature flags to `on` during catalog boot has the desired effect.
1736macro_rules! feature_flags {
1737    // Resolve an optional `scope:` field to a `ParameterScope`, using the
1738    // default scope when the field is omitted.
1739    (@scope_or_default) => {
1740        ParameterScope::DEFAULT
1741    };
1742    (@scope_or_default $scope:expr) => {
1743        $scope
1744    };
1745    // Match `$name, $feature_desc, $value`.
1746    (@inner
1747        // The feature flag name.
1748        name: $name:expr,
1749        // The feature flag description.
1750        desc: $desc:literal,
1751        // The feature flag default value.
1752        default: $value:expr,
1753        // The scope class of the feature flag.
1754        scope: $scope:expr,
1755    ) => {
1756        paste::paste!{
1757            // Note that the ServerVar is not directly exported; we expect these to be
1758            // accessible through their FeatureFlag variant.
1759            static [<$name:upper _VAR>]: VarDefinition = VarDefinition::new(
1760                stringify!($name),
1761                value!(bool; $value),
1762                concat!("Whether ", $desc, " is allowed (Materialize)."),
1763                false,
1764            )
1765            .scoped($scope);
1766
1767            pub static [<$name:upper >]: FeatureFlag = FeatureFlag {
1768                flag: &[<$name:upper _VAR>],
1769                feature_desc: $desc,
1770            };
1771        }
1772    };
1773    ($({
1774        // The feature flag name.
1775        name: $name:expr,
1776        // The feature flag description.
1777        desc: $desc:literal,
1778        // The feature flag default value.
1779        default: $value:expr,
1780        // Should the feature be turned on during catalog rehydration when
1781        // parsing a catalog item.
1782        enable_for_item_parsing: $enable_for_item_parsing:expr,
1783        // The optional scope class. Uses `ParameterScope::DEFAULT` when omitted.
1784        // Cluster-coherent optimizer flags declare `scope: ParameterScope::Cluster`.
1785        $(scope: $scope:expr,)?
1786    },)+) => {
1787        $(feature_flags! { @inner
1788            name: $name,
1789            desc: $desc,
1790            default: $value,
1791            scope: feature_flags!(@scope_or_default $($scope)?),
1792        })+
1793
1794        paste::paste!{
1795            pub static FEATURE_FLAGS: &'static [&'static VarDefinition] = &[
1796                $(  & [<$name:upper _VAR>] , )+
1797            ];
1798        }
1799
1800        paste::paste!{
1801            impl super::SystemVars {
1802                pub fn enable_all_feature_flags_by_default(&mut self) {
1803                    $(
1804                        self.set_default(stringify!($name), super::VarInput::Flat("on"))
1805                            .expect("setting default value must work");
1806                    )+
1807                }
1808
1809                pub fn enable_for_item_parsing(&mut self) {
1810                    $(
1811                        if $enable_for_item_parsing {
1812                            self.set(stringify!($name), super::VarInput::Flat("on"))
1813                                .expect("setting default value must work");
1814                        }
1815                    )+
1816                }
1817
1818                $(
1819                    pub fn [<$name:lower>](&self) -> bool {
1820                        *self.expect_value(&[<$name:upper _VAR>])
1821                    }
1822                )+
1823            }
1824        }
1825    }
1826}
1827
1828feature_flags!(
1829    // Gates for other feature flags
1830    {
1831        name: allow_real_time_recency,
1832        desc: "real time recency",
1833        default: false,
1834        enable_for_item_parsing: true,
1835    },
1836    // Actual feature flags
1837    {
1838        name: enable_binary_date_bin,
1839        desc: "the binary version of date_bin function",
1840        default: false,
1841        enable_for_item_parsing: true,
1842    },
1843    {
1844        name: enable_date_bin_hopping,
1845        desc: "the date_bin_hopping function",
1846        default: false,
1847        enable_for_item_parsing: true,
1848    },
1849    {
1850        name: enable_envelope_debezium_in_subscribe,
1851        desc: "`ENVELOPE DEBEZIUM (KEY (..))`",
1852        default: false,
1853        enable_for_item_parsing: true,
1854    },
1855    {
1856        name: enable_envelope_materialize,
1857        desc: "ENVELOPE MATERIALIZE",
1858        default: false,
1859        enable_for_item_parsing: true,
1860    },
1861    {
1862        name: enable_explain_pushdown,
1863        desc: "EXPLAIN FILTER PUSHDOWN",
1864        default: true,
1865        enable_for_item_parsing: true,
1866    },
1867    {
1868        name: enable_index_options,
1869        desc: "INDEX OPTIONS",
1870        default: false,
1871        enable_for_item_parsing: true,
1872    },
1873    {
1874        name: enable_list_length_max,
1875        desc: "the list_length_max function",
1876        default: false,
1877        enable_for_item_parsing: true,
1878    },
1879    {
1880        name: enable_list_n_layers,
1881        desc: "the list_n_layers function",
1882        default: false,
1883        enable_for_item_parsing: true,
1884    },
1885    {
1886        name: enable_list_remove,
1887        desc: "the list_remove function",
1888        default: false,
1889        enable_for_item_parsing: true,
1890    },
1891    {
1892
1893        name: enable_logical_compaction_window,
1894        desc: "RETAIN HISTORY",
1895        default: false,
1896        enable_for_item_parsing: true,
1897    },
1898    {
1899        name: enable_primary_key_not_enforced,
1900        desc: "PRIMARY KEY NOT ENFORCED",
1901        default: false,
1902        enable_for_item_parsing: true,
1903    },
1904    {
1905        name: enable_collection_partition_by,
1906        desc: "PARTITION BY",
1907        default: true,
1908        enable_for_item_parsing: true,
1909    },
1910    {
1911        name: enable_multi_worker_storage_persist_sink,
1912        desc: "multi-worker storage persist sink",
1913        default: true,
1914        enable_for_item_parsing: true,
1915    },
1916    {
1917        name: enable_persist_streaming_snapshot_and_fetch,
1918        desc: "use the new streaming consolidate for snapshot_and_fetch",
1919        default: false,
1920        enable_for_item_parsing: true,
1921    },
1922    {
1923        name: enable_persist_streaming_compaction,
1924        desc: "use the new streaming consolidate for compaction",
1925        default: false,
1926        enable_for_item_parsing: true,
1927    },
1928    {
1929        name: enable_raise_statement,
1930        desc: "RAISE statement",
1931        default: false,
1932        enable_for_item_parsing: true,
1933    },
1934    {
1935        name: enable_repeat_row,
1936        desc: "the repeat_row function",
1937        default: false,
1938        enable_for_item_parsing: true,
1939    },
1940    {
1941        name: enable_repeat_row_non_negative,
1942        desc: "the repeat_row_non_negative function",
1943        default: false,
1944        enable_for_item_parsing: true,
1945    },
1946    {
1947        name: enable_replica_targeted_materialized_views,
1948        desc: "replica-targeted materialized views",
1949        default: false,
1950        enable_for_item_parsing: true,
1951    },
1952    {
1953        name: unsafe_enable_incomplete_view_column_lists,
1954        desc: "declaring a view with fewer column names than columns",
1955        default: false,
1956        enable_for_item_parsing: true,
1957    },
1958    {
1959        name: unsafe_enable_table_check_constraint,
1960        desc: "CREATE TABLE with a check constraint",
1961        default: false,
1962        enable_for_item_parsing: true,
1963    },
1964    {
1965        name: unsafe_enable_table_foreign_key,
1966        desc: "CREATE TABLE with a foreign key",
1967        default: false,
1968        enable_for_item_parsing: true,
1969    },
1970    {
1971        name: unsafe_enable_table_keys,
1972        desc: "CREATE TABLE with a primary key or unique constraint",
1973        default: false,
1974        enable_for_item_parsing: true,
1975    },
1976    {
1977        name: unsafe_enable_unorchestrated_cluster_replicas,
1978        desc: "unorchestrated cluster replicas",
1979        default: false,
1980        enable_for_item_parsing: true,
1981    },
1982    {
1983        name: unsafe_enable_unstable_dependencies,
1984        desc: "depending on unstable objects",
1985        default: false,
1986        enable_for_item_parsing: true,
1987    },
1988    {
1989        name: unsafe_enable_unbounded_custom_type_resolution,
1990        desc: "resolving custom types without the depth and complexity limits that bound resolution work",
1991        default: false,
1992        enable_for_item_parsing: true,
1993    },
1994    {
1995        name: enable_within_timestamp_order_by_in_subscribe,
1996        desc: "`WITHIN TIMESTAMP ORDER BY ..`",
1997        default: false,
1998        enable_for_item_parsing: true,
1999    },
2000    {
2001        name: enable_cardinality_estimates,
2002        desc: "join planning with cardinality estimates",
2003        default: false,
2004        enable_for_item_parsing: false,
2005    },
2006    {
2007        name: enable_connection_validation_syntax,
2008        desc: "CREATE CONNECTION .. WITH (VALIDATE) and VALIDATE CONNECTION syntax",
2009        default: true,
2010        enable_for_item_parsing: true,
2011    },
2012    {
2013        name: enable_kafka_broker_matching_rules,
2014        desc: "MATCHING broker rules in BROKERS for Kafka PrivateLink connections",
2015        default: false,
2016        enable_for_item_parsing: true,
2017    },
2018    {
2019        name: enable_alter_set_cluster,
2020        desc: "ALTER ... SET CLUSTER syntax",
2021        default: false,
2022        enable_for_item_parsing: true,
2023    },
2024    {
2025        name: unsafe_enable_unsafe_functions,
2026        desc: "executing potentially dangerous functions",
2027        default: false,
2028        enable_for_item_parsing: true,
2029    },
2030    {
2031        name: enable_managed_cluster_availability_zones,
2032        desc: "MANAGED, AVAILABILITY ZONES syntax",
2033        default: false,
2034        enable_for_item_parsing: true,
2035    },
2036    {
2037        name: statement_logging_use_reproducible_rng,
2038        desc: "statement logging with reproducible RNG",
2039        default: false,
2040        enable_for_item_parsing: false,
2041    },
2042    {
2043        name: enable_notices_for_index_already_exists,
2044        desc: "emitting notices for IndexAlreadyExists (doesn't affect EXPLAIN)",
2045        default: true,
2046        enable_for_item_parsing: true,
2047    },
2048    {
2049        name: enable_notices_for_index_too_wide_for_literal_constraints,
2050        desc: "emitting notices for IndexTooWideForLiteralConstraints (doesn't affect EXPLAIN)",
2051        default: false,
2052        enable_for_item_parsing: true,
2053    },
2054    {
2055        name: enable_notices_for_index_empty_key,
2056        desc: "emitting notices for indexes with an empty key (doesn't affect EXPLAIN)",
2057        default: true,
2058        enable_for_item_parsing: true,
2059    },
2060    {
2061        name: enable_notices_for_equals_null,
2062        desc: "emitting notices for `= NULL` and `<> NULL` comparisons (doesn't affect EXPLAIN)",
2063        default: true,
2064        enable_for_item_parsing: true,
2065    },
2066    {
2067        name: enable_alter_swap,
2068        desc: "the ALTER SWAP feature for objects",
2069        default: true,
2070        enable_for_item_parsing: true,
2071    },
2072    {
2073        name: enable_new_outer_join_lowering,
2074        desc: "new outer join lowering",
2075        default: true,
2076        enable_for_item_parsing: false,
2077        scope: ParameterScope::Cluster,
2078    },
2079    {
2080        name: enable_fixed_correlated_cte_lowering,
2081        desc: "CTE-aware branch keys in HIR-to-MIR lowering, fixing references to \
2082               correlated CTEs from nested correlated scopes",
2083        default: true,
2084        enable_for_item_parsing: false,
2085    },
2086    {
2087        name: enable_time_at_time_zone,
2088        desc: "use of AT TIME ZONE or timezone() with time type",
2089        default: false,
2090        enable_for_item_parsing: true,
2091    },
2092    {
2093        name: enable_load_generator_counter,
2094        desc: "Create a LOAD GENERATOR COUNTER",
2095        default: false,
2096        enable_for_item_parsing: true,
2097    },
2098    {
2099        name: enable_load_generator_clock,
2100        desc: "Create a LOAD GENERATOR CLOCK",
2101        default: false,
2102        enable_for_item_parsing: true,
2103    },
2104    {
2105        name: enable_load_generator_datums,
2106        desc: "Create a LOAD GENERATOR DATUMS",
2107        default: false,
2108        enable_for_item_parsing: true,
2109    },
2110    {
2111        name: enable_load_generator_key_value,
2112        desc: "Create a LOAD GENERATOR KEY VALUE",
2113        default: false,
2114        enable_for_item_parsing: true,
2115    },
2116    {
2117        name: enable_expressions_in_limit_syntax,
2118        desc: "LIMIT <expr> syntax",
2119        default: true,
2120        enable_for_item_parsing: true,
2121    },
2122    {
2123        name: enable_mz_notices,
2124        desc: "Populate the contents of `mz_internal.mz_notices`",
2125        default: true,
2126        enable_for_item_parsing: false,
2127    },
2128    {
2129        name: enable_eager_delta_joins,
2130        desc:
2131            "eager delta joins",
2132        default: false,
2133        enable_for_item_parsing: false,
2134        scope: ParameterScope::Cluster,
2135    },
2136    {
2137        name: enable_off_thread_optimization,
2138        desc: "use off-thread optimization in `CREATE` statements",
2139        default: true,
2140        enable_for_item_parsing: false,
2141    },
2142    {
2143        name: enable_refresh_every_mvs,
2144        desc: "REFRESH EVERY and REFRESH AT materialized views",
2145        default: false,
2146        enable_for_item_parsing: true,
2147    },
2148    {
2149        name: enable_cluster_schedule_refresh,
2150        desc: "`SCHEDULE = ON REFRESH` cluster option",
2151        default: false,
2152        enable_for_item_parsing: true,
2153    },
2154    {
2155        name: enable_auto_scaling_strategy,
2156        desc: "`AUTO SCALING STRATEGY` cluster option",
2157        default: true,
2158        enable_for_item_parsing: true,
2159    },
2160    {
2161        name: enable_reduce_mfp_fusion,
2162        desc: "fusion of MFPs in reductions",
2163        default: true,
2164        enable_for_item_parsing: false,
2165    },
2166    {
2167        name: enable_worker_core_affinity,
2168        desc: "set core affinity for replica worker threads",
2169        default: false,
2170        enable_for_item_parsing: false,
2171    },
2172    {
2173        name: enable_storage_introspection_logs,
2174        desc: "forward storage timely logging events into compute's introspection dataflow",
2175        default: false,
2176        enable_for_item_parsing: false,
2177    },
2178    {
2179        name: enable_session_timelines,
2180        desc: "strong session serializable isolation levels",
2181        default: false,
2182        enable_for_item_parsing: false,
2183    },
2184    {
2185        name: enable_variadic_left_join_lowering,
2186        desc: "Enable joint HIR ⇒ MIR lowering of stacks of left joins",
2187        default: true,
2188        enable_for_item_parsing: false,
2189        scope: ParameterScope::Cluster,
2190    },
2191    {
2192        name: enable_redacted_test_option,
2193        desc: "Enable useless option to test value redaction",
2194        default: false,
2195        enable_for_item_parsing: true,
2196    },
2197    {
2198        name: enable_letrec_fixpoint_analysis,
2199        desc: "Enable Lattice-based fixpoint iteration on LetRec nodes in the Analysis framework",
2200        default: true, // This is just a failsafe switch for the deployment of materialize#25591.
2201        enable_for_item_parsing: false,
2202        scope: ParameterScope::Cluster,
2203    },
2204    {
2205        name: enable_kafka_sink_headers,
2206        desc: "Enable the HEADERS option for Kafka sinks",
2207        default: false,
2208        enable_for_item_parsing: true,
2209    },
2210    {
2211        name: enable_unlimited_retain_history,
2212        desc: "Disable limits on RETAIN HISTORY (below 1s default, and 0 disables compaction).",
2213        default: false,
2214        enable_for_item_parsing: true,
2215    },
2216    {
2217        name: enable_envelope_upsert_inline_errors,
2218        desc: "The VALUE DECODING ERRORS = INLINE option on ENVELOPE UPSERT",
2219        default: true,
2220        enable_for_item_parsing: true,
2221    },
2222    {
2223        name: enable_alter_table_add_column,
2224        desc: "Enable ALTER TABLE ... ADD COLUMN ...",
2225        default: false,
2226        enable_for_item_parsing: false,
2227    },
2228    {
2229        name: enable_zero_downtime_cluster_reconfiguration,
2230        desc: "Enable zero-downtime reconfiguration for alter cluster",
2231        default: false,
2232        enable_for_item_parsing: false,
2233    },
2234    {
2235        name: enable_network_policies,
2236        desc: "ENABLE NETWORK POLICIES",
2237        default: true,
2238        enable_for_item_parsing: true,
2239    },
2240    {
2241        name: enable_create_table_from_source,
2242        desc: "Whether to allow CREATE TABLE .. FROM SOURCE syntax.",
2243        default: true,
2244        enable_for_item_parsing: true,
2245    },
2246    {
2247        name: enable_join_prioritize_arranged,
2248        desc: "Whether join planning should prioritize already-arranged keys over keys with more fields.",
2249        default: false,
2250        enable_for_item_parsing: false,
2251        scope: ParameterScope::Cluster,
2252    },
2253    {
2254        name: enable_projection_pushdown_after_relation_cse,
2255        desc: "Run ProjectionPushdown one more time after the last RelationCSE.",
2256        default: true,
2257        enable_for_item_parsing: false,
2258        scope: ParameterScope::Cluster,
2259    },
2260    {
2261        name: enable_less_reduce_in_eqprop,
2262        desc: "Run MSE::reduce in EquivalencePropagation only if reduce_expr changed something.",
2263        default: true,
2264        enable_for_item_parsing: false,
2265    },
2266    {
2267        name: enable_dequadratic_eqprop_map,
2268        desc: "Skip the quadratic part of EquivalencePropagation's handling of Map.",
2269        default: true,
2270        enable_for_item_parsing: false,
2271    },
2272    {
2273        name: enable_eq_classes_withholding_errors,
2274        desc: "Use `EquivalenceClassesWithholdingErrors` instead of raw `EquivalenceClasses` during eq prop for joins.",
2275        default: true,
2276        enable_for_item_parsing: false,
2277    },
2278    {
2279        name: enable_fast_path_plan_insights,
2280        desc: "Enables those plan insight notices that help with getting fast path queries. Don't turn on before #9492 is fixed!",
2281        default: false,
2282        enable_for_item_parsing: false,
2283    },
2284    {
2285        name: enable_with_ordinality_legacy_fallback,
2286        desc: "When the new WITH ORDINALITY implementation can't be used with a table func, whether to fall back to the legacy implementation or error out.",
2287        default: false,
2288        enable_for_item_parsing: true,
2289    },
2290    {
2291        name: enable_frontend_peek_sequencing, // currently, changes only take effect for new sessions
2292        desc: "Enables the new peek sequencing code, which does most of its work in the Adapter Frontend instead of the Coordinator main task.",
2293        default: true,
2294        enable_for_item_parsing: false,
2295    },
2296    {
2297        name: enable_replacement_materialized_views,
2298        desc: "Whether to enable replacement materialized views.",
2299        default: true,
2300        enable_for_item_parsing: true,
2301    },
2302    {
2303        name: enable_cast_elimination,
2304        desc: "Allow the optimizer to eliminate noop casts between values of equivalent representation types.",
2305        default: true,
2306        enable_for_item_parsing: false,
2307    },
2308    {
2309        // Just an escape hatch for the unlikely case that we have some user who is doing such
2310        // queries. Can be removed after one week in prod.
2311        // https://github.com/MaterializeInc/database-issues/issues/10004
2312        name: disallow_unmaterializable_functions_as_of,
2313        desc: "Prohibits calling unmaterializable functions (except `mz_now`) in AS OF queries.",
2314        default: true,
2315        enable_for_item_parsing: false,
2316    },
2317    {
2318        name: enable_case_literal_transform,
2319        desc: "Allow the optimizer to rewrite If-chains matching a single expression against literals into a CaseLiteral lookup.",
2320        default: false,
2321        enable_for_item_parsing: false,
2322    },
2323    {
2324        name: enable_simplify_quantified_comparisons,
2325        desc: "Allow the optimizer to simplify quantified comparisons in JOIN ON clauses into semi/anti-join EXISTS form during HIR-to-MIR lowering.",
2326        default: true,
2327        enable_for_item_parsing: false,
2328    },
2329    {
2330        name: enable_simplify_from_less_existence,
2331        desc: "Allow the optimizer to collapse EXISTS/NOT EXISTS over a FROM-less correlated subquery into a plain Filter during HIR-to-MIR lowering.",
2332        default: true,
2333        enable_for_item_parsing: false,
2334    },
2335    {
2336        name: enable_coalesce_case_transform,
2337        desc: "Allow the optimizer to push `COALESCE` into `CASE WHEN`.",
2338        default: true,
2339        enable_for_item_parsing: false,
2340    },
2341    // Disposition: added 2026-05-29, default on; remove after several weeks of observation.
2342    {
2343        name: enable_will_distinct_propagation,
2344        desc: "Allow the WillDistinct transform to propagate a pending distinct through Map, Filter, FlatMap, Threshold, Negate, non-negative Project, and TopK with limit 1 and offset 0.",
2345        default: true,
2346        enable_for_item_parsing: false,
2347    },
2348    {
2349        name: enable_bounded_staleness_isolation,
2350        desc: "the `bounded staleness <duration>` transaction isolation level",
2351        default: true,
2352        enable_for_item_parsing: false,
2353    },
2354);
2355
2356impl From<&super::SystemVars> for OptimizerFeatures {
2357    fn from(vars: &super::SystemVars) -> Self {
2358        Self {
2359            enable_eager_delta_joins: vars.enable_eager_delta_joins(),
2360            enable_new_outer_join_lowering: vars.enable_new_outer_join_lowering(),
2361            enable_reduce_mfp_fusion: vars.enable_reduce_mfp_fusion(),
2362            enable_variadic_left_join_lowering: vars.enable_variadic_left_join_lowering(),
2363            enable_letrec_fixpoint_analysis: vars.enable_letrec_fixpoint_analysis(),
2364            enable_cardinality_estimates: vars.enable_cardinality_estimates(),
2365            persist_fast_path_limit: vars.persist_fast_path_limit(),
2366            reoptimize_imported_views: false,
2367            enable_join_prioritize_arranged: vars.enable_join_prioritize_arranged(),
2368            enable_projection_pushdown_after_relation_cse: vars
2369                .enable_projection_pushdown_after_relation_cse(),
2370            enable_less_reduce_in_eqprop: vars.enable_less_reduce_in_eqprop(),
2371            enable_dequadratic_eqprop_map: vars.enable_dequadratic_eqprop_map(),
2372            enable_eq_classes_withholding_errors: vars.enable_eq_classes_withholding_errors(),
2373            enable_fast_path_plan_insights: vars.enable_fast_path_plan_insights(),
2374            enable_cast_elimination: vars.enable_cast_elimination(),
2375            enable_case_literal_transform: vars.enable_case_literal_transform(),
2376            enable_simplify_quantified_comparisons: vars.enable_simplify_quantified_comparisons(),
2377            enable_simplify_from_less_existence: vars.enable_simplify_from_less_existence(),
2378            enable_coalesce_case_transform: vars.enable_coalesce_case_transform(),
2379            enable_will_distinct_propagation: vars.enable_will_distinct_propagation(),
2380            enable_fixed_correlated_cte_lowering: vars.enable_fixed_correlated_cte_lowering(),
2381        }
2382    }
2383}
2384
2385#[cfg(test)]
2386mod tests {
2387    use super::*;
2388    use crate::session::vars::SystemVars;
2389
2390    /// Ensure that all vars used for optimizer features have `enable_for_item_parsing = false`.
2391    ///
2392    /// This is important to ensure that plan caching works as intended during item parsing. Cached
2393    /// plans include the optimizer features they were produced with, and if they don't match on
2394    /// lookup, that results in a cache miss.
2395    #[mz_ore::test]
2396    fn optimizer_features_no_enable_for_item_parsing() {
2397        // Construct a `SystemVars` where all optimizer features are `false`.
2398        //
2399        // We do this in a roundabout way, by first constructing all-false `OptimizerFeatures` and
2400        // then assigning them to their respective system vars, to ensure we don't forget to update
2401        // this test when new optimizer features are added.
2402        let false_features = OptimizerFeatures::default();
2403        let OptimizerFeatures {
2404            enable_eq_classes_withholding_errors,
2405            enable_eager_delta_joins,
2406            enable_letrec_fixpoint_analysis,
2407            enable_new_outer_join_lowering,
2408            enable_reduce_mfp_fusion,
2409            enable_variadic_left_join_lowering,
2410            enable_cardinality_estimates,
2411            persist_fast_path_limit,
2412            reoptimize_imported_views,
2413            enable_join_prioritize_arranged,
2414            enable_projection_pushdown_after_relation_cse,
2415            enable_less_reduce_in_eqprop,
2416            enable_dequadratic_eqprop_map,
2417            enable_fast_path_plan_insights,
2418            enable_cast_elimination,
2419            enable_case_literal_transform,
2420            enable_simplify_quantified_comparisons,
2421            enable_simplify_from_less_existence,
2422            enable_coalesce_case_transform,
2423            enable_will_distinct_propagation,
2424            enable_fixed_correlated_cte_lowering,
2425        } = false_features;
2426
2427        let mut vars = SystemVars::new();
2428
2429        macro_rules! set_var {
2430            ($var:ident) => {
2431                vars.set(stringify!($var), VarInput::Flat(&$var.to_string()))
2432                    .unwrap();
2433            };
2434        }
2435
2436        set_var!(enable_eq_classes_withholding_errors);
2437        set_var!(enable_eager_delta_joins);
2438        set_var!(enable_letrec_fixpoint_analysis);
2439        set_var!(enable_new_outer_join_lowering);
2440        set_var!(enable_reduce_mfp_fusion);
2441        set_var!(enable_variadic_left_join_lowering);
2442        set_var!(enable_cardinality_estimates);
2443        set_var!(persist_fast_path_limit);
2444        let _ = reoptimize_imported_views; // no corresponding var
2445        set_var!(enable_join_prioritize_arranged);
2446        set_var!(enable_projection_pushdown_after_relation_cse);
2447        set_var!(enable_less_reduce_in_eqprop);
2448        set_var!(enable_dequadratic_eqprop_map);
2449        set_var!(enable_fast_path_plan_insights);
2450        set_var!(enable_cast_elimination);
2451        set_var!(enable_case_literal_transform);
2452        set_var!(enable_simplify_quantified_comparisons);
2453        set_var!(enable_simplify_from_less_existence);
2454        set_var!(enable_coalesce_case_transform);
2455        set_var!(enable_will_distinct_propagation);
2456        set_var!(enable_fixed_correlated_cte_lowering);
2457
2458        // Enable for item parsing, then ensure we still get the same optimizer features.
2459        vars.enable_for_item_parsing();
2460        let features_for_item_parsing = OptimizerFeatures::from(&vars);
2461        assert_eq!(features_for_item_parsing, false_features);
2462    }
2463}