use crate::error::{TViewError, TViewResult};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Compression {
Pglz,
Lz4,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DataStorage {
Extended,
Main,
External,
}
impl Compression {
pub const NAMES: &'static str = "pglz or lz4";
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name {
"pglz" => Some(Self::Pglz),
"lz4" => Some(Self::Lz4),
_ => None,
}
}
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::Pglz => "pglz",
Self::Lz4 => "lz4",
}
}
pub fn available(self) -> TViewResult<bool> {
Ok(crate::utils::spi::one::<bool>(
"SELECT $1 = ANY (enumvals) FROM pg_catalog.pg_settings \
WHERE name = 'default_toast_compression'",
&[crate::utils::spi::text(self.name())],
)?
.unwrap_or(false))
}
pub fn check_available(self) -> TViewResult<()> {
if self.available()? {
Ok(())
} else {
Err(TViewError::InvalidInput {
parameter: "data_compression".to_string(),
reason: format!(
"{} is not available: this PostgreSQL server was built without it; \
declare \"pglz\"",
self.name()
),
})
}
}
pub fn server_default() -> TViewResult<Self> {
Ok(if Self::Lz4.available()? {
Self::Lz4
} else {
Self::Pglz
})
}
}
impl DataStorage {
pub const NAMES: &'static str = "extended, main or external";
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name {
"extended" => Some(Self::Extended),
"main" => Some(Self::Main),
"external" => Some(Self::External),
_ => None,
}
}
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::Extended => "extended",
Self::Main => "main",
Self::External => "external",
}
}
}
pub const TOAST_TUPLE_TARGET: std::ops::RangeInclusive<i32> = 128..=8160;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Storage {
pub logged: bool,
pub fillfactor: i32,
pub data_gin_index: bool,
pub data_compression: Compression,
pub data_storage: DataStorage,
pub toast_tuple_target: Option<i32>,
}
impl Storage {
pub const DEFAULT: Self = Self {
logged: true,
fillfactor: 85,
data_gin_index: false,
data_compression: Compression::Lz4,
data_storage: DataStorage::Main,
toast_tuple_target: None,
};
#[must_use]
pub fn data_column_clause(&self) -> String {
format!(
" STORAGE {} COMPRESSION {}",
self.data_storage.name().to_uppercase(),
self.data_compression.name()
)
}
#[must_use]
pub fn with_clause(&self) -> String {
let mut parameters = Vec::new();
if self.fillfactor < 100 {
parameters.push(format!("fillfactor = {}", self.fillfactor));
}
if let Some(target) = self.toast_tuple_target {
parameters.push(format!("toast_tuple_target = {target}"));
}
if parameters.is_empty() {
String::new()
} else {
format!(" WITH ({})", parameters.join(", "))
}
}
#[must_use]
pub fn rewrites_rows_from(&self, current: &Self) -> bool {
self.data_compression != current.data_compression
|| self.data_storage != current.data_storage
|| self.toast_tuple_target != current.toast_tuple_target
}
}