Skip to content

Commit ebb57a5

Browse files
CreateTable: move Display from Statement
Move the Statement Display implementation to the CreateTable struct
1 parent e70024e commit ebb57a5

File tree

2 files changed

+217
-246
lines changed

2 files changed

+217
-246
lines changed

src/ast/dml.rs

+213-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#[cfg(not(feature = "std"))]
1414
use alloc::{boxed::Box, string::String, vec::Vec};
1515

16+
use core::fmt::{self, Display};
1617
#[cfg(feature = "serde")]
1718
use serde::{Deserialize, Serialize};
1819
#[cfg(feature = "visitor")]
@@ -21,9 +22,10 @@ use sqlparser_derive::{Visit, VisitMut};
2122
pub use super::ddl::{ColumnDef, TableConstraint};
2223

2324
use super::{
24-
Expr, FileFormat, FromTable, HiveDistributionStyle, HiveFormat, Ident, InsertAliases,
25-
MysqlInsertPriority, ObjectName, OnCommit, OnInsert, OrderByExpr, Query, SelectItem, SqlOption,
26-
SqliteOnConflict, TableWithJoins,
25+
display_comma_separated, display_separated, Expr, FileFormat, FromTable, HiveDistributionStyle,
26+
HiveFormat, HiveIOFormat, HiveRowFormat, Ident, InsertAliases, MysqlInsertPriority, ObjectName,
27+
OnCommit, OnInsert, OrderByExpr, Query, SelectItem, SqlOption, SqliteOnConflict,
28+
TableWithJoins,
2729
};
2830

2931
/// CREATE INDEX statement.
@@ -99,6 +101,214 @@ pub struct CreateTable {
99101
pub strict: bool,
100102
}
101103

104+
impl Display for CreateTable {
105+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106+
// We want to allow the following options
107+
// Empty column list, allowed by PostgreSQL:
108+
// `CREATE TABLE t ()`
109+
// No columns provided for CREATE TABLE AS:
110+
// `CREATE TABLE t AS SELECT a from t2`
111+
// Columns provided for CREATE TABLE AS:
112+
// `CREATE TABLE t (a INT) AS SELECT a from t2`
113+
write!(
114+
f,
115+
"CREATE {or_replace}{external}{global}{temporary}{transient}TABLE {if_not_exists}{name}",
116+
or_replace = if self.or_replace { "OR REPLACE " } else { "" },
117+
external = if self.external { "EXTERNAL " } else { "" },
118+
global = self.global
119+
.map(|global| {
120+
if global {
121+
"GLOBAL "
122+
} else {
123+
"LOCAL "
124+
}
125+
})
126+
.unwrap_or(""),
127+
if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
128+
temporary = if self.temporary { "TEMPORARY " } else { "" },
129+
transient = if self.transient { "TRANSIENT " } else { "" },
130+
name = self.name,
131+
)?;
132+
if let Some(on_cluster) = &self.on_cluster {
133+
write!(
134+
f,
135+
" ON CLUSTER {}",
136+
on_cluster.replace('{', "'{").replace('}', "}'")
137+
)?;
138+
}
139+
if !self.columns.is_empty() || !self.constraints.is_empty() {
140+
write!(f, " ({}", display_comma_separated(&self.columns))?;
141+
if !self.columns.is_empty() && !self.constraints.is_empty() {
142+
write!(f, ", ")?;
143+
}
144+
write!(f, "{})", display_comma_separated(&self.constraints))?;
145+
} else if self.query.is_none() && self.like.is_none() && self.clone.is_none() {
146+
// PostgreSQL allows `CREATE TABLE t ();`, but requires empty parens
147+
write!(f, " ()")?;
148+
}
149+
// Only for SQLite
150+
if self.without_rowid {
151+
write!(f, " WITHOUT ROWID")?;
152+
}
153+
154+
// Only for Hive
155+
if let Some(l) = &self.like {
156+
write!(f, " LIKE {l}")?;
157+
}
158+
159+
if let Some(c) = &self.clone {
160+
write!(f, " CLONE {c}")?;
161+
}
162+
163+
match &self.hive_distribution {
164+
HiveDistributionStyle::PARTITIONED { columns } => {
165+
write!(f, " PARTITIONED BY ({})", display_comma_separated(columns))?;
166+
}
167+
HiveDistributionStyle::CLUSTERED {
168+
columns,
169+
sorted_by,
170+
num_buckets,
171+
} => {
172+
write!(f, " CLUSTERED BY ({})", display_comma_separated(columns))?;
173+
if !sorted_by.is_empty() {
174+
write!(f, " SORTED BY ({})", display_comma_separated(sorted_by))?;
175+
}
176+
if *num_buckets > 0 {
177+
write!(f, " INTO {num_buckets} BUCKETS")?;
178+
}
179+
}
180+
HiveDistributionStyle::SKEWED {
181+
columns,
182+
on,
183+
stored_as_directories,
184+
} => {
185+
write!(
186+
f,
187+
" SKEWED BY ({})) ON ({})",
188+
display_comma_separated(columns),
189+
display_comma_separated(on)
190+
)?;
191+
if *stored_as_directories {
192+
write!(f, " STORED AS DIRECTORIES")?;
193+
}
194+
}
195+
_ => (),
196+
}
197+
198+
if let Some(HiveFormat {
199+
row_format,
200+
serde_properties,
201+
storage,
202+
location,
203+
}) = &self.hive_formats
204+
{
205+
match row_format {
206+
Some(HiveRowFormat::SERDE { class }) => write!(f, " ROW FORMAT SERDE '{class}'")?,
207+
Some(HiveRowFormat::DELIMITED { delimiters }) => {
208+
write!(f, " ROW FORMAT DELIMITED")?;
209+
if !delimiters.is_empty() {
210+
write!(f, " {}", display_separated(delimiters, " "))?;
211+
}
212+
}
213+
None => (),
214+
}
215+
match storage {
216+
Some(HiveIOFormat::IOF {
217+
input_format,
218+
output_format,
219+
}) => write!(
220+
f,
221+
" STORED AS INPUTFORMAT {input_format} OUTPUTFORMAT {output_format}"
222+
)?,
223+
Some(HiveIOFormat::FileFormat { format }) if !self.external => {
224+
write!(f, " STORED AS {format}")?
225+
}
226+
_ => (),
227+
}
228+
if let Some(serde_properties) = serde_properties.as_ref() {
229+
write!(
230+
f,
231+
" WITH SERDEPROPERTIES ({})",
232+
display_comma_separated(serde_properties)
233+
)?;
234+
}
235+
if !self.external {
236+
if let Some(loc) = location {
237+
write!(f, " LOCATION '{loc}'")?;
238+
}
239+
}
240+
}
241+
if self.external {
242+
if let Some(file_format) = self.file_format {
243+
write!(f, " STORED AS {file_format}")?;
244+
}
245+
write!(f, " LOCATION '{}'", self.location.as_ref().unwrap())?;
246+
}
247+
if !self.table_properties.is_empty() {
248+
write!(
249+
f,
250+
" TBLPROPERTIES ({})",
251+
display_comma_separated(&self.table_properties)
252+
)?;
253+
}
254+
if !self.with_options.is_empty() {
255+
write!(f, " WITH ({})", display_comma_separated(&self.with_options))?;
256+
}
257+
if let Some(engine) = &self.engine {
258+
write!(f, " ENGINE={engine}")?;
259+
}
260+
if let Some(comment) = &self.comment {
261+
write!(f, " COMMENT '{comment}'")?;
262+
}
263+
if let Some(auto_increment_offset) = self.auto_increment_offset {
264+
write!(f, " AUTO_INCREMENT {auto_increment_offset}")?;
265+
}
266+
if let Some(order_by) = &self.order_by {
267+
write!(f, " ORDER BY ({})", display_comma_separated(order_by))?;
268+
}
269+
if let Some(partition_by) = self.partition_by.as_ref() {
270+
write!(f, " PARTITION BY {partition_by}")?;
271+
}
272+
if let Some(cluster_by) = self.cluster_by.as_ref() {
273+
write!(
274+
f,
275+
" CLUSTER BY {}",
276+
display_comma_separated(cluster_by.as_slice())
277+
)?;
278+
}
279+
if let Some(options) = self.options.as_ref() {
280+
write!(
281+
f,
282+
" OPTIONS({})",
283+
display_comma_separated(options.as_slice())
284+
)?;
285+
}
286+
if let Some(query) = &self.query {
287+
write!(f, " AS {query}")?;
288+
}
289+
if let Some(default_charset) = &self.default_charset {
290+
write!(f, " DEFAULT CHARSET={default_charset}")?;
291+
}
292+
if let Some(collation) = &self.collation {
293+
write!(f, " COLLATE={collation}")?;
294+
}
295+
296+
if self.on_commit.is_some() {
297+
let on_commit = match self.on_commit {
298+
Some(OnCommit::DeleteRows) => "ON COMMIT DELETE ROWS",
299+
Some(OnCommit::PreserveRows) => "ON COMMIT PRESERVE ROWS",
300+
Some(OnCommit::Drop) => "ON COMMIT DROP",
301+
None => "",
302+
};
303+
write!(f, " {on_commit}")?;
304+
}
305+
if self.strict {
306+
write!(f, " STRICT")?;
307+
}
308+
Ok(())
309+
}
310+
}
311+
102312
/// INSERT statement.
103313
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
104314
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

0 commit comments

Comments
 (0)