@@ -925,23 +925,31 @@ impl<'a> DFParser<'a> {
925925 /// Parse a SQL `CREATE` statement handling `CREATE EXTERNAL TABLE`
926926 pub fn parse_create ( & mut self ) -> Result < Statement , DataFusionError > {
927927 // TODO: Change sql parser to take in `or_replace: bool` inside parse_create()
928- if self
929- . parser
930- . parse_keywords ( & [ Keyword :: OR , Keyword :: REPLACE , Keyword :: EXTERNAL ] )
928+ if self . external_is_followed_by_table ( 2 )
929+ && self . parser . parse_keywords ( & [
930+ Keyword :: OR ,
931+ Keyword :: REPLACE ,
932+ Keyword :: EXTERNAL ,
933+ ] )
931934 {
932935 self . parse_create_external_table ( false , true )
933- } else if self . parser . parse_keywords ( & [
934- Keyword :: OR ,
935- Keyword :: REPLACE ,
936- Keyword :: UNBOUNDED ,
937- Keyword :: EXTERNAL ,
938- ] ) {
936+ } else if self . external_is_followed_by_table ( 3 )
937+ && self . parser . parse_keywords ( & [
938+ Keyword :: OR ,
939+ Keyword :: REPLACE ,
940+ Keyword :: UNBOUNDED ,
941+ Keyword :: EXTERNAL ,
942+ ] )
943+ {
939944 self . parse_create_external_table ( true , true )
940- } else if self . parser . parse_keyword ( Keyword :: EXTERNAL ) {
945+ } else if self . external_is_followed_by_table ( 0 )
946+ && self . parser . parse_keyword ( Keyword :: EXTERNAL )
947+ {
941948 self . parse_create_external_table ( false , false )
942- } else if self
943- . parser
944- . parse_keywords ( & [ Keyword :: UNBOUNDED , Keyword :: EXTERNAL ] )
949+ } else if self . external_is_followed_by_table ( 1 )
950+ && self
951+ . parser
952+ . parse_keywords ( & [ Keyword :: UNBOUNDED , Keyword :: EXTERNAL ] )
945953 {
946954 self . parse_create_external_table ( true , false )
947955 } else {
@@ -953,6 +961,23 @@ impl<'a> DFParser<'a> {
953961 }
954962 }
955963
964+ fn external_is_followed_by_table ( & self , external_offset : usize ) -> bool {
965+ let next_keyword = match self . parser . peek_nth_token ( external_offset + 1 ) . token {
966+ Token :: Word ( word) => word. keyword ,
967+ _ => return false ,
968+ } ;
969+ if next_keyword == Keyword :: TABLE {
970+ return true ;
971+ }
972+ if !matches ! ( next_keyword, Keyword :: TEMP | Keyword :: TEMPORARY ) {
973+ return false ;
974+ }
975+ matches ! (
976+ self . parser. peek_nth_token( external_offset + 2 ) . token,
977+ Token :: Word ( word) if word. keyword == Keyword :: TABLE
978+ )
979+ }
980+
956981 fn parse_partitions ( & mut self ) -> Result < Vec < String > , DataFusionError > {
957982 let mut partitions: Vec < String > = vec ! [ ] ;
958983 if !self . parser . consume_token ( & Token :: LParen )
@@ -1396,6 +1421,13 @@ mod tests {
13961421 } ) ;
13971422 expect_parse_ok ( sql, expected) ?;
13981423
1424+ let sql = "CREATE EXTERNAL TEMPORARY TABLE t STORED AS CSV LOCATION 'foo.csv'" ;
1425+ let expected = Statement :: CreateExternalTable ( CreateExternalTable {
1426+ temporary : true ,
1427+ ..make_create_external_table ( "foo.csv" )
1428+ } ) ;
1429+ expect_parse_ok ( sql, expected) ?;
1430+
13991431 // positive case: literal comma remains part of a single path
14001432 let sql = "CREATE EXTERNAL TABLE t(c1 int) STORED AS CSV LOCATION 'foo,bar.csv'" ;
14011433 let expected = Statement :: CreateExternalTable ( CreateExternalTable {
@@ -1880,6 +1912,31 @@ mod tests {
18801912 Ok ( ( ) )
18811913 }
18821914
1915+ #[ test]
1916+ fn delegate_create_stage_to_snowflake_dialect ( ) -> Result < ( ) , DataFusionError > {
1917+ let sql =
1918+ "CREATE OR REPLACE STAGE stage URL='s3://data.csv' FILE_FORMAT=(TYPE=csv)" ;
1919+ let dialect = SnowflakeDialect ;
1920+ let statements = DFParser :: parse_sql_with_dialect ( sql, & dialect) ?;
1921+
1922+ assert_eq ! ( statements. len( ) , 1 ) ;
1923+ let Statement :: Statement ( statement) = & statements[ 0 ] else {
1924+ panic ! ( "expected a sqlparser statement, got {:?}" , statements[ 0 ] ) ;
1925+ } ;
1926+ assert_eq ! ( statement. to_string( ) , sql) ;
1927+ Ok ( ( ) )
1928+ }
1929+
1930+ #[ test]
1931+ fn parse_standalone_begin_with_snowflake_dialect ( ) -> Result < ( ) , DataFusionError > {
1932+ let dialect = SnowflakeDialect ;
1933+ let statements = DFParser :: parse_sql_with_dialect ( "BEGIN" , & dialect) ?;
1934+
1935+ assert_eq ! ( statements. len( ) , 1 ) ;
1936+ assert ! ( matches!( statements[ 0 ] , Statement :: Statement ( _) ) ) ;
1937+ Ok ( ( ) )
1938+ }
1939+
18831940 #[ test]
18841941 fn explain_copy_to_table_to_table ( ) -> Result < ( ) , DataFusionError > {
18851942 let cases = vec ! [
0 commit comments