Skip to content
Open
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
13 changes: 11 additions & 2 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4849,11 +4849,16 @@ impl Spanned for AlterCollation {
}
}

/// `ALTER VIEW` statement.
/// `ALTER [ MATERIALIZED ] VIEW` statement.
///
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-altermaterializedview.html)
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct AlterView {
/// Whether `MATERIALIZED` was specified. A materialized view's operation is never
/// [`AlterViewOperation::As`] or [`AlterViewOperation::AlterColumn`].
pub materialized: bool,
/// View name being altered.
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub name: ObjectName,
Expand Down Expand Up @@ -4977,7 +4982,11 @@ impl fmt::Display for AlterViewOperation {

impl fmt::Display for AlterView {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ALTER VIEW ")?;
write!(f, "ALTER ")?;
if self.materialized {
write!(f, "MATERIALIZED ")?;
}
write!(f, "VIEW ")?;
if self.if_exists {
write!(f, "IF EXISTS ")?;
}
Expand Down
2 changes: 1 addition & 1 deletion src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3911,7 +3911,7 @@ pub enum Statement {
operation: AlterIndexOperation,
},
/// ```sql
/// ALTER VIEW
/// ALTER [ MATERIALIZED ] VIEW
/// ```
AlterView(AlterView),
/// ```sql
Expand Down
13 changes: 9 additions & 4 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11847,7 +11847,11 @@ impl<'a> Parser<'a> {
self.prev_token();
self.parse_alter_schema()
}
Keyword::VIEW => self.parse_alter_view(),
Keyword::VIEW => self.parse_alter_view(false),
Keyword::MATERIALIZED => {
self.expect_keyword_is(Keyword::VIEW)?;
self.parse_alter_view(true)
}
Keyword::TYPE => self.parse_alter_type(),
Keyword::COLLATION => self.parse_alter_collation().map(Into::into),
Keyword::TABLE => self.parse_alter_table(false),
Expand Down Expand Up @@ -11895,7 +11899,7 @@ impl<'a> Parser<'a> {
_ => {
self.index = index;
self.expected_ref(
"one of VIEW or TYPE or COLLATION or TABLE or INDEX or FUNCTION or AGGREGATE or ROLE or POLICY or TRIGGER or CONNECTOR or ICEBERG or SCHEMA or USER or OPERATOR",
"one of VIEW or MATERIALIZED VIEW or TYPE or COLLATION or TABLE or INDEX or FUNCTION or AGGREGATE or ROLE or POLICY or TRIGGER or CONNECTOR or ICEBERG or SCHEMA or USER or OPERATOR",
self.peek_token_ref(),
)
}
Expand Down Expand Up @@ -12159,8 +12163,8 @@ impl<'a> Parser<'a> {
.into())
}

/// Parse an `ALTER VIEW` statement.
pub fn parse_alter_view(&mut self) -> Result<Statement, ParserError> {
/// Parse an `ALTER [ MATERIALIZED ] VIEW` statement.
pub fn parse_alter_view(&mut self, materialized: bool) -> Result<Statement, ParserError> {
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
let name = self.parse_object_name(false)?;

Expand Down Expand Up @@ -12230,6 +12234,7 @@ impl<'a> Parser<'a> {
};

Ok(AlterView {
materialized,
name,
if_exists,
operation,
Expand Down
9 changes: 6 additions & 3 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5669,6 +5669,7 @@ fn parse_alter_view() {
let sql = "ALTER VIEW myschema.myview AS SELECT foo FROM bar";
match verified_stmt(sql) {
Statement::AlterView(AlterView {
materialized: false,
name,
if_exists,
operation:
Expand Down Expand Up @@ -5723,6 +5724,7 @@ fn parse_alter_view_with_columns() {
let sql = "ALTER VIEW v (has, cols) AS SELECT 1, 2";
match verified_stmt(sql) {
Statement::AlterView(AlterView {
materialized: false,
name,
if_exists,
operation:
Expand Down Expand Up @@ -5752,6 +5754,7 @@ fn parse_alter_view_operations() {
assert_eq!(
verified_stmt("ALTER VIEW IF EXISTS s.v OWNER TO o"),
Statement::AlterView(AlterView {
materialized: false,
name: ObjectName::from(vec![Ident::new("s"), Ident::new("v")]),
if_exists: true,
operation: AlterViewOperation::OwnerTo(Owner::Ident(Ident::new("o"))),
Expand Down Expand Up @@ -5902,7 +5905,7 @@ fn display_alter_view_propagates_write_errors() {
}

let with_options = verified_stmt("ALTER VIEW IF EXISTS v WITH (x = 1) AS SELECT 1");
for rejected in ["ALTER VIEW ", "IF EXISTS ", "WITH ("] {
for rejected in ["ALTER ", "VIEW ", "IF EXISTS ", "WITH ("] {
let mut writer = RejectingWriter(rejected);
assert_eq!(
write!(writer, "{with_options}"),
Expand All @@ -5912,7 +5915,7 @@ fn display_alter_view_propagates_write_errors() {
}

let columns = verified_stmt("ALTER VIEW IF EXISTS v (zeta) AS SELECT 1");
for rejected in ["ALTER VIEW ", "IF EXISTS ", "("] {
for rejected in ["ALTER ", "VIEW ", "IF EXISTS ", "("] {
let mut writer = RejectingWriter(rejected);
assert_eq!(write!(writer, "{columns}"), Err(fmt::Error), "{rejected:?}");
}
Expand Down Expand Up @@ -16070,7 +16073,7 @@ fn parse_alter_trigger_spans() {

#[test]
fn parse_alter_rejects_missing_or_unknown_object_type() {
let objects = "one of VIEW or TYPE or COLLATION or TABLE or INDEX or FUNCTION or AGGREGATE or ROLE or POLICY or TRIGGER or CONNECTOR or ICEBERG or SCHEMA or USER or OPERATOR";
let objects = "one of VIEW or MATERIALIZED VIEW or TYPE or COLLATION or TABLE or INDEX or FUNCTION or AGGREGATE or ROLE or POLICY or TRIGGER or CONNECTOR or ICEBERG or SCHEMA or USER or OPERATOR";
for (sql, found) in [
("ALTER", "EOF"),
("ALTER 1", "1"),
Expand Down
84 changes: 84 additions & 0 deletions tests/sqlparser_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12291,3 +12291,87 @@ fn parse_create_table_partition_of_untyped_columns() {
);
}
}

#[test]
fn parse_alter_materialized_view() {
assert_eq!(
pg_and_generic().verified_stmt("ALTER MATERIALIZED VIEW IF EXISTS s.m OWNER TO alice"),
Statement::AlterView(AlterView {
materialized: true,
name: ObjectName::from(vec![Ident::new("s"), Ident::new("m")]),
if_exists: true,
operation: AlterViewOperation::OwnerTo(Owner::Ident(Ident::new("alice"))),
})
);
assert_eq!(
pg_and_generic().verified_stmt("ALTER MATERIALIZED VIEW m SET (fillfactor = 70)"),
Statement::AlterView(AlterView {
materialized: true,
name: ObjectName::from(vec![Ident::new("m")]),
if_exists: false,
operation: AlterViewOperation::SetOptions {
options: vec![SqlOption::KeyValue {
key: ObjectName::from(vec![Ident::new("fillfactor")]),
value: Expr::value(number("70")),
}],
},
})
);
for sql in [
"ALTER MATERIALIZED VIEW m RESET (fillfactor, autovacuum_enabled)",
"ALTER MATERIALIZED VIEW m RENAME TO m2",
"ALTER MATERIALIZED VIEW m RENAME COLUMN a TO b",
"ALTER MATERIALIZED VIEW m SET SCHEMA s",
] {
pg_and_generic().verified_stmt(sql);
}
assert_eq!(
pg_and_generic().verified_stmt("ALTER MATERIALIZED VIEW m ALTER COLUMN c SET DEFAULT 1"),
Statement::AlterView(AlterView {
materialized: true,
name: ObjectName::from(vec![Ident::new("m")]),
if_exists: false,
operation: AlterViewOperation::AlterColumn {
column_name: Ident::new("c"),
op: AlterColumnOperation::SetDefault {
value: Expr::value(number("1")),
},
},
})
);
pg_and_generic().verified_stmt("ALTER MATERIALIZED VIEW m ALTER COLUMN c DROP DEFAULT");

assert_eq!(
pg_and_generic()
.parse_sql_statements("ALTER MATERIALIZED m OWNER TO alice")
.unwrap_err(),
ParserError::ParserError("Expected: VIEW, found: m".to_string())
);
}

#[test]
fn display_alter_materialized_view_propagates_write_errors() {
use core::fmt::{self, Write};

struct RejectingWriter(&'static str);

impl Write for RejectingWriter {
fn write_str(&mut self, value: &str) -> fmt::Result {
if value == self.0 {
Err(fmt::Error)
} else {
Ok(())
}
}
}

let materialized = pg_and_generic().verified_stmt("ALTER MATERIALIZED VIEW m RENAME TO m2");
for rejected in ["ALTER ", "MATERIALIZED ", "VIEW "] {
let mut writer = RejectingWriter(rejected);
assert_eq!(
write!(writer, "{materialized}"),
Err(fmt::Error),
"{rejected:?}"
);
}
}
Loading