diff --git a/src/ast/query.rs b/src/ast/query.rs index ce57fcf7b..e0dbe4c72 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -235,6 +235,11 @@ pub enum TableFactor { subquery: Box, alias: Option, }, + /// `TABLE()[ AS ]` + TableFunction { + expr: Expr, + alias: Option, + }, /// Represents a parenthesized table factor. The SQL spec only allows a /// join expression (`(foo bar [ baz ... ])`) to be nested, /// possibly several times, but the parser also accepts the non-standard @@ -278,6 +283,13 @@ impl fmt::Display for TableFactor { } Ok(()) } + TableFactor::TableFunction { expr, alias } => { + write!(f, "TABLE({})", expr)?; + if let Some(alias) = alias { + write!(f, " AS {}", alias)?; + } + Ok(()) + } TableFactor::NestedJoin(table_reference) => write!(f, "({})", table_reference), } } diff --git a/src/parser.rs b/src/parser.rs index 625a424fb..5f77b6691 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2066,10 +2066,15 @@ impl Parser { if !self.consume_token(&Token::LParen) { self.expected("subquery after LATERAL", self.peek_token())?; } - return self.parse_derived_table_factor(Lateral); - } - - if self.consume_token(&Token::LParen) { + self.parse_derived_table_factor(Lateral) + } else if self.parse_keyword(Keyword::TABLE) { + // parse table function (SELECT * FROM TABLE () [ AS ]) + self.expect_token(&Token::LParen)?; + let expr = self.parse_expr()?; + self.expect_token(&Token::RParen)?; + let alias = self.parse_optional_table_alias(keywords::RESERVED_FOR_TABLE_ALIAS)?; + Ok(TableFactor::TableFunction { expr, alias }) + } else if self.consume_token(&Token::LParen) { // A left paren introduces either a derived table (i.e., a subquery) // or a nested join. It's nearly impossible to determine ahead of // time which it is... so we just try to parse both. diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 5443c06e2..a96ed1838 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1158,8 +1158,8 @@ fn parse_create_table_with_multiple_on_delete_fails() { #[test] fn parse_assert() { - let sql = "ASSERT (SELECT COUNT(*) FROM table) > 0"; - let ast = one_statement_parses_to(sql, "ASSERT (SELECT COUNT(*) FROM table) > 0"); + let sql = "ASSERT (SELECT COUNT(*) FROM my_table) > 0"; + let ast = one_statement_parses_to(sql, "ASSERT (SELECT COUNT(*) FROM my_table) > 0"); match ast { Statement::Assert { condition: _condition, @@ -1173,10 +1173,10 @@ fn parse_assert() { #[test] fn parse_assert_message() { - let sql = "ASSERT (SELECT COUNT(*) FROM table) > 0 AS 'No rows in table'"; + let sql = "ASSERT (SELECT COUNT(*) FROM my_table) > 0 AS 'No rows in my_table'"; let ast = one_statement_parses_to( sql, - "ASSERT (SELECT COUNT(*) FROM table) > 0 AS 'No rows in table'", + "ASSERT (SELECT COUNT(*) FROM my_table) > 0 AS 'No rows in my_table'", ); match ast { Statement::Assert { @@ -1184,7 +1184,7 @@ fn parse_assert_message() { message: Some(message), } => { match message { - Expr::Value(Value::SingleQuotedString(s)) => assert_eq!(s, "No rows in table"), + Expr::Value(Value::SingleQuotedString(s)) => assert_eq!(s, "No rows in my_table"), _ => unreachable!(), }; } @@ -1864,6 +1864,39 @@ fn parse_simple_math_expr_minus() { verified_only_select(sql); } +#[test] +fn parse_table_function() { + let select = verified_only_select("SELECT * FROM TABLE(FUN('1')) AS a"); + + match only(select.from).relation { + TableFactor::TableFunction { expr, alias } => { + let expected_expr = Expr::Function(Function { + name: ObjectName(vec![Ident::new("FUN")]), + args: vec![FunctionArg::Unnamed(Expr::Value( + Value::SingleQuotedString("1".to_owned()), + ))], + over: None, + distinct: false, + }); + assert_eq!(expr, expected_expr); + assert_eq!(alias, table_alias("a")) + } + _ => panic!("Expecting TableFactor::TableFunction"), + } + + let res = parse_sql_statements("SELECT * FROM TABLE '1' AS a"); + assert_eq!( + ParserError::ParserError("Expected (, found: \'1\'".to_string()), + res.unwrap_err() + ); + + let res = parse_sql_statements("SELECT * FROM TABLE (FUN(a) AS a"); + assert_eq!( + ParserError::ParserError("Expected ), found: AS".to_string()), + res.unwrap_err() + ); +} + #[test] fn parse_delimited_identifiers() { // check that quoted identifiers in any position remain quoted after serialization