Skip to content

Commit cb7a51e

Browse files
authored
feat: Add ALTER SCHEMA support (#1980)
1 parent 56848b0 commit cb7a51e

File tree

5 files changed

+164
-11
lines changed

5 files changed

+164
-11
lines changed

src/ast/ddl.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3080,6 +3080,48 @@ impl fmt::Display for CreateConnector {
30803080
}
30813081
}
30823082

3083+
/// An `ALTER SCHEMA` (`Statement::AlterSchema`) operation.
3084+
///
3085+
/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3086+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3087+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3088+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3089+
pub enum AlterSchemaOperation {
3090+
SetDefaultCollate {
3091+
collate: Expr,
3092+
},
3093+
AddReplica {
3094+
replica: Ident,
3095+
options: Option<Vec<SqlOption>>,
3096+
},
3097+
DropReplica {
3098+
replica: Ident,
3099+
},
3100+
SetOptionsParens {
3101+
options: Vec<SqlOption>,
3102+
},
3103+
}
3104+
3105+
impl fmt::Display for AlterSchemaOperation {
3106+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3107+
match self {
3108+
AlterSchemaOperation::SetDefaultCollate { collate } => {
3109+
write!(f, "SET DEFAULT COLLATE {collate}")
3110+
}
3111+
AlterSchemaOperation::AddReplica { replica, options } => {
3112+
write!(f, "ADD REPLICA {replica}")?;
3113+
if let Some(options) = options {
3114+
write!(f, " OPTIONS ({})", display_comma_separated(options))?;
3115+
}
3116+
Ok(())
3117+
}
3118+
AlterSchemaOperation::DropReplica { replica } => write!(f, "DROP REPLICA {replica}"),
3119+
AlterSchemaOperation::SetOptionsParens { options } => {
3120+
write!(f, "SET OPTIONS ({})", display_comma_separated(options))
3121+
}
3122+
}
3123+
}
3124+
}
30833125
/// `RenameTableNameKind` is the kind used in an `ALTER TABLE _ RENAME` statement.
30843126
///
30853127
/// Note: [MySQL] is the only database that supports the AS keyword for this operation.
@@ -3102,6 +3144,30 @@ impl fmt::Display for RenameTableNameKind {
31023144
}
31033145
}
31043146

3147+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3148+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3149+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3150+
pub struct AlterSchema {
3151+
pub name: ObjectName,
3152+
pub if_exists: bool,
3153+
pub operations: Vec<AlterSchemaOperation>,
3154+
}
3155+
3156+
impl fmt::Display for AlterSchema {
3157+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3158+
write!(f, "ALTER SCHEMA ")?;
3159+
if self.if_exists {
3160+
write!(f, "IF EXISTS ")?;
3161+
}
3162+
write!(f, "{}", self.name)?;
3163+
for operation in &self.operations {
3164+
write!(f, " {operation}")?;
3165+
}
3166+
3167+
Ok(())
3168+
}
3169+
}
3170+
31053171
impl Spanned for RenameTableNameKind {
31063172
fn span(&self) -> Span {
31073173
match self {

src/ast/mod.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,17 @@ pub use self::dcl::{
5959
};
6060
pub use self::ddl::{
6161
AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation, AlterPolicyOperation,
62-
AlterTableAlgorithm, AlterTableLock, AlterTableOperation, AlterType, AlterTypeAddValue,
63-
AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
64-
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy,
65-
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain, CreateFunction,
66-
CreateIndex, CreateTable, Deduplicate, DeferrableInitial, DropBehavior, GeneratedAs,
67-
GeneratedExpressionMode, IdentityParameters, IdentityProperty, IdentityPropertyFormatKind,
68-
IdentityPropertyKind, IdentityPropertyOrder, IndexColumn, IndexOption, IndexType,
69-
KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition, ProcedureParam, ReferentialAction,
70-
RenameTableNameKind, ReplicaIdentity, TableConstraint, TagsColumnOption,
71-
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation, ViewColumnDef,
62+
AlterSchema, AlterSchemaOperation, AlterTableAlgorithm, AlterTableLock, AlterTableOperation,
63+
AlterType, AlterTypeAddValue, AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename,
64+
AlterTypeRenameValue, ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions,
65+
ColumnPolicy, ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
66+
CreateFunction, CreateIndex, CreateTable, Deduplicate, DeferrableInitial, DropBehavior,
67+
GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
68+
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
69+
IndexOption, IndexType, KeyOrIndexDisplay, NullsDistinctOption, Owner, Partition,
70+
ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity, TableConstraint,
71+
TagsColumnOption, UserDefinedTypeCompositeAttributeDef, UserDefinedTypeRepresentation,
72+
ViewColumnDef,
7273
};
7374
pub use self::dml::{Delete, Insert};
7475
pub use self::operator::{BinaryOperator, UnaryOperator};
@@ -3388,6 +3389,11 @@ pub enum Statement {
33883389
end_token: AttachedToken,
33893390
},
33903391
/// ```sql
3392+
/// ALTER SCHEMA
3393+
/// ```
3394+
/// See [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language#alter_schema_collate_statement)
3395+
AlterSchema(AlterSchema),
3396+
/// ```sql
33913397
/// ALTER INDEX
33923398
/// ```
33933399
AlterIndex {
@@ -6336,6 +6342,7 @@ impl fmt::Display for Statement {
63366342
Statement::Remove(command) => write!(f, "REMOVE {command}"),
63376343
Statement::ExportData(e) => write!(f, "{e}"),
63386344
Statement::CreateUser(s) => write!(f, "{s}"),
6345+
Statement::AlterSchema(s) => write!(f, "{s}"),
63396346
}
63406347
}
63416348
}

src/ast/spans.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
// specific language governing permissions and limitations
1616
// under the License.
1717

18-
use crate::ast::{query::SelectItemQualifiedWildcardKind, ColumnOptions, ExportData, TypedString};
18+
use crate::ast::{
19+
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, ColumnOptions,
20+
ExportData, TypedString,
21+
};
1922
use core::iter;
2023

2124
use crate::tokenizer::Span;
@@ -548,6 +551,7 @@ impl Spanned for Statement {
548551
.chain(connection.iter().map(|i| i.span())),
549552
),
550553
Statement::CreateUser(..) => Span::empty(),
554+
Statement::AlterSchema(s) => s.span(),
551555
}
552556
}
553557
}
@@ -2387,6 +2391,30 @@ impl Spanned for OpenStatement {
23872391
}
23882392
}
23892393

2394+
impl Spanned for AlterSchemaOperation {
2395+
fn span(&self) -> Span {
2396+
match self {
2397+
AlterSchemaOperation::SetDefaultCollate { collate } => collate.span(),
2398+
AlterSchemaOperation::AddReplica { replica, options } => union_spans(
2399+
core::iter::once(replica.span)
2400+
.chain(options.iter().flat_map(|i| i.iter().map(|i| i.span()))),
2401+
),
2402+
AlterSchemaOperation::DropReplica { replica } => replica.span,
2403+
AlterSchemaOperation::SetOptionsParens { options } => {
2404+
union_spans(options.iter().map(|i| i.span()))
2405+
}
2406+
}
2407+
}
2408+
}
2409+
2410+
impl Spanned for AlterSchema {
2411+
fn span(&self) -> Span {
2412+
union_spans(
2413+
core::iter::once(self.name.span()).chain(self.operations.iter().map(|i| i.span())),
2414+
)
2415+
}
2416+
}
2417+
23902418
#[cfg(test)]
23912419
pub mod tests {
23922420
use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect};

src/parser/mod.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9247,8 +9247,14 @@ impl<'a> Parser<'a> {
92479247
Keyword::POLICY,
92489248
Keyword::CONNECTOR,
92499249
Keyword::ICEBERG,
9250+
Keyword::SCHEMA,
92509251
])?;
92519252
match object_type {
9253+
Keyword::SCHEMA => {
9254+
self.prev_token();
9255+
self.prev_token();
9256+
self.parse_alter_schema()
9257+
}
92529258
Keyword::VIEW => self.parse_alter_view(),
92539259
Keyword::TYPE => self.parse_alter_type(),
92549260
Keyword::TABLE => self.parse_alter_table(false),
@@ -9387,6 +9393,40 @@ impl<'a> Parser<'a> {
93879393
}
93889394
}
93899395

9396+
// Parse a [Statement::AlterSchema]
9397+
// ALTER SCHEMA [ IF EXISTS ] schema_name
9398+
pub fn parse_alter_schema(&mut self) -> Result<Statement, ParserError> {
9399+
self.expect_keywords(&[Keyword::ALTER, Keyword::SCHEMA])?;
9400+
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
9401+
let name = self.parse_object_name(false)?;
9402+
let operation = if self.parse_keywords(&[Keyword::SET, Keyword::OPTIONS]) {
9403+
self.prev_token();
9404+
let options = self.parse_options(Keyword::OPTIONS)?;
9405+
AlterSchemaOperation::SetOptionsParens { options }
9406+
} else if self.parse_keywords(&[Keyword::SET, Keyword::DEFAULT, Keyword::COLLATE]) {
9407+
let collate = self.parse_expr()?;
9408+
AlterSchemaOperation::SetDefaultCollate { collate }
9409+
} else if self.parse_keywords(&[Keyword::ADD, Keyword::REPLICA]) {
9410+
let replica = self.parse_identifier()?;
9411+
let options = if self.peek_keyword(Keyword::OPTIONS) {
9412+
Some(self.parse_options(Keyword::OPTIONS)?)
9413+
} else {
9414+
None
9415+
};
9416+
AlterSchemaOperation::AddReplica { replica, options }
9417+
} else if self.parse_keywords(&[Keyword::DROP, Keyword::REPLICA]) {
9418+
let replica = self.parse_identifier()?;
9419+
AlterSchemaOperation::DropReplica { replica }
9420+
} else {
9421+
return self.expected_ref("ALTER SCHEMA operation", self.peek_token_ref());
9422+
};
9423+
Ok(Statement::AlterSchema(AlterSchema {
9424+
name,
9425+
if_exists,
9426+
operations: vec![operation],
9427+
}))
9428+
}
9429+
93909430
/// Parse a `CALL procedure_name(arg1, arg2, ...)`
93919431
/// or `CALL procedure_name` statement
93929432
pub fn parse_call(&mut self) -> Result<Statement, ParserError> {

tests/sqlparser_bigquery.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2825,3 +2825,15 @@ fn test_begin_transaction() {
28252825
fn test_begin_statement() {
28262826
bigquery().verified_stmt("BEGIN");
28272827
}
2828+
2829+
#[test]
2830+
fn test_alter_schema() {
2831+
bigquery_and_generic().verified_stmt("ALTER SCHEMA mydataset SET DEFAULT COLLATE 'und:ci'");
2832+
bigquery_and_generic().verified_stmt("ALTER SCHEMA mydataset ADD REPLICA 'us'");
2833+
bigquery_and_generic()
2834+
.verified_stmt("ALTER SCHEMA mydataset ADD REPLICA 'us' OPTIONS (location = 'us')");
2835+
bigquery_and_generic().verified_stmt("ALTER SCHEMA mydataset DROP REPLICA 'us'");
2836+
bigquery_and_generic().verified_stmt("ALTER SCHEMA mydataset SET OPTIONS (location = 'us')");
2837+
bigquery_and_generic()
2838+
.verified_stmt("ALTER SCHEMA IF EXISTS mydataset SET OPTIONS (location = 'us')");
2839+
}

0 commit comments

Comments
 (0)