use super::{CatalogIndexRow, Engine, RelationIdentity, StorageBackendError, StorageBackendResult};
pub(crate) fn is_virtual_system_schema(name: &str) -> bool {
matches!(name, "pg_catalog" | "information_schema" | "ag_catalog")
}
impl Engine {
pub fn list_catalog_indexes(&self) -> StorageBackendResult<Vec<CatalogIndexRow>> {
if let Some(snapshot) = self.query_catalog_snapshot.as_ref() {
let mut out = snapshot
.catalog_indexes
.values()
.cloned()
.collect::<Vec<_>>();
out.sort_by(|a, b| a.relation.cmp(&b.relation));
return Ok(out);
}
self.synchronize_catalog_registries()?;
let mut out: Vec<CatalogIndexRow> = self
.durable
.catalog_indexes
.read()
.values()
.cloned()
.collect();
out.sort_by(|a, b| a.relation.cmp(&b.relation));
Ok(out)
}
pub fn register_schema(&self, name: &str, if_not_exists: bool) -> StorageBackendResult<bool> {
self.with_implicit_storage_transaction(|engine| {
engine.synchronize_catalog_registries()?;
let role_owner = engine.current_user_name();
engine
.mutation_coordinator()
.register_schema(name, if_not_exists, &role_owner)
})
}
pub fn drop_schema(&self, name: &str) -> StorageBackendResult<bool> {
self.with_implicit_storage_transaction(|engine| engine.drop_schema_inner(name))
}
pub(crate) fn preflight_drop_schema(&self, name: &str) -> StorageBackendResult<bool> {
self.synchronize_catalog_registries()?;
if name == "public" || is_virtual_system_schema(name) {
return Err(StorageBackendError::Other(format!(
"schema `{name}` cannot be dropped"
)));
}
if !self.durable.schemas.read().contains_key(name) {
return Ok(false);
}
if !self.schema_is_empty(name) {
return Err(StorageBackendError::Other(format!(
"schema `{name}` is not empty"
)));
}
Ok(true)
}
fn drop_schema_inner(&self, name: &str) -> StorageBackendResult<bool> {
if !self.preflight_drop_schema(name)? {
return Ok(false);
}
let mut schemas = self.durable.schemas.write();
if let Some(catalog) = self.storage.catalog.as_ref() {
catalog.drop_schema(name)?;
}
let removed = schemas.remove(name).is_some();
drop(schemas);
if removed {
self.note_catalog_registry_changed();
}
Ok(removed)
}
pub fn has_schema(&self, name: &str) -> StorageBackendResult<bool> {
self.synchronize_catalog_registries()?;
Ok(self.durable.schemas.read().contains_key(name))
}
pub fn has_namespace(&self, name: &str) -> StorageBackendResult<bool> {
self.synchronize_catalog_registries()?;
Ok(is_virtual_system_schema(name)
|| self.durable.schemas.read().contains_key(name)
|| self.durable.graphs.read().contains_key(name))
}
pub(crate) fn validate_schema_name(name: &str) -> StorageBackendResult<()> {
crate::engine_capabilities::validate_schema_name(name)
}
fn schema_is_empty(&self, schema: &str) -> bool {
!self
.storage
.tables
.read()
.keys()
.any(|relation| relation.schema == schema)
&& !self
.durable
.views
.read()
.keys()
.any(|relation| relation.schema == schema)
&& !self
.durable
.sequences
.read()
.keys()
.any(|relation| relation.schema == schema)
&& !self
.durable
.foreign_tables
.read()
.keys()
.any(|relation| relation.schema == schema)
&& !self
.durable
.catalog_indexes
.read()
.keys()
.any(|relation| relation.schema == schema)
&& !self.durable.sql_user_functions.read().keys().any(|name| {
RelationIdentity::from_legacy_name(name)
.map_or(true, |relation| relation.schema == schema)
})
}
pub fn list_schemas(&self) -> StorageBackendResult<Vec<String>> {
if let Some(snapshot) = self.query_catalog_snapshot.as_ref() {
return Ok(snapshot.schemas.keys().cloned().collect());
}
self.synchronize_catalog_registries()?;
Ok(self.durable.schemas.read().keys().cloned().collect())
}
pub fn tables_in_schema(&self, schema: &str) -> StorageBackendResult<Vec<String>> {
self.synchronize_table_catalog()?;
let mut out: Vec<String> = Vec::new();
for relation in self.storage.tables.read().keys() {
if relation.schema == schema {
out.push(relation.name.clone());
}
}
out.sort_unstable();
Ok(out)
}
pub fn list_sequences(&self) -> StorageBackendResult<Vec<String>> {
if let Some(snapshot) = self.query_catalog_snapshot.as_ref() {
let mut out = snapshot
.sequences
.keys()
.map(RelationIdentity::qualified_name)
.collect::<Vec<_>>();
out.sort_unstable();
return Ok(out);
}
self.refresh_sequences_from_catalog()?;
let mut out: Vec<String> = self
.durable
.sequences
.read()
.keys()
.map(RelationIdentity::qualified_name)
.collect();
out.sort_unstable();
Ok(out)
}
}