This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new d78dbc97 Added support for `ALTER OPERATOR FAMILY` syntax (#2125)
d78dbc97 is described below
commit d78dbc97a1f65ce7ee353fea181a6c3bb15a5050
Author: Luca Cappelletti <[email protected]>
AuthorDate: Thu Dec 18 05:34:48 2025 +0100
Added support for `ALTER OPERATOR FAMILY` syntax (#2125)
---
src/ast/ddl.rs | 198 +++++++++++++++++++++-
src/ast/mod.rs | 30 ++--
src/ast/spans.rs | 1 +
src/parser/mod.rs | 176 +++++++++++++++++++-
tests/sqlparser_postgres.rs | 398 +++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 778 insertions(+), 25 deletions(-)
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index d0aed448..4e042a36 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -4198,25 +4198,25 @@ impl fmt::Display for OperatorArgTypes {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum OperatorClassItem {
- /// OPERATOR clause
+ /// `OPERATOR` clause
Operator {
- strategy_number: u32,
+ strategy_number: u64,
operator_name: ObjectName,
/// Optional operator argument types
op_types: Option<OperatorArgTypes>,
- /// FOR SEARCH or FOR ORDER BY
+ /// `FOR SEARCH` or `FOR ORDER BY`
purpose: Option<OperatorPurpose>,
},
- /// FUNCTION clause
+ /// `FUNCTION` clause
Function {
- support_number: u32,
+ support_number: u64,
/// Optional function argument types for the operator class
op_types: Option<Vec<DataType>>,
function_name: ObjectName,
/// Function argument types
argument_types: Vec<DataType>,
},
- /// STORAGE clause
+ /// `STORAGE` clause
Storage { storage_type: DataType },
}
@@ -4413,3 +4413,189 @@ impl Spanned for DropOperatorClass {
Span::empty()
}
}
+
+/// An item in an ALTER OPERATOR FAMILY ADD statement
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum OperatorFamilyItem {
+ /// `OPERATOR` clause
+ Operator {
+ strategy_number: u64,
+ operator_name: ObjectName,
+ /// Operator argument types
+ op_types: Vec<DataType>,
+ /// `FOR SEARCH` or `FOR ORDER BY`
+ purpose: Option<OperatorPurpose>,
+ },
+ /// `FUNCTION` clause
+ Function {
+ support_number: u64,
+ /// Optional operator argument types for the function
+ op_types: Option<Vec<DataType>>,
+ function_name: ObjectName,
+ /// Function argument types
+ argument_types: Vec<DataType>,
+ },
+}
+
+/// An item in an ALTER OPERATOR FAMILY DROP statement
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum OperatorFamilyDropItem {
+ /// `OPERATOR` clause
+ Operator {
+ strategy_number: u64,
+ /// Operator argument types
+ op_types: Vec<DataType>,
+ },
+ /// `FUNCTION` clause
+ Function {
+ support_number: u64,
+ /// Operator argument types for the function
+ op_types: Vec<DataType>,
+ },
+}
+
+impl fmt::Display for OperatorFamilyItem {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ OperatorFamilyItem::Operator {
+ strategy_number,
+ operator_name,
+ op_types,
+ purpose,
+ } => {
+ write!(
+ f,
+ "OPERATOR {strategy_number} {operator_name} ({})",
+ display_comma_separated(op_types)
+ )?;
+ if let Some(purpose) = purpose {
+ write!(f, " {purpose}")?;
+ }
+ Ok(())
+ }
+ OperatorFamilyItem::Function {
+ support_number,
+ op_types,
+ function_name,
+ argument_types,
+ } => {
+ write!(f, "FUNCTION {support_number}")?;
+ if let Some(types) = op_types {
+ write!(f, " ({})", display_comma_separated(types))?;
+ }
+ write!(f, " {function_name}")?;
+ if !argument_types.is_empty() {
+ write!(f, "({})",
display_comma_separated(argument_types))?;
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
+impl fmt::Display for OperatorFamilyDropItem {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ OperatorFamilyDropItem::Operator {
+ strategy_number,
+ op_types,
+ } => {
+ write!(
+ f,
+ "OPERATOR {strategy_number} ({})",
+ display_comma_separated(op_types)
+ )
+ }
+ OperatorFamilyDropItem::Function {
+ support_number,
+ op_types,
+ } => {
+ write!(
+ f,
+ "FUNCTION {support_number} ({})",
+ display_comma_separated(op_types)
+ )
+ }
+ }
+ }
+}
+
+/// `ALTER OPERATOR FAMILY` statement
+/// See <https://www.postgresql.org/docs/current/sql-alteropfamily.html>
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct AlterOperatorFamily {
+ /// Operator family name (can be schema-qualified)
+ pub name: ObjectName,
+ /// Index method (btree, hash, gist, gin, etc.)
+ pub using: Ident,
+ /// The operation to perform
+ pub operation: AlterOperatorFamilyOperation,
+}
+
+/// An [AlterOperatorFamily] operation
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum AlterOperatorFamilyOperation {
+ /// `ADD { OPERATOR ... | FUNCTION ... } [, ...]`
+ Add {
+ /// List of operator family items to add
+ items: Vec<OperatorFamilyItem>,
+ },
+ /// `DROP { OPERATOR ... | FUNCTION ... } [, ...]`
+ Drop {
+ /// List of operator family items to drop
+ items: Vec<OperatorFamilyDropItem>,
+ },
+ /// `RENAME TO new_name`
+ RenameTo { new_name: ObjectName },
+ /// `OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }`
+ OwnerTo(Owner),
+ /// `SET SCHEMA new_schema`
+ SetSchema { schema_name: ObjectName },
+}
+
+impl fmt::Display for AlterOperatorFamily {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(
+ f,
+ "ALTER OPERATOR FAMILY {} USING {}",
+ self.name, self.using
+ )?;
+ write!(f, " {}", self.operation)
+ }
+}
+
+impl fmt::Display for AlterOperatorFamilyOperation {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ AlterOperatorFamilyOperation::Add { items } => {
+ write!(f, "ADD {}", display_comma_separated(items))
+ }
+ AlterOperatorFamilyOperation::Drop { items } => {
+ write!(f, "DROP {}", display_comma_separated(items))
+ }
+ AlterOperatorFamilyOperation::RenameTo { new_name } => {
+ write!(f, "RENAME TO {new_name}")
+ }
+ AlterOperatorFamilyOperation::OwnerTo(owner) => {
+ write!(f, "OWNER TO {owner}")
+ }
+ AlterOperatorFamilyOperation::SetSchema { schema_name } => {
+ write!(f, "SET SCHEMA {schema_name}")
+ }
+ }
+ }
+}
+
+impl Spanned for AlterOperatorFamily {
+ fn span(&self) -> Span {
+ Span::empty()
+ }
+}
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index f1e79b0d..46767860 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -60,22 +60,24 @@ pub use self::dcl::{
};
pub use self::ddl::{
Alignment, AlterColumnOperation, AlterConnectorOwner, AlterIndexOperation,
AlterOperator,
- AlterOperatorOperation, AlterPolicyOperation, AlterSchema,
AlterSchemaOperation, AlterTable,
- AlterTableAlgorithm, AlterTableLock, AlterTableOperation, AlterTableType,
AlterType,
- AlterTypeAddValue, AlterTypeAddValuePosition, AlterTypeOperation,
AlterTypeRename,
- AlterTypeRenameValue, ClusteredBy, ColumnDef, ColumnOption,
ColumnOptionDef, ColumnOptions,
- ColumnPolicy, ColumnPolicyProperty, ConstraintCharacteristics,
CreateConnector, CreateDomain,
+ AlterOperatorFamily, AlterOperatorFamilyOperation, AlterOperatorOperation,
+ AlterPolicyOperation, AlterSchema, AlterSchemaOperation, AlterTable,
AlterTableAlgorithm,
+ AlterTableLock, AlterTableOperation, AlterTableType, AlterType,
AlterTypeAddValue,
+ AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename,
AlterTypeRenameValue,
+ ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions,
ColumnPolicy,
+ ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector,
CreateDomain,
CreateExtension, CreateFunction, CreateIndex, CreateOperator,
CreateOperatorClass,
CreateOperatorFamily, CreateTable, CreateTrigger, CreateView, Deduplicate,
DeferrableInitial,
DropBehavior, DropExtension, DropFunction, DropOperator,
DropOperatorClass, DropOperatorFamily,
DropOperatorSignature, DropTrigger, GeneratedAs, GeneratedExpressionMode,
IdentityParameters,
IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
IdentityPropertyOrder,
IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck,
NullsDistinctOption,
- OperatorArgTypes, OperatorClassItem, OperatorOption, OperatorPurpose,
Owner, Partition,
- ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity,
TagsColumnOption,
- TriggerObjectKind, Truncate, UserDefinedTypeCompositeAttributeDef,
- UserDefinedTypeInternalLength, UserDefinedTypeRangeOption,
UserDefinedTypeRepresentation,
- UserDefinedTypeSqlDefinitionOption, UserDefinedTypeStorage, ViewColumnDef,
+ OperatorArgTypes, OperatorClassItem, OperatorFamilyDropItem,
OperatorFamilyItem,
+ OperatorOption, OperatorPurpose, Owner, Partition, ProcedureParam,
ReferentialAction,
+ RenameTableNameKind, ReplicaIdentity, TagsColumnOption, TriggerObjectKind,
Truncate,
+ UserDefinedTypeCompositeAttributeDef, UserDefinedTypeInternalLength,
+ UserDefinedTypeRangeOption, UserDefinedTypeRepresentation,
UserDefinedTypeSqlDefinitionOption,
+ UserDefinedTypeStorage, ViewColumnDef,
};
pub use self::dml::{
Delete, Insert, Merge, MergeAction, MergeClause, MergeClauseKind,
MergeInsertExpr,
@@ -3411,6 +3413,11 @@ pub enum Statement {
/// See
[PostgreSQL](https://www.postgresql.org/docs/current/sql-alteroperator.html)
AlterOperator(AlterOperator),
/// ```sql
+ /// ALTER OPERATOR FAMILY
+ /// ```
+ /// See
[PostgreSQL](https://www.postgresql.org/docs/current/sql-alteropfamily.html)
+ AlterOperatorFamily(AlterOperatorFamily),
+ /// ```sql
/// ALTER ROLE
/// ```
AlterRole {
@@ -4972,6 +4979,9 @@ impl fmt::Display for Statement {
write!(f, "ALTER TYPE {name} {operation}")
}
Statement::AlterOperator(alter_operator) => write!(f,
"{alter_operator}"),
+ Statement::AlterOperatorFamily(alter_operator_family) => {
+ write!(f, "{alter_operator_family}")
+ }
Statement::AlterRole { name, operation } => {
write!(f, "ALTER ROLE {name} {operation}")
}
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 2ec797db..d4e84315 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -403,6 +403,7 @@ impl Spanned for Statement {
// These statements need to be implemented
Statement::AlterType { .. } => Span::empty(),
Statement::AlterOperator { .. } => Span::empty(),
+ Statement::AlterOperatorFamily { .. } => Span::empty(),
Statement::AlterRole { .. } => Span::empty(),
Statement::AlterSession { .. } => Span::empty(),
Statement::AttachDatabase { .. } => Span::empty(),
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index ade3c250..74b06ec8 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -6701,7 +6701,7 @@ impl<'a> Parser<'a> {
let mut items = vec![];
loop {
if self.parse_keyword(Keyword::OPERATOR) {
- let strategy_number = self.parse_literal_uint()? as u32;
+ let strategy_number = self.parse_literal_uint()?;
let operator_name = self.parse_operator_name()?;
// Optional operator argument types
@@ -6736,7 +6736,7 @@ impl<'a> Parser<'a> {
purpose,
});
} else if self.parse_keyword(Keyword::FUNCTION) {
- let support_number = self.parse_literal_uint()? as u32;
+ let support_number = self.parse_literal_uint()?;
// Optional operator types
let op_types =
@@ -9898,7 +9898,13 @@ impl<'a> Parser<'a> {
operation,
})
}
- Keyword::OPERATOR => self.parse_alter_operator(),
+ Keyword::OPERATOR => {
+ if self.parse_keyword(Keyword::FAMILY) {
+ self.parse_alter_operator_family()
+ } else {
+ self.parse_alter_operator()
+ }
+ }
Keyword::ROLE => self.parse_alter_role(),
Keyword::POLICY => self.parse_alter_policy(),
Keyword::CONNECTOR => self.parse_alter_connector(),
@@ -10130,6 +10136,170 @@ impl<'a> Parser<'a> {
}))
}
+ /// Parse an operator item for ALTER OPERATOR FAMILY ADD operations
+ fn parse_operator_family_add_operator(&mut self) ->
Result<OperatorFamilyItem, ParserError> {
+ let strategy_number = self.parse_literal_uint()?;
+ let operator_name = self.parse_operator_name()?;
+
+ // Operator argument types (required for ALTER OPERATOR FAMILY)
+ self.expect_token(&Token::LParen)?;
+ let op_types = self.parse_comma_separated(Parser::parse_data_type)?;
+ self.expect_token(&Token::RParen)?;
+
+ // Optional purpose
+ let purpose = if self.parse_keyword(Keyword::FOR) {
+ if self.parse_keyword(Keyword::SEARCH) {
+ Some(OperatorPurpose::ForSearch)
+ } else if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) {
+ let sort_family = self.parse_object_name(false)?;
+ Some(OperatorPurpose::ForOrderBy { sort_family })
+ } else {
+ return self.expected("SEARCH or ORDER BY after FOR",
self.peek_token());
+ }
+ } else {
+ None
+ };
+
+ Ok(OperatorFamilyItem::Operator {
+ strategy_number,
+ operator_name,
+ op_types,
+ purpose,
+ })
+ }
+
+ /// Parse a function item for ALTER OPERATOR FAMILY ADD operations
+ fn parse_operator_family_add_function(&mut self) ->
Result<OperatorFamilyItem, ParserError> {
+ let support_number = self.parse_literal_uint()?;
+
+ // Optional operator types
+ let op_types = if self.consume_token(&Token::LParen) &&
self.peek_token() != Token::RParen {
+ let types = self.parse_comma_separated(Parser::parse_data_type)?;
+ self.expect_token(&Token::RParen)?;
+ Some(types)
+ } else if self.consume_token(&Token::LParen) {
+ self.expect_token(&Token::RParen)?;
+ Some(vec![])
+ } else {
+ None
+ };
+
+ let function_name = self.parse_object_name(false)?;
+
+ // Function argument types
+ let argument_types = if self.consume_token(&Token::LParen) {
+ if self.peek_token() == Token::RParen {
+ self.expect_token(&Token::RParen)?;
+ vec![]
+ } else {
+ let types =
self.parse_comma_separated(Parser::parse_data_type)?;
+ self.expect_token(&Token::RParen)?;
+ types
+ }
+ } else {
+ vec![]
+ };
+
+ Ok(OperatorFamilyItem::Function {
+ support_number,
+ op_types,
+ function_name,
+ argument_types,
+ })
+ }
+
+ /// Parse an operator item for ALTER OPERATOR FAMILY DROP operations
+ fn parse_operator_family_drop_operator(
+ &mut self,
+ ) -> Result<OperatorFamilyDropItem, ParserError> {
+ let strategy_number = self.parse_literal_uint()?;
+
+ // Operator argument types (required for DROP)
+ self.expect_token(&Token::LParen)?;
+ let op_types = self.parse_comma_separated(Parser::parse_data_type)?;
+ self.expect_token(&Token::RParen)?;
+
+ Ok(OperatorFamilyDropItem::Operator {
+ strategy_number,
+ op_types,
+ })
+ }
+
+ /// Parse a function item for ALTER OPERATOR FAMILY DROP operations
+ fn parse_operator_family_drop_function(
+ &mut self,
+ ) -> Result<OperatorFamilyDropItem, ParserError> {
+ let support_number = self.parse_literal_uint()?;
+
+ // Operator types (required for DROP)
+ self.expect_token(&Token::LParen)?;
+ let op_types = self.parse_comma_separated(Parser::parse_data_type)?;
+ self.expect_token(&Token::RParen)?;
+
+ Ok(OperatorFamilyDropItem::Function {
+ support_number,
+ op_types,
+ })
+ }
+
+ /// Parse an operator family item for ADD operations (dispatches to
operator or function parsing)
+ fn parse_operator_family_add_item(&mut self) -> Result<OperatorFamilyItem,
ParserError> {
+ if self.parse_keyword(Keyword::OPERATOR) {
+ self.parse_operator_family_add_operator()
+ } else if self.parse_keyword(Keyword::FUNCTION) {
+ self.parse_operator_family_add_function()
+ } else {
+ self.expected("OPERATOR or FUNCTION", self.peek_token())
+ }
+ }
+
+ /// Parse an operator family item for DROP operations (dispatches to
operator or function parsing)
+ fn parse_operator_family_drop_item(&mut self) ->
Result<OperatorFamilyDropItem, ParserError> {
+ if self.parse_keyword(Keyword::OPERATOR) {
+ self.parse_operator_family_drop_operator()
+ } else if self.parse_keyword(Keyword::FUNCTION) {
+ self.parse_operator_family_drop_function()
+ } else {
+ self.expected("OPERATOR or FUNCTION", self.peek_token())
+ }
+ }
+
+ /// Parse a [Statement::AlterOperatorFamily]
+ /// See <https://www.postgresql.org/docs/current/sql-alteropfamily.html>
+ pub fn parse_alter_operator_family(&mut self) -> Result<Statement,
ParserError> {
+ let name = self.parse_object_name(false)?;
+ self.expect_keyword(Keyword::USING)?;
+ let using = self.parse_identifier()?;
+
+ let operation = if self.parse_keyword(Keyword::ADD) {
+ let items =
self.parse_comma_separated(Parser::parse_operator_family_add_item)?;
+ AlterOperatorFamilyOperation::Add { items }
+ } else if self.parse_keyword(Keyword::DROP) {
+ let items =
self.parse_comma_separated(Parser::parse_operator_family_drop_item)?;
+ AlterOperatorFamilyOperation::Drop { items }
+ } else if self.parse_keywords(&[Keyword::RENAME, Keyword::TO]) {
+ let new_name = self.parse_object_name(false)?;
+ AlterOperatorFamilyOperation::RenameTo { new_name }
+ } else if self.parse_keywords(&[Keyword::OWNER, Keyword::TO]) {
+ let owner = self.parse_owner()?;
+ AlterOperatorFamilyOperation::OwnerTo(owner)
+ } else if self.parse_keywords(&[Keyword::SET, Keyword::SCHEMA]) {
+ let schema_name = self.parse_object_name(false)?;
+ AlterOperatorFamilyOperation::SetSchema { schema_name }
+ } else {
+ return self.expected_ref(
+ "ADD, DROP, RENAME TO, OWNER TO, or SET SCHEMA after ALTER
OPERATOR FAMILY",
+ self.peek_token_ref(),
+ );
+ };
+
+ Ok(Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name,
+ using,
+ operation,
+ }))
+ }
+
// Parse a [Statement::AlterSchema]
// ALTER SCHEMA [ IF EXISTS ] schema_name
pub fn parse_alter_schema(&mut self) -> Result<Statement, ParserError> {
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index d595a0a2..9f4564ef 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -23,15 +23,11 @@
mod test_utils;
use helpers::attached_token::AttachedToken;
-use sqlparser::ast::{
- DataType, DropBehavior, DropOperator, DropOperatorClass,
DropOperatorSignature,
-};
-use sqlparser::tokenizer::Span;
-use test_utils::*;
-
use sqlparser::ast::*;
use sqlparser::dialect::{GenericDialect, PostgreSqlDialect};
use sqlparser::parser::ParserError;
+use sqlparser::tokenizer::Span;
+use test_utils::*;
#[test]
fn parse_create_table_generated_always_as_identity() {
@@ -7145,6 +7141,396 @@ fn parse_alter_operator() {
);
}
+#[test]
+fn parse_alter_operator_family() {
+ // Test ALTER OPERATOR FAMILY ... ADD OPERATOR
+ let sql = "ALTER OPERATOR FAMILY integer_ops USING btree ADD OPERATOR 1 <
(INT4, INT2)";
+ assert_eq!(
+ pg_and_generic().verified_stmt(sql),
+ Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name: ObjectName::from(vec![Ident::new("integer_ops")]),
+ using: Ident::new("btree"),
+ operation: AlterOperatorFamilyOperation::Add {
+ items: vec![OperatorFamilyItem::Operator {
+ strategy_number: 1,
+ operator_name: ObjectName::from(vec![Ident::new("<")]),
+ op_types: vec![DataType::Int4(None), DataType::Int2(None)],
+ purpose: None,
+ }],
+ },
+ })
+ );
+
+ // Test ALTER OPERATOR FAMILY ... ADD OPERATOR with FOR SEARCH
+ let sql =
+ "ALTER OPERATOR FAMILY text_ops USING btree ADD OPERATOR 1 @@ (TEXT,
TEXT) FOR SEARCH";
+ assert_eq!(
+ pg_and_generic().verified_stmt(sql),
+ Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name: ObjectName::from(vec![Ident::new("text_ops")]),
+ using: Ident::new("btree"),
+ operation: AlterOperatorFamilyOperation::Add {
+ items: vec![OperatorFamilyItem::Operator {
+ strategy_number: 1,
+ operator_name: ObjectName::from(vec![Ident::new("@@")]),
+ op_types: vec![DataType::Text, DataType::Text],
+ purpose: Some(OperatorPurpose::ForSearch),
+ }],
+ },
+ })
+ );
+
+ // Test ALTER OPERATOR FAMILY ... ADD FUNCTION
+ let sql = "ALTER OPERATOR FAMILY integer_ops USING btree ADD FUNCTION 1
btint42cmp(INT4, INT2)";
+ assert_eq!(
+ pg_and_generic().verified_stmt(sql),
+ Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name: ObjectName::from(vec![Ident::new("integer_ops")]),
+ using: Ident::new("btree"),
+ operation: AlterOperatorFamilyOperation::Add {
+ items: vec![OperatorFamilyItem::Function {
+ support_number: 1,
+ op_types: None,
+ function_name:
ObjectName::from(vec![Ident::new("btint42cmp")]),
+ argument_types: vec![DataType::Int4(None),
DataType::Int2(None)],
+ }],
+ },
+ })
+ );
+
+ // Test ALTER OPERATOR FAMILY ... DROP OPERATOR
+ let sql = "ALTER OPERATOR FAMILY integer_ops USING btree DROP OPERATOR 1
(INT4, INT2)";
+ assert_eq!(
+ pg_and_generic().verified_stmt(sql),
+ Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name: ObjectName::from(vec![Ident::new("integer_ops")]),
+ using: Ident::new("btree"),
+ operation: AlterOperatorFamilyOperation::Drop {
+ items: vec![OperatorFamilyDropItem::Operator {
+ strategy_number: 1,
+ op_types: vec![DataType::Int4(None), DataType::Int2(None)],
+ }],
+ },
+ })
+ );
+
+ // Test ALTER OPERATOR FAMILY ... DROP FUNCTION
+ let sql = "ALTER OPERATOR FAMILY integer_ops USING btree DROP FUNCTION 1
(INT4, INT2)";
+ assert_eq!(
+ pg_and_generic().verified_stmt(sql),
+ Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name: ObjectName::from(vec![Ident::new("integer_ops")]),
+ using: Ident::new("btree"),
+ operation: AlterOperatorFamilyOperation::Drop {
+ items: vec![OperatorFamilyDropItem::Function {
+ support_number: 1,
+ op_types: vec![DataType::Int4(None), DataType::Int2(None)],
+ }],
+ },
+ })
+ );
+
+ // Test ALTER OPERATOR FAMILY ... RENAME TO
+ let sql = "ALTER OPERATOR FAMILY old_ops USING btree RENAME TO new_ops";
+ assert_eq!(
+ pg_and_generic().verified_stmt(sql),
+ Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name: ObjectName::from(vec![Ident::new("old_ops")]),
+ using: Ident::new("btree"),
+ operation: AlterOperatorFamilyOperation::RenameTo {
+ new_name: ObjectName::from(vec![Ident::new("new_ops")]),
+ },
+ })
+ );
+
+ // Test ALTER OPERATOR FAMILY ... OWNER TO
+ let sql = "ALTER OPERATOR FAMILY my_ops USING btree OWNER TO joe";
+ assert_eq!(
+ pg_and_generic().verified_stmt(sql),
+ Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name: ObjectName::from(vec![Ident::new("my_ops")]),
+ using: Ident::new("btree"),
+ operation:
AlterOperatorFamilyOperation::OwnerTo(Owner::Ident(Ident::new("joe"))),
+ })
+ );
+
+ // Test ALTER OPERATOR FAMILY ... SET SCHEMA
+ let sql = "ALTER OPERATOR FAMILY my_ops USING btree SET SCHEMA new_schema";
+ assert_eq!(
+ pg_and_generic().verified_stmt(sql),
+ Statement::AlterOperatorFamily(AlterOperatorFamily {
+ name: ObjectName::from(vec![Ident::new("my_ops")]),
+ using: Ident::new("btree"),
+ operation: AlterOperatorFamilyOperation::SetSchema {
+ schema_name: ObjectName::from(vec![Ident::new("new_schema")]),
+ },
+ })
+ );
+
+ // Test error cases
+ // Missing USING clause
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops ADD OPERATOR 1 <
(INT4, INT2)")
+ .is_err());
+
+ // Invalid operation
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree
INVALID_OPERATION")
+ .is_err());
+
+ // Missing operator name in ADD OPERATOR
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 (INT4,
INT2)"
+ )
+ .is_err());
+
+ // Missing function name in ADD FUNCTION
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION 1 (INT4,
INT2)"
+ )
+ .is_err());
+
+ // Missing parentheses in DROP OPERATOR
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree DROP
OPERATOR 1 INT4, INT2")
+ .is_err());
+
+ // Invalid operator name (empty)
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 (INT4,
INT2)"
+ )
+ .is_err());
+
+ // Invalid operator name (special characters)
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 @#$
(INT4, INT2)"
+ )
+ .is_err());
+
+ // Negative strategy number
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR -1 < (INT4,
INT2)"
+ )
+ .is_err());
+
+ // Non-integer strategy number
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1.5 <
(INT4, INT2)"
+ )
+ .is_err());
+
+ // Missing closing parenthesis in operator types
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 < (INT4,
INT2"
+ )
+ .is_err());
+
+ // Missing opening parenthesis in operator types
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 < INT4,
INT2)"
+ )
+ .is_err());
+
+ // Empty operator types
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree ADD
OPERATOR 1 < ()")
+ .is_err());
+
+ // Invalid data type (using punctuation)
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 < (@#$%,
INT2)"
+ )
+ .is_err());
+
+ // Incomplete FOR clause
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 < (INT4,
INT2) FOR"
+ )
+ .is_err());
+
+ // Invalid FOR clause keyword
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 < (INT4,
INT2) FOR INVALID"
+ )
+ .is_err());
+
+ // FOR ORDER BY without sort family
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 < (INT4,
INT2) FOR ORDER BY"
+ )
+ .is_err());
+
+ // Missing function name in ADD FUNCTION
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION 1 (INT4,
INT2)"
+ )
+ .is_err());
+
+ // Invalid function name
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION 1
123invalid(INT4, INT2)"
+ )
+ .is_err());
+
+ // Negative support number
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION -1
func(INT4, INT2)"
+ )
+ .is_err());
+
+ // Non-integer support number
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION 1.5
func(INT4, INT2)"
+ )
+ .is_err());
+
+ // Missing closing parenthesis in function operator types
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION 1 (INT4,
INT2 func()"
+ )
+ .is_err());
+
+ // Missing closing parenthesis in function arguments
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION 1
func(INT4, INT2"
+ )
+ .is_err());
+
+ // Invalid data type in function arguments
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION 1
func(@#$%, INT2)"
+ )
+ .is_err());
+
+ // DROP OPERATOR with FOR clause (not allowed)
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree DROP OPERATOR 1 (INT4,
INT2) FOR SEARCH"
+ )
+ .is_err());
+
+ // DROP FUNCTION with function arguments (not allowed)
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree DROP FUNCTION 1 (INT4,
INT2) func(INT4)"
+ )
+ .is_err());
+
+ // Multiple ADD items with error in middle
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 < (INT4,
INT2), INVALID_ITEM"
+ )
+ .is_err());
+
+ // Multiple DROP items with error in middle
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree DROP OPERATOR 1 (INT4,
INT2), INVALID_ITEM"
+ )
+ .is_err());
+
+ // RENAME TO with invalid new name
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree RENAME
TO 123invalid")
+ .is_err());
+
+ // OWNER TO with invalid owner
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree OWNER
TO 123invalid")
+ .is_err());
+
+ // SET SCHEMA with invalid schema name
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree SET
SCHEMA 123invalid")
+ .is_err());
+
+ // Schema-qualified operator family name with invalid schema
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY 123invalid.my_ops USING btree ADD OPERATOR
1 < (INT4, INT2)"
+ )
+ .is_err());
+
+ // Missing operator family name
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY USING btree ADD OPERATOR
1 < (INT4, INT2)")
+ .is_err());
+
+ // Extra tokens at end
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD OPERATOR 1 < (INT4,
INT2) EXTRA"
+ )
+ .is_err());
+
+ // Incomplete statement
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree ADD")
+ .is_err());
+
+ // Very long numbers
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree ADD
OPERATOR 999999999999999999999 < (INT4, INT2)")
+ .is_err());
+
+ // Multiple FOR clauses
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree ADD
OPERATOR 1 < (INT4, INT2) FOR SEARCH FOR ORDER BY sort_family")
+ .is_err());
+
+ // FOR SEARCH with extra tokens
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree ADD
OPERATOR 1 < (INT4, INT2) FOR SEARCH EXTRA")
+ .is_err());
+
+ // FOR ORDER BY with invalid sort family
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree ADD
OPERATOR 1 < (INT4, INT2) FOR ORDER BY 123invalid")
+ .is_err());
+
+ // Function with empty operator types but missing function args parens
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree ADD
FUNCTION 1 () func")
+ .is_err());
+
+ // Function with mismatched parentheses
+ assert!(pg()
+ .parse_sql_statements(
+ "ALTER OPERATOR FAMILY my_ops USING btree ADD FUNCTION 1 (INT4
func(INT2"
+ )
+ .is_err());
+
+ // DROP with empty types
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree DROP
OPERATOR 1 ()")
+ .is_err());
+
+ // DROP FUNCTION with empty types
+ assert!(pg()
+ .parse_sql_statements("ALTER OPERATOR FAMILY my_ops USING btree DROP
FUNCTION 1 ()")
+ .is_err());
+}
+
#[test]
fn parse_drop_operator_family() {
for if_exists in [true, false] {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]