@@ -5113,6 +5113,13 @@ impl<'a> Parser<'a> {
51135113 let create_view_params = self.parse_create_view_params()?;
51145114 if self.peek_keywords(&[Keyword::SNAPSHOT, Keyword::TABLE]) {
51155115 self.parse_create_snapshot_table().map(Into::into)
5116+ } else if self.parse_keywords(&[Keyword::TEXT, Keyword::SEARCH]) {
5117+ if or_replace || or_alter || temporary || global.is_some() || transient || persistent {
5118+ return Err(ParserError::ParserError(
5119+ "CREATE TEXT SEARCH does not support CREATE modifiers".to_string(),
5120+ ));
5121+ }
5122+ self.parse_create_text_search().map(Into::into)
51165123 } else if self.parse_keyword(Keyword::TABLE) {
51175124 self.parse_create_table(or_replace, temporary, global, transient)
51185125 .map(Into::into)
@@ -5186,6 +5193,145 @@ impl<'a> Parser<'a> {
51865193 }
51875194 }
51885195
5196+ fn parse_text_search_object_type(&mut self) -> Result<TextSearchObjectType, ParserError> {
5197+ match self.expect_one_of_keywords(&[
5198+ Keyword::DICTIONARY,
5199+ Keyword::CONFIGURATION,
5200+ Keyword::TEMPLATE,
5201+ Keyword::PARSER,
5202+ ])? {
5203+ Keyword::DICTIONARY => Ok(TextSearchObjectType::Dictionary),
5204+ Keyword::CONFIGURATION => Ok(TextSearchObjectType::Configuration),
5205+ Keyword::TEMPLATE => Ok(TextSearchObjectType::Template),
5206+ Keyword::PARSER => Ok(TextSearchObjectType::Parser),
5207+ // unreachable because expect_one_of_keywords used above
5208+ unexpected_keyword => Err(ParserError::ParserError(format!(
5209+ "Internal parser error: expected any of {{DICTIONARY, CONFIGURATION, TEMPLATE, PARSER}}, got {unexpected_keyword:?}"
5210+ ))),
5211+ }
5212+ }
5213+
5214+ fn parse_text_search_option(&mut self) -> Result<SqlOption, ParserError> {
5215+ let key = self.parse_identifier()?;
5216+ self.expect_token(&Token::Eq)?;
5217+ let value = self.parse_expr()?;
5218+ Ok(SqlOption::KeyValue { key, value })
5219+ }
5220+
5221+ /// Parse a PostgreSQL `CREATE TEXT SEARCH ...` statement.
5222+ pub fn parse_create_text_search(&mut self) -> Result<CreateTextSearch, ParserError> {
5223+ let object_type = self.parse_text_search_object_type()?;
5224+ let name = self.parse_object_name(false)?;
5225+ self.expect_token(&Token::LParen)?;
5226+ let options = self.parse_comma_separated(Parser::parse_text_search_option)?;
5227+ self.expect_token(&Token::RParen)?;
5228+ Ok(CreateTextSearch {
5229+ object_type,
5230+ name,
5231+ options,
5232+ })
5233+ }
5234+
5235+ fn parse_alter_text_search_dictionary_option(
5236+ &mut self,
5237+ ) -> Result<AlterTextSearchDictionaryOption, ParserError> {
5238+ let key = self.parse_identifier()?;
5239+ let value = if self.consume_token(&Token::Eq) {
5240+ Some(self.parse_expr()?)
5241+ } else {
5242+ None
5243+ };
5244+ Ok(AlterTextSearchDictionaryOption { key, value })
5245+ }
5246+
5247+ /// Parse a PostgreSQL `ALTER TEXT SEARCH ...` statement.
5248+ pub fn parse_alter_text_search(&mut self) -> Result<AlterTextSearch, ParserError> {
5249+ let object_type = self.parse_text_search_object_type()?;
5250+ let name = self.parse_object_name(false)?;
5251+
5252+ let operation = match object_type {
5253+ TextSearchObjectType::Dictionary => {
5254+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5255+ AlterTextSearchOperation::RenameTo {
5256+ new_name: self.parse_identifier()?,
5257+ }
5258+ } else if self.parse_keywords(&[Keyword::OWNER, Keyword::TO]) {
5259+ AlterTextSearchOperation::OwnerTo(self.parse_owner()?)
5260+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5261+ AlterTextSearchOperation::SetSchema {
5262+ schema_name: self.parse_object_name(false)?,
5263+ }
5264+ } else if self.consume_token(&Token::LParen) {
5265+ let options = self
5266+ .parse_comma_separated(Parser::parse_alter_text_search_dictionary_option)?;
5267+ self.expect_token(&Token::RParen)?;
5268+ AlterTextSearchOperation::SetOptions { options }
5269+ } else {
5270+ return self.expected_ref(
5271+ "RENAME TO, OWNER TO, SET SCHEMA, or (...) after ALTER TEXT SEARCH DICTIONARY",
5272+ self.peek_token_ref(),
5273+ );
5274+ }
5275+ }
5276+ TextSearchObjectType::Configuration => {
5277+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5278+ AlterTextSearchOperation::RenameTo {
5279+ new_name: self.parse_identifier()?,
5280+ }
5281+ } else if self.parse_keywords(&[Keyword::OWNER, Keyword::TO]) {
5282+ AlterTextSearchOperation::OwnerTo(self.parse_owner()?)
5283+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5284+ AlterTextSearchOperation::SetSchema {
5285+ schema_name: self.parse_object_name(false)?,
5286+ }
5287+ } else {
5288+ return self.expected_ref(
5289+ "RENAME TO, OWNER TO, or SET SCHEMA after ALTER TEXT SEARCH CONFIGURATION",
5290+ self.peek_token_ref(),
5291+ );
5292+ }
5293+ }
5294+ TextSearchObjectType::Template => {
5295+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5296+ AlterTextSearchOperation::RenameTo {
5297+ new_name: self.parse_identifier()?,
5298+ }
5299+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5300+ AlterTextSearchOperation::SetSchema {
5301+ schema_name: self.parse_object_name(false)?,
5302+ }
5303+ } else {
5304+ return self.expected_ref(
5305+ "RENAME TO or SET SCHEMA after ALTER TEXT SEARCH TEMPLATE",
5306+ self.peek_token_ref(),
5307+ );
5308+ }
5309+ }
5310+ TextSearchObjectType::Parser => {
5311+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5312+ AlterTextSearchOperation::RenameTo {
5313+ new_name: self.parse_identifier()?,
5314+ }
5315+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5316+ AlterTextSearchOperation::SetSchema {
5317+ schema_name: self.parse_object_name(false)?,
5318+ }
5319+ } else {
5320+ return self.expected_ref(
5321+ "RENAME TO or SET SCHEMA after ALTER TEXT SEARCH PARSER",
5322+ self.peek_token_ref(),
5323+ );
5324+ }
5325+ }
5326+ };
5327+
5328+ Ok(AlterTextSearch {
5329+ object_type,
5330+ name,
5331+ operation,
5332+ })
5333+ }
5334+
51895335 fn parse_create_user(&mut self, or_replace: bool) -> Result<CreateUser, ParserError> {
51905336 let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
51915337 let name = self.parse_identifier()?;
@@ -10577,6 +10723,10 @@ impl<'a> Parser<'a> {
1057710723
1057810724 /// Parse an `ALTER <object>` statement and dispatch to the appropriate alter handler.
1057910725 pub fn parse_alter(&mut self) -> Result<Statement, ParserError> {
10726+ if self.parse_keywords(&[Keyword::TEXT, Keyword::SEARCH]) {
10727+ return self.parse_alter_text_search().map(Into::into);
10728+ }
10729+
1058010730 let object_type = self.expect_one_of_keywords(&[
1058110731 Keyword::VIEW,
1058210732 Keyword::TYPE,
@@ -10636,7 +10786,7 @@ impl<'a> Parser<'a> {
1063610786 Keyword::USER => self.parse_alter_user().map(Into::into),
1063710787 // unreachable because expect_one_of_keywords used above
1063810788 unexpected_keyword => Err(ParserError::ParserError(
10639- format!("Internal parser error: expected any of {{VIEW, TYPE, TABLE, INDEX, ROLE, POLICY, CONNECTOR, ICEBERG, SCHEMA, USER, OPERATOR}}, got {unexpected_keyword:?}"),
10789+ format!("Internal parser error: expected any of {{VIEW, TYPE, TABLE, INDEX, ROLE, POLICY, CONNECTOR, ICEBERG, SCHEMA, USER, OPERATOR, TEXT SEARCH }}, got {unexpected_keyword:?}"),
1064010790 )),
1064110791 }
1064210792 }
0 commit comments