use rupg_common::{Error, Result, SqlState};
use rupg_sql::nodes::Node;
use super::alter::Target;
use super::reloptions::{self, Opt};
use super::{Definer, relkind_detail};
const HEAP_NAMESPACES: &[&str] = &["toast"];
const HASH: u32 = 405;
fn index_options(method: u32) -> &'static [Opt] {
if method == HASH { reloptions::HASH } else { reloptions::BTREE }
}
impl Definer<'_, '_> {
pub(super) fn create_table_options(&self, defs: &[Option<Node>]) -> Result<Vec<String>> {
let options = reloptions::transform_create(defs, None, HEAP_NAMESPACES)?;
reloptions::validate(&options, reloptions::HEAP, false)?;
Ok(options)
}
pub(super) fn create_toast_options(&mut self, table: u32, defs: &[Option<Node>]) -> Result<()> {
let options = reloptions::transform_create(defs, Some("toast"), HEAP_NAMESPACES)?;
reloptions::validate(&options, reloptions::HEAP, true)?;
let toast = self.catalog.relation(table).map_or(0, |r| r.toast);
if toast != 0 && !options.is_empty() {
self.catalog.set_options(toast, options)?;
}
Ok(())
}
pub(super) fn create_index_options(
&self,
method: u32,
defs: &[Option<Node>],
) -> Result<Vec<String>> {
let options = reloptions::transform(&[], defs, None, &[], false)?;
reloptions::validate(&options, index_options(method), false)?;
Ok(options)
}
pub(super) fn set_rel_options(
&mut self,
target: &Target,
defs: &[Option<Node>],
reset: bool,
) -> Result<()> {
if defs.is_empty() {
return Ok(());
}
let Some(rel) = self.catalog.relation(target.oid) else { return Ok(()) };
let toast = rel.toast;
let method = rel.index.as_ref().map_or(0, |i| i.method);
let options = reloptions::transform(&rel.options, defs, None, HEAP_NAMESPACES, reset)?;
match target.kind {
b'r' | b'm' => reloptions::validate(&options, reloptions::HEAP, false)?,
b'p' if !options.is_empty() => {
return Err(Error::new(
SqlState::WRONG_OBJECT_TYPE,
"cannot specify storage parameters for a partitioned table",
)
.with_hint("Specify storage parameters for its leaf partitions instead."));
}
b'p' => {}
b'v' => reloptions::validate(&options, reloptions::VIEW, false)?,
b'i' | b'I' => reloptions::validate(&options, index_options(method), false)?,
kind => {
return Err(Error::new(
SqlState::WRONG_OBJECT_TYPE,
format!("cannot set options for relation \"{}\"", target.name),
)
.with_detail(relkind_detail(kind)));
}
}
if target.kind == b'v' && options.iter().any(|o| o.starts_with("check_option=")) {
let (query, _) = self
.an
.stored_query_perms(target.oid)?
.ok_or_else(|| Error::internal("a view with no query"))?;
self.an.auto_updatable(&query, true).map_err(super::view::check_option_error)?;
}
self.catalog.set_options(target.oid, options)?;
if let Some(rel) = self.catalog.relation(toast) {
let options =
reloptions::transform(&rel.options, defs, Some("toast"), HEAP_NAMESPACES, reset)?;
reloptions::validate(&options, reloptions::HEAP, true)?;
self.catalog.set_options(toast, options)?;
}
Ok(())
}
}