Skip to main content

uqa_sql/semantics/parameters/
catalog.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! The configuration parameters the engine defines, with the types, bounds, contexts and descriptions of `PostgreSQL` 18's `guc_tables.c`, in the case-insensitive name order of `SHOW ALL`.
8
9use super::definition::{
10    EnumOption, ParameterContext, ParameterDefinition, ParameterFlags, ParameterKind,
11};
12use super::units::ParameterUnit;
13
14const STATEMENT_BEHAVIOR: &str = "Client Connection Defaults / Statement Behavior";
15const LOCALE_AND_FORMATTING: &str = "Client Connection Defaults / Locale and Formatting";
16const PREVIOUS_VERSIONS: &str = "Version and Platform Compatibility / Previous PostgreSQL Versions";
17const PRESET_OPTIONS: &str = "Preset Options";
18const TIMEOUT_DISABLED: Option<&str> = Some("0 disables the timeout.");
19
20/// The message levels of `PostgreSQL`'s `elog.h`, which order `client_min_messages`.
21pub mod message_levels {
22    pub const DEBUG5: u8 = 10;
23    pub const DEBUG4: u8 = 11;
24    pub const DEBUG3: u8 = 12;
25    pub const DEBUG2: u8 = 13;
26    pub const DEBUG1: u8 = 14;
27    pub const LOG: u8 = 15;
28    pub const INFO: u8 = 17;
29    pub const NOTICE: u8 = 18;
30    pub const WARNING: u8 = 19;
31    pub const ERROR: u8 = 21;
32}
33
34const BACKSLASH_QUOTE_OPTIONS: &[EnumOption] = &[
35    EnumOption::listed("safe_encoding", 2),
36    EnumOption::listed("on", 1),
37    EnumOption::listed("off", 0),
38    EnumOption::hidden("true", 1),
39    EnumOption::hidden("false", 0),
40    EnumOption::hidden("yes", 1),
41    EnumOption::hidden("no", 0),
42    EnumOption::hidden("1", 1),
43    EnumOption::hidden("0", 0),
44];
45
46const CLIENT_MESSAGE_LEVELS: &[EnumOption] = &[
47    EnumOption::listed("debug5", message_levels::DEBUG5),
48    EnumOption::listed("debug4", message_levels::DEBUG4),
49    EnumOption::listed("debug3", message_levels::DEBUG3),
50    EnumOption::listed("debug2", message_levels::DEBUG2),
51    EnumOption::listed("debug1", message_levels::DEBUG1),
52    EnumOption::hidden("debug", message_levels::DEBUG2),
53    EnumOption::listed("log", message_levels::LOG),
54    EnumOption::hidden("info", message_levels::INFO),
55    EnumOption::listed("notice", message_levels::NOTICE),
56    EnumOption::listed("warning", message_levels::WARNING),
57    EnumOption::listed("error", message_levels::ERROR),
58];
59
60const ISOLATION_LEVELS: &[EnumOption] = &[
61    EnumOption::listed("serializable", 3),
62    EnumOption::listed("repeatable read", 2),
63    EnumOption::listed("read committed", 1),
64    EnumOption::listed("read uncommitted", 0),
65];
66
67const PLAN_CACHE_MODES: &[EnumOption] = &[
68    EnumOption::listed("auto", 0),
69    EnumOption::listed("force_generic_plan", 1),
70    EnumOption::listed("force_custom_plan", 2),
71];
72
73/// The values of `plpgsql.variable_conflict`, as `plpgsql_variable_conflict` lists them.
74const VARIABLE_CONFLICTS: &[EnumOption] = &[
75    EnumOption::listed("error", 0),
76    EnumOption::listed("use_variable", 1),
77    EnumOption::listed("use_column", 2),
78];
79const REPLICATION_ROLES: &[EnumOption] = &[
80    EnumOption::listed("origin", 0),
81    EnumOption::listed("replica", 1),
82    EnumOption::listed("local", 2),
83];
84
85const XML_OPTIONS: &[EnumOption] = &[
86    EnumOption::listed("content", 1),
87    EnumOption::listed("document", 0),
88];
89
90const INTERVAL_STYLES: &[EnumOption] = &[
91    EnumOption::listed("postgres", 0),
92    EnumOption::listed("postgres_verbose", 1),
93    EnumOption::listed("sql_standard", 2),
94    EnumOption::listed("iso_8601", 3),
95];
96
97/// The version the engine reports as `server_version_num`.
98pub const SERVER_VERSION_NUM: i32 = 180_000;
99
100const fn define(
101    name: &'static str,
102    kind: ParameterKind,
103    context: ParameterContext,
104    category: &'static str,
105    short_desc: &'static str,
106    extra_desc: Option<&'static str>,
107    flags: ParameterFlags,
108) -> ParameterDefinition {
109    ParameterDefinition {
110        name,
111        kind,
112        context,
113        category,
114        short_desc,
115        extra_desc,
116        flags,
117        library: None,
118    }
119}
120
121const fn timeout(name: &'static str, short_desc: &'static str) -> ParameterDefinition {
122    define(
123        name,
124        ParameterKind::Integer {
125            boot: 0,
126            min: 0,
127            max: i32::MAX,
128            unit: Some(ParameterUnit::Milliseconds),
129        },
130        ParameterContext::User,
131        STATEMENT_BEHAVIOR,
132        short_desc,
133        TIMEOUT_DISABLED,
134        ParameterFlags::NONE,
135    )
136}
137
138const fn boolean(boot: bool) -> ParameterKind {
139    ParameterKind::Bool { boot }
140}
141
142const fn string(boot: &'static str) -> ParameterKind {
143    ParameterKind::String { boot }
144}
145
146const fn enumerated(boot: u8, options: &'static [EnumOption]) -> ParameterKind {
147    ParameterKind::Enum { boot, options }
148}
149
150const NO_RESET: ParameterFlags = ParameterFlags::NO_RESET.union(ParameterFlags::NO_RESET_ALL);
151const AUTHORIZATION: ParameterFlags = ParameterFlags::IS_NAME
152    .union(ParameterFlags::NO_SHOW_ALL)
153    .union(ParameterFlags::NO_RESET_ALL);
154
155static PARAMETERS: &[ParameterDefinition] = &[
156    define(
157        "application_name",
158        string(""),
159        ParameterContext::User,
160        "Reporting and Logging / What to Log",
161        "Sets the application name to be reported in statistics and logs.",
162        None,
163        ParameterFlags::IS_NAME.union(ParameterFlags::REPORT),
164    ),
165    define(
166        "backslash_quote",
167        enumerated(2, BACKSLASH_QUOTE_OPTIONS),
168        ParameterContext::User,
169        PREVIOUS_VERSIONS,
170        "Sets whether \"\\'\" is allowed in string literals.",
171        None,
172        ParameterFlags::NONE,
173    ),
174    define(
175        "check_function_bodies",
176        boolean(true),
177        ParameterContext::User,
178        STATEMENT_BEHAVIOR,
179        "Check routine bodies during CREATE FUNCTION and CREATE PROCEDURE.",
180        None,
181        ParameterFlags::NONE,
182    ),
183    define(
184        "client_encoding",
185        string("SQL_ASCII"),
186        ParameterContext::User,
187        LOCALE_AND_FORMATTING,
188        "Sets the client's character set encoding.",
189        None,
190        ParameterFlags::IS_NAME.union(ParameterFlags::REPORT),
191    ),
192    define(
193        "client_min_messages",
194        enumerated(message_levels::NOTICE, CLIENT_MESSAGE_LEVELS),
195        ParameterContext::User,
196        STATEMENT_BEHAVIOR,
197        "Sets the message levels that are sent to the client.",
198        Some("Each level includes all the levels that follow it. The later the level, the fewer messages are sent."),
199        ParameterFlags::NONE,
200    ),
201    define(
202        "DateStyle",
203        string("ISO, MDY"),
204        ParameterContext::User,
205        LOCALE_AND_FORMATTING,
206        "Sets the display format for date and time values.",
207        Some("Also controls interpretation of ambiguous date inputs."),
208        ParameterFlags::LIST_INPUT.union(ParameterFlags::REPORT),
209    ),
210    define(
211        "default_table_access_method",
212        string("heap"),
213        ParameterContext::User,
214        STATEMENT_BEHAVIOR,
215        "Sets the default table access method for new tables.",
216        None,
217        ParameterFlags::IS_NAME,
218    ),
219    define(
220        "default_tablespace",
221        string(""),
222        ParameterContext::User,
223        STATEMENT_BEHAVIOR,
224        "Sets the default tablespace to create tables and indexes in.",
225        Some("An empty string means use the database's default tablespace."),
226        ParameterFlags::IS_NAME,
227    ),
228    define(
229        "default_transaction_deferrable",
230        boolean(false),
231        ParameterContext::User,
232        STATEMENT_BEHAVIOR,
233        "Sets the default deferrable status of new transactions.",
234        None,
235        ParameterFlags::NONE,
236    ),
237    define(
238        "default_transaction_isolation",
239        enumerated(1, ISOLATION_LEVELS),
240        ParameterContext::User,
241        STATEMENT_BEHAVIOR,
242        "Sets the transaction isolation level of each new transaction.",
243        None,
244        ParameterFlags::NONE,
245    ),
246    define(
247        "default_transaction_read_only",
248        boolean(false),
249        ParameterContext::User,
250        STATEMENT_BEHAVIOR,
251        "Sets the default read-only status of new transactions.",
252        None,
253        ParameterFlags::REPORT,
254    ),
255    define(
256        "default_with_oids",
257        boolean(false),
258        ParameterContext::User,
259        PREVIOUS_VERSIONS,
260        "WITH OIDS is no longer supported; this can only be false.",
261        None,
262        ParameterFlags::NO_SHOW_ALL,
263    ),
264    define(
265        "enable_indexonlyscan",
266        boolean(true),
267        ParameterContext::User,
268        "Query Tuning / Planner Method Configuration",
269        "Enables the planner's use of index-only-scan plans.",
270        None,
271        ParameterFlags::NONE,
272    ),
273    define(
274        "escape_string_warning",
275        boolean(true),
276        ParameterContext::User,
277        PREVIOUS_VERSIONS,
278        "Warn about backslash escapes in ordinary string literals.",
279        None,
280        ParameterFlags::NONE,
281    ),
282    timeout(
283        "idle_in_transaction_session_timeout",
284        "Sets the maximum allowed idle time between queries, when in a transaction.",
285    ),
286    timeout(
287        "idle_session_timeout",
288        "Sets the maximum allowed idle time between queries, when not in a transaction.",
289    ),
290    define(
291        "in_hot_standby",
292        boolean(false),
293        ParameterContext::Internal,
294        PRESET_OPTIONS,
295        "Shows whether hot standby is currently active.",
296        None,
297        ParameterFlags::REPORT,
298    ),
299    define(
300        "integer_datetimes",
301        boolean(true),
302        ParameterContext::Internal,
303        PRESET_OPTIONS,
304        "Shows whether datetimes are integer based.",
305        None,
306        ParameterFlags::REPORT,
307    ),
308    define(
309        "IntervalStyle",
310        enumerated(0, INTERVAL_STYLES),
311        ParameterContext::User,
312        LOCALE_AND_FORMATTING,
313        "Sets the display format for interval values.",
314        None,
315        ParameterFlags::REPORT,
316    ),
317    define(
318        "is_superuser",
319        boolean(false),
320        ParameterContext::Internal,
321        PRESET_OPTIONS,
322        "Shows whether the current user is a superuser.",
323        None,
324        ParameterFlags::REPORT
325            .union(ParameterFlags::NO_SHOW_ALL)
326            .union(ParameterFlags::NO_RESET_ALL),
327    ),
328    timeout(
329        "lock_timeout",
330        "Sets the maximum allowed duration of any wait for a lock.",
331    ),
332    define(
333        "plan_cache_mode",
334        enumerated(0, PLAN_CACHE_MODES),
335        ParameterContext::User,
336        "Query Tuning / Other Planner Options",
337        "Controls the planner's selection of custom or generic plan.",
338        Some("Prepared statements can have custom and generic plans, and the planner will attempt to choose which is better.  This can be set to override the default behavior."),
339        ParameterFlags::NONE,
340    ),
341    ParameterDefinition {
342        library: Some("plpgsql"),
343        ..define(
344            "plpgsql.check_asserts",
345            boolean(true),
346            ParameterContext::User,
347            "Customized Options",
348            "Perform checks given in ASSERT statements.",
349            None,
350            ParameterFlags::NONE,
351        )
352    },
353    ParameterDefinition {
354        library: Some("plpgsql"),
355        ..define(
356            "plpgsql.variable_conflict",
357            enumerated(0, VARIABLE_CONFLICTS),
358            ParameterContext::Superuser,
359            "Customized Options",
360            "Sets handling of conflicts between PL/pgSQL variable names and table column names.",
361            None,
362            ParameterFlags::NONE,
363        )
364    },
365    define(
366        "role",
367        string("none"),
368        ParameterContext::User,
369        "Ungrouped",
370        "Sets the current role.",
371        None,
372        AUTHORIZATION,
373    ),
374    define(
375        "row_security",
376        boolean(true),
377        ParameterContext::User,
378        STATEMENT_BEHAVIOR,
379        "Enables row security.",
380        Some("When enabled, row security will be applied to all users."),
381        ParameterFlags::NONE,
382    ),
383    define(
384        "search_path",
385        string("\"$user\", public"),
386        ParameterContext::User,
387        STATEMENT_BEHAVIOR,
388        "Sets the schema search order for names that are not schema-qualified.",
389        None,
390        ParameterFlags::LIST_INPUT
391            .union(ParameterFlags::LIST_QUOTE)
392            .union(ParameterFlags::REPORT),
393    ),
394    define(
395        "server_encoding",
396        string("SQL_ASCII"),
397        ParameterContext::Internal,
398        PRESET_OPTIONS,
399        "Shows the server (database) character set encoding.",
400        None,
401        ParameterFlags::IS_NAME.union(ParameterFlags::REPORT),
402    ),
403    define(
404        "server_version",
405        string("18.0-uqa"),
406        ParameterContext::Internal,
407        PRESET_OPTIONS,
408        "Shows the server version.",
409        None,
410        ParameterFlags::REPORT,
411    ),
412    ParameterDefinition {
413        name: "server_version_num",
414        kind: ParameterKind::Integer {
415            boot: SERVER_VERSION_NUM,
416            min: SERVER_VERSION_NUM,
417            max: SERVER_VERSION_NUM,
418            unit: None,
419        },
420        context: ParameterContext::Internal,
421        category: PRESET_OPTIONS,
422        short_desc: "Shows the server version as an integer.",
423        extra_desc: None,
424        flags: ParameterFlags::NONE,
425        library: None,
426    },
427    define(
428        "session_authorization",
429        string(""),
430        ParameterContext::User,
431        "Ungrouped",
432        "Sets the session user name.",
433        None,
434        AUTHORIZATION.union(ParameterFlags::REPORT),
435    ),
436    define(
437        "session_replication_role",
438        enumerated(0, REPLICATION_ROLES),
439        ParameterContext::Superuser,
440        STATEMENT_BEHAVIOR,
441        "Sets the session's behavior for triggers and rewrite rules.",
442        None,
443        ParameterFlags::NONE,
444    ),
445    define(
446        "standard_conforming_strings",
447        boolean(true),
448        ParameterContext::User,
449        PREVIOUS_VERSIONS,
450        "Causes '...' strings to treat backslashes literally.",
451        None,
452        ParameterFlags::REPORT,
453    ),
454    timeout(
455        "statement_timeout",
456        "Sets the maximum allowed duration of any statement.",
457    ),
458    define(
459        "TimeZone",
460        string("GMT"),
461        ParameterContext::User,
462        LOCALE_AND_FORMATTING,
463        "Sets the time zone for displaying and interpreting time stamps.",
464        None,
465        ParameterFlags::REPORT,
466    ),
467    define(
468        "transaction_deferrable",
469        boolean(false),
470        ParameterContext::User,
471        STATEMENT_BEHAVIOR,
472        "Whether to defer a read-only serializable transaction until it can be executed with no possible serialization failures.",
473        None,
474        NO_RESET,
475    ),
476    define(
477        "transaction_isolation",
478        enumerated(1, ISOLATION_LEVELS),
479        ParameterContext::User,
480        STATEMENT_BEHAVIOR,
481        "Sets the current transaction's isolation level.",
482        None,
483        NO_RESET,
484    ),
485    define(
486        "transaction_read_only",
487        boolean(false),
488        ParameterContext::User,
489        STATEMENT_BEHAVIOR,
490        "Sets the current transaction's read-only status.",
491        None,
492        NO_RESET,
493    ),
494    timeout(
495        "transaction_timeout",
496        "Sets the maximum allowed duration of any transaction within a session (not a prepared transaction).",
497    ),
498    ParameterDefinition {
499        name: "work_mem",
500        kind: ParameterKind::Integer {
501            boot: 4096,
502            min: 64,
503            max: i32::MAX,
504            unit: Some(ParameterUnit::Kilobytes),
505        },
506        context: ParameterContext::User,
507        category: "Resource Usage / Memory",
508        short_desc: "Sets the maximum memory to be used for query workspaces.",
509        extra_desc: Some("This much memory can be used by each internal sort operation and hash table before switching to temporary disk files."),
510        flags: ParameterFlags::NONE,
511        library: None,
512    },
513    define(
514        "xmloption",
515        enumerated(1, XML_OPTIONS),
516        ParameterContext::User,
517        STATEMENT_BEHAVIOR,
518        "Sets whether XML data in implicit parsing and serialization operations is to be considered as documents or content fragments.",
519        None,
520        ParameterFlags::NONE,
521    ),
522];
523
524/// The names that `PostgreSQL` still accepts for renamed parameters (`map_old_guc_names`).
525const OLD_NAMES: &[(&str, &str)] = &[("sort_mem", "work_mem")];
526
527/// Every parameter the engine defines, in `SHOW ALL` order.
528pub fn parameter_definitions() -> &'static [ParameterDefinition] {
529    PARAMETERS
530}
531
532/// The parameter `name` refers to, in any case and under a former name.
533pub fn find_parameter(name: &str) -> Option<&'static ParameterDefinition> {
534    let name = OLD_NAMES
535        .iter()
536        .find(|(old, _)| old.eq_ignore_ascii_case(name))
537        .map_or(name, |(_, current)| current);
538    PARAMETERS
539        .iter()
540        .find(|definition| definition.name.eq_ignore_ascii_case(name))
541}