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
5 changes: 5 additions & 0 deletions fuzz/fuzz_seeds/postgres_886_alter_view.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ALTER VIEW IF EXISTS s.v OWNER TO CURRENT_USER;
ALTER VIEW v SET (security_invoker = true, security_barrier);
ALTER VIEW v RESET (check_option);
ALTER VIEW v ALTER c SET DEFAULT 1;
ALTER VIEW v RENAME c TO d
136 changes: 136 additions & 0 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4825,6 +4825,142 @@ impl Spanned for AlterCollation {
}
}

/// `ALTER VIEW` statement.
#[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 {
/// View name being altered.
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub name: ObjectName,
/// Whether `IF EXISTS` was specified.
pub if_exists: bool,
/// The operation to perform on the view.
pub operation: AlterViewOperation,
}

/// Operations supported by `ALTER VIEW`.
///
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-alterview.html)
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum AlterViewOperation {
/// Replace the view definition.
///
/// ```sql
/// ALTER VIEW name [ (columns) ] [ WITH (options) ] AS query
/// ```
///
/// See [MySQL](https://dev.mysql.com/doc/refman/8.4/en/alter-view.html)
As {
/// Optional new column list for the view.
columns: Vec<Ident>,
/// Replacement query for the view definition.
query: Box<Query>,
/// Additional `WITH` options for the view.
with_options: Vec<SqlOption>,
},
/// ```sql
/// ALTER VIEW name ALTER [ COLUMN ] column_name { SET DEFAULT expression | DROP DEFAULT }
/// ```
AlterColumn {
/// The column to alter.
column_name: Ident,
/// Either [`AlterColumnOperation::SetDefault`] or [`AlterColumnOperation::DropDefault`].
op: AlterColumnOperation,
},
/// ```sql
/// ALTER VIEW name OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
/// ```
OwnerTo(Owner),
/// ```sql
/// ALTER VIEW name RENAME [ COLUMN ] column_name TO new_column_name
/// ```
RenameColumn {
/// Existing column name.
old_column_name: Ident,
/// New column name.
new_column_name: Ident,
},
/// ```sql
/// ALTER VIEW name RENAME TO new_name
/// ```
RenameTo {
/// New view name.
new_name: ObjectName,
},
/// ```sql
/// ALTER VIEW name SET SCHEMA new_schema
/// ```
SetSchema {
/// Target schema name.
schema_name: ObjectName,
},
/// ```sql
/// ALTER VIEW name SET ( view_option_name [ = view_option_value ] [, ... ] )
/// ```
SetOptions {
/// Options to set, [`SqlOption::Ident`] when no value is given.
options: Vec<SqlOption>,
},
/// ```sql
/// ALTER VIEW name RESET ( view_option_name [, ... ] )
/// ```
ResetOptions {
/// Options to reset.
options: Vec<Ident>,
},
}

impl fmt::Display for AlterViewOperation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AlterViewOperation::As {
columns,
query,
with_options,
} => {
if !with_options.is_empty() {
write!(f, "WITH ({}) ", display_comma_separated(with_options))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing, but the parser reads (columns) before WITH (...) while this writes them the other way round, so ALTER VIEW v (a) WITH (x = 1) AS SELECT 1 displays as ALTER VIEW v WITH (x = 1) (a) AS SELECT 1, which doesn't re-parse. Swapping the two blocks here fixes the round-trip.

}
if !columns.is_empty() {
write!(f, "({}) ", display_comma_separated(columns))?;
}
write!(f, "AS {query}")
}
AlterViewOperation::AlterColumn { column_name, op } => {
write!(f, "ALTER COLUMN {column_name} {op}")
}
AlterViewOperation::OwnerTo(owner) => write!(f, "OWNER TO {owner}"),
AlterViewOperation::RenameColumn {
old_column_name,
new_column_name,
} => write!(f, "RENAME COLUMN {old_column_name} TO {new_column_name}"),
AlterViewOperation::RenameTo { new_name } => write!(f, "RENAME TO {new_name}"),
AlterViewOperation::SetSchema { schema_name } => {
write!(f, "SET SCHEMA {schema_name}")
}
AlterViewOperation::SetOptions { options } => {
write!(f, "SET ({})", display_comma_separated(options))
}
AlterViewOperation::ResetOptions { options } => {
write!(f, "RESET ({})", display_comma_separated(options))
}
}
}
}

impl fmt::Display for AlterView {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ALTER VIEW ")?;
if self.if_exists {
write!(f, "IF EXISTS ")?;
}
write!(f, "{} {}", self.name, self.operation)
}
}

/// Table type for ALTER TABLE statements.
/// Used to distinguish between regular tables, Iceberg tables, and Dynamic tables.
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
Expand Down
67 changes: 25 additions & 42 deletions src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,23 @@ pub use self::ddl::{
AlterTable, AlterTableAlgorithm, AlterTableLock, AlterTableOperation, AlterTableType,
AlterTextSearch, AlterTextSearchOperation, AlterTextSearchOption, AlterTrigger,
AlterTriggerOperation, AlterType, AlterTypeAddValue, AlterTypeAddValuePosition,
AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue, ClusteredBy, ColumnDef,
ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy, ColumnPolicyProperty,
ConstraintCharacteristics, CreateAggregate, CreateAggregateArgs, CreateAggregateOption,
CreateCollation, CreateCollationDefinition, CreateConnector, CreateDomain, CreateExtension,
CreateForeignDataWrapper, CreateForeignTable, CreateFunction, CreateIndex, CreateOperator,
CreateOperatorClass, CreateOperatorFamily, CreatePolicy, CreatePolicyCommand, CreatePolicyType,
CreateRule, CreateRuleAction, CreateRuleDoKind, CreateRuleEvent, CreateTable, CreateTextSearch,
CreateTrigger, CreateView, Deduplicate, DeferrableInitial, DistStyle, DropBehavior,
DropExtension, DropFunction, DropOperator, DropOperatorClass, DropOperatorFamily,
DropOperatorSignature, DropPolicy, DropTrigger, ForValues, ForeignDataWrapperRoutineClause,
FunctionReturnType, GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, OperatorArgTypes,
OperatorClassItem, OperatorFamilyDropItem, OperatorFamilyItem, OperatorOption, OperatorPurpose,
Owner, Partition, PartitionBoundValue, ProcedureParam, ReferentialAction, RenameTableNameKind,
ReplicaIdentity, SqliteTableOption, SqliteTableOptions, TagsColumnOption, TextSearchObjectType,
AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue, AlterView, AlterViewOperation,
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy,
ColumnPolicyProperty, ConstraintCharacteristics, CreateAggregate, CreateAggregateArgs,
CreateAggregateOption, CreateCollation, CreateCollationDefinition, CreateConnector,
CreateDomain, CreateExtension, CreateForeignDataWrapper, CreateForeignTable, CreateFunction,
CreateIndex, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreatePolicy,
CreatePolicyCommand, CreatePolicyType, CreateRule, CreateRuleAction, CreateRuleDoKind,
CreateRuleEvent, CreateTable, CreateTextSearch, CreateTrigger, CreateView, Deduplicate,
DeferrableInitial, DistStyle, DropBehavior, DropExtension, DropFunction, DropOperator,
DropOperatorClass, DropOperatorFamily, DropOperatorSignature, DropPolicy, DropTrigger,
ForValues, ForeignDataWrapperRoutineClause, FunctionReturnType, GeneratedAs,
GeneratedExpressionMode, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
IdentityPropertyKind, IdentityPropertyOrder, IndexColumn, IndexOption, IndexType,
KeyOrIndexDisplay, Msck, NullsDistinctOption, OperatorArgTypes, OperatorClassItem,
OperatorFamilyDropItem, OperatorFamilyItem, OperatorOption, OperatorPurpose, Owner, Partition,
PartitionBoundValue, ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity,
SqliteTableOption, SqliteTableOptions, TagsColumnOption, TextSearchObjectType,
TriggerObjectKind, Truncate, UserDefinedTypeCompositeAttributeDef,
UserDefinedTypeInternalLength, UserDefinedTypeRangeOption, UserDefinedTypeRepresentation,
UserDefinedTypeSqlDefinitionOption, UserDefinedTypeStorage, ViewColumnDef, WithData,
Expand Down Expand Up @@ -3906,17 +3907,7 @@ pub enum Statement {
/// ```sql
/// ALTER VIEW
/// ```
AlterView {
/// View name being altered.
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
name: ObjectName,
/// Optional new column list for the view.
columns: Vec<Ident>,
/// Replacement query for the view definition.
query: Box<Query>,
/// Additional WITH options for the view.
with_options: Vec<SqlOption>,
},
AlterView(AlterView),
/// ```sql
/// ALTER FUNCTION
/// ALTER AGGREGATE
Expand Down Expand Up @@ -5743,21 +5734,7 @@ impl fmt::Display for Statement {
Statement::AlterIndex { name, operation } => {
write!(f, "ALTER INDEX {name} {operation}")
}
Statement::AlterView {
name,
columns,
query,
with_options,
} => {
write!(f, "ALTER VIEW {name}")?;
if !with_options.is_empty() {
write!(f, " WITH ({})", display_comma_separated(with_options))?;
}
if !columns.is_empty() {
write!(f, " ({})", display_comma_separated(columns))?;
}
write!(f, " AS {query}")
}
Statement::AlterView(alter_view) => write!(f, "{alter_view}"),
Statement::AlterFunction(alter_function) => write!(f, "{alter_function}"),
Statement::AlterType(AlterType { name, operation }) => {
write!(f, "ALTER TYPE {name} {operation}")
Expand Down Expand Up @@ -12601,6 +12578,12 @@ impl From<AlterCollation> for Statement {
}
}

impl From<AlterView> for Statement {
fn from(a: AlterView) -> Self {
Self::AlterView(a)
}
}

impl From<AlterOperator> for Statement {
fn from(a: AlterOperator) -> Self {
Self::AlterOperator(a)
Expand Down
125 changes: 94 additions & 31 deletions src/ast/spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,27 @@ use crate::tokenizer::Span;

use super::{
comments, dcl::SecondaryRoles, value::ValueWithSpan, AccessExpr, AlterColumnOperation,
AlterIndexOperation, AlterTableOperation, AlterTrigger, AlterTriggerOperation, Analyze, Array,
Assignment, AssignmentTarget, AttachedToken, BeginEndStatements, CaseStatement, CloseCursor,
ClusteredIndex, ColumnDef, ColumnOption, ColumnOptionDef, ConditionalStatementBlock,
ConditionalStatements, ConflictTarget, ConnectByKind, ConstraintCharacteristics, CopySource,
CreateIndex, CreateRule, CreateRuleAction, CreateTable, CreateTableOptions, Cte, Delete,
DoUpdate, ExceptSelectItem, ExcludeConstraintElement, ExcludeSelectItem, Expr, ExprWithAlias,
Fetch, ForValues, FromTable, Function, FunctionArg, FunctionArgExpr, FunctionArgumentClause,
FunctionArgumentList, FunctionArguments, GroupByExpr, HavingBound, IfStatement,
IlikeSelectItem, InTarget, IndexColumn, Insert, Interpolate, InterpolateExpr, Join,
JoinConstraint, JoinOperator, JsonPath, JsonPathElem, LateralView, LimitClause,
MatchRecognizePattern, Measure, Merge, MergeAction, MergeClause, MergeInsertExpr,
MergeInsertKind, MergeUpdateExpr, MergeUpdateKind, NamedParenthesizedList,
NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction,
OnInsert, OpenStatement, OperateFunctionArg, OrderBy, OrderByExpr, OrderByKind, OutputClause,
Parens, Partition, PartitionBoundValue, PivotValueSource, ProjectionSelect, Query,
RaiseStatement, RaiseStatementValue, ReferentialAction, RenameSelectItem, ReplaceSelectElement,
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, Setting, SqlOption, Statement,
Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint, TableFactor,
TableObject, TableOptionsClustered, TableWithJoins, Update, UpdateTableFromKind, Use, Values,
ViewColumnDef, WhileStatement, WildcardAdditionalOptions, With, WithFill,
AlterIndexOperation, AlterTableOperation, AlterTrigger, AlterTriggerOperation, AlterView,
AlterViewOperation, Analyze, Array, Assignment, AssignmentTarget, AttachedToken,
BeginEndStatements, CaseStatement, CloseCursor, ClusteredIndex, ColumnDef, ColumnOption,
ColumnOptionDef, ConditionalStatementBlock, ConditionalStatements, ConflictTarget,
ConnectByKind, ConstraintCharacteristics, CopySource, CreateIndex, CreateRule,
CreateRuleAction, CreateTable, CreateTableOptions, Cte, Delete, DoUpdate, ExceptSelectItem,
ExcludeConstraintElement, ExcludeSelectItem, Expr, ExprWithAlias, Fetch, ForValues, FromTable,
Function, FunctionArg, FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList,
FunctionArguments, GroupByExpr, HavingBound, IfStatement, IlikeSelectItem, InTarget,
IndexColumn, Insert, Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator,
JsonPath, JsonPathElem, LateralView, LimitClause, MatchRecognizePattern, Measure, Merge,
MergeAction, MergeClause, MergeInsertExpr, MergeInsertKind, MergeUpdateExpr, MergeUpdateKind,
NamedParenthesizedList, NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict,
OnConflictAction, OnInsert, OpenStatement, OperateFunctionArg, OrderBy, OrderByExpr,
OrderByKind, OutputClause, Parens, Partition, PartitionBoundValue, PivotValueSource,
ProjectionSelect, Query, RaiseStatement, RaiseStatementValue, ReferentialAction,
RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem,
SetExpr, Setting, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias,
TableAliasColumnDef, TableConstraint, TableFactor, TableObject, TableOptionsClustered,
TableWithJoins, Update, UpdateTableFromKind, Use, Values, ViewColumnDef, WhileStatement,
WildcardAdditionalOptions, With, WithFill,
};

/// Given an iterator of spans, return the [Span::union] of all spans.
Expand Down Expand Up @@ -408,17 +409,7 @@ impl Spanned for Statement {
Statement::CreateTextSearch(create_text_search) => create_text_search.span(),
Statement::AlterTable(alter_table) => alter_table.span(),
Statement::AlterIndex { name, operation } => name.span().union(&operation.span()),
Statement::AlterView {
name,
columns,
query,
with_options,
} => union_spans(
core::iter::once(name.span())
.chain(columns.iter().map(|i| i.span))
.chain(core::iter::once(query.span()))
.chain(with_options.iter().map(|i| i.span())),
),
Statement::AlterView(alter_view) => alter_view.span(),
// These statements need to be implemented
Statement::AlterFunction { .. } => Span::empty(),
Statement::AlterType { .. } => Span::empty(),
Expand Down Expand Up @@ -1162,6 +1153,50 @@ impl Spanned for CreateTableOptions {
}
}

impl Spanned for AlterView {
fn span(&self) -> Span {
self.name.span().union(&self.operation.span())
}
}

/// # partial span
///
/// Missing spans:
/// - [AlterViewOperation::OwnerTo]
impl Spanned for AlterViewOperation {
fn span(&self) -> Span {
match self {
AlterViewOperation::As {
columns,
query,
with_options,
} => union_spans(
columns
.iter()
.map(|i| i.span)
.chain(core::iter::once(query.span()))
.chain(with_options.iter().map(|i| i.span())),
),
AlterViewOperation::AlterColumn { column_name, op } => {
column_name.span.union(&op.span())
}
AlterViewOperation::OwnerTo(_) => Span::empty(),
AlterViewOperation::RenameColumn {
old_column_name,
new_column_name,
} => old_column_name.span.union(&new_column_name.span),
AlterViewOperation::RenameTo { new_name } => new_name.span(),
AlterViewOperation::SetSchema { schema_name } => schema_name.span(),
AlterViewOperation::SetOptions { options } => {
union_spans(options.iter().map(|i| i.span()))
}
AlterViewOperation::ResetOptions { options } => {
union_spans(options.iter().map(|i| i.span))
}
}
}
}

/// # partial span
///
/// Missing spans:
Expand Down Expand Up @@ -3423,4 +3458,32 @@ SETTINGS update_parallel_mode = 'auto'"#;
assert_eq!(test.get_source(expr.span()), expected, "{sql}");
}
}

#[test]
fn test_alter_view_spans() {
let dialect = &crate::dialect::PostgreSqlDialect {};
for (sql, expected) in [
(
"ALTER VIEW v (a) WITH (k = 1) AS SELECT 1",
"v (a) WITH (k = 1) AS SELECT 1",
),
(
"ALTER VIEW v ALTER COLUMN c SET DEFAULT 1",
"v ALTER COLUMN c SET DEFAULT 1",
),
("ALTER VIEW IF EXISTS s.v OWNER TO o", "s.v"),
(
"ALTER VIEW v RENAME COLUMN a TO b",
"v RENAME COLUMN a TO b",
),
("ALTER VIEW v RENAME TO w", "v RENAME TO w"),
("ALTER VIEW v SET SCHEMA s", "v SET SCHEMA s"),
("ALTER VIEW v SET (a = 1, b)", "v SET (a = 1, b"),
("ALTER VIEW v RESET (a, b)", "v RESET (a, b"),
] {
let test = SpanTest::new(dialect, sql);
let stmt = &Parser::parse_sql(dialect, sql).unwrap()[0];
assert_eq!(test.get_source(stmt.span()), expected, "{sql}");
}
}
}
Loading
Loading