mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-12-23 11:12:51 +00:00
Add PostgreSQL Operator DDL Support (#2096)
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
Some checks failed
license / Release Audit Tool (RAT) (push) Has been cancelled
Rust / codestyle (push) Has been cancelled
Rust / lint (push) Has been cancelled
Rust / benchmark-lint (push) Has been cancelled
Rust / compile (push) Has been cancelled
Rust / docs (push) Has been cancelled
Rust / compile-no-std (push) Has been cancelled
Rust / test (beta) (push) Has been cancelled
Rust / test (nightly) (push) Has been cancelled
Rust / test (stable) (push) Has been cancelled
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
This commit is contained in:
parent
1198c1ad11
commit
1114d6a2bc
6 changed files with 987 additions and 53 deletions
238
src/ast/ddl.rs
238
src/ast/ddl.rs
|
|
@ -19,7 +19,13 @@
|
|||
//! (commonly referred to as Data Definition Language, or DDL)
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
use core::fmt::{self, Display, Write};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
|
|
@ -3952,3 +3958,233 @@ impl Spanned for DropFunction {
|
|||
Span::empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// CREATE OPERATOR statement
|
||||
/// See <https://www.postgresql.org/docs/current/sql-createoperator.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 CreateOperator {
|
||||
/// Operator name (can be schema-qualified)
|
||||
pub name: ObjectName,
|
||||
/// FUNCTION or PROCEDURE parameter (function name)
|
||||
pub function: ObjectName,
|
||||
/// Whether PROCEDURE keyword was used (vs FUNCTION)
|
||||
pub is_procedure: bool,
|
||||
/// LEFTARG parameter (left operand type)
|
||||
pub left_arg: Option<DataType>,
|
||||
/// RIGHTARG parameter (right operand type)
|
||||
pub right_arg: Option<DataType>,
|
||||
/// COMMUTATOR parameter (commutator operator)
|
||||
pub commutator: Option<ObjectName>,
|
||||
/// NEGATOR parameter (negator operator)
|
||||
pub negator: Option<ObjectName>,
|
||||
/// RESTRICT parameter (restriction selectivity function)
|
||||
pub restrict: Option<ObjectName>,
|
||||
/// JOIN parameter (join selectivity function)
|
||||
pub join: Option<ObjectName>,
|
||||
/// HASHES flag
|
||||
pub hashes: bool,
|
||||
/// MERGES flag
|
||||
pub merges: bool,
|
||||
}
|
||||
|
||||
/// CREATE OPERATOR FAMILY statement
|
||||
/// See <https://www.postgresql.org/docs/current/sql-createopfamily.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 CreateOperatorFamily {
|
||||
/// Operator family name (can be schema-qualified)
|
||||
pub name: ObjectName,
|
||||
/// Index method (btree, hash, gist, gin, etc.)
|
||||
pub using: Ident,
|
||||
}
|
||||
|
||||
/// CREATE OPERATOR CLASS statement
|
||||
/// See <https://www.postgresql.org/docs/current/sql-createopclass.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 CreateOperatorClass {
|
||||
/// Operator class name (can be schema-qualified)
|
||||
pub name: ObjectName,
|
||||
/// Whether this is the default operator class for the type
|
||||
pub default: bool,
|
||||
/// The data type
|
||||
pub for_type: DataType,
|
||||
/// Index method (btree, hash, gist, gin, etc.)
|
||||
pub using: Ident,
|
||||
/// Optional operator family name
|
||||
pub family: Option<ObjectName>,
|
||||
/// List of operator class items (operators, functions, storage)
|
||||
pub items: Vec<OperatorClassItem>,
|
||||
}
|
||||
|
||||
impl fmt::Display for CreateOperator {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "CREATE OPERATOR {} (", self.name)?;
|
||||
|
||||
let function_keyword = if self.is_procedure {
|
||||
"PROCEDURE"
|
||||
} else {
|
||||
"FUNCTION"
|
||||
};
|
||||
let mut params = vec![format!("{} = {}", function_keyword, self.function)];
|
||||
|
||||
if let Some(left_arg) = &self.left_arg {
|
||||
params.push(format!("LEFTARG = {}", left_arg));
|
||||
}
|
||||
if let Some(right_arg) = &self.right_arg {
|
||||
params.push(format!("RIGHTARG = {}", right_arg));
|
||||
}
|
||||
if let Some(commutator) = &self.commutator {
|
||||
params.push(format!("COMMUTATOR = {}", commutator));
|
||||
}
|
||||
if let Some(negator) = &self.negator {
|
||||
params.push(format!("NEGATOR = {}", negator));
|
||||
}
|
||||
if let Some(restrict) = &self.restrict {
|
||||
params.push(format!("RESTRICT = {}", restrict));
|
||||
}
|
||||
if let Some(join) = &self.join {
|
||||
params.push(format!("JOIN = {}", join));
|
||||
}
|
||||
if self.hashes {
|
||||
params.push("HASHES".to_string());
|
||||
}
|
||||
if self.merges {
|
||||
params.push("MERGES".to_string());
|
||||
}
|
||||
|
||||
write!(f, "{}", params.join(", "))?;
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CreateOperatorFamily {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"CREATE OPERATOR FAMILY {} USING {}",
|
||||
self.name, self.using
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CreateOperatorClass {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "CREATE OPERATOR CLASS {}", self.name)?;
|
||||
if self.default {
|
||||
write!(f, " DEFAULT")?;
|
||||
}
|
||||
write!(f, " FOR TYPE {} USING {}", self.for_type, self.using)?;
|
||||
if let Some(family) = &self.family {
|
||||
write!(f, " FAMILY {}", family)?;
|
||||
}
|
||||
write!(f, " AS {}", display_comma_separated(&self.items))
|
||||
}
|
||||
}
|
||||
|
||||
/// Operator argument types for CREATE OPERATOR CLASS
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub struct OperatorArgTypes {
|
||||
pub left: DataType,
|
||||
pub right: DataType,
|
||||
}
|
||||
|
||||
impl fmt::Display for OperatorArgTypes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}, {}", self.left, self.right)
|
||||
}
|
||||
}
|
||||
|
||||
/// An item in a CREATE OPERATOR CLASS 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 OperatorClassItem {
|
||||
/// OPERATOR clause
|
||||
Operator {
|
||||
strategy_number: u32,
|
||||
operator_name: ObjectName,
|
||||
/// Optional operator argument types
|
||||
op_types: Option<OperatorArgTypes>,
|
||||
/// FOR SEARCH or FOR ORDER BY
|
||||
purpose: Option<OperatorPurpose>,
|
||||
},
|
||||
/// FUNCTION clause
|
||||
Function {
|
||||
support_number: u32,
|
||||
/// 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 { storage_type: DataType },
|
||||
}
|
||||
|
||||
/// Purpose of an operator in an operator class
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub enum OperatorPurpose {
|
||||
ForSearch,
|
||||
ForOrderBy { sort_family: ObjectName },
|
||||
}
|
||||
|
||||
impl fmt::Display for OperatorClassItem {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
OperatorClassItem::Operator {
|
||||
strategy_number,
|
||||
operator_name,
|
||||
op_types,
|
||||
purpose,
|
||||
} => {
|
||||
write!(f, "OPERATOR {strategy_number} {operator_name}")?;
|
||||
if let Some(types) = op_types {
|
||||
write!(f, " ({types})")?;
|
||||
}
|
||||
if let Some(purpose) = purpose {
|
||||
write!(f, " {purpose}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
OperatorClassItem::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(())
|
||||
}
|
||||
OperatorClassItem::Storage { storage_type } => {
|
||||
write!(f, "STORAGE {storage_type}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OperatorPurpose {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
OperatorPurpose::ForSearch => write!(f, "FOR SEARCH"),
|
||||
OperatorPurpose::ForOrderBy { sort_family } => {
|
||||
write!(f, "FOR ORDER BY {sort_family}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,11 +65,12 @@ pub use self::ddl::{
|
|||
AlterTypeAddValuePosition, AlterTypeOperation, AlterTypeRename, AlterTypeRenameValue,
|
||||
ClusteredBy, ColumnDef, ColumnOption, ColumnOptionDef, ColumnOptions, ColumnPolicy,
|
||||
ColumnPolicyProperty, ConstraintCharacteristics, CreateConnector, CreateDomain,
|
||||
CreateExtension, CreateFunction, CreateIndex, CreateTable, CreateTrigger, CreateView,
|
||||
Deduplicate, DeferrableInitial, DropBehavior, DropExtension, DropFunction, DropTrigger,
|
||||
GeneratedAs, GeneratedExpressionMode, IdentityParameters, IdentityProperty,
|
||||
IdentityPropertyFormatKind, IdentityPropertyKind, IdentityPropertyOrder, IndexColumn,
|
||||
IndexOption, IndexType, KeyOrIndexDisplay, Msck, NullsDistinctOption, Owner, Partition,
|
||||
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,
|
||||
|
|
@ -3347,6 +3348,21 @@ pub enum Statement {
|
|||
/// See [Hive](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362034#LanguageManualDDL-CreateDataConnectorCreateConnector)
|
||||
CreateConnector(CreateConnector),
|
||||
/// ```sql
|
||||
/// CREATE OPERATOR
|
||||
/// ```
|
||||
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createoperator.html)
|
||||
CreateOperator(CreateOperator),
|
||||
/// ```sql
|
||||
/// CREATE OPERATOR FAMILY
|
||||
/// ```
|
||||
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createopfamily.html)
|
||||
CreateOperatorFamily(CreateOperatorFamily),
|
||||
/// ```sql
|
||||
/// CREATE OPERATOR CLASS
|
||||
/// ```
|
||||
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createopclass.html)
|
||||
CreateOperatorClass(CreateOperatorClass),
|
||||
/// ```sql
|
||||
/// ALTER TABLE
|
||||
/// ```
|
||||
AlterTable(AlterTable),
|
||||
|
|
@ -4901,6 +4917,11 @@ impl fmt::Display for Statement {
|
|||
Ok(())
|
||||
}
|
||||
Statement::CreateConnector(create_connector) => create_connector.fmt(f),
|
||||
Statement::CreateOperator(create_operator) => create_operator.fmt(f),
|
||||
Statement::CreateOperatorFamily(create_operator_family) => {
|
||||
create_operator_family.fmt(f)
|
||||
}
|
||||
Statement::CreateOperatorClass(create_operator_class) => create_operator_class.fmt(f),
|
||||
Statement::AlterTable(alter_table) => write!(f, "{alter_table}"),
|
||||
Statement::AlterIndex { name, operation } => {
|
||||
write!(f, "ALTER INDEX {name} {operation}")
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
|
||||
use crate::ast::{
|
||||
ddl::AlterSchema, query::SelectItemQualifiedWildcardKind, AlterSchemaOperation, AlterTable,
|
||||
ColumnOptions, CreateView, ExportData, Owner, TypedString,
|
||||
ColumnOptions, CreateOperator, CreateOperatorClass, CreateOperatorFamily, CreateView,
|
||||
ExportData, Owner, TypedString,
|
||||
};
|
||||
use core::iter;
|
||||
|
||||
|
|
@ -368,6 +369,11 @@ impl Spanned for Statement {
|
|||
Statement::CreateSecret { .. } => Span::empty(),
|
||||
Statement::CreateServer { .. } => Span::empty(),
|
||||
Statement::CreateConnector { .. } => Span::empty(),
|
||||
Statement::CreateOperator(create_operator) => create_operator.span(),
|
||||
Statement::CreateOperatorFamily(create_operator_family) => {
|
||||
create_operator_family.span()
|
||||
}
|
||||
Statement::CreateOperatorClass(create_operator_class) => create_operator_class.span(),
|
||||
Statement::AlterTable(alter_table) => alter_table.span(),
|
||||
Statement::AlterIndex { name, operation } => name.span().union(&operation.span()),
|
||||
Statement::AlterView {
|
||||
|
|
@ -2357,6 +2363,24 @@ impl Spanned for AlterTable {
|
|||
}
|
||||
}
|
||||
|
||||
impl Spanned for CreateOperator {
|
||||
fn span(&self) -> Span {
|
||||
Span::empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for CreateOperatorFamily {
|
||||
fn span(&self) -> Span {
|
||||
Span::empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for CreateOperatorClass {
|
||||
fn span(&self) -> Span {
|
||||
Span::empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::dialect::{Dialect, GenericDialect, SnowflakeDialect};
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ define_keywords!(
|
|||
CHECK,
|
||||
CHECKSUM,
|
||||
CIRCLE,
|
||||
CLASS,
|
||||
CLEANPATH,
|
||||
CLEAR,
|
||||
CLOB,
|
||||
|
|
@ -217,6 +218,7 @@ define_keywords!(
|
|||
COMMENT,
|
||||
COMMIT,
|
||||
COMMITTED,
|
||||
COMMUTATOR,
|
||||
COMPATIBLE,
|
||||
COMPRESSION,
|
||||
COMPUPDATE,
|
||||
|
|
@ -385,6 +387,7 @@ define_keywords!(
|
|||
FAIL,
|
||||
FAILOVER,
|
||||
FALSE,
|
||||
FAMILY,
|
||||
FETCH,
|
||||
FIELDS,
|
||||
FILE,
|
||||
|
|
@ -446,6 +449,7 @@ define_keywords!(
|
|||
GROUPS,
|
||||
GZIP,
|
||||
HASH,
|
||||
HASHES,
|
||||
HAVING,
|
||||
HEADER,
|
||||
HEAP,
|
||||
|
|
@ -539,7 +543,10 @@ define_keywords!(
|
|||
LATERAL,
|
||||
LEAD,
|
||||
LEADING,
|
||||
LEAKPROOF,
|
||||
LEAST,
|
||||
LEFT,
|
||||
LEFTARG,
|
||||
LEVEL,
|
||||
LIKE,
|
||||
LIKE_REGEX,
|
||||
|
|
@ -594,6 +601,7 @@ define_keywords!(
|
|||
MEDIUMTEXT,
|
||||
MEMBER,
|
||||
MERGE,
|
||||
MERGES,
|
||||
MESSAGE,
|
||||
METADATA,
|
||||
METHOD,
|
||||
|
|
@ -632,6 +640,7 @@ define_keywords!(
|
|||
NATURAL,
|
||||
NCHAR,
|
||||
NCLOB,
|
||||
NEGATOR,
|
||||
NEST,
|
||||
NESTED,
|
||||
NETWORK,
|
||||
|
|
@ -844,6 +853,7 @@ define_keywords!(
|
|||
RETURNS,
|
||||
REVOKE,
|
||||
RIGHT,
|
||||
RIGHTARG,
|
||||
RLIKE,
|
||||
RM,
|
||||
ROLE,
|
||||
|
|
|
|||
|
|
@ -4792,6 +4792,15 @@ impl<'a> Parser<'a> {
|
|||
self.parse_create_procedure(or_alter)
|
||||
} else if self.parse_keyword(Keyword::CONNECTOR) {
|
||||
self.parse_create_connector()
|
||||
} else if self.parse_keyword(Keyword::OPERATOR) {
|
||||
// Check if this is CREATE OPERATOR FAMILY or CREATE OPERATOR CLASS
|
||||
if self.parse_keyword(Keyword::FAMILY) {
|
||||
self.parse_create_operator_family()
|
||||
} else if self.parse_keyword(Keyword::CLASS) {
|
||||
self.parse_create_operator_class()
|
||||
} else {
|
||||
self.parse_create_operator()
|
||||
}
|
||||
} else if self.parse_keyword(Keyword::SERVER) {
|
||||
self.parse_pg_create_server()
|
||||
} else {
|
||||
|
|
@ -6436,6 +6445,281 @@ impl<'a> Parser<'a> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Parse an operator name, which can contain special characters like +, -, <, >, =
|
||||
/// that are tokenized as operator tokens rather than identifiers.
|
||||
/// This is used for PostgreSQL CREATE OPERATOR statements.
|
||||
///
|
||||
/// Examples: `+`, `myschema.+`, `pg_catalog.<=`
|
||||
fn parse_operator_name(&mut self) -> Result<ObjectName, ParserError> {
|
||||
let mut parts = vec![];
|
||||
loop {
|
||||
parts.push(ObjectNamePart::Identifier(Ident::new(
|
||||
self.next_token().to_string(),
|
||||
)));
|
||||
if !self.consume_token(&Token::Period) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(ObjectName(parts))
|
||||
}
|
||||
|
||||
/// Parse a [Statement::CreateOperator]
|
||||
///
|
||||
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-createoperator.html)
|
||||
pub fn parse_create_operator(&mut self) -> Result<Statement, ParserError> {
|
||||
let name = self.parse_operator_name()?;
|
||||
self.expect_token(&Token::LParen)?;
|
||||
|
||||
let mut function: Option<ObjectName> = None;
|
||||
let mut is_procedure = false;
|
||||
let mut left_arg: Option<DataType> = None;
|
||||
let mut right_arg: Option<DataType> = None;
|
||||
let mut commutator: Option<ObjectName> = None;
|
||||
let mut negator: Option<ObjectName> = None;
|
||||
let mut restrict: Option<ObjectName> = None;
|
||||
let mut join: Option<ObjectName> = None;
|
||||
let mut hashes = false;
|
||||
let mut merges = false;
|
||||
|
||||
loop {
|
||||
let keyword = self.expect_one_of_keywords(&[
|
||||
Keyword::FUNCTION,
|
||||
Keyword::PROCEDURE,
|
||||
Keyword::LEFTARG,
|
||||
Keyword::RIGHTARG,
|
||||
Keyword::COMMUTATOR,
|
||||
Keyword::NEGATOR,
|
||||
Keyword::RESTRICT,
|
||||
Keyword::JOIN,
|
||||
Keyword::HASHES,
|
||||
Keyword::MERGES,
|
||||
])?;
|
||||
|
||||
match keyword {
|
||||
Keyword::HASHES if !hashes => {
|
||||
hashes = true;
|
||||
}
|
||||
Keyword::MERGES if !merges => {
|
||||
merges = true;
|
||||
}
|
||||
Keyword::FUNCTION | Keyword::PROCEDURE if function.is_none() => {
|
||||
self.expect_token(&Token::Eq)?;
|
||||
function = Some(self.parse_object_name(false)?);
|
||||
is_procedure = keyword == Keyword::PROCEDURE;
|
||||
}
|
||||
Keyword::LEFTARG if left_arg.is_none() => {
|
||||
self.expect_token(&Token::Eq)?;
|
||||
left_arg = Some(self.parse_data_type()?);
|
||||
}
|
||||
Keyword::RIGHTARG if right_arg.is_none() => {
|
||||
self.expect_token(&Token::Eq)?;
|
||||
right_arg = Some(self.parse_data_type()?);
|
||||
}
|
||||
Keyword::COMMUTATOR if commutator.is_none() => {
|
||||
self.expect_token(&Token::Eq)?;
|
||||
if self.parse_keyword(Keyword::OPERATOR) {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
commutator = Some(self.parse_operator_name()?);
|
||||
self.expect_token(&Token::RParen)?;
|
||||
} else {
|
||||
commutator = Some(self.parse_operator_name()?);
|
||||
}
|
||||
}
|
||||
Keyword::NEGATOR if negator.is_none() => {
|
||||
self.expect_token(&Token::Eq)?;
|
||||
if self.parse_keyword(Keyword::OPERATOR) {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
negator = Some(self.parse_operator_name()?);
|
||||
self.expect_token(&Token::RParen)?;
|
||||
} else {
|
||||
negator = Some(self.parse_operator_name()?);
|
||||
}
|
||||
}
|
||||
Keyword::RESTRICT if restrict.is_none() => {
|
||||
self.expect_token(&Token::Eq)?;
|
||||
restrict = Some(self.parse_object_name(false)?);
|
||||
}
|
||||
Keyword::JOIN if join.is_none() => {
|
||||
self.expect_token(&Token::Eq)?;
|
||||
join = Some(self.parse_object_name(false)?);
|
||||
}
|
||||
_ => {
|
||||
return Err(ParserError::ParserError(format!(
|
||||
"Duplicate or unexpected keyword {:?} in CREATE OPERATOR",
|
||||
keyword
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
if !self.consume_token(&Token::Comma) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Expect closing parenthesis
|
||||
self.expect_token(&Token::RParen)?;
|
||||
|
||||
// FUNCTION is required
|
||||
let function = function.ok_or_else(|| {
|
||||
ParserError::ParserError("CREATE OPERATOR requires FUNCTION parameter".to_string())
|
||||
})?;
|
||||
|
||||
Ok(Statement::CreateOperator(CreateOperator {
|
||||
name,
|
||||
function,
|
||||
is_procedure,
|
||||
left_arg,
|
||||
right_arg,
|
||||
commutator,
|
||||
negator,
|
||||
restrict,
|
||||
join,
|
||||
hashes,
|
||||
merges,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Parse a [Statement::CreateOperatorFamily]
|
||||
///
|
||||
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-createopfamily.html)
|
||||
pub fn parse_create_operator_family(&mut self) -> Result<Statement, ParserError> {
|
||||
let name = self.parse_object_name(false)?;
|
||||
self.expect_keyword(Keyword::USING)?;
|
||||
let using = self.parse_identifier()?;
|
||||
|
||||
Ok(Statement::CreateOperatorFamily(CreateOperatorFamily {
|
||||
name,
|
||||
using,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Parse a [Statement::CreateOperatorClass]
|
||||
///
|
||||
/// [PostgreSQL Documentation](https://www.postgresql.org/docs/current/sql-createopclass.html)
|
||||
pub fn parse_create_operator_class(&mut self) -> Result<Statement, ParserError> {
|
||||
let name = self.parse_object_name(false)?;
|
||||
let default = self.parse_keyword(Keyword::DEFAULT);
|
||||
self.expect_keywords(&[Keyword::FOR, Keyword::TYPE])?;
|
||||
let for_type = self.parse_data_type()?;
|
||||
self.expect_keyword(Keyword::USING)?;
|
||||
let using = self.parse_identifier()?;
|
||||
|
||||
let family = if self.parse_keyword(Keyword::FAMILY) {
|
||||
Some(self.parse_object_name(false)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.expect_keyword(Keyword::AS)?;
|
||||
|
||||
let mut items = vec![];
|
||||
loop {
|
||||
if self.parse_keyword(Keyword::OPERATOR) {
|
||||
let strategy_number = self.parse_literal_uint()? as u32;
|
||||
let operator_name = self.parse_operator_name()?;
|
||||
|
||||
// Optional operator argument types
|
||||
let op_types = if self.consume_token(&Token::LParen) {
|
||||
let left = self.parse_data_type()?;
|
||||
self.expect_token(&Token::Comma)?;
|
||||
let right = self.parse_data_type()?;
|
||||
self.expect_token(&Token::RParen)?;
|
||||
Some(OperatorArgTypes { left, right })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
items.push(OperatorClassItem::Operator {
|
||||
strategy_number,
|
||||
operator_name,
|
||||
op_types,
|
||||
purpose,
|
||||
});
|
||||
} else if self.parse_keyword(Keyword::FUNCTION) {
|
||||
let support_number = self.parse_literal_uint()? as u32;
|
||||
|
||||
// Optional operator types
|
||||
let op_types =
|
||||
if self.consume_token(&Token::LParen) && self.peek_token() != Token::RParen {
|
||||
let mut types = vec![];
|
||||
loop {
|
||||
types.push(self.parse_data_type()?);
|
||||
if !self.consume_token(&Token::Comma) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
let mut types = vec![];
|
||||
loop {
|
||||
if self.peek_token() == Token::RParen {
|
||||
break;
|
||||
}
|
||||
types.push(self.parse_data_type()?);
|
||||
if !self.consume_token(&Token::Comma) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.expect_token(&Token::RParen)?;
|
||||
types
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
items.push(OperatorClassItem::Function {
|
||||
support_number,
|
||||
op_types,
|
||||
function_name,
|
||||
argument_types,
|
||||
});
|
||||
} else if self.parse_keyword(Keyword::STORAGE) {
|
||||
let storage_type = self.parse_data_type()?;
|
||||
items.push(OperatorClassItem::Storage { storage_type });
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for comma separator
|
||||
if !self.consume_token(&Token::Comma) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Statement::CreateOperatorClass(CreateOperatorClass {
|
||||
name,
|
||||
default,
|
||||
for_type,
|
||||
using,
|
||||
family,
|
||||
items,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn parse_drop(&mut self) -> Result<Statement, ParserError> {
|
||||
// MySQL dialect supports `TEMPORARY`
|
||||
let temporary = dialect_of!(self is MySqlDialect | GenericDialect | DuckDbDialect)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue