Skip to main content

mz_sql/session/vars/
definitions.rs

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