Skip to content

Support remaining pipe operators #1879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

simonvandel
Copy link
Contributor

Fixes #1758

This PR adds support for the remaining SQL pipe operators as defined by BigQuery.

@simonvandel simonvandel mentioned this pull request Jun 10, 2025
18 tasks
Copy link
Contributor

@iffyio iffyio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @simonvandel! The changes look good to me overall! left some comments

Comment on lines +2893 to +2898
for (i, query) in queries.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "({})", query)?;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this use the display_comma_separated() helper function?

@@ -9947,6 +9947,51 @@ impl<'a> Parser<'a> {
Ok(IdentWithAlias { ident, alias })
}

/// Parse `identifier [AS] identifier` where the AS keyword is optional
pub fn parse_identifier_with_optional_alias(&mut self) -> Result<IdentWithAlias, ParserError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn parse_identifier_with_optional_alias(&mut self) -> Result<IdentWithAlias, ParserError> {
fn parse_identifier_with_optional_alias(&mut self) -> Result<IdentWithAlias, ParserError> {

Comment on lines +9973 to +9982
if self.parse_keywords(&[Keyword::DISTINCT, Keyword::BY, Keyword::NAME]) {
Ok(SetQuantifier::DistinctByName)
} else if self.parse_keyword(Keyword::DISTINCT) {
Ok(SetQuantifier::Distinct)
} else {
Err(ParserError::ParserError(format!(
"{} pipe operator requires DISTINCT modifier",
operator_name
)))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking since this block is a subset of the set_quantifier parsing logic here, it might be good to reuse? one way could be we pull the latter out into a function and call it here, rejecting any returned upexpected variants. another would be that we update the latter to call this parse_distinct_required_set_quantifier() function

/// Parse optional alias (with or without AS keyword) for pipe operators
fn parse_optional_pipe_alias(&mut self) -> Result<Option<Ident>, ParserError> {
if self.parse_keyword(Keyword::AS) {
Some(self.parse_identifier()).transpose()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Some(self.parse_identifier()).transpose()
Ok(Some(self.parse_identifier()?))

thinking this variant would be more explicit in this case? (the transpose seemed to obfuscate a bit what was going on)

}

/// Parse optional alias (with or without AS keyword) for pipe operators
fn parse_optional_pipe_alias(&mut self) -> Result<Option<Ident>, ParserError> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn parse_optional_pipe_alias(&mut self) -> Result<Option<Ident>, ParserError> {
fn parse_identifier_optional_alias(&mut self) -> Result<Option<Ident>, ParserError> {

maybe we could rename this to something more generic? feels like it could be reusable in other contexts than pipe operators

alias,
});
}
Keyword::JOIN => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the joins, I'm wondering if its possible to pull out and reuse the existing logic here? e.g. here we'll prev_token() if needed whenever we see the next operator looks like a join and delegate to that helper function?

Comment on lines +11305 to +11309
if matches!(constraint, JoinConstraint::None) {
return Err(ParserError::ParserError(
"JOIN in pipe syntax requires ON or USING clause".to_string(),
));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thinking these constraint validations might not be ideal and we can skip them? in case the pipe syntax is later ported to other dialects, there the semantics might differ between dialects, prev related behavior

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support SQL pipe operator
2 participants