@@ -5100,7 +5100,14 @@ impl<'a> Parser<'a> {
51005100 let persistent = dialect_of!(self is DuckDbDialect)
51015101 && self.parse_one_of_keywords(&[Keyword::PERSISTENT]).is_some();
51025102 let create_view_params = self.parse_create_view_params()?;
5103- if self.parse_keyword(Keyword::TABLE) {
5103+ if self.parse_keywords(&[Keyword::TEXT, Keyword::SEARCH]) {
5104+ if or_replace || or_alter || temporary || global.is_some() || transient || persistent {
5105+ return Err(ParserError::ParserError(
5106+ "CREATE TEXT SEARCH does not support CREATE modifiers".to_string(),
5107+ ));
5108+ }
5109+ self.parse_create_text_search().map(Into::into)
5110+ } else if self.parse_keyword(Keyword::TABLE) {
51045111 self.parse_create_table(or_replace, temporary, global, transient)
51055112 .map(Into::into)
51065113 } else if self.peek_keyword(Keyword::MATERIALIZED)
@@ -5173,6 +5180,145 @@ impl<'a> Parser<'a> {
51735180 }
51745181 }
51755182
5183+ fn parse_text_search_object_type(&mut self) -> Result<TextSearchObjectType, ParserError> {
5184+ match self.expect_one_of_keywords(&[
5185+ Keyword::DICTIONARY,
5186+ Keyword::CONFIGURATION,
5187+ Keyword::TEMPLATE,
5188+ Keyword::PARSER,
5189+ ])? {
5190+ Keyword::DICTIONARY => Ok(TextSearchObjectType::Dictionary),
5191+ Keyword::CONFIGURATION => Ok(TextSearchObjectType::Configuration),
5192+ Keyword::TEMPLATE => Ok(TextSearchObjectType::Template),
5193+ Keyword::PARSER => Ok(TextSearchObjectType::Parser),
5194+ // unreachable because expect_one_of_keywords used above
5195+ unexpected_keyword => Err(ParserError::ParserError(format!(
5196+ "Internal parser error: expected any of {{DICTIONARY, CONFIGURATION, TEMPLATE, PARSER}}, got {unexpected_keyword:?}"
5197+ ))),
5198+ }
5199+ }
5200+
5201+ fn parse_text_search_option(&mut self) -> Result<SqlOption, ParserError> {
5202+ let key = self.parse_identifier()?;
5203+ self.expect_token(&Token::Eq)?;
5204+ let value = self.parse_expr()?;
5205+ Ok(SqlOption::KeyValue { key, value })
5206+ }
5207+
5208+ /// Parse a PostgreSQL `CREATE TEXT SEARCH ...` statement.
5209+ pub fn parse_create_text_search(&mut self) -> Result<CreateTextSearch, ParserError> {
5210+ let object_type = self.parse_text_search_object_type()?;
5211+ let name = self.parse_object_name(false)?;
5212+ self.expect_token(&Token::LParen)?;
5213+ let options = self.parse_comma_separated(Parser::parse_text_search_option)?;
5214+ self.expect_token(&Token::RParen)?;
5215+ Ok(CreateTextSearch {
5216+ object_type,
5217+ name,
5218+ options,
5219+ })
5220+ }
5221+
5222+ fn parse_alter_text_search_dictionary_option(
5223+ &mut self,
5224+ ) -> Result<AlterTextSearchDictionaryOption, ParserError> {
5225+ let key = self.parse_identifier()?;
5226+ let value = if self.consume_token(&Token::Eq) {
5227+ Some(self.parse_expr()?)
5228+ } else {
5229+ None
5230+ };
5231+ Ok(AlterTextSearchDictionaryOption { key, value })
5232+ }
5233+
5234+ /// Parse a PostgreSQL `ALTER TEXT SEARCH ...` statement.
5235+ pub fn parse_alter_text_search(&mut self) -> Result<AlterTextSearch, ParserError> {
5236+ let object_type = self.parse_text_search_object_type()?;
5237+ let name = self.parse_object_name(false)?;
5238+
5239+ let operation = match object_type {
5240+ TextSearchObjectType::Dictionary => {
5241+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5242+ AlterTextSearchOperation::RenameTo {
5243+ new_name: self.parse_identifier()?,
5244+ }
5245+ } else if self.parse_keywords(&[Keyword::OWNER, Keyword::TO]) {
5246+ AlterTextSearchOperation::OwnerTo(self.parse_owner()?)
5247+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5248+ AlterTextSearchOperation::SetSchema {
5249+ schema_name: self.parse_object_name(false)?,
5250+ }
5251+ } else if self.consume_token(&Token::LParen) {
5252+ let options = self
5253+ .parse_comma_separated(Parser::parse_alter_text_search_dictionary_option)?;
5254+ self.expect_token(&Token::RParen)?;
5255+ AlterTextSearchOperation::SetOptions { options }
5256+ } else {
5257+ return self.expected_ref(
5258+ "RENAME TO, OWNER TO, SET SCHEMA, or (...) after ALTER TEXT SEARCH DICTIONARY",
5259+ self.peek_token_ref(),
5260+ );
5261+ }
5262+ }
5263+ TextSearchObjectType::Configuration => {
5264+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5265+ AlterTextSearchOperation::RenameTo {
5266+ new_name: self.parse_identifier()?,
5267+ }
5268+ } else if self.parse_keywords(&[Keyword::OWNER, Keyword::TO]) {
5269+ AlterTextSearchOperation::OwnerTo(self.parse_owner()?)
5270+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5271+ AlterTextSearchOperation::SetSchema {
5272+ schema_name: self.parse_object_name(false)?,
5273+ }
5274+ } else {
5275+ return self.expected_ref(
5276+ "RENAME TO, OWNER TO, or SET SCHEMA after ALTER TEXT SEARCH CONFIGURATION",
5277+ self.peek_token_ref(),
5278+ );
5279+ }
5280+ }
5281+ TextSearchObjectType::Template => {
5282+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5283+ AlterTextSearchOperation::RenameTo {
5284+ new_name: self.parse_identifier()?,
5285+ }
5286+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5287+ AlterTextSearchOperation::SetSchema {
5288+ schema_name: self.parse_object_name(false)?,
5289+ }
5290+ } else {
5291+ return self.expected_ref(
5292+ "RENAME TO or SET SCHEMA after ALTER TEXT SEARCH TEMPLATE",
5293+ self.peek_token_ref(),
5294+ );
5295+ }
5296+ }
5297+ TextSearchObjectType::Parser => {
5298+ if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
5299+ AlterTextSearchOperation::RenameTo {
5300+ new_name: self.parse_identifier()?,
5301+ }
5302+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
5303+ AlterTextSearchOperation::SetSchema {
5304+ schema_name: self.parse_object_name(false)?,
5305+ }
5306+ } else {
5307+ return self.expected_ref(
5308+ "RENAME TO or SET SCHEMA after ALTER TEXT SEARCH PARSER",
5309+ self.peek_token_ref(),
5310+ );
5311+ }
5312+ }
5313+ };
5314+
5315+ Ok(AlterTextSearch {
5316+ object_type,
5317+ name,
5318+ operation,
5319+ })
5320+ }
5321+
51765322 fn parse_create_user(&mut self, or_replace: bool) -> Result<CreateUser, ParserError> {
51775323 let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
51785324 let name = self.parse_identifier()?;
@@ -10428,6 +10574,10 @@ impl<'a> Parser<'a> {
1042810574
1042910575 /// Parse an `ALTER <object>` statement and dispatch to the appropriate alter handler.
1043010576 pub fn parse_alter(&mut self) -> Result<Statement, ParserError> {
10577+ if self.parse_keywords(&[Keyword::TEXT, Keyword::SEARCH]) {
10578+ return self.parse_alter_text_search().map(Into::into);
10579+ }
10580+
1043110581 let object_type = self.expect_one_of_keywords(&[
1043210582 Keyword::VIEW,
1043310583 Keyword::TYPE,
@@ -10487,7 +10637,7 @@ impl<'a> Parser<'a> {
1048710637 Keyword::USER => self.parse_alter_user().map(Into::into),
1048810638 // unreachable because expect_one_of_keywords used above
1048910639 unexpected_keyword => Err(ParserError::ParserError(
10490- format!("Internal parser error: expected any of {{VIEW, TYPE, TABLE, INDEX, ROLE, POLICY, CONNECTOR, ICEBERG, SCHEMA, USER, OPERATOR}}, got {unexpected_keyword:?}"),
10640+ format!("Internal parser error: expected any of {{VIEW, TYPE, TABLE, INDEX, ROLE, POLICY, CONNECTOR, ICEBERG, SCHEMA, USER, OPERATOR, TEXT SEARCH }}, got {unexpected_keyword:?}"),
1049110641 )),
1049210642 }
1049310643 }
0 commit comments