Skip to content

Commit

Permalink
Add tests for invalid syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
nickpresta committed Jul 5, 2024
1 parent 47ba442 commit ebcd31e
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 3 deletions.
33 changes: 32 additions & 1 deletion src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7888,7 +7888,9 @@ impl<'a> Parser<'a> {
let body = self.parse_boxed_query_body(0)?;

let order_by = if self.parse_keywords(&[Keyword::ORDER, Keyword::BY]) {
self.parse_comma_separated(Parser::parse_order_by_expr)?
let order_by_exprs = self.parse_comma_separated(Parser::parse_order_by_expr)?;
self.validate_order_by_exprs_for_interpolate_and_with_fill(&order_by_exprs)?;
order_by_exprs
} else {
vec![]
};
Expand Down Expand Up @@ -10465,6 +10467,35 @@ impl<'a> Parser<'a> {
Ok(WithFill { from, to, step })
}

pub fn validate_order_by_exprs_for_interpolate_and_with_fill(
&mut self,
order_by_exprs: &Vec<OrderByExpr>,
) -> Result<(), ParserError> {
if dialect_of!(self is ClickHouseDialect | GenericDialect) {
let mut has_with_fill = false;
let mut has_interpolate = false;
for order_by_expr in order_by_exprs {
if order_by_expr.with_fill.is_some() {
has_with_fill = true;
}
if order_by_expr.interpolate.is_some() {
if has_interpolate {
return Err(ParserError::ParserError(
"Only the last ORDER BY expression can contain interpolate".to_string(),
));
}
if !has_with_fill {
return Err(ParserError::ParserError(
"INTERPOLATE requires WITH FILL".to_string(),
));
}
has_interpolate = true;
}
}
}
Ok(())
}

// Parse a set of comma seperated INTERPOLATE expressions (ClickHouse dialect)
// that follow the INTERPOLATE keyword in an ORDER BY clause with the WITH FILL modifier
pub fn parse_interpolations(&mut self) -> Result<Vec<Interpolate>, ParserError> {
Expand Down
64 changes: 62 additions & 2 deletions tests/sqlparser_clickhouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -727,10 +727,51 @@ fn parse_select_order_by_with_fill_interpolate() {
assert_eq!(Some(Expr::Value(number("2"))), select.limit);
}

#[test]
fn parse_select_order_by_with_fill_interpolate_multi_interpolates() {
let sql = "SELECT id, fname, lname FROM customer ORDER BY fname WITH FILL \
INTERPOLATE (col1 AS col1 + 1) INTERPOLATE (col2 AS col2 + 2)";
clickhouse_and_generic()
.parse_sql_statements(sql)
.expect_err("ORDER BY only accepts a single INTERPOLATE clause");
}

#[test]
fn parse_select_order_by_with_fill_interpolate_multi_with_fill_interpolates() {
let sql = "SELECT id, fname, lname FROM customer \
ORDER BY \
fname WITH FILL INTERPOLATE (col1 AS col1 + 1), \
lname WITH FILL INTERPOLATE (col2 AS col2 + 2)";
clickhouse_and_generic()
.parse_sql_statements(sql)
.expect_err("ORDER BY only accepts a single INTERPOLATE clause");
}

#[test]
fn parse_select_order_by_interpolate_missing_with_fill() {
let sql = "SELECT id, fname, lname FROM customer \
ORDER BY fname, lname \
INTERPOLATE (col2 AS col2 + 2)";
clickhouse_and_generic()
.parse_sql_statements(sql)
.expect_err("ORDER BY INTERPOLATE must have at least one WITH FILL");
}

#[test]
fn parse_select_order_by_interpolate_not_last() {
let sql = "SELECT id, fname, lname FROM customer \
ORDER BY \
fname INTERPOLATE (col2 AS col2 + 2),
lname";
clickhouse_and_generic()
.parse_sql_statements(sql)
.expect_err("ORDER BY INTERPOLATE must be in the last position");
}

#[test]
fn parse_with_fill() {
let sql = "SELECT fname FROM customer \
ORDER BY fname WITH FILL FROM 10 TO 20 STEP 2";
let sql = "SELECT fname FROM customer ORDER BY fname \
WITH FILL FROM 10 TO 20 STEP 2";
let select = clickhouse().verified_query(sql);
assert_eq!(
Some(WithFill {
Expand All @@ -742,6 +783,25 @@ fn parse_with_fill() {
);
}

#[test]
fn parse_with_fill_missing_single_argument() {
let sql = "SELECT id, fname, lname FROM customer ORDER BY \
fname WITH FILL FROM TO 20";
clickhouse_and_generic()
.parse_sql_statements(sql)
.expect_err("WITH FILL requires expressions for all arguments");
}

#[test]
fn parse_with_fill_multiple_incomplete_arguments() {
let sql = "SELECT id, fname, lname FROM customer ORDER BY \
fname WITH FILL FROM TO 20, lname WITH FILL FROM TO STEP 1";
clickhouse_and_generic()
.parse_sql_statements(sql)
.expect_err("WITH FILL requires expressions for all arguments");
}


#[test]
fn parse_interpolate_body_with_columns() {
let sql = "SELECT fname FROM customer ORDER BY fname WITH FILL \
Expand Down

0 comments on commit ebcd31e

Please sign in to comment.