uqa_sql/semantics/parameters/
custom.rs1use crate::SQLError;
10
11pub fn valid_custom_name(name: &str) -> bool {
13 let mut saw_separator = false;
14 let mut component_start = true;
15 for byte in name.bytes() {
16 if byte == b'.' {
17 if component_start {
18 return false;
19 }
20 saw_separator = true;
21 component_start = true;
22 } else if byte.is_ascii_alphabetic() || byte == b'_' || byte >= 0x80 {
23 component_start = false;
24 } else if component_start || !(byte.is_ascii_digit() || byte == b'$') {
25 return false;
26 }
27 }
28 !component_start && saw_separator
29}
30
31pub fn check_assignable_custom_name<'a>(
33 name: &str,
34 reserved_prefixes: impl IntoIterator<Item = &'a str>,
35) -> Result<(), SQLError> {
36 let Some((prefix, _)) = name.split_once('.') else {
37 return Err(unrecognized_parameter(name));
38 };
39 if !valid_custom_name(name) {
40 return Err(SQLError::Diagnostic {
41 sqlstate: "42602".into(),
42 message: format!("invalid configuration parameter name \"{name}\""),
43 detail: Some(
44 "Custom parameter names must be two or more simple identifiers separated by dots."
45 .into(),
46 ),
47 hint: None,
48 });
49 }
50 if let Some(reserved) = reserved_prefixes
51 .into_iter()
52 .find(|reserved| *reserved == prefix)
53 {
54 return Err(SQLError::Diagnostic {
55 sqlstate: "42602".into(),
56 message: format!("invalid configuration parameter name \"{name}\""),
57 detail: Some(format!("\"{reserved}\" is a reserved prefix.")),
58 hint: None,
59 });
60 }
61 Ok(())
62}
63
64pub fn reserved_placeholder_warning(name: &str, prefix: &str) -> (String, String) {
66 (
67 format!("invalid configuration parameter name \"{name}\", removing it"),
68 format!("\"{prefix}\" is now a reserved prefix."),
69 )
70}
71
72pub fn unrecognized_parameter(name: &str) -> SQLError {
74 SQLError::Routine {
75 sqlstate: "42704".into(),
76 message: format!("unrecognized configuration parameter \"{name}\""),
77 }
78}
79
80#[cfg(test)]
81mod tests;