@@ -31,9 +31,12 @@ use lazy_static::lazy_static;
3131use sqlparser:: ast:: {
3232 CreateFunctionBody , Expr , ObjectName , OrderByExpr , TruncateTableTarget , Value ,
3333} ;
34- use sqlparser:: tokenizer:: { TokenWithLocation , Word } ;
34+ use sqlparser:: tokenizer:: { TokenWithSpan , Word } ;
3535use sqlparser:: {
36- ast:: { ColumnDef , ColumnOptionDef , Statement as SQLStatement , TableConstraint } ,
36+ ast:: {
37+ ColumnDef , ColumnOptionDef , CreateFunction , Statement as SQLStatement ,
38+ TableConstraint ,
39+ } ,
3740 dialect:: { keywords:: Keyword , Dialect , GenericDialect } ,
3841 parser:: { Parser , ParserError } ,
3942 tokenizer:: { Token , Tokenizer } ,
@@ -135,7 +138,7 @@ impl<'a> DFParser<'a> {
135138 fn expected < T > (
136139 & self ,
137140 expected : & str ,
138- found : TokenWithLocation ,
141+ found : TokenWithSpan ,
139142 ) -> Result < T , ParserError > {
140143 parser_err ! ( format!( "Expected {expected}, found: {found}" ) )
141144 }
@@ -225,6 +228,7 @@ impl<'a> DFParser<'a> {
225228 only : false ,
226229 identity : None ,
227230 cascade : None ,
231+ on_cluster : None ,
228232 } ) ) )
229233 }
230234
@@ -242,6 +246,7 @@ impl<'a> DFParser<'a> {
242246 only : false ,
243247 identity : None ,
244248 cascade : None ,
249+ on_cluster : None ,
245250 } ) ) )
246251 }
247252
@@ -258,23 +263,76 @@ impl<'a> DFParser<'a> {
258263 CopyToSource :: Relation ( table_name)
259264 } ;
260265
261- self . parser . expect_keyword ( Keyword :: TO ) ?;
266+ #[ derive( Default ) ]
267+ struct Builder {
268+ stored_as : Option < String > ,
269+ target : Option < String > ,
270+ partitioned_by : Option < Vec < String > > ,
271+ options : Option < Vec < ( String , Value ) > > ,
272+ }
262273
263- let target = self . parser . parse_literal_string ( ) ? ;
274+ let mut builder = Builder :: default ( ) ;
264275
265- // check for options in parens
266- let options = if self . parser . peek_token ( ) . token == Token :: LParen {
267- self . parse_value_options ( ) ?
268- } else {
269- vec ! [ ]
276+ loop {
277+ if let Some ( keyword) = self . parser . parse_one_of_keywords ( & [
278+ Keyword :: STORED ,
279+ Keyword :: TO ,
280+ Keyword :: PARTITIONED ,
281+ Keyword :: OPTIONS ,
282+ Keyword :: WITH ,
283+ ] ) {
284+ match keyword {
285+ Keyword :: STORED => {
286+ self . parser . expect_keyword ( Keyword :: AS ) ?;
287+ ensure_not_set ( & builder. stored_as , "STORED AS" ) ?;
288+ builder. stored_as = Some ( self . parse_file_format ( ) ?) ;
289+ }
290+ Keyword :: TO => {
291+ ensure_not_set ( & builder. target , "TO" ) ?;
292+ builder. target = Some ( self . parser . parse_literal_string ( ) ?) ;
293+ }
294+ Keyword :: WITH => {
295+ self . parser . expect_keyword ( Keyword :: HEADER ) ?;
296+ self . parser . expect_keyword ( Keyword :: ROW ) ?;
297+ return parser_err ! ( "WITH HEADER ROW clause is no longer in use. Please use the OPTIONS clause with 'format.has_header' set appropriately, e.g., OPTIONS ('format.has_header' 'true')" ) ;
298+ }
299+ Keyword :: PARTITIONED => {
300+ self . parser . expect_keyword ( Keyword :: BY ) ?;
301+ ensure_not_set ( & builder. partitioned_by , "PARTITIONED BY" ) ?;
302+ builder. partitioned_by = Some ( self . parse_partitions ( ) ?) ;
303+ }
304+ Keyword :: OPTIONS => {
305+ ensure_not_set ( & builder. options , "OPTIONS" ) ?;
306+ builder. options = Some ( self . parse_value_options ( ) ?) ;
307+ }
308+ _ => {
309+ unreachable ! ( )
310+ }
311+ }
312+ } else {
313+ let token = self . parser . next_token ( ) ;
314+ if token == Token :: EOF || token == Token :: SemiColon {
315+ break ;
316+ } else {
317+ return Err ( ParserError :: ParserError ( format ! (
318+ "Unexpected token {token}"
319+ ) ) ) ;
320+ }
321+ }
322+ }
323+
324+ let Some ( target) = builder. target else {
325+ return Err ( ParserError :: ParserError (
326+ "Missing TO clause in COPY statement" . into ( ) ,
327+ ) ) ;
270328 } ;
271329
272330 Ok ( Statement :: CopyTo ( CopyToStatement {
273331 source,
274332 target,
275- options ,
276- partitioned_by : vec ! [ ] ,
277- stored_as : None ,
333+ partitioned_by : builder . partitioned_by . unwrap_or ( vec ! [ ] ) ,
334+ stored_as : builder . stored_as ,
335+ options : builder . options . unwrap_or ( vec ! [ ] ) ,
278336 } ) )
279337 }
280338
@@ -358,7 +416,7 @@ impl<'a> DFParser<'a> {
358416 self . parser . expect_keyword ( Keyword :: AS ) ?;
359417 let body = self . parse_create_function_body_string ( ) ?;
360418
361- let create_function = SQLStatement :: CreateFunction {
419+ let create_function = SQLStatement :: CreateFunction ( CreateFunction {
362420 or_replace,
363421 temporary,
364422 if_not_exists : false ,
@@ -374,7 +432,7 @@ impl<'a> DFParser<'a> {
374432 determinism_specifier : None ,
375433 options : None ,
376434 remote_connection : None ,
377- } ;
435+ } ) ;
378436
379437 Ok ( Statement :: Statement ( Box :: from ( create_function) ) )
380438 }
@@ -544,6 +602,10 @@ impl<'a> DFParser<'a> {
544602 & mut self ,
545603 unbounded : bool ,
546604 ) -> Result < Statement , ParserError > {
605+ let temporary = self
606+ . parser
607+ . parse_one_of_keywords ( & [ Keyword :: TEMP , Keyword :: TEMPORARY ] )
608+ . is_some ( ) ;
547609 self . parser . expect_keyword ( Keyword :: TABLE ) ?;
548610 let if_not_exists =
549611 self . parser
@@ -606,10 +668,10 @@ impl<'a> DFParser<'a> {
606668 // Note that mixing both names and definitions is not allowed
607669 let peeked = self . parser . peek_nth_token ( 2 ) ;
608670 if peeked == Token :: Comma || peeked == Token :: RParen {
609- // list of column names
671+ // List of column names
610672 builder. table_partition_cols = Some ( self . parse_partitions ( ) ?)
611673 } else {
612- // list of column defs
674+ // List of column defs
613675 let ( cols, cons) = self . parse_columns ( ) ?;
614676 builder. table_partition_cols = Some (
615677 cols. iter ( ) . map ( |col| col. name . to_string ( ) ) . collect ( ) ,
@@ -665,7 +727,7 @@ impl<'a> DFParser<'a> {
665727 table_partition_cols : builder. table_partition_cols . unwrap_or ( vec ! [ ] ) ,
666728 order_exprs : builder. order_exprs ,
667729 if_not_exists,
668- temporary : false ,
730+ temporary,
669731 unbounded,
670732 options : builder. options . unwrap_or ( Vec :: new ( ) ) ,
671733 constraints,
@@ -692,7 +754,7 @@ impl<'a> DFParser<'a> {
692754 options. push ( ( key, value) ) ;
693755 let comma = self . parser . consume_token ( & Token :: Comma ) ;
694756 if self . parser . consume_token ( & Token :: RParen ) {
695- // allow a trailing comma, even though it's not in standard
757+ // Allow a trailing comma, even though it's not in standard
696758 break ;
697759 } else if !comma {
698760 return self . expected (
0 commit comments