mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-12-23 11:12:51 +00:00
Added support for DROP OPERATOR CLASS syntax (#2109)
Some checks are pending
license / Release Audit Tool (RAT) (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 / codestyle (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
Some checks are pending
license / Release Audit Tool (RAT) (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 / codestyle (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:
parent
89938b9fcb
commit
367aa6e8d0
5 changed files with 160 additions and 13 deletions
|
|
@ -4288,3 +4288,40 @@ impl Spanned for DropOperatorFamily {
|
|||
Span::empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// `DROP OPERATOR CLASS` statement
|
||||
/// See <https://www.postgresql.org/docs/current/sql-dropopclass.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 DropOperatorClass {
|
||||
/// `IF EXISTS` clause
|
||||
pub if_exists: bool,
|
||||
/// One or more operator classes to drop
|
||||
pub names: Vec<ObjectName>,
|
||||
/// Index method (btree, hash, gist, gin, etc.)
|
||||
pub using: Ident,
|
||||
/// `CASCADE or RESTRICT`
|
||||
pub drop_behavior: Option<DropBehavior>,
|
||||
}
|
||||
|
||||
impl fmt::Display for DropOperatorClass {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DROP OPERATOR CLASS")?;
|
||||
if self.if_exists {
|
||||
write!(f, " IF EXISTS")?;
|
||||
}
|
||||
write!(f, " {}", display_comma_separated(&self.names))?;
|
||||
write!(f, " USING {}", self.using)?;
|
||||
if let Some(drop_behavior) = &self.drop_behavior {
|
||||
write!(f, " {}", drop_behavior)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for DropOperatorClass {
|
||||
fn span(&self) -> Span {
|
||||
Span::empty()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ pub use self::ddl::{
|
|||
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
|
||||
CreateExtension, CreateFunction, CreateIndex, CreateOperator, CreateOperatorClass,
|
||||
CreateOperatorFamily, CreateTable, CreateTrigger, CreateView, Deduplicate, DeferrableInitial,
|
||||
DropBehavior, DropExtension, DropFunction, DropOperator, DropOperatorFamily,
|
||||
DropBehavior, DropExtension, DropFunction, DropOperator, DropOperatorClass, DropOperatorFamily,
|
||||
DropOperatorSignature, DropTrigger, GeneratedAs, GeneratedExpressionMode, IdentityParameters,
|
||||
IdentityProperty, IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder,
|
||||
IndexColumn, IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption,
|
||||
|
|
@ -3586,6 +3586,12 @@ pub enum Statement {
|
|||
/// <https://www.postgresql.org/docs/current/sql-dropopfamily.html>
|
||||
DropOperatorFamily(DropOperatorFamily),
|
||||
/// ```sql
|
||||
/// DROP OPERATOR CLASS [ IF EXISTS ] name USING index_method [ CASCADE | RESTRICT ]
|
||||
/// ```
|
||||
/// Note: this is a PostgreSQL-specific statement.
|
||||
/// <https://www.postgresql.org/docs/current/sql-dropopclass.html>
|
||||
DropOperatorClass(DropOperatorClass),
|
||||
/// ```sql
|
||||
/// FETCH
|
||||
/// ```
|
||||
/// Retrieve rows from a query using a cursor
|
||||
|
|
@ -4853,6 +4859,9 @@ impl fmt::Display for Statement {
|
|||
Statement::DropOperatorFamily(drop_operator_family) => {
|
||||
write!(f, "{drop_operator_family}")
|
||||
}
|
||||
Statement::DropOperatorClass(drop_operator_class) => {
|
||||
write!(f, "{drop_operator_class}")
|
||||
}
|
||||
Statement::CreateRole(create_role) => write!(f, "{create_role}"),
|
||||
Statement::CreateSecret {
|
||||
or_replace,
|
||||
|
|
|
|||
|
|
@ -377,6 +377,7 @@ impl Spanned for Statement {
|
|||
Statement::DropExtension(drop_extension) => drop_extension.span(),
|
||||
Statement::DropOperator(drop_operator) => drop_operator.span(),
|
||||
Statement::DropOperatorFamily(drop_operator_family) => drop_operator_family.span(),
|
||||
Statement::DropOperatorClass(drop_operator_class) => drop_operator_class.span(),
|
||||
Statement::CreateSecret { .. } => Span::empty(),
|
||||
Statement::CreateServer { .. } => Span::empty(),
|
||||
Statement::CreateConnector { .. } => Span::empty(),
|
||||
|
|
|
|||
|
|
@ -6773,9 +6773,11 @@ impl<'a> Parser<'a> {
|
|||
} else if self.parse_keyword(Keyword::EXTENSION) {
|
||||
return self.parse_drop_extension();
|
||||
} else if self.parse_keyword(Keyword::OPERATOR) {
|
||||
// Check if this is DROP OPERATOR FAMILY
|
||||
// Check if this is DROP OPERATOR FAMILY or DROP OPERATOR CLASS
|
||||
return if self.parse_keyword(Keyword::FAMILY) {
|
||||
self.parse_drop_operator_family()
|
||||
} else if self.parse_keyword(Keyword::CLASS) {
|
||||
self.parse_drop_operator_class()
|
||||
} else {
|
||||
self.parse_drop_operator()
|
||||
};
|
||||
|
|
@ -7594,6 +7596,23 @@ impl<'a> Parser<'a> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Parse a [Statement::DropOperatorClass]
|
||||
///
|
||||
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-dropopclass.html)
|
||||
pub fn parse_drop_operator_class(&mut self) -> Result<Statement, ParserError> {
|
||||
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
|
||||
let names = self.parse_comma_separated(|p| p.parse_object_name(false))?;
|
||||
self.expect_keyword(Keyword::USING)?;
|
||||
let using = self.parse_identifier()?;
|
||||
let drop_behavior = self.parse_optional_drop_behavior();
|
||||
Ok(Statement::DropOperatorClass(DropOperatorClass {
|
||||
if_exists,
|
||||
names,
|
||||
using,
|
||||
drop_behavior,
|
||||
}))
|
||||
}
|
||||
|
||||
//TODO: Implement parsing for Skewed
|
||||
pub fn parse_hive_distribution(&mut self) -> Result<HiveDistributionStyle, ParserError> {
|
||||
if self.parse_keywords(&[Keyword::PARTITIONED, Keyword::BY]) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@
|
|||
mod test_utils;
|
||||
|
||||
use helpers::attached_token::AttachedToken;
|
||||
use sqlparser::ast::{DataType, DropBehavior, DropOperator, DropOperatorSignature};
|
||||
use sqlparser::ast::{
|
||||
DataType, DropBehavior, DropOperator, DropOperatorClass, DropOperatorSignature,
|
||||
};
|
||||
use sqlparser::tokenizer::Span;
|
||||
use test_utils::*;
|
||||
|
||||
|
|
@ -6908,6 +6910,14 @@ fn parse_drop_operator() {
|
|||
drop_behavior: Some(DropBehavior::Cascade),
|
||||
})
|
||||
);
|
||||
|
||||
// Test error: DROP OPERATOR with no operators
|
||||
let sql = "DROP OPERATOR (INTEGER, INTEGER)";
|
||||
assert!(pg().parse_sql_statements(sql).is_err());
|
||||
|
||||
// Test error: DROP OPERATOR IF EXISTS with no operators
|
||||
let sql = "DROP OPERATOR IF EXISTS (INTEGER, INTEGER)";
|
||||
assert!(pg().parse_sql_statements(sql).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -6963,13 +6973,84 @@ fn parse_drop_operator_family() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test error: DROP OPERATOR FAMILY with no names
|
||||
let sql = "DROP OPERATOR FAMILY USING btree";
|
||||
assert!(pg_and_generic().parse_sql_statements(sql).is_err());
|
||||
|
||||
// Test error: DROP OPERATOR FAMILY IF EXISTS with no names
|
||||
let sql = "DROP OPERATOR FAMILY IF EXISTS USING btree";
|
||||
assert!(pg_and_generic().parse_sql_statements(sql).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_drop_operator_class() {
|
||||
for if_exists in [true, false] {
|
||||
for drop_behavior in [
|
||||
None,
|
||||
Some(DropBehavior::Cascade),
|
||||
Some(DropBehavior::Restrict),
|
||||
] {
|
||||
for index_method in &["btree", "hash", "gist", "gin", "spgist", "brin"] {
|
||||
for (names_str, names_vec) in [
|
||||
(
|
||||
"widget_ops",
|
||||
vec![ObjectName::from(vec![Ident::new("widget_ops")])],
|
||||
),
|
||||
(
|
||||
"myschema.int4_ops",
|
||||
vec![ObjectName::from(vec![
|
||||
Ident::new("myschema"),
|
||||
Ident::new("int4_ops"),
|
||||
])],
|
||||
),
|
||||
(
|
||||
"ops1, ops2, schema.ops3",
|
||||
vec![
|
||||
ObjectName::from(vec![Ident::new("ops1")]),
|
||||
ObjectName::from(vec![Ident::new("ops2")]),
|
||||
ObjectName::from(vec![Ident::new("schema"), Ident::new("ops3")]),
|
||||
],
|
||||
),
|
||||
] {
|
||||
let sql = format!(
|
||||
"DROP OPERATOR CLASS{} {} USING {}{}",
|
||||
if if_exists { " IF EXISTS" } else { "" },
|
||||
names_str,
|
||||
index_method,
|
||||
match drop_behavior {
|
||||
Some(behavior) => format!(" {}", behavior),
|
||||
None => String::new(),
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
pg_and_generic().verified_stmt(&sql),
|
||||
Statement::DropOperatorClass(DropOperatorClass {
|
||||
if_exists,
|
||||
names: names_vec.clone(),
|
||||
using: Ident::new(*index_method),
|
||||
drop_behavior,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test error: DROP OPERATOR CLASS with no names
|
||||
let sql = "DROP OPERATOR CLASS USING btree";
|
||||
assert!(pg_and_generic().parse_sql_statements(sql).is_err());
|
||||
|
||||
// Test error: DROP OPERATOR CLASS IF EXISTS with no names
|
||||
let sql = "DROP OPERATOR CLASS IF EXISTS USING btree";
|
||||
assert!(pg_and_generic().parse_sql_statements(sql).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_operator_family() {
|
||||
for index_method in &["btree", "hash", "gist", "gin", "spgist", "brin"] {
|
||||
assert_eq!(
|
||||
pg().verified_stmt(&format!(
|
||||
pg_and_generic().verified_stmt(&format!(
|
||||
"CREATE OPERATOR FAMILY my_family USING {index_method}"
|
||||
)),
|
||||
Statement::CreateOperatorFamily(CreateOperatorFamily {
|
||||
|
|
@ -6978,7 +7059,7 @@ fn parse_create_operator_family() {
|
|||
})
|
||||
);
|
||||
assert_eq!(
|
||||
pg().verified_stmt(&format!(
|
||||
pg_and_generic().verified_stmt(&format!(
|
||||
"CREATE OPERATOR FAMILY myschema.test_family USING {index_method}"
|
||||
)),
|
||||
Statement::CreateOperatorFamily(CreateOperatorFamily {
|
||||
|
|
@ -7004,7 +7085,7 @@ fn parse_create_operator_class() {
|
|||
let sql = format!(
|
||||
"CREATE OPERATOR CLASS {class_name} {default_clause}FOR TYPE INT4 USING btree{family_clause} AS OPERATOR 1 <"
|
||||
);
|
||||
match pg().verified_stmt(&sql) {
|
||||
match pg_and_generic().verified_stmt(&sql) {
|
||||
Statement::CreateOperatorClass(CreateOperatorClass {
|
||||
name,
|
||||
default,
|
||||
|
|
@ -7034,7 +7115,7 @@ fn parse_create_operator_class() {
|
|||
}
|
||||
|
||||
// Test comprehensive operator class with all fields
|
||||
match pg().verified_stmt("CREATE OPERATOR CLASS CAS_btree_ops DEFAULT FOR TYPE CAS USING btree FAMILY CAS_btree_ops AS OPERATOR 1 <, OPERATOR 2 <=, OPERATOR 3 =, OPERATOR 4 >=, OPERATOR 5 >, FUNCTION 1 cas_cmp(CAS, CAS)") {
|
||||
match pg_and_generic().verified_stmt("CREATE OPERATOR CLASS CAS_btree_ops DEFAULT FOR TYPE CAS USING btree FAMILY CAS_btree_ops AS OPERATOR 1 <, OPERATOR 2 <=, OPERATOR 3 =, OPERATOR 4 >=, OPERATOR 5 >, FUNCTION 1 cas_cmp(CAS, CAS)") {
|
||||
Statement::CreateOperatorClass(CreateOperatorClass {
|
||||
name,
|
||||
default: true,
|
||||
|
|
@ -7053,7 +7134,7 @@ fn parse_create_operator_class() {
|
|||
}
|
||||
|
||||
// Test operator with argument types
|
||||
match pg().verified_stmt(
|
||||
match pg_and_generic().verified_stmt(
|
||||
"CREATE OPERATOR CLASS test_ops FOR TYPE INT4 USING gist AS OPERATOR 1 < (INT4, INT4)",
|
||||
) {
|
||||
Statement::CreateOperatorClass(CreateOperatorClass { ref items, .. }) => {
|
||||
|
|
@ -7078,7 +7159,7 @@ fn parse_create_operator_class() {
|
|||
}
|
||||
|
||||
// Test operator FOR SEARCH
|
||||
match pg().verified_stmt(
|
||||
match pg_and_generic().verified_stmt(
|
||||
"CREATE OPERATOR CLASS test_ops FOR TYPE INT4 USING gist AS OPERATOR 1 < FOR SEARCH",
|
||||
) {
|
||||
Statement::CreateOperatorClass(CreateOperatorClass { ref items, .. }) => {
|
||||
|
|
@ -7122,7 +7203,7 @@ fn parse_create_operator_class() {
|
|||
}
|
||||
|
||||
// Test function with operator class arg types
|
||||
match pg().verified_stmt("CREATE OPERATOR CLASS test_ops FOR TYPE INT4 USING btree AS FUNCTION 1 (INT4, INT4) btcmp(INT4, INT4)") {
|
||||
match pg_and_generic().verified_stmt("CREATE OPERATOR CLASS test_ops FOR TYPE INT4 USING btree AS FUNCTION 1 (INT4, INT4) btcmp(INT4, INT4)") {
|
||||
Statement::CreateOperatorClass(CreateOperatorClass {
|
||||
ref items,
|
||||
..
|
||||
|
|
@ -7145,11 +7226,11 @@ fn parse_create_operator_class() {
|
|||
}
|
||||
|
||||
// Test function with no arguments (empty parentheses normalizes to no parentheses)
|
||||
pg().one_statement_parses_to(
|
||||
pg_and_generic().one_statement_parses_to(
|
||||
"CREATE OPERATOR CLASS test_ops FOR TYPE INT4 USING btree AS FUNCTION 1 my_func()",
|
||||
"CREATE OPERATOR CLASS test_ops FOR TYPE INT4 USING btree AS FUNCTION 1 my_func",
|
||||
);
|
||||
match pg().verified_stmt(
|
||||
match pg_and_generic().verified_stmt(
|
||||
"CREATE OPERATOR CLASS test_ops FOR TYPE INT4 USING btree AS FUNCTION 1 my_func",
|
||||
) {
|
||||
Statement::CreateOperatorClass(CreateOperatorClass { ref items, .. }) => {
|
||||
|
|
@ -7174,7 +7255,7 @@ fn parse_create_operator_class() {
|
|||
}
|
||||
|
||||
// Test multiple items including STORAGE
|
||||
match pg().verified_stmt("CREATE OPERATOR CLASS gist_ops FOR TYPE geometry USING gist AS OPERATOR 1 <<, FUNCTION 1 gist_consistent(internal, geometry, INT4), STORAGE box") {
|
||||
match pg_and_generic().verified_stmt("CREATE OPERATOR CLASS gist_ops FOR TYPE geometry USING gist AS OPERATOR 1 <<, FUNCTION 1 gist_consistent(internal, geometry, INT4), STORAGE box") {
|
||||
Statement::CreateOperatorClass(CreateOperatorClass {
|
||||
ref items,
|
||||
..
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue