Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ast/ddl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ impl<'a> From<&'a str> for IndexColumn {

impl fmt::Display for IndexColumn {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.column)?;
write!(f, "{}", self.column.expr)?;
if let Some(operator_class) = &self.operator_class {
write!(f, " {operator_class}")?;
}
Ok(())
self.column.fmt_sort_modifiers(f)
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/ast/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2981,8 +2981,15 @@ impl From<Ident> for OrderByExpr {
impl fmt::Display for OrderByExpr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.expr)?;
self.fmt_sort_modifiers(f)
}
}

impl OrderByExpr {
/// Writes the modifiers that follow the sort expression (`ASC`/`DESC`, `NULLS`, `WITH FILL`).
pub(crate) fn fmt_sort_modifiers(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.options)?;
if let Some(ref with_fill) = self.with_fill {
if let Some(with_fill) = &self.with_fill {
write!(f, " {with_fill}")?
}
Ok(())
Expand Down
51 changes: 51 additions & 0 deletions tests/sqlparser_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21022,3 +21022,54 @@ fn parse_window_spec_keyword_base_window_name() {
"SELECT count(*) OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM t",
);
}

#[test]
fn parse_create_index_operator_class_before_sort_options() {
let dialects = all_dialects();
dialects.verified_stmt("CREATE INDEX ii ON t(c)");
dialects.verified_stmt("CREATE INDEX ii ON t(c ops)");
dialects.verified_stmt("CREATE INDEX ii ON t(c DESC)");
dialects.verified_stmt("CREATE INDEX ii ON t(c ops DESC)");
dialects.verified_stmt("CREATE INDEX ii ON t(c ops DESC NULLS FIRST)");

let statements = dialects
.parse_sql_statements("CREATE INDEX ii ON t(c ops DESC)")
.unwrap();
let Statement::CreateIndex(create_index) = &statements[0] else {
panic!("expected CREATE INDEX")
};
let column = &create_index.columns[0];
assert_eq!(column.column.expr, Expr::Identifier(Ident::new("c")));
assert_eq!(
column.operator_class,
Some(ObjectName::from(vec![Ident::new("ops")]))
);
assert_eq!(column.column.options.sort, Some(OrderBySort::Desc));
}

#[test]
fn display_index_column_propagates_expression_errors() {
use core::fmt::{self, Write};

struct RejectingWriter(char);

impl Write for RejectingWriter {
fn write_str(&mut self, value: &str) -> fmt::Result {
if value.contains(self.0) {
Err(fmt::Error)
} else {
Ok(())
}
}
}

let statements = all_dialects()
.parse_sql_statements("CREATE INDEX ii ON t(c ops DESC)")
.unwrap();
let Statement::CreateIndex(create_index) = &statements[0] else {
panic!("expected CREATE INDEX")
};
let column = &create_index.columns[0];
let mut writer = RejectingWriter('c');
assert_eq!(write!(writer, "{column}"), Err(fmt::Error));
}
Loading