use std::net::SocketAddr;
use super::store::SessionStore;
impl SessionStore {
pub fn set_parameter(&self, addr: &SocketAddr, key: String, value: String) {
self.write_session(addr, |session| {
session.parameters.insert(key, value);
});
}
pub fn get_parameter(&self, addr: &SocketAddr, key: &str) -> Option<String> {
self.read_session(addr, |s| s.parameters.get(key).cloned())?
}
pub fn all_parameters(&self, addr: &SocketAddr) -> Vec<(String, String)> {
self.read_session(addr, |s| {
let mut params: Vec<_> = s
.parameters
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect();
params.sort_by(|a, b| a.0.cmp(&b.0));
params
})
.unwrap_or_default()
}
}
pub fn parse_set_command(sql: &str) -> Option<(String, String)> {
let trimmed = sql.trim();
let upper = trimmed.to_uppercase();
let rest = if upper.starts_with("SET SESSION ") {
&trimmed[12..]
} else if upper.starts_with("SET LOCAL ") {
&trimmed[10..]
} else if upper.starts_with("SET ") {
&trimmed[4..]
} else {
return None;
};
let rest = rest.trim();
let (key, value) = if let Some(eq_pos) = rest.find('=') {
let k = rest[..eq_pos].trim();
let v = rest[eq_pos + 1..].trim();
(k, v)
} else {
let upper_rest = rest.to_uppercase();
if let Some(to_pos) = upper_rest.find(" TO ") {
let k = rest[..to_pos].trim();
let v = rest[to_pos + 4..].trim();
(k, v)
} else {
return None;
}
};
if key.is_empty() {
return None;
}
let value = value.trim_matches('\'').trim_matches('"').to_string();
Some((key.to_lowercase(), value))
}
pub const KNOWN_PG_RUNTIME_PARAMETERS: &[&str] = &[
"all",
"application_name",
"client_encoding",
"client_min_messages",
"datestyle",
"default_transaction_isolation",
"default_transaction_read_only",
"extra_float_digits",
"integer_datetimes",
"intervalstyle",
"is_superuser",
"lc_collate",
"lc_ctype",
"lc_messages",
"lc_monetary",
"lc_numeric",
"lc_time",
"server_encoding",
"server_version",
"server_version_num",
"search_path",
"session_authorization",
"standard_conforming_strings",
"statement_timeout",
"timezone",
"time zone",
"transaction_isolation",
"transaction_read_only",
"nodedb.consistency",
"nodedb.tenant_id",
"rounding_mode",
];
pub const SETTABLE_RUNTIME_PARAMETERS: &[&str] = &[
"application_name",
"client_encoding",
"client_min_messages",
"datestyle",
"default_transaction_isolation",
"default_transaction_read_only",
"extra_float_digits",
"intervalstyle",
"lc_collate",
"lc_ctype",
"lc_messages",
"lc_monetary",
"lc_numeric",
"lc_time",
"search_path",
"standard_conforming_strings",
"statement_timeout",
"timezone",
"time zone",
"transaction_isolation",
"transaction_read_only",
"rounding_mode",
"tenant",
"role",
"session_authorization",
"nodedb.consistency",
"nodedb.read_consistency",
"nodedb.cross_shard_mode",
"nodedb.tenant_id",
"nodedb.auth_session",
"cross_shard_txn",
];
pub fn is_known_settable_runtime_parameter(name: &str) -> bool {
let lower = name.to_lowercase();
SETTABLE_RUNTIME_PARAMETERS
.iter()
.any(|p| p.eq_ignore_ascii_case(&lower))
}
pub fn is_known_pg_runtime_parameter(name: &str) -> bool {
let lower = name.to_lowercase();
KNOWN_PG_RUNTIME_PARAMETERS
.iter()
.any(|p| p.eq_ignore_ascii_case(&lower))
}
pub fn parse_show_command(sql: &str) -> Option<String> {
let trimmed = sql.trim();
let upper = trimmed.to_uppercase();
if !upper.starts_with("SHOW ") {
return None;
}
let param = trimmed[5..].trim().to_lowercase();
if param.is_empty() {
return None;
}
Some(param)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_set_equals() {
let (k, v) = parse_set_command("SET client_encoding = 'UTF8'").unwrap();
assert_eq!(k, "client_encoding");
assert_eq!(v, "UTF8");
}
#[test]
fn parse_set_to() {
let (k, v) = parse_set_command("SET search_path TO public").unwrap();
assert_eq!(k, "search_path");
assert_eq!(v, "public");
}
#[test]
fn parse_set_session() {
let (k, v) = parse_set_command("SET SESSION nodedb.consistency = 'eventual'").unwrap();
assert_eq!(k, "nodedb.consistency");
assert_eq!(v, "eventual");
}
#[test]
fn parse_set_nodedb_tenant() {
let (k, v) = parse_set_command("SET nodedb.tenant_id = 5").unwrap();
assert_eq!(k, "nodedb.tenant_id");
assert_eq!(v, "5");
}
#[test]
fn parse_show() {
assert_eq!(
parse_show_command("SHOW client_encoding"),
Some("client_encoding".into())
);
assert_eq!(parse_show_command("SHOW ALL"), Some("all".into()));
assert_eq!(parse_show_command("SHOW"), None);
}
}