Skip to content

Commit 90d6578

Browse files
feat(parser): parse PostgreSQL collation DDL
Extend parser dispatch and handlers for PostgreSQL collation syntax.\n\n- parse CREATE COLLATION with FROM and option-list forms\n- parse ALTER COLLATION operations: RENAME TO, OWNER TO, SET SCHEMA, REFRESH VERSION\n- accept DROP COLLATION via generic DROP statement path\n- support COMMENT ON COLLATION targets
1 parent 28de160 commit 90d6578

File tree

1 file changed

+63
-2
lines changed

1 file changed

+63
-2
lines changed

src/parser/mod.rs

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,9 @@ impl<'a> Parser<'a> {
902902
let token = self.next_token();
903903

904904
let (object_type, object_name) = match token.token {
905+
Token::Word(w) if w.keyword == Keyword::COLLATION => {
906+
(CommentObject::Collation, self.parse_object_name(false)?)
907+
}
905908
Token::Word(w) if w.keyword == Keyword::COLUMN => {
906909
(CommentObject::Column, self.parse_object_name(false)?)
907910
}
@@ -5188,6 +5191,8 @@ impl<'a> Parser<'a> {
51885191
self.parse_create_role().map(Into::into)
51895192
} else if self.parse_keyword(Keyword::SEQUENCE) {
51905193
self.parse_create_sequence(temporary)
5194+
} else if self.parse_keyword(Keyword::COLLATION) {
5195+
self.parse_create_collation().map(Into::into)
51915196
} else if self.parse_keyword(Keyword::TYPE) {
51925197
self.parse_create_type()
51935198
} else if self.parse_keyword(Keyword::PROCEDURE) {
@@ -7352,6 +7357,8 @@ impl<'a> Parser<'a> {
73527357

73537358
let object_type = if self.parse_keyword(Keyword::TABLE) {
73547359
ObjectType::Table
7360+
} else if self.parse_keyword(Keyword::COLLATION) {
7361+
ObjectType::Collation
73557362
} else if self.parse_keyword(Keyword::VIEW) {
73567363
ObjectType::View
73577364
} else if self.parse_keywords(&[Keyword::MATERIALIZED, Keyword::VIEW]) {
@@ -7401,7 +7408,7 @@ impl<'a> Parser<'a> {
74017408
};
74027409
} else {
74037410
return self.expected_ref(
7404-
"CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, OPERATOR, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW or USER after DROP",
7411+
"COLLATION, CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, OPERATOR, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW or USER after DROP",
74057412
self.peek_token_ref(),
74067413
);
74077414
};
@@ -8142,6 +8149,31 @@ impl<'a> Parser<'a> {
81428149
})
81438150
}
81448151

8152+
/// Parse a PostgreSQL-specific [Statement::CreateCollation] statement.
8153+
pub fn parse_create_collation(&mut self) -> Result<CreateCollation, ParserError> {
8154+
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
8155+
let name = self.parse_object_name(false)?;
8156+
8157+
let definition = if self.parse_keyword(Keyword::FROM) {
8158+
CreateCollationDefinition::From(self.parse_object_name(false)?)
8159+
} else if self.consume_token(&Token::LParen) {
8160+
let options = self.parse_comma_separated(Parser::parse_sql_option)?;
8161+
self.expect_token(&Token::RParen)?;
8162+
CreateCollationDefinition::Options(options)
8163+
} else {
8164+
return self.expected_ref(
8165+
"FROM or parenthesized option list after CREATE COLLATION name",
8166+
self.peek_token_ref(),
8167+
);
8168+
};
8169+
8170+
Ok(CreateCollation {
8171+
if_not_exists,
8172+
name,
8173+
definition,
8174+
})
8175+
}
8176+
81458177
/// Parse a PostgreSQL-specific [Statement::DropExtension] statement.
81468178
pub fn parse_drop_extension(&mut self) -> Result<Statement, ParserError> {
81478179
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
@@ -10673,6 +10705,7 @@ impl<'a> Parser<'a> {
1067310705
let object_type = self.expect_one_of_keywords(&[
1067410706
Keyword::VIEW,
1067510707
Keyword::TYPE,
10708+
Keyword::COLLATION,
1067610709
Keyword::TABLE,
1067710710
Keyword::INDEX,
1067810711
Keyword::FUNCTION,
@@ -10693,6 +10726,7 @@ impl<'a> Parser<'a> {
1069310726
}
1069410727
Keyword::VIEW => self.parse_alter_view(),
1069510728
Keyword::TYPE => self.parse_alter_type(),
10729+
Keyword::COLLATION => self.parse_alter_collation().map(Into::into),
1069610730
Keyword::TABLE => self.parse_alter_table(false),
1069710731
Keyword::ICEBERG => {
1069810732
self.expect_keyword(Keyword::TABLE)?;
@@ -10733,7 +10767,7 @@ impl<'a> Parser<'a> {
1073310767
Keyword::USER => self.parse_alter_user().map(Into::into),
1073410768
// unreachable because expect_one_of_keywords used above
1073510769
unexpected_keyword => Err(ParserError::ParserError(
10736-
format!("Internal parser error: expected any of {{VIEW, TYPE, TABLE, INDEX, FUNCTION, AGGREGATE, ROLE, POLICY, CONNECTOR, ICEBERG, SCHEMA, USER, OPERATOR}}, got {unexpected_keyword:?}"),
10770+
format!("Internal parser error: expected any of {{VIEW, TYPE, COLLATION, TABLE, INDEX, FUNCTION, AGGREGATE, ROLE, POLICY, CONNECTOR, ICEBERG, SCHEMA, USER, OPERATOR}}, got {unexpected_keyword:?}"),
1073710771
)),
1073810772
}
1073910773
}
@@ -11070,6 +11104,33 @@ impl<'a> Parser<'a> {
1107011104
}
1107111105
}
1107211106

11107+
/// Parse a [Statement::AlterCollation].
11108+
///
11109+
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-altercollation.html)
11110+
pub fn parse_alter_collation(&mut self) -> Result<AlterCollation, ParserError> {
11111+
let name = self.parse_object_name(false)?;
11112+
let operation = if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
11113+
AlterCollationOperation::RenameTo {
11114+
new_name: self.parse_identifier()?,
11115+
}
11116+
} else if self.parse_keywords(&[Keyword::OWNER, Keyword::TO]) {
11117+
AlterCollationOperation::OwnerTo(self.parse_owner()?)
11118+
} else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
11119+
AlterCollationOperation::SetSchema {
11120+
schema_name: self.parse_object_name(false)?,
11121+
}
11122+
} else if self.parse_keywords(&[Keyword::REFRESH, Keyword::VERSION]) {
11123+
AlterCollationOperation::RefreshVersion
11124+
} else {
11125+
return self.expected_ref(
11126+
"RENAME TO, OWNER TO, SET SCHEMA, or REFRESH VERSION after ALTER COLLATION",
11127+
self.peek_token_ref(),
11128+
);
11129+
};
11130+
11131+
Ok(AlterCollation { name, operation })
11132+
}
11133+
1107311134
/// Parse a [Statement::AlterOperator]
1107411135
///
1107511136
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-alteroperator.html)

0 commit comments

Comments
 (0)