diff --git a/src/dialect/keywords.rs b/src/dialect/keywords.rs index dd1548d9..c3489ac6 100644 --- a/src/dialect/keywords.rs +++ b/src/dialect/keywords.rs @@ -420,7 +420,7 @@ define_keywords!( /// can be parsed unambiguously without looking ahead. pub const RESERVED_FOR_TABLE_ALIAS: &[&str] = &[ // Reserved as both a table and a column alias: - WITH, SELECT, WHERE, GROUP, ORDER, LIMIT, OFFSET, FETCH, UNION, EXCEPT, INTERSECT, + WITH, SELECT, WHERE, GROUP, HAVING, ORDER, LIMIT, OFFSET, FETCH, UNION, EXCEPT, INTERSECT, // Reserved only as a table alias in the `FROM`/`JOIN` clauses: ON, JOIN, INNER, CROSS, FULL, LEFT, RIGHT, NATURAL, USING, ]; @@ -429,7 +429,7 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[&str] = &[ /// can be parsed unambiguously without looking ahead. pub const RESERVED_FOR_COLUMN_ALIAS: &[&str] = &[ // Reserved as both a table and a column alias: - WITH, SELECT, WHERE, GROUP, ORDER, LIMIT, OFFSET, FETCH, UNION, EXCEPT, INTERSECT, + WITH, SELECT, WHERE, GROUP, HAVING, ORDER, LIMIT, OFFSET, FETCH, UNION, EXCEPT, INTERSECT, // Reserved only as a column alias in the `SELECT` clause: FROM, ]; diff --git a/src/sqlparser.rs b/src/sqlparser.rs index b55aede0..3e11f2e9 100644 --- a/src/sqlparser.rs +++ b/src/sqlparser.rs @@ -1566,6 +1566,11 @@ impl Parser { } let projection = self.parse_select_list()?; + // Note that for keywords to be properly handled here, they need to be + // added to `RESERVED_FOR_COLUMN_ALIAS` / `RESERVED_FOR_TABLE_ALIAS`, + // otherwise they may be parsed as an alias as part of the `projection` + // or `from`. + let mut from = vec![]; if self.parse_keyword("FROM") { loop { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 4984c483..7b4341fb 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -789,6 +789,29 @@ fn parse_select_group_by() { ); } +#[test] +fn parse_select_having() { + let sql = "SELECT foo FROM bar GROUP BY foo HAVING COUNT(*) > 1"; + let select = verified_only_select(sql); + assert_eq!( + Some(ASTNode::SQLBinaryOp { + left: Box::new(ASTNode::SQLFunction(SQLFunction { + name: SQLObjectName(vec!["COUNT".to_string()]), + args: vec![ASTNode::SQLWildcard], + over: None, + distinct: false + })), + op: SQLBinaryOperator::Gt, + right: Box::new(ASTNode::SQLValue(Value::Long(1))) + }), + select.having + ); + + let sql = "SELECT 'foo' HAVING 1 = 1"; + let select = verified_only_select(sql); + assert!(select.having.is_some()); +} + #[test] fn parse_limit_accepts_all() { one_statement_parses_to(