Added support for ALTER OPERATOR FAMILY syntax (#2125)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run

This commit is contained in:
Luca Cappelletti 2025-12-18 05:34:48 +01:00 committed by GitHub
parent f84887d004
commit d78dbc97a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 778 additions and 25 deletions

View file

@ -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()
}
}

View file

@ -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}")
}

View file

@ -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(),

View file

@ -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> {

View file

@ -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] {