13
13
#[ cfg( not( feature = "std" ) ) ]
14
14
use alloc:: { boxed:: Box , string:: String , vec:: Vec } ;
15
15
16
+ use core:: fmt:: { self , Display } ;
16
17
#[ cfg( feature = "serde" ) ]
17
18
use serde:: { Deserialize , Serialize } ;
18
19
#[ cfg( feature = "visitor" ) ]
@@ -21,9 +22,10 @@ use sqlparser_derive::{Visit, VisitMut};
21
22
pub use super :: ddl:: { ColumnDef , TableConstraint } ;
22
23
23
24
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 ,
27
29
} ;
28
30
29
31
/// CREATE INDEX statement.
@@ -99,6 +101,214 @@ pub struct CreateTable {
99
101
pub strict : bool ,
100
102
}
101
103
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
+
102
312
/// INSERT statement.
103
313
#[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
104
314
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
0 commit comments