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