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