From 7ccce5a05ad68a06b8ecde468ca3372d7e7fe365 Mon Sep 17 00:00:00 2001 From: zidaye <1025632192@qq.com> Date: Thu, 8 Dec 2022 12:07:53 +0800 Subject: [PATCH 1/5] drop function --- src/ast/mod.rs | 49 +++++++++++++++-- src/parser.rs | 43 +++++++++++++-- tests/sqlparser_postgres.rs | 101 ++++++++++++++++++++++++++++++++++-- 3 files changed, 180 insertions(+), 13 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 7f3d15438..8a44650dc 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1247,6 +1247,14 @@ pub enum Statement { /// deleted along with the dropped table purge: bool, }, + /// DROP Function + DropFunction { + if_exists: bool, + /// One or more function to drop + func_desc: Vec, + cascade: bool, + restrict: bool, + }, /// DECLARE - Declaring Cursor Variables /// /// Note: this is a PostgreSQL-specific statement, @@ -1411,7 +1419,7 @@ pub enum Statement { or_replace: bool, temporary: bool, name: ObjectName, - args: Option>, + args: Option>, return_type: Option, /// Optional parameters. params: CreateFunctionBody, @@ -2263,6 +2271,19 @@ impl fmt::Display for Statement { if *restrict { " RESTRICT" } else { "" }, if *purge { " PURGE" } else { "" } ), + Statement::DropFunction { + if_exists, + func_desc, + cascade, + restrict, + } => write!( + f, + "DROP FUNCTION{} {}{}{}", + if *if_exists { " IF EXISTS" } else { "" }, + display_comma_separated(func_desc), + if *cascade { " CASCADE" } else { "" }, + if *restrict { " RESTRICT" } else { "" } + ), Statement::Discard { object_type } => { write!(f, "DISCARD {object_type}", object_type = object_type)?; Ok(()) @@ -3691,17 +3712,35 @@ impl fmt::Display for ContextModifier { } } -/// Function argument in CREATE FUNCTION. +/// Function describe in DROP FUNCTION. +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct DropFunctionDesc { + pub name: ObjectName, + pub args: Option>, +} + +impl fmt::Display for DropFunctionDesc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name)?; + if let Some(args) = &self.args { + write!(f, "({})", display_comma_separated(args))?; + } + Ok(()) + } +} + +/// Function argument in CREATE OR DROP FUNCTION. #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct CreateFunctionArg { +pub struct OperateFunctionArg { pub mode: Option, pub name: Option, pub data_type: DataType, pub default_expr: Option, } -impl CreateFunctionArg { +impl OperateFunctionArg { /// Returns an unnamed argument. pub fn unnamed(data_type: DataType) -> Self { Self { @@ -3723,7 +3762,7 @@ impl CreateFunctionArg { } } -impl fmt::Display for CreateFunctionArg { +impl fmt::Display for OperateFunctionArg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(mode) = &self.mode { write!(f, "{} ", mode)?; diff --git a/src/parser.rs b/src/parser.rs index 87fb674aa..f5f40796b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2328,7 +2328,7 @@ impl<'a> Parser<'a> { } else if dialect_of!(self is PostgreSqlDialect) { let name = self.parse_object_name()?; self.expect_token(&Token::LParen)?; - let args = self.parse_comma_separated(Parser::parse_create_function_arg)?; + let args = self.parse_comma_separated(Parser::parse_function_arg)?; self.expect_token(&Token::RParen)?; let return_type = if self.parse_keyword(Keyword::RETURNS) { @@ -2353,7 +2353,7 @@ impl<'a> Parser<'a> { } } - fn parse_create_function_arg(&mut self) -> Result { + fn parse_function_arg(&mut self) -> Result { let mode = if self.parse_keyword(Keyword::IN) { Some(ArgMode::In) } else if self.parse_keyword(Keyword::OUT) { @@ -2379,7 +2379,7 @@ impl<'a> Parser<'a> { } else { None }; - Ok(CreateFunctionArg { + Ok(OperateFunctionArg { mode, name, data_type, @@ -2752,9 +2752,11 @@ impl<'a> Parser<'a> { ObjectType::Schema } else if self.parse_keyword(Keyword::SEQUENCE) { ObjectType::Sequence + } else if self.parse_keyword(Keyword::FUNCTION) { + return self.parse_drop_function(); } else { return self.expected( - "TABLE, VIEW, INDEX, ROLE, SCHEMA, or SEQUENCE after DROP", + "TABLE, VIEW, INDEX, ROLE, SCHEMA, FUNCTION or SEQUENCE after DROP", self.peek_token(), ); }; @@ -2781,6 +2783,39 @@ impl<'a> Parser<'a> { }) } + /// DROP FUNCTION [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] [, ...] + /// [ CASCADE | RESTRICT ] + fn parse_drop_function(&mut self) -> Result { + let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); + let func_desc = self.parse_comma_separated(Parser::parse_drop_function_desc)?; + let cascade = self.parse_keyword(Keyword::CASCADE); + let restrict = self.parse_keyword(Keyword::RESTRICT); + Ok(Statement::DropFunction { + if_exists, + func_desc, + cascade, + restrict, + }) + } + + fn parse_drop_function_desc(&mut self) -> Result { + let name = self.parse_object_name()?; + + let args = if self.consume_token(&Token::LParen) { + if self.consume_token(&Token::RParen) { + None + } else { + let args = self.parse_comma_separated(Parser::parse_function_arg)?; + self.expect_token(&Token::RParen)?; + Some(args) + } + } else { + None + }; + + Ok(DropFunctionDesc { name, args }) + } + /// DECLARE name [ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ] // CURSOR [ { WITH | WITHOUT } HOLD ] FOR query pub fn parse_declare(&mut self) -> Result { diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index fac98b8ef..240365ef4 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -2250,8 +2250,8 @@ fn parse_create_function() { temporary: false, name: ObjectName(vec![Ident::new("add")]), args: Some(vec![ - CreateFunctionArg::unnamed(DataType::Integer(None)), - CreateFunctionArg::unnamed(DataType::Integer(None)), + OperateFunctionArg::unnamed(DataType::Integer(None)), + OperateFunctionArg::unnamed(DataType::Integer(None)), ]), return_type: Some(DataType::Integer(None)), params: CreateFunctionBody { @@ -2271,8 +2271,8 @@ fn parse_create_function() { temporary: false, name: ObjectName(vec![Ident::new("add")]), args: Some(vec![ - CreateFunctionArg::with_name("a", DataType::Integer(None)), - CreateFunctionArg { + OperateFunctionArg::with_name("a", DataType::Integer(None)), + OperateFunctionArg { mode: Some(ArgMode::In), name: Some("b".into()), data_type: DataType::Integer(None), @@ -2293,3 +2293,96 @@ fn parse_create_function() { } ); } + +#[test] +fn parse_drop_function() { + let sql = "DROP FUNCTION IF EXISTS test_func"; + assert_eq!( + pg().verified_stmt(sql), + Statement::DropFunction { + if_exists: true, + func_desc: vec![DropFunctionDesc { + name: ObjectName(vec![Ident { + value: "test_func".to_string(), + quote_style: None + }]), + args: None + }], + cascade: false, + restrict: false + } + ); + + let sql = "DROP FUNCTION IF EXISTS test_func(a INTEGER, IN b INTEGER = 1)"; + assert_eq!( + pg().verified_stmt(sql), + Statement::DropFunction { + if_exists: true, + func_desc: vec![DropFunctionDesc { + name: ObjectName(vec![Ident { + value: "test_func".to_string(), + quote_style: None + }]), + args: Some(vec![ + OperateFunctionArg::with_name("a", DataType::Integer(None)), + OperateFunctionArg { + mode: Some(ArgMode::In), + name: Some("b".into()), + data_type: DataType::Integer(None), + default_expr: Some(Expr::Value(Value::Number("1".parse().unwrap(), false))), + } + ]), + }], + cascade: false, + restrict: false + } + ); + + let sql = "DROP FUNCTION IF EXISTS test_func1(a INTEGER, IN b INTEGER = 1), test_func2(a VARCHAR, IN b INTEGER = 1)"; + assert_eq!( + pg().verified_stmt(sql), + Statement::DropFunction { + if_exists: true, + func_desc: vec![ + DropFunctionDesc { + name: ObjectName(vec![Ident { + value: "test_func1".to_string(), + quote_style: None + }]), + args: Some(vec![ + OperateFunctionArg::with_name("a", DataType::Integer(None)), + OperateFunctionArg { + mode: Some(ArgMode::In), + name: Some("b".into()), + data_type: DataType::Integer(None), + default_expr: Some(Expr::Value(Value::Number( + "1".parse().unwrap(), + false + ))), + } + ]), + }, + DropFunctionDesc { + name: ObjectName(vec![Ident { + value: "test_func2".to_string(), + quote_style: None + }]), + args: Some(vec![ + OperateFunctionArg::with_name("a", DataType::Varchar(None)), + OperateFunctionArg { + mode: Some(ArgMode::In), + name: Some("b".into()), + data_type: DataType::Integer(None), + default_expr: Some(Expr::Value(Value::Number( + "1".parse().unwrap(), + false + ))), + } + ]), + } + ], + cascade: false, + restrict: false + } + ); +} From 0c06cb06898bec0253e38e3073d188a032d4b32a Mon Sep 17 00:00:00 2001 From: zidaye <1025632192@qq.com> Date: Sat, 10 Dec 2022 12:25:15 +0800 Subject: [PATCH 2/5] update and to Option --- src/ast/mod.rs | 44 +++++++++++++++++++++++++++---------- src/parser.rs | 10 +++++---- tests/sqlparser_postgres.rs | 9 +++----- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 8a44650dc..752dddd43 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1252,8 +1252,8 @@ pub enum Statement { if_exists: bool, /// One or more function to drop func_desc: Vec, - cascade: bool, - restrict: bool, + /// `CASCADE` or `RESTRICT` + option: Option, }, /// DECLARE - Declaring Cursor Variables /// @@ -2274,16 +2274,19 @@ impl fmt::Display for Statement { Statement::DropFunction { if_exists, func_desc, - cascade, - restrict, - } => write!( - f, - "DROP FUNCTION{} {}{}{}", - if *if_exists { " IF EXISTS" } else { "" }, - display_comma_separated(func_desc), - if *cascade { " CASCADE" } else { "" }, - if *restrict { " RESTRICT" } else { "" } - ), + option, + } => { + write!( + f, + "DROP FUNCTION{} {}", + if *if_exists { " IF EXISTS" } else { "" }, + display_comma_separated(func_desc), + )?; + if let Some(op) = option { + write!(f, " {}", op)?; + } + Ok(()) + } Statement::Discard { object_type } => { write!(f, "DISCARD {object_type}", object_type = object_type)?; Ok(()) @@ -3712,6 +3715,23 @@ impl fmt::Display for ContextModifier { } } +/// Function describe in DROP FUNCTION. +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum DropFunctionOption { + Restrict, + Cascade, +} + +impl fmt::Display for DropFunctionOption { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + DropFunctionOption::Restrict => write!(f, "RESTRICT "), + DropFunctionOption::Cascade => write!(f, "CASCADE "), + } + } +} + /// Function describe in DROP FUNCTION. #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/src/parser.rs b/src/parser.rs index f5f40796b..933d9c564 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2788,13 +2788,15 @@ impl<'a> Parser<'a> { fn parse_drop_function(&mut self) -> Result { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let func_desc = self.parse_comma_separated(Parser::parse_drop_function_desc)?; - let cascade = self.parse_keyword(Keyword::CASCADE); - let restrict = self.parse_keyword(Keyword::RESTRICT); + let option = match self.parse_one_of_keywords(&[Keyword::CASCADE, Keyword::RESTRICT]) { + Some(Keyword::CASCADE) => Some(DropFunctionOption::Cascade), + Some(Keyword::RESTRICT) => Some(DropFunctionOption::Restrict), + _ => None, + }; Ok(Statement::DropFunction { if_exists, func_desc, - cascade, - restrict, + option, }) } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 240365ef4..67a17c449 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -2308,8 +2308,7 @@ fn parse_drop_function() { }]), args: None }], - cascade: false, - restrict: false + option: None } ); @@ -2333,8 +2332,7 @@ fn parse_drop_function() { } ]), }], - cascade: false, - restrict: false + option: None } ); @@ -2381,8 +2379,7 @@ fn parse_drop_function() { ]), } ], - cascade: false, - restrict: false + option: None } ); } From d1bddce54e502f5ab47d86ec676ad5b1eb9b0db6 Mon Sep 17 00:00:00 2001 From: zidaye <1025632192@qq.com> Date: Tue, 20 Dec 2022 15:11:19 +0800 Subject: [PATCH 3/5] fix review --- src/ast/mod.rs | 2 +- src/parser.rs | 4 ++-- tests/sqlparser_postgres.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index ada3daf46..6003cb1d4 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1274,7 +1274,7 @@ pub enum Statement { /// One or more function to drop func_desc: Vec, /// `CASCADE` or `RESTRICT` - option: Option, + option: Option, }, /// DECLARE - Declaring Cursor Variables /// diff --git a/src/parser.rs b/src/parser.rs index 3784cf76c..0621c1ffd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2804,8 +2804,8 @@ impl<'a> Parser<'a> { let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let func_desc = self.parse_comma_separated(Parser::parse_drop_function_desc)?; let option = match self.parse_one_of_keywords(&[Keyword::CASCADE, Keyword::RESTRICT]) { - Some(Keyword::CASCADE) => Some(DropFunctionOption::Cascade), - Some(Keyword::RESTRICT) => Some(DropFunctionOption::Restrict), + Some(Keyword::CASCADE) => Some(ReferentialAction::Cascade), + Some(Keyword::RESTRICT) => Some(ReferentialAction::Restrict), _ => None, }; Ok(Statement::DropFunction { diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 9eb743031..6e190a01b 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -2400,7 +2400,7 @@ fn parse_create_function() { or_replace: true, temporary: false, name: ObjectName(vec![Ident::new("increment")]), - args: Some(vec![CreateFunctionArg::with_name( + args: Some(vec![OperateFunctionArg::with_name( "i", DataType::Integer(None) )]), From cb1ec9317711f3b6ed02699362aee8c938f764e2 Mon Sep 17 00:00:00 2001 From: zidaye <1025632192@qq.com> Date: Thu, 22 Dec 2022 17:50:04 +0800 Subject: [PATCH 4/5] update --- src/parser.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 0621c1ffd..7607e5ad0 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2343,7 +2343,13 @@ impl<'a> Parser<'a> { } else if dialect_of!(self is PostgreSqlDialect) { let name = self.parse_object_name()?; self.expect_token(&Token::LParen)?; - let args = self.parse_comma_separated(Parser::parse_function_arg)?; + let args = if self.consume_token(&Token::RParen) { + self.prev_token(); + None + }else { + Some(self.parse_comma_separated(Parser::parse_function_arg)?) + }; + self.expect_token(&Token::RParen)?; let return_type = if self.parse_keyword(Keyword::RETURNS) { @@ -2358,7 +2364,7 @@ impl<'a> Parser<'a> { or_replace, temporary, name, - args: Some(args), + args, return_type, params, }) From 19fcca0e3fd8ef083db214b79aea26c3f31d9e76 Mon Sep 17 00:00:00 2001 From: zidaye <1025632192@qq.com> Date: Fri, 23 Dec 2022 16:17:17 +0800 Subject: [PATCH 5/5] fmt --- src/parser.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 7607e5ad0..21ab6d2c6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2346,10 +2346,10 @@ impl<'a> Parser<'a> { let args = if self.consume_token(&Token::RParen) { self.prev_token(); None - }else { + } else { Some(self.parse_comma_separated(Parser::parse_function_arg)?) }; - + self.expect_token(&Token::RParen)?; let return_type = if self.parse_keyword(Keyword::RETURNS) {