Parse SETTINGS clause for ClickHouse table-valued functions (#1358)

This commit is contained in:
Jesse 2024-08-01 23:28:15 +02:00 committed by GitHub
parent a692ba5fd1
commit d49acc67b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 167 additions and 34 deletions

View file

@ -3430,6 +3430,29 @@ impl<'a> Parser<'a> {
Ok(values)
}
/// Parse the comma of a comma-separated syntax element.
/// Returns true if there is a next element
fn is_parse_comma_separated_end(&mut self) -> bool {
if !self.consume_token(&Token::Comma) {
true
} else if self.options.trailing_commas {
let token = self.peek_token().token;
match token {
Token::Word(ref kw)
if keywords::RESERVED_FOR_COLUMN_ALIAS.contains(&kw.keyword) =>
{
true
}
Token::RParen | Token::SemiColon | Token::EOF | Token::RBracket | Token::RBrace => {
true
}
_ => false,
}
} else {
false
}
}
/// Parse a comma-separated list of 1+ items accepted by `F`
pub fn parse_comma_separated<T, F>(&mut self, mut f: F) -> Result<Vec<T>, ParserError>
where
@ -3438,22 +3461,8 @@ impl<'a> Parser<'a> {
let mut values = vec![];
loop {
values.push(f(self)?);
if !self.consume_token(&Token::Comma) {
if self.is_parse_comma_separated_end() {
break;
} else if self.options.trailing_commas {
match self.peek_token().token {
Token::Word(kw)
if keywords::RESERVED_FOR_COLUMN_ALIAS.contains(&kw.keyword) =>
{
break;
}
Token::RParen
| Token::SemiColon
| Token::EOF
| Token::RBracket
| Token::RBrace => break,
_ => continue,
}
}
}
Ok(values)
@ -8104,19 +8113,7 @@ impl<'a> Parser<'a> {
vec![]
};
let settings = if dialect_of!(self is ClickHouseDialect|GenericDialect)
&& self.parse_keyword(Keyword::SETTINGS)
{
let key_values = self.parse_comma_separated(|p| {
let key = p.parse_identifier(false)?;
p.expect_token(&Token::Eq)?;
let value = p.parse_value()?;
Ok(Setting { key, value })
})?;
Some(key_values)
} else {
None
};
let settings = self.parse_settings()?;
let fetch = if self.parse_keyword(Keyword::FETCH) {
Some(self.parse_fetch()?)
@ -8163,6 +8160,23 @@ impl<'a> Parser<'a> {
}
}
fn parse_settings(&mut self) -> Result<Option<Vec<Setting>>, ParserError> {
let settings = if dialect_of!(self is ClickHouseDialect|GenericDialect)
&& self.parse_keyword(Keyword::SETTINGS)
{
let key_values = self.parse_comma_separated(|p| {
let key = p.parse_identifier(false)?;
p.expect_token(&Token::Eq)?;
let value = p.parse_value()?;
Ok(Setting { key, value })
})?;
Some(key_values)
} else {
None
};
Ok(settings)
}
/// Parse a mssql `FOR [XML | JSON | BROWSE]` clause
pub fn parse_for_clause(&mut self) -> Result<Option<ForClause>, ParserError> {
if self.parse_keyword(Keyword::XML) {
@ -9382,9 +9396,9 @@ impl<'a> Parser<'a> {
// Parse potential version qualifier
let version = self.parse_table_version()?;
// Postgres, MSSQL: table-valued functions:
// Postgres, MSSQL, ClickHouse: table-valued functions:
let args = if self.consume_token(&Token::LParen) {
Some(self.parse_optional_args()?)
Some(self.parse_table_function_args()?)
} else {
None
};
@ -10327,6 +10341,27 @@ impl<'a> Parser<'a> {
}
}
fn parse_table_function_args(&mut self) -> Result<TableFunctionArgs, ParserError> {
if self.consume_token(&Token::RParen) {
return Ok(TableFunctionArgs {
args: vec![],
settings: None,
});
}
let mut args = vec![];
let settings = loop {
if let Some(settings) = self.parse_settings()? {
break Some(settings);
}
args.push(self.parse_function_args()?);
if self.is_parse_comma_separated_end() {
break None;
}
};
self.expect_token(&Token::RParen)?;
Ok(TableFunctionArgs { args, settings })
}
/// Parses a potentially empty list of arguments to a window function
/// (including the closing parenthesis).
///