@@ -5144,6 +5144,13 @@ impl<'a> Parser<'a> {
51445144 let create_view_params = self.parse_create_view_params()?;
51455145 if self.peek_keywords(&[Keyword::SNAPSHOT, Keyword::TABLE]) {
51465146 self.parse_create_snapshot_table().map(Into::into)
5147+ } else if self.parse_keywords(&[Keyword::TEXT, Keyword::SEARCH]) {
5148+ if or_replace || or_alter || temporary || global.is_some() || transient || persistent {
5149+ return Err(ParserError::ParserError(
5150+ "CREATE TEXT SEARCH does not support CREATE modifiers".to_string(),
5151+ ));
5152+ }
5153+ self.parse_create_text_search().map(Into::into)
51475154 } else if self.parse_keyword(Keyword::TABLE) {
51485155 self.parse_create_table(or_replace, temporary, global, transient, volatile, multiset)
51495156 .map(Into::into)
@@ -5219,6 +5226,145 @@ impl<'a> Parser<'a> {
52195226 }
52205227 }
52215228
5229+ fn parse_text_search_object_type(&mut self) -> Result<TextSearchObjectType, ParserError> {
5230+ match self.expect_one_of_keywords(&[
5231+ Keyword::DICTIONARY,
5232+ Keyword::CONFIGURATION,
5233+ Keyword::TEMPLATE,
5234+ Keyword::PARSER,
5235+ ])? {
5236+ Keyword::DICTIONARY => Ok(TextSearchObjectType::Dictionary),
5237+ Keyword::CONFIGURATION => Ok(TextSearchObjectType::Configuration),
5238+ Keyword::TEMPLATE => Ok(TextSearchObjectType::Template),
5239+ Keyword::PARSER => Ok(TextSearchObjectType::Parser),
5240+ // unreachable because expect_one_of_keywords used above
5241+ unexpected_keyword => Err(ParserError::ParserError(format!(
5242+ "Internal parser error: expected any of {{DICTIONARY, CONFIGURATION, TEMPLATE, PARSER}}, got {unexpected_keyword:?}"
5243+ ))),
5244+ }
5245+ }
5246+
5247+ fn parse_text_search_option(&mut self) -> Result<SqlOption, ParserError> {
5248+ let key = self.parse_identifier()?;
5249+ self.expect_token(&Token::Eq)?;
5250+ let value = self.parse_expr()?;
5251+ Ok(SqlOption::KeyValue { key, value })
5252+ }
5253+
5254+ /// Parse a PostgreSQL `CREATE TEXT SEARCH ...` statement.
5255+ pub fn parse_create_text_search(&mut self) -> Result<CreateTextSearch, ParserError> {
5256+ let object_type = self.parse_text_search_object_type()?;
5257+ let name = self.parse_object_name(false)?;
5258+ self.expect_token(&Token::LParen)?;
5259+ let options = self.parse_comma_separated(Parser::parse_text_search_option)?;
5260+ self.expect_token(&Token::RParen)?;
5261+ Ok(CreateTextSearch {
5262+ object_type,
5263+ name,
5264+ options,
5265+ })
5266+ }
5267+
5268+ fn parse_alter_text_search_dictionary_option(
5269+ &mut self,
5270+ ) -> Result<AlterTextSearchDictionaryOption, ParserError> {
5271+ let key = self.parse_identifier()?;
5272+ let value = if self.consume_token(&Token::Eq) {
5273+ Some(self.parse_expr()?)
5274+ } else {
5275+ None
5276+ };
5277+ Ok(AlterTextSearchDictionaryOption { key, value })
5278+ }
5279+
5280+ /// Parse a PostgreSQL `ALTER TEXT SEARCH ...` statement.
5281+ pub fn parse_alter_text_search(&mut self) -> Result<AlterTextSearch, ParserError> {
5282+ let object_type = self.parse_text_search_object_type()?;
5283+ let name = self.parse_object_name(false)?;
5284+
5285+ let operation = match object_type {
5286+ TextSearchObjectType::Dictionary => {
5287+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5288+ AlterTextSearchOperation::RenameTo {
5289+ new_name: self.parse_identifier()?,
5290+ }
5291+ } else if self.parse_keywords(&[Keyword::OWNER, Keyword::TO]) {
5292+ AlterTextSearchOperation::OwnerTo(self.parse_owner()?)
5293+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5294+ AlterTextSearchOperation::SetSchema {
5295+ schema_name: self.parse_object_name(false)?,
5296+ }
5297+ } else if self.consume_token(&Token::LParen) {
5298+ let options = self
5299+ .parse_comma_separated(Parser::parse_alter_text_search_dictionary_option)?;
5300+ self.expect_token(&Token::RParen)?;
5301+ AlterTextSearchOperation::SetOptions { options }
5302+ } else {
5303+ return self.expected_ref(
5304+ "RENAME TO, OWNER TO, SET SCHEMA, or (...) after ALTER TEXT SEARCH DICTIONARY",
5305+ self.peek_token_ref(),
5306+ );
5307+ }
5308+ }
5309+ TextSearchObjectType::Configuration => {
5310+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5311+ AlterTextSearchOperation::RenameTo {
5312+ new_name: self.parse_identifier()?,
5313+ }
5314+ } else if self.parse_keywords(&[Keyword::OWNER, Keyword::TO]) {
5315+ AlterTextSearchOperation::OwnerTo(self.parse_owner()?)
5316+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5317+ AlterTextSearchOperation::SetSchema {
5318+ schema_name: self.parse_object_name(false)?,
5319+ }
5320+ } else {
5321+ return self.expected_ref(
5322+ "RENAME TO, OWNER TO, or SET SCHEMA after ALTER TEXT SEARCH CONFIGURATION",
5323+ self.peek_token_ref(),
5324+ );
5325+ }
5326+ }
5327+ TextSearchObjectType::Template => {
5328+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5329+ AlterTextSearchOperation::RenameTo {
5330+ new_name: self.parse_identifier()?,
5331+ }
5332+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5333+ AlterTextSearchOperation::SetSchema {
5334+ schema_name: self.parse_object_name(false)?,
5335+ }
5336+ } else {
5337+ return self.expected_ref(
5338+ "RENAME TO or SET SCHEMA after ALTER TEXT SEARCH TEMPLATE",
5339+ self.peek_token_ref(),
5340+ );
5341+ }
5342+ }
5343+ TextSearchObjectType::Parser => {
5344+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5345+ AlterTextSearchOperation::RenameTo {
5346+ new_name: self.parse_identifier()?,
5347+ }
5348+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5349+ AlterTextSearchOperation::SetSchema {
5350+ schema_name: self.parse_object_name(false)?,
5351+ }
5352+ } else {
5353+ return self.expected_ref(
5354+ "RENAME TO or SET SCHEMA after ALTER TEXT SEARCH PARSER",
5355+ self.peek_token_ref(),
5356+ );
5357+ }
5358+ }
5359+ };
5360+
5361+ Ok(AlterTextSearch {
5362+ object_type,
5363+ name,
5364+ operation,
5365+ })
5366+ }
5367+
52225368 fn parse_create_user(&mut self, or_replace: bool) -> Result<CreateUser, ParserError> {
52235369 let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
52245370 let name = self.parse_identifier()?;
@@ -10797,6 +10943,10 @@ impl<'a> Parser<'a> {
1079710943
1079810944 /// Parse an `ALTER <object>` statement and dispatch to the appropriate alter handler.
1079910945 pub fn parse_alter(&mut self) -> Result<Statement, ParserError> {
10946+ if self.parse_keywords(&[Keyword::TEXT, Keyword::SEARCH]) {
10947+ return self.parse_alter_text_search().map(Into::into);
10948+ }
10949+
1080010950 let object_type = self.expect_one_of_keywords(&[
1080110951 Keyword::VIEW,
1080210952 Keyword::TYPE,
@@ -10862,7 +11012,7 @@ impl<'a> Parser<'a> {
1086211012 Keyword::USER => self.parse_alter_user().map(Into::into),
1086311013 // unreachable because expect_one_of_keywords used above
1086411014 unexpected_keyword => Err(ParserError::ParserError(
10865- format!("Internal parser error: expected any of {{VIEW, TYPE, COLLATION, TABLE, INDEX, FUNCTION, AGGREGATE, ROLE, POLICY, CONNECTOR, ICEBERG, SCHEMA, USER, OPERATOR}}, got {unexpected_keyword:?}"),
11015+ format!("Internal parser error: expected any of {{TEXT SEARCH, VIEW, TYPE, COLLATION, TABLE, INDEX, FUNCTION, AGGREGATE, ROLE, POLICY, CONNECTOR, ICEBERG, SCHEMA, USER, OPERATOR}}, got {unexpected_keyword:?}"),
1086611016 )),
1086711017 }
1086811018 }
0 commit comments