Skip to content

Commit 1114d6a

Browse files
Add PostgreSQL Operator DDL Support (#2096)
Co-authored-by: Ifeanyi Ubah <[email protected]>
1 parent 1198c1a commit 1114d6a

File tree

6 files changed

+987
-53
lines changed

6 files changed

+987
-53
lines changed

src/ast/ddl.rs

Lines changed: 237 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@
1919
//! (commonly referred to as Data Definition Language, or DDL)
2020
2121
#[cfg(not(feature = "std"))]
22-
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
22+
use alloc::{
23+
boxed::Box,
24+
format,
25+
string::{String, ToString},
26+
vec,
27+
vec::Vec,
28+
};
2329
use core::fmt::{self, Display, Write};
2430

2531
#[cfg(feature = "serde")]
@@ -3952,3 +3958,233 @@ impl Spanned for DropFunction {
39523958
Span::empty()
39533959
}
39543960
}
3961+
3962+
/// CREATE OPERATOR statement
3963+
/// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
3964+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3965+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3966+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3967+
pub struct CreateOperator {
3968+
/// Operator name (can be schema-qualified)
3969+
pub name: ObjectName,
3970+
/// FUNCTION or PROCEDURE parameter (function name)
3971+
pub function: ObjectName,
3972+
/// Whether PROCEDURE keyword was used (vs FUNCTION)
3973+
pub is_procedure: bool,
3974+
/// LEFTARG parameter (left operand type)
3975+
pub left_arg: Option<DataType>,
3976+
/// RIGHTARG parameter (right operand type)
3977+
pub right_arg: Option<DataType>,
3978+
/// COMMUTATOR parameter (commutator operator)
3979+
pub commutator: Option<ObjectName>,
3980+
/// NEGATOR parameter (negator operator)
3981+
pub negator: Option<ObjectName>,
3982+
/// RESTRICT parameter (restriction selectivity function)
3983+
pub restrict: Option<ObjectName>,
3984+
/// JOIN parameter (join selectivity function)
3985+
pub join: Option<ObjectName>,
3986+
/// HASHES flag
3987+
pub hashes: bool,
3988+
/// MERGES flag
3989+
pub merges: bool,
3990+
}
3991+
3992+
/// CREATE OPERATOR FAMILY statement
3993+
/// See <https://www.postgresql.org/docs/current/sql-createopfamily.html>
3994+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3995+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3996+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3997+
pub struct CreateOperatorFamily {
3998+
/// Operator family name (can be schema-qualified)
3999+
pub name: ObjectName,
4000+
/// Index method (btree, hash, gist, gin, etc.)
4001+
pub using: Ident,
4002+
}
4003+
4004+
/// CREATE OPERATOR CLASS statement
4005+
/// See <https://www.postgresql.org/docs/current/sql-createopclass.html>
4006+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4007+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4008+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4009+
pub struct CreateOperatorClass {
4010+
/// Operator class name (can be schema-qualified)
4011+
pub name: ObjectName,
4012+
/// Whether this is the default operator class for the type
4013+
pub default: bool,
4014+
/// The data type
4015+
pub for_type: DataType,
4016+
/// Index method (btree, hash, gist, gin, etc.)
4017+
pub using: Ident,
4018+
/// Optional operator family name
4019+
pub family: Option<ObjectName>,
4020+
/// List of operator class items (operators, functions, storage)
4021+
pub items: Vec<OperatorClassItem>,
4022+
}
4023+
4024+
impl fmt::Display for CreateOperator {
4025+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4026+
write!(f, "CREATE OPERATOR {} (", self.name)?;
4027+
4028+
let function_keyword = if self.is_procedure {
4029+
"PROCEDURE"
4030+
} else {
4031+
"FUNCTION"
4032+
};
4033+
let mut params = vec![format!("{} = {}", function_keyword, self.function)];
4034+
4035+
if let Some(left_arg) = &self.left_arg {
4036+
params.push(format!("LEFTARG = {}", left_arg));
4037+
}
4038+
if let Some(right_arg) = &self.right_arg {
4039+
params.push(format!("RIGHTARG = {}", right_arg));
4040+
}
4041+
if let Some(commutator) = &self.commutator {
4042+
params.push(format!("COMMUTATOR = {}", commutator));
4043+
}
4044+
if let Some(negator) = &self.negator {
4045+
params.push(format!("NEGATOR = {}", negator));
4046+
}
4047+
if let Some(restrict) = &self.restrict {
4048+
params.push(format!("RESTRICT = {}", restrict));
4049+
}
4050+
if let Some(join) = &self.join {
4051+
params.push(format!("JOIN = {}", join));
4052+
}
4053+
if self.hashes {
4054+
params.push("HASHES".to_string());
4055+
}
4056+
if self.merges {
4057+
params.push("MERGES".to_string());
4058+
}
4059+
4060+
write!(f, "{}", params.join(", "))?;
4061+
write!(f, ")")
4062+
}
4063+
}
4064+
4065+
impl fmt::Display for CreateOperatorFamily {
4066+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4067+
write!(
4068+
f,
4069+
"CREATE OPERATOR FAMILY {} USING {}",
4070+
self.name, self.using
4071+
)
4072+
}
4073+
}
4074+
4075+
impl fmt::Display for CreateOperatorClass {
4076+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4077+
write!(f, "CREATE OPERATOR CLASS {}", self.name)?;
4078+
if self.default {
4079+
write!(f, " DEFAULT")?;
4080+
}
4081+
write!(f, " FOR TYPE {} USING {}", self.for_type, self.using)?;
4082+
if let Some(family) = &self.family {
4083+
write!(f, " FAMILY {}", family)?;
4084+
}
4085+
write!(f, " AS {}", display_comma_separated(&self.items))
4086+
}
4087+
}
4088+
4089+
/// Operator argument types for CREATE OPERATOR CLASS
4090+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4091+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4092+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4093+
pub struct OperatorArgTypes {
4094+
pub left: DataType,
4095+
pub right: DataType,
4096+
}
4097+
4098+
impl fmt::Display for OperatorArgTypes {
4099+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4100+
write!(f, "{}, {}", self.left, self.right)
4101+
}
4102+
}
4103+
4104+
/// An item in a CREATE OPERATOR CLASS statement
4105+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4106+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4107+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4108+
pub enum OperatorClassItem {
4109+
/// OPERATOR clause
4110+
Operator {
4111+
strategy_number: u32,
4112+
operator_name: ObjectName,
4113+
/// Optional operator argument types
4114+
op_types: Option<OperatorArgTypes>,
4115+
/// FOR SEARCH or FOR ORDER BY
4116+
purpose: Option<OperatorPurpose>,
4117+
},
4118+
/// FUNCTION clause
4119+
Function {
4120+
support_number: u32,
4121+
/// Optional function argument types for the operator class
4122+
op_types: Option<Vec<DataType>>,
4123+
function_name: ObjectName,
4124+
/// Function argument types
4125+
argument_types: Vec<DataType>,
4126+
},
4127+
/// STORAGE clause
4128+
Storage { storage_type: DataType },
4129+
}
4130+
4131+
/// Purpose of an operator in an operator class
4132+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4133+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4134+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
4135+
pub enum OperatorPurpose {
4136+
ForSearch,
4137+
ForOrderBy { sort_family: ObjectName },
4138+
}
4139+
4140+
impl fmt::Display for OperatorClassItem {
4141+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4142+
match self {
4143+
OperatorClassItem::Operator {
4144+
strategy_number,
4145+
operator_name,
4146+
op_types,
4147+
purpose,
4148+
} => {
4149+
write!(f, "OPERATOR {strategy_number} {operator_name}")?;
4150+
if let Some(types) = op_types {
4151+
write!(f, " ({types})")?;
4152+
}
4153+
if let Some(purpose) = purpose {
4154+
write!(f, " {purpose}")?;
4155+
}
4156+
Ok(())
4157+
}
4158+
OperatorClassItem::Function {
4159+
support_number,
4160+
op_types,
4161+
function_name,
4162+
argument_types,
4163+
} => {
4164+
write!(f, "FUNCTION {support_number}")?;
4165+
if let Some(types) = op_types {
4166+
write!(f, " ({})", display_comma_separated(types))?;
4167+
}
4168+
write!(f, " {function_name}")?;
4169+
if !argument_types.is_empty() {
4170+
write!(f, "({})", display_comma_separated(argument_types))?;
4171+
}
4172+
Ok(())
4173+
}
4174+
OperatorClassItem::Storage { storage_type } => {
4175+
write!(f, "STORAGE {storage_type}")
4176+
}
4177+
}
4178+
}
4179+
}
4180+
4181+
impl fmt::Display for OperatorPurpose {
4182+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4183+
match self {
4184+
OperatorPurpose::ForSearch => write!(f, "FOR SEARCH"),
4185+
OperatorPurpose::ForOrderBy { sort_family } => {
4186+
write!(f, "FOR ORDER BY {sort_family}")
4187+
}
4188+
}
4189+
}
4190+
}

src/ast/mod.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,12 @@ pub use self::ddl::{
6565
AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
6666
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy,
6767
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
68-
CreateExtension, CreateFunction, CreateIndex, CreateTable, CreateTrigger, CreateView,
69-
Deduplicate, DeferrableInitial, DropBehavior, DropExtension, DropFunction, DropTrigger,
70-
GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
71-
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
72-
IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, Owner, Partition,
68+
CreateExtension, CreateFunction, CreateIndex, CreateOperator, CreateOperatorClass,
69+
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,
7374
ProcedureParam, ReferentialAction, RenameTableNameKind, ReplicaIdentity, TagsColumnOption,
7475
TriggerObjectKind, Truncate, UserDefinedTypeCompositeAttributeDef,
7576
UserDefinedTypeInternalLength, UserDefinedTypeRangeOption, UserDefinedTypeRepresentation,
@@ -3347,6 +3348,21 @@ pub enum Statement {
33473348
/// See [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
33483349
CreateConnector(CreateConnector),
33493350
/// ```sql
3351+
/// CREATE OPERATOR
3352+
/// ```
3353+
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createoperator.html)
3354+
CreateOperator(CreateOperator),
3355+
/// ```sql
3356+
/// CREATE OPERATOR FAMILY
3357+
/// ```
3358+
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createopfamily.html)
3359+
CreateOperatorFamily(CreateOperatorFamily),
3360+
/// ```sql
3361+
/// CREATE OPERATOR CLASS
3362+
/// ```
3363+
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createopclass.html)
3364+
CreateOperatorClass(CreateOperatorClass),
3365+
/// ```sql
33503366
/// ALTER TABLE
33513367
/// ```
33523368
AlterTable(AlterTable),
@@ -4901,6 +4917,11 @@ impl fmt::Display for Statement {
49014917
Ok(())
49024918
}
49034919
Statement::CreateConnector(create_connector) => create_connector.fmt(f),
4920+
Statement::CreateOperator(create_operator) => create_operator.fmt(f),
4921+
Statement::CreateOperatorFamily(create_operator_family) => {
4922+
create_operator_family.fmt(f)
4923+
}
4924+
Statement::CreateOperatorClass(create_operator_class) => create_operator_class.fmt(f),
49044925
Statement::AlterTable(alter_table) => write!(f, "{alter_table}"),
49054926
Statement::AlterIndex { name, operation } => {
49064927
write!(f, "ALTER INDEX {name} {operation}")

src/ast/spans.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717

1818
use crate::ast::{
1919
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
20-
ColumnOptions, CreateView, ExportData, Owner, TypedString,
20+
ColumnOptions, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreateView,
21+
ExportData, Owner, TypedString,
2122
};
2223
use core::iter;
2324

@@ -368,6 +369,11 @@ impl Spanned for Statement {
368369
Statement::CreateSecret { .. } => Span::empty(),
369370
Statement::CreateServer { .. } => Span::empty(),
370371
Statement::CreateConnector { .. } => Span::empty(),
372+
Statement::CreateOperator(create_operator) => create_operator.span(),
373+
Statement::CreateOperatorFamily(create_operator_family) => {
374+
create_operator_family.span()
375+
}
376+
Statement::CreateOperatorClass(create_operator_class) => create_operator_class.span(),
371377
Statement::AlterTable(alter_table) => alter_table.span(),
372378
Statement::AlterIndex { name, operation } => name.span().union(&operation.span()),
373379
Statement::AlterView {
@@ -2357,6 +2363,24 @@ impl Spanned for AlterTable {
23572363
}
23582364
}
23592365

2366+
impl Spanned for CreateOperator {
2367+
fn span(&self) -> Span {
2368+
Span::empty()
2369+
}
2370+
}
2371+
2372+
impl Spanned for CreateOperatorFamily {
2373+
fn span(&self) -> Span {
2374+
Span::empty()
2375+
}
2376+
}
2377+
2378+
impl Spanned for CreateOperatorClass {
2379+
fn span(&self) -> Span {
2380+
Span::empty()
2381+
}
2382+
}
2383+
23602384
#[cfg(test)]
23612385
pub mod tests {
23622386
use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect};

0 commit comments

Comments
 (0)