MCPcopy Create free account
hub / github.com/MaterializeInc/materialize / parse_parenthesized_fragment

Method parse_parenthesized_fragment

src/sql-parser/src/parser.rs:750–828  ·  view source on GitHub ↗

Parses an expression list that appears in parentheses, like `(1 + 1)`, `(SELECT 1)`, or `(1, 2)`. Assumes that the opening parenthesis has already been parsed. Parses up to the closing parenthesis without consuming it.

(&mut self)

Source from the content-addressed store, hash-verified

748 /// already been parsed. Parses up to the closing parenthesis without
749 /// consuming it.
750 fn parse_parenthesized_fragment(&mut self) -> Result<ParenthesizedFragment, ParserError> {
751 // The SQL grammar has an irritating ambiguity that presents here.
752 // Consider these two expression fragments:
753 //
754 // SELECT (((SELECT 2)) + 3)
755 // SELECT (((SELECT 2)) UNION SELECT 2)
756 // ^ ^
757 // (1) (2)
758 // When we see the parenthesis marked (1), we have no way to know ahead
759 // of time whether that parenthesis is part of a `SetExpr::Query` inside
760 // of an `Expr::Subquery` or whether it introduces an `Expr::Nested`.
761 // The approach taken here avoids backtracking by deferring the decision
762 // of whether to parse as a subquery or a nested expression until we get
763 // to the point marked (2) above. Once there, we know that the presence
764 // of a set operator implies that the parentheses belonged to the
765 // subquery; otherwise, they belonged to the expression.
766 //
767 // See also PostgreSQL's comments on the matter:
768 // https://github.com/postgres/postgres/blob/42c63ab/src/backend/parser/gram.y#L11125-L11136
769 //
770 // Each call of this function handles one layer of parentheses. Before
771 // every call, the parser must be positioned after an opening
772 // parenthesis; upon non-error return, the parser will be positioned
773 // before the corresponding close parenthesis. Somewhat weirdly, the
774 // returned expression semantically includes the opening/closing
775 // parentheses, even though this function is not responsible for parsing
776 // them.
777
778 if self.peek_one_of_keywords(QUERY_START_KEYWORDS) {
779 // Easy case one: unambiguously a subquery.
780 Ok(ParenthesizedFragment::Query(self.parse_query()?))
781 } else if !self.consume_token(&Token::LParen) {
782 // Easy case two: unambiguously an expression.
783 let exprs = self.parse_comma_separated(Parser::parse_expr)?;
784 Ok(ParenthesizedFragment::Exprs(exprs))
785 } else {
786 // Hard case: we have an open parenthesis, and we need to decide
787 // whether it belongs to the inner expression or the outer
788 // expression.
789
790 // Parse to the closing parenthesis.
791 let fragment = self.checked_recur_mut(Parser::parse_parenthesized_fragment)?;
792 self.expect_token(&Token::RParen)?;
793
794 // Decide if we need to associate any tokens after the closing
795 // parenthesis with what we've parsed so far.
796 match (fragment, self.peek_token()) {
797 // We have a subquery and the next token is a set operator or a
798 // closing parenthesis. That implies we have a partially-parsed
799 // subquery (or a syntax error). Hop into parsing a set
800 // expression where our subquery is the LHS of the set operator.
801 (
802 ParenthesizedFragment::Query(query),
803 Some(Token::RParen | Token::Keyword(UNION | INTERSECT | EXCEPT)),
804 ) => {
805 let query = SetExpr::Query(Box::new(query));
806 let ctes = CteBlock::empty();
807 let body = self.parse_query_body_seeded(SetPrecedence::Zero, query)?;

Callers 3

parse_prefixMethod · 0.80
parse_any_allMethod · 0.80
parse_inMethod · 0.80

Calls 14

peek_one_of_keywordsMethod · 0.80
consume_tokenMethod · 0.80
parse_comma_separatedMethod · 0.80
checked_recur_mutMethod · 0.80
expect_tokenMethod · 0.80
peek_tokenMethod · 0.80
parse_query_tailMethod · 0.80
parse_subexpr_seededMethod · 0.80
parse_exprMethod · 0.80
QueryClass · 0.50
parse_queryMethod · 0.45

Tested by

no test coverage detected