Skip to main content

mz_sql/session/vars/
definitions.rs

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