From 54a29e872d2f752daa48ce0ede5d48ea682ef0cc Mon Sep 17 00:00:00 2001 From: Dmitry Patsura Date: Thu, 11 Aug 2022 15:30:06 +0300 Subject: [PATCH] feat: Parse special keywords as functions (current_user, user, etc) (#561) * feat: Parse special keywors as functions (current_user, user, etc) * explain special field --- src/ast/mod.rs | 27 +++++++++++++------- src/parser.rs | 16 ++++++++++++ tests/sqlparser_common.rs | 19 ++++++++++++-- tests/sqlparser_mysql.rs | 15 +++++++---- tests/sqlparser_postgres.rs | 47 +++++++++++++++++++++++++++++++++++ tests/sqpparser_clickhouse.rs | 4 ++- 6 files changed, 111 insertions(+), 17 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index eeead0de0..5e8296f88 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -2321,20 +2321,29 @@ pub struct Function { pub over: Option, // aggregate functions may specify eg `COUNT(DISTINCT x)` pub distinct: bool, + // Some functions must be called without trailing parentheses, for example Postgres + // do it for current_catalog, current_schema, etc. This flags is used for formatting. + pub special: bool, } impl fmt::Display for Function { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{}({}{})", - self.name, - if self.distinct { "DISTINCT " } else { "" }, - display_comma_separated(&self.args), - )?; - if let Some(o) = &self.over { - write!(f, " OVER ({})", o)?; + if self.special { + write!(f, "{}", self.name)?; + } else { + write!( + f, + "{}({}{})", + self.name, + if self.distinct { "DISTINCT " } else { "" }, + display_comma_separated(&self.args), + )?; + + if let Some(o) = &self.over { + write!(f, " OVER ({})", o)?; + } } + Ok(()) } } diff --git a/src/parser.rs b/src/parser.rs index 412d3eb0a..11f14ecf4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -421,6 +421,20 @@ impl<'a> Parser<'a> { self.prev_token(); Ok(Expr::Value(self.parse_value()?)) } + Keyword::CURRENT_CATALOG + | Keyword::CURRENT_USER + | Keyword::SESSION_USER + | Keyword::USER + if dialect_of!(self is PostgreSqlDialect | GenericDialect) => + { + Ok(Expr::Function(Function { + name: ObjectName(vec![w.to_ident()]), + args: vec![], + over: None, + distinct: false, + special: true, + })) + } Keyword::CURRENT_TIMESTAMP | Keyword::CURRENT_TIME | Keyword::CURRENT_DATE => { self.parse_time_functions(ObjectName(vec![w.to_ident()])) } @@ -598,6 +612,7 @@ impl<'a> Parser<'a> { args, over, distinct, + special: false, })) } @@ -612,6 +627,7 @@ impl<'a> Parser<'a> { args, over: None, distinct: false, + special: false, })) } diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 0f818e5fc..27b8879bf 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -572,6 +572,7 @@ fn parse_select_count_wildcard() { args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)], over: None, distinct: false, + special: false, }), expr_from_projection(only(&select.projection)) ); @@ -590,6 +591,7 @@ fn parse_select_count_distinct() { }))], over: None, distinct: true, + special: false, }), expr_from_projection(only(&select.projection)) ); @@ -1414,6 +1416,7 @@ fn parse_select_having() { args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)], over: None, distinct: false, + special: false, })), op: BinaryOperator::Gt, right: Box::new(Expr::Value(number("1"))) @@ -1445,7 +1448,8 @@ fn parse_select_qualify() { }], window_frame: None }), - distinct: false + distinct: false, + special: false })), op: BinaryOperator::Eq, right: Box::new(Expr::Value(number("1"))) @@ -2532,6 +2536,7 @@ fn parse_scalar_function_in_projection() { ))], over: None, distinct: false, + special: false, }), expr_from_projection(only(&select.projection)) ); @@ -2610,6 +2615,7 @@ fn parse_named_argument_function() { ], over: None, distinct: false, + special: false, }), expr_from_projection(only(&select.projection)) ); @@ -2643,6 +2649,7 @@ fn parse_window_functions() { window_frame: None, }), distinct: false, + special: false, }), expr_from_projection(&select.projection[0]) ); @@ -2906,7 +2913,8 @@ fn parse_at_timezone() { }]), args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(zero.clone()))], over: None, - distinct: false + distinct: false, + special: false, })), time_zone: "UTC-06:00".to_string() }, @@ -2932,6 +2940,7 @@ fn parse_at_timezone() { args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(zero,),),], over: None, distinct: false, + special: false },)), time_zone: "UTC-06:00".to_string(), },),), @@ -2941,6 +2950,7 @@ fn parse_at_timezone() { ], over: None, distinct: false, + special: false },), alias: Ident { value: "hour".to_string(), @@ -2976,6 +2986,7 @@ fn parse_table_function() { )))], over: None, distinct: false, + special: false, }); assert_eq!(expr, expected_expr); assert_eq!(alias, table_alias("a")) @@ -3148,6 +3159,7 @@ fn parse_delimited_identifiers() { args: vec![], over: None, distinct: false, + special: false, }), expr_from_projection(&select.projection[1]), ); @@ -5125,6 +5137,7 @@ fn parse_time_functions() { args: vec![], over: None, distinct: false, + special: false, }), expr_from_projection(&select.projection[0]) ); @@ -5140,6 +5153,7 @@ fn parse_time_functions() { args: vec![], over: None, distinct: false, + special: false, }), expr_from_projection(&select.projection[0]) ); @@ -5155,6 +5169,7 @@ fn parse_time_functions() { args: vec![], over: None, distinct: false, + special: false, }), expr_from_projection(&select.projection[0]) ); diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index a72ffbb07..16d0daf8d 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -686,7 +686,8 @@ fn parse_insert_with_on_duplicate_update() { Expr::Identifier(Ident::new("description")) ))], over: None, - distinct: false + distinct: false, + special: false, }) }, Assignment { @@ -697,7 +698,8 @@ fn parse_insert_with_on_duplicate_update() { Expr::Identifier(Ident::new("perm_create")) ))], over: None, - distinct: false + distinct: false, + special: false, }) }, Assignment { @@ -708,7 +710,8 @@ fn parse_insert_with_on_duplicate_update() { Expr::Identifier(Ident::new("perm_read")) ))], over: None, - distinct: false + distinct: false, + special: false, }) }, Assignment { @@ -719,7 +722,8 @@ fn parse_insert_with_on_duplicate_update() { Expr::Identifier(Ident::new("perm_update")) ))], over: None, - distinct: false + distinct: false, + special: false, }) }, Assignment { @@ -730,7 +734,8 @@ fn parse_insert_with_on_duplicate_update() { Expr::Identifier(Ident::new("perm_delete")) ))], over: None, - distinct: false + distinct: false, + special: false, }) }, ])), diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 632a8bf34..d227df626 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1400,6 +1400,7 @@ fn test_composite_value() { )))], over: None, distinct: false, + special: false })))) }), select.projection[0] @@ -1542,6 +1543,52 @@ fn parse_declare() { pg_and_generic().verified_stmt("DECLARE \"SQL_CUR0x7fa44801bc00\" BINARY INSENSITIVE SCROLL CURSOR WITH HOLD FOR SELECT * FROM table_name LIMIT 2222"); } +#[test] +fn parse_current_functions() { + let sql = "SELECT CURRENT_CATALOG, CURRENT_USER, SESSION_USER, USER"; + let select = pg_and_generic().verified_only_select(sql); + assert_eq!( + &Expr::Function(Function { + name: ObjectName(vec![Ident::new("CURRENT_CATALOG")]), + args: vec![], + over: None, + distinct: false, + special: true, + }), + expr_from_projection(&select.projection[0]) + ); + assert_eq!( + &Expr::Function(Function { + name: ObjectName(vec![Ident::new("CURRENT_USER")]), + args: vec![], + over: None, + distinct: false, + special: true, + }), + expr_from_projection(&select.projection[1]) + ); + assert_eq!( + &Expr::Function(Function { + name: ObjectName(vec![Ident::new("SESSION_USER")]), + args: vec![], + over: None, + distinct: false, + special: true, + }), + expr_from_projection(&select.projection[2]) + ); + assert_eq!( + &Expr::Function(Function { + name: ObjectName(vec![Ident::new("USER")]), + args: vec![], + over: None, + distinct: false, + special: true, + }), + expr_from_projection(&select.projection[3]) + ); +} + #[test] fn parse_fetch() { pg_and_generic().verified_stmt("FETCH 2048 IN \"SQL_CUR0x7fa44801bc00\""); diff --git a/tests/sqpparser_clickhouse.rs b/tests/sqpparser_clickhouse.rs index 72a1a0556..af0f59fe6 100644 --- a/tests/sqpparser_clickhouse.rs +++ b/tests/sqpparser_clickhouse.rs @@ -51,6 +51,7 @@ fn parse_map_access_expr() { ], over: None, distinct: false, + special: false, })], })], into: None, @@ -85,7 +86,8 @@ fn parse_map_access_expr() { ))), ], over: None, - distinct: false + distinct: false, + special: false, })] }), op: BinaryOperator::NotEq,