Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions src/impls/translator_impls/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ fn drop_label(object_type: ObjectType) -> &'static str {
ObjectType::Stage => "DROP STAGE",
ObjectType::Stream => "DROP STREAM",
ObjectType::Warehouse => "DROP WAREHOUSE",
ObjectType::ForeignTable => "DROP FOREIGN TABLE",
ObjectType::Table
| ObjectType::View
| ObjectType::Index
Expand Down Expand Up @@ -1890,11 +1891,8 @@ impl crate::traits::translator::TranslatorWithContext for Statement {
}
statements
}
// A schema, role, or type never reached the output, so
// dropping the statement removes nothing that exists. The
// exceptions are the two that would destroy tables: a
// cascading DROP SCHEMA removes every table in the schema,
// and DROP DATABASE removes the lot.
// These never reached the output, so a drop removes nothing
// unless it cascades into tables or views that did.
ObjectType::Schema if *cascade => {
return Err(reject_unsupported_statement(
self,
Expand All @@ -1903,6 +1901,14 @@ impl crate::traits::translator::TranslatorWithContext for Statement {
determined. Drop the tables by name instead.",
));
}
ObjectType::ForeignTable if *cascade => {
return Err(reject_unsupported_statement(
self,
"A cascading DROP FOREIGN TABLE also deletes the views that read the \
table, and those views reach the output although the table does not. Drop \
the views by name instead.",
));
}
ObjectType::Database | ObjectType::MaterializedView => {
return Err(reject_unsupported_statement(
self,
Expand All @@ -1918,7 +1924,8 @@ impl crate::traits::translator::TranslatorWithContext for Statement {
| ObjectType::Collation
| ObjectType::Stage
| ObjectType::Stream
| ObjectType::Warehouse => {
| ObjectType::Warehouse
| ObjectType::ForeignTable => {
drop_with_warning(
drop_label(*object_type),
REASON_DROP_OF_ABSENT_OBJECT,
Expand Down
12 changes: 12 additions & 0 deletions tests/test_drop_statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,18 @@ fn drop_database_is_rejected() {
);
}

/// A cascading `DROP FOREIGN TABLE` also deletes the views over the table,
/// which reach the output.
#[test]
fn drop_foreign_table_cascade_is_rejected() {
let error = translate_statement("DROP FOREIGN TABLE remote_users CASCADE;")
.expect_err("a cascading DROP FOREIGN TABLE must be reported");
assert!(
error.to_string().contains("DROP FOREIGN TABLE remote_users CASCADE"),
"expected the error to name the statement, got {error}"
);
}

#[test]
fn test_drop_sequence_ignored() -> Result<(), Box<dyn std::error::Error>> {
let translated = translate_statement("DROP SEQUENCE my_sequence;")?;
Expand Down
2 changes: 2 additions & 0 deletions tests/test_no_statement_is_silently_dropped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ const CASES: &[Case] = &[
// Warned and dropped: foreign data and credentials.
warned("CREATE SERVER srv FOREIGN DATA WRAPPER postgres_fdw"),
warned("CREATE FOREIGN TABLE ft (id INT) SERVER srv"),
warned("DROP FOREIGN TABLE ft"),
warned("COMMENT ON FOREIGN TABLE ft IS 'note'"),
warned("CREATE CONNECTOR c TYPE 'mysql'"),
warned("ALTER CONNECTOR c SET URL 'u'"),
warned("DROP CONNECTOR c"),
Expand Down