use crate::SQLError;
pub fn valid_custom_name(name: &str) -> bool {
let mut saw_separator = false;
let mut component_start = true;
for byte in name.bytes() {
if byte == b'.' {
if component_start {
return false;
}
saw_separator = true;
component_start = true;
} else if byte.is_ascii_alphabetic() || byte == b'_' || byte >= 0x80 {
component_start = false;
} else if component_start || !(byte.is_ascii_digit() || byte == b'$') {
return false;
}
}
!component_start && saw_separator
}
pub fn check_assignable_custom_name<'a>(
name: &str,
reserved_prefixes: impl IntoIterator<Item = &'a str>,
) -> Result<(), SQLError> {
let Some((prefix, _)) = name.split_once('.') else {
return Err(unrecognized_parameter(name));
};
if !valid_custom_name(name) {
return Err(SQLError::Diagnostic {
sqlstate: "42602".into(),
message: format!("invalid configuration parameter name \"{name}\""),
detail: Some(
"Custom parameter names must be two or more simple identifiers separated by dots."
.into(),
),
hint: None,
});
}
if let Some(reserved) = reserved_prefixes
.into_iter()
.find(|reserved| *reserved == prefix)
{
return Err(SQLError::Diagnostic {
sqlstate: "42602".into(),
message: format!("invalid configuration parameter name \"{name}\""),
detail: Some(format!("\"{reserved}\" is a reserved prefix.")),
hint: None,
});
}
Ok(())
}
pub fn reserved_placeholder_warning(name: &str, prefix: &str) -> (String, String) {
(
format!("invalid configuration parameter name \"{name}\", removing it"),
format!("\"{prefix}\" is now a reserved prefix."),
)
}
pub fn unrecognized_parameter(name: &str) -> SQLError {
SQLError::Routine {
sqlstate: "42704".into(),
message: format!("unrecognized configuration parameter \"{name}\""),
}
}
#[cfg(test)]
mod tests;