mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-12-23 11:12:51 +00:00
Added support for DROP OPERATOR syntax (#2102)
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
This commit is contained in:
parent
2ceae006a4
commit
2a2abc8dad
5 changed files with 206 additions and 9 deletions
|
|
@ -4188,3 +4188,62 @@ impl fmt::Display for OperatorPurpose {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `DROP OPERATOR` statement
|
||||
/// See <https://www.postgresql.org/docs/current/sql-dropoperator.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 DropOperator {
|
||||
/// `IF EXISTS` clause
|
||||
pub if_exists: bool,
|
||||
/// One or more operators to drop with their signatures
|
||||
pub operators: Vec<DropOperatorSignature>,
|
||||
/// `CASCADE or RESTRICT`
|
||||
pub drop_behavior: Option<DropBehavior>,
|
||||
}
|
||||
|
||||
/// Operator signature for a `DROP OPERATOR` statement
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub struct DropOperatorSignature {
|
||||
/// Operator name
|
||||
pub name: ObjectName,
|
||||
/// Left operand type
|
||||
pub left_type: Option<DataType>,
|
||||
/// Right operand type
|
||||
pub right_type: DataType,
|
||||
}
|
||||
|
||||
impl fmt::Display for DropOperatorSignature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} (", self.name)?;
|
||||
if let Some(left_type) = &self.left_type {
|
||||
write!(f, "{}", left_type)?;
|
||||
} else {
|
||||
write!(f, "NONE")?;
|
||||
}
|
||||
write!(f, ", {})", self.right_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DropOperator {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DROP OPERATOR")?;
|
||||
if self.if_exists {
|
||||
write!(f, " IF EXISTS")?;
|
||||
}
|
||||
write!(f, " {}", display_comma_separated(&self.operators))?;
|
||||
if let Some(drop_behavior) = &self.drop_behavior {
|
||||
write!(f, " {}", drop_behavior)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for DropOperator {
|
||||
fn span(&self) -> Span {
|
||||
Span::empty()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,14 +67,15 @@ pub use self::ddl::{
|
|||
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
|
||||
CreateExtension, CreateFunction, CreateIndex, CreateOperator, CreateOperatorClass,
|
||||
CreateOperatorFamily, CreateTable, CreateTrigger, CreateView, Deduplicate, DeferrableInitial,
|
||||
DropBehavior, DropExtension, DropFunction, DropTrigger, GeneratedAs, GeneratedExpressionMode,
|
||||
IdentityParameters, IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind,
|
||||
IdentityPropertyOrder, IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck,
|
||||
NullsDistinctOption, OperatorArgTypes, OperatorClassItem, OperatorPurpose, Owner, Partition,
|
||||
ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity, TagsColumnOption,
|
||||
TriggerObjectKind, Truncate, UserDefinedTypeCompositeAttributeDef,
|
||||
UserDefinedTypeInternalLength, UserDefinedTypeRangeOption, UserDefinedTypeRepresentation,
|
||||
UserDefinedTypeSqlDefinitionOption, UserDefinedTypeStorage, ViewColumnDef,
|
||||
DropBehavior, DropExtension, DropFunction, DropOperator, DropOperatorSignature, DropTrigger,
|
||||
GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
|
||||
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
|
||||
IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, OperatorArgTypes,
|
||||
OperatorClassItem, OperatorPurpose, Owner, Partition, ProcedureParam, ReferentialAction,
|
||||
RenameTableNameKind, ReplicaIdentity, TagsColumnOption, TriggerObjectKind, Truncate,
|
||||
UserDefinedTypeCompositeAttributeDef, UserDefinedTypeInternalLength,
|
||||
UserDefinedTypeRangeOption, UserDefinedTypeRepresentation, UserDefinedTypeSqlDefinitionOption,
|
||||
UserDefinedTypeStorage, ViewColumnDef,
|
||||
};
|
||||
pub use self::dml::{Delete, Insert, Update};
|
||||
pub use self::operator::{BinaryOperator, UnaryOperator};
|
||||
|
|
@ -3573,6 +3574,12 @@ pub enum Statement {
|
|||
/// <https://www.postgresql.org/docs/current/sql-dropextension.html>
|
||||
DropExtension(DropExtension),
|
||||
/// ```sql
|
||||
/// DROP OPERATOR [ IF EXISTS ] name ( { left_type | NONE } , right_type ) [, ...] [ CASCADE | RESTRICT ]
|
||||
/// ```
|
||||
/// Note: this is a PostgreSQL-specific statement.
|
||||
/// <https://www.postgresql.org/docs/current/sql-dropoperator.html>
|
||||
DropOperator(DropOperator),
|
||||
/// ```sql
|
||||
/// FETCH
|
||||
/// ```
|
||||
/// Retrieve rows from a query using a cursor
|
||||
|
|
@ -4836,6 +4843,7 @@ impl fmt::Display for Statement {
|
|||
Statement::CreateIndex(create_index) => create_index.fmt(f),
|
||||
Statement::CreateExtension(create_extension) => write!(f, "{create_extension}"),
|
||||
Statement::DropExtension(drop_extension) => write!(f, "{drop_extension}"),
|
||||
Statement::DropOperator(drop_operator) => write!(f, "{drop_operator}"),
|
||||
Statement::CreateRole(create_role) => write!(f, "{create_role}"),
|
||||
Statement::CreateSecret {
|
||||
or_replace,
|
||||
|
|
|
|||
|
|
@ -375,6 +375,7 @@ impl Spanned for Statement {
|
|||
Statement::CreateRole(create_role) => create_role.span(),
|
||||
Statement::CreateExtension(create_extension) => create_extension.span(),
|
||||
Statement::DropExtension(drop_extension) => drop_extension.span(),
|
||||
Statement::DropOperator(drop_operator) => drop_operator.span(),
|
||||
Statement::CreateSecret { .. } => Span::empty(),
|
||||
Statement::CreateServer { .. } => Span::empty(),
|
||||
Statement::CreateConnector { .. } => Span::empty(),
|
||||
|
|
|
|||
|
|
@ -6767,9 +6767,11 @@ impl<'a> Parser<'a> {
|
|||
return self.parse_drop_trigger();
|
||||
} else if self.parse_keyword(Keyword::EXTENSION) {
|
||||
return self.parse_drop_extension();
|
||||
} else if self.parse_keyword(Keyword::OPERATOR) {
|
||||
return self.parse_drop_operator();
|
||||
} else {
|
||||
return self.expected(
|
||||
"CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW or USER after DROP",
|
||||
"CONNECTOR, DATABASE, EXTENSION, FUNCTION, INDEX, OPERATOR, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW or USER after DROP",
|
||||
self.peek_token(),
|
||||
);
|
||||
};
|
||||
|
|
@ -7525,6 +7527,46 @@ impl<'a> Parser<'a> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Parse a[Statement::DropOperator] statement.
|
||||
///
|
||||
pub fn parse_drop_operator(&mut self) -> Result<Statement, ParserError> {
|
||||
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
|
||||
let operators = self.parse_comma_separated(|p| p.parse_drop_operator_signature())?;
|
||||
let drop_behavior = self.parse_optional_drop_behavior();
|
||||
Ok(Statement::DropOperator(DropOperator {
|
||||
if_exists,
|
||||
operators,
|
||||
drop_behavior,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Parse an operator signature for a [Statement::DropOperator]
|
||||
/// Format: `name ( { left_type | NONE } , right_type )`
|
||||
fn parse_drop_operator_signature(&mut self) -> Result<DropOperatorSignature, ParserError> {
|
||||
let name = self.parse_operator_name()?;
|
||||
self.expect_token(&Token::LParen)?;
|
||||
|
||||
// Parse left operand type (or NONE for prefix operators)
|
||||
let left_type = if self.parse_keyword(Keyword::NONE) {
|
||||
None
|
||||
} else {
|
||||
Some(self.parse_data_type()?)
|
||||
};
|
||||
|
||||
self.expect_token(&Token::Comma)?;
|
||||
|
||||
// Parse right operand type (always required)
|
||||
let right_type = self.parse_data_type()?;
|
||||
|
||||
self.expect_token(&Token::RParen)?;
|
||||
|
||||
Ok(DropOperatorSignature {
|
||||
name,
|
||||
left_type,
|
||||
right_type,
|
||||
})
|
||||
}
|
||||
|
||||
//TODO: Implement parsing for Skewed
|
||||
pub fn parse_hive_distribution(&mut self) -> Result<HiveDistributionStyle, ParserError> {
|
||||
if self.parse_keywords(&[Keyword::PARTITIONED, Keyword::BY]) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
mod test_utils;
|
||||
|
||||
use helpers::attached_token::AttachedToken;
|
||||
use sqlparser::ast::{DataType, DropBehavior, DropOperator, DropOperatorSignature};
|
||||
use sqlparser::tokenizer::Span;
|
||||
use test_utils::*;
|
||||
|
||||
|
|
@ -6763,6 +6764,92 @@ fn parse_create_operator() {
|
|||
assert!(pg().parse_sql_statements("CREATE OPERATOR > ())").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_drop_operator() {
|
||||
// Test DROP OPERATOR with NONE for prefix operator
|
||||
let sql = "DROP OPERATOR ~ (NONE, BIT)";
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(sql),
|
||||
Statement::DropOperator(DropOperator {
|
||||
if_exists: false,
|
||||
operators: vec![DropOperatorSignature {
|
||||
name: ObjectName::from(vec![Ident::new("~")]),
|
||||
left_type: None,
|
||||
right_type: DataType::Bit(None),
|
||||
}],
|
||||
drop_behavior: None,
|
||||
})
|
||||
);
|
||||
|
||||
for if_exist in [true, false] {
|
||||
for cascading in [
|
||||
None,
|
||||
Some(DropBehavior::Cascade),
|
||||
Some(DropBehavior::Restrict),
|
||||
] {
|
||||
for op in &["<", ">", "<=", ">=", "<>", "||", "&&", "<<", ">>"] {
|
||||
let sql = format!(
|
||||
"DROP OPERATOR{} {op} (INTEGER, INTEGER){}",
|
||||
if if_exist { " IF EXISTS" } else { "" },
|
||||
match cascading {
|
||||
Some(cascading) => format!(" {cascading}"),
|
||||
None => String::new(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(&sql),
|
||||
Statement::DropOperator(DropOperator {
|
||||
if_exists: if_exist,
|
||||
operators: vec![DropOperatorSignature {
|
||||
name: ObjectName::from(vec![Ident::new(*op)]),
|
||||
left_type: Some(DataType::Integer(None)),
|
||||
right_type: DataType::Integer(None),
|
||||
}],
|
||||
drop_behavior: cascading,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test DROP OPERATOR with schema-qualified operator name
|
||||
let sql = "DROP OPERATOR myschema.@@ (TEXT, TEXT)";
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(sql),
|
||||
Statement::DropOperator(DropOperator {
|
||||
if_exists: false,
|
||||
operators: vec![DropOperatorSignature {
|
||||
name: ObjectName::from(vec![Ident::new("myschema"), Ident::new("@@")]),
|
||||
left_type: Some(DataType::Text),
|
||||
right_type: DataType::Text,
|
||||
}],
|
||||
drop_behavior: None,
|
||||
})
|
||||
);
|
||||
|
||||
// Test DROP OPERATOR with multiple operators, IF EXISTS and CASCADE
|
||||
let sql = "DROP OPERATOR IF EXISTS + (INTEGER, INTEGER), - (INTEGER, INTEGER) CASCADE";
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(sql),
|
||||
Statement::DropOperator(DropOperator {
|
||||
if_exists: true,
|
||||
operators: vec![
|
||||
DropOperatorSignature {
|
||||
name: ObjectName::from(vec![Ident::new("+")]),
|
||||
left_type: Some(DataType::Integer(None)),
|
||||
right_type: DataType::Integer(None),
|
||||
},
|
||||
DropOperatorSignature {
|
||||
name: ObjectName::from(vec![Ident::new("-")]),
|
||||
left_type: Some(DataType::Integer(None)),
|
||||
right_type: DataType::Integer(None),
|
||||
}
|
||||
],
|
||||
drop_behavior: Some(DropBehavior::Cascade),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_operator_family() {
|
||||
for index_method in &["btree", "hash", "gist", "gin", "spgist", "brin"] {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue