Skip to content

Commit 9883296

Browse files
LucaCappelletti94iffyio
authored andcommitted
Added support for DROP OPERATOR syntax (apache#2102)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
1 parent 8d14e8e commit 9883296

File tree

5 files changed

+206
-9
lines changed

5 files changed

+206
-9
lines changed

src/ast/ddl.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4188,3 +4188,62 @@ impl fmt::Display for OperatorPurpose {
41884188
}
41894189
}
41904190
}
4191+
4192+
/// `DROP OPERATOR` statement
4193+
/// See <https://www.postgresql.org/docs/current/sql-dropoperator.html>
4194+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4195+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4196+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4197+
pub struct DropOperator {
4198+
/// `IF EXISTS` clause
4199+
pub if_exists: bool,
4200+
/// One or more operators to drop with their signatures
4201+
pub operators: Vec<DropOperatorSignature>,
4202+
/// `CASCADE or RESTRICT`
4203+
pub drop_behavior: Option<DropBehavior>,
4204+
}
4205+
4206+
/// Operator signature for a `DROP OPERATOR` statement
4207+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4208+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4209+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4210+
pub struct DropOperatorSignature {
4211+
/// Operator name
4212+
pub name: ObjectName,
4213+
/// Left operand type
4214+
pub left_type: Option<DataType>,
4215+
/// Right operand type
4216+
pub right_type: DataType,
4217+
}
4218+
4219+
impl fmt::Display for DropOperatorSignature {
4220+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4221+
write!(f, "{} (", self.name)?;
4222+
if let Some(left_type) = &self.left_type {
4223+
write!(f, "{}", left_type)?;
4224+
} else {
4225+
write!(f, "NONE")?;
4226+
}
4227+
write!(f, ", {})", self.right_type)
4228+
}
4229+
}
4230+
4231+
impl fmt::Display for DropOperator {
4232+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4233+
write!(f, "DROP OPERATOR")?;
4234+
if self.if_exists {
4235+
write!(f, " IF EXISTS")?;
4236+
}
4237+
write!(f, " {}", display_comma_separated(&self.operators))?;
4238+
if let Some(drop_behavior) = &self.drop_behavior {
4239+
write!(f, " {}", drop_behavior)?;
4240+
}
4241+
Ok(())
4242+
}
4243+
}
4244+
4245+
impl Spanned for DropOperator {
4246+
fn span(&self) -> Span {
4247+
Span::empty()
4248+
}
4249+
}

src/ast/mod.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,15 @@ pub use self::ddl::{
6767
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
6868
CreateExtension, CreateFunction, CreateIndex, CreateOperator, CreateOperatorClass,
6969
CreateOperatorFamily, CreateTable, CreateTrigger, CreateView, Deduplicate, DeferrableInitial,
70-
DropBehavior, DropExtension, DropFunction, DropTrigger, GeneratedAs, GeneratedExpressionMode,
71-
IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
72-
IdentityPropertyOrder, IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck,
73-
NullsDistinctOption, OperatorArgTypes, OperatorClassItem, OperatorPurpose, Owner, Partition,
74-
ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity, TagsColumnOption,
75-
TriggerObjectKind, Truncate, UserDefinedTypeCompositeAttributeDef,
76-
UserDefinedTypeInternalLength, UserDefinedTypeRangeOption, UserDefinedTypeRepresentation,
77-
UserDefinedTypeSqlDefinitionOption, UserDefinedTypeStorage, ViewColumnDef,
70+
DropBehavior, DropExtension, DropFunction, DropOperator, DropOperatorSignature, DropTrigger,
71+
GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
72+
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
73+
IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, OperatorArgTypes,
74+
OperatorClassItem, OperatorPurpose, Owner, Partition, ProcedureParam, ReferentialAction,
75+
RenameTableNameKind, ReplicaIdentity, TagsColumnOption, TriggerObjectKind, Truncate,
76+
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeInternalLength,
77+
UserDefinedTypeRangeOption, UserDefinedTypeRepresentation, UserDefinedTypeSqlDefinitionOption,
78+
UserDefinedTypeStorage, ViewColumnDef,
7879
};
7980
pub use self::dml::{Delete, Insert, Update};
8081
pub use self::operator::{BinaryOperator, UnaryOperator};
@@ -3607,6 +3608,12 @@ pub enum Statement {
36073608
/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
36083609
DropExtension(DropExtension),
36093610
/// ```sql
3611+
/// DROP OPERATOR [ IF EXISTS ] name ( { left_type | NONE } , right_type ) [, ...] [ CASCADE | RESTRICT ]
3612+
/// ```
3613+
/// Note: this is a PostgreSQL-specific statement.
3614+
/// <https://www.postgresql.org/docs/current/sql-dropoperator.html>
3615+
DropOperator(DropOperator),
3616+
/// ```sql
36103617
/// FETCH
36113618
/// ```
36123619
/// Retrieve rows from a query using a cursor
@@ -4870,6 +4877,7 @@ impl fmt::Display for Statement {
48704877
Statement::CreateIndex(create_index) => create_index.fmt(f),
48714878
Statement::CreateExtension(create_extension) => write!(f, "{create_extension}"),
48724879
Statement::DropExtension(drop_extension) => write!(f, "{drop_extension}"),
4880+
Statement::DropOperator(drop_operator) => write!(f, "{drop_operator}"),
48734881
Statement::CreateRole(create_role) => write!(f, "{create_role}"),
48744882
Statement::CreateSecret {
48754883
or_replace,

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ impl Spanned for Statement {
375375
Statement::CreateRole(create_role) => create_role.span(),
376376
Statement::CreateExtension(create_extension) => create_extension.span(),
377377
Statement::DropExtension(drop_extension) => drop_extension.span(),
378+
Statement::DropOperator(drop_operator) => drop_operator.span(),
378379
Statement::CreateSecret { .. } => Span::empty(),
379380
Statement::CreateServer { .. } => Span::empty(),
380381
Statement::CreateConnector { .. } => Span::empty(),

src/parser/mod.rs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6798,9 +6798,11 @@ impl<'a> Parser<'a> {
67986798
return self.parse_drop_trigger();
67996799
} else if self.parse_keyword(Keyword::EXTENSION) {
68006800
return self.parse_drop_extension();
6801+
} else if self.parse_keyword(Keyword::OPERATOR) {
6802+
return self.parse_drop_operator();
68016803
} else {
68026804
return self.expected(
6803-
"CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW or USER after DROP",
6805+
"CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, OPERATOR, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW or USER after DROP",
68046806
self.peek_token(),
68056807
);
68066808
};
@@ -7556,6 +7558,46 @@ impl<'a> Parser<'a> {
75567558
}))
75577559
}
75587560

7561+
/// Parse a[Statement::DropOperator] statement.
7562+
///
7563+
pub fn parse_drop_operator(&mut self) -> Result<Statement, ParserError> {
7564+
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
7565+
let operators = self.parse_comma_separated(|p| p.parse_drop_operator_signature())?;
7566+
let drop_behavior = self.parse_optional_drop_behavior();
7567+
Ok(Statement::DropOperator(DropOperator {
7568+
if_exists,
7569+
operators,
7570+
drop_behavior,
7571+
}))
7572+
}
7573+
7574+
/// Parse an operator signature for a [Statement::DropOperator]
7575+
/// Format: `name ( { left_type | NONE } , right_type )`
7576+
fn parse_drop_operator_signature(&mut self) -> Result<DropOperatorSignature, ParserError> {
7577+
let name = self.parse_operator_name()?;
7578+
self.expect_token(&Token::LParen)?;
7579+
7580+
// Parse left operand type (or NONE for prefix operators)
7581+
let left_type = if self.parse_keyword(Keyword::NONE) {
7582+
None
7583+
} else {
7584+
Some(self.parse_data_type()?)
7585+
};
7586+
7587+
self.expect_token(&Token::Comma)?;
7588+
7589+
// Parse right operand type (always required)
7590+
let right_type = self.parse_data_type()?;
7591+
7592+
self.expect_token(&Token::RParen)?;
7593+
7594+
Ok(DropOperatorSignature {
7595+
name,
7596+
left_type,
7597+
right_type,
7598+
})
7599+
}
7600+
75597601
//TODO: Implement parsing for Skewed
75607602
pub fn parse_hive_distribution(&mut self) -> Result<HiveDistributionStyle, ParserError> {
75617603
if self.parse_keywords(&[Keyword::PARTITIONED, Keyword::BY]) {

tests/sqlparser_postgres.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
mod test_utils;
2424

2525
use helpers::attached_token::AttachedToken;
26+
use sqlparser::ast::{DataType, DropBehavior, DropOperator, DropOperatorSignature};
2627
use sqlparser::tokenizer::Span;
2728
use test_utils::*;
2829

@@ -6763,6 +6764,92 @@ fn parse_create_operator() {
67636764
assert!(pg().parse_sql_statements("CREATE OPERATOR > ())").is_err());
67646765
}
67656766

6767+
#[test]
6768+
fn parse_drop_operator() {
6769+
// Test DROP OPERATOR with NONE for prefix operator
6770+
let sql = "DROP OPERATOR ~ (NONE, BIT)";
6771+
assert_eq!(
6772+
pg_and_generic().verified_stmt(sql),
6773+
Statement::DropOperator(DropOperator {
6774+
if_exists: false,
6775+
operators: vec![DropOperatorSignature {
6776+
name: ObjectName::from(vec![Ident::new("~")]),
6777+
left_type: None,
6778+
right_type: DataType::Bit(None),
6779+
}],
6780+
drop_behavior: None,
6781+
})
6782+
);
6783+
6784+
for if_exist in [true, false] {
6785+
for cascading in [
6786+
None,
6787+
Some(DropBehavior::Cascade),
6788+
Some(DropBehavior::Restrict),
6789+
] {
6790+
for op in &["<", ">", "<=", ">=", "<>", "||", "&&", "<<", ">>"] {
6791+
let sql = format!(
6792+
"DROP OPERATOR{} {op} (INTEGER, INTEGER){}",
6793+
if if_exist { " IF EXISTS" } else { "" },
6794+
match cascading {
6795+
Some(cascading) => format!(" {cascading}"),
6796+
None => String::new(),
6797+
}
6798+
);
6799+
assert_eq!(
6800+
pg_and_generic().verified_stmt(&sql),
6801+
Statement::DropOperator(DropOperator {
6802+
if_exists: if_exist,
6803+
operators: vec![DropOperatorSignature {
6804+
name: ObjectName::from(vec![Ident::new(*op)]),
6805+
left_type: Some(DataType::Integer(None)),
6806+
right_type: DataType::Integer(None),
6807+
}],
6808+
drop_behavior: cascading,
6809+
})
6810+
);
6811+
}
6812+
}
6813+
}
6814+
6815+
// Test DROP OPERATOR with schema-qualified operator name
6816+
let sql = "DROP OPERATOR myschema.@@ (TEXT, TEXT)";
6817+
assert_eq!(
6818+
pg_and_generic().verified_stmt(sql),
6819+
Statement::DropOperator(DropOperator {
6820+
if_exists: false,
6821+
operators: vec![DropOperatorSignature {
6822+
name: ObjectName::from(vec![Ident::new("myschema"), Ident::new("@@")]),
6823+
left_type: Some(DataType::Text),
6824+
right_type: DataType::Text,
6825+
}],
6826+
drop_behavior: None,
6827+
})
6828+
);
6829+
6830+
// Test DROP OPERATOR with multiple operators, IF EXISTS and CASCADE
6831+
let sql = "DROP OPERATOR IF EXISTS + (INTEGER, INTEGER), - (INTEGER, INTEGER) CASCADE";
6832+
assert_eq!(
6833+
pg_and_generic().verified_stmt(sql),
6834+
Statement::DropOperator(DropOperator {
6835+
if_exists: true,
6836+
operators: vec![
6837+
DropOperatorSignature {
6838+
name: ObjectName::from(vec![Ident::new("+")]),
6839+
left_type: Some(DataType::Integer(None)),
6840+
right_type: DataType::Integer(None),
6841+
},
6842+
DropOperatorSignature {
6843+
name: ObjectName::from(vec![Ident::new("-")]),
6844+
left_type: Some(DataType::Integer(None)),
6845+
right_type: DataType::Integer(None),
6846+
}
6847+
],
6848+
drop_behavior: Some(DropBehavior::Cascade),
6849+
})
6850+
);
6851+
}
6852+
67666853
#[test]
67676854
fn parse_create_operator_family() {
67686855
for index_method in &["btree", "hash", "gist", "gin", "spgist", "brin"] {

0 commit comments

Comments
 (0)