Skip to content

Commit 8096e8c

Browse files
committed
fix: Use separate types for FormatClause and InputFormatClause
1 parent e75aafe commit 8096e8c

File tree

5 files changed

+47
-48
lines changed

5 files changed

+47
-48
lines changed

src/ast/dml.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ use sqlparser_derive::{Visit, VisitMut};
3232
pub use super::ddl::{ColumnDef, TableConstraint};
3333

3434
use super::{
35-
display_comma_separated, display_separated, Assignment, ClusteredBy, CommentDef, Expr,
36-
FileFormat, FormatClause, FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat,
35+
display_comma_separated, display_separated, query::InputFormatClause, Assignment, ClusteredBy,
36+
CommentDef, Expr, FileFormat, FromTable, HiveDistributionStyle, HiveFormat, HiveIOFormat,
3737
HiveRowFormat, Ident, InsertAliases, MysqlInsertPriority, ObjectName, OnCommit, OnInsert,
3838
OneOrManyWithParens, OrderByExpr, Query, RowAccessPolicy, SelectItem, Setting, SqlOption,
3939
SqliteOnConflict, TableEngine, TableWithJoins, Tag, WrappedCollection,
@@ -510,7 +510,7 @@ pub struct Insert {
510510
/// ClickHouse syntax: `INSERT INTO tbl FORMAT JSONEachRow {"foo": 1, "bar": 2}, {"foo": 3}`
511511
///
512512
/// [ClickHouse formats JSON insert](https://clickhouse.com/docs/en/interfaces/formats#json-inserting-data)
513-
pub format_clause: Option<FormatClause>,
513+
pub format_clause: Option<InputFormatClause>,
514514
}
515515

516516
impl Display for Insert {

src/ast/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ pub use self::operator::{BinaryOperator, UnaryOperator};
6161
pub use self::query::{
6262
AfterMatchSkip, ConnectBy, Cte, CteAsMaterialized, Distinct, EmptyMatchesMode,
6363
ExceptSelectItem, ExcludeSelectItem, ExprWithAlias, Fetch, ForClause, ForJson, ForXml,
64-
FormatClause, GroupByExpr, GroupByWithModifier, IdentWithAlias, IlikeSelectItem, Interpolate,
65-
InterpolateExpr, Join, JoinConstraint, JoinOperator, JsonTableColumn,
66-
JsonTableColumnErrorHandling, JsonTableNamedColumn, JsonTableNestedColumn, LateralView,
67-
LockClause, LockType, MatchRecognizePattern, MatchRecognizeSymbol, Measure,
64+
FormatClause, GroupByExpr, GroupByWithModifier, IdentWithAlias, IlikeSelectItem,
65+
InputFormatClause, Interpolate, InterpolateExpr, Join, JoinConstraint, JoinOperator,
66+
JsonTableColumn, JsonTableColumnErrorHandling, JsonTableNamedColumn, JsonTableNestedColumn,
67+
LateralView, LockClause, LockType, MatchRecognizePattern, MatchRecognizeSymbol, Measure,
6868
NamedWindowDefinition, NamedWindowExpr, NonBlock, Offset, OffsetRows, OpenJsonTableColumn,
6969
OrderBy, OrderByExpr, PivotValueSource, ProjectionSelect, Query, RenameSelectItem,
7070
RepetitionQuantifier, ReplaceSelectElement, ReplaceSelectItem, RowsPerMatch, Select,

src/ast/query.rs

+24-12
Original file line numberDiff line numberDiff line change
@@ -2465,27 +2465,39 @@ impl fmt::Display for GroupByExpr {
24652465
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
24662466
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
24672467
pub enum FormatClause {
2468-
Identifier {
2469-
ident: Ident,
2470-
expr: Option<Vec<Expr>>,
2471-
},
2468+
Identifier(Ident),
24722469
Null,
24732470
}
24742471

24752472
impl fmt::Display for FormatClause {
24762473
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24772474
match self {
2478-
FormatClause::Identifier { ident, expr } => {
2479-
write!(f, "FORMAT {}", ident)?;
2475+
FormatClause::Identifier(ident) => write!(f, "FORMAT {}", ident),
2476+
FormatClause::Null => write!(f, "FORMAT NULL"),
2477+
}
2478+
}
2479+
}
24802480

2481-
if let Some(exprs) = expr {
2482-
write!(f, " {}", display_comma_separated(exprs))?;
2483-
}
2481+
/// FORMAT identifier in input context, specific to ClickHouse.
2482+
///
2483+
/// [ClickHouse]: <https://clickhouse.com/docs/en/interfaces/formats>
2484+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2485+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2486+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2487+
pub struct InputFormatClause {
2488+
pub ident: Ident,
2489+
pub values: Vec<Expr>,
2490+
}
24842491

2485-
Ok(())
2486-
}
2487-
FormatClause::Null => write!(f, "FORMAT NULL"),
2492+
impl fmt::Display for InputFormatClause {
2493+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2494+
write!(f, "FORMAT {}", self.ident)?;
2495+
2496+
if !self.values.is_empty() {
2497+
write!(f, " {}", display_comma_separated(self.values.as_slice()))?;
24882498
}
2499+
2500+
Ok(())
24892501
}
24902502
}
24912503

src/parser/mod.rs

+15-25
Original file line numberDiff line numberDiff line change
@@ -9589,7 +9589,12 @@ impl<'a> Parser<'a> {
95899589
let format_clause = if dialect_of!(self is ClickHouseDialect | GenericDialect)
95909590
&& self.parse_keyword(Keyword::FORMAT)
95919591
{
9592-
Some(self.parse_format_clause(false)?)
9592+
if self.parse_keyword(Keyword::NULL) {
9593+
Some(FormatClause::Null)
9594+
} else {
9595+
let ident = self.parse_identifier()?;
9596+
Some(FormatClause::Identifier(ident))
9597+
}
95939598
} else {
95949599
None
95959600
};
@@ -11934,7 +11939,7 @@ impl<'a> Parser<'a> {
1193411939
let settings = self.parse_settings()?;
1193511940

1193611941
let format = if self.parse_keyword(Keyword::FORMAT) {
11937-
Some(self.parse_format_clause(true)?)
11942+
Some(self.parse_input_format_clause()?)
1193811943
} else {
1193911944
None
1194011945
};
@@ -12035,32 +12040,17 @@ impl<'a> Parser<'a> {
1203512040
}
1203612041

1203712042
// Parses format clause used for [ClickHouse]. Formats are different when using `SELECT` and
12038-
// `INSERT` and also when using the CLI for pipes. It may or may not take an additional
12039-
// expression after the format so we try to parse the expression but allow failure.
12040-
//
12041-
// Since we know we never take an additional expression in `SELECT` context we never only try
12042-
// to parse if `can_have_expression` is true.
12043+
// `INSERT` and also when using the CLI for pipes. For `INSERT` it can take an optional values
12044+
// list which we try to parse here.
1204312045
//
1204412046
// <https://clickhouse.com/docs/en/interfaces/formats>
12045-
pub fn parse_format_clause(
12046-
&mut self,
12047-
can_have_expression: bool,
12048-
) -> Result<FormatClause, ParserError> {
12049-
if self.parse_keyword(Keyword::NULL) {
12050-
Ok(FormatClause::Null)
12051-
} else {
12052-
let ident = self.parse_identifier()?;
12053-
let expr = if can_have_expression {
12054-
match self.try_parse(|p| p.parse_comma_separated(|p| p.parse_expr())) {
12055-
Ok(expr) => Some(expr),
12056-
_ => None,
12057-
}
12058-
} else {
12059-
None
12060-
};
12047+
pub fn parse_input_format_clause(&mut self) -> Result<InputFormatClause, ParserError> {
12048+
let ident = self.parse_identifier()?;
12049+
let values = self
12050+
.try_parse(|p| p.parse_comma_separated(|p| p.parse_expr()))
12051+
.unwrap_or_default();
1206112052

12062-
Ok(FormatClause::Identifier { ident, expr })
12063-
}
12053+
Ok(InputFormatClause { ident, values })
1206412054
}
1206512055

1206612056
/// Returns true if the immediate tokens look like the

tests/sqlparser_clickhouse.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -1378,10 +1378,7 @@ fn test_query_with_format_clause() {
13781378
} else {
13791379
assert_eq!(
13801380
query.format_clause,
1381-
Some(FormatClause::Identifier {
1382-
ident: Ident::new(*format),
1383-
expr: None
1384-
})
1381+
Some(FormatClause::Identifier(Ident::new(*format)))
13851382
);
13861383
}
13871384
}

0 commit comments

Comments
 (0)