use pgrx::pg_sys::panic::ErrorReport;
use pgrx::prelude::*;
use crate::ddl::replace;
use crate::error::TViewError;
#[pg_extern(name = "pg_tviews_create")]
#[allow(clippy::needless_pass_by_value)] fn pg_tviews_create_with_options(
tview: &str,
query: &str,
options: default!(pgrx::JsonB, "'{}'"),
) -> Result<String, ErrorReport> {
crate::revision::check();
let options = replace::parse_options(&options.0)?;
match replace::create_only(tview, query, options, false) {
Ok(replace::Created::Rows(_) | replace::Created::Skipped) => {
Ok(format!("TVIEW {} created", created_relation(tview)))
}
Ok(replace::Created::Exists(name)) => Err(TViewError::RelationExists { name }.into()),
Err(e) => Err(e.report_in("Failed to create TVIEW")),
}
}
#[pg_extern]
#[allow(clippy::needless_pass_by_value)] fn pg_tviews_create_or_replace(
tview: &str,
query: &str,
options: default!(pgrx::JsonB, "'{}'"),
) -> Result<String, ErrorReport> {
crate::revision::check();
replace::create_or_replace(tview, query, &options.0)
.map(str::to_string)
.map_err(|e| e.report_in(&format!("Failed to create or replace TVIEW {tview}")))
}
#[pg_extern]
fn pg_tviews_drop(
tview: &str,
if_exists: default!(bool, false),
cascade: default!(bool, false),
) -> Result<String, ErrorReport> {
crate::revision::check();
let relation = crate::catalog::resolve::find(tview)
.ok()
.map(|found| super::table_name(found.table, &found.entity));
match crate::ddl::drop_tview(tview, if_exists, cascade) {
Ok(true) => Ok(format!(
"TVIEW {} dropped",
relation.unwrap_or_else(|| tview.to_string())
)),
Ok(false) => Ok(format!("TVIEW {tview} does not exist, nothing dropped")),
Err(e) => Err(e.report_in("Failed to drop TVIEW")),
}
}
#[pg_extern]
fn pg_tviews_reregister(tview: &str) -> Result<String, ErrorReport> {
crate::revision::check();
let found = super::owned(tview)?;
crate::ddl::create::reregister_tview(&found.entity)
.map(|()| "reregistered".to_string())
.map_err(|e| e.report_in(&format!("Failed to re-register TVIEW {tview}")))
}
#[pg_extern]
fn pg_tviews_refresh(tview: &str) -> Result<(), ErrorReport> {
crate::revision::check();
let found = super::owned(tview)?;
crate::admin::rebuild_with_dependents(&[found.entity])?;
Ok(())
}
#[pg_extern]
fn pg_tviews_refresh_time_dependent(
tview: default!(Option<&str>, "NULL"),
) -> Result<SetOfIterator<'static, String>, ErrorReport> {
crate::revision::check();
let chosen = match tview {
Some(name) => {
let meta = super::owned_meta(name)?;
if !meta.time_dependent {
return Err(TViewError::InvalidInput {
parameter: "tview".to_string(),
reason: format!(
"{} does not read the time: nothing to refresh",
super::relation(&meta)
),
}
.into());
}
vec![meta]
}
None => crate::admin::owned_time_dependent()?,
};
Ok(SetOfIterator::new(crate::admin::refresh_time_dependent(
&chosen,
)?))
}
#[pg_extern]
fn pg_tviews_ensure_propagation_indexes(
tview: default!(Option<&str>, "NULL"),
dry_run: default!(bool, false),
) -> Result<SetOfIterator<'static, String>, ErrorReport> {
crate::revision::check();
let metas = if let Some(name) = tview {
vec![super::owned_meta(name)?]
} else {
let metas: Vec<_> = crate::catalog::TviewMeta::load_all()?
.into_iter()
.map(std::rc::Rc::new)
.collect();
for meta in &metas {
crate::owner::require_owner(meta.tview_oid, &super::relation(meta))?;
}
metas
};
Ok(SetOfIterator::new(
crate::admin::ensure_propagation_indexes(&metas, dry_run)?,
))
}
#[pg_extern]
#[allow(clippy::type_complexity)] fn pg_tviews_show_cascade_path(
tview: &str,
) -> Result<
TableIterator<
'static,
(
name!(depth, i32),
name!(entity, String),
name!(depends_on, String),
),
>,
ErrorReport,
> {
crate::revision::check();
let found = crate::catalog::resolve::find(tview)?;
Ok(TableIterator::new(crate::admin::cascade_path(
&found.entity,
)?))
}
#[pg_extern]
fn pg_tviews_mapping_query(
tview: &str,
base_table: pg_sys::Oid,
) -> Result<Option<String>, ErrorReport> {
crate::revision::check();
let report = |e: TViewError| e.report_in(&format!("pg_tviews: the mapping query of {tview}"));
let meta = crate::catalog::resolve::resolve(tview)?;
crate::delta::mapping_query(&meta, base_table).map_err(report)
}
#[pg_extern]
#[allow(clippy::type_complexity)] fn pg_tviews_read_set_queries(
tview: &str,
base_table: pg_sys::Oid,
) -> Result<
TableIterator<
'static,
(
name!(column_name, Option<String>),
name!(query, Option<String>),
),
>,
ErrorReport,
> {
crate::revision::check();
let report = |e: TViewError| e.report_in(&format!("pg_tviews: the read sets of {tview}"));
let meta = crate::catalog::resolve::resolve(tview)?;
Ok(TableIterator::new(
crate::delta::read_set_queries(&meta, base_table).map_err(report)?,
))
}
fn created_relation(tview: &str) -> String {
crate::catalog::resolve::find(tview).map_or_else(
|_| tview.to_string(),
|found| super::table_name(found.table, &found.entity),
)
}