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